Module Name: src
Committed By: riastradh
Date: Sun Sep 8 15:52:20 UTC 2013
Modified Files:
src/sys/external/bsd/drm2/dist/drm/i915 [riastradh-drm2]: i915_drv.h
i915_gem.c i915_gem_execbuffer.c i915_gem_tiling.c
src/sys/modules/i915drm2 [riastradh-drm2]: Makefile
Added Files:
src/sys/external/bsd/drm2/i915drm [riastradh-drm2]: i915_gem_gtt.c
intel_gtt.c
Removed Files:
src/sys/external/bsd/drm2/i915drm [riastradh-drm2]: i915_gem.c
Log Message:
Adapt the i915 GEM code to NetBSD.
To generate a diff of this commit:
cvs rdiff -u -r1.1.1.1.2.14 -r1.1.1.1.2.15 \
src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h
cvs rdiff -u -r1.1.1.1.2.7 -r1.1.1.1.2.8 \
src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c
cvs rdiff -u -r1.1.1.1.2.3 -r1.1.1.1.2.4 \
src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c
cvs rdiff -u -r1.1.1.1.2.2 -r1.1.1.1.2.3 \
src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c
cvs rdiff -u -r1.1.2.2 -r0 src/sys/external/bsd/drm2/i915drm/i915_gem.c
cvs rdiff -u -r0 -r1.1.2.1 src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c \
src/sys/external/bsd/drm2/i915drm/intel_gtt.c
cvs rdiff -u -r1.1.2.8 -r1.1.2.9 src/sys/modules/i915drm2/Makefile
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.1.1.1.2.14 src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.1.1.1.2.15
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.1.1.1.2.14 Wed Jul 24 03:40:29 2013
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h Sun Sep 8 15:52:20 2013
@@ -1084,7 +1084,14 @@ struct drm_i915_gem_object {
unsigned int has_global_gtt_mapping:1;
unsigned int has_dma_mapping:1;
+#ifdef __NetBSD__
+ struct pglist igo_pageq;
+ bus_dma_segment_t *pages; /* `pages' is an expedient misnomer. */
+ int igo_nsegs;
+ bus_dmamap_t igo_dmamap;
+#else
struct sg_table *pages;
+#endif
int pages_pin_count;
/* prime dma-buf support */
@@ -1436,7 +1443,23 @@ void i915_gem_release_mmap(struct drm_i9
void i915_gem_lastclose(struct drm_device *dev);
int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
-#ifndef __NetBSD__ /* XXX */
+#ifdef __NetBSD__ /* XXX */
+static inline struct page *
+i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
+{
+
+ /*
+ * Pages must be pinned so that we need not hold the lock to
+ * prevent them from disappearing.
+ */
+ KASSERT(obj->pages != NULL);
+ mutex_enter(obj->base.gemo_uvmobj.vmobjlock);
+ struct vm_page *const page = uvm_pagelookup(obj->base.gemo_shm_uao, n);
+ mutex_exit(obj->base.gemo_uvmobj.vmobjlock);
+
+ return container_of(page, struct page, p_vmp);
+}
+#else
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
{
struct scatterlist *sg = obj->pages->sgl;
@@ -1534,7 +1557,10 @@ int i915_add_request(struct intel_ring_b
u32 *seqno);
int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
uint32_t seqno);
-#ifndef __NetBSD__ /* XXX */
+#ifdef __NetBSD__ /* XXX */
+int i915_gem_fault(struct uvm_faultinfo *, vaddr_t, struct vm_page **,
+ int, int, vm_prot_t, int);
+#else
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
#endif
int __must_check
Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.1.1.1.2.7 src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.1.1.1.2.8
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.1.1.1.2.7 Sun Sep 8 15:41:41 2013
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c Sun Sep 8 15:52:20 2013
@@ -25,6 +25,21 @@
*
*/
+#ifdef __NetBSD__
+#if 0 /* XXX uvmhist option? */
+#include "opt_uvmhist.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_fault.h>
+#include <uvm/uvm_page.h>
+#include <uvm/uvm_pmap.h>
+#include <uvm/uvm_prot.h>
+#endif
+
#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
@@ -350,6 +365,9 @@ shmem_pread_fast(struct page *page, int
char __user *user_data,
bool page_do_bit17_swizzling, bool needs_clflush)
{
+#ifdef __NetBSD__ /* XXX atomic shmem fast path */
+ return -EFAULT;
+#else
char *vaddr;
int ret;
@@ -366,6 +384,7 @@ shmem_pread_fast(struct page *page, int
kunmap_atomic(vaddr);
return ret ? -EFAULT : 0;
+#endif
}
static void
@@ -431,10 +450,14 @@ i915_gem_shmem_pread(struct drm_device *
int shmem_page_offset, page_length, ret = 0;
int obj_do_bit17_swizzling, page_do_bit17_swizzling;
int hit_slowpath = 0;
+#ifndef __NetBSD__ /* XXX */
int prefaulted = 0;
+#endif
int needs_clflush = 0;
+#ifndef __NetBSD__
struct scatterlist *sg;
int i;
+#endif
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
@@ -463,6 +486,50 @@ i915_gem_shmem_pread(struct drm_device *
offset = args->offset;
+#ifdef __NetBSD__
+ /*
+ * XXX This is a big #ifdef with a lot of duplicated code, but
+ * factoring out the loop head -- which is all that
+ * substantially differs -- is probably more trouble than it's
+ * worth at the moment.
+ */
+ while (0 < remain) {
+ /* Get the next page. */
+ shmem_page_offset = offset_in_page(offset);
+ KASSERT(shmem_page_offset < PAGE_SIZE);
+ page_length = MIN(remain, (PAGE_SIZE - shmem_page_offset));
+ struct page *const page = i915_gem_object_get_page(obj,
+ (offset & ~(PAGE_SIZE-1)));
+
+ /* Decide whether to swizzle bit 17. */
+ page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+ (page_to_phys(page) & (1 << 17)) != 0;
+
+ /* Try the fast path. */
+ ret = shmem_pread_fast(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling, needs_clflush);
+ if (ret == 0)
+ goto next_page;
+
+ /* Fast path failed. Try the slow path. */
+ hit_slowpath = 1;
+ mutex_unlock(&dev->struct_mutex);
+ /* XXX prefault */
+ ret = shmem_pread_slow(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling, needs_clflush);
+ mutex_lock(&dev->struct_mutex);
+
+next_page:
+ /* XXX mark page accessed */
+ if (ret)
+ goto out;
+
+ KASSERT(page_length <= remain);
+ remain -= page_length;
+ user_data += page_length;
+ offset += page_length;
+ }
+#else
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
struct page *page;
@@ -521,6 +588,7 @@ next_page:
user_data += page_length;
offset += page_length;
}
+#endif
out:
i915_gem_object_unpin_pages(obj);
@@ -572,6 +640,7 @@ i915_gem_pread_ioctl(struct drm_device *
goto out;
}
+#ifndef __NetBSD__ /* XXX drm prime */
/* prime objects have no backing filp to GEM pread/pwrite
* pages from.
*/
@@ -579,6 +648,7 @@ i915_gem_pread_ioctl(struct drm_device *
ret = -EINVAL;
goto out;
}
+#endif
trace_i915_gem_object_pread(obj, args->offset, args->size);
@@ -601,6 +671,9 @@ fast_user_write(struct io_mapping *mappi
char __user *user_data,
int length)
{
+#ifdef __NetBSD__ /* XXX atomic shmem fast path */
+ return -EFAULT;
+#else
void __iomem *vaddr_atomic;
void *vaddr;
unsigned long unwritten;
@@ -612,6 +685,7 @@ fast_user_write(struct io_mapping *mappi
user_data, length);
io_mapping_unmap_atomic(vaddr_atomic);
return unwritten;
+#endif
}
/**
@@ -692,6 +766,9 @@ shmem_pwrite_fast(struct page *page, int
bool needs_clflush_before,
bool needs_clflush_after)
{
+#ifdef __NetBSD__
+ return -EFAULT;
+#else
char *vaddr;
int ret;
@@ -711,6 +788,7 @@ shmem_pwrite_fast(struct page *page, int
kunmap_atomic(vaddr);
return ret ? -EFAULT : 0;
+#endif
}
/* Only difference to the fast-path function is that this can handle bit17
@@ -761,8 +839,10 @@ i915_gem_shmem_pwrite(struct drm_device
int hit_slowpath = 0;
int needs_clflush_after = 0;
int needs_clflush_before = 0;
+#ifndef __NetBSD__
int i;
struct scatterlist *sg;
+#endif
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
@@ -797,6 +877,49 @@ i915_gem_shmem_pwrite(struct drm_device
offset = args->offset;
obj->dirty = 1;
+#ifdef __NetBSD__
+ while (0 < remain) {
+ /* Get the next page. */
+ shmem_page_offset = offset_in_page(offset);
+ KASSERT(shmem_page_offset < PAGE_SIZE);
+ page_length = MIN(remain, (PAGE_SIZE - shmem_page_offset));
+ struct page *const page = i915_gem_object_get_page(obj,
+ (offset & ~(PAGE_SIZE-1)));
+
+ /* Decide whether to flush the cache or swizzle bit 17. */
+ const bool partial_cacheline_write = needs_clflush_before &&
+ ((shmem_page_offset | page_length)
+ & (cpu_info_primary.ci_cflush_lsize - 1));
+ page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+ (page_to_phys(page) & (1 << 17)) != 0;
+
+ /* Try the fast path. */
+ ret = shmem_pwrite_fast(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ partial_cacheline_write, needs_clflush_after);
+ if (ret == 0)
+ goto next_page;
+
+ /* Fast path failed. Try the slow path. */
+ hit_slowpath = 1;
+ mutex_unlock(&dev->struct_mutex);
+ ret = shmem_pwrite_slow(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ partial_cacheline_write, needs_clflush_after);
+ mutex_lock(&dev->struct_mutex);
+
+next_page:
+ page->p_vmp.flags &= ~PG_CLEAN;
+ /* XXX mark page accessed */
+ if (ret)
+ goto out;
+
+ KASSERT(page_length <= remain);
+ remain -= page_length;
+ user_data += page_length;
+ offset += page_length;
+ }
+#else
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
struct page *page;
int partial_cacheline_write;
@@ -856,6 +979,7 @@ next_page:
user_data += page_length;
offset += page_length;
}
+#endif
out:
i915_gem_object_unpin_pages(obj);
@@ -899,10 +1023,12 @@ i915_gem_pwrite_ioctl(struct drm_device
args->size))
return -EFAULT;
+#ifndef __NetBSD__ /* XXX prefault */
ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr,
args->size);
if (ret)
return -EFAULT;
+#endif
ret = i915_mutex_lock_interruptible(dev);
if (ret)
@@ -921,6 +1047,7 @@ i915_gem_pwrite_ioctl(struct drm_device
goto out;
}
+#ifndef __NetBSD__ /* XXX drm prime */
/* prime objects have no backing filp to GEM pread/pwrite
* pages from.
*/
@@ -928,6 +1055,7 @@ i915_gem_pwrite_ioctl(struct drm_device
ret = -EINVAL;
goto out;
}
+#endif
trace_i915_gem_object_pwrite(obj, args->offset, args->size);
@@ -969,12 +1097,24 @@ i915_gem_check_wedge(struct drm_i915_pri
if (atomic_read(&dev_priv->mm.wedged)) {
struct completion *x = &dev_priv->error_completion;
bool recovery_complete;
+#ifndef __NetBSD__
unsigned long flags;
+#endif
+#ifdef __NetBSD__
+ /*
+ * XXX This is a horrible kludge. Reading internal
+ * fields is no good, nor is reading them unlocked, and
+ * neither is locking it and then unlocking it before
+ * making a decision.
+ */
+ recovery_complete = x->c_done > 0;
+#else
/* Give the error handler a chance to run. */
spin_lock_irqsave(&x->wait.lock, flags);
recovery_complete = x->done > 0;
spin_unlock_irqrestore(&x->wait.lock, flags);
+#endif
/* Non-interruptible callers can't handle -EAGAIN, hence return
* -EIO unconditionally for these. */
@@ -1316,11 +1456,15 @@ i915_gem_mmap_ioctl(struct drm_device *d
struct drm_i915_gem_mmap *args = data;
struct drm_gem_object *obj;
unsigned long addr;
+#ifdef __NetBSD__
+ int ret;
+#endif
obj = drm_gem_object_lookup(dev, file, args->handle);
if (obj == NULL)
return -ENOENT;
+#ifndef __NetBSD__ /* XXX drm prime */
/* prime objects have no backing filp to GEM mmap
* pages from.
*/
@@ -1328,19 +1472,174 @@ i915_gem_mmap_ioctl(struct drm_device *d
drm_gem_object_unreference_unlocked(obj);
return -EINVAL;
}
+#endif
+#ifdef __NetBSD__
+ addr = (*curproc->p_emul->e_vm_default_addr)(curproc,
+ (vaddr_t)curproc->p_vmspace->vm_daddr, args->size);
+ /* XXX errno NetBSD->Linux */
+ ret = -uvm_map(&curproc->p_vmspace->vm_map, &addr, args->size,
+ obj->gemo_shm_uao, args->offset, 0,
+ UVM_MAPFLAG((VM_PROT_READ | VM_PROT_WRITE),
+ (VM_PROT_READ | VM_PROT_WRITE), UVM_INH_COPY, UVM_ADV_NORMAL,
+ UVM_FLAG_COPYONW));
+ if (ret)
+ return ret;
+#else
addr = vm_mmap(obj->filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
drm_gem_object_unreference_unlocked(obj);
if (IS_ERR((void *)addr))
return addr;
+#endif
args->addr_ptr = (uint64_t) addr;
return 0;
}
+#ifdef __NetBSD__ /* XXX gem gtt fault */
+static int i915_udv_fault(struct uvm_faultinfo *, vaddr_t,
+ struct vm_page **, int, int, vm_prot_t, int, paddr_t);
+
+int
+i915_gem_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr, struct vm_page **pps,
+ int npages, int centeridx, vm_prot_t access_type, int flags)
+{
+ struct uvm_object *uobj = ufi->entry->object.uvm_obj;
+ struct drm_gem_object *gem_obj =
+ container_of(uobj, struct drm_gem_object, gemo_uvmobj);
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ pgoff_t page_offset;
+ int ret = 0;
+ bool write = ISSET(access_type, VM_PROT_WRITE)? 1 : 0;
+
+ page_offset = (ufi->entry->offset + (vaddr - ufi->entry->start)) >>
+ PAGE_SHIFT;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ goto out;
+
+ trace_i915_gem_object_fault(obj, page_offset, true, write);
+
+ /* Now bind it into the GTT if needed */
+ ret = i915_gem_object_pin(obj, 0, true, false);
+ if (ret)
+ goto unlock;
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, write);
+ if (ret)
+ goto unpin;
+
+ ret = i915_gem_object_get_fence(obj);
+ if (ret)
+ goto unpin;
+
+ obj->fault_mappable = true;
+
+ /* Finally, remap it using the new GTT offset */
+ /* XXX errno NetBSD->Linux */
+ ret = -i915_udv_fault(ufi, vaddr, pps, npages, centeridx, access_type,
+ flags, (dev_priv->mm.gtt_base_addr + obj->gtt_offset));
+unpin:
+ i915_gem_object_unpin(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+out:
+ return ret;
+}
+
+/*
+ * XXX i915_udv_fault is copypasta of udv_fault from uvm_device.c.
+ */
+static int
+i915_udv_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr, struct vm_page **pps,
+ int npages, int centeridx, vm_prot_t access_type, int flags,
+ paddr_t gtt_paddr)
+{
+ struct vm_map_entry *entry = ufi->entry;
+ struct uvm_object *uobj = entry->object.uvm_obj;
+ vaddr_t curr_va;
+ off_t curr_offset;
+ paddr_t paddr;
+ u_int mmapflags;
+ int lcv, retval;
+ vm_prot_t mapprot;
+ UVMHIST_FUNC("i915_udv_fault"); UVMHIST_CALLED(maphist);
+ UVMHIST_LOG(maphist," flags=%d", flags,0,0,0);
+
+ /*
+ * we do not allow device mappings to be mapped copy-on-write
+ * so we kill any attempt to do so here.
+ */
+
+ if (UVM_ET_ISCOPYONWRITE(entry)) {
+ UVMHIST_LOG(maphist, "<- failed -- COW entry (etype=0x%x)",
+ entry->etype, 0,0,0);
+ uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj);
+ return(EIO);
+ }
+
+ /*
+ * now we must determine the offset in udv to use and the VA to
+ * use for pmap_enter. note that we always use orig_map's pmap
+ * for pmap_enter (even if we have a submap). since virtual
+ * addresses in a submap must match the main map, this is ok.
+ */
+
+ /* udv offset = (offset from start of entry) + entry's offset */
+ curr_offset = entry->offset + (vaddr - entry->start);
+ /* pmap va = vaddr (virtual address of pps[0]) */
+ curr_va = vaddr;
+
+ /*
+ * loop over the page range entering in as needed
+ */
+
+ retval = 0;
+ for (lcv = 0 ; lcv < npages ; lcv++, curr_offset += PAGE_SIZE,
+ curr_va += PAGE_SIZE) {
+ if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx)
+ continue;
+
+ if (pps[lcv] == PGO_DONTCARE)
+ continue;
+
+ paddr = (gtt_paddr + curr_offset);
+ mmapflags = 0;
+ mapprot = ufi->entry->protection;
+ UVMHIST_LOG(maphist,
+ " MAPPING: device: pm=0x%x, va=0x%x, pa=0x%lx, at=%d",
+ ufi->orig_map->pmap, curr_va, paddr, mapprot);
+ if (pmap_enter(ufi->orig_map->pmap, curr_va, paddr, mapprot,
+ PMAP_CANFAIL | mapprot | mmapflags) != 0) {
+ /*
+ * pmap_enter() didn't have the resource to
+ * enter this mapping. Unlock everything,
+ * wait for the pagedaemon to free up some
+ * pages, and then tell uvm_fault() to start
+ * the fault again.
+ *
+ * XXX Needs some rethinking for the PGO_ALLPAGES
+ * XXX case.
+ */
+ pmap_update(ufi->orig_map->pmap); /* sync what we have so far */
+ uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap,
+ uobj);
+ uvm_wait("i915flt");
+ return (ERESTART);
+ }
+ }
+
+ pmap_update(ufi->orig_map->pmap);
+ uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj);
+ return (retval);
+}
+#else
/**
* i915_gem_fault - fault a page into the GTT
* vma: VMA in question
@@ -1436,6 +1735,7 @@ out:
return VM_FAULT_SIGBUS;
}
}
+#endif
/**
* i915_gem_release_mmap - remove physical page mappings
@@ -1457,10 +1757,21 @@ i915_gem_release_mmap(struct drm_i915_ge
if (!obj->fault_mappable)
return;
+#ifdef __NetBSD__ /* XXX gem gtt fault */
+ {
+ struct vm_page *page;
+
+ KASSERT(obj->pages != NULL);
+ /* Force a fresh fault for each page. */
+ TAILQ_FOREACH(page, &obj->igo_pageq, pageq.queue)
+ pmap_page_protect(page, VM_PROT_NONE);
+ }
+#else
if (obj->base.dev->dev_mapping)
unmap_mapping_range(obj->base.dev->dev_mapping,
(loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
obj->base.size, 1);
+#endif
obj->fault_mappable = false;
}
@@ -1656,10 +1967,22 @@ i915_gem_mmap_gtt_ioctl(struct drm_devic
static void
i915_gem_object_truncate(struct drm_i915_gem_object *obj)
{
+#ifndef __NetBSD__
struct inode *inode;
+#endif
i915_gem_object_free_mmap_offset(obj);
+#ifdef __NetBSD__
+ {
+ struct uvm_object *const uobj = obj->base.gemo_shm_uao;
+
+ if (uobj != NULL)
+ /* XXX Calling pgo_put like this is bogus. */
+ (*uobj->pgops->pgo_put)(uobj, 0, obj->base.size,
+ (PGO_ALLPAGES | PGO_FREE));
+ }
+#else
if (obj->base.filp == NULL)
return;
@@ -1670,6 +1993,7 @@ i915_gem_object_truncate(struct drm_i915
*/
inode = obj->base.filp->f_path.dentry->d_inode;
shmem_truncate_range(inode, 0, (loff_t)-1);
+#endif
obj->madv = __I915_MADV_PURGED;
}
@@ -1680,6 +2004,37 @@ i915_gem_object_is_purgeable(struct drm_
return obj->madv == I915_MADV_DONTNEED;
}
+#ifdef __NetBSD__
+static void
+i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *const dev = obj->base.dev;
+ int ret;
+
+ /* XXX Cargo-culted from the Linux code. */
+ BUG_ON(obj->madv == __I915_MADV_PURGED);
+
+ ret = i915_gem_object_set_to_cpu_domain(obj, true);
+ if (ret) {
+ WARN_ON(ret != -EIO);
+ i915_gem_clflush_object(obj);
+ obj->base.read_domains = obj->base.write_domain =
+ I915_GEM_DOMAIN_CPU;
+ }
+
+ if (i915_gem_object_needs_bit17_swizzle(obj))
+ i915_gem_object_save_bit_17_swizzle(obj);
+
+ /* XXX Maintain dirty flag? */
+
+ bus_dmamap_unload(dev->dmat, obj->igo_dmamap);
+ bus_dmamap_destroy(dev->dmat, obj->igo_dmamap);
+ bus_dmamem_unwire_uvm_object(dev->dmat, obj->base.gemo_shm_uao, 0,
+ obj->base.size, obj->pages, obj->igo_nsegs);
+
+ kfree(obj->pages);
+}
+#else
static void
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
{
@@ -1721,6 +2076,7 @@ i915_gem_object_put_pages_gtt(struct drm
sg_free_table(obj->pages);
kfree(obj->pages);
}
+#endif
static int
i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
@@ -1799,6 +2155,63 @@ i915_gem_shrink_all(struct drm_i915_priv
i915_gem_object_put_pages(obj);
}
+#ifdef __NetBSD__
+static int
+i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *const dev = obj->base.dev;
+ int error;
+
+ /* XXX Cargo-culted from the Linux code. */
+ BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
+ BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
+
+ KASSERT(obj->pages == NULL);
+ TAILQ_INIT(&obj->igo_pageq);
+ obj->pages = kcalloc((obj->base.size / PAGE_SIZE),
+ sizeof(obj->pages[0]), GFP_KERNEL);
+ if (obj->pages == NULL) {
+ error = -ENOMEM;
+ goto fail0;
+ }
+
+ /* XXX errno NetBSD->Linux */
+ error = -bus_dmamem_wire_uvm_object(dev->dmat, obj->base.gemo_shm_uao,
+ 0, obj->base.size, &obj->igo_pageq, PAGE_SIZE, 0, obj->pages,
+ (obj->base.size / PAGE_SIZE), &obj->igo_nsegs, BUS_DMA_NOWAIT);
+ if (error)
+ /* XXX Try i915_gem_purge, i915_gem_shrink_all. */
+ goto fail1;
+ KASSERT(0 < obj->igo_nsegs);
+ KASSERT(obj->igo_nsegs <= (obj->base.size / PAGE_SIZE));
+
+ /* XXX errno NetBSD->Linux */
+ error = -bus_dmamap_create(dev->dmat, obj->base.size, obj->igo_nsegs,
+ PAGE_SIZE, 0, BUS_DMA_NOWAIT, &obj->igo_dmamap);
+ if (error)
+ goto fail2;
+
+ /* XXX errno NetBSD->Linux */
+ error = -bus_dmamap_load_raw(dev->dmat, obj->igo_dmamap, obj->pages,
+ obj->igo_nsegs, obj->base.size, BUS_DMA_NOWAIT);
+ if (error)
+ goto fail3;
+
+ /* XXX Cargo-culted from the Linux code. */
+ if (i915_gem_object_needs_bit17_swizzle(obj))
+ i915_gem_object_do_bit_17_swizzle(obj);
+
+ /* Success! */
+ return 0;
+
+fail3: bus_dmamap_destroy(dev->dmat, obj->igo_dmamap);
+fail2: bus_dmamem_unwire_uvm_object(dev->dmat, obj->base.gemo_shm_uao, 0,
+ obj->base.size, obj->pages, (obj->base.size / PAGE_SIZE));
+fail1: kfree(obj->pages);
+ obj->pages = NULL;
+fail0: return error;
+}
+#else
static int
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
{
@@ -1877,6 +2290,7 @@ err_pages:
kfree(st);
return PTR_ERR(page);
}
+#endif
/* Ensure that the associated pages are gathered from the backing storage
* and pinned into our object. i915_gem_object_get_pages() may be called
@@ -3065,7 +3479,11 @@ i915_gem_clflush_object(struct drm_i915_
trace_i915_gem_object_clflush(obj);
+#ifdef __NetBSD__
+ drm_clflush_pglist(&obj->igo_pageq);
+#else
drm_clflush_sg(obj->pages);
+#endif
}
/** Flushes the GTT write domain for the object if it's dirty. */
@@ -3738,8 +4156,10 @@ struct drm_i915_gem_object *i915_gem_all
size_t size)
{
struct drm_i915_gem_object *obj;
+#ifndef __NetBSD__ /* XXX >32bit dma? */
struct address_space *mapping;
u32 mask;
+#endif
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL)
@@ -3750,6 +4170,7 @@ struct drm_i915_gem_object *i915_gem_all
return NULL;
}
+#ifndef __NetBSD__ /* XXX >32bit dma? */
mask = GFP_HIGHUSER | __GFP_RECLAIMABLE;
if (IS_CRESTLINE(dev) || IS_BROADWATER(dev)) {
/* 965gm cannot relocate objects above 4GiB. */
@@ -3759,6 +4180,7 @@ struct drm_i915_gem_object *i915_gem_all
mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
mapping_set_gfp_mask(mapping, mask);
+#endif
i915_gem_object_init(obj, &i915_gem_object_ops);
@@ -3821,8 +4243,10 @@ void i915_gem_free_object(struct drm_gem
BUG_ON(obj->pages);
+#ifndef __NetBSD__ /* XXX drm prime */
if (obj->base.import_attach)
drm_prime_gem_destroy(&obj->base, NULL);
+#endif
drm_gem_object_release(&obj->base);
i915_gem_info_remove_obj(dev_priv, obj->base.size);
@@ -3997,6 +4421,9 @@ cleanup_render_ring:
static bool
intel_enable_ppgtt(struct drm_device *dev)
{
+#ifdef __NetBSD__ /* XXX ppgtt */
+ return false;
+#else
if (i915_enable_ppgtt >= 0)
return i915_enable_ppgtt;
@@ -4007,6 +4434,7 @@ intel_enable_ppgtt(struct drm_device *de
#endif
return true;
+#endif
}
int i915_gem_init(struct drm_device *dev)
@@ -4183,7 +4611,11 @@ i915_gem_load(struct drm_device *dev)
i915_gem_reset_fences(dev);
i915_gem_detect_bit_6_swizzle(dev);
+#ifdef __NetBSD__
+ DRM_INIT_WAITQUEUE(&dev_priv->pending_flip_queue, "i915flip");
+#else
init_waitqueue_head(&dev_priv->pending_flip_queue);
+#endif
dev_priv->mm.interruptible = true;
@@ -4217,9 +4649,11 @@ static int i915_gem_init_phys_object(str
ret = -ENOMEM;
goto kfree_obj;
}
+#ifndef __NetBSD__ /* XXX x86 wc? */
#ifdef CONFIG_X86
set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
+#endif
dev_priv->mm.phys_objs[id - 1] = phys_obj;
@@ -4242,9 +4676,11 @@ static void i915_gem_free_phys_object(st
i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
}
+#ifndef __NetBSD__ /* XXX x86 wb? */
#ifdef CONFIG_X86
set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
+#endif
drm_pci_free(dev, phys_obj->handle);
kfree(phys_obj);
dev_priv->mm.phys_objs[id - 1] = NULL;
@@ -4261,7 +4697,9 @@ void i915_gem_free_all_phys_object(struc
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_i915_gem_object *obj)
{
+#ifndef __NetBSD__
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+#endif
char *vaddr;
int i;
int page_count;
@@ -4272,6 +4710,36 @@ void i915_gem_detach_phys_object(struct
page_count = obj->base.size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
+#ifdef __NetBSD__
+ /* XXX Just use ubc_uiomove? */
+ struct pglist pages;
+ int error;
+
+ TAILQ_INIT(&pages);
+ error = uvm_obj_wirepages(obj->base.gemo_shm_uao, i*PAGE_SIZE,
+ (i+1)*PAGE_SIZE, &pages);
+ if (error) {
+ printf("unable to map page %d of i915 gem obj: %d\n",
+ i, error);
+ continue;
+ }
+
+ KASSERT(!TAILQ_EMPTY(&pages));
+ struct vm_page *const page = TAILQ_FIRST(&pages);
+ TAILQ_REMOVE(&pages, page, pageq.queue);
+ KASSERT(TAILQ_EMPTY(&pages));
+
+ char *const dst = kmap_atomic(container_of(page, struct page,
+ p_vmp));
+ (void)memcpy(dst, vaddr + (i*PAGE_SIZE), PAGE_SIZE);
+ kunmap_atomic(dst);
+
+ drm_clflush_page(container_of(page, struct page, p_vmp));
+ page->flags &= ~PG_CLEAN;
+ /* XXX mark page accessed */
+ uvm_obj_unwirepages(obj->base.gemo_shm_uao, i*PAGE_SIZE,
+ (i+1)*PAGE_SIZE);
+#else
struct page *page = shmem_read_mapping_page(mapping, i);
if (!IS_ERR(page)) {
char *dst = kmap_atomic(page);
@@ -4284,6 +4752,7 @@ void i915_gem_detach_phys_object(struct
mark_page_accessed(page);
page_cache_release(page);
}
+#endif
}
i915_gem_chipset_flush(dev);
@@ -4297,7 +4766,9 @@ i915_gem_attach_phys_object(struct drm_d
int id,
int align)
{
+#ifndef __NetBSD__
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+#endif
drm_i915_private_t *dev_priv = dev->dev_private;
int ret = 0;
int page_count;
@@ -4330,6 +4801,32 @@ i915_gem_attach_phys_object(struct drm_d
page_count = obj->base.size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
+#ifdef __NetBSD__
+ char *const vaddr = obj->phys_obj->handle->vaddr;
+ struct pglist pages;
+ int error;
+
+ TAILQ_INIT(&pages);
+ error = uvm_obj_wirepages(obj->base.gemo_shm_uao, i*PAGE_SIZE,
+ (i+1)*PAGE_SIZE, &pages);
+ if (error)
+ /* XXX errno NetBSD->Linux */
+ return -error;
+
+ KASSERT(!TAILQ_EMPTY(&pages));
+ struct vm_page *const page = TAILQ_FIRST(&pages);
+ TAILQ_REMOVE(&pages, page, pageq.queue);
+ KASSERT(TAILQ_EMPTY(&pages));
+
+ char *const src = kmap_atomic(container_of(page, struct page,
+ p_vmp));
+ (void)memcpy(vaddr + (i*PAGE_SIZE), src, PAGE_SIZE);
+ kunmap_atomic(src);
+
+ /* XXX mark page accessed */
+ uvm_obj_unwirepages(obj->base.gemo_shm_uao, i*PAGE_SIZE,
+ (i+1)*PAGE_SIZE);
+#else
struct page *page;
char *dst, *src;
@@ -4344,6 +4841,7 @@ i915_gem_attach_phys_object(struct drm_d
mark_page_accessed(page);
page_cache_release(page);
+#endif
}
return 0;
@@ -4355,7 +4853,7 @@ i915_gem_phys_pwrite(struct drm_device *
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- void *vaddr = obj->phys_obj->handle->vaddr + args->offset;
+ void *vaddr = (char *)obj->phys_obj->handle->vaddr + args->offset;
char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
@@ -4397,6 +4895,7 @@ void i915_gem_release(struct drm_device
spin_unlock(&file_priv->mm.lock);
}
+#ifndef __NetBSD__ /* XXX */
static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
{
if (!mutex_is_locked(mutex))
@@ -4409,10 +4908,14 @@ static bool mutex_is_locked_by(struct mu
return false;
#endif
}
+#endif
static int
i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
{
+#ifdef __NetBSD__ /* XXX shrinkers */
+ return 0;
+#else
struct drm_i915_private *dev_priv =
container_of(shrinker,
struct drm_i915_private,
@@ -4453,4 +4956,5 @@ i915_gem_inactive_shrink(struct shrinker
if (unlock)
mutex_unlock(&dev->struct_mutex);
return cnt;
+#endif
}
Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c:1.1.1.1.2.3 src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c:1.1.1.1.2.4
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c:1.1.1.1.2.3 Sun Sep 8 15:42:12 2013
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_execbuffer.c Sun Sep 8 15:52:20 2013
@@ -101,6 +101,19 @@ static inline int use_cpu_reloc(struct d
obj->cache_level != I915_CACHE_NONE);
}
+#ifdef __NetBSD__
+# define __gtt_iomem
+# define __iomem __gtt_iomem
+
+static inline void
+iowrite32(uint32_t value, uint32_t __acpi_iomem *ptr)
+{
+
+ __insn_barrier();
+ *ptr = value;
+}
+#endif
+
static int
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
struct eb_objects *eb,
@@ -190,9 +203,11 @@ i915_gem_execbuffer_relocate_entry(struc
return ret;
}
+#ifndef __NetBSD__ /* XXX atomic GEM reloc fast path */
/* We can't wait for rendering with pagefaults disabled */
if (obj->active && in_atomic())
return -EFAULT;
+#endif
reloc->delta += target_offset;
if (use_cpu_reloc(obj)) {
@@ -225,9 +240,13 @@ i915_gem_execbuffer_relocate_entry(struc
reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
reloc->offset & PAGE_MASK);
reloc_entry = (uint32_t __iomem *)
- (reloc_page + (reloc->offset & ~PAGE_MASK));
+ ((char *)reloc_page + (reloc->offset & ~PAGE_MASK));
iowrite32(reloc->delta, reloc_entry);
+#ifdef __NetBSD__ /* XXX io mapping */
+ io_mapping_unmap_atomic(dev_priv->mm.gtt_mapping, reloc_page);
+#else
io_mapping_unmap_atomic(reloc_page);
+#endif
}
/* and update the user's relocation entry */
@@ -236,6 +255,12 @@ i915_gem_execbuffer_relocate_entry(struc
return 0;
}
+#ifdef __NetBSD__
+# undef __gtt_iomem
+# undef __iomem
+#endif
+
+#ifndef __NetBSD__ /* XXX atomic GEM reloc fast path */
static int
i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
struct eb_objects *eb)
@@ -281,6 +306,7 @@ i915_gem_execbuffer_relocate_object(stru
return 0;
#undef N_RELOC
}
+#endif
static int
i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
@@ -304,9 +330,14 @@ i915_gem_execbuffer_relocate(struct drm_
struct eb_objects *eb,
struct list_head *objects)
{
+#ifndef __NetBSD__
struct drm_i915_gem_object *obj;
+#endif
int ret = 0;
+#ifdef __NetBSD__ /* XXX atomic GEM reloc fast path */
+ ret = -EFAULT;
+#else
/* This is the fast path and we cannot handle a pagefault whilst
* holding the struct mutex lest the user pass in the relocations
* contained within a mmaped bo. For in such a case we, the page
@@ -321,6 +352,7 @@ i915_gem_execbuffer_relocate(struct drm_
break;
}
pagefault_enable();
+#endif
return ret;
}
@@ -826,8 +858,13 @@ i915_gem_do_execbuffer(struct drm_device
flags = 0;
if (args->flags & I915_EXEC_SECURE) {
+#ifdef __NetBSD__
+ if (!file->is_master || !DRM_SUSER())
+ return -EPERM;
+#else
if (!file->is_master || !capable(CAP_SYS_ADMIN))
return -EPERM;
+#endif
flags |= I915_DISPATCH_SECURE;
}
Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c:1.1.1.1.2.2 src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c:1.1.1.1.2.3
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c:1.1.1.1.2.2 Tue Jul 23 21:28:22 2013
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_gem_tiling.c Sun Sep 8 15:52:20 2013
@@ -472,13 +472,30 @@ i915_gem_swizzle_page(struct page *page)
void
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
+#ifdef __NetBSD__
+ struct vm_page *page;
+#else
struct scatterlist *sg;
int page_count = obj->base.size >> PAGE_SHIFT;
+#endif
int i;
if (obj->bit_17 == NULL)
return;
+#ifdef __NetBSD__
+ i = 0;
+ TAILQ_FOREACH(page, &obj->igo_pageq, pageq.queue) {
+ unsigned char new_bit_17 = VM_PAGE_TO_PHYS(page) >> 17;
+ if ((new_bit_17 & 0x1) !=
+ (test_bit(i, obj->bit_17) != 0)) {
+ i915_gem_swizzle_page(container_of(page, struct page,
+ p_vmp));
+ page->flags &= ~PG_CLEAN;
+ }
+ i += 1;
+ }
+#else
for_each_sg(obj->pages->sgl, sg, page_count, i) {
struct page *page = sg_page(sg);
char new_bit_17 = page_to_phys(page) >> 17;
@@ -488,12 +505,17 @@ i915_gem_object_do_bit_17_swizzle(struct
set_page_dirty(page);
}
}
+#endif
}
void
i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
+#ifdef __NetBSD__
+ struct vm_page *page;
+#else
struct scatterlist *sg;
+#endif
int page_count = obj->base.size >> PAGE_SHIFT;
int i;
@@ -507,6 +529,16 @@ i915_gem_object_save_bit_17_swizzle(stru
}
}
+#ifdef __NetBSD__
+ i = 0;
+ TAILQ_FOREACH(page, &obj->igo_pageq, pageq.queue) {
+ if (ISSET(VM_PAGE_TO_PHYS(page), __BIT(17)))
+ __set_bit(i, obj->bit_17);
+ else
+ __clear_bit(i, obj->bit_17);
+ i += 1;
+ }
+#else
for_each_sg(obj->pages->sgl, sg, page_count, i) {
struct page *page = sg_page(sg);
if (page_to_phys(page) & (1 << 17))
@@ -514,4 +546,5 @@ i915_gem_object_save_bit_17_swizzle(stru
else
__clear_bit(i, obj->bit_17);
}
+#endif
}
Index: src/sys/modules/i915drm2/Makefile
diff -u src/sys/modules/i915drm2/Makefile:1.1.2.8 src/sys/modules/i915drm2/Makefile:1.1.2.9
--- src/sys/modules/i915drm2/Makefile:1.1.2.8 Wed Jul 24 03:52:13 2013
+++ src/sys/modules/i915drm2/Makefile Sun Sep 8 15:52:20 2013
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.1.2.8 2013/07/24 03:52:13 riastradh Exp $
+# $NetBSD: Makefile,v 1.1.2.9 2013/09/08 15:52:20 riastradh Exp $
.include "../Makefile.inc"
.include "../drm2/Makefile.inc"
@@ -20,15 +20,15 @@ SRCS+= dvo_tfp410.c
#SRCS+= i915_debugfs.c # XXX No debugfs in NetBSD.
SRCS+= i915_dma.c
SRCS+= i915_drv.c
-SRCS+= i915_gem.c # XXX overridden for now
-#SRCS+= i915_gem_context.c
-#SRCS+= i915_gem_debug.c
+SRCS+= i915_gem.c
+SRCS+= i915_gem_context.c
+SRCS+= i915_gem_debug.c
#SRCS+= i915_gem_dmabuf.c
-#SRCS+= i915_gem_evict.c
-#SRCS+= i915_gem_execbuffer.c
-#SRCS+= i915_gem_gtt.c
-#SRCS+= i915_gem_stolen.c
-#SRCS+= i915_gem_tiling.c
+SRCS+= i915_gem_evict.c
+SRCS+= i915_gem_execbuffer.c
+SRCS+= i915_gem_gtt.c
+SRCS+= i915_gem_stolen.c
+SRCS+= i915_gem_tiling.c
#SRCS+= i915_ioc32.c
SRCS+= i915_irq.c
SRCS+= i915_suspend.c
@@ -55,5 +55,6 @@ SRCS+= intel_tv.c
SRCS+= i915_module.c
SRCS+= i915_pci.c
+SRCS+= intel_gtt.c
.include <bsd.kmodule.mk>
Added files:
Index: src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c
diff -u /dev/null src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c:1.1.2.1
--- /dev/null Sun Sep 8 15:52:20 2013
+++ src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c Sun Sep 8 15:52:20 2013
@@ -0,0 +1,432 @@
+/* $NetBSD: i915_gem_gtt.c,v 1.1.2.1 2013/09/08 15:52:20 riastradh Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: i915_gem_gtt.c,v 1.1.2.1 2013/09/08 15:52:20 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <drm/drmP.h>
+
+#include "i915_drv.h"
+
+static void i915_gtt_color_adjust(struct drm_mm_node *, unsigned long,
+ unsigned long *, unsigned long *);
+static void i915_ggtt_clear_range(struct drm_device *, unsigned, unsigned);
+static void gen6_ggtt_bind_object(struct drm_i915_gem_object *,
+ enum i915_cache_level);
+static void gen6_ggtt_clear_range(struct drm_device *, unsigned, unsigned);
+
+#define SNB_GMCH_GGMS (SNB_GMCH_GGMS_MASK << SNB_GMCH_GGMS_SHIFT)
+#define SNB_GMCH_GMS (SNB_GMCH_GMS_MASK << SNB_GMCH_GMS_SHIFT)
+#define IVB_GMCH_GMS (IVB_GMCH_GMS_MASK << IVB_GMCH_GMS_SHIFT)
+
+typedef uint32_t gtt_pte_t;
+
+#define GEN6_PTE_VALID __BIT(0)
+#define GEN6_PTE_UNCACHED __BIT(1)
+#define HSW_PTE_UNCACHED (0)
+#define GEN6_PTE_CACHE_LLC __BIT(2)
+#define GEN6_PTE_CACHE_LLC_MLC __BIT(3)
+
+static uint32_t
+gen6_pte_addr_encode(bus_addr_t addr)
+{
+ /* XXX KASSERT bounds? Must be at most 36-bit, it seems. */
+ return (addr | ((addr >> 28) & 0xff0));
+}
+
+static gtt_pte_t
+pte_encode(struct drm_device *dev, bus_addr_t addr,
+ enum i915_cache_level level)
+{
+ uint32_t flags = GEN6_PTE_VALID;
+
+ switch (level) {
+ case I915_CACHE_LLC_MLC:
+ flags |= (IS_HASWELL(dev)? GEN6_PTE_CACHE_LLC
+ : GEN6_PTE_CACHE_LLC_MLC);
+ break;
+
+ case I915_CACHE_LLC:
+ flags |= GEN6_PTE_CACHE_LLC;
+ break;
+
+ case I915_CACHE_NONE:
+ flags |= (IS_HASWELL(dev)? HSW_PTE_UNCACHED
+ : GEN6_PTE_UNCACHED);
+ break;
+
+ default:
+ panic("invalid i915 GTT cache level: %d", (int)level);
+ break;
+ }
+
+ return (gen6_pte_addr_encode(addr) | flags);
+}
+
+int
+i915_gem_gtt_init(struct drm_device *dev)
+{
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+ struct pci_attach_args *const pa = &dev->pdev->pd_pa;
+ struct intel_gtt *gtt;
+ uint16_t snb_gmch_ctl, ggms, gms;
+ int nsegs;
+ int ret;
+
+ if (INTEL_INFO(dev)->gen < 6) {
+ /* XXX gen<6 */
+ DRM_ERROR("device is too old for drm2 for now!\n");
+ return -ENODEV;
+ }
+
+ gtt = kmem_zalloc(sizeof(*gtt), KM_NOSLEEP);
+
+ /* XXX pci_set_dma_mask? pci_set_consistent_dma_mask? */
+ drm_limit_dma_space(dev, 0, 0x0000000fffffffffULL);
+
+ gtt->gma_bus_addr = dev->bus_maps[2].bm_base;
+
+ snb_gmch_ctl = pci_conf_read(pa->pa_pc, pa->pa_tag, SNB_GMCH_CTRL);
+
+ /* GMS: Graphics Mode Select. */
+ if (INTEL_INFO(dev)->gen < 7) {
+ gms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GMS);
+ gtt->stolen_size = (gms << 25);
+ } else {
+ gms = __SHIFTOUT(snb_gmch_ctl, IVB_GMCH_GMS);
+ static const unsigned sizes[] = {
+ 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352
+ };
+ gtt->stolen_size = sizes[gms] << 20;
+ }
+
+ /* GGMS: GTT Graphics Memory Size. */
+ ggms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GGMS) << 20;
+ gtt->gtt_total_entries = (ggms << 20) / sizeof(gtt_pte_t);
+
+ gtt->gtt_mappable_entries = (dev->bus_maps[2].bm_size >> PAGE_SHIFT);
+ if (((gtt->gtt_mappable_entries >> 8) < 64) ||
+ (gtt->gtt_total_entries < gtt->gtt_mappable_entries)) {
+ DRM_ERROR("unknown GMADR entries: %d\n",
+ gtt->gtt_mappable_entries);
+ ret = -ENXIO;
+ goto fail0;
+ }
+
+ /* XXX errno NetBSD->Linux */
+ ret = -bus_dmamem_alloc(dev->dmat, PAGE_SIZE, PAGE_SIZE, 0,
+ >t->gtt_scratch_seg, 1, &nsegs, 0);
+ if (ret)
+ goto fail0;
+ KASSERT(nsegs == 1);
+
+ /* XXX errno NetBSD->Linux */
+ ret = -bus_dmamap_create(dev->dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 0,
+ >t->gtt_scratch_map);
+ if (ret)
+ goto fail1;
+
+ /* XXX errno NetBSD->Linux */
+ ret = -bus_dmamap_load_raw(dev->dmat, gtt->gtt_scratch_map,
+ >t->gtt_scratch_seg, 1, PAGE_SIZE, BUS_DMA_NOCACHE);
+ if (ret)
+ goto fail2;
+
+ /* Linux sez: For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
+ if (dev->bus_maps[0].bm_size < (gtt->gtt_total_entries *
+ sizeof(gtt_pte_t))) {
+ DRM_ERROR("BAR0 too small for GTT: 0x%"PRIxMAX" < 0x%"PRIxMAX
+ "\n",
+ dev->bus_maps[0].bm_size,
+ (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
+ ret = -ENODEV;
+ goto fail3;
+ }
+ if (bus_space_map(dev->bst, (dev->bus_maps[0].bm_base + (2<<20)),
+ (gtt->gtt_total_entries * sizeof(gtt_pte_t)),
+ 0,
+ >t->gtt_bsh)) {
+ DRM_ERROR("unable to map GTT\n");
+ ret = -ENODEV;
+ goto fail3;
+ }
+
+ DRM_INFO("Memory usable by graphics device = %dM\n",
+ gtt->gtt_total_entries >> 8);
+ DRM_DEBUG_DRIVER("GMADR size = %dM\n", gtt->gtt_mappable_entries >> 8);
+ DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", gtt->stolen_size >> 20);
+
+ /* Success! */
+ dev_priv->mm.gtt = gtt;
+ return 0;
+
+fail3: bus_dmamap_unload(dev->dmat, gtt->gtt_scratch_map);
+fail2: bus_dmamap_destroy(dev->dmat, gtt->gtt_scratch_map);
+fail1: bus_dmamem_free(dev->dmat, >t->gtt_scratch_seg, 1);
+fail0: kmem_free(gtt, sizeof(*gtt));
+ return ret;
+}
+
+void
+i915_gem_gtt_fini(struct drm_device *dev)
+{
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+ struct intel_gtt *const gtt = dev_priv->mm.gtt;
+
+ bus_space_unmap(dev->bst, gtt->gtt_bsh,
+ (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
+ bus_dmamap_unload(dev->dmat, gtt->gtt_scratch_map);
+ bus_dmamap_destroy(dev->dmat, gtt->gtt_scratch_map);
+ bus_dmamem_free(dev->dmat, >t->gtt_scratch_seg, 1);
+ kmem_free(gtt, sizeof(*gtt));
+}
+
+void
+i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start,
+ unsigned long mappable_end, unsigned long end)
+{
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+
+ KASSERT(start <= end);
+ KASSERT(start <= mappable_end);
+ KASSERT(PAGE_SIZE <= (end - start));
+ drm_mm_init(&dev_priv->mm.gtt_space, start, (end - start - PAGE_SIZE));
+ if (!HAS_LLC(dev))
+ dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
+
+ dev_priv->mm.gtt_start = start;
+ dev_priv->mm.gtt_mappable_end = mappable_end;
+ dev_priv->mm.gtt_end = end;
+ dev_priv->mm.gtt_total = (end - start);
+ dev_priv->mm.mappable_gtt_total = (MIN(end, mappable_end) - start);
+
+ i915_ggtt_clear_range(dev, (start >> PAGE_SHIFT),
+ ((end - start) >> PAGE_SHIFT));
+}
+
+static void
+i915_gtt_color_adjust(struct drm_mm_node *node, unsigned long color,
+ unsigned long *start, unsigned long *end)
+{
+
+ if (node->color != color)
+ *start += PAGE_SIZE;
+ if (list_empty(&node->node_list))
+ return;
+ node = list_entry(node->node_list.next, struct drm_mm_node, node_list);
+ if (node->allocated && (node->color != color))
+ *end -= PAGE_SIZE;
+}
+
+void
+i915_gem_init_ppgtt(struct drm_device *dev __unused)
+{
+}
+
+int
+i915_gem_init_aliasing_ppgtt(struct drm_device *dev __unused)
+{
+ return -ENODEV;
+}
+
+void
+i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev __unused)
+{
+}
+
+void
+i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt __unused,
+ struct drm_i915_gem_object *obj __unused,
+ enum i915_cache_level cache_level __unused)
+{
+ panic("%s: not implemented", __func__);
+}
+
+void
+i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt __unused,
+ struct drm_i915_gem_object *obj __unused)
+{
+ panic("%s: not implemented", __func__);
+}
+
+int
+i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *const dev = obj->base.dev;
+ int error;
+
+ if (obj->has_dma_mapping)
+ return 0;
+
+ /* XXX errno NetBSD->Linux */
+ error = -bus_dmamap_load_raw(dev->dmat, obj->igo_dmamap, obj->pages,
+ obj->igo_nsegs, obj->base.size, BUS_DMA_NOWAIT);
+ if (error)
+ goto fail0;
+
+ /* Success! */
+ return 0;
+
+fail0: return error;
+}
+
+void
+i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
+ enum i915_cache_level cache_level)
+{
+
+ KASSERT(6 < INTEL_INFO(obj->base.dev)->gen); /* XXX gen<6 */
+ gen6_ggtt_bind_object(obj, cache_level);
+ obj->has_global_gtt_mapping = 1;
+}
+
+void
+i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
+{
+
+ i915_ggtt_clear_range(obj->base.dev,
+ (obj->gtt_space->start >> PAGE_SHIFT),
+ (obj->base.size >> PAGE_SHIFT));
+ obj->has_global_gtt_mapping = 0;
+}
+
+void
+i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *const dev = obj->base.dev;
+
+ /* XXX Idle, for gen<6. */
+
+ if (obj->has_dma_mapping)
+ return;
+
+ bus_dmamap_unload(dev->dmat, obj->igo_dmamap);
+}
+
+void
+i915_gem_restore_gtt_mappings(struct drm_device *dev)
+{
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+
+ i915_ggtt_clear_range(dev, (dev_priv->mm.gtt_start >> PAGE_SHIFT),
+ ((dev_priv->mm.gtt_start - dev_priv->mm.gtt_end) >> PAGE_SHIFT));
+
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ i915_gem_clflush_object(obj);
+ i915_gem_gtt_bind_object(obj, obj->cache_level);
+ }
+
+ i915_gem_chipset_flush(dev);
+}
+
+static void
+i915_ggtt_clear_range(struct drm_device *dev, unsigned start_page,
+ unsigned npages)
+{
+
+ KASSERT(6 <= INTEL_INFO(dev)->gen);
+
+ gen6_ggtt_clear_range(dev, start_page, npages);
+}
+
+static void
+gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
+ enum i915_cache_level cache_level)
+{
+ struct drm_device *const dev = obj->base.dev;
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+ const bus_space_tag_t bst = dev->bst;
+ const bus_space_handle_t bsh = dev_priv->mm.gtt->gtt_bsh;
+ const unsigned first_entry = obj->gtt_space->start >> PAGE_SHIFT;
+ bus_addr_t addr;
+ bus_size_t len;
+ unsigned int seg, i = 0;
+
+ for (seg = 0; seg < obj->igo_dmamap->dm_nsegs; seg++) {
+ addr = obj->igo_dmamap->dm_segs[seg].ds_addr;
+ len = obj->igo_dmamap->dm_segs[seg].ds_len;
+ do {
+ KASSERT(PAGE_SIZE <= len);
+ bus_space_write_4(bst, bsh, 4*(first_entry + i),
+ pte_encode(dev, addr, cache_level));
+ addr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ i += 1;
+ } while (0 < len);
+ }
+
+ KASSERT(first_entry <= dev_priv->mm.gtt->gtt_total_entries);
+ KASSERT(i <= (dev_priv->mm.gtt->gtt_total_entries - first_entry));
+ KASSERT(i == (obj->base.size >> PAGE_SHIFT));
+
+ /* XXX Why could i ever be zero? */
+ if (0 < i) {
+ /* Posting read and sanity check. */
+ /* XXX Shouldn't there be a bus_space_sync? */
+ const uint32_t expected = pte_encode(dev, addr, cache_level);
+ const uint32_t actual = bus_space_read_4(bst, bsh,
+ (first_entry + (4*(i-1))));
+ if (actual != expected)
+ aprint_error_dev(dev->dev, "mismatched PTE"
+ ": 0x%"PRIxMAX" != 0x%"PRIxMAX"\n",
+ (uintmax_t)actual, (uintmax_t)expected);
+ }
+
+ I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
+ POSTING_READ(GFX_FLSH_CNTL_GEN6);
+}
+
+static void
+gen6_ggtt_clear_range(struct drm_device *dev, unsigned start_page,
+ unsigned npages)
+{
+ struct drm_i915_private *const dev_priv = dev->dev_private;
+ const bus_space_tag_t bst = dev->bst;
+ const bus_space_handle_t bsh = dev_priv->mm.gtt->gtt_bsh;
+ const unsigned n = (dev_priv->mm.gtt->gtt_total_entries - start_page);
+ const gtt_pte_t scratch_pte = pte_encode(dev,
+ dev_priv->mm.gtt->gtt_scratch_map->dm_segs[0].ds_addr,
+ I915_CACHE_LLC);
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ bus_space_write_4(bst, bsh, 4*(start_page + i), scratch_pte);
+ bus_space_read_4(bst, bsh, 4*start_page);
+}
Index: src/sys/external/bsd/drm2/i915drm/intel_gtt.c
diff -u /dev/null src/sys/external/bsd/drm2/i915drm/intel_gtt.c:1.1.2.1
--- /dev/null Sun Sep 8 15:52:20 2013
+++ src/sys/external/bsd/drm2/i915drm/intel_gtt.c Sun Sep 8 15:52:20 2013
@@ -0,0 +1,48 @@
+/* $NetBSD: intel_gtt.c,v 1.1.2.1 2013/09/08 15:52:20 riastradh Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Intel GTT stubs */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: intel_gtt.c,v 1.1.2.1 2013/09/08 15:52:20 riastradh Exp $");
+
+#include "drm/intel-gtt.h"
+
+bool
+intel_enable_gtt(void)
+{
+ return false;
+}
+
+void
+intel_gtt_chipset_flush(void)
+{
+}