From 9199075a6a975ebcc44aff53fe0f77080c01a30b Mon Sep 17 00:00:00 2001 From: Jeff Hartmann Date: Mon, 7 Aug 2000 16:55:10 +0000 Subject: Fix for multiple sarea bug + agp built into kernel segfault --- linux-core/drmP.h | 6 ++++++ linux/agpsupport.c | 47 ++++++++++++++++++++++++++++++++--------------- linux/drmP.h | 6 ++++++ linux/vm.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 16 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 3e5149c9..516e9b22 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -558,6 +558,9 @@ extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -569,6 +572,9 @@ extern struct page *drm_vm_nopage(struct vm_area_struct *vma, extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); diff --git a/linux/agpsupport.c b/linux/agpsupport.c index 48a6aa5f..7ed234e1 100644 --- a/linux/agpsupport.c +++ b/linux/agpsupport.c @@ -287,23 +287,40 @@ drm_agp_head_t *drm_agp_init(void) return NULL; memset((void *)head, 0, sizeof(*head)); (*drm_agp.copy_info)(&head->agp_info); + if (head->agp_info.chipset == NOT_SUPPORTED) { + drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + return NULL; + } head->memory = NULL; switch (head->agp_info.chipset) { - case INTEL_GENERIC: head->chipset = "Intel"; break; - case INTEL_LX: head->chipset = "Intel 440LX"; break; - case INTEL_BX: head->chipset = "Intel 440BX"; break; - case INTEL_GX: head->chipset = "Intel 440GX"; break; - case INTEL_I810: head->chipset = "Intel i810"; break; - case VIA_GENERIC: head->chipset = "VIA"; break; - case VIA_VP3: head->chipset = "VIA VP3"; break; - case VIA_MVP3: head->chipset = "VIA MVP3"; break; - case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break; - case SIS_GENERIC: head->chipset = "SiS"; break; - case AMD_GENERIC: head->chipset = "AMD"; break; - case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; - case ALI_GENERIC: head->chipset = "ALi"; break; - case ALI_M1541: head->chipset = "ALi M1541"; break; - default: + case INTEL_GENERIC: head->chipset = "Intel"; break; + case INTEL_LX: head->chipset = "Intel 440LX"; break; + case INTEL_BX: head->chipset = "Intel 440BX"; break; + case INTEL_GX: head->chipset = "Intel 440GX"; break; + case INTEL_I810: head->chipset = "Intel i810"; break; + +#if LINUX_VERSION_CODE >= 0x020400 + case INTEL_I840: head->chipset = "Intel i840"; break; +#endif + + case VIA_GENERIC: head->chipset = "VIA"; break; + case VIA_VP3: head->chipset = "VIA VP3"; break; + case VIA_MVP3: head->chipset = "VIA MVP3"; break; + +#if LINUX_VERSION_CODE >= 0x020400 + case VIA_MVP4: head->chipset = "VIA MVP4"; break; + case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; + break; +#endif + + case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; + break; + case SIS_GENERIC: head->chipset = "SiS"; break; + case AMD_GENERIC: head->chipset = "AMD"; break; + case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; + case ALI_GENERIC: head->chipset = "ALi"; break; + case ALI_M1541: head->chipset = "ALi M1541"; break; + default: head->chipset = "Unknown"; break; } DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n", head->agp_info.version.major, diff --git a/linux/drmP.h b/linux/drmP.h index 3e5149c9..516e9b22 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -558,6 +558,9 @@ extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -569,6 +572,9 @@ extern struct page *drm_vm_nopage(struct vm_area_struct *vma, extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); diff --git a/linux/vm.c b/linux/vm.c index 5ee9e324..b1f0d49a 100644 --- a/linux/vm.c +++ b/linux/vm.c @@ -44,6 +44,12 @@ struct vm_operations_struct drm_vm_shm_ops = { close: drm_vm_close, }; +struct vm_operations_struct drm_vm_shm_lock_ops = { + nopage: drm_vm_shm_nopage_lock, + open: drm_vm_open, + close: drm_vm_close, +}; + struct vm_operations_struct drm_vm_dma_ops = { nopage: drm_vm_dma_nopage, open: drm_vm_open, @@ -76,6 +82,40 @@ struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) #endif +{ +#if LINUX_VERSION_CODE >= 0x020300 + drm_map_t *map = (drm_map_t *)vma->vm_private_data; +#else + drm_map_t *map = (drm_map_t *)vma->vm_pte; +#endif + unsigned long physical; + unsigned long offset; + + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!map) return NOPAGE_OOM; /* Nothing allocated */ + + offset = address - vma->vm_start; + physical = (unsigned long)map->handle + offset; + atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */ + + DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical); +#if LINUX_VERSION_CODE < 0x020317 + return physical; +#else + return mem_map + MAP_NR(physical); +#endif +} + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; @@ -298,7 +338,17 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: - vma->vm_ops = &drm_vm_shm_ops; + if (map->flags & _DRM_CONTAINS_LOCK) + vma->vm_ops = &drm_vm_shm_lock_ops; + else { + vma->vm_ops = &drm_vm_shm_ops; +#if LINUX_VERSION_CODE >= 0x020300 + vma->vm_private_data = (void *)map; +#else + vma->vm_pte = (unsigned long)map; +#endif + } + /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ vma->vm_flags |= VM_LOCKED; -- cgit v1.2.3