From 01dcc47d895997f77c9457558e974d41c23ed4e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Feb 2008 16:24:17 +1000 Subject: drm: add modesetting as a driver feature. This change adds a driver feature that for i915 is controlled by a module parameter. You now need to do insmod i915.ko modeset=1 to enable it the modesetting paths. It also fixes up lots of X paths. I can run my new DDX driver on this code with and without modesetting enabled --- linux-core/drmP.h | 1 + linux-core/drm_drv.c | 3 ++- linux-core/drm_fops.c | 3 ++- linux-core/drm_irq.c | 5 +++++ linux-core/drm_stub.c | 9 ++++++--- linux-core/i915_drv.c | 10 ++++++++-- 6 files changed, 24 insertions(+), 7 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 51b02dc8..1a0a5659 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -106,6 +106,7 @@ struct drm_file; #define DRIVER_IRQ_SHARED 0x80 #define DRIVER_DMA_QUEUE 0x100 #define DRIVER_FB_DMA 0x200 +#define DRIVER_MODESET 0x400 /*@}*/ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 4932ea59..dd76421f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -414,7 +414,8 @@ static void drm_cleanup(struct drm_device * dev) drm_ht_remove(&dev->object_hash); drm_put_minor(&dev->primary); - drm_put_minor(&dev->control); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 5a74f424..fcadc544 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -481,7 +481,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&dev->ctxlist_mutex); - drm_fb_release(filp); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_fb_release(filp); file_priv->master = NULL; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 637f5e1d..7dddbe19 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -261,6 +261,9 @@ int drm_irq_uninstall(struct drm_device * dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -306,6 +309,8 @@ int drm_control(struct drm_device *dev, void *data, case DRM_INST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && ctl->irq != dev->irq) return -EINVAL; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 334c8f03..6856075b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -343,8 +343,10 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, goto err_g3; } - if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) - goto err_g3; + /* only add the control node on a modesetting platform */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) + goto err_g3; if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) goto err_g4; @@ -361,7 +363,8 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, err_g5: drm_put_minor(&dev->primary); err_g4: - drm_put_minor(&dev->control); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 6c12f1a1..b844dfe6 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -39,6 +39,9 @@ static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; +unsigned int i915_modeset = 0; +module_param_named(modeset, i915_modeset, int, 0400); + #ifdef I915_HAVE_FENCE extern struct drm_fence_driver i915_fence_driver; #endif @@ -563,8 +566,8 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .unload = i915_driver_unload, -/* .lastclose = i915_driver_lastclose, - .preclose = i915_driver_preclose, */ + .lastclose = i915_driver_lastclose, + .preclose = i915_driver_preclose, .suspend = i915_suspend, .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, @@ -624,6 +627,9 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init i915_init(void) { driver.num_ioctls = i915_max_ioctl; + if (i915_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + return drm_init(&driver, pciidlist); } -- cgit v1.2.3 From 8ef838e5ff7b3c005d7fbc725e17bcccd0e1e1eb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Feb 2008 13:47:15 +0100 Subject: Add a compat kmap_atomic_prot_pfn to do quick kernel map / unmaps of PCI- or high memory. This is substantially more efficient than drm_bo_kmap, since the mapping only lives on a single processor. Unmapping is done use kunmap_atomic(). Flushes only a single tlb() entry. Add a support utility int drm_bo_pfn_prot() that returns the pfn and desired page protection for a given bo offset. This is all intended for relocations in bound TTMS or vram. Mapping-accessing-unmapping must be atomic, either using preempt_xx() macros or a spinlock. --- linux-core/drm_bo_move.c | 33 +++++++++++++++++++++++++++++++++ linux-core/drm_compat.c | 32 ++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 5 +++++ linux-core/drm_objects.h | 4 ++++ 4 files changed, 74 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index b06a09f0..30e0f43f 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -595,3 +595,36 @@ void drm_bo_kunmap(struct drm_bo_kmap_obj *map) map->page = NULL; } EXPORT_SYMBOL(drm_bo_kunmap); + +int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot) +{ + struct drm_bo_mem_reg *mem = &bo->mem; + struct drm_device *dev = bo->dev; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; + int ret; + + ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, + &bus_size); + if (ret) + return -EINVAL; + + if (bus_size != 0) + *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT; + else if (!bo->ttm) + return -EINVAL; + else + *pfn = page_to_pfn(drm_ttm_get_page(bo->ttm, dst_offset >> PAGE_SHIFT)); + + *prot = (mem->flags & DRM_BO_FLAG_CACHED) ? + PAGE_KERNEL : drm_kernel_io_prot(man->drm_bus_maptype); + + return 0; +} +EXPORT_SYMBOL(drm_bo_pfn_prot); + diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index a745a7d9..32e43a0a 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -729,3 +729,35 @@ void *idr_replace(struct idr *idp, void *ptr, int id) } EXPORT_SYMBOL(idr_replace); #endif + +#if defined(CONFIG_X86) + +#define drm_kmap_get_fixmap_pte(vaddr) \ + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) + +void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, + pgprot_t protection) +{ + enum fixed_addresses idx; + unsigned long vaddr; + static pte_t *km_pte; + static int initialized = 0; + + if (unlikely(!initialized)) { + km_pte = drm_kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); + initialized = 1; + } + + pagefault_disable(); + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte(km_pte-idx, pfn_pte(pfn, protection)); + + return (void*) vaddr; +} + +EXPORT_SYMBOL(kmap_atomic_prot_pfn); + +#endif + + diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index f8933e0c..39027cf4 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,4 +328,9 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif +#if defined(CONFIG_X86) +#define DRM_KMAP_ATOMIC_PROT_PFN +extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, + pgprot_t protection); +#endif #endif diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index e43e8dfd..8055afe1 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -738,6 +738,10 @@ static inline void *drm_bmo_virtual(struct drm_bo_kmap_obj *map, int *is_iomem) extern void drm_bo_kunmap(struct drm_bo_kmap_obj *map); extern int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, unsigned long num_pages, struct drm_bo_kmap_obj *map); +extern int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot); /* -- cgit v1.2.3 From cdbd616ea5f0ee491ff82cac74b918a14b039917 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Feb 2008 10:16:24 +1000 Subject: agp: export the correct symbol --- linux-core/drm_agpsupport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 02187017..f58d5516 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -666,7 +666,7 @@ void drm_agp_chipset_flush(struct drm_device *dev) { agp_flush_chipset(dev->agp->bridge); } -EXPORT_SYMBOL(drm_agp_flush_chipset); +EXPORT_SYMBOL(drm_agp_chipset_flush); #endif #endif /* __OS_HAS_AGP */ -- cgit v1.2.3 From 1d068973d5f5e6d8d14b4c0c6e28588107aafc6f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Feb 2008 13:31:14 +0100 Subject: Fix compilation breakage on x86-64. --- linux-core/drm_compat.c | 3 +-- linux-core/drm_compat.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 32e43a0a..eb6c5d81 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -730,8 +730,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) EXPORT_SYMBOL(idr_replace); #endif -#if defined(CONFIG_X86) - +#if defined(DRM_KMAP_ATOMIC_PROT_PFN) #define drm_kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 39027cf4..08892e6b 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,7 +328,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif -#if defined(CONFIG_X86) +#if (defined(CONFIG_X86) && defined(CONFIG_X86_32)) #define DRM_KMAP_ATOMIC_PROT_PFN extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); -- cgit v1.2.3 From 09999c90ab1bf3f7d8b277895c962c8a7b3afc18 Mon Sep 17 00:00:00 2001 From: Patrice Mandin Date: Fri, 29 Feb 2008 21:57:40 +0100 Subject: FIX_KMAP_BEGIN requires CONFIG_HIMEM (see include/asm-i386.h/fixmap.h) --- linux-core/drm_compat.c | 2 +- linux-core/drm_compat.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index eb6c5d81..d4044cbd 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -730,7 +730,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) EXPORT_SYMBOL(idr_replace); #endif -#if defined(DRM_KMAP_ATOMIC_PROT_PFN) +#if defined(DRM_KMAP_ATOMIC_PROT_PFN) && defined(CONFIG_HIMEM) #define drm_kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 08892e6b..136a7296 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,7 +328,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif -#if (defined(CONFIG_X86) && defined(CONFIG_X86_32)) +#if (defined(CONFIG_X86) && defined(CONFIG_X86_32) && defined(CONFIG_HIMEM)) #define DRM_KMAP_ATOMIC_PROT_PFN extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); -- cgit v1.2.3 From d41846adb72ba89c94ea1164e366032b1d36bd55 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 Mar 2008 13:35:23 -0800 Subject: Clarify through the names what drm_ttm_alloc_pages() and friend actually did. These are all about the page directory (pointers to pages) rather than the actual pages backing the allocation. --- linux-core/drm_objects.h | 2 +- linux-core/drm_ttm.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 8055afe1..69a5c27f 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -384,7 +384,7 @@ extern int drm_ttm_destroy(struct drm_ttm *ttm); * The array of page pointers was allocated with vmalloc * instead of drm_calloc. */ -#define DRM_TTM_PAGE_VMALLOC (1 << 4) +#define DRM_TTM_PAGEDIR_VMALLOC (1 << 4) /* * This ttm is mapped from user space */ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index a9d87338..cc80b132 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,11 +42,12 @@ void drm_ttm_cache_flush(void) } EXPORT_SYMBOL(drm_ttm_cache_flush); -/* - * Use kmalloc if possible. Otherwise fall back to vmalloc. +/** + * Allocates storage for pointers to the pages that back the ttm. + * + * Uses kmalloc if possible. Otherwise falls back to vmalloc. */ - -static void drm_ttm_alloc_pages(struct drm_ttm *ttm) +static void drm_ttm_alloc_page_directory(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); ttm->pages = NULL; @@ -60,19 +61,19 @@ static void drm_ttm_alloc_pages(struct drm_ttm *ttm) if (!ttm->pages) { ttm->pages = vmalloc_user(size); if (ttm->pages) - ttm->page_flags |= DRM_TTM_PAGE_VMALLOC; + ttm->page_flags |= DRM_TTM_PAGEDIR_VMALLOC; } if (!ttm->pages) drm_free_memctl(size); } -static void drm_ttm_free_pages(struct drm_ttm *ttm) +static void drm_ttm_free_page_directory(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); - if (ttm->page_flags & DRM_TTM_PAGE_VMALLOC) { + if (ttm->page_flags & DRM_TTM_PAGEDIR_VMALLOC) { vfree(ttm->pages); - ttm->page_flags &= ~DRM_TTM_PAGE_VMALLOC; + ttm->page_flags &= ~DRM_TTM_PAGEDIR_VMALLOC; } else { drm_free(ttm->pages, size, DRM_MEM_TTM); } @@ -215,7 +216,7 @@ int drm_ttm_destroy(struct drm_ttm *ttm) else drm_ttm_free_alloced_pages(ttm); - drm_ttm_free_pages(ttm); + drm_ttm_free_page_directory(ttm); } drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); @@ -349,7 +350,7 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, * Account also for AGP module memory usage. */ - drm_ttm_alloc_pages(ttm); + drm_ttm_alloc_page_directory(ttm); if (!ttm->pages) { drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); -- cgit v1.2.3 From 4dbf447f4305e3c2aa8914b5ccfc07d9bf8ef28e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 15:28:38 +1000 Subject: drm: fixup compat with old x.org drivers --- linux-core/drm_drv.c | 15 ++++++++++++--- linux-core/i915_drv.c | 5 +++-- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index dd76421f..434789dd 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -187,7 +187,9 @@ int drm_lastclose(struct drm_device * dev) DRM_DEBUG("\n"); -/* return 0; */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + drm_bo_driver_finish(dev); + /* * We can't do much about this function failing. */ @@ -425,13 +427,20 @@ int drm_minors_cleanup(int id, void *ptr, void *data) struct drm_minor *minor = ptr; struct drm_device *dev; struct drm_driver *driver = data; - if (id < 127 || id > 192) - return 0; dev = minor->dev; if (minor->dev->driver != driver) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (minor->type != DRM_MINOR_CONTROL) + return 0; + } else { + if (minor->type != DRM_MINOR_LEGACY) + return 0; + } + + if (dev) pci_dev_put(dev->pdev); drm_cleanup(dev); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index b844dfe6..0e65c0cd 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,8 +48,8 @@ extern struct drm_fence_driver i915_fence_driver; #ifdef I915_HAVE_BUFFER -static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; +static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; static struct drm_bo_driver i915_bo_driver = { .mem_type_prio = i915_mem_prios, @@ -566,6 +566,7 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .unload = i915_driver_unload, + .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .suspend = i915_suspend, -- cgit v1.2.3 From f78cdac8e512642db1aaf09bf9178e23ede25586 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 15:28:59 +1000 Subject: fixup previous merge --- linux-core/drm_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index b7b8e395..9b982662 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -806,5 +806,5 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, } EXPORT_SYMBOL(kmap_atomic_prot_pfn); - +#endif -- cgit v1.2.3 From 638353103d009d44bd5bdbe97cc7cef1bf011cdf Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Wed, 5 Mar 2008 15:08:46 +0800 Subject: i915: Evict if relocatee buffer is CACHED_MAPPED before writting relocations, otherwise the GPU probably sees some inconsistent data. Fix fd.o bug#14656 --- linux-core/drm_bo.c | 3 ++- linux-core/drm_objects.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3b180d15..17180d8d 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1066,7 +1066,7 @@ static int drm_bo_busy(struct drm_buffer_object *bo) return 0; } -static int drm_bo_evict_cached(struct drm_buffer_object *bo) +int drm_bo_evict_cached(struct drm_buffer_object *bo) { int ret = 0; @@ -1076,6 +1076,7 @@ static int drm_bo_evict_cached(struct drm_buffer_object *bo) return ret; } +EXPORT_SYMBOL(drm_bo_evict_cached); /* * Wait until a buffer is unmapped. */ diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 69a5c27f..fd32f0f4 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -697,7 +697,7 @@ extern int drm_bo_do_validate(struct drm_buffer_object *bo, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, struct drm_bo_info_rep *rep); - +extern int drm_bo_evict_cached(struct drm_buffer_object *bo); /* * Buffer object memory move- and map helpers. * drm_bo_move.c -- cgit v1.2.3 From 180c9188f4cb7163f1e3e7d5098eaabf29a98540 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 13:27:10 +1000 Subject: drm/ttm: add ioctl to get back memory managed area sized taken from modesetting branch but could be useful outside it. --- linux-core/drm_bo.c | 37 +++++++++++++++++++++++++++++++++++++ linux-core/drm_drv.c | 2 ++ linux-core/drm_objects.h | 2 ++ 3 files changed, 41 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 95802fe2..b67946eb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2283,6 +2283,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->size = p_size; INIT_LIST_HEAD(&man->lru); INIT_LIST_HEAD(&man->pinned); @@ -2553,6 +2554,42 @@ int drm_mm_unlock_ioctl(struct drm_device *dev, return 0; } +int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + struct drm_mm_info_arg *arg = data; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_bo_driver *driver = dev->driver->bo_driver; + struct drm_mem_type_manager *man; + int ret = 0; + int mem_type = arg->mem_type; + + if (!driver) { + DRM_ERROR("Buffer objects are not supported by this driver\n"); + return -EINVAL; + } + + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", arg->mem_type); + return -EINVAL; + } + + mutex_lock(&dev->struct_mutex); + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized\n"); + ret = -EINVAL; + goto out; + } + + + man = &bm->man[arg->mem_type]; + + arg->p_size = man->size; + +out: + mutex_unlock(&dev->struct_mutex); + + return ret; +} /* * buffer object vm functions. */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 1daa8653..b8b8333e 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -148,6 +148,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0), + + DRM_IOCTL_DEF(DRM_IOCTL_MM_INFO, drm_mm_info_ioctl, 0), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index fd32f0f4..ae0725c1 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -525,6 +525,7 @@ struct drm_mem_type_manager { unsigned long io_offset; unsigned long io_size; void *io_addr; + uint64_t size; /* size of managed area for reporting to userspace */ }; struct drm_bo_lock { @@ -651,6 +652,7 @@ extern int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_version_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_driver_finish(struct drm_device *dev); extern int drm_bo_driver_init(struct drm_device *dev); -- cgit v1.2.3 From d5c0101252e9f48ef1b59f48c05fea7007df97f0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 18 Feb 2008 10:39:21 +1000 Subject: ttm: make sure userspace can't destroy kernel create memory managers this adds something to say the kernel initialised the memory region not the userspace. and blocks userspace from deallocating kernel areas --- linux-core/drm_bo.c | 30 ++++++++++++++++++++---------- linux-core/drm_objects.h | 6 ++++-- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index b67946eb..3e8ffa0f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2180,7 +2180,7 @@ restart: return 0; } -int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) +int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean) { struct drm_buffer_manager *bm = &dev->bm; struct drm_mem_type_manager *man = &bm->man[mem_type]; @@ -2196,6 +2196,13 @@ int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) "memory manager type %u\n", mem_type); return ret; } + + if ((man->kern_init_type) && (kern_clean == 0)) { + DRM_ERROR("Trying to take down kernel initialized " + "memory manager type %u\n", mem_type); + return -EPERM; + } + man->use_type = 0; man->has_type = 0; @@ -2247,9 +2254,9 @@ static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) return ret; } -int drm_bo_init_mm(struct drm_device *dev, - unsigned type, - unsigned long p_offset, unsigned long p_size) +int drm_bo_init_mm(struct drm_device *dev, unsigned type, + unsigned long p_offset, unsigned long p_size, + int kern_init) { struct drm_buffer_manager *bm = &dev->bm; int ret = -EINVAL; @@ -2283,6 +2290,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->kern_init_type = kern_init; man->size = p_size; INIT_LIST_HEAD(&man->lru); @@ -2316,7 +2324,7 @@ int drm_bo_driver_finish(struct drm_device *dev) man = &bm->man[i]; if (man->has_type) { man->use_type = 0; - if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { + if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i, 1)) { ret = -EBUSY; DRM_ERROR("DRM memory manager type %d " "is not clean.\n", i); @@ -2386,7 +2394,7 @@ int drm_bo_driver_init(struct drm_device *dev) * Initialize the system memory buffer type. * Other types need to be driver / IOCTL initialized. */ - ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0); + ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1); if (ret) goto out_unlock; @@ -2446,7 +2454,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ goto out; } ret = drm_bo_init_mm(dev, arg->mem_type, - arg->p_offset, arg->p_size); + arg->p_offset, arg->p_size, 0); out: mutex_unlock(&dev->struct_mutex); @@ -2485,9 +2493,11 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f goto out; } ret = 0; - if (drm_bo_clean_mm(dev, arg->mem_type)) { - DRM_ERROR("Memory manager type %d not clean. " - "Delaying takedown\n", arg->mem_type); + if ((ret = drm_bo_clean_mm(dev, arg->mem_type, 0))) { + if (ret == -EINVAL) + DRM_ERROR("Memory manager type %d not clean. " + "Delaying takedown\n", arg->mem_type); + ret = 0; } out: mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index ae0725c1..69e3f67f 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -516,6 +516,7 @@ struct drm_buffer_object { struct drm_mem_type_manager { int has_type; int use_type; + int kern_init_type; struct drm_mm manager; struct list_head lru; struct list_head pinned; @@ -684,9 +685,10 @@ extern int drm_bo_mem_space(struct drm_buffer_object *bo, extern int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, int no_wait, int move_unfenced); -extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type); +extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean); extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, - unsigned long p_offset, unsigned long p_size); + unsigned long p_offset, unsigned long p_size, + int kern_init); extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, int use_old_fence_class, -- cgit v1.2.3 From a875821f7b19a1bcee238cef5c3b507d2869542d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 5 Mar 2008 19:25:03 +1000 Subject: drm: Fix for non-coherent DMA PowerPC This patch fixes bits of the DRM so to make the radeon DRI work on non-cache coherent PCI DMA variants of the PowerPC processors. It moves the few places that needs change to wrappers to that other architectures with similar issues can easily add their own changes to those wrappers, at least until we have more useful generic kernel API. Signed-off-by: Benjamin Herrenschmidt --- linux-core/ati_pcigart.c | 6 ++++++ linux-core/drm_scatter.c | 11 ++++++++++- linux-core/drm_vm.c | 19 ++++++++++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'linux-core') diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 68029635..93519e5f 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -224,6 +224,12 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga } } + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) + dma_sync_single_for_device(&dev->pdev->dev, + bus_address, + max_pages * sizeof(u32), + PCI_DMA_TODEVICE); + ret = 1; #if defined(__i386__) || defined(__x86_64__) diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index 77b9f95d..dfae4b84 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -36,6 +36,15 @@ #define DEBUG_SCATTER 0 +static inline void *drm_vmalloc_dma(unsigned long size) +{ +#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) + return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL | _PAGE_NO_CACHE); +#else + return vmalloc_32(size); +#endif +} + void drm_sg_cleanup(struct drm_sg_mem *entry) { struct page *page; @@ -105,7 +114,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) } memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr)); - entry->virtual = vmalloc_32(pages << PAGE_SHIFT); + entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT); if (!entry->virtual) { drm_free(entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 15e1c0f5..ffda8284 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -59,17 +59,27 @@ pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) pgprot_val(tmp) |= _PAGE_NO_CACHE; if (map_type == _DRM_REGISTERS) pgprot_val(tmp) |= _PAGE_GUARDED; -#endif -#if defined(__ia64__) +#elif defined(__ia64__) if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) tmp = pgprot_writecombine(tmp); else tmp = pgprot_noncached(tmp); +#elif defined(__sparc__) + tmp = pgprot_noncached(tmp); #endif return tmp; } +static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) +{ + pgprot_t tmp = vm_get_page_prot(vma->vm_flags); + +#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) + tmp |= _PAGE_NO_CACHE; +#endif + return tmp; +} /** * \c nopage method for AGP virtual memory. @@ -628,9 +638,6 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) offset = dev->driver->get_reg_ofs(dev); vma->vm_flags |= VM_IO; /* not in core dump */ vma->vm_page_prot = drm_io_prot(map->type, vma); -#ifdef __sparc__ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, @@ -649,6 +656,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) page_to_pfn(virt_to_page(map->handle)), vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + vma->vm_page_prot = drm_dma_prot(map->type, vma); /* fall through to _DRM_SHM */ case _DRM_SHM: vma->vm_ops = &drm_vm_shm_ops; @@ -661,6 +669,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_sg_ops; vma->vm_private_data = (void *)map; vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = drm_dma_prot(map->type, vma); break; case _DRM_TTM: return drm_bo_mmap_locked(vma, filp, map); -- cgit v1.2.3 From 12574590cdf7871755d1939463ca6898251fd0d1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Mar 2008 05:21:50 +1000 Subject: drm: reorganise minor number handling using code from modesetting branch Rip out the whole head thing and replace it with an idr and drm_minor structure. --- linux-core/drmP.h | 42 ++++++------ linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 14 ++-- linux-core/drm_bo_lock.c | 4 +- linux-core/drm_drv.c | 57 ++++++++--------- linux-core/drm_fence.c | 4 +- linux-core/drm_fops.c | 39 ++++++------ linux-core/drm_object.c | 16 ++--- linux-core/drm_proc.c | 67 ++++++++++++-------- linux-core/drm_stub.c | 151 ++++++++++++++++++++++++++++---------------- linux-core/drm_sysfs.c | 46 ++++++++------ linux-core/drm_vm.c | 20 +++--- linux-core/i810_dma.c | 4 +- 13 files changed, 261 insertions(+), 205 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f196e11d..1fea807b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -408,13 +408,12 @@ enum drm_ref_type { struct drm_file { int authenticated; int master; - int minor; pid_t pid; uid_t uid; drm_magic_t magic; unsigned long ioctl_count; struct list_head lhead; - struct drm_head *head; + struct drm_minor *minor; int remove_auth_on_close; unsigned long lock_count; @@ -721,16 +720,19 @@ struct drm_driver { struct pci_driver pci_driver; }; +#define DRM_MINOR_UNASSIGNED 0 +#define DRM_MINOR_LEGACY 1 + /** - * DRM head structure. This structure represent a video head on a card - * that may contain multiple heads. Embed one per head of these in the - * private drm_device structure. + * DRM minor structure. This structure represents a drm minor number. */ -struct drm_head { - int minor; /**< Minor device number */ +struct drm_minor { + int index; /**< Minor device number */ + int type; /**< Control or render */ + dev_t device; /**< Device number for mknod */ + struct device kdev; /**< Linux device */ struct drm_device *dev; struct proc_dir_entry *dev_root; /**< proc directory entry */ - dev_t device; /**< Device number for mknod */ struct class_device *dev_class; }; @@ -740,7 +742,6 @@ struct drm_head { * may contain multiple heads. */ struct drm_device { - struct device dev; /**< Linux device */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ @@ -870,7 +871,7 @@ struct drm_device { struct drm_driver *driver; drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; - struct drm_head primary; /**< primary screen head */ + struct drm_minor *primary; /**< render type primary screen head */ struct drm_fence_manager fm; struct drm_buffer_manager bm; @@ -1187,23 +1188,20 @@ extern void drm_agp_chipset_flush(struct drm_device *dev); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_head(struct drm_head * head); +extern int drm_put_minor(struct drm_minor **minor); extern unsigned int drm_debug; /* 1 to enable debug output */ -extern unsigned int drm_cards_limit; -extern struct drm_head **drm_heads; + extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; +extern struct idr drm_minors_idr; + extern drm_local_map_t *drm_getsarea(struct drm_device *dev); /* Proc support (drm_proc.h) */ -extern int drm_proc_init(struct drm_device *dev, - int minor, - struct proc_dir_entry *root, - struct proc_dir_entry **dev_root); -extern int drm_proc_cleanup(int minor, - struct proc_dir_entry *root, - struct proc_dir_entry *dev_root); +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root); +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root); /* Scatter Gather Support (drm_scatter.h) */ extern void drm_sg_cleanup(struct drm_sg_mem * entry); @@ -1226,8 +1224,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(void); -extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); -extern void drm_sysfs_device_remove(struct drm_device *dev); +extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_device_remove(struct drm_minor *minor); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index f58d5516..0aa94a75 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(drm_agp_acquire); int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return drm_agp_acquire((struct drm_device *) file_priv->head->dev); + return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); } /** diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 17180d8d..95802fe2 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1190,7 +1190,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { struct drm_buffer_object *bo; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret = 0; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; @@ -1262,7 +1262,7 @@ out: static int drm_buffer_object_unmap(struct drm_file *file_priv, uint32_t handle) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; struct drm_ref_object *ro; int ret = 0; @@ -1654,7 +1654,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int ret; @@ -1690,7 +1690,7 @@ EXPORT_SYMBOL(drm_bo_handle_validate); static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; mutex_lock(&dev->struct_mutex); @@ -1713,7 +1713,7 @@ static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle, uint32_t hint, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; @@ -1833,7 +1833,7 @@ EXPORT_SYMBOL(drm_buffer_object_create); static int drm_bo_add_user_object(struct drm_file *file_priv, struct drm_buffer_object *bo, int shareable) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -1881,7 +1881,7 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil if (bo_type == drm_bo_type_user) req->flags &= ~DRM_BO_FLAG_SHAREABLE; - ret = drm_buffer_object_create(file_priv->head->dev, + ret = drm_buffer_object_create(file_priv->minor->dev, req->size, bo_type, req->flags, req->hint, req->page_alignment, req->buffer_start, &entry); diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index f967fb7c..2795384e 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -141,7 +141,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) * while holding it. */ - dev = file_priv->head->dev; + dev = file_priv->minor->dev; mutex_lock(&dev->struct_mutex); ret = drm_add_user_object(file_priv, &lock->base, 0); lock->base.remove = &drm_bo_write_lock_remove; @@ -156,7 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ref_object *ro; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 3c2794d0..1daa8653 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -416,35 +416,35 @@ static void drm_cleanup(struct drm_device * dev) drm_mm_takedown(&dev->offset_manager); drm_ht_remove(&dev->object_hash); - drm_put_head(&dev->primary); + drm_put_minor(&dev->primary); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); } -void drm_exit(struct drm_driver *driver) +int drm_minors_cleanup(int id, void *ptr, void *data) { - int i; - struct drm_device *dev = NULL; - struct drm_head *head; + struct drm_minor *minor = ptr; + struct drm_device *dev; + struct drm_driver *driver = data; + + dev = minor->dev; + if (minor->dev->driver != driver) + return 0; + + if (minor->type != DRM_MINOR_LEGACY) + return 0; + if (dev) + pci_dev_put(dev->pdev); + drm_cleanup(dev); + return 1; +} + +void drm_exit(struct drm_driver *driver) +{ DRM_DEBUG("\n"); if (drm_fb_loaded) { - for (i = 0; i < drm_cards_limit; i++) { - head = drm_heads[i]; - if (!head) - continue; - if (!head->dev) - continue; - if (head->dev->driver != driver) - continue; - dev = head->dev; - if (dev) { - /* release the pci driver */ - if (dev->pdev) - pci_dev_put(dev->pdev); - drm_cleanup(dev); - } - } + idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver); } else pci_unregister_driver(&driver->pci_driver); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -467,6 +467,7 @@ static int __init drm_core_init(void) unsigned long avail_memctl_mem; unsigned long max_memctl_mem; + idr_init(&drm_minors_idr); si_meminfo(&si); /* @@ -488,11 +489,6 @@ static int __init drm_core_init(void) drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit); ret = -ENOMEM; - drm_cards_limit = - (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); - drm_heads = drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); - if (!drm_heads) - goto err_p1; if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) goto err_p1; @@ -521,7 +517,8 @@ err_p3: drm_sysfs_destroy(); err_p2: unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + + idr_destroy(&drm_minors_idr); err_p1: return ret; } @@ -533,7 +530,7 @@ static void __exit drm_core_exit(void) unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + idr_destroy(&drm_minors_idr); } module_init(drm_core_init); @@ -593,7 +590,7 @@ EXPORT_SYMBOL(drm_ioctl); long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ioctl_desc *ioctl; drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); @@ -605,7 +602,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++file_priv->ioctl_count; DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", - current->pid, cmd, nr, (long)old_encode_dev(file_priv->head->device), + current->pid, cmd, nr, (long)old_encode_dev(file_priv->minor->device), file_priv->authenticated); if ((nr >= DRM_CORE_IOCTL_COUNT) && diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 247bc0a4..9d80327f 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -494,7 +494,7 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, int drm_fence_add_user_object(struct drm_file *priv, struct drm_fence_object *fence, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -590,7 +590,7 @@ void drm_fence_manager_takedown(struct drm_device *dev) struct drm_fence_object *drm_lookup_fence_object(struct drm_file *priv, uint32_t handle) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_fence_object *fence; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 0e1c486c..7fe274a2 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -128,16 +128,15 @@ static int drm_setup(struct drm_device * dev) int drm_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + int minor_id = iminor(inode); + struct drm_minor *minor; int retcode = 0; - if (!((minor >= 0) && (minor < drm_cards_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - if (!drm_heads[minor]) - return -ENODEV; - - if (!(dev = drm_heads[minor]->dev)) + if (!(dev = minor->dev)) return -ENODEV; retcode = drm_open_helper(inode, filp, dev); @@ -176,19 +175,18 @@ EXPORT_SYMBOL(drm_open); int drm_stub_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + struct drm_minor *minor; + int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *old_fops; DRM_DEBUG("\n"); - if (!((minor >= 0) && (minor < drm_cards_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - - if (!drm_heads[minor]) - return -ENODEV; - - if (!(dev = drm_heads[minor]->dev)) + + if (!(dev = minor->dev)) return -ENODEV; old_fops = filp->f_op; @@ -233,7 +231,7 @@ static int drm_cpu_valid(void) static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev) { - int minor = iminor(inode); + int minor_id = iminor(inode); struct drm_file *priv; int ret; int i, j; @@ -243,7 +241,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (!drm_cpu_valid()) return -EINVAL; - DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id); priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); if (!priv) @@ -254,8 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current->euid; priv->pid = current->pid; - priv->minor = minor; - priv->head = drm_heads[minor]; + priv->minor = idr_find(&drm_minors_idr, minor_id); priv->ioctl_count = 0; /* for compatibility root is always authenticated */ priv->authenticated = capable(CAP_SYS_ADMIN); @@ -320,11 +317,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, int drm_fasync(int fd, struct file *filp, int on) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int retcode; DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, - (long)old_encode_dev(priv->head->device)); + (long)old_encode_dev(priv->minor->device)); retcode = fasync_helper(fd, filp, on, &dev->buf_async); if (retcode < 0) return retcode; @@ -374,7 +371,7 @@ static void drm_object_release(struct file *filp) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int retcode = 0; lock_kernel(); @@ -389,7 +386,7 @@ int drm_release(struct inode *inode, struct file *filp) */ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - current->pid, (long)old_encode_dev(file_priv->head->device), + current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index 7d2e3a2b..2994b716 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -33,7 +33,7 @@ int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; DRM_ASSERT_LOCKED(&dev->struct_mutex); @@ -58,7 +58,7 @@ EXPORT_SYMBOL(drm_add_user_object); struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_hash_item *hash; int ret; struct drm_user_object *item; @@ -85,7 +85,7 @@ EXPORT_SYMBOL(drm_lookup_user_object); static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; if (atomic_dec_and_test(&item->refcount)) { @@ -121,7 +121,7 @@ int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced struct drm_ref_object *item; struct drm_open_hash *ht = &priv->refd_object_hash[ref_action]; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); if (!referenced_object->shareable && priv != referenced_object->owner) { DRM_ERROR("Not allowed to reference this object\n"); return -EINVAL; @@ -178,7 +178,7 @@ struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv, struct drm_hash_item *hash; int ret; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], (unsigned long)referenced_object, &hash); if (ret) @@ -212,7 +212,7 @@ void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item) struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action]; enum drm_ref_type unref_action; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); unref_action = item->unref_action; if (atomic_dec_and_test(&item->refcount)) { ret = drm_ht_remove_item(ht, &item->hash); @@ -239,7 +239,7 @@ EXPORT_SYMBOL(drm_remove_ref_object); int drm_user_object_ref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type, struct drm_user_object **object) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_hash_item *hash; int ret; @@ -269,7 +269,7 @@ out_err: int drm_user_object_unref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_ref_object *ro; int ret; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 3012c5b0..67afee8e 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -90,34 +90,35 @@ static struct drm_proc_list { * "/proc/dri/%minor%/", and each entry in proc_list as * "/proc/dri/%minor%/%name%". */ -int drm_proc_init(struct drm_device * dev, int minor, - struct proc_dir_entry *root, struct proc_dir_entry **dev_root) +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root) { struct proc_dir_entry *ent; int i, j; char name[64]; - sprintf(name, "%d", minor); - *dev_root = proc_mkdir(name, root); - if (!*dev_root) { + sprintf(name, "%d", minor_id); + minor->dev_root = proc_mkdir(name, root); + if (!minor->dev_root) { DRM_ERROR("Cannot create /proc/dri/%s\n", name); return -1; } for (i = 0; i < DRM_PROC_ENTRIES; i++) { ent = create_proc_entry(drm_proc_list[i].name, - S_IFREG | S_IRUGO, *dev_root); + S_IFREG | S_IRUGO, minor->dev_root); if (!ent) { DRM_ERROR("Cannot create /proc/dri/%s/%s\n", name, drm_proc_list[i].name); for (j = 0; j < i; j++) remove_proc_entry(drm_proc_list[i].name, - *dev_root); + minor->dev_root); remove_proc_entry(name, root); + minor->dev_root = NULL; return -1; } ent->read_proc = drm_proc_list[i].f; - ent->data = dev; + ent->data = minor; } return 0; } @@ -132,18 +133,17 @@ int drm_proc_init(struct drm_device * dev, int minor, * * Remove all proc entries created by proc_init(). */ -int drm_proc_cleanup(int minor, struct proc_dir_entry *root, - struct proc_dir_entry *dev_root) +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) { int i; char name[64]; - if (!root || !dev_root) + if (!root || !minor->dev_root) return 0; for (i = 0; i < DRM_PROC_ENTRIES; i++) - remove_proc_entry(drm_proc_list[i].name, dev_root); - sprintf(name, "%d", minor); + remove_proc_entry(drm_proc_list[i].name, minor->dev_root); + sprintf(name, "%d", minor->index); remove_proc_entry(name, root); return 0; @@ -165,7 +165,8 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root, static int drm_name_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; if (offset > DRM_PROC_LIMIT) { @@ -207,7 +208,8 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, static int drm__vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_map *map; struct drm_map_list *r_list; @@ -264,7 +266,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -287,7 +290,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, static int drm__queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; int i; struct drm_queue *q; @@ -337,7 +341,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset, static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -360,7 +365,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, static int drm__bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_device_dma *dma = dev->dma; int i; @@ -409,7 +415,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -432,7 +439,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, static int drm__objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_buffer_manager *bm = &dev->bm; struct drm_fence_manager *fm = &dev->fm; @@ -496,7 +504,8 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, static int drm_objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -519,7 +528,8 @@ static int drm_objects_info(char *buf, char **start, off_t offset, int request, static int drm__clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_file *priv; @@ -535,7 +545,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, list_for_each_entry(priv, &dev->filelist, lhead) { DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", priv->authenticated ? 'y' : 'n', - priv->minor, + priv->minor->index, priv->pid, priv->uid, priv->magic, priv->ioctl_count); } @@ -552,7 +562,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset, static int drm_clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -566,7 +577,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset, static int drm__vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_vma_entry *pt; struct vm_area_struct *vma; @@ -625,7 +637,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, static int drm_vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 00a24521..6584f51d 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,23 +37,49 @@ #include "drmP.h" #include "drm_core.h" -unsigned int drm_cards_limit = 16; /* Enough for one machine */ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); MODULE_PARM_DESC(debug, "Enable debug output"); -module_param_named(cards_limit, drm_cards_limit, int, 0444); module_param_named(debug, drm_debug, int, 0600); -struct drm_head **drm_heads; +struct idr drm_minors_idr; + struct class *drm_class; struct proc_dir_entry *drm_proc_root; +static int drm_minor_get_id(struct drm_device *dev, int type) +{ + int new_id; + int ret; + int base = 0, limit = 63; + +again: + if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Out of memory expanding drawable idr\n"); + return -ENOMEM; + } + mutex_lock(&dev->struct_mutex); + ret = idr_get_new_above(&drm_minors_idr, NULL, + base, &new_id); + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) { + goto again; + } else if (ret) { + return ret; + } + + if (new_id >= limit) { + idr_remove(&drm_minors_idr, new_id); + return -EINVAL; + } + return new_id; +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) @@ -161,49 +187,60 @@ error_out_unreg: * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_head(struct drm_device * dev, struct drm_head * head) +static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) { - struct drm_head **heads = drm_heads; + struct drm_minor *new_minor; int ret; - int minor; + int minor_id; DRM_DEBUG("\n"); - for (minor = 0; minor < drm_cards_limit; minor++, heads++) { - if (!*heads) { - - *head = (struct drm_head) { - .dev = dev, - .device = MKDEV(DRM_MAJOR, minor), - .minor = minor, - }; - if ((ret = - drm_proc_init(dev, minor, drm_proc_root, - &head->dev_root))) { - printk(KERN_ERR - "DRM: Failed to initialize /proc/dri.\n"); - goto err_g1; - } - - ret = drm_sysfs_device_add(dev, head); - if (ret) { - printk(KERN_ERR - "DRM: Error sysfs_device_add.\n"); - goto err_g2; - } - *heads = head; - - DRM_DEBUG("new minor assigned %d\n", minor); - return 0; + minor_id = drm_minor_get_id(dev, type); + if (minor_id < 0) + return minor_id; + + new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); + if (!new_minor) { + ret = -ENOMEM; + goto err_idr; + } + + new_minor->type = type; + new_minor->device = MKDEV(DRM_MAJOR, minor_id); + new_minor->dev = dev; + new_minor->index = minor_id; + + idr_replace(&drm_minors_idr, new_minor, minor_id); + + if (type == DRM_MINOR_LEGACY) { + ret = drm_proc_init(new_minor, minor_id, drm_proc_root); + if (ret) { + DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); + goto err_mem; } + } else + new_minor->dev_root = NULL; + + ret = drm_sysfs_device_add(new_minor); + if (ret) { + printk(KERN_ERR + "DRM: Error sysfs_device_add.\n"); + goto err_g2; } - DRM_ERROR("out of minors\n"); - return -ENOMEM; + *minor = new_minor; + + DRM_DEBUG("new minor assigned %d\n", minor_id); + return 0; + + err_g2: - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); -err_g1: - *head = (struct drm_head) { - .dev = NULL}; + if (new_minor->type == DRM_MINOR_LEGACY) + drm_proc_cleanup(new_minor, drm_proc_root); +err_mem: + kfree(new_minor); +err_idr: + idr_remove(&drm_minors_idr, minor_id); + *minor = NULL; return ret; } @@ -246,22 +283,29 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, printk(KERN_ERR "DRM: fill_in_dev failed\n"); goto err_g3; } - if ((ret = drm_get_head(dev, &dev->primary))) + + /* only add the control node on a modesetting platform */ + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) goto err_g3; + if (dev->driver->load) + if ((ret = dev->driver->load(dev, ent->driver_data))) + goto err_g4; + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, - driver->date, dev->primary.minor); + driver->date, dev->primary->index); return 0; - - err_g3: +err_g4: + drm_put_minor(&dev->primary); +err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); - err_g2: +err_g2: if (!drm_fb_loaded) pci_release_regions(pdev); - err_g1: +err_g1: if (!drm_fb_loaded) pci_set_drvdata(pdev, NULL); @@ -310,17 +354,18 @@ int drm_put_dev(struct drm_device * dev) * last minor released. * */ -int drm_put_head(struct drm_head * head) +int drm_put_minor(struct drm_minor **minor_p) { - int minor = head->minor; - - DRM_DEBUG("release secondary minor %d\n", minor); + struct drm_minor *minor = *minor_p; + DRM_DEBUG("release secondary minor %d\n", minor->index); - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(head->dev); + if (minor->type == DRM_MINOR_LEGACY) + drm_proc_cleanup(minor, drm_proc_root); + drm_sysfs_device_remove(minor); - *head = (struct drm_head) {.dev = NULL}; + idr_remove(&drm_minors_idr, minor->index); - drm_heads[minor] = NULL; + kfree(minor); + *minor_p = NULL; return 0; } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index c02e2049..32759424 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,7 +19,7 @@ #include "drm_core.h" #include "drmP.h" -#define to_drm_device(d) container_of(d, struct drm_device, dev) +#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) /** * drm_sysfs_suspend - DRM class suspend hook @@ -31,7 +31,8 @@ */ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; printk(KERN_ERR "%s\n", __FUNCTION__); @@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) */ static int drm_sysfs_resume(struct device *dev) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; if (drm_dev->driver->resume) return drm_dev->driver->resume(drm_dev); @@ -122,10 +124,11 @@ void drm_sysfs_destroy(void) static ssize_t show_dri(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_device *dev = to_drm_device(device); - if (dev->driver->dri_library_name) - return dev->driver->dri_library_name(dev, buf); - return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); + struct drm_minor *drm_minor = to_drm_minor(device); + struct drm_device *drm_dev = drm_minor->dev; + if (drm_dev->driver->dri_library_name) + return drm_dev->driver->dri_library_name(drm_dev, buf); + return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } static struct device_attribute device_attrs[] = { @@ -154,25 +157,28 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +int drm_sysfs_device_add(struct drm_minor *minor) { int err; int i, j; + char *minor_str; - dev->dev.parent = &dev->pdev->dev; - dev->dev.class = drm_class; - dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = head->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + minor->kdev.parent = &minor->dev->pdev->dev; + minor->kdev.class = drm_class; + minor->kdev.release = drm_sysfs_device_release; + minor->kdev.devt = minor->device; + minor_str = "card%d"; + + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); - err = device_register(&dev->dev); + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); goto err_out; } for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&dev->dev, &device_attrs[i]); + err = device_create_file(&minor->kdev, &device_attrs[i]); if (err) goto err_out_files; } @@ -182,8 +188,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); err_out: return err; @@ -196,11 +202,11 @@ err_out: * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct drm_device *dev) +void drm_sysfs_device_remove(struct drm_minor *minor) { int i; for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index c481a530..15e1c0f5 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -86,7 +86,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; struct drm_map_list *r_list; struct drm_hash_item *hash; @@ -204,7 +204,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, static void drm_vm_shm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; struct drm_map *map; struct drm_map_list *r_list; @@ -286,7 +286,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_device_dma *dma = dev->dma; unsigned long offset; unsigned long page_nr; @@ -323,7 +323,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, { struct drm_map *map = (struct drm_map *) vma->vm_private_data; struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_sg_mem *entry = dev->sg; unsigned long offset; unsigned long map_offset; @@ -419,7 +419,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { static void drm_vm_open_locked(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *vma_entry; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -437,7 +437,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma) static void drm_vm_open(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; mutex_lock(&dev->struct_mutex); drm_vm_open_locked(vma); @@ -455,7 +455,7 @@ static void drm_vm_open(struct vm_area_struct *vma) static void drm_vm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -491,7 +491,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) struct drm_device_dma *dma; unsigned long length = vma->vm_end - vma->vm_start; - dev = priv->head->dev; + dev = priv->minor->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); @@ -556,7 +556,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; unsigned long offset = 0; struct drm_hash_item *hash; @@ -677,7 +677,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) int drm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 3c9ca3b2..f2bf5d9d 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -113,7 +113,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) drm_i810_buf_priv_t *buf_priv; lock_kernel(); - dev = priv->head->dev; + dev = priv->minor->dev; dev_priv = dev->dev_private; buf = dev_priv->mmap_buffer; buf_priv = buf->dev_private; @@ -141,7 +141,7 @@ static const struct file_operations i810_buffer_fops = { static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_private_t *dev_priv = dev->dev_private; const struct file_operations *old_fops; -- cgit v1.2.3 From 5662934ee467c3a29f9551a40fc7b2f6ee16280a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:50:59 +0000 Subject: Fix connector description table --- linux-core/drm_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1a4624c8..345569b6 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -48,7 +48,8 @@ static struct drm_prop_enum_list drm_dpms_enum_list[] = { DPMSModeOff, "Off" } }; static struct drm_prop_enum_list drm_conn_enum_list[] = -{ { ConnectorVGA, "VGA" }, +{ { ConnectorUnknown, "Unknown" }, + { ConnectorVGA, "VGA" }, { ConnectorDVII, "DVI-I" }, { ConnectorDVID, "DVI-D" }, { ConnectorDVIA, "DVI-A" }, -- cgit v1.2.3 From 3ea1902be993e88c068ce67355e2b3d253d1c9f2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:51:56 +0000 Subject: propogate failed fixups back up --- linux-core/drm_crtc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 345569b6..5f93275a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -458,12 +458,12 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, if (output->crtc != crtc) continue; - if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) { goto done; } } - if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) { goto done; } @@ -517,10 +517,16 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, // drm_crtc_set_screen_sub_pixel_order(dev); done: + if (!ret) { + crtc->mode = saved_mode; + crtc->x = saved_x; + crtc->y = saved_y; + } + if (didLock) crtc->funcs->unlock (crtc); - return true; + return ret; } EXPORT_SYMBOL(drm_crtc_set_mode); -- cgit v1.2.3 From 8bfe29d9e44690a3896406acb25ca654dfad054d Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:52:37 +0000 Subject: Use ARRAY_SIZE --- linux-core/drm_crtc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 5f93275a..dfa0987f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -735,20 +735,20 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) "EDID", 0); dev->mode_config.dpms_property = - drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", 4); - + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name); dev->mode_config.connector_type_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, - "Connector Type", 10); + "Connector Type", ARRAY_SIZE(drm_conn_enum_list)); for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++) drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name); dev->mode_config.connector_num_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, - "Connector ID", 2); + "Connector ID", 2); dev->mode_config.connector_num_property->values[0] = 0; dev->mode_config.connector_num_property->values[1] = 20; @@ -783,7 +783,6 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) dev->mode_config.tv_bottom_margin_property->values[0] = 0; dev->mode_config.tv_bottom_margin_property->values[1] = 100; - return 0; } -- cgit v1.2.3 From 1a959a2095aef397ea14a6f6cbdf2a035ec0eb5c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:53:04 +0000 Subject: Check mode before adding to EDID --- linux-core/drm_edid.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 41aa8f5e..9762567b 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -223,8 +223,10 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) if (est_bits & (1<standard_timings[i]); - drm_mode_probed_add(output, newmode); - modes++; + if (newmode) { + drm_mode_probed_add(output, newmode); + modes++; + } } return modes; @@ -283,11 +287,13 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) if (timing->pixel_clock) { newmode = drm_mode_detailed(dev, timing); /* First detailed mode is preferred */ - if (i == 0 && edid->preferred_timing) - newmode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(output, newmode); + if (newmode) { + if (i == 0 && edid->preferred_timing) + newmode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(output, newmode); - modes++; + modes++; + } continue; } @@ -312,8 +318,10 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) std = &data->data.timings[j]; newmode = drm_mode_std(dev, std); - drm_mode_probed_add(output, newmode); - modes++; + if (newmode) { + drm_mode_probed_add(output, newmode); + modes++; + } } break; default: -- cgit v1.2.3 From fef1c93aa87a1ccbc473749a7e42557fc90a1fca Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 5 Mar 2008 10:33:57 +0000 Subject: build fix --- linux-core/drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index dfa0987f..be491908 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -420,14 +420,14 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int saved_x, saved_y; bool didLock = false; struct drm_output *output; + bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); crtc->enabled = drm_crtc_in_use(crtc); - if (!crtc->enabled) { + if (!crtc->enabled) return true; - } didLock = crtc->funcs->lock(crtc); -- cgit v1.2.3 From 92a30dd608c2838dea97efc04e1447056f37d0b5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Mar 2008 14:43:23 +1000 Subject: drm/bo: allow non-suser priv to add kernel BOs. modprobe can be run with dropped capabilities we still want the kernel bos to work. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3e8ffa0f..fd3cf9db 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -970,7 +970,7 @@ static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo, return -EINVAL; } - if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { + if (bo->type != drm_bo_type_kernel && (new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged processes.\n"); return -EPERM; } -- cgit v1.2.3 From 2540ea7dc6c0c4f0ebca3370d6ec7359e4276e13 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 09:29:35 +1000 Subject: flush_agp_mappings commit --- linux-core/drm_compat.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 136a7296..8f2d9a94 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -333,4 +333,9 @@ typedef _Bool bool; extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); #endif + +#if !defined(flush_agp_mappings) +#define flush_agp_mappings() do {} while(0) +#endif + #endif -- cgit v1.2.3 From 47b7ec71fefc2574293c48172c563f549c31f87a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 12:15:38 +1100 Subject: drm/modesetting: fixup irq removal on exit --- linux-core/drm_irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 7dddbe19..6b740b18 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -261,9 +261,6 @@ int drm_irq_uninstall(struct drm_device * dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return 0; - mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -318,6 +315,8 @@ int drm_control(struct drm_device *dev, void *data, case DRM_UNINST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; return drm_irq_uninstall(dev); default: return -EINVAL; -- cgit v1.2.3 From 348d95e00be73b650dabcf121e6b18d669bf4192 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 12:25:26 +1100 Subject: worst merge effort ever --- linux-core/drm_stub.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index ba13e5e5..6856075b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -355,10 +355,6 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if ((ret = dev->driver->load(dev, ent->driver_data))) goto err_g5; - if (dev->driver->load) - if ((ret = dev->driver->load(dev, ent->driver_data))) - goto err_g4; - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); -- cgit v1.2.3 From 33cb42a9f7c7c4f4dd91756af55de7352944efa4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 13:03:42 +1100 Subject: make startup of Xorg smoother if the mode doesn't change. just flip the framebuffer in when required. --- linux-core/drm_crtc.c | 10 ++++++++-- linux-core/intel_fb.c | 29 +++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index be491908..e0c85cef 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1110,13 +1110,17 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ if (crtc->fb != fb) - changed = true; + flip_or_move = true; if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) flip_or_move = true; - if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) + if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) { + DRM_DEBUG("modes are different\n"); + drm_mode_debug_printmodeline(dev, &crtc->mode); + drm_mode_debug_printmodeline(dev, new_mode); changed = true; + } list_for_each_entry(output, &dev->mode_config.output_list, head) { save_crtcs[count++] = output->crtc; @@ -1161,6 +1165,8 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } drm_disable_unused_functions(dev); } else if (flip_or_move) { + if (crtc->fb != fb) + crtc->fb = fb; crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y); } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index e33494c6..931bc1b6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -228,6 +228,7 @@ static int intelfb_set_par(struct fb_info *info) struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; + int changed = 0; DRM_DEBUG("\n"); @@ -310,11 +311,22 @@ static int intelfb_set_par(struct fb_info *info) } /* re-attach fb */ - if (!par->crtc->fb) + if (!par->crtc->fb) { par->crtc->fb = par->fb; + changed = 1; + } - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; + + drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(dev, &par->crtc->mode); + if (!drm_mode_equal(drm_mode, &par->crtc->mode)) + changed = 1; + + if (changed) + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; return 0; } @@ -469,16 +481,21 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; - + int changed = 0; DRM_DEBUG("\n"); /* TODO add check size and pos*/ + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; /* re-attach fb */ - if (!crtc->fb) + if (!crtc->fb) { crtc->fb = par->fb; + changed = 1; + } - drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); + if (changed) + drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; -- cgit v1.2.3 From 9f19e79f955281b9de393219e4ad9835ffe29c49 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 17:09:51 +1100 Subject: drm: we already worked out the pitch. multiplying by 4 is just madness.. --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 931bc1b6..52ff3a67 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -589,7 +589,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, + ret = drm_buffer_object_create(dev, fb->pitch * fb->height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | -- cgit v1.2.3