diff options
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/drmP.h | 106 | ||||
-rw-r--r-- | linux-core/drm_agpsupport.c | 451 | ||||
-rw-r--r-- | linux-core/drm_bufs.c | 3 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 68 | ||||
-rw-r--r-- | linux-core/drm_memory.h | 12 | ||||
-rw-r--r-- | linux-core/drm_memory_debug.h | 10 | ||||
-rw-r--r-- | linux-core/drm_scatter.c | 229 | ||||
-rw-r--r-- | linux-core/i810_drv.c | 2 | ||||
-rw-r--r-- | linux-core/i830_drv.c | 2 | ||||
-rw-r--r-- | linux-core/mga_drv.c | 2 | ||||
-rw-r--r-- | linux-core/r128_drv.c | 4 | ||||
-rw-r--r-- | linux-core/radeon_drv.c | 4 | ||||
-rw-r--r-- | linux-core/sis_drv.c | 2 |
13 files changed, 836 insertions, 59 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 3d352a6d..5626e4ff 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -66,6 +66,10 @@ #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#include <linux/types.h> +#include <linux/agp_backend.h> +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) #define HAS_WORKQUEUE 0 #else @@ -82,10 +86,14 @@ #include "drm_os_linux.h" + /***********************************************************************/ /** \name DRM template customization defaults */ /*@{*/ +#ifndef __HAVE_AGP +#define __HAVE_AGP 0 +#endif #ifndef __HAVE_MTRR #define __HAVE_MTRR 0 #endif @@ -105,18 +113,14 @@ #define __HAVE_DMA_FREELIST 0 #endif +#define __REALLY_HAVE_AGP (__HAVE_AGP && (defined(CONFIG_AGP) || \ + defined(CONFIG_AGP_MODULE))) #define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR)) #define __REALLY_HAVE_SG (__HAVE_SG) /*@}*/ -typedef struct drm_device drm_device_t; - -#include "drm_agp.h" -#include "drm_sg.h" - - /***********************************************************************/ /** \name Begin the DRM... */ /*@{*/ @@ -571,6 +575,48 @@ typedef struct drm_device_dma { /*@}*/ } drm_device_dma_t; +#if __REALLY_HAVE_AGP +/** + * AGP memory entry. Stored as a doubly linked list. + */ +typedef struct drm_agp_mem { + unsigned long handle; /**< handle */ + agp_memory *memory; + unsigned long bound; /**< address */ + int pages; + struct drm_agp_mem *prev; /**< previous entry */ + struct drm_agp_mem *next; /**< next entry */ +} drm_agp_mem_t; + +/** + * AGP data. + * + * \sa DRM(agp_init)() and drm_device::agp. + */ +typedef struct drm_agp_head { + agp_kern_info agp_info; /**< AGP device information */ + drm_agp_mem_t *memory; /**< memory entries */ + unsigned long mode; /**< AGP mode */ + int enabled; /**< whether the AGP bus as been enabled */ + int acquired; /**< whether the AGP device has been acquired */ + unsigned long base; + int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; +} drm_agp_head_t; +#endif + +/** + * Scatter-gather memory. + */ +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; + dma_addr_t *busaddr; +} drm_sg_mem_t; + typedef struct drm_sigdata { int context; drm_hw_lock_t *lock; @@ -600,7 +646,7 @@ typedef struct drm_vbl_sig { /** * DRM device structure. */ -struct drm_device { +typedef struct drm_device { const char *name; /**< Simple driver name */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ @@ -711,12 +757,11 @@ struct drm_device { #endif #endif drm_sg_mem_t *sg; /**< Scatter gather memory */ - unsigned long *ctx_bitmap; /**< context bitmap */ void *dev_private; /**< device private data */ drm_sigdata_t sigdata; /**< For block_all_signals */ sigset_t sigmask; -}; +} drm_device_t; /******************************************************************/ @@ -785,10 +830,10 @@ extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); #if __REALLY_HAVE_AGP -extern agp_memory *DRM(agp_alloc)(int pages, u32 type); -extern int DRM(agp_free)(agp_memory *handle, int pages); -extern int DRM(agp_bind)(agp_memory *handle, unsigned int start); -extern int DRM(agp_unbind)(agp_memory *handle); +extern agp_memory *DRM(alloc_agp)(int pages, u32 type); +extern int DRM(free_agp)(agp_memory *handle, int pages); +extern int DRM(bind_agp)(agp_memory *handle, unsigned int start); +extern int DRM(unbind_agp)(agp_memory *handle); #endif /* Misc. IOCTL support (drm_ioctl.h) */ @@ -911,6 +956,32 @@ extern void DRM(dma_immediate_bh)( void *dev ); #endif /* __HAVE_DMA */ +#if __REALLY_HAVE_AGP + /* AGP/GART support (drm_agpsupport.h) */ +extern drm_agp_head_t *DRM(agp_init)(void); +extern void DRM(agp_uninit)(void); +extern int DRM(agp_acquire)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void DRM(agp_do_release)(void); +extern int DRM(agp_release)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_enable)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_info)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_alloc)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_free)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_unbind)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(agp_bind)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type); +extern int DRM(agp_free_memory)(agp_memory *handle); +extern int DRM(agp_bind_memory)(agp_memory *handle, off_t start); +extern int DRM(agp_unbind_memory)(agp_memory *handle); +#endif /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, @@ -927,6 +998,15 @@ extern int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root); +#if __HAVE_SG + /* Scatter Gather Support (drm_scatter.h) */ +extern void DRM(sg_cleanup)(drm_sg_mem_t *entry); +extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(sg_free)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#endif + /* ATI PCIGART support (ati_pcigart.h) */ extern int DRM(ati_pcigart_init)(drm_device_t *dev, unsigned long *addr, diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c new file mode 100644 index 00000000..81850593 --- /dev/null +++ b/linux-core/drm_agpsupport.c @@ -0,0 +1,451 @@ +/** + * \file drm_agpsupport.h + * DRM support for AGP/GART backend + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include <linux/module.h> + +#if __REALLY_HAVE_AGP + + +#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") +#define DRM_AGP_PUT inter_module_put("drm_agp") + +/** + * Pointer to the drm_agp_t structure made available by the agpgart module. + */ +static const drm_agp_t *drm_agp = NULL; + +/** + * AGP information ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a (output) drm_agp_info structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been initialized and acquired and fills in the + * drm_agp_info structure with the information in drm_agp_head::agp_info. + */ +int DRM(agp_info)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + agp_kern_info *kern; + drm_agp_info_t info; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info) + return -EINVAL; + + kern = &dev->agp->agp_info; + info.agp_version_major = kern->version.major; + info.agp_version_minor = kern->version.minor; + info.mode = kern->mode; + info.aperture_base = kern->aper_base; + info.aperture_size = kern->aper_size * 1024 * 1024; + info.memory_allowed = kern->max_memory << PAGE_SHIFT; + info.memory_used = kern->current_memory << PAGE_SHIFT; + info.id_vendor = kern->device->vendor; + info.id_device = kern->device->device; + + if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +/** + * Acquire the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device hasn't been acquired before and calls + * drm_agp->acquire(). + */ +int DRM(agp_acquire)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode; + + if (!dev->agp || dev->agp->acquired || !drm_agp->acquire) + return -EINVAL; + if ((retcode = drm_agp->acquire())) return retcode; + dev->agp->acquired = 1; + return 0; +} + +/** + * Release the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired and calls drm_agp->release(). + */ +int DRM(agp_release)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->release) + return -EINVAL; + drm_agp->release(); + dev->agp->acquired = 0; + return 0; + +} + +/** + * Release the AGP device. + * + * Calls drm_agp->release(). + */ +void DRM(agp_do_release)(void) +{ + if (drm_agp->release) drm_agp->release(); +} + +/** + * Enable the AGP bus. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_mode structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired but not enabled, and calls + * drm_agp->enable(). + */ +int DRM(agp_enable)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_agp_mode_t mode; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->enable) + return -EINVAL; + + if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode))) + return -EFAULT; + + dev->agp->mode = mode.mode; + drm_agp->enable(mode.mode); + dev->agp->base = dev->agp->agp_info.aper_base; + dev->agp->enabled = 1; + return 0; +} + +/** + * Allocate AGP memory. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired, allocates the + * memory via alloc_agp() and creates a drm_agp_mem entry for it. + */ +int DRM(agp_alloc)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_agp_buffer_t request; + drm_agp_mem_t *entry; + agp_memory *memory; + unsigned long pages; + u32 type; + + if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS))) + return -ENOMEM; + + memset(entry, 0, sizeof(*entry)); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + type = (u32) request.type; + + if (!(memory = DRM(alloc_agp)(pages, type))) { + DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -ENOMEM; + } + + entry->handle = (unsigned long)memory->key; + entry->memory = memory; + entry->bound = 0; + entry->pages = pages; + entry->prev = NULL; + entry->next = dev->agp->memory; + if (dev->agp->memory) dev->agp->memory->prev = entry; + dev->agp->memory = entry; + + request.handle = entry->handle; + request.physical = memory->physical; + + if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) { + dev->agp->memory = entry->next; + dev->agp->memory->prev = NULL; + DRM(free_agp)(memory, pages); + DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -EFAULT; + } + return 0; +} + +/** + * Search for the AGP memory entry associated with a handle. + * + * \param dev DRM device structure. + * \param handle AGP memory handle. + * \return pointer to the drm_agp_mem structure associated with \p handle. + * + * Walks through drm_agp_head::memory until finding a matching handle. + */ +static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev, + unsigned long handle) +{ + drm_agp_mem_t *entry; + + for (entry = dev->agp->memory; entry; entry = entry->next) { + if (entry->handle == handle) return entry; + } + return NULL; +} + +/** + * Unbind AGP memory from the GATT (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and acquired, looks-up the AGP memory + * entry and passes it to the unbind_agp() function. + */ +int DRM(agp_unbind)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_agp_binding_t request; + drm_agp_mem_t *entry; + int ret; + + if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (!entry->bound) return -EINVAL; + ret = DRM(unbind_agp)(entry->memory); + if (ret == 0) + entry->bound = 0; + return ret; +} + +/** + * Bind AGP memory into the GATT (ioctl) + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and that no memory + * is currently bound into the GATT. Looks-up the AGP memory entry and passes + * it to bind_agp() function. + */ +int DRM(agp_bind)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_agp_binding_t request; + drm_agp_mem_t *entry; + int retcode; + int page; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->bind_memory) + return -EINVAL; + if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (entry->bound) return -EINVAL; + page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; + if ((retcode = DRM(bind_agp)(entry->memory, page))) return retcode; + entry->bound = dev->agp->base + (page << PAGE_SHIFT); + DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", + dev->agp->base, entry->bound); + return 0; +} + +/** + * Free AGP memory (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and looks up the + * AGP memory entry. If the memory it's currently bound, unbind it via + * unbind_agp(). Frees it via free_agp() as well as the entry itself + * and unlinks from the doubly linked list it's inserted in. + */ +int DRM(agp_free)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_agp_buffer_t request; + drm_agp_mem_t *entry; + + if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (entry->bound) DRM(unbind_agp)(entry->memory); + + if (entry->prev) entry->prev->next = entry->next; + else dev->agp->memory = entry->next; + if (entry->next) entry->next->prev = entry->prev; + DRM(free_agp)(entry->memory, entry->pages); + DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return 0; +} + +/** + * Initialize the AGP resources. + * + * \return pointer to a drm_agp_head structure. + * + * Gets the drm_agp_t structure which is made available by the agpgart module + * via the inter_module_* functions. Creates and initializes a drm_agp_head + * structure. + */ +drm_agp_head_t *DRM(agp_init)(void) +{ + drm_agp_head_t *head = NULL; + + drm_agp = DRM_AGP_GET; + if (drm_agp) { + if (!(head = DRM(alloc)(sizeof(*head), DRM_MEM_AGPLISTS))) + 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; +#if LINUX_VERSION_CODE <= 0x020408 + head->cant_use_aperture = 0; + head->page_mask = ~(0xfff); +#else + head->cant_use_aperture = head->agp_info.cant_use_aperture; + head->page_mask = head->agp_info.page_mask; +#endif + + DRM_INFO("AGP %d.%d aperture @ 0x%08lx %ZuMB\n", + head->agp_info.version.major, + head->agp_info.version.minor, + head->agp_info.aper_base, + head->agp_info.aper_size); + } + return head; +} + +/** + * Free the AGP resources. + * + * Releases the pointer in ::drm_agp. + */ +void DRM(agp_uninit)(void) +{ + DRM_AGP_PUT; + drm_agp = NULL; +} + +/** Calls drm_agp->allocate_memory() */ +agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type) +{ + if (!drm_agp->allocate_memory) return NULL; + return drm_agp->allocate_memory(pages, type); +} + +/** Calls drm_agp->free_memory() */ +int DRM(agp_free_memory)(agp_memory *handle) +{ + if (!handle || !drm_agp->free_memory) return 0; + drm_agp->free_memory(handle); + return 1; +} + +/** Calls drm_agp->bind_memory() */ +int DRM(agp_bind_memory)(agp_memory *handle, off_t start) +{ + if (!handle || !drm_agp->bind_memory) return -EINVAL; + return drm_agp->bind_memory(handle, start); +} + +/** Calls drm_agp->unbind_memory() */ +int DRM(agp_unbind_memory)(agp_memory *handle) +{ + if (!handle || !drm_agp->unbind_memory) return -EINVAL; + return drm_agp->unbind_memory(handle); +} + +#endif /* __REALLY_HAVE_AGP */ diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index f42fabef..77573709 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -174,8 +174,6 @@ int DRM(addmap)( struct inode *inode, struct file *filp, map->mtrr = dev->agp->agp_mtrr; /* for getmap */ break; #endif - -#if __HAVE_SG case _DRM_SCATTER_GATHER: if (!dev->sg) { DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -183,7 +181,6 @@ int DRM(addmap)( struct inode *inode, struct file *filp, } map->offset += dev->sg->handle; break; -#endif default: DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5a4ab36e..90c2d18b 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -225,19 +225,19 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { #endif #if __REALLY_HAVE_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info_ioctl), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind_ioctl), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, #endif #if __HAVE_SG - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc_ioctl), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free_ioctl), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, #endif #if __HAVE_VBL_IRQ @@ -416,6 +416,29 @@ static int DRM(takedown)( drm_device_t *dev ) dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } +#if __REALLY_HAVE_AGP + /* Clear AGP information */ + if ( dev->agp ) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until drv_cleanup is called. */ + for ( entry = dev->agp->memory ; entry ; entry = nexte ) { + nexte = entry->next; + if ( entry->bound ) DRM(unbind_agp)( entry->memory ); + DRM(free_agp)( entry->memory, entry->pages ); + DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); + } + dev->agp->memory = NULL; + + if ( dev->agp->acquired ) DRM(agp_do_release)(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } +#endif + /* Clear vma list (only built for debugging) */ if ( dev->vmalist ) { for ( vma = dev->vmalist ; vma ; vma = vma_next ) { @@ -463,7 +486,10 @@ static int DRM(takedown)( drm_device_t *dev ) * isn't defined. */ #if __HAVE_SG - DRM(sg_cleanup)(dev); + if(dev->sg) { + DRM(sg_cleanup)(dev->sg); + dev->sg = NULL; + } #endif break; } @@ -592,10 +618,6 @@ static int __init drm_init( void ) DRM(mem_init)(); -#if __REALLY_HAVE_AGP - DRM(agp_init)(); -#endif - for (i = 0; i < DRM(numdevs); i++) { dev = &(DRM(device)[i]); memset( (void *)dev, 0, sizeof(*dev) ); @@ -608,9 +630,8 @@ static int __init drm_init( void ) dev->name = DRIVER_NAME; #if __REALLY_HAVE_AGP - DRM(agp_init_dev)( dev ); + dev->agp = DRM(agp_init)(); #if __MUST_HAVE_AGP - if ( dev->agp == NULL ) { DRM_ERROR( "Cannot initialize the agpgart module.\n" ); DRM(stub_unregister)(DRM(minor)[i]); @@ -618,12 +639,14 @@ static int __init drm_init( void ) return -ENOMEM; } #endif +#if __REALLY_HAVE_MTRR if (dev->agp) dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, dev->agp->agp_info.aper_size*1024*1024, MTRR_TYPE_WRCOMB, 1 ); #endif +#endif #if __HAVE_CTX_BITMAP retcode = DRM(ctxbitmap_init)( dev ); @@ -689,14 +712,13 @@ static void __exit drm_cleanup( void ) DRM(takedown)( dev ); #if __REALLY_HAVE_AGP - DRM(agp_cleanup_dev)( dev ); + if ( dev->agp ) { + DRM(agp_uninit)(); + DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); + dev->agp = NULL; + } #endif } - -#if __REALLY_HAVE_AGP - DRM(agp_cleanup)(); -#endif - DRIVER_POSTCLEANUP(); kfree(DRM(minor)); kfree(DRM(device)); diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h index 9999c213..2a969fcd 100644 --- a/linux-core/drm_memory.h +++ b/linux-core/drm_memory.h @@ -332,29 +332,27 @@ void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) #if __REALLY_HAVE_AGP /** Wrapper around agp_allocate_memory() */ -agp_memory *DRM(agp_alloc)(int pages, u32 type) +agp_memory *DRM(alloc_agp)(int pages, u32 type) { return DRM(agp_allocate_memory)(pages, type); } /** Wrapper around agp_free_memory() */ -int DRM(agp_free)(agp_memory *handle, int pages) +int DRM(free_agp)(agp_memory *handle, int pages) { return DRM(agp_free_memory)(handle) ? 0 : -EINVAL; } /** Wrapper around agp_bind_memory() */ -int DRM(agp_bind)(agp_memory *handle, unsigned int start) +int DRM(bind_agp)(agp_memory *handle, unsigned int start) { return DRM(agp_bind_memory)(handle, start); } /** Wrapper around agp_unbind_memory() */ -int DRM(agp_unbind)(agp_memory *handle) +int DRM(unbind_agp)(agp_memory *handle) { return DRM(agp_unbind_memory)(handle); } -#endif /* __REALLY_HAVE_AGP */ - - +#endif /* agp */ #endif /* debug_memory */ diff --git a/linux-core/drm_memory_debug.h b/linux-core/drm_memory_debug.h index 91b42126..5cfff83a 100644 --- a/linux-core/drm_memory_debug.h +++ b/linux-core/drm_memory_debug.h @@ -1,5 +1,5 @@ /** - * \file drm_memory_debug.h + * \file drm_memory.h * Memory management wrappers for DRM. * * \author Rickard E. (Rik) Faith <faith@valinux.com> @@ -343,7 +343,7 @@ void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) #if __REALLY_HAVE_AGP -agp_memory *DRM(agp_alloc)(int pages, u32 type) +agp_memory *DRM(alloc_agp)(int pages, u32 type) { agp_memory *handle; @@ -366,7 +366,7 @@ agp_memory *DRM(agp_alloc)(int pages, u32 type) return NULL; } -int DRM(agp_free)(agp_memory *handle, int pages) +int DRM(free_agp)(agp_memory *handle, int pages) { int alloc_count; int free_count; @@ -395,7 +395,7 @@ int DRM(agp_free)(agp_memory *handle, int pages) return retval; } -int DRM(agp_bind)(agp_memory *handle, unsigned int start) +int DRM(bind_agp)(agp_memory *handle, unsigned int start) { int retcode = -EINVAL; @@ -419,7 +419,7 @@ int DRM(agp_bind)(agp_memory *handle, unsigned int start) return retcode; } -int DRM(agp_unbind)(agp_memory *handle) +int DRM(unbind_agp)(agp_memory *handle) { int alloc_count; int free_count; diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c new file mode 100644 index 00000000..45a30fc3 --- /dev/null +++ b/linux-core/drm_scatter.c @@ -0,0 +1,229 @@ +/** + * \file drm_scatter.h + * IOCTLs to manage scatter/gather memory + * + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include <linux/vmalloc.h> +#include "drmP.h" + +#define DEBUG_SCATTER 0 + +void DRM(sg_cleanup)( drm_sg_mem_t *entry ) +{ + struct page *page; + int i; + + for ( i = 0 ; i < entry->pages ; i++ ) { + page = entry->pagelist[i]; + if ( page ) + ClearPageReserved( page ); + } + + vfree( entry->virtual ); + + DRM(free)( entry->busaddr, + entry->pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); +} + +int DRM(sg_alloc)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + unsigned long pages, i, j; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( dev->sg ) + return -EINVAL; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = DRM(alloc)( sizeof(*entry), DRM_MEM_SGLISTS ); + if ( !entry ) + return -ENOMEM; + + memset( entry, 0, sizeof(*entry) ); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); + + entry->pages = pages; + entry->pagelist = DRM(alloc)( pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + if ( !entry->pagelist ) { + DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); + + entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); + if ( !entry->busaddr ) { + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); + return -ENOMEM; + } + memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) ); + + entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); + if ( !entry->virtual ) { + DRM(free)( entry->busaddr, + entry->pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + /* This also forces the mapping of COW pages, so our page list + * will be valid. Please don't remove it... + */ + memset( entry->virtual, 0, pages << PAGE_SHIFT ); + + entry->handle = (unsigned long)entry->virtual; + + DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle ); + DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); + + for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { + entry->pagelist[j] = vmalloc_to_page((void *)i); + if (!entry->pagelist[j]) + goto failed; + SetPageReserved(entry->pagelist[j]); + } + + request.handle = entry->handle; + + if ( copy_to_user( (drm_scatter_gather_t *)arg, + &request, + sizeof(request) ) ) { + DRM(sg_cleanup)( entry ); + return -EFAULT; + } + + dev->sg = entry; + +#if DEBUG_SCATTER + /* Verify that each page points to its virtual address, and vice + * versa. + */ + { + int error = 0; + + for ( i = 0 ; i < pages ; i++ ) { + unsigned long *tmp; + + tmp = page_address( entry->pagelist[i] ); + for ( j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++ ) { + *tmp = 0xcafebabe; + } + tmp = (unsigned long *)((u8 *)entry->virtual + + (PAGE_SIZE * i)); + for( j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++ ) { + if ( *tmp != 0xcafebabe && error == 0 ) { + error = 1; + DRM_ERROR( "Scatter allocation error, " + "pagelist does not match " + "virtual mapping\n" ); + } + } + tmp = page_address( entry->pagelist[i] ); + for(j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++) { + *tmp = 0; + } + } + if (error == 0) + DRM_ERROR( "Scatter allocation matches pagelist\n" ); + } +#endif + + return 0; + + failed: + DRM(sg_cleanup)( entry ); + return -ENOMEM; +} + +int DRM(sg_free)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = dev->sg; + dev->sg = NULL; + + if ( !entry || entry->handle != request.handle ) + return -EINVAL; + + DRM_DEBUG( "sg free virtual = %p\n", entry->virtual ); + + DRM(sg_cleanup)( entry ); + + return 0; +} diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index 2b816fbf..0bc79386 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -37,7 +37,7 @@ #include "i810_drm.h" #include "i810_drv.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" diff --git a/linux-core/i830_drv.c b/linux-core/i830_drv.c index 496c41ee..0735c94d 100644 --- a/linux-core/i830_drv.c +++ b/linux-core/i830_drv.c @@ -39,7 +39,7 @@ #include "i830_drm.h" #include "i830_drv.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index f438660c..f0d4935d 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -35,7 +35,7 @@ #include "drm.h" #include "mga_drm.h" #include "mga_drv.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index 474c1418..e2e42690 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -37,7 +37,7 @@ #include "r128_drv.h" #include "ati_pcigart.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" @@ -52,4 +52,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" -#include "drm_sg_tmp.h" +#include "drm_scatter.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 1473e2ee..6152b8a5 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -38,7 +38,7 @@ #include "radeon_drv.h" #include "ati_pcigart.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" @@ -53,4 +53,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" -#include "drm_sg_tmp.h" +#include "drm_scatter.h" diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index 64d0754f..3dd075d3 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -32,7 +32,7 @@ #include "sis_drv.h" #include "drm_auth.h" -#include "drm_agp_tmp.h" +#include "drm_agpsupport.h" #include "drm_bufs.h" #include "drm_context.h" #include "drm_dma.h" |