-/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $
- * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
+/* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com)
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/delay.h>
+#include <linux/pci.h>
-#include <asm/pbm.h>
+#include <asm/oplib.h>
#include "iommu_common.h"
+#include "pci_impl.h"
#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
"i" (ASI_PHYS_BYPASS_EC_E))
/* Must be invoked under the IOMMU lock. */
-static void __iommu_flushall(struct pci_iommu *iommu)
+static void __iommu_flushall(struct iommu *iommu)
{
- unsigned long tag;
- int entry;
+ if (iommu->iommu_flushinv) {
+ pci_iommu_write(iommu->iommu_flushinv, ~(u64)0);
+ } else {
+ unsigned long tag;
+ int entry;
- tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
- for (entry = 0; entry < 16; entry++) {
- pci_iommu_write(tag, 0);
- tag += 8;
- }
+ tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+ for (entry = 0; entry < 16; entry++) {
+ pci_iommu_write(tag, 0);
+ tag += 8;
+ }
- /* Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ /* Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ }
}
#define IOPTE_CONSISTENT(CTX) \
#define IOPTE_IS_DUMMY(iommu, iopte) \
((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)
-static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
+static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
{
unsigned long val = iopte_val(*iopte);
}
/* Based largely upon the ppc64 iommu allocator. */
-static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages)
+static long pci_arena_alloc(struct iommu *iommu, unsigned long npages)
{
- struct pci_iommu_arena *arena = &iommu->arena;
+ struct iommu_arena *arena = &iommu->arena;
unsigned long n, i, start, end, limit;
int pass;
return n;
}
-static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
{
unsigned long i;
__clear_bit(i, arena->map);
}
-void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
+void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
{
unsigned long i, tsbbase, order, sz, num_tsb_entries;
iopte_make_dummy(iommu, &iommu->page_table[i]);
}
-static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages)
+static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
{
long entry;
return iommu->page_table + entry;
}
-static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages)
+static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
{
pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
}
-static int iommu_alloc_ctx(struct pci_iommu *iommu)
+static int iommu_alloc_ctx(struct iommu *iommu)
{
int lowest = iommu->ctx_lowest_free;
int sz = IOMMU_NUM_CTXS - lowest;
return n;
}
-static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
+static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
{
if (likely(ctx)) {
__clear_bit(ctx, iommu->ctx_bitmap);
*/
static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, first_page;
void *ret;
return NULL;
memset((char *)first_page, 0, PAGE_SIZE << order);
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
spin_lock_irqsave(&iommu->lock, flags);
iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
/* Free and unmap a consistent DMA translation. */
static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
+ struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, npages;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
+ iommu = pdev->dev.archdata.iommu;
iopte = iommu->page_table +
((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- free_npages(iommu, dvma, npages);
+ free_npages(iommu, dvma - iommu->page_table_map_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
*/
static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, npages, oaddr;
unsigned long i, base_paddr, ctx;
u32 bus_addr, ret;
unsigned long iopte_protection;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (unlikely(direction == PCI_DMA_NONE))
goto bad_no_ctx;
return PCI_DMA_ERROR_CODE;
}
-static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
+static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
{
int limit;
/* Unmap a single streaming mode DMA translation. */
static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, npages, ctx, i;
return;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
*/
static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages, iopte_protection;
iopte_t *base;
u32 dma_base;
return 1;
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (unlikely(direction == PCI_DMA_NONE))
goto bad_no_ctx;
/* Unmap a set of streaming mode DMA translations. */
static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, ctx, i, npages;
u32 bus_addr;
WARN_ON(1);
}
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
*/
static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (!strbuf->strbuf_enabled)
return;
*/
static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
- struct pcidev_cookie *pcp;
- struct pci_iommu *iommu;
- struct pci_strbuf *strbuf;
+ struct iommu *iommu;
+ struct strbuf *strbuf;
unsigned long flags, ctx, npages, i;
u32 bus_addr;
- pcp = pdev->sysdata;
- iommu = pcp->pbm->iommu;
- strbuf = &pcp->pbm->stc;
+ iommu = pdev->dev.archdata.iommu;
+ strbuf = pdev->dev.archdata.stc;
if (!strbuf->strbuf_enabled)
return;
spin_unlock_irqrestore(&iommu->lock, flags);
}
-struct pci_iommu_ops pci_sun4u_iommu_ops = {
+const struct pci_iommu_ops pci_sun4u_iommu_ops = {
.alloc_consistent = pci_4u_alloc_consistent,
.free_consistent = pci_4u_free_consistent,
.map_single = pci_4u_map_single,
int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
u64 dma_addr_mask;
if (pdev == NULL) {
dma_addr_mask = 0xffffffff;
} else {
- struct pci_iommu *iommu = pcp->pbm->iommu;
+ struct iommu *iommu = pdev->dev.archdata.iommu;
dma_addr_mask = iommu->dma_addr_mask;