diff options
| -rw-r--r-- | arch/sparc64/kernel/iommu.c | 12 | ||||
| -rw-r--r-- | arch/sparc64/kernel/iommu_common.h | 13 | ||||
| -rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 12 |
3 files changed, 33 insertions, 4 deletions
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index b781d3d54fb8..756fa24eeefa 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c | |||
| @@ -516,9 +516,11 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 516 | unsigned long flags, handle, prot, ctx; | 516 | unsigned long flags, handle, prot, ctx; |
| 517 | dma_addr_t dma_next = 0, dma_addr; | 517 | dma_addr_t dma_next = 0, dma_addr; |
| 518 | unsigned int max_seg_size; | 518 | unsigned int max_seg_size; |
| 519 | unsigned long seg_boundary_size; | ||
| 519 | int outcount, incount, i; | 520 | int outcount, incount, i; |
| 520 | struct strbuf *strbuf; | 521 | struct strbuf *strbuf; |
| 521 | struct iommu *iommu; | 522 | struct iommu *iommu; |
| 523 | unsigned long base_shift; | ||
| 522 | 524 | ||
| 523 | BUG_ON(direction == DMA_NONE); | 525 | BUG_ON(direction == DMA_NONE); |
| 524 | 526 | ||
| @@ -549,8 +551,11 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 549 | outs->dma_length = 0; | 551 | outs->dma_length = 0; |
| 550 | 552 | ||
| 551 | max_seg_size = dma_get_max_seg_size(dev); | 553 | max_seg_size = dma_get_max_seg_size(dev); |
| 554 | seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, | ||
| 555 | IO_PAGE_SIZE) >> IO_PAGE_SHIFT; | ||
| 556 | base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT; | ||
| 552 | for_each_sg(sglist, s, nelems, i) { | 557 | for_each_sg(sglist, s, nelems, i) { |
| 553 | unsigned long paddr, npages, entry, slen; | 558 | unsigned long paddr, npages, entry, out_entry = 0, slen; |
| 554 | iopte_t *base; | 559 | iopte_t *base; |
| 555 | 560 | ||
| 556 | slen = s->length; | 561 | slen = s->length; |
| @@ -593,7 +598,9 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 593 | * - allocated dma_addr isn't contiguous to previous allocation | 598 | * - allocated dma_addr isn't contiguous to previous allocation |
| 594 | */ | 599 | */ |
| 595 | if ((dma_addr != dma_next) || | 600 | if ((dma_addr != dma_next) || |
| 596 | (outs->dma_length + s->length > max_seg_size)) { | 601 | (outs->dma_length + s->length > max_seg_size) || |
| 602 | (is_span_boundary(out_entry, base_shift, | ||
| 603 | seg_boundary_size, outs, s))) { | ||
| 597 | /* Can't merge: create a new segment */ | 604 | /* Can't merge: create a new segment */ |
| 598 | segstart = s; | 605 | segstart = s; |
| 599 | outcount++; | 606 | outcount++; |
| @@ -607,6 +614,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 607 | /* This is a new segment, fill entries */ | 614 | /* This is a new segment, fill entries */ |
| 608 | outs->dma_address = dma_addr; | 615 | outs->dma_address = dma_addr; |
| 609 | outs->dma_length = slen; | 616 | outs->dma_length = slen; |
| 617 | out_entry = entry; | ||
| 610 | } | 618 | } |
| 611 | 619 | ||
| 612 | /* Calculate next page pointer for contiguous check */ | 620 | /* Calculate next page pointer for contiguous check */ |
diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h index 0713bd58499c..87ace495d45f 100644 --- a/arch/sparc64/kernel/iommu_common.h +++ b/arch/sparc64/kernel/iommu_common.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
| 13 | #include <linux/scatterlist.h> | 13 | #include <linux/scatterlist.h> |
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/iommu-helper.h> | ||
| 15 | 16 | ||
| 16 | #include <asm/iommu.h> | 17 | #include <asm/iommu.h> |
| 17 | #include <asm/scatterlist.h> | 18 | #include <asm/scatterlist.h> |
| @@ -58,6 +59,18 @@ static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems) | |||
| 58 | return npages; | 59 | return npages; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 62 | static inline int is_span_boundary(unsigned long entry, | ||
| 63 | unsigned long shift, | ||
| 64 | unsigned long boundary_size, | ||
| 65 | struct scatterlist *outs, | ||
| 66 | struct scatterlist *sg) | ||
| 67 | { | ||
| 68 | unsigned long paddr = SG_ENT_PHYS_ADDRESS(outs); | ||
| 69 | int nr = iommu_num_pages(paddr, outs->dma_length + sg->length); | ||
| 70 | |||
| 71 | return iommu_is_span_boundary(entry, nr, shift, boundary_size); | ||
| 72 | } | ||
| 73 | |||
| 61 | extern unsigned long iommu_range_alloc(struct device *dev, | 74 | extern unsigned long iommu_range_alloc(struct device *dev, |
| 62 | struct iommu *iommu, | 75 | struct iommu *iommu, |
| 63 | unsigned long npages, | 76 | unsigned long npages, |
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index ddca6c6c0b49..01839706bd52 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
| @@ -335,8 +335,10 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 335 | unsigned long flags, handle, prot; | 335 | unsigned long flags, handle, prot; |
| 336 | dma_addr_t dma_next = 0, dma_addr; | 336 | dma_addr_t dma_next = 0, dma_addr; |
| 337 | unsigned int max_seg_size; | 337 | unsigned int max_seg_size; |
| 338 | unsigned long seg_boundary_size; | ||
| 338 | int outcount, incount, i; | 339 | int outcount, incount, i; |
| 339 | struct iommu *iommu; | 340 | struct iommu *iommu; |
| 341 | unsigned long base_shift; | ||
| 340 | long err; | 342 | long err; |
| 341 | 343 | ||
| 342 | BUG_ON(direction == DMA_NONE); | 344 | BUG_ON(direction == DMA_NONE); |
| @@ -362,8 +364,11 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 362 | iommu_batch_start(dev, prot, ~0UL); | 364 | iommu_batch_start(dev, prot, ~0UL); |
| 363 | 365 | ||
| 364 | max_seg_size = dma_get_max_seg_size(dev); | 366 | max_seg_size = dma_get_max_seg_size(dev); |
| 367 | seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, | ||
| 368 | IO_PAGE_SIZE) >> IO_PAGE_SHIFT; | ||
| 369 | base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT; | ||
| 365 | for_each_sg(sglist, s, nelems, i) { | 370 | for_each_sg(sglist, s, nelems, i) { |
| 366 | unsigned long paddr, npages, entry, slen; | 371 | unsigned long paddr, npages, entry, out_entry = 0, slen; |
| 367 | 372 | ||
| 368 | slen = s->length; | 373 | slen = s->length; |
| 369 | /* Sanity check */ | 374 | /* Sanity check */ |
| @@ -406,7 +411,9 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 406 | * - allocated dma_addr isn't contiguous to previous allocation | 411 | * - allocated dma_addr isn't contiguous to previous allocation |
| 407 | */ | 412 | */ |
| 408 | if ((dma_addr != dma_next) || | 413 | if ((dma_addr != dma_next) || |
| 409 | (outs->dma_length + s->length > max_seg_size)) { | 414 | (outs->dma_length + s->length > max_seg_size) || |
| 415 | (is_span_boundary(out_entry, base_shift, | ||
| 416 | seg_boundary_size, outs, s))) { | ||
| 410 | /* Can't merge: create a new segment */ | 417 | /* Can't merge: create a new segment */ |
| 411 | segstart = s; | 418 | segstart = s; |
| 412 | outcount++; | 419 | outcount++; |
| @@ -420,6 +427,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 420 | /* This is a new segment, fill entries */ | 427 | /* This is a new segment, fill entries */ |
| 421 | outs->dma_address = dma_addr; | 428 | outs->dma_address = dma_addr; |
| 422 | outs->dma_length = slen; | 429 | outs->dma_length = slen; |
| 430 | out_entry = entry; | ||
| 423 | } | 431 | } |
| 424 | 432 | ||
| 425 | /* Calculate next page pointer for contiguous check */ | 433 | /* Calculate next page pointer for contiguous check */ |
