diff options
author | Ian Romanick <idr@us.ibm.com> | 2005-06-14 22:34:11 +0000 |
---|---|---|
committer | Ian Romanick <idr@us.ibm.com> | 2005-06-14 22:34:11 +0000 |
commit | 72cfc797b51e59ecf8a2787c6a176838241cc94b (patch) | |
tree | 87ade354c97e962a29b3d1fc8b620972754092eb | |
parent | 3585bdf7d81a92c729bb5bcbc7cfca6048d640ce (diff) |
Adds support for PCI cards to MGA DRM
This patch adds serveral new ioctls and a new query to get_param query to
support PCI MGA cards.
Two ioctls were added to implement interrupt based waiting. With this
change, the client-side driver no longer needs to map the primary DMA
region or the MMIO region. Previously, end-of-frame waiting was done by
busy waiting in the client-side driver until one of the MMIO registers
(the current DMA pointer) matched a pointer to the end of primary DMA
space. By using interrupts, the busy waiting and the extra mappings are
removed.
A third ioctl was added to bootstrap DMA. This ioctl, which is used by the
X-server, moves a *LOT* of code from the X-server into the kernel. This
allows the kernel to do whatever needs to be done to setup DMA buffers.
The entire process and the locations of the buffers are hidden from
user-mode.
Additionally, a get_param query was added to differentiate between G4x0
cards and G550 cards. A gap was left in the numbering sequence so that,
if needed, G450 cards could be distinguished from G400 cards. According
to Ville Syrjälä, the G4x0 cards and the G550 cards handle
anisotropic filtering differently. This seems the most compatible way
to let the client-side driver know which card it's own. Doing this very
small change now eliminates the need to bump the DRM minor version
twice.
http://marc.theaimsgroup.com/?l=dri-devel&m=106625815319773&w=2
A number of ioctl handlers in linux-core were also modified so that they
could be called in-kernel. In these cases, the in-kernel callable
version kept the existing name (e.g., drm_agp_acquire) and the ioctl
handler added _ioctl to the name (e.g., drm_agp_acquire_ioctl).
This patch also replaces the drm_agp_do_release function with
drm_agp_release. drm_agp_release (drm_core_agp_release in the previous
patch) is very similar to drm_agp_do_release, and I saw no reason to
have both.
This commit *breaks the build* on BSD. Eric said that he would make the
required updates to the BSD side soon.
Xorg bug: 3259 Reviewed by: Eric Anholt
-rw-r--r-- | bsd-core/drmP.h | 4 | ||||
-rw-r--r-- | bsd-core/drm_agpsupport.c | 17 | ||||
-rw-r--r-- | bsd-core/drm_drv.c | 4 | ||||
-rw-r--r-- | linux-core/drmP.h | 28 | ||||
-rw-r--r-- | linux-core/drm_agpsupport.c | 132 | ||||
-rw-r--r-- | linux-core/drm_bufs.c | 89 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 18 | ||||
-rw-r--r-- | linux-core/drm_memory.c | 4 | ||||
-rw-r--r-- | linux-core/mga_drv.c | 13 | ||||
-rw-r--r-- | shared-core/drm_pciids.txt | 3 | ||||
-rw-r--r-- | shared-core/mga_dma.c | 550 | ||||
-rw-r--r-- | shared-core/mga_drm.h | 89 | ||||
-rw-r--r-- | shared-core/mga_drv.h | 64 | ||||
-rw-r--r-- | shared-core/mga_irq.c | 50 | ||||
-rw-r--r-- | shared-core/mga_state.c | 80 | ||||
-rw-r--r-- | shared-core/mga_warp.c | 3 | ||||
-rw-r--r-- | shared/mga_drm.h | 88 |
17 files changed, 1063 insertions, 173 deletions
diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 98e4945c..b22ce3b2 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -848,7 +848,7 @@ void drm_vbl_send_signals(drm_device_t *dev); int drm_device_is_agp(drm_device_t *dev); drm_agp_head_t *drm_agp_init(void); void drm_agp_uninit(void); -void drm_agp_do_release(void); +int drm_agp_release(drm_device_t *dev); void *drm_agp_allocate_memory(size_t pages, u32 type); int drm_agp_free_memory(void *handle); int drm_agp_bind_memory(void *handle, off_t start); @@ -921,7 +921,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS); /* AGP/GART support (drm_agpsupport.c) */ int drm_agp_acquire(DRM_IOCTL_ARGS); -int drm_agp_release(DRM_IOCTL_ARGS); +int drm_agp_release_ioctl(DRM_IOCTL_ARGS); int drm_agp_enable(DRM_IOCTL_ARGS); int drm_agp_info(DRM_IOCTL_ARGS); int drm_agp_alloc(DRM_IOCTL_ARGS); diff --git a/bsd-core/drm_agpsupport.c b/bsd-core/drm_agpsupport.c index 540cb402..7c5351ae 100644 --- a/bsd-core/drm_agpsupport.c +++ b/bsd-core/drm_agpsupport.c @@ -129,25 +129,20 @@ int drm_agp_acquire(DRM_IOCTL_ARGS) return 0; } -int drm_agp_release(DRM_IOCTL_ARGS) +int drm_agp_release_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; + return drm_agp_release(dev); +} + +void drm_agp_release(drm_device_t * dev) +{ if (!dev->agp || !dev->agp->acquired) return EINVAL; agp_release(dev->agp->agpdev); dev->agp->acquired = 0; return 0; - -} - -void drm_agp_do_release(void) -{ - device_t agpdev; - - agpdev = DRM_AGP_FIND_DEVICE(); - if (agpdev) - agp_release(agpdev); } int drm_agp_enable(DRM_IOCTL_ARGS) diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 44a6c85a..e3cac422 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -102,7 +102,7 @@ static drm_ioctl_desc_t drm_ioctls[256] = { [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { drm_control, 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_RELEASE)] = { drm_agp_release_ioctl, 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 }, @@ -424,7 +424,7 @@ static int drm_takedown(drm_device_t *dev) dev->agp->memory = NULL; if (dev->agp->acquired) - drm_agp_do_release(); + drm_agp_release(); dev->agp->acquired = 0; dev->agp->enabled = 0; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 40579bfa..7d5902ef 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -862,10 +862,17 @@ extern int drm_lock_free(drm_device_t * dev, __volatile__ unsigned int *lock, unsigned int context); /* Buffer management support (drm_bufs.h) */ -extern int drm_addmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_rmmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); +extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request); +extern int drm_addbufs_fb (drm_device_t * dev, drm_buf_desc_t * request); +extern int drm_addmap(drm_device_t * dev, unsigned int offset, + unsigned int size, drm_map_type_t type, + drm_map_flags_t flags, drm_map_t ** map_ptr); +extern int drm_addmap_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_rmmap(drm_device_t *dev, void *handle); +extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int drm_initmap(drm_device_t * dev, unsigned int offset, unsigned int size, unsigned int resource, int type, int flags); @@ -913,14 +920,17 @@ extern void drm_vbl_send_signals(drm_device_t * dev); /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *drm_agp_init(drm_device_t *dev); -extern int drm_agp_acquire(struct inode *inode, struct file *filp, +extern int drm_agp_acquire(drm_device_t * dev); +extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void drm_agp_do_release(drm_device_t *dev); -extern int drm_agp_release(struct inode *inode, struct file *filp, +extern int drm_agp_release(drm_device_t *dev); +extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_enable(struct inode *inode, struct file *filp, +extern int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode); +extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_info(struct inode *inode, struct file *filp, +extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info); +extern int drm_agp_info_ioctl(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); diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index fcbe56a3..686efcc9 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -37,7 +37,7 @@ #if __OS_HAS_AGP /** - * AGP information ioctl. + * Get AGP information. * * \param inode device inode. * \param filp file pointer. @@ -48,50 +48,56 @@ * 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) +int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; DRM_AGP_KERN *kern; - drm_agp_info_t info; if (!dev->agp || !dev->agp->acquired) 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; + 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; + + return 0; +} +EXPORT_SYMBOL(drm_agp_info); + +int drm_agp_info_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_info_t info; + int err; + err = drm_agp_info(dev, &info); + if (err) + return err; + if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info))) return -EFAULT; return 0; } /** - * Acquire the AGP device (ioctl). + * Acquire the AGP device * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg user argument. + * \param dev DRM device that is to acquire AGP. * \return zero on success or a negative number on failure. * * Verifies the AGP device hasn't been acquired before and calls - * agp_backend_acquire(). + * \c agp_backend_acquire. */ -int drm_agp_acquire(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_acquire(drm_device_t * dev) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) int retcode; #endif @@ -115,9 +121,10 @@ int drm_agp_acquire(struct inode *inode, struct file *filp, dev->agp->acquired = 1; return 0; } +EXPORT_SYMBOL(drm_agp_acquire); /** - * Release the AGP device (ioctl). + * Acquire the AGP device (ioctl). * * \param inode device inode. * \param filp file pointer. @@ -125,14 +132,27 @@ int drm_agp_acquire(struct inode *inode, struct file *filp, * \param arg user argument. * \return zero on success or a negative number on failure. * - * Verifies the AGP device has been acquired and calls agp_backend_release(). + * Verifies the AGP device hasn't been acquired before and calls + * \c agp_backend_acquire. */ -int drm_agp_release(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; + + return drm_agp_acquire( (drm_device_t *) priv->head->dev ); +} +/** + * Release the AGP device + * + * \param dev DRM device that is to release AGP. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired and calls \c agp_backend_release. + */ +int drm_agp_release(drm_device_t *dev) +{ if (!dev->agp || !dev->agp->acquired) return -EINVAL; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) @@ -144,46 +164,32 @@ int drm_agp_release(struct inode *inode, struct file *filp, return 0; } +EXPORT_SYMBOL(drm_agp_release); -/** - * Release the AGP device. - * - * Calls agp_backend_release(). - */ -void drm_agp_do_release(drm_device_t *dev) +int drm_agp_release_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) - agp_backend_release(); -#else - agp_backend_release(dev->agp->bridge); -#endif + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + + return drm_agp_release(dev); } /** * Enable the AGP bus. * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg pointer to a drm_agp_mode structure. + * \param dev DRM device that has previously acquired AGP. + * \param mode Requested AGP mode. * \return zero on success or a negative number on failure. * * Verifies the AGP device has been acquired but not enabled, and calls - * agp_enable(). + * \c agp_enable. */ -int drm_agp_enable(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_agp_mode_t mode; - if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode))) - return -EFAULT; - dev->agp->mode = mode.mode; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) agp_enable(mode.mode); @@ -194,6 +200,21 @@ int drm_agp_enable(struct inode *inode, struct file *filp, dev->agp->enabled = 1; return 0; } +EXPORT_SYMBOL(drm_agp_enable); + +int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_mode_t mode; + + + if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode))) + return -EFAULT; + + return drm_agp_enable(dev, mode); +} /** * Allocate AGP memory. @@ -479,6 +500,7 @@ int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start) return -EINVAL; return agp_bind_memory(handle, start); } +EXPORT_SYMBOL(drm_agp_bind_memory); /** Calls agp_unbind_memory() */ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 50182160..b54aaeb8 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -122,27 +122,23 @@ EXPORT_SYMBOL(drm_initmap); * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where * applicable and if supported by the kernel. */ -int drm_addmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_addmap(drm_device_t * dev, unsigned int offset, + unsigned int size, drm_map_type_t type, + drm_map_flags_t flags, drm_map_t ** map_ptr) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; drm_map_t *map; - drm_map_t __user *argp = (void __user *)arg; drm_map_list_t *list; drm_dma_handle_t *dmah; - if (!(filp->f_mode & 3)) - return -EACCES; /* Require read/write */ map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); if (!map) return -ENOMEM; - if (copy_from_user(map, argp, sizeof(*map))) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - return -EFAULT; - } + map->offset = offset; + map->size = size; + map->flags = flags; + map->type = type; /* Only allow shared memory to be removable since we only keep enough * book keeping information about shared memory to allow for removal @@ -289,11 +285,40 @@ int drm_addmap(struct inode *inode, struct file *filp, list_add(&list->head, &dev->maplist->head); up(&dev->struct_sem); found_it: - if (copy_to_user(argp, map, sizeof(*map))) + *map_ptr = map; + return 0; +} +EXPORT_SYMBOL(drm_addmap); + +int drm_addmap_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_map_t map; + drm_map_t *map_ptr; + drm_map_t __user *argp = (void __user *)arg; + int err; + + if (!(filp->f_mode & 3)) + return -EACCES; /* Require read/write */ + + if (copy_from_user(& map, argp, sizeof(map))) { return -EFAULT; - if (map->type != _DRM_SHM) { + } + + err = drm_addmap( dev, map.offset, map.size, map.type, map.flags, + & map_ptr ); + + if (err) { + return err; + } + + if (copy_to_user(argp, map_ptr, sizeof(*map_ptr))) + return -EFAULT; + if (map_ptr->type != _DRM_SHM) { if (copy_to_user(&argp->handle, - &map->offset, sizeof(map->offset))) + &map_ptr->offset, sizeof(map_ptr->offset))) return -EFAULT; } return 0; @@ -313,23 +338,16 @@ int drm_addmap(struct inode *inode, struct file *filp, * its being used, and free any associate resource (such as MTRR's) if it's not * being on use. * - * \sa addmap(). + * \sa drm_addmap */ -int drm_rmmap(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_rmmap(drm_device_t *dev, void *handle) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; struct list_head *list; drm_map_list_t *r_list = NULL; drm_vma_entry_t *pt, *prev; drm_map_t *map; - drm_map_t request; int found_maps = 0; - if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) { - return -EFAULT; - } down(&dev->struct_sem); list = &dev->maplist->head; @@ -337,7 +355,7 @@ int drm_rmmap(struct inode *inode, struct file *filp, r_list = list_entry(list, drm_map_list_t, head); if (r_list->map && - r_list->map->handle == request.handle && + r_list->map->handle == handle && r_list->map->flags & _DRM_REMOVABLE) break; } @@ -389,6 +407,22 @@ int drm_rmmap(struct inode *inode, struct file *filp, up(&dev->struct_sem); return 0; } +EXPORT_SYMBOL(drm_rmmap); + +int drm_rmmap_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_map_t request; + + + if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) { + return -EFAULT; + } + + return drm_rmmap(dev, request.handle); +} /** * Cleanup after an error on one of the addbufs() functions. @@ -444,7 +478,7 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry) * reallocates the buffer list of the same size order to accommodate the new * buffers. */ -static int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) +int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; @@ -596,9 +630,10 @@ static int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } +EXPORT_SYMBOL(drm_addbufs_agp); #endif /* __OS_HAS_AGP */ -static int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) +int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; int count; @@ -814,6 +849,7 @@ static int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) return 0; } +EXPORT_SYMBOL(drm_addbufs_pci); static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) { @@ -1127,6 +1163,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } +EXPORT_SYMBOL(drm_addbufs_fb); /** diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5a39e34e..39c893ce 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -72,8 +72,8 @@ drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, 1, 1}, [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap, 1, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, 1, 0}, [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, 1, 1}, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, 1, 0}, @@ -105,10 +105,10 @@ drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, 1, 1}, #if __OS_HAS_AGP - [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_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, 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}, @@ -130,7 +130,7 @@ drm_ioctl_desc_t drm_ioctls[] = { * * Frees every resource in \p dev. * - * \sa drm_device and setup(). + * \sa drm_device */ int drm_takedown(drm_device_t * dev) { @@ -190,7 +190,7 @@ int drm_takedown(drm_device_t * dev) dev->agp->memory = NULL; if (dev->agp->acquired) - drm_agp_do_release(dev); + drm_agp_release(dev); dev->agp->acquired = 0; dev->agp->enabled = 0; @@ -365,7 +365,7 @@ EXPORT_SYMBOL(drm_init); * * Cleans up all DRM device, calling takedown(). * - * \sa drm_init(). + * \sa drm_init */ static void __exit drm_cleanup(drm_device_t * dev) { diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 55523c62..2cc3dc67 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -162,23 +162,27 @@ DRM_AGP_MEM *drm_alloc_agp(struct agp_bridge_data *bridge, int pages, u32 type) return drm_agp_allocate_memory(bridge, pages, type); } #endif +EXPORT_SYMBOL(drm_alloc_agp); /** Wrapper around agp_free_memory() */ int drm_free_agp(DRM_AGP_MEM * handle, int pages) { return drm_agp_free_memory(handle) ? 0 : -EINVAL; } +EXPORT_SYMBOL(drm_free_agp); /** Wrapper around agp_bind_memory() */ int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) { return drm_agp_bind_memory(handle, start); } +EXPORT_SYMBOL(drm_bind_agp); /** Wrapper around agp_unbind_memory() */ int drm_unbind_agp(DRM_AGP_MEM * handle) { return drm_agp_unbind_memory(handle); } +EXPORT_SYMBOL(drm_unbind_agp); #endif /* agp */ #endif /* debug_memory */ diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 43877597..ed55c1f3 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -40,6 +40,12 @@ static int mga_driver_device_is_agp(drm_device_t * dev); static int postinit(struct drm_device *dev, unsigned long flags) { + drm_mga_private_t * const dev_priv = + (drm_mga_private_t *) dev->dev_private; + + dev_priv->mmio_base = pci_resource_start(dev->pdev, 1); + dev_priv->mmio_size = pci_resource_len(dev->pdev, 1); + dev->counters += 3; dev->types[6] = _DRM_STAT_IRQ; dev->types[7] = _DRM_STAT_PRIMARY; @@ -78,7 +84,7 @@ extern int mga_max_ioctl; static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = - DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .preinit = mga_driver_preinit, @@ -168,11 +174,6 @@ int mga_driver_device_is_agp(drm_device_t * dev) if ( (pdev->device == 0x0525) && (pdev->bus->self->vendor == 0x3388) && (pdev->bus->self->device == 0x0021) ) { -#if defined( __powerpc__ ) - DRM_ERROR("GXT135p is not yet supported\n"); -#else - DRM_ERROR("PCI G450 is not yet supported\n"); -#endif return 0; } diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 82cbdd46..aa975eed 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -110,9 +110,10 @@ 0x1002 0x5452 0 "ATI Rage 128 Pro Ultra TR (AGP)" [mga] +0x102b 0x0520 MGA_CARD_TYPE_G200 "Matrox G200 (PCI)" 0x102b 0x0521 MGA_CARD_TYPE_G200 "Matrox G200 (AGP)" 0x102b 0x0525 MGA_CARD_TYPE_G400 "Matrox G400/G450 (AGP)" -0x102b 0x2527 MGA_CARD_TYPE_G400 "Matrox G550 (AGP)" +0x102b 0x2527 MGA_CARD_TYPE_G550 "Matrox G550 (AGP)" [mach64] 0x1002 0x4749 0 "3D Rage Pro" diff --git a/shared-core/mga_dma.c b/shared-core/mga_dma.c index 4c0be4cc..998886d6 100644 --- a/shared-core/mga_dma.c +++ b/shared-core/mga_dma.c @@ -23,18 +23,21 @@ * 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. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Jeff Hartmann <jhartmann@valinux.com> - * Keith Whitwell <keith@tungstengraphics.com> - * - * Rewritten by: - * Gareth Hughes <gareth@valinux.com> + */ + +/** + * \file mga_dma.c + * DMA support for MGA G200 / G400. + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Jeff Hartmann <jhartmann@valinux.com> + * \author Keith Whitwell <keith@tungstengraphics.com> + * \author Gareth Hughes <gareth@valinux.com> */ #include "drmP.h" #include "drm.h" +#include "drm_sarea.h" #include "mga_drm.h" #include "mga_drv.h" @@ -148,7 +151,7 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv) DRM_DEBUG(" space = 0x%06x\n", primary->space); mga_flush_write_combine(); - MGA_WRITE(MGA_PRIMEND, tail | MGA_PAGPXFER); + MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access); DRM_DEBUG("done.\n"); } @@ -188,7 +191,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv) DRM_DEBUG(" space = 0x%06x\n", primary->space); mga_flush_write_combine(); - MGA_WRITE(MGA_PRIMEND, tail | MGA_PAGPXFER); + MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access); set_bit(0, &primary->wrapped); DRM_DEBUG("done.\n"); @@ -405,6 +408,405 @@ int mga_driver_preinit(drm_device_t *dev, unsigned long flags) return 0; } +/** + * Bootstrap the driver for AGP DMA. + * + * \todo + * Investigate whether there is any benifit to storing the WARP microcode in + * AGP memory. If not, the microcode may as well always be put in PCI + * memory. + * + * \todo + * This routine needs to set dma_bs->agp_mode to the mode actually configured + * in the hardware. Looking just at the Linux AGP driver code, I don't see + * an easy way to determine this. + * + * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap + */ +static int mga_do_agp_dma_bootstrap(drm_device_t * dev, + drm_mga_dma_bootstrap_t * dma_bs) +{ + drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; + const unsigned int warp_size = mga_warp_microcode_size(dev_priv); + int err; + unsigned offset; + const unsigned secondary_size = dma_bs->secondary_bin_count + * dma_bs->secondary_bin_size; + const unsigned agp_size = (dma_bs->agp_size << 20); + drm_buf_desc_t req; + drm_agp_mode_t mode; + drm_agp_info_t info; + + + /* Acquire AGP. */ + err = drm_agp_acquire(dev); + if (err) { + DRM_ERROR("Unable to acquire AGP\n"); + return err; + } + + err = drm_agp_info(dev, &info); + if (err) { + DRM_ERROR("Unable to get AGP info\n"); + return err; + } + + mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode; + err = drm_agp_enable(dev, mode); + if (err) { + DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); + return err; + } + + + /* In addition to the usual AGP mode configuration, the G200 AGP cards + * need to have the AGP mode "manually" set. + */ + + if (dev_priv->chipset == MGA_CARD_TYPE_G200) { + if (mode.mode & 0x02) { + MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE); + } + else { + MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE); + } + } + + + /* Allocate and bind AGP memory. */ + dev_priv->agp_pages = agp_size / PAGE_SIZE; + dev_priv->agp_mem = drm_alloc_agp( dev_priv->agp_pages, 0 ); + if (dev_priv->agp_mem == NULL) { + dev_priv->agp_pages = 0; + DRM_ERROR("Unable to allocate %uMB AGP memory\n", + dma_bs->agp_size); + return DRM_ERR(ENOMEM); + } + + err = drm_bind_agp( dev_priv->agp_mem, 0 ); + if (err) { + DRM_ERROR("Unable to bind AGP memory\n"); + return err; + } + + offset = 0; + err = drm_addmap( dev, offset, warp_size, + _DRM_AGP, _DRM_READ_ONLY, & dev_priv->warp ); + if (err) { + DRM_ERROR("Unable to map WARP microcode\n"); + return err; + } + + offset += warp_size; + err = drm_addmap( dev, offset, dma_bs->primary_size, + _DRM_AGP, _DRM_READ_ONLY, & dev_priv->primary ); + if (err) { + DRM_ERROR("Unable to map primary DMA region\n"); + return err; + } + + offset += dma_bs->primary_size; + err = drm_addmap( dev, offset, secondary_size, + _DRM_AGP, 0, & dev->agp_buffer_map ); + if (err) { + DRM_ERROR("Unable to map secondary DMA region\n"); + return err; + } + + (void) memset( &req, 0, sizeof(req) ); + req.count = dma_bs->secondary_bin_count; + req.size = dma_bs->secondary_bin_size; + req.flags = _DRM_AGP_BUFFER; + req.agp_start = offset; + + err = drm_addbufs_agp( dev, & req ); + if (err) { + DRM_ERROR("Unable to add secondary DMA buffers\n"); + return err; + } + + offset += secondary_size; + err = drm_addmap( dev, offset, agp_size - offset, + _DRM_AGP, 0, & dev_priv->agp_textures ); + if (err) { + DRM_ERROR("Unable to map AGP texture region\n"); + return err; + } + + drm_core_ioremap(dev_priv->warp, dev); + drm_core_ioremap(dev_priv->primary, dev); + drm_core_ioremap(dev->agp_buffer_map, dev); + + if (!dev_priv->warp->handle || + !dev_priv->primary->handle || !dev->agp_buffer_map->handle) { + DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n", + dev_priv->warp->handle, dev_priv->primary->handle, + dev->agp_buffer_map->handle); + return DRM_ERR(ENOMEM); + } + + dev_priv->dma_access = MGA_PAGPXFER; + dev_priv->wagp_enable = MGA_WAGP_ENABLE; + + DRM_INFO("Initialized card for AGP DMA.\n"); + return 0; +} + +/** + * Create a "fake" drm_map_t for a pre-mapped range of PCI consistent memory. + * + * Unlike \c drm_addmap, this function just creates a \c drm_map_t wrapper for + * a block of PCI consistent memory. \c drm_addmap, basically, converts a bus + * address to a virtual address. However, \c drm_pci_alloc gives both the bus + * address and the virtual address for the memory region. Not only is there + * no need to map it again, but mapping it again will cause problems. + * + * \param dmah DRM DMA handle returned by \c drm_pci_alloc. + * \param map_ptr Location to store a pointer to the \c drm_map_t. + * + * \returns + * On success, zero is returned. Otherwise and error code suitable for + * returning from an ioctl is returned. + */ +static int mga_fake_addmap(drm_dma_handle_t * dmah, drm_map_t ** map_ptr) +{ + drm_map_t * map; + + + map = drm_alloc(sizeof(drm_map_t), DRM_MEM_DRIVER); + if (map == NULL) { + return DRM_ERR(ENOMEM); + } + + map->offset = dmah->busaddr; + map->size = dmah->size; + map->type = _DRM_CONSISTENT; + map->flags = _DRM_READ_ONLY; + map->handle = dmah->vaddr; + map->mtrr = 0; + + *map_ptr = map; + + return 0; +} + +/** + * Bootstrap the driver for PCI DMA. + * + * \todo + * The algorithm for decreasing the size of the primary DMA buffer could be + * better. The size should be rounded up to the nearest page size, then + * decrease the request size by a single page each pass through the loop. + * + * \todo + * Determine whether the maximum address passed to drm_pci_alloc is correct. + * The same goes for drm_addbufs_pci. + * + * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap + */ +static int mga_do_pci_dma_bootstrap(drm_device_t * dev, + drm_mga_dma_bootstrap_t * dma_bs) +{ + drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; + const unsigned int warp_size = mga_warp_microcode_size(dev_priv); + unsigned int primary_size; + unsigned int bin_count; + int err; + drm_buf_desc_t req; + + + if (dev->dma == NULL) { + DRM_ERROR("dev->dma is NULL\n"); + return DRM_ERR(EFAULT); + } + + + /* The WARP microcode base address must be 256-byte aligned. + */ + dev_priv->warp_dmah = drm_pci_alloc(dev, warp_size, 0x100, 0x7fffffff); + err = mga_fake_addmap(dev_priv->warp_dmah, & dev_priv->warp); + if (err) { + DRM_ERROR("Unable to map WARP microcode\n"); + return err; + } + + + /* Other than the bottom two bits being used to encode other + * information, there don't appear to be any restrictions on the + * alignment of the primary or secondary DMA buffers. + */ + + dev_priv->primary_dmah = NULL; + for ( primary_size = dma_bs->primary_size + ; primary_size != 0 + ; primary_size >>= 1 ) { + dev_priv->primary_dmah = drm_pci_alloc(dev, primary_size, + 0x04, 0x7fffffff); + if (dev_priv->primary_dmah != NULL) { + break; + } + } + + if (dev_priv->primary_dmah == NULL) { + DRM_ERROR("Unable to allocate primary DMA region\n"); + return DRM_ERR(ENOMEM); + } + + if (dev_priv->primary_dmah->size != dma_bs->primary_size) { + DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n", + dma_bs->primary_size, + (unsigned) dev_priv->primary_dmah->size); + dma_bs->primary_size = dev_priv->primary_dmah->size; + } + + err = mga_fake_addmap(dev_priv->primary_dmah, & dev_priv->primary); + if (err) { + DRM_ERROR("Unable to map primary DMA region\n"); + return err; + } + + + for ( bin_count = dma_bs->secondary_bin_count + ; bin_count > 0 + ; bin_count-- ) { + (void) memset( &req, 0, sizeof(req) ); + req.count = bin_count; + req.size = dma_bs->secondary_bin_size; + + err = drm_addbufs_pci( dev, & req ); + if (!err) { + break; + } + } + + if (bin_count == 0) { + DRM_ERROR("Unable to add secondary DMA buffers\n"); + return err; + } + + if (bin_count != dma_bs->secondary_bin_count) { + DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u " + "to %u.\n", dma_bs->secondary_bin_count, bin_count); + + dma_bs->secondary_bin_count = bin_count; + } + + dev_priv->dma_access = 0; + dev_priv->wagp_enable = 0; + + dma_bs->agp_mode = 0; + + DRM_INFO("Initialized card for PCI DMA.\n"); + return 0; +} + + +static int mga_do_dma_bootstrap(drm_device_t * dev, + drm_mga_dma_bootstrap_t * dma_bs) +{ + const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev); + int err; + drm_mga_private_t * const dev_priv = + (drm_mga_private_t *) dev->dev_private; + + + dev_priv->used_new_dma_init = 1; + + /* The first steps are the same for both PCI and AGP based DMA. Map + * the cards MMIO registers and map a status page. + */ + err = drm_addmap( dev, dev_priv->mmio_base, dev_priv->mmio_size, + _DRM_REGISTERS, _DRM_READ_ONLY, & dev_priv->mmio ); + if (err) { + DRM_ERROR("Unable to map MMIO region\n"); + return err; + } + + + err = drm_addmap( dev, 0, SAREA_MAX, _DRM_SHM, + _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL, + & dev_priv->status ); + if (err) { + DRM_ERROR("Unable to map status region\n"); + return err; + } + + + /* The DMA initialization procedure is slightly different for PCI and + * AGP cards. AGP cards just allocate a large block of AGP memory and + * carve off portions of it for internal uses. The remaining memory + * is returned to user-mode to be used for AGP textures. + */ + + if (is_agp) { + err = mga_do_agp_dma_bootstrap(dev, dma_bs); + } + + /* If we attempted to initialize the card for AGP DMA but failed, + * clean-up any mess that may have been created. + */ + + if (err) { + mga_do_cleanup_dma(dev); + } + + + /* Not only do we want to try and initialized PCI cards for PCI DMA, + * but we also try to initialized AGP cards that could not be + * initialized for AGP DMA. This covers the case where we have an AGP + * card in a system with an unsupported AGP chipset. In that case the + * card will be detected as AGP, but we won't be able to allocate any + * AGP memory, etc. + */ + + if (!is_agp || err) { + err = mga_do_pci_dma_bootstrap(dev, dma_bs); + } + + + return err; +} + +int mga_dma_bootstrap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_mga_dma_bootstrap_t bootstrap; + int err; + + + DRM_COPY_FROM_USER_IOCTL(bootstrap, + (drm_mga_dma_bootstrap_t __user *) data, + sizeof(bootstrap)); + + err = mga_do_dma_bootstrap(dev, & bootstrap); + if (! err) { + static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; + const drm_mga_private_t * const dev_priv = + (drm_mga_private_t *) dev->dev_private; + + if (dev_priv->agp_textures != NULL) { + bootstrap.texture_handle = dev_priv->agp_textures->offset; + bootstrap.texture_size = dev_priv->agp_textures->size; + } + else { + bootstrap.texture_handle = 0; + bootstrap.texture_size = 0; + } + + bootstrap.agp_mode = modes[ bootstrap.agp_mode & 0x07 ]; + if (DRM_COPY_TO_USER( (void __user *) data, & bootstrap, + sizeof(bootstrap))) { + err = DRM_ERR(EFAULT); + } + } + else { + mga_do_cleanup_dma(dev); + } + + return err; +} + + static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init) { drm_mga_private_t *dev_priv; @@ -443,42 +845,47 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init) return DRM_ERR(EINVAL); } - dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio) { - DRM_ERROR("failed to find mmio region!\n"); - return DRM_ERR(EINVAL); - } - dev_priv->status = drm_core_findmap(dev, init->status_offset); - if (!dev_priv->status) { - DRM_ERROR("failed to find status page!\n"); - return DRM_ERR(EINVAL); - } - dev_priv->warp = drm_core_findmap(dev, init->warp_offset); - if (!dev_priv->warp) { - DRM_ERROR("failed to find warp microcode region!\n"); - return DRM_ERR(EINVAL); - } - dev_priv->primary = drm_core_findmap(dev, init->primary_offset); - if (!dev_priv->primary) { - DRM_ERROR("failed to find primary dma region!\n"); - return DRM_ERR(EINVAL); - } - dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); - if (!dev->agp_buffer_map) { - DRM_ERROR("failed to find dma buffer region!\n"); - return DRM_ERR(EINVAL); + if (! dev_priv->used_new_dma_init) { + dev_priv->status = drm_core_findmap(dev, init->status_offset); + if (!dev_priv->status) { + DRM_ERROR("failed to find status page!\n"); + return DRM_ERR(EINVAL); + } + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio) { + DRM_ERROR("failed to find mmio region!\n"); + return DRM_ERR(EINVAL); + } + dev_priv->warp = drm_core_findmap(dev, init->warp_offset); + if (!dev_priv->warp) { + DRM_ERROR("failed to find warp microcode region!\n"); + return DRM_ERR(EINVAL); + } + dev_priv->primary = drm_core_findmap(dev, init->primary_offset); + if (!dev_priv->primary) { + DRM_ERROR("failed to find primary dma region!\n"); + return DRM_ERR(EINVAL); + } + dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + if (!dev->agp_buffer_map) { + DRM_ERROR("failed to find dma buffer region!\n"); + return DRM_ERR(EINVAL); + } + + drm_core_ioremap(dev_priv->warp, dev); + drm_core_ioremap(dev_priv->primary, dev); + drm_core_ioremap(dev->agp_buffer_map, dev); } dev_priv->sarea_priv = (drm_mga_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); - drm_core_ioremap(dev_priv->warp, dev); - drm_core_ioremap(dev_priv->primary, dev); - drm_core_ioremap(dev->agp_buffer_map, dev); - if (!dev_priv->warp->handle || - !dev_priv->primary->handle || !dev->agp_buffer_map->handle) { + !dev_priv->primary->handle || + ((dev_priv->dma_access != 0) && + ((dev->agp_buffer_map == NULL) || + (dev->agp_buffer_map->handle == NULL)))) { DRM_ERROR("failed to ioremap agp regions!\n"); return DRM_ERR(ENOMEM); } @@ -538,6 +945,7 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init) static int mga_do_cleanup_dma(drm_device_t * dev) { + int err = 0; DRM_DEBUG("\n"); /* Make sure interrupts are disabled here because the uninstall ioctl @@ -550,13 +958,73 @@ static int mga_do_cleanup_dma(drm_device_t * dev) if (dev->dev_private) { drm_mga_private_t *dev_priv = dev->dev_private; - if (dev_priv->warp != NULL) + if ((dev_priv->warp != NULL) + && (dev_priv->mmio->type != _DRM_CONSISTENT)) drm_core_ioremapfree(dev_priv->warp, dev); - if (dev_priv->primary != NULL) + + if ((dev_priv->primary != NULL) + && (dev_priv->primary->type != _DRM_CONSISTENT)) drm_core_ioremapfree(dev_priv->primary, dev); + if (dev->agp_buffer_map != NULL) drm_core_ioremapfree(dev->agp_buffer_map, dev); + if (dev_priv->used_new_dma_init) { + if (dev_priv->warp != NULL) { + drm_rmmap(dev, (void *) dev_priv->warp->offset); + } + + if (dev_priv->primary != NULL) { + if (dev_priv->primary->type != _DRM_CONSISTENT) { + drm_rmmap(dev, (void *) dev_priv->primary->offset); + } + else { + drm_free(dev_priv->primary, sizeof(drm_map_t), DRM_MEM_DRIVER); + } + } + + if (dev_priv->warp_dmah != NULL) { + drm_pci_free(dev, dev_priv->warp_dmah); + dev_priv->warp_dmah = NULL; + } + + if (dev_priv->primary_dmah != NULL) { + drm_pci_free(dev, dev_priv->primary_dmah); + dev_priv->primary_dmah = NULL; + } + + if (dev_priv->mmio != NULL) { + drm_rmmap(dev, (void *) dev_priv->mmio->offset); + } + + if (dev_priv->status != NULL) { + drm_rmmap(dev, (void *) dev_priv->status->offset); + } + + if (dev_priv->agp_mem != NULL) { + if (dev->agp_buffer_map != NULL) { + drm_rmmap(dev, (void *) dev->agp_buffer_map->offset); + } + + if (dev_priv->agp_textures != NULL) { + drm_rmmap(dev, (void *) dev_priv->agp_textures->offset); + dev_priv->agp_textures = NULL; + } + + drm_unbind_agp(dev_priv->agp_mem); + + drm_free_agp(dev_priv->agp_mem, dev_priv->agp_pages); + dev_priv->agp_pages = 0; + dev_priv->agp_mem = NULL; + } + + if ((dev->agp != NULL) && dev->agp->acquired) { + err = drm_agp_release(dev); + } + + dev_priv->used_new_dma_init = 0; + } + dev_priv->warp = NULL; dev_priv->primary = NULL; dev_priv->mmio = NULL; diff --git a/shared-core/mga_drm.h b/shared-core/mga_drm.h index c3811fea..5b8f1564 100644 --- a/shared-core/mga_drm.h +++ b/shared-core/mga_drm.h @@ -73,6 +73,8 @@ #define MGA_CARD_TYPE_G200 1 #define MGA_CARD_TYPE_G400 2 +#define MGA_CARD_TYPE_G450 3 /* not currently used */ +#define MGA_CARD_TYPE_G550 4 #define MGA_FRONT 0x1 #define MGA_BACK 0x2 @@ -237,6 +239,14 @@ typedef struct _drm_mga_sarea { #define DRM_MGA_BLIT 0x08 #define DRM_MGA_GETPARAM 0x09 +/* 3.2: + * ioctls for operating on fences. + */ +#define DRM_MGA_SET_FENCE 0x0a +#define DRM_MGA_WAIT_FENCE 0x0b +#define DRM_MGA_DMA_BOOTSTRAP 0x0c + + #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) @@ -247,6 +257,9 @@ typedef struct _drm_mga_sarea { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) #define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) +#define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t) +#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t) +#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) typedef struct _drm_mga_warp_index { int installed; @@ -285,6 +298,74 @@ typedef struct drm_mga_init { unsigned long buffers_offset; } drm_mga_init_t; + +typedef struct drm_mga_dma_bootstrap { + /** + * \name AGP texture region + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will + * be filled in with the actual AGP texture settings. + * + * \warning + * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode + * is zero, it means that PCI memory (most likely through the use of + * an IOMMU) is being used for "AGP" textures. + */ + /*@{*/ + drm_handle_t texture_handle; /**< Handle used to map AGP textures. */ + uint32_t texture_size; /**< Size of the AGP texture region. */ + /*@}*/ + + + /** + * Requested size of the primary DMA region. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + */ + uint32_t primary_size; + + + /** + * Requested number of secondary DMA buffers. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual number of secondary DMA buffers + * allocated. Particularly when PCI DMA is used, this may be + * (subtantially) less than the number requested. + */ + uint32_t secondary_bin_count; + + + /** + * Requested size of each secondary DMA buffer. + * + * While the kernel \b is free to reduce + * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed + * to reduce dma_mga_dma_bootstrap::secondary_bin_size. + */ + uint32_t secondary_bin_size; + + + /** + * Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X, + * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is + * zero, it means that PCI DMA should be used, even if AGP is + * possible. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + * (i.e., PCI DMA was used), this value will be zero. + */ + uint32_t agp_mode; + + + /** + * Desired AGP GART size, measured in megabytes. + */ + uint8_t agp_size; +} drm_mga_dma_bootstrap_t; + typedef struct drm_mga_clear { unsigned int flags; unsigned int clear_color; @@ -328,6 +409,14 @@ typedef struct _drm_mga_blit { */ #define MGA_PARAM_IRQ_NR 1 +/* 3.2: Query the actual card type. The DDX only distinguishes between + * G200 chips and non-G200 chips, which it calls G400. It turns out that + * there are some very sublte differences between the G4x0 chips and the G550 + * chips. Using this parameter query, a client-side driver can detect the + * difference between a G4x0 and a G550. + */ +#define MGA_PARAM_CARD_TYPE 2 + typedef struct drm_mga_getparam { int param; void __user *value; diff --git a/shared-core/mga_drv.h b/shared-core/mga_drv.h index 180c1235..7a1799b9 100644 --- a/shared-core/mga_drv.h +++ b/shared-core/mga_drv.h @@ -38,11 +38,11 @@ #define DRIVER_NAME "mga" #define DRIVER_DESC "Matrox G200/G400" -#define DRIVER_DATE "20050606" +#define DRIVER_DATE "20050607" #define DRIVER_MAJOR 3 -#define DRIVER_MINOR 1 -#define DRIVER_PATCHLEVEL 3 +#define DRIVER_MINOR 2 +#define DRIVER_PATCHLEVEL 0 typedef struct drm_mga_primary_buffer { u8 *start; @@ -87,9 +87,55 @@ typedef struct drm_mga_private { int chipset; int usec_timeout; + /** + * If set, the new DMA initialization sequence was used. This is + * primarilly used to select how the driver should uninitialized its + * internal DMA structures. + */ + int used_new_dma_init; + + /** + * If AGP memory is used for DMA buffers, this will be the value + * \c MGA_PAGPXFER. Otherwise, it will be zero (for a PCI transfer). + */ + u32 dma_access; + + /** + * If AGP memory is used for DMA buffers, this will be the value + * \c MGA_WAGP_ENABLE. Otherwise, it will be zero (for a PCI + * transfer). + */ + u32 wagp_enable; + + + /** + * \name Handles for PCI consistent memory. + * + * \sa drm_mga_private_t::primary, drm_mga_private_t::warp + */ + /*@{*/ + drm_dma_handle_t * warp_dmah; /**< Handle for WARP ucode region. */ + drm_dma_handle_t * primary_dmah; /**< Handle for primary DMA region. */ + /*@}*/ + + + /** + * \name MMIO region parameters. + * + * \sa drm_mga_private_t::mmio + */ + /*@{*/ + u32 mmio_base; /**< Bus address of base of MMIO. */ + u32 mmio_size; /**< Size of the MMIO region. */ + /*@}*/ + u32 clear_cmd; u32 maccess; + wait_queue_head_t fence_queue; + atomic_t last_fence_retired; + u32 next_fence_to_post; + unsigned int fb_cpp; unsigned int front_offset; unsigned int front_pitch; @@ -109,10 +155,14 @@ typedef struct drm_mga_private { drm_local_map_t *warp; drm_local_map_t *primary; drm_local_map_t *agp_textures; + + DRM_AGP_MEM *agp_mem; + unsigned int agp_pages; } drm_mga_private_t; /* mga_dma.c */ extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags); +extern int mga_dma_bootstrap(DRM_IOCTL_ARGS); extern int mga_dma_init(DRM_IOCTL_ARGS); extern int mga_dma_flush(DRM_IOCTL_ARGS); extern int mga_dma_reset(DRM_IOCTL_ARGS); @@ -134,6 +184,8 @@ extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv); extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); extern int mga_warp_init(drm_mga_private_t * dev_priv); + /* mga_irq.c */ +extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence); extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); extern void mga_driver_irq_preinstall(drm_device_t * dev); @@ -520,6 +572,12 @@ do { \ */ #define MGA_EXEC 0x0100 +/* AGP PLL encoding (for G200 only). + */ +#define MGA_AGP_PLL 0x1e4c +# define MGA_AGP2XPLL_DISABLE (0 << 0) +# define MGA_AGP2XPLL_ENABLE (1 << 0) + /* Warp registers */ #define MGA_WR0 0x2d00 diff --git a/shared-core/mga_irq.c b/shared-core/mga_irq.c index 99a23fe1..16dfd44b 100644 --- a/shared-core/mga_irq.c +++ b/shared-core/mga_irq.c @@ -40,6 +40,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) drm_device_t *dev = (drm_device_t *) arg; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; int status; + int handled = 0; status = MGA_READ(MGA_STATUS); @@ -49,6 +50,30 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); + handled = 1; + } + + /* SOFTRAP interrupt */ + if (status & MGA_SOFTRAPEN) { + const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); + const u32 prim_end = MGA_READ(MGA_PRIMEND); + + + MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); + + /* In addition to clearing the interrupt-pending bit, we + * have to write to MGA_PRIMEND to re-start the DMA operation. + */ + if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) { + MGA_WRITE(MGA_PRIMEND, prim_end); + } + + atomic_inc(&dev_priv->last_fence_retired); + DRM_WAKEUP(&dev_priv->fence_queue); + handled = 1; + } + + if ( handled ) { return IRQ_HANDLED; } return IRQ_NONE; @@ -72,6 +97,25 @@ int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) return ret; } +int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; + unsigned int cur_fence; + int ret = 0; + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using fences. + */ + DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ, + (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) + - *sequence) <= (1 << 23))); + + *sequence = cur_fence; + + return ret; +} + void mga_driver_irq_preinstall(drm_device_t * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -86,8 +130,10 @@ void mga_driver_irq_postinstall(drm_device_t * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - /* Turn on VBL interrupt */ - MGA_WRITE(MGA_IEN, MGA_VLINEIEN); + DRM_INIT_WAITQUEUE( &dev_priv->fence_queue ); + + /* Turn on vertical blank interrupt and soft trap interrupt. */ + MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); } void mga_driver_irq_uninstall(drm_device_t * dev) diff --git a/shared-core/mga_state.c b/shared-core/mga_state.c index e7921bd2..273854cd 100644 --- a/shared-core/mga_state.c +++ b/shared-core/mga_state.c @@ -264,7 +264,7 @@ static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv) MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff, MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | - MGA_WMODE_START | MGA_WAGP_ENABLE)); + MGA_WMODE_START | dev_priv->wagp_enable)); ADVANCE_DMA(); } @@ -345,7 +345,7 @@ static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv) MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff, MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | - MGA_WMODE_START | MGA_WAGP_ENABLE)); + MGA_WMODE_START | dev_priv->wagp_enable)); ADVANCE_DMA(); } @@ -455,7 +455,7 @@ static int mga_verify_state(drm_mga_private_t * dev_priv) if (dirty & MGA_UPLOAD_TEX0) ret |= mga_verify_tex(dev_priv, 0); - if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { if (dirty & MGA_UPLOAD_TEX1) ret |= mga_verify_tex(dev_priv, 1); @@ -679,7 +679,7 @@ static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf) MGA_SECADDRESS, (address | MGA_DMA_VERTEX), MGA_SECEND, ((address + length) | - MGA_PAGPXFER)); + dev_priv->dma_access)); ADVANCE_DMA(); } while (++i < sarea_priv->nbox); @@ -725,7 +725,7 @@ static void mga_dma_dispatch_indices(drm_device_t * dev, drm_buf_t * buf, MGA_DMAPAD, 0x00000000, MGA_SETUPADDRESS, address + start, MGA_SETUPEND, ((address + end) | - MGA_PAGPXFER)); + dev_priv->dma_access)); ADVANCE_DMA(); } while (++i < sarea_priv->nbox); @@ -752,7 +752,7 @@ static void mga_dma_dispatch_iload(drm_device_t * dev, drm_buf_t * buf, drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; - u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM; + u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM; u32 y2; DMA_LOCALS; DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used); @@ -1087,6 +1087,9 @@ static int mga_getparam(DRM_IOCTL_ARGS) case MGA_PARAM_IRQ_NR: value = dev->irq; break; + case MGA_PARAM_CARD_TYPE: + value = dev_priv->chipset; + break; default: return DRM_ERR(EINVAL); } @@ -1099,6 +1102,67 @@ static int mga_getparam(DRM_IOCTL_ARGS) return 0; } +static int mga_set_fence(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_mga_private_t *dev_priv = dev->dev_private; + u32 temp; + DMA_LOCALS; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); + + /* I would normal do this assignment in the declaration of temp, + * but dev_priv may be NULL. + */ + + temp = dev_priv->next_fence_to_post; + dev_priv->next_fence_to_post++; + + BEGIN_DMA(1); + DMA_BLOCK(MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_SOFTRAP, 0x00000000); + ADVANCE_DMA(); + + if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + +static int mga_wait_fence(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_mga_private_t *dev_priv = dev->dev_private; + u32 fence; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32)); + + DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); + + mga_driver_fence_wait(dev, & fence); + + if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) { + DRM_ERROR("copy_to_user\n"); + return DRM_ERR(EFAULT); + } + + return 0; +} + drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1}, [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0}, @@ -1110,6 +1174,10 @@ drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0}, [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0}, [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0}, + [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0}, + [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0}, + [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1}, + }; int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); diff --git a/shared-core/mga_warp.c b/shared-core/mga_warp.c index b8fe48d1..304d9ff6 100644 --- a/shared-core/mga_warp.c +++ b/shared-core/mga_warp.c @@ -80,6 +80,7 @@ unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv) { switch (dev_priv->chipset) { case MGA_CARD_TYPE_G400: + case MGA_CARD_TYPE_G550: return PAGE_ALIGN(mga_warp_g400_microcode_size); case MGA_CARD_TYPE_G200: return PAGE_ALIGN(mga_warp_g200_microcode_size); @@ -148,6 +149,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv) switch (dev_priv->chipset) { case MGA_CARD_TYPE_G400: + case MGA_CARD_TYPE_G550: return mga_warp_install_g400_microcode(dev_priv); case MGA_CARD_TYPE_G200: return mga_warp_install_g200_microcode(dev_priv); @@ -166,6 +168,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv) */ switch (dev_priv->chipset) { case MGA_CARD_TYPE_G400: + case MGA_CARD_TYPE_G550: MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND); MGA_WRITE(MGA_WGETMSB, 0x00000E00); MGA_WRITE(MGA_WVRTXSZ, 0x00001807); diff --git a/shared/mga_drm.h b/shared/mga_drm.h index c3811fea..4934414a 100644 --- a/shared/mga_drm.h +++ b/shared/mga_drm.h @@ -73,6 +73,7 @@ #define MGA_CARD_TYPE_G200 1 #define MGA_CARD_TYPE_G400 2 +#define MGA_CARD_TYPE_G550 3 #define MGA_FRONT 0x1 #define MGA_BACK 0x2 @@ -237,6 +238,14 @@ typedef struct _drm_mga_sarea { #define DRM_MGA_BLIT 0x08 #define DRM_MGA_GETPARAM 0x09 +/* 3.2: + * ioctls for operating on fences. + */ +#define DRM_MGA_SET_FENCE 0x0a +#define DRM_MGA_WAIT_FENCE 0x0b +#define DRM_MGA_DMA_BOOTSTRAP 0x0c + + #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) @@ -247,6 +256,9 @@ typedef struct _drm_mga_sarea { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) #define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) +#define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t) +#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t) +#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) typedef struct _drm_mga_warp_index { int installed; @@ -285,6 +297,74 @@ typedef struct drm_mga_init { unsigned long buffers_offset; } drm_mga_init_t; + +typedef struct drm_mga_dma_bootstrap { + /** + * \name AGP texture region + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will + * be filled in with the actual AGP texture settings. + * + * \warning + * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode + * is zero, it means that PCI memory (most likely through the use of + * an IOMMU) is being used for "AGP" textures. + */ + /*@{*/ + drm_handle_t texture_handle; /**< Handle used to map AGP textures. */ + uint32_t texture_size; /**< Size of the AGP texture region. */ + /*@}*/ + + + /** + * Requested size of the primary DMA region. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + */ + uint32_t primary_size; + + + /** + * Requested number of secondary DMA buffers. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual number of secondary DMA buffers + * allocated. Particularly when PCI DMA is used, this may be + * (subtantially) less than the number requested. + */ + uint32_t secondary_bin_count; + + + /** + * Requested size of each secondary DMA buffer. + * + * While the kernel \b is free to reduce + * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed + * to reduce dma_mga_dma_bootstrap::secondary_bin_size. + */ + uint32_t secondary_bin_size; + + + /** + * Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X, + * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is + * zero, it means that PCI DMA should be used, even if AGP is + * possible. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + * (i.e., PCI DMA was used), this value will be zero. + */ + uint32_t agp_mode; + + + /** + * Desired AGP GART size, measured in megabytes. + */ + uint8_t agp_size; +} drm_mga_dma_bootstrap_t; + typedef struct drm_mga_clear { unsigned int flags; unsigned int clear_color; @@ -328,6 +408,14 @@ typedef struct _drm_mga_blit { */ #define MGA_PARAM_IRQ_NR 1 +/* 3.2: Query the actual card type. The DDX only distinguishes between + * G200 chips and non-G200 chips, which it calls G400. It turns out that + * there are some very sublte differences between the G4x0 chips and the G550 + * chips. Using this parameter query, a client-side driver can detect the + * difference between a G4x0 and a G550. + */ +#define MGA_PARAM_CARD_TYPE 2 + typedef struct drm_mga_getparam { int param; void __user *value; |