[PATCH 10/10] staging: drm/omap: mmap of tiled buffers with stride >4kb
From: Rob ClarkDeal with the case of buffers with virtual stride larger than one page in fault_2d(). Signed-off-by: Rob Clark --- drivers/staging/omapdrm/omap_gem.c | 86 --- 1 files changed, 59 insertions(+), 27 deletions(-) diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 5abd294..921f058 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -153,10 +153,23 @@ static void evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct usergart_entry *entry) { if (obj->dev->dev_mapping) { - size_t size = PAGE_SIZE * usergart[fmt].height; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int n = usergart[fmt].height; + size_t size = PAGE_SIZE * n; loff_t off = mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); - unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + if (m > 1) { + int i; + /* if stride > than PAGE_SIZE then sparse mapping: */ + for (i = n; i > 0; i--) { + unmap_mapping_range(obj->dev->dev_mapping, + off, PAGE_SIZE, 1); + off += PAGE_SIZE * m; + } + } else { + unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + } } entry->obj = NULL; @@ -342,26 +355,39 @@ static int fault_2d(struct drm_gem_object *obj, void __user *vaddr; int i, ret, slots; - if (!usergart) - return -EFAULT; - - /* TODO: this fxn might need a bit tweaking to deal w/ tiled buffers -* that are wider than 4kb + /* +* Note the height of the slot is also equal to the number of pages +* that need to be mapped in to fill 4kb wide CPU page. If the slot +* height is 64, then 64 pages fill a 4kb wide by 64 row region. +*/ + const int n = usergart[fmt].height; + const int n_shift = usergart[fmt].height_shift; + + /* +* If buffer width in bytes > PAGE_SIZE then the virtual stride is +* rounded up to next multiple of PAGE_SIZE.. this need to be taken +* into account in some of the math, so figure out virtual stride +* in pages */ + const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); /* We don't use vmf->pgoff since that has the fake offset: */ pgoff = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - /* actual address we start mapping at is rounded down to previous slot + /* +* Actual address we start mapping at is rounded down to previous slot * boundary in the y direction: */ - base_pgoff = round_down(pgoff, usergart[fmt].height); - vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); - entry = [fmt].entry[usergart[fmt].last]; + base_pgoff = round_down(pgoff, m << n_shift); + /* figure out buffer width in slots */ slots = omap_obj->width >> usergart[fmt].slot_shift; + vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); + + entry = [fmt].entry[usergart[fmt].last]; + /* evict previous buffer using this usergart entry, if any: */ if (entry->obj) evict_entry(entry->obj, fmt, entry); @@ -369,23 +395,30 @@ static int fault_2d(struct drm_gem_object *obj, entry->obj = obj; entry->obj_pgoff = base_pgoff; - /* now convert base_pgoff to phys offset from virt offset: -*/ - base_pgoff = (base_pgoff >> usergart[fmt].height_shift) * slots; - - /* map in pages. Note the height of the slot is also equal to the -* number of pages that need to be mapped in to fill 4kb wide CPU page. -* If the height is 64, then 64 pages fill a 4kb wide by 64 row region. -* Beyond the valid pixel part of the buffer, we set pages[i] to NULL to -* get a dummy page mapped in.. if someone reads/writes it they will get -* random/undefined content, but at least it won't be corrupting -* whatever other random page used to be mapped in, or other undefined -* behavior. + /* now convert base_pgoff to phys offset from virt offset: */ + base_pgoff = (base_pgoff >> n_shift) * slots; + + /* for wider-than 4k.. figure out which part of the slot-row we want: */ + if (m > 1) { + int off = pgoff % m; + entry->obj_pgoff += off; + base_pgoff /= m; + slots = min(slots - (off << n_shift), n); +
[PATCH 10/10] staging: drm/omap: mmap of tiled buffers with stride 4kb
From: Rob Clark r...@ti.com Deal with the case of buffers with virtual stride larger than one page in fault_2d(). Signed-off-by: Rob Clark r...@ti.com --- drivers/staging/omapdrm/omap_gem.c | 86 --- 1 files changed, 59 insertions(+), 27 deletions(-) diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 5abd294..921f058 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -153,10 +153,23 @@ static void evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct usergart_entry *entry) { if (obj-dev-dev_mapping) { - size_t size = PAGE_SIZE * usergart[fmt].height; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int n = usergart[fmt].height; + size_t size = PAGE_SIZE * n; loff_t off = mmap_offset(obj) + (entry-obj_pgoff PAGE_SHIFT); - unmap_mapping_range(obj-dev-dev_mapping, off, size, 1); + const int m = 1 + ((omap_obj-width fmt) / PAGE_SIZE); + if (m 1) { + int i; + /* if stride than PAGE_SIZE then sparse mapping: */ + for (i = n; i 0; i--) { + unmap_mapping_range(obj-dev-dev_mapping, + off, PAGE_SIZE, 1); + off += PAGE_SIZE * m; + } + } else { + unmap_mapping_range(obj-dev-dev_mapping, off, size, 1); + } } entry-obj = NULL; @@ -342,26 +355,39 @@ static int fault_2d(struct drm_gem_object *obj, void __user *vaddr; int i, ret, slots; - if (!usergart) - return -EFAULT; - - /* TODO: this fxn might need a bit tweaking to deal w/ tiled buffers -* that are wider than 4kb + /* +* Note the height of the slot is also equal to the number of pages +* that need to be mapped in to fill 4kb wide CPU page. If the slot +* height is 64, then 64 pages fill a 4kb wide by 64 row region. +*/ + const int n = usergart[fmt].height; + const int n_shift = usergart[fmt].height_shift; + + /* +* If buffer width in bytes PAGE_SIZE then the virtual stride is +* rounded up to next multiple of PAGE_SIZE.. this need to be taken +* into account in some of the math, so figure out virtual stride +* in pages */ + const int m = 1 + ((omap_obj-width fmt) / PAGE_SIZE); /* We don't use vmf-pgoff since that has the fake offset: */ pgoff = ((unsigned long)vmf-virtual_address - vma-vm_start) PAGE_SHIFT; - /* actual address we start mapping at is rounded down to previous slot + /* +* Actual address we start mapping at is rounded down to previous slot * boundary in the y direction: */ - base_pgoff = round_down(pgoff, usergart[fmt].height); - vaddr = vmf-virtual_address - ((pgoff - base_pgoff) PAGE_SHIFT); - entry = usergart[fmt].entry[usergart[fmt].last]; + base_pgoff = round_down(pgoff, m n_shift); + /* figure out buffer width in slots */ slots = omap_obj-width usergart[fmt].slot_shift; + vaddr = vmf-virtual_address - ((pgoff - base_pgoff) PAGE_SHIFT); + + entry = usergart[fmt].entry[usergart[fmt].last]; + /* evict previous buffer using this usergart entry, if any: */ if (entry-obj) evict_entry(entry-obj, fmt, entry); @@ -369,23 +395,30 @@ static int fault_2d(struct drm_gem_object *obj, entry-obj = obj; entry-obj_pgoff = base_pgoff; - /* now convert base_pgoff to phys offset from virt offset: -*/ - base_pgoff = (base_pgoff usergart[fmt].height_shift) * slots; - - /* map in pages. Note the height of the slot is also equal to the -* number of pages that need to be mapped in to fill 4kb wide CPU page. -* If the height is 64, then 64 pages fill a 4kb wide by 64 row region. -* Beyond the valid pixel part of the buffer, we set pages[i] to NULL to -* get a dummy page mapped in.. if someone reads/writes it they will get -* random/undefined content, but at least it won't be corrupting -* whatever other random page used to be mapped in, or other undefined -* behavior. + /* now convert base_pgoff to phys offset from virt offset: */ + base_pgoff = (base_pgoff n_shift) * slots; + + /* for wider-than 4k.. figure out which part of the slot-row we want: */ + if (m 1) { + int off = pgoff % m; + entry-obj_pgoff += off; + base_pgoff /= m; + slots = min(slots - (off n_shift), n); + base_pgoff +=