diff options
-rw-r--r-- | libdrm/xf86drm.c | 12 | ||||
-rw-r--r-- | linux-core/ati_pcigart.c | 69 | ||||
-rw-r--r-- | linux-core/drmP.h | 3 | ||||
-rw-r--r-- | linux-core/drm_compat.c | 107 | ||||
-rw-r--r-- | linux-core/drm_compat.h | 23 | ||||
-rw-r--r-- | linux-core/drm_fence.c | 75 | ||||
-rw-r--r-- | linux-core/drm_vm.c | 81 | ||||
-rw-r--r-- | linux-core/i915_fence.c | 18 | ||||
-rw-r--r-- | shared-core/drm.h | 14 | ||||
-rw-r--r-- | shared-core/drm_pciids.txt | 1 | ||||
-rw-r--r-- | shared-core/nouveau_drm.h | 29 | ||||
-rw-r--r-- | shared-core/nouveau_drv.h | 13 | ||||
-rw-r--r-- | shared-core/nouveau_fifo.c | 9 | ||||
-rw-r--r-- | shared-core/nouveau_irq.c | 64 | ||||
-rw-r--r-- | shared-core/nouveau_mem.c | 4 | ||||
-rw-r--r-- | shared-core/nouveau_object.c | 234 | ||||
-rw-r--r-- | shared-core/nouveau_reg.h | 10 | ||||
-rw-r--r-- | shared-core/nouveau_state.c | 13 | ||||
-rw-r--r-- | shared-core/nv40_graph.c | 8 | ||||
-rw-r--r-- | shared-core/r128_cce.c | 1 | ||||
-rw-r--r-- | shared-core/r128_drv.h | 2 | ||||
-rw-r--r-- | shared-core/radeon_cp.c | 6 | ||||
-rw-r--r-- | shared-core/radeon_drm.h | 1 | ||||
-rw-r--r-- | shared-core/radeon_drv.h | 4 | ||||
-rw-r--r-- | shared-core/radeon_state.c | 6 |
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); |