[PATCH 10/10] staging: drm/omap: mmap of tiled buffers with stride >4kb

2012-03-05 Thread Rob Clark
From: Rob Clark 

Deal 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

2012-03-05 Thread Rob Clark
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 +=