|
@@ -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 += off << n_shift;
|
|
|
+ vaddr += off << PAGE_SHIFT;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Map in pages. 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.
|
|
|
*/
|
|
|
memcpy(pages, &omap_obj->pages[base_pgoff],
|
|
|
sizeof(struct page *) * slots);
|
|
|
memset(pages + slots, 0,
|
|
|
- sizeof(struct page *) * (usergart[fmt].height - slots));
|
|
|
+ sizeof(struct page *) * (n - slots));
|
|
|
|
|
|
ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true);
|
|
|
if (ret) {
|
|
@@ -393,16 +426,15 @@ static int fault_2d(struct drm_gem_object *obj,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- i = usergart[fmt].height;
|
|
|
pfn = entry->paddr >> PAGE_SHIFT;
|
|
|
|
|
|
VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
|
|
|
pfn, pfn << PAGE_SHIFT);
|
|
|
|
|
|
- while (i--) {
|
|
|
+ for (i = n; i > 0; i--) {
|
|
|
vm_insert_mixed(vma, (unsigned long)vaddr, pfn);
|
|
|
pfn += usergart[fmt].stride_pfn;
|
|
|
- vaddr += PAGE_SIZE;
|
|
|
+ vaddr += PAGE_SIZE * m;
|
|
|
}
|
|
|
|
|
|
/* simple round-robin: */
|