diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
commit | 482368b1a8e45430672c58c9a42e7d2004367126 (patch) | |
tree | ce2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /arch/sparc64/kernel/pci_iommu.c | |
parent | e4d0251c6f56ab2e191afb70f80f382793e23f74 (diff) |
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch/sparc64/kernel/pci_iommu.c')
-rw-r--r-- | arch/sparc64/kernel/pci_iommu.c | 112 |
1 files changed, 63 insertions, 49 deletions
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 409a44897..00f635ab3 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/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 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long 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 @@ -123,18 +122,10 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad int npages; size = PAGE_ALIGN(size); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } - if (order == 10) + order = get_order(size); + 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; @@ -160,7 +151,9 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad 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; } @@ -210,10 +203,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ spin_unlock_irqrestore(&iommu->lock, flags); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); } @@ -221,7 +211,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ /* 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; @@ -230,14 +220,13 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) 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; @@ -254,13 +243,15 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) 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) { @@ -276,7 +267,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) } /* 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; @@ -284,6 +275,9 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) 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; @@ -341,7 +335,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) 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; @@ -381,10 +375,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un 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; @@ -419,12 +410,12 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un * 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; @@ -432,7 +423,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) /* 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; } @@ -441,9 +432,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) 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. */ @@ -474,7 +463,13 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) 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 @@ -493,7 +488,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) } /* 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; @@ -502,6 +497,9 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) 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; @@ -568,7 +566,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) /* 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; @@ -629,7 +627,7 @@ void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) /* 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; @@ -690,3 +688,19 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem 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; +} |