diff options
author | FUJITA Tomonori <tomof@acm.org> | 2008-02-05 01:28:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:10 -0500 |
commit | fde6a3c82d67f592eb587be4d12222b0ae6d4321 (patch) | |
tree | 33c79ecea87dc99a9c4961b6ab42d53c46f1f8f2 | |
parent | 7c53664dcd5df7349edb56f04c743bf66510a6f1 (diff) |
iommu sg merging: sparc64: make iommu respect the segment size limits
This patch makes iommu respect segment size limits when merging sg
lists.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/sparc64/kernel/iommu.c | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/iommu_common.c | 8 | ||||
-rw-r--r-- | arch/sparc64/kernel/iommu_common.h | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 2 |
4 files changed, 10 insertions, 5 deletions
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 070a4846c0cb..4b9115a4d92e 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c | |||
@@ -580,7 +580,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
580 | 580 | ||
581 | /* Step 1: Prepare scatter list. */ | 581 | /* Step 1: Prepare scatter list. */ |
582 | 582 | ||
583 | npages = prepare_sg(sglist, nelems); | 583 | npages = prepare_sg(dev, sglist, nelems); |
584 | 584 | ||
585 | /* Step 2: Allocate a cluster and context, if necessary. */ | 585 | /* Step 2: Allocate a cluster and context, if necessary. */ |
586 | 586 | ||
diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c index efd5dff85f60..72a4acfe8c7b 100644 --- a/arch/sparc64/kernel/iommu_common.c +++ b/arch/sparc64/kernel/iommu_common.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) | 4 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/dma-mapping.h> | ||
7 | #include "iommu_common.h" | 8 | #include "iommu_common.h" |
8 | 9 | ||
9 | /* You are _strongly_ advised to enable the following debugging code | 10 | /* You are _strongly_ advised to enable the following debugging code |
@@ -201,21 +202,24 @@ void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int np | |||
201 | } | 202 | } |
202 | #endif | 203 | #endif |
203 | 204 | ||
204 | unsigned long prepare_sg(struct scatterlist *sg, int nents) | 205 | unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents) |
205 | { | 206 | { |
206 | struct scatterlist *dma_sg = sg; | 207 | struct scatterlist *dma_sg = sg; |
207 | unsigned long prev; | 208 | unsigned long prev; |
208 | u32 dent_addr, dent_len; | 209 | u32 dent_addr, dent_len; |
210 | unsigned int max_seg_size; | ||
209 | 211 | ||
210 | prev = (unsigned long) sg_virt(sg); | 212 | prev = (unsigned long) sg_virt(sg); |
211 | prev += (unsigned long) (dent_len = sg->length); | 213 | prev += (unsigned long) (dent_len = sg->length); |
212 | dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); | 214 | dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); |
215 | max_seg_size = dma_get_max_seg_size(dev); | ||
213 | while (--nents) { | 216 | while (--nents) { |
214 | unsigned long addr; | 217 | unsigned long addr; |
215 | 218 | ||
216 | sg = sg_next(sg); | 219 | sg = sg_next(sg); |
217 | addr = (unsigned long) sg_virt(sg); | 220 | addr = (unsigned long) sg_virt(sg); |
218 | if (! VCONTIG(prev, addr)) { | 221 | if (! VCONTIG(prev, addr) || |
222 | dent_len + sg->length > max_seg_size) { | ||
219 | dma_sg->dma_address = dent_addr; | 223 | dma_sg->dma_address = dent_addr; |
220 | dma_sg->dma_length = dent_len; | 224 | dma_sg->dma_length = dent_len; |
221 | dma_sg = sg_next(dma_sg); | 225 | dma_sg = sg_next(dma_sg); |
diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h index 75b5a5814522..a90d046e8024 100644 --- a/arch/sparc64/kernel/iommu_common.h +++ b/arch/sparc64/kernel/iommu_common.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/scatterlist.h> | 11 | #include <linux/scatterlist.h> |
12 | #include <linux/device.h> | ||
12 | 13 | ||
13 | #include <asm/iommu.h> | 14 | #include <asm/iommu.h> |
14 | #include <asm/scatterlist.h> | 15 | #include <asm/scatterlist.h> |
@@ -46,4 +47,4 @@ extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int | |||
46 | #define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ | 47 | #define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ |
47 | (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) | 48 | (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) |
48 | 49 | ||
49 | extern unsigned long prepare_sg(struct scatterlist *sg, int nents); | 50 | extern unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents); |
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 1aa8e044b105..67d6dce90b1c 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
@@ -490,7 +490,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
490 | goto bad; | 490 | goto bad; |
491 | 491 | ||
492 | /* Step 1: Prepare scatter list. */ | 492 | /* Step 1: Prepare scatter list. */ |
493 | npages = prepare_sg(sglist, nelems); | 493 | npages = prepare_sg(dev, sglist, nelems); |
494 | 494 | ||
495 | /* Step 2: Allocate a cluster and context, if necessary. */ | 495 | /* Step 2: Allocate a cluster and context, if necessary. */ |
496 | spin_lock_irqsave(&iommu->lock, flags); | 496 | spin_lock_irqsave(&iommu->lock, flags); |