patch-2.3.47 linux/arch/sparc64/kernel/pci_iommu.c
Next file: linux/arch/sparc64/kernel/pci_psycho.c
Previous file: linux/arch/sparc64/kernel/ioctl32.c
Back to the patch index
Back to the overall index
- Lines: 245
- Date:
Fri Feb 18 15:07:20 2000
- Orig file:
v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c
- Orig date:
Wed Feb 16 17:03:51 2000
diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $
+/* $Id: pci_iommu.c,v 1.10 2000/02/18 13:48:54 davem Exp $
* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -99,13 +99,12 @@
return NULL;
}
-#define IOPTE_CONSISTANT(CTX, PADDR) \
- (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \
- (((CTX) << 47) & IOPTE_CONTEXT) | \
- ((PADDR) & IOPTE_PAGE))
+#define IOPTE_CONSISTENT(CTX) \
+ (IOPTE_VALID | IOPTE_CACHE | \
+ (((CTX) << 47) & IOPTE_CONTEXT))
-#define IOPTE_STREAMING(CTX, PADDR) \
- (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF)
+#define IOPTE_STREAMING(CTX) \
+ (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF)
#define IOPTE_INVALID 0UL
@@ -127,11 +126,6 @@
if (order >= 10)
return NULL;
- /* We still don't support devices which don't recognize at least 30 bits
- of bus address. Bug me to code it (is pretty easy actually). -jj */
- if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
- BUG();
-
first_page = __get_free_pages(GFP_ATOMIC, order);
if (first_page == 0UL)
return NULL;
@@ -157,7 +151,9 @@
ctx = iommu->iommu_cur_ctx++;
first_page = __pa(first_page);
while (npages--) {
- iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page);
+ iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) |
+ IOPTE_WRITE |
+ (first_page & IOPTE_PAGE));
iopte++;
first_page += PAGE_SIZE;
}
@@ -215,7 +211,7 @@
/* Map a single buffer at PTR of SZ bytes for PCI DMA
* in streaming mode.
*/
-dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz)
+dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
{
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
@@ -224,14 +220,13 @@
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->parent->iommu;
strbuf = &pcp->pbm->stc;
- /* We still don't support devices which don't recognize at least 30 bits
- of bus address. Bug me to code it (is pretty easy actually). -jj */
- if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
+ if (direction == PCI_DMA_NONE)
BUG();
oaddr = (unsigned long)ptr;
@@ -248,13 +243,15 @@
ctx = 0;
if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++;
- if (strbuf->strbuf_enabled) {
- for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
- iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
- } else {
- for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
- iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr);
- }
+ if (strbuf->strbuf_enabled)
+ iopte_protection = IOPTE_STREAMING(ctx);
+ else
+ iopte_protection = IOPTE_CONSISTENT(ctx);
+ if (direction != PCI_DMA_TODEVICE)
+ iopte_protection |= IOPTE_WRITE;
+
+ for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+ iopte_val(*base) = iopte_protection | base_paddr;
/* Flush the IOMMU TLB. */
if (iommu->iommu_ctxflush) {
@@ -270,7 +267,7 @@
}
/* Unmap a single streaming mode DMA translation. */
-void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
+void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
@@ -278,6 +275,9 @@
iopte_t *base;
unsigned long flags, npages, i, ctx;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
pcp = pdev->sysdata;
iommu = &pcp->pbm->parent->iommu;
strbuf = &pcp->pbm->stc;
@@ -335,7 +335,7 @@
spin_unlock_irqrestore(&iommu->lock, flags);
}
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long ctx, int streaming)
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection)
{
struct scatterlist *dma_sg = sg;
int i;
@@ -375,10 +375,7 @@
sg++;
}
- if (streaming)
- pteval = IOPTE_STREAMING(ctx, pteval);
- else
- pteval = IOPTE_CONSISTANT(ctx, pteval);
+ pteval = iopte_protection | (pteval & IOPTE_PAGE);
while (len > 0) {
*iopte++ = __iopte(pteval);
pteval += PAGE_SIZE;
@@ -413,12 +410,12 @@
* When making changes here, inspect the assembly output. I was having
* hard time to kepp this routine out of using stack slots for holding variables.
*/
-int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+int pci_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;
- unsigned long flags, ctx, i, npages;
+ unsigned long flags, ctx, i, npages, iopte_protection;
iopte_t *base;
u32 dma_base;
struct scatterlist *sgtmp;
@@ -426,7 +423,7 @@
/* Fast path single entry scatterlists. */
if (nelems == 1) {
- sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length);
+ sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction);
sglist->dvma_length = sglist->length;
return 1;
}
@@ -435,9 +432,7 @@
iommu = &pcp->pbm->parent->iommu;
strbuf = &pcp->pbm->stc;
- /* We still don't support devices which don't recognize at least 30 bits
- of bus address. Bug me to code it (is pretty easy actually). -jj */
- if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff)
+ if (direction == PCI_DMA_NONE)
BUG();
/* Step 1: Prepare scatter list. */
@@ -468,7 +463,13 @@
ctx = iommu->iommu_cur_ctx++;
/* Step 5: Create the mappings. */
- fill_sg (base, sglist, used, ctx, strbuf->strbuf_enabled);
+ if (strbuf->strbuf_enabled)
+ iopte_protection = IOPTE_STREAMING(ctx);
+ else
+ iopte_protection = IOPTE_CONSISTENT(ctx);
+ if (direction != PCI_DMA_TODEVICE)
+ iopte_protection |= IOPTE_WRITE;
+ fill_sg (base, sglist, used, iopte_protection);
#ifdef VERIFY_SG
verify_sglist(sglist, nelems, base, npages);
#endif
@@ -487,7 +488,7 @@
}
/* Unmap a set of streaming mode DMA translations. */
-void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
@@ -496,6 +497,9 @@
unsigned long flags, ctx, i, npages;
u32 bus_addr;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
pcp = pdev->sysdata;
iommu = &pcp->pbm->parent->iommu;
strbuf = &pcp->pbm->stc;
@@ -562,7 +566,7 @@
/* Make physical memory consistent for a single
* streaming mode DMA translation after a transfer.
*/
-void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz)
+void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
{
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
@@ -623,7 +627,7 @@
/* Make physical memory consistent for a set of streaming
* mode DMA translations after a transfer.
*/
-void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
{
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
@@ -683,4 +687,20 @@
membar("#LoadLoad");
spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ u32 dma_addr_mask;
+
+ if (pdev == NULL) {
+ dma_addr_mask = 0xffffffff;
+ } else {
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+
+ dma_addr_mask = iommu->dma_addr_mask;
+ }
+
+ return (device_mask & dma_addr_mask) == dma_addr_mask;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)