diff options
author | Brian King <brking@us.ibm.com> | 2005-08-17 17:32:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-17 17:41:22 -0400 |
commit | ac9af7cba9e642961bfdee1a1fac6060405597e5 (patch) | |
tree | 5baf99a801a00137fefb158983c88180d36fa999 | |
parent | 75e8727fbb3749075b6df36be636a3045ed9d515 (diff) |
[PATCH] ppc64: iommu vmerge fix
This fixes a bug in the PPC64 iommu vmerge code which results in the
potential for iommu_unmap_sg to go off unmapping more than it should.
This was found on a test system which resulted in PCI bus errors due to
PCI memory being unmapped while DMAs were still in progress.
Signed-off-by: Brian King <brking@us.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/ppc64/kernel/iommu.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c index 8316426ccaf6..845eebd1e28d 100644 --- a/arch/ppc64/kernel/iommu.c +++ b/arch/ppc64/kernel/iommu.c | |||
@@ -242,7 +242,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
242 | dma_addr_t dma_next = 0, dma_addr; | 242 | dma_addr_t dma_next = 0, dma_addr; |
243 | unsigned long flags; | 243 | unsigned long flags; |
244 | struct scatterlist *s, *outs, *segstart; | 244 | struct scatterlist *s, *outs, *segstart; |
245 | int outcount; | 245 | int outcount, incount; |
246 | unsigned long handle; | 246 | unsigned long handle; |
247 | 247 | ||
248 | BUG_ON(direction == DMA_NONE); | 248 | BUG_ON(direction == DMA_NONE); |
@@ -252,6 +252,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
252 | 252 | ||
253 | outs = s = segstart = &sglist[0]; | 253 | outs = s = segstart = &sglist[0]; |
254 | outcount = 1; | 254 | outcount = 1; |
255 | incount = nelems; | ||
255 | handle = 0; | 256 | handle = 0; |
256 | 257 | ||
257 | /* Init first segment length for backout at failure */ | 258 | /* Init first segment length for backout at failure */ |
@@ -338,10 +339,10 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
338 | 339 | ||
339 | DBG("mapped %d elements:\n", outcount); | 340 | DBG("mapped %d elements:\n", outcount); |
340 | 341 | ||
341 | /* For the sake of iommu_free_sg, we clear out the length in the | 342 | /* For the sake of iommu_unmap_sg, we clear out the length in the |
342 | * next entry of the sglist if we didn't fill the list completely | 343 | * next entry of the sglist if we didn't fill the list completely |
343 | */ | 344 | */ |
344 | if (outcount < nelems) { | 345 | if (outcount < incount) { |
345 | outs++; | 346 | outs++; |
346 | outs->dma_address = DMA_ERROR_CODE; | 347 | outs->dma_address = DMA_ERROR_CODE; |
347 | outs->dma_length = 0; | 348 | outs->dma_length = 0; |