summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/xf86drm.c12
-rw-r--r--linux-core/ati_pcigart.c69
-rw-r--r--linux-core/drmP.h3
-rw-r--r--linux-core/drm_compat.c107
-rw-r--r--linux-core/drm_compat.h23
-rw-r--r--linux-core/drm_fence.c75
-rw-r--r--linux-core/drm_vm.c81
-rw-r--r--linux-core/i915_fence.c18
-rw-r--r--shared-core/drm.h14
-rw-r--r--shared-core/drm_pciids.txt1
-rw-r--r--shared-core/nouveau_drm.h29
-rw-r--r--shared-core/nouveau_drv.h13
-rw-r--r--shared-core/nouveau_fifo.c9
-rw-r--r--shared-core/nouveau_irq.c64
-rw-r--r--shared-core/nouveau_mem.c4
-rw-r--r--shared-core/nouveau_object.c234
-rw-r--r--shared-core/nouveau_reg.h10
-rw-r--r--shared-core/nouveau_state.c13
-rw-r--r--shared-core/nv40_graph.c8
-rw-r--r--shared-core/r128_cce.c1
-rw-r--r--shared-core/r128_drv.h2
-rw-r--r--shared-core/radeon_cp.c6
-rw-r--r--shared-core/radeon_drm.h1
-rw-r--r--shared-core/radeon_drv.h4
-rw-r--r--shared-core/radeon_state.c6
25 files changed, 471 insertions, 336 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 862772d5..a815ed7a 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -585,9 +585,9 @@ int drmOpen(const char *name, const char *busid)
void drmFreeVersion(drmVersionPtr v)
{
if (!v) return;
- if (v->name) drmFree(v->name);
- if (v->date) drmFree(v->date);
- if (v->desc) drmFree(v->desc);
+ drmFree(v->name);
+ drmFree(v->date);
+ drmFree(v->desc);
drmFree(v);
}
@@ -604,9 +604,9 @@ void drmFreeVersion(drmVersionPtr v)
static void drmFreeKernelVersion(drm_version_t *v)
{
if (!v) return;
- if (v->name) drmFree(v->name);
- if (v->date) drmFree(v->date);
- if (v->desc) drmFree(v->desc);
+ drmFree(v->name);
+ drmFree(v->date);
+ drmFree(v->desc);
drmFree(v);
}
diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c
index bbdb841c..bb30dd74 100644
--- a/linux-core/ati_pcigart.c
+++ b/linux-core/ati_pcigart.c
@@ -33,41 +33,25 @@
#include "drmP.h"
-#if PAGE_SIZE == 65536
-# define ATI_PCIGART_TABLE_ORDER 0
-# define ATI_PCIGART_TABLE_PAGES (1 << 0)
-#elif PAGE_SIZE == 16384
-# define ATI_PCIGART_TABLE_ORDER 1
-# define ATI_PCIGART_TABLE_PAGES (1 << 1)
-#elif PAGE_SIZE == 8192
-# define ATI_PCIGART_TABLE_ORDER 2
-# define ATI_PCIGART_TABLE_PAGES (1 << 2)
-#elif PAGE_SIZE == 4096
-# define ATI_PCIGART_TABLE_ORDER 3
-# define ATI_PCIGART_TABLE_PAGES (1 << 3)
-#else
-# error - PAGE_SIZE not 64K, 16K, 8K or 4K
-#endif
-
-# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-static void *drm_ati_alloc_pcigart_table(void)
+static void *drm_ati_alloc_pcigart_table(int order)
{
unsigned long address;
struct page *page;
int i;
- DRM_DEBUG("%s\n", __FUNCTION__);
+
+ DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
- ATI_PCIGART_TABLE_ORDER);
+ order);
if (address == 0UL) {
return NULL;
}
page = virt_to_page(address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
+ for (i = 0; i < order; i++, page++) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
get_page(page);
#endif
@@ -78,22 +62,23 @@ static void *drm_ati_alloc_pcigart_table(void)
return (void *)address;
}
-static void drm_ati_free_pcigart_table(void *address)
+static void drm_ati_free_pcigart_table(void *address, int order)
{
struct page *page;
int i;
+ int num_pages = 1 << order;
DRM_DEBUG("%s\n", __FUNCTION__);
page = virt_to_page((unsigned long)address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
+ for (i = 0; i < num_pages; i++, page++) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
__put_page(page);
#endif
ClearPageReserved(page);
}
- free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
+ free_pages((unsigned long)address, order);
}
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -101,6 +86,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
drm_sg_mem_t *entry = dev->sg;
unsigned long pages;
int i;
+ int order;
+ int num_pages, max_pages;
/* we need to support large memory configurations */
if (!entry) {
@@ -108,15 +95,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
return 0;
}
+ order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+
if (gart_info->bus_addr) {
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
pci_unmap_single(dev->pdev, gart_info->bus_addr,
- ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+ num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE);
}
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
for (i = 0; i < pages; i++) {
if (!entry->busaddr[i])
@@ -132,7 +123,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
&& gart_info->addr) {
- drm_ati_free_pcigart_table(gart_info->addr);
+
+ drm_ati_free_pcigart_table(gart_info->addr, order);
gart_info->addr = NULL;
}
@@ -147,6 +139,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0;
int i, j, ret = 0;
+ int order;
+ int max_pages;
+ int num_pages;
if (!entry) {
DRM_ERROR("no scatter/gather memory!\n");
@@ -156,7 +151,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
- address = drm_ati_alloc_pcigart_table();
+ order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+ address = drm_ati_alloc_pcigart_table(order);
if (!address) {
DRM_ERROR("cannot allocate PCI GART page!\n");
goto done;
@@ -168,11 +165,12 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
}
bus_address = pci_map_single(dev->pdev, address,
- ATI_PCIGART_TABLE_PAGES *
- PAGE_SIZE, PCI_DMA_TODEVICE);
+ num_pages * PAGE_SIZE,
+ PCI_DMA_TODEVICE);
if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
- drm_ati_free_pcigart_table(address);
+ order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+ drm_ati_free_pcigart_table(address, order);
address = NULL;
goto done;
}
@@ -185,10 +183,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
pci_gart = (u32 *) address;
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
- memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32));
+ memset(pci_gart, 0, max_pages * sizeof(u32));
for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 9b5f5bdd..d1dbdc2d 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -593,6 +593,7 @@ typedef struct ati_pcigart_info {
void *addr;
dma_addr_t bus_addr;
drm_local_map_t mapping;
+ int table_size;
} drm_ati_pcigart_info;
@@ -847,7 +848,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
}
#ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->bus->number
+#define drm_get_pci_domain(dev) dev->hose->index
#else
#define drm_get_pci_domain(dev) 0
#endif
diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c
index 4825f0c0..23441811 100644
--- a/linux-core/drm_compat.c
+++ b/linux-core/drm_compat.c
@@ -94,6 +94,11 @@ static struct {
} drm_np_retry =
{SPIN_LOCK_UNLOCKED, NOPAGE_OOM, ATOMIC_INIT(0)};
+
+static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
+ struct fault_data *data);
+
+
struct page * get_nopage_retry(void)
{
if (atomic_read(&drm_np_retry.present) == 0) {
@@ -180,7 +185,7 @@ static int drm_pte_is_clear(struct vm_area_struct *vma,
return ret;
}
-int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
+static int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn)
{
int ret;
@@ -190,14 +195,106 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
ret = io_remap_pfn_range(vma, addr, pfn, PAGE_SIZE, vma->vm_page_prot);
return ret;
}
+
+static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
+ struct fault_data *data)
+{
+ unsigned long address = data->address;
+ drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
+ unsigned long page_offset;
+ struct page *page = NULL;
+ drm_ttm_t *ttm;
+ drm_device_t *dev;
+ unsigned long pfn;
+ int err;
+ unsigned long bus_base;
+ unsigned long bus_offset;
+ unsigned long bus_size;
+
+
+ mutex_lock(&bo->mutex);
+
+ err = drm_bo_wait(bo, 0, 1, 0);
+ if (err) {
+ data->type = (err == -EAGAIN) ?
+ VM_FAULT_MINOR : VM_FAULT_SIGBUS;
+ goto out_unlock;
+ }
+
+
+ /*
+ * If buffer happens to be in a non-mappable location,
+ * move it to a mappable.
+ */
+
+ if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
+ unsigned long _end = jiffies + 3*DRM_HZ;
+ uint32_t new_mask = bo->mem.mask |
+ DRM_BO_FLAG_MAPPABLE |
+ DRM_BO_FLAG_FORCE_MAPPABLE;
+
+ do {
+ err = drm_bo_move_buffer(bo, new_mask, 0, 0);
+ } while((err == -EAGAIN) && !time_after_eq(jiffies, _end));
+
+ if (err) {
+ DRM_ERROR("Timeout moving buffer to mappable location.\n");
+ data->type = VM_FAULT_SIGBUS;
+ goto out_unlock;
+ }
+ }
+
+ if (address > vma->vm_end) {
+ data->type = VM_FAULT_SIGBUS;
+ goto out_unlock;
+ }
+
+ dev = bo->dev;
+ err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
+ &bus_size);
+
+ if (err) {
+ data->type = VM_FAULT_SIGBUS;
+ goto out_unlock;
+ }
+
+ page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
+
+ if (bus_size) {
+ drm_mem_type_manager_t *man = &dev->bm.man[bo->mem.mem_type];
+
+ pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset;
+ vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma);
+ } else {
+ ttm = bo->ttm;
+
+ drm_ttm_fixup_caching(ttm);
+ page = drm_ttm_get_page(ttm, page_offset);
+ if (!page) {
+ data->type = VM_FAULT_OOM;
+ goto out_unlock;
+ }
+ pfn = page_to_pfn(page);
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ }
+
+ err = vm_insert_pfn(vma, address, pfn);
+
+ if (!err || err == -EBUSY)
+ data->type = VM_FAULT_MINOR;
+ else
+ data->type = VM_FAULT_OOM;
+out_unlock:
+ mutex_unlock(&bo->mutex);
+ return NULL;
+}
+
#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) && !defined(DRM_FULL_MM_COMPAT))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) && \
+ !defined(DRM_FULL_MM_COMPAT)
/**
- * While waiting for the fault() handler to appear in
- * we accomplish approximately
- * the same wrapping it with nopfn.
*/
unsigned long drm_bo_vm_nopfn(struct vm_area_struct * vma,
diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h
index 9692492d..bf5899fb 100644
--- a/linux-core/drm_compat.h
+++ b/linux-core/drm_compat.h
@@ -152,6 +152,13 @@ static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags)
(tmp);})
#endif
+#ifndef list_for_each_entry_safe_reverse
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+#endif
#include <linux/mm.h>
#include <asm/page.h>
@@ -205,19 +212,10 @@ extern void free_nopage_retry(void);
#define NOPAGE_REFAULT get_nopage_retry()
#endif
-#if !defined(DRM_FULL_MM_COMPAT) && \
- ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) || \
- (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)))
-
-struct fault_data;
-extern struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
- struct fault_data *data);
-#endif
#ifndef DRM_FULL_MM_COMPAT
/*
- * Hopefully, real NOPAGE_RETRY functionality will be in 2.6.19.
* For now, just return a dummy page that we've allocated out of
* static space. The page will be put by do_nopage() since we've already
* filled out the pte.
@@ -232,15 +230,12 @@ struct fault_data {
int type;
};
-
-extern int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn);
-
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
extern struct page *drm_bo_vm_nopage(struct vm_area_struct *vma,
unsigned long address,
int *type);
-#else
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) && \
+ !defined(DRM_FULL_MM_COMPAT)
extern unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
unsigned long address);
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) */
diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c
index 3e17a16d..6dd04a35 100644
--- a/linux-core/drm_fence.c
+++ b/linux-core/drm_fence.c
@@ -43,10 +43,29 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class,
drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[class];
drm_fence_driver_t *driver = dev->driver->fence_driver;
- struct list_head *list, *prev;
- drm_fence_object_t *fence;
+ struct list_head *head;
+ drm_fence_object_t *fence, *next;
int found = 0;
+ int is_exe = (type & DRM_FENCE_TYPE_EXE);
+ int ge_last_exe;
+
+
+
+ diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask;
+
+ if (fc->pending_exe_flush && is_exe && diff < driver->wrap_diff)
+ fc->pending_exe_flush = 0;
+
+ diff = (sequence - fc->last_exe_flush) & driver->sequence_mask;
+ ge_last_exe = diff < driver->wrap_diff;
+
+ if (ge_last_exe)
+ fc->pending_flush &= ~type;
+ if (is_exe && ge_last_exe) {
+ fc->last_exe_flush = sequence;
+ }
+
if (list_empty(&fc->ring))
return;
@@ -58,11 +77,11 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class,
}
}
- list = (found) ? fence->ring.prev : fc->ring.prev;
- prev = list->prev;
+ head = (found) ? &fence->ring : &fc->ring;
- for (; list != &fc->ring; list = prev, prev = list->prev) {
- fence = list_entry(list, drm_fence_object_t, ring);
+ list_for_each_entry_safe_reverse(fence, next, head, ring) {
+ if (&fence->ring == &fc->ring)
+ break;
type |= fence->native_type;
relevant = type & fence->type;
@@ -90,12 +109,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class,
}
}
-
- fc->pending_flush &= ~type;
- if (fc->pending_exe_flush && (type & DRM_FENCE_TYPE_EXE) &&
- ((sequence - fc->exe_flush_sequence) < driver->wrap_diff))
- fc->pending_exe_flush = 0;
-
+
if (wake) {
DRM_WAKEUP(&fc->fence_queue);
}
@@ -178,24 +192,6 @@ static void drm_fence_flush_exe(drm_fence_class_manager_t * fc,
uint32_t diff;
if (!fc->pending_exe_flush) {
- struct list_head *list;
-
- /*
- * Last_exe_flush is invalid. Find oldest sequence.
- */
-
- list = &fc->ring;
- if (list_empty(list)) {
- return;
- } else {
- drm_fence_object_t *fence =
- list_entry(list->next, drm_fence_object_t, ring);
- fc->last_exe_flush = (fence->sequence - 1) &
- driver->sequence_mask;
- }
- diff = (sequence - fc->last_exe_flush) & driver->sequence_mask;
- if (diff >= driver->wrap_diff)
- return;
fc->exe_flush_sequence = sequence;
fc->pending_exe_flush = 1;
} else {
@@ -261,14 +257,24 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t class, uint32_t sequence)
drm_fence_object_t *fence;
uint32_t diff;
+ write_lock_irqsave(&fm->lock, flags);
+ old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask;
+ diff = (old_sequence - fc->last_exe_flush) & driver->sequence_mask;
+
+ if ((diff < driver->wrap_diff) && !fc->pending_exe_flush) {
+ fc->pending_exe_flush = 1;
+ fc->exe_flush_sequence = sequence - (driver->flush_diff / 2);
+ }
+ write_unlock_irqrestore(&fm->lock, flags);
+
mutex_lock(&dev->struct_mutex);
read_lock_irqsave(&fm->lock, flags);
- if (fc->ring.next == &fc->ring) {
+
+ if (list_empty(&fc->ring)) {
read_unlock_irqrestore(&fm->lock, flags);
mutex_unlock(&dev->struct_mutex);
return;
}
- old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask;
fence = list_entry(fc->ring.next, drm_fence_object_t, ring);
atomic_inc(&fence->usage);
mutex_unlock(&dev->struct_mutex);
@@ -384,6 +390,7 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence,
{
drm_fence_manager_t *fm = &dev->fm;
drm_fence_driver_t *driver = dev->driver->fence_driver;
+ drm_fence_class_manager_t *fc = &fm->class[fence->class];
unsigned long flags;
uint32_t sequence;
uint32_t native_type;
@@ -402,7 +409,9 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence,
fence->signaled = 0x00;
fence->sequence = sequence;
fence->native_type = native_type;
- list_add_tail(&fence->ring, &fm->class[class].ring);
+ if (list_empty(&fc->ring))
+ fc->last_exe_flush = sequence - 1;
+ list_add_tail(&fence->ring, &fc->ring);
write_unlock_irqrestore(&fm->lock, flags);
return 0;
}
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index f3b1088f..a4a55e37 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -718,28 +718,23 @@ EXPORT_SYMBOL(drm_mmap);
* \c Pagefault method for buffer objects.
*
* \param vma Virtual memory area.
- * \param data Fault data on failure or refault.
- * \return Always NULL as we insert pfns directly.
+ * \param address File offset.
+ * \return Error or refault. The pfn is manually inserted.
*
* It's important that pfns are inserted while holding the bo->mutex lock.
* otherwise we might race with unmap_mapping_range() which is always
* called with the bo->mutex lock held.
*
- * It's not pretty to modify the vma->vm_page_prot variable while not
- * holding the mm semaphore in write mode. However, we have it i read mode,
- * so we won't be racing with any other writers, and we only actually modify
- * it when no ptes are present so it shouldn't be a big deal.
+ * We're modifying the page attribute bits of the vma->vm_page_prot field,
+ * without holding the mmap_sem in write mode. Only in read mode.
+ * These bits are not used by the mm subsystem code, and we consider them
+ * protected by the bo->mutex lock.
*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) || \
- LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
#ifdef DRM_FULL_MM_COMPAT
-static
-#endif
-struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
- struct fault_data *data)
+static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
+ unsigned long address)
{
- unsigned long address = data->address;
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
unsigned long page_offset;
struct page *page = NULL;
@@ -750,66 +745,43 @@ struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
unsigned long bus_base;
unsigned long bus_offset;
unsigned long bus_size;
+ int ret = NOPFN_REFAULT;
-
- mutex_lock(&bo->mutex);
+ if (address > vma->vm_end)
+ return NOPFN_SIGBUS;
+
+ err = mutex_lock_interruptible(&bo->mutex);
+ if (err)
+ return NOPFN_REFAULT;
err = drm_bo_wait(bo, 0, 0, 0);
if (err) {
- data->type = (err == -EAGAIN) ?
- VM_FAULT_MINOR : VM_FAULT_SIGBUS;
+ ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
goto out_unlock;
}
-
-
+
/*
* If buffer happens to be in a non-mappable location,
* move it to a mappable.
*/
-#ifdef DRM_BO_FULL_COMPAT
if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
uint32_t new_mask = bo->mem.mask |
DRM_BO_FLAG_MAPPABLE |
DRM_BO_FLAG_FORCE_MAPPABLE;
err = drm_bo_move_buffer(bo, new_mask, 0, 0);
-
if (err) {
- data->type = (err == -EAGAIN) ?
- VM_FAULT_MINOR : VM_FAULT_SIGBUS;
+ ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
goto out_unlock;
}
}
-#else
- if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
- unsigned long _end = jiffies + 3*DRM_HZ;
- uint32_t new_mask = bo->mem.mask |
- DRM_BO_FLAG_MAPPABLE |
- DRM_BO_FLAG_FORCE_MAPPABLE;
-
- do {
- err = drm_bo_move_buffer(bo, new_mask, 0, 0);
- } while((err == -EAGAIN) && !time_after_eq(jiffies, _end));
-
- if (err) {
- DRM_ERROR("Timeout moving buffer to mappable location.\n");
- data->type = VM_FAULT_SIGBUS;
- goto out_unlock;
- }
- }
-#endif
-
- if (address > vma->vm_end) {
- data->type = VM_FAULT_SIGBUS;
- goto out_unlock;
- }
dev = bo->dev;
err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
&bus_size);
if (err) {
- data->type = VM_FAULT_SIGBUS;
+ ret = NOPFN_SIGBUS;
goto out_unlock;
}
@@ -826,7 +798,7 @@ struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
drm_ttm_fixup_caching(ttm);
page = drm_ttm_get_page(ttm, page_offset);
if (!page) {
- data->type = VM_FAULT_OOM;
+ ret = NOPFN_OOM;
goto out_unlock;
}
pfn = page_to_pfn(page);
@@ -834,14 +806,13 @@ struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
}
err = vm_insert_pfn(vma, address, pfn);
-
- if (!err || err == -EBUSY)
- data->type = VM_FAULT_MINOR;
- else
- data->type = VM_FAULT_OOM;
+ if (err) {
+ ret = (err != -EAGAIN) ? NOPFN_OOM : NOPFN_REFAULT;
+ goto out_unlock;
+ }
out_unlock:
mutex_unlock(&bo->mutex);
- return NULL;
+ return ret;
}
#endif
@@ -897,7 +868,7 @@ static void drm_bo_vm_close(struct vm_area_struct *vma)
static struct vm_operations_struct drm_bo_vm_ops = {
#ifdef DRM_FULL_MM_COMPAT
- .fault = drm_bo_vm_fault,
+ .nopfn = drm_bo_vm_nopfn,
#else
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
.nopfn = drm_bo_vm_nopfn,
diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c
index 81d9b176..88daa57c 100644
--- a/linux-core/i915_fence.c
+++ b/linux-core/i915_fence.c
@@ -49,6 +49,7 @@ static void i915_perform_flush(drm_device_t * dev)
uint32_t i_status;
uint32_t diff;
uint32_t sequence;
+ int rwflush;
if (!dev_priv)
return;
@@ -65,14 +66,10 @@ static void i915_perform_flush(drm_device_t * dev)
drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE);
}
- diff = sequence - fc->exe_flush_sequence;
- if (diff < driver->wrap_diff) {
- fc->pending_exe_flush = 0;
- if (dev_priv->fence_irq_on) {
- i915_user_irq_off(dev_priv);
- dev_priv->fence_irq_on = 0;
- }
- } else if (!dev_priv->fence_irq_on) {
+ if (dev_priv->fence_irq_on && !fc->pending_exe_flush) {
+ i915_user_irq_off(dev_priv);
+ dev_priv->fence_irq_on = 0;
+ } else if (!dev_priv->fence_irq_on && fc->pending_exe_flush) {
i915_user_irq_on(dev_priv);
dev_priv->fence_irq_on = 1;
}
@@ -89,13 +86,14 @@ static void i915_perform_flush(drm_device_t * dev)
}
}
- if (fc->pending_flush && !dev_priv->flush_pending) {
+ rwflush = fc->pending_flush & DRM_I915_FENCE_TYPE_RW;
+ if (rwflush && !dev_priv->flush_pending) {
dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv);
dev_priv->flush_flags = fc->pending_flush;
dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0);
I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
dev_priv->flush_pending = 1;
- fc->pending_flush = 0;
+ fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW;
}
if (dev_priv->flush_pending) {
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 3a5d6346..bcb3eedf 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -679,7 +679,7 @@ typedef struct drm_set_version {
typedef struct drm_fence_arg {
unsigned handle;
- int class;
+ int class;
unsigned type;
unsigned flags;
unsigned signaled;
@@ -808,7 +808,7 @@ typedef struct drm_bo_arg_request {
drm_bo_type_t type;
unsigned arg_handle;
drm_u64_t buffer_start;
- unsigned page_alignment;
+ unsigned page_alignment;
unsigned expand_pad[4]; /*Future expansion */
enum {
drm_bo_create,
@@ -839,11 +839,11 @@ typedef struct drm_bo_arg_reply {
drm_u64_t size;
drm_u64_t offset;
drm_u64_t arg_handle;
- unsigned mask;
- drm_u64_t buffer_start;
- unsigned fence_flags;
- unsigned rep_flags;
- unsigned page_alignment;
+ unsigned mask;
+ drm_u64_t buffer_start;
+ unsigned fence_flags;
+ unsigned rep_flags;
+ unsigned page_alignment;
unsigned expand_pad[4]; /*Future expansion */
}drm_bo_arg_reply_t;
diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt
index 0fc9775b..a1bc907b 100644
--- a/shared-core/drm_pciids.txt
+++ b/shared-core/drm_pciids.txt
@@ -222,6 +222,7 @@
0x1106 0x3344 0 "VIA CN700 / VM800 / P4M800Pro"
0x1106 0x3343 0 "VIA P4M890"
0x1106 0x3230 VIA_DX9_0 "VIA K8M890"
+0x1106 0x3157 VIA_PRO_GROUP_A "VIA CX700"
[i810]
0x8086 0x7121 0 "Intel i810 GMCH"
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 0f11c43a..8a1964ed 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -25,6 +25,8 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
+#define NOUVEAU_DRM_HEADER_PATCHLEVEL 4
+
typedef struct drm_nouveau_fifo_alloc {
int channel;
uint32_t put_base;
@@ -37,24 +39,18 @@ typedef struct drm_nouveau_fifo_alloc {
}
drm_nouveau_fifo_alloc_t;
-#define NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND 0x1
-#define NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY 0x2
-#define NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE 0x4
-#define NV_DMA_CONTEXT_FLAGS_MONO 0x8
-
typedef struct drm_nouveau_object_init {
uint32_t handle;
- int class;
- uint32_t flags;
- /* these are object handles */
- uint32_t dma0;
- uint32_t dma1;
- uint32_t dma_notifier;
+ int class;
}
drm_nouveau_object_init_t;
+#define NOUVEAU_MEM_ACCESS_RO 1
+#define NOUVEAU_MEM_ACCESS_WO 2
+#define NOUVEAU_MEM_ACCESS_RW 3
typedef struct drm_nouveau_dma_object_init {
uint32_t handle;
+ int class;
int access;
int target;
uint32_t offset;
@@ -80,8 +76,8 @@ typedef struct drm_nouveau_mem_alloc {
drm_nouveau_mem_alloc_t;
typedef struct drm_nouveau_mem_free {
- int flags;
uint64_t region_offset;
+ int flags;
}
drm_nouveau_mem_free_t;
@@ -91,9 +87,10 @@ drm_nouveau_mem_free_t;
#define NOUVEAU_GETPARAM_BUS_TYPE 5
#define NOUVEAU_GETPARAM_FB_PHYSICAL 6
#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7
+#define NOUVEAU_GETPARAM_FB_SIZE 8
+#define NOUVEAU_GETPARAM_AGP_SIZE 9
typedef struct drm_nouveau_getparam {
- unsigned int param;
- unsigned int dummy;
+ uint64_t param;
uint64_t value;
}
drm_nouveau_getparam_t;
@@ -101,8 +98,8 @@ drm_nouveau_getparam_t;
#define NOUVEAU_SETPARAM_CMDBUF_LOCATION 1
#define NOUVEAU_SETPARAM_CMDBUF_SIZE 2
typedef struct drm_nouveau_setparam {
- unsigned int param;
- unsigned int value;
+ uint64_t param;
+ uint64_t value;
}
drm_nouveau_setparam_t;
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index 63721650..c3d19bb0 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 3
+#define DRIVER_PATCHLEVEL 4
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@@ -70,9 +70,6 @@ struct nouveau_object
int engine;
};
-#define NV_DMA_TARGET_VIDMEM 0
-#define NV_DMA_TARGET_PCI 2
-#define NV_DMA_TARGET_AGP 3
struct nouveau_fifo
{
int used;
@@ -134,7 +131,9 @@ typedef struct drm_nouveau_private {
/* base physical adresses */
uint64_t fb_phys;
+ uint64_t fb_available_size;
uint64_t agp_phys;
+ uint64_t agp_available_size;
/* the mtrr covering the FB */
int fb_mtrr;
@@ -192,8 +191,10 @@ extern void nouveau_fifo_free(drm_device_t *dev, int channel);
/* nouveau_object.c */
extern void nouveau_object_cleanup(drm_device_t *dev, DRMFILE filp);
-extern struct nouveau_object *nouveau_dma_object_create(drm_device_t *dev,
- uint32_t offset, uint32_t size, int access, uint32_t target);
+extern struct nouveau_object *
+nouveau_dma_object_create(drm_device_t *dev, int class,
+ uint32_t offset, uint32_t size,
+ int access, int target);
extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS);
extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS);
extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem);
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index fd5455bf..6f75a05b 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -239,11 +239,12 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
}
if (cb->flags & NOUVEAU_MEM_AGP) {
- cb_dma = nouveau_dma_object_create(dev,
- cb->start, cb->size,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
+ cb->start - dev_priv->agp_phys,
+ cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP);
} else if (dev_priv->card_type != NV_04) {
- cb_dma = nouveau_dma_object_create(dev,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
cb->start - drm_get_resource_start(dev, 1),
cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
@@ -252,7 +253,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
* exact reason for existing :) PCI access to cmdbuf in
* VRAM.
*/
- cb_dma = nouveau_dma_object_create(dev,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
cb->start, cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI);
}
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c
index 51d4bae1..32b33070 100644
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@ -44,7 +44,7 @@ void nouveau_irq_preinstall(drm_device_t *dev)
/* Disable/Clear PFIFO interrupts */
NV_WRITE(NV03_PFIFO_INTR_EN_0, 0);
- NV_WRITE(NV03_PMC_INTR_0, 0xFFFFFFFF);
+ NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF);
/* Disable/Clear PGRAPH interrupts */
if (dev_priv->card_type<NV_40)
NV_WRITE(NV03_PGRAPH_INTR_EN, 0);
@@ -78,7 +78,7 @@ void nouveau_irq_postinstall(drm_device_t *dev)
NV_PFIFO_INTR_SEMAPHORE |
NV_PFIFO_INTR_ACQUIRE_TIMEOUT
);
- NV_WRITE(NV03_PMC_INTR_0, 0xFFFFFFFF);
+ NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF);
/* Enable PGRAPH interrupts */
if (dev_priv->card_type<NV_40)
@@ -136,7 +136,7 @@ static void nouveau_fifo_irq_handler(drm_device_t *dev)
uint32_t status, chmode, chstat, channel;
drm_nouveau_private_t *dev_priv = dev->dev_private;
- status = NV_READ(NV03_PMC_INTR_0);
+ status = NV_READ(NV03_PFIFO_INTR_0);
if (!status)
return;
chmode = NV_READ(NV04_PFIFO_MODE);
@@ -166,14 +166,14 @@ static void nouveau_fifo_irq_handler(drm_device_t *dev)
);
status &= ~NV_PFIFO_INTR_CACHE_ERROR;
- NV_WRITE(NV03_PMC_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
+ NV_WRITE(NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
}
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
DRM_INFO("NV: PFIFO DMA pusher interrupt\n");
status &= ~NV_PFIFO_INTR_DMA_PUSHER;
- NV_WRITE(NV03_PMC_INTR_0, NV_PFIFO_INTR_DMA_PUSHER);
+ NV_WRITE(NV03_PFIFO_INTR_0, NV_PFIFO_INTR_DMA_PUSHER);
NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
if (NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)!=NV_READ(NV04_PFIFO_CACHE1_DMA_GET))
@@ -186,7 +186,7 @@ static void nouveau_fifo_irq_handler(drm_device_t *dev)
if (status) {
DRM_INFO("NV: unknown PFIFO interrupt. status=0x%08x\n", status);
- NV_WRITE(NV03_PMC_INTR_0, status);
+ NV_WRITE(NV03_PFIFO_INTR_0, status);
}
NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
@@ -239,6 +239,30 @@ static void nouveau_nv04_context_switch(drm_device_t *dev)
}
#endif
+static void
+nouveau_graph_dump_trap_info(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t address;
+ uint32_t channel;
+ uint32_t method, subc, data;
+
+ address = NV_READ(0x400704);
+ data = NV_READ(0x400708);
+ channel = (address >> 20) & 0x1F;
+ subc = (address >> 16) & 0x7;
+ method = address & 0x1FFC;
+
+ DRM_ERROR("NV: nSource: 0x%08x, nStatus: 0x%08x\n",
+ NV_READ(0x400108), NV_READ(0x400104));
+ DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -"
+ "Method 0x%04x, Data 0x%08x\n",
+ channel, subc,
+ NV_READ(0x400160+subc*4) & 0xFFFF,
+ method, data
+ );
+}
+
static void nouveau_pgraph_irq_handler(drm_device_t *dev)
{
uint32_t status;
@@ -256,9 +280,15 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
nsource = NV_READ(0x00400108);
DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);
- instance = NV_READ(0x00400158);
- notify = NV_READ(0x00400150) >> 16;
- DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", nsource, nstatus);
+ /* if this wasn't NOTIFICATION_PENDING, dump extra trap info */
+ if (nsource & ~(1<<0)) {
+ nouveau_graph_dump_trap_info(dev);
+ } else {
+ instance = NV_READ(0x00400158);
+ notify = NV_READ(0x00400150) >> 16;
+ DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n",
+ nsource, nstatus);
+ }
status &= ~NV_PGRAPH_INTR_NOTIFY;
NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
@@ -289,9 +319,6 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
if (status & NV_PGRAPH_INTR_ERROR) {
uint32_t nsource, nstatus, instance;
- uint32_t address;
- uint32_t channel;
- uint32_t method, subc, data;
DRM_ERROR("NV: PGRAPH error interrupt\n");
@@ -302,18 +329,7 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
instance = NV_READ(0x00400158);
DRM_ERROR("instance:0x%08x\n", instance);
- address = NV_READ(0x400704);
- data = NV_READ(0x400708);
- channel = (address >> 20) & 0x1F;
- subc = (address >> 16) & 0x7;
- method = address & 0x1FFC;
- DRM_DEBUG("NV: 0x400704 = 0x%08x\n", address);
- DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -"
- "Method 0x%04x, Data 0x%08x\n",
- channel, subc,
- NV_READ(0x400160+subc*4) & 0xFFFF,
- method, data
- );
+ nouveau_graph_dump_trap_info(dev);
status &= ~NV_PGRAPH_INTR_ERROR;
NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index 3b1f443c..f62d8615 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -335,7 +335,8 @@ int nouveau_mem_init(struct drm_device *dev)
if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size))
goto no_agp;
- dev_priv->agp_phys=info.aperture_base;
+ dev_priv->agp_phys = info.aperture_base;
+ dev_priv->agp_available_size = info.aperture_size;
}
no_agp:
@@ -346,6 +347,7 @@ no_agp:
* We don't want to allocate this... */
if (dev_priv->card_type >= NV_40)
fb_size -= dev_priv->ramin_size;
+ dev_priv->fb_available_size = fb_size;
DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10);
if (fb_size>256*1024*1024) {
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index c11b05eb..b3c4b0e0 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -97,9 +97,6 @@ nouveau_object_handle_find(drm_device_t *dev, int fifo_num, uint32_t handle)
struct nouveau_fifo *fifo = &dev_priv->fifos[fifo_num];
struct nouveau_object *obj = fifo->objs;
- if (!handle)
- return NULL;
-
DRM_DEBUG("Looking for handle 0x%08x\n", handle);
while (obj) {
if (obj->handle == handle)
@@ -166,7 +163,7 @@ static int nouveau_hash_table_insert(drm_device_t* dev, int fifo,
o_ofs = ofs = nouveau_handle_hash(dev, obj->handle, fifo);
- while (NV_READ(ht_base + ofs)) {
+ while (NV_READ(ht_base + ofs) || NV_READ(ht_base + ofs + 4)) {
ofs += 8;
if (ofs == ht_end) ofs = ht_base;
if (ofs == o_ofs) {
@@ -284,17 +281,40 @@ static void nouveau_object_instance_free(drm_device_t *dev,
The method below creates a DMA object in instance RAM and returns a handle
to it that can be used to set up context objects.
*/
-struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
- uint32_t offset, uint32_t size,
- int access, uint32_t target)
+
+struct nouveau_object *
+nouveau_dma_object_create(drm_device_t* dev, int class,
+ uint32_t offset, uint32_t size,
+ int access, int target)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
struct nouveau_object *obj;
uint32_t frame, adjust;
+ uint32_t pte_flags = 0;
DRM_DEBUG("offset:0x%08x, size:0x%08x, target:%d, access:%d\n",
offset, size, target, access);
+ switch (target) {
+ case NV_DMA_TARGET_AGP:
+ offset += dev_priv->agp_phys;
+ break;
+ default:
+ break;
+ }
+
+ switch (access) {
+ case NV_DMA_ACCESS_RO:
+ break;
+ case NV_DMA_ACCESS_WO:
+ case NV_DMA_ACCESS_RW:
+ pte_flags |= (1 << 1);
+ break;
+ default:
+ DRM_ERROR("invalid access mode=%d\n", access);
+ return NULL;
+ }
+
frame = offset & ~0x00000FFF;
adjust = offset & 0x00000FFF;
@@ -305,21 +325,16 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
}
obj->engine = 0;
- obj->class = 0;
+ obj->class = class;
INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) |
(adjust << 20) |
(access << 14) |
(target << 16) |
- 0x3D /* DMA_IN_MEMORY */));
+ class));
INSTANCE_WR(obj->instance, 1, size-1);
- INSTANCE_WR(obj->instance, 2,
- frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0));
- /* I don't actually know what this is, the DMA objects I see
- * in renouveau dumps usually have this as the same as +8
- */
- INSTANCE_WR(obj->instance, 3,
- frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0));
+ INSTANCE_WR(obj->instance, 2, frame | pte_flags);
+ INSTANCE_WR(obj->instance, 3, frame | pte_flags);
return obj;
}
@@ -376,55 +391,13 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
entry[5]:
set to 0?
*/
-static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev,
- int class, uint32_t flags,
- struct nouveau_object *dma0,
- struct nouveau_object *dma1,
- struct nouveau_object *dma_notifier)
+static struct nouveau_object *
+nouveau_context_object_create(drm_device_t* dev, int class)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
struct nouveau_object *obj;
- uint32_t d0, d1, dn;
- uint32_t flags0,flags1,flags2;
- flags0=0;flags1=0;flags2=0;
-
- if (dev_priv->card_type >= NV_40) {
- if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
- flags0 |= 0x02080000;
- else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
- flags0 |= 0x02080000;
- if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
- flags0 |= 0x00020000;
-#ifdef __BIG_ENDIAN
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x01000000;
- flags2 |= 0x01000000;
-#else
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x02000000;
-#endif
- } else {
- if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
- flags0 |= 0x01008000;
- else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
- flags0 |= 0x01018000;
- if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
- flags0 |= 0x00002000;
-#ifdef __BIG_ENDIAN
- flags0 |= 0x00080000;
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x00000001;
-#else
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x00000002;
-#endif
- }
- DRM_DEBUG("class=%x, dma0=%08x, dma1=%08x, dman=%08x\n",
- class,
- dma0 ? dma0->handle : 0,
- dma1 ? dma1->handle : 0,
- dma_notifier ? dma_notifier->handle : 0);
+ DRM_DEBUG("class=%x\n", class);
obj = nouveau_instance_alloc(dev);
if (!obj) {
@@ -435,25 +408,37 @@ static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev,
obj->engine = 1;
obj->class = class;
- d0 = dma0 ? nouveau_chip_instance_get(dev, dma0->instance) : 0;
- d1 = dma1 ? nouveau_chip_instance_get(dev, dma1->instance) : 0;
- dn = dma_notifier ?
- nouveau_chip_instance_get(dev, dma_notifier->instance) : 0;
-
- if (dev_priv->card_type >= NV_40) {
- INSTANCE_WR(obj->instance, 0, class | flags0);
- INSTANCE_WR(obj->instance, 1, dn | flags1);
- INSTANCE_WR(obj->instance, 2, d0 | flags2);
- INSTANCE_WR(obj->instance, 3, d1);
- INSTANCE_WR(obj->instance, 4, 0x00000000);
- INSTANCE_WR(obj->instance, 5, 0x00000000);
- INSTANCE_WR(obj->instance, 6, 0x00000000);
- INSTANCE_WR(obj->instance, 7, 0x00000000);
- } else {
- INSTANCE_WR(obj->instance, 0, class | flags0);
- INSTANCE_WR(obj->instance, 1, (dn << 16) | flags1);
- INSTANCE_WR(obj->instance, 2, d0 | (d1 << 16));
- INSTANCE_WR(obj->instance, 3, 0);
+ switch (class) {
+ case NV_CLASS_NULL:
+ INSTANCE_WR(obj->instance, 0, 0x00001030);
+ INSTANCE_WR(obj->instance, 1, 0xFFFFFFFF);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ break;
+ default:
+ if (dev_priv->card_type >= NV_40) {
+ INSTANCE_WR(obj->instance, 0, obj->class);
+ INSTANCE_WR(obj->instance, 1, 0x00000000);
+#ifdef __BIG_ENDIAN
+ INSTANCE_WR(obj->instance, 2, 0x01000000);
+#else
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+#endif
+ INSTANCE_WR(obj->instance, 3, 0x00000000);
+ INSTANCE_WR(obj->instance, 4, 0x00000000);
+ INSTANCE_WR(obj->instance, 5, 0x00000000);
+ INSTANCE_WR(obj->instance, 6, 0x00000000);
+ INSTANCE_WR(obj->instance, 7, 0x00000000);
+ } else {
+#ifdef __BIG_ENDIAN
+ INSTANCE_WR(obj->instance, 0, obj->class | 0x00080000);
+#else
+ INSTANCE_WR(obj->instance, 0, obj->class);
+#endif
+ INSTANCE_WR(obj->instance, 1, 0x00000000);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ INSTANCE_WR(obj->instance, 3, 0x00000000);
+ }
}
return obj;
@@ -488,7 +473,7 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_object_init_t init;
- struct nouveau_object *obj, *dma0, *dma1, *dman;
+ struct nouveau_object *obj;
int fifo;
fifo = nouveau_fifo_id_get(dev, filp);
@@ -506,30 +491,11 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
return DRM_ERR(EINVAL);
}
- dma0 = nouveau_object_handle_find(dev, fifo, init.dma0);
- if (init.dma0 && !dma0) {
- DRM_ERROR("context dma0 - invalid handle 0x%08x\n", init.dma0);
- return DRM_ERR(EINVAL);
- }
- dma1 = nouveau_object_handle_find(dev, fifo, init.dma1);
- if (init.dma1 && !dma1) {
- DRM_ERROR("context dma1 - invalid handle 0x%08x\n", init.dma0);
- return DRM_ERR(EINVAL);
- }
- dman = nouveau_object_handle_find(dev, fifo, init.dma_notifier);
- if (init.dma_notifier && !dman) {
- DRM_ERROR("context dman - invalid handle 0x%08x\n",
- init.dma_notifier);
- return DRM_ERR(EINVAL);
- }
-
- obj = nouveau_context_object_create(dev, init.class, init.flags,
- dma0, dma1, dman);
+ obj = nouveau_context_object_create(dev, init.class);
if (!obj)
return DRM_ERR(ENOMEM);
obj->handle = init.handle;
-
if (nouveau_hash_table_insert(dev, fifo, obj)) {
nouveau_object_free(dev, fifo, obj);
return DRM_ERR(ENOMEM);
@@ -540,6 +506,64 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
return 0;
}
+static int
+nouveau_dma_object_check_access(drm_device_t *dev,
+ drm_nouveau_dma_object_init_t *init)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint64_t limit;
+
+ /* Check for known DMA object classes */
+ switch (init->class) {
+ case NV_CLASS_DMA_IN_MEMORY:
+ case NV_CLASS_DMA_FROM_MEMORY:
+ case NV_CLASS_DMA_TO_MEMORY:
+ break;
+ default:
+ DRM_ERROR("invalid class = 0x%x\n", init->class);
+ return DRM_ERR(EPERM);
+ }
+
+ /* Check access mode, and translate to NV_DMA_ACCESS_* */
+ switch (init->access) {
+ case NOUVEAU_MEM_ACCESS_RO:
+ init->access = NV_DMA_ACCESS_RO;
+ break;
+ case NOUVEAU_MEM_ACCESS_WO:
+ init->access = NV_DMA_ACCESS_WO;
+ break;
+ case NOUVEAU_MEM_ACCESS_RW:
+ init->access = NV_DMA_ACCESS_RW;
+ break;
+ default:
+ DRM_ERROR("invalid access mode = %d\n", init->access);
+ return DRM_ERR(EPERM);
+ }
+
+ /* Check that request is within the allowed limits of "target" */
+ switch (init->target) {
+ case NOUVEAU_MEM_FB:
+ limit = dev_priv->fb_available_size;
+ init->target = NV_DMA_TARGET_VIDMEM;
+ break;
+ case NOUVEAU_MEM_AGP:
+ limit = dev_priv->agp_available_size;
+ init->target = NV_DMA_TARGET_AGP;
+ break;
+ default:
+ DRM_ERROR("invalid target = 0x%x\n", init->target);
+ return DRM_ERR(EPERM);
+ }
+
+ if ((init->offset > limit) || (init->offset + init->size) > limit) {
+ DRM_ERROR("access out of allowed range (%d,0x%08x,0x%08x)\n",
+ init->target, init->offset, init->size);
+ return DRM_ERR(EPERM);
+ }
+
+ return 0;
+}
+
int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
@@ -554,14 +578,18 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *)
data, sizeof(init));
+ if (nouveau_dma_object_check_access(dev, &init))
+ return DRM_ERR(EPERM);
+
if (nouveau_object_handle_find(dev, fifo, init.handle)) {
DRM_ERROR("Channel %d: handle 0x%08x already exists\n",
fifo, init.handle);
return DRM_ERR(EINVAL);
}
- obj = nouveau_dma_object_create(dev, init.offset, init.size,
- init.access, init.target);
+ obj = nouveau_dma_object_create(dev, init.class,
+ init.offset, init.size,
+ init.access, init.target);
if (!obj)
return DRM_ERR(ENOMEM);
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index 966600cf..e7ab3804 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -32,12 +32,20 @@
# define NV40_RAMHT_CONTEXT_ENGINE_SHIFT 20
# define NV40_RAMHT_CONTEXT_INSTANCE_SHIFT 0
+/* DMA object defines */
#define NV_DMA_ACCESS_RW 0
#define NV_DMA_ACCESS_RO 1
#define NV_DMA_ACCESS_WO 2
#define NV_DMA_TARGET_VIDMEM 0
+#define NV_DMA_TARGET_PCI 2
#define NV_DMA_TARGET_AGP 3
+/* Some object classes we care about in the drm */
+#define NV_CLASS_DMA_FROM_MEMORY 0x00000002
+#define NV_CLASS_DMA_TO_MEMORY 0x00000003
+#define NV_CLASS_NULL 0x00000030
+#define NV_CLASS_DMA_IN_MEMORY 0x0000003D
+
#define NV03_FIFO_SIZE 0x8000UL
#define NV_MAX_FIFO_NUMBER 32
#define NV03_FIFO_REGS_SIZE 0x10000
@@ -88,8 +96,6 @@
#define NV10_PGRAPH_CTX_CACHE4 0x004001C0
#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
#define NV10_PGRAPH_CTX_CACHE5 0x004001E0
-#define NV40_PGRAPH_UNK220 0x00400220
-# define NV40_PGRAPH_UNK220_FB_INSTANCE 0xFFFFFFFF
#define NV03_PGRAPH_ABS_X_RAM 0x00400400
#define NV03_PGRAPH_ABS_Y_RAM 0x00400480
#define NV03_PGRAPH_X_MISC 0x00400500
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index f1f272e7..e1fc6330 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -181,8 +181,14 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS)
case NOUVEAU_GETPARAM_AGP_PHYSICAL:
getparam.value=dev_priv->agp_phys;
break;
+ case NOUVEAU_GETPARAM_FB_SIZE:
+ getparam.value=dev_priv->fb_available_size;
+ break;
+ case NOUVEAU_GETPARAM_AGP_SIZE:
+ getparam.value=dev_priv->agp_available_size;
+ break;
default:
- DRM_ERROR("unknown parameter %d\n", getparam.param);
+ DRM_ERROR("unknown parameter %lld\n", getparam.param);
return DRM_ERR(EINVAL);
}
@@ -207,7 +213,8 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
case NOUVEAU_MEM_FB:
break;
default:
- DRM_ERROR("invalid CMDBUF_LOCATION value=%d\n", setparam.value);
+ DRM_ERROR("invalid CMDBUF_LOCATION value=%lld\n",
+ setparam.value);
return DRM_ERR(EINVAL);
}
dev_priv->config.cmdbuf.location = setparam.value;
@@ -216,7 +223,7 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
dev_priv->config.cmdbuf.size = setparam.value;
break;
default:
- DRM_ERROR("unknown parameter %d\n", setparam.param);
+ DRM_ERROR("unknown parameter %lld\n", setparam.param);
return DRM_ERR(EINVAL);
}
diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c
index 659767f2..5e0d8d77 100644
--- a/shared-core/nv40_graph.c
+++ b/shared-core/nv40_graph.c
@@ -924,14 +924,6 @@ nv40_graph_init(drm_device_t *dev)
/* No context present currently */
NV_WRITE(0x40032C, 0x00000000);
- /* No idea what this is for.. */
- dev_priv->fb_obj = nouveau_dma_object_create(dev,
- 0, nouveau_mem_fb_amount(dev),
- NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM);
- pg0220_inst = nouveau_chip_instance_get(dev,
- dev_priv->fb_obj->instance);
- NV_WRITE(NV40_PGRAPH_UNK220, pg0220_inst);
-
return 0;
}
diff --git a/shared-core/r128_cce.c b/shared-core/r128_cce.c
index f9a9eb32..62859d5a 100644
--- a/shared-core/r128_cce.c
+++ b/shared-core/r128_cce.c
@@ -560,6 +560,7 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
if (dev_priv->is_pci) {
#endif
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
+ dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
dev_priv->gart_info.addr = NULL;
dev_priv->gart_info.bus_addr = 0;
dev_priv->gart_info.is_pcie = 0;
diff --git a/shared-core/r128_drv.h b/shared-core/r128_drv.h
index f1efb49d..90868356 100644
--- a/shared-core/r128_drv.h
+++ b/shared-core/r128_drv.h
@@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
#define R128_PERFORMANCE_BOXES 0
+#define R128_PCIGART_TABLE_SIZE 32768
+
#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
index 0fa6535d..e02796e7 100644
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1623,13 +1623,13 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
#endif
{
/* if we have an offset set from userspace */
- if (dev_priv->pcigart_offset) {
+ if (dev_priv->pcigart_offset_set) {
dev_priv->gart_info.bus_addr =
dev_priv->pcigart_offset + dev_priv->fb_location;
dev_priv->gart_info.mapping.offset =
dev_priv->gart_info.bus_addr;
dev_priv->gart_info.mapping.size =
- RADEON_PCIGART_TABLE_SIZE;
+ dev_priv->gart_info.table_size;
drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
dev_priv->gart_info.addr =
@@ -2230,6 +2230,8 @@ int radeon_driver_firstopen(struct drm_device *dev)
drm_local_map_t *map;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+
ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
drm_get_resource_len(dev, 2), _DRM_REGISTERS,
_DRM_READ_ONLY, &dev_priv->mmio);
diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h
index f5edbc19..e96e7851 100644
--- a/shared-core/radeon_drm.h
+++ b/shared-core/radeon_drm.h
@@ -708,6 +708,7 @@ typedef struct drm_radeon_setparam {
#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */
#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */
+#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */
/* 1.14: Clients can allocate/free a surface
*/
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 5c426fe0..3e56af30 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -95,10 +95,11 @@
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
* 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
* new packet type)
+ * 1.26- Add support for variable size PCI(E) gart aperture
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 25
+#define DRIVER_MINOR 26
#define DRIVER_PATCHLEVEL 0
/*
@@ -282,6 +283,7 @@ typedef struct drm_radeon_private {
struct radeon_virt_surface virt_surfaces[2*RADEON_MAX_SURFACES];
unsigned long pcigart_offset;
+ unsigned int pcigart_offset_set;
drm_ati_pcigart_info gart_info;
u32 scratch_ages[5];
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index 40b7d6ce..b95549d8 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -3196,10 +3196,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
break;
case RADEON_SETPARAM_PCIGART_LOCATION:
dev_priv->pcigart_offset = sp.value;
+ dev_priv->pcigart_offset_set = 1;
break;
case RADEON_SETPARAM_NEW_MEMMAP:
dev_priv->new_memmap = sp.value;
break;
+ case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
+ dev_priv->gart_info.table_size = sp.value;
+ if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", sp.param);
return DRM_ERR(EINVAL);