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

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)