diff options
| author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-09-02 13:32:30 -0400 |
|---|---|---|
| committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-09-05 09:14:37 -0400 |
| commit | 329d8d3b474923087f6988737ff12137b58e55cc (patch) | |
| tree | 9db30cae05fb15b6dfede6976aae1dfbd9dfd80d | |
| parent | 024ae884a657f8ddeeff6b472c1fe538f277980e (diff) | |
iommu/omap-iovmm: support non page-aligned buffers in iommu_vmap
omap_iovmm requires page-aligned buffers, and that sometimes causes
omap3isp failures (i.e. whenever the buffer passed from userspace is not
page-aligned).
Remove this limitation by rounding the address of the first page entry
down, and adding the offset back to the device address.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
[ohad@wizery.com: rebased, but tested only with aligned buffers]
[ohad@wizery.com: slightly edited the commit log]
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
| -rw-r--r-- | drivers/iommu/omap-iovmm.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c index 5e7f97dc76ef..39bdb92aa96f 100644 --- a/drivers/iommu/omap-iovmm.c +++ b/drivers/iommu/omap-iovmm.c | |||
| @@ -27,6 +27,15 @@ | |||
| 27 | 27 | ||
| 28 | static struct kmem_cache *iovm_area_cachep; | 28 | static struct kmem_cache *iovm_area_cachep; |
| 29 | 29 | ||
| 30 | /* return the offset of the first scatterlist entry in a sg table */ | ||
| 31 | static unsigned int sgtable_offset(const struct sg_table *sgt) | ||
| 32 | { | ||
| 33 | if (!sgt || !sgt->nents) | ||
| 34 | return 0; | ||
| 35 | |||
| 36 | return sgt->sgl->offset; | ||
| 37 | } | ||
| 38 | |||
| 30 | /* return total bytes of sg buffers */ | 39 | /* return total bytes of sg buffers */ |
| 31 | static size_t sgtable_len(const struct sg_table *sgt) | 40 | static size_t sgtable_len(const struct sg_table *sgt) |
| 32 | { | 41 | { |
| @@ -39,11 +48,17 @@ static size_t sgtable_len(const struct sg_table *sgt) | |||
| 39 | for_each_sg(sgt->sgl, sg, sgt->nents, i) { | 48 | for_each_sg(sgt->sgl, sg, sgt->nents, i) { |
| 40 | size_t bytes; | 49 | size_t bytes; |
| 41 | 50 | ||
| 42 | bytes = sg->length; | 51 | bytes = sg->length + sg->offset; |
| 43 | 52 | ||
| 44 | if (!iopgsz_ok(bytes)) { | 53 | if (!iopgsz_ok(bytes)) { |
| 45 | pr_err("%s: sg[%d] not iommu pagesize(%x)\n", | 54 | pr_err("%s: sg[%d] not iommu pagesize(%u %u)\n", |
| 46 | __func__, i, bytes); | 55 | __func__, i, bytes, sg->offset); |
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | if (i && sg->offset) { | ||
| 60 | pr_err("%s: sg[%d] offset not allowed in internal " | ||
| 61 | "entries\n", __func__, i); | ||
| 47 | return 0; | 62 | return 0; |
| 48 | } | 63 | } |
| 49 | 64 | ||
| @@ -164,8 +179,8 @@ static void *vmap_sg(const struct sg_table *sgt) | |||
| 164 | u32 pa; | 179 | u32 pa; |
| 165 | int err; | 180 | int err; |
| 166 | 181 | ||
| 167 | pa = sg_phys(sg); | 182 | pa = sg_phys(sg) - sg->offset; |
| 168 | bytes = sg->length; | 183 | bytes = sg->length + sg->offset; |
| 169 | 184 | ||
| 170 | BUG_ON(bytes != PAGE_SIZE); | 185 | BUG_ON(bytes != PAGE_SIZE); |
| 171 | 186 | ||
| @@ -405,8 +420,8 @@ static int map_iovm_area(struct iommu_domain *domain, struct iovm_struct *new, | |||
| 405 | u32 pa; | 420 | u32 pa; |
| 406 | size_t bytes; | 421 | size_t bytes; |
| 407 | 422 | ||
| 408 | pa = sg_phys(sg); | 423 | pa = sg_phys(sg) - sg->offset; |
| 409 | bytes = sg->length; | 424 | bytes = sg->length + sg->offset; |
| 410 | 425 | ||
| 411 | flags &= ~IOVMF_PGSZ_MASK; | 426 | flags &= ~IOVMF_PGSZ_MASK; |
| 412 | 427 | ||
| @@ -432,7 +447,7 @@ err_out: | |||
| 432 | for_each_sg(sgt->sgl, sg, i, j) { | 447 | for_each_sg(sgt->sgl, sg, i, j) { |
| 433 | size_t bytes; | 448 | size_t bytes; |
| 434 | 449 | ||
| 435 | bytes = sg->length; | 450 | bytes = sg->length + sg->offset; |
| 436 | order = get_order(bytes); | 451 | order = get_order(bytes); |
| 437 | 452 | ||
| 438 | /* ignore failures.. we're already handling one */ | 453 | /* ignore failures.. we're already handling one */ |
| @@ -461,7 +476,7 @@ static void unmap_iovm_area(struct iommu_domain *domain, struct omap_iommu *obj, | |||
| 461 | size_t bytes; | 476 | size_t bytes; |
| 462 | int order; | 477 | int order; |
| 463 | 478 | ||
| 464 | bytes = sg->length; | 479 | bytes = sg->length + sg->offset; |
| 465 | order = get_order(bytes); | 480 | order = get_order(bytes); |
| 466 | 481 | ||
| 467 | err = iommu_unmap(domain, start, order); | 482 | err = iommu_unmap(domain, start, order); |
| @@ -600,7 +615,7 @@ u32 omap_iommu_vmap(struct iommu_domain *domain, struct omap_iommu *obj, u32 da, | |||
| 600 | if (IS_ERR_VALUE(da)) | 615 | if (IS_ERR_VALUE(da)) |
| 601 | vunmap_sg(va); | 616 | vunmap_sg(va); |
| 602 | 617 | ||
| 603 | return da; | 618 | return da + sgtable_offset(sgt); |
| 604 | } | 619 | } |
| 605 | EXPORT_SYMBOL_GPL(omap_iommu_vmap); | 620 | EXPORT_SYMBOL_GPL(omap_iommu_vmap); |
| 606 | 621 | ||
| @@ -620,6 +635,7 @@ omap_iommu_vunmap(struct iommu_domain *domain, struct omap_iommu *obj, u32 da) | |||
| 620 | * 'sgt' is allocated before 'omap_iommu_vmalloc()' is called. | 635 | * 'sgt' is allocated before 'omap_iommu_vmalloc()' is called. |
| 621 | * Just returns 'sgt' to the caller to free | 636 | * Just returns 'sgt' to the caller to free |
| 622 | */ | 637 | */ |
| 638 | da &= PAGE_MASK; | ||
| 623 | sgt = unmap_vm_area(domain, obj, da, vunmap_sg, | 639 | sgt = unmap_vm_area(domain, obj, da, vunmap_sg, |
| 624 | IOVMF_DISCONT | IOVMF_MMIO); | 640 | IOVMF_DISCONT | IOVMF_MMIO); |
| 625 | if (!sgt) | 641 | if (!sgt) |
