From 72cfc797b51e59ecf8a2787c6a176838241cc94b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 14 Jun 2005 22:34:11 +0000 Subject: [PATCH] =?utf8?q?Adds=20support=20for=20PCI=20cards=20to=20MGA=20?= =?utf8?q?DRM=20This=20patch=20adds=20serveral=20new=20ioctls=20and=20a=20?= =?utf8?q?new=20query=20to=20get=5Fparam=20query=20to=20=20=20=20=20suppor?= =?utf8?q?t=20PCI=20MGA=20cards.=20Two=20ioctls=20were=20added=20to=20impl?= =?utf8?q?ement=20interrupt=20based=20waiting.=20With=20this=20=20=20=20?= =?utf8?q?=20change,=20the=20client-side=20driver=20no=20longer=20needs=20?= =?utf8?q?to=20map=20the=20primary=20DMA=20=20=20=20=20region=20or=20the?= =?utf8?q?=20MMIO=20region.=20Previously,=20end-of-frame=20waiting=20was?= =?utf8?q?=20done=20by=20=20=20=20=20busy=20waiting=20in=20the=20client-si?= =?utf8?q?de=20driver=20until=20one=20of=20the=20MMIO=20registers=20=20=20?= =?utf8?q?=20=20(the=20current=20DMA=20pointer)=20matched=20a=20pointer=20?= =?utf8?q?to=20the=20end=20of=20primary=20DMA=20=20=20=20=20space.=20By=20?= =?utf8?q?using=20interrupts,=20the=20busy=20waiting=20and=20the=20extra?= =?utf8?q?=20mappings=20are=20=20=20=20=20removed.=20A=20third=20ioctl=20w?= =?utf8?q?as=20added=20to=20bootstrap=20DMA.=20This=20ioctl,=20which=20is?= =?utf8?q?=20used=20by=20the=20=20=20=20=20X-server,=20moves=20a=20*LOT*?= =?utf8?q?=20of=20code=20from=20the=20X-server=20into=20the=20kernel.=20Th?= =?utf8?q?is=20=20=20=20=20allows=20the=20kernel=20to=20do=20whatever=20ne?= =?utf8?q?eds=20to=20be=20done=20to=20setup=20DMA=20buffers.=20=20=20=20?= =?utf8?q?=20The=20entire=20process=20and=20the=20locations=20of=20the=20b?= =?utf8?q?uffers=20are=20hidden=20from=20=20=20=20=20user-mode.=20Addition?= =?utf8?q?ally,=20a=20get=5Fparam=20query=20was=20added=20to=20differentia?= =?utf8?q?te=20between=20G4x0=20=20=20=20=20cards=20and=20G550=20cards.=20?= =?utf8?q?A=20gap=20was=20left=20in=20the=20numbering=20sequence=20so=20th?= =?utf8?q?at,=20=20=20=20=20if=20needed,=20G450=20cards=20could=20be=20dis?= =?utf8?q?tinguished=20from=20G400=20cards.=20According=20=20=20=20=20to?= =?utf8?q?=20Ville=20Syrj=C3=A4l=C3=A4,=20the=20G4x0=20cards=20and=20the?= =?utf8?q?=20G550=20cards=20handle=20=20=20=20=20anisotropic=20filtering?= =?utf8?q?=20differently.=20This=20seems=20the=20most=20compatible=20way?= =?utf8?q?=20=20=20=20=20to=20let=20the=20client-side=20driver=20know=20wh?= =?utf8?q?ich=20card=20it's=20own.=20Doing=20this=20very=20=20=20=20=20sma?= =?utf8?q?ll=20change=20now=20eliminates=20the=20need=20to=20bump=20the=20?= =?utf8?q?DRM=20minor=20version=20=20=20=20=20twice.=20http://marc.theaims?= =?utf8?q?group.com/=3Fl=3Ddri-devel&m=3D106625815319773&w=3D2=20A=20numbe?= =?utf8?q?r=20of=20ioctl=20handlers=20in=20linux-core=20were=20also=20modi?= =?utf8?q?fied=20so=20that=20they=20=20=20=20=20could=20be=20called=20in-k?= =?utf8?q?ernel.=20In=20these=20cases,=20the=20in-kernel=20callable=20=20?= =?utf8?q?=20=20=20version=20kept=20the=20existing=20name=20(e.g.,=20drm?= =?utf8?q?=5Fagp=5Facquire)=20and=20the=20ioctl=20=20=20=20=20handler=20ad?= =?utf8?q?ded=20=5Fioctl=20to=20the=20name=20(e.g.,=20drm=5Fagp=5Facquire?= =?utf8?q?=5Fioctl).=20This=20patch=20also=20replaces=20the=20drm=5Fagp=5F?= =?utf8?q?do=5Frelease=20function=20with=20=20=20=20=20drm=5Fagp=5Frelease?= =?utf8?q?.=20drm=5Fagp=5Frelease=20(drm=5Fcore=5Fagp=5Frelease=20in=20the?= =?utf8?q?=20previous=20=20=20=20=20patch)=20is=20very=20similar=20to=20dr?= =?utf8?q?m=5Fagp=5Fdo=5Frelease,=20and=20I=20saw=20no=20reason=20to=20=20?= =?utf8?q?=20=20=20have=20both.=20This=20commit=20*breaks=20the=20build*?= =?utf8?q?=20on=20BSD.=20Eric=20said=20that=20he=20would=20make=20the=20?= =?utf8?q?=20=20=20=20required=20updates=20to=20the=20BSD=20side=20soon.?= =?utf8?q?=20Xorg=20bug:=203259=20Reviewed=20by:=20Eric=20Anholt?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- bsd-core/drmP.h | 4 +- bsd-core/drm_agpsupport.c | 17 +- bsd-core/drm_drv.c | 4 +- linux-core/drmP.h | 28 ++- linux-core/drm_agpsupport.c | 132 ++++++----- linux-core/drm_bufs.c | 89 ++++--- linux-core/drm_drv.c | 18 +- linux-core/drm_memory.c | 4 + linux-core/mga_drv.c | 13 +- shared-core/drm_pciids.txt | 3 +- shared-core/mga_dma.c | 550 ++++++++++++++++++++++++++++++++++++++++---- shared-core/mga_drm.h | 89 +++++++ shared-core/mga_drv.h | 64 +++++- shared-core/mga_irq.c | 50 +++- shared-core/mga_state.c | 80 ++++++- shared-core/mga_warp.c | 3 + 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 98e4945..b22ce3b 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 540cb40..7c5351a 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 44a6c85..e3cac42 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 40579bf..7d5902e 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 fcbe56a..686efcc 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 5018216..b54aaeb 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 5a39e34..39c893c 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 55523c6..2cc3dc6 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 4387759..ed55c1f 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 82cbdd4..aa975ee 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 4c0be4c..998886d 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 - * Jeff Hartmann - * Keith Whitwell - * - * Rewritten by: - * Gareth Hughes + */ + +/** + * \file mga_dma.c + * DMA support for MGA G200 / G400. + * + * \author Rickard E. (Rik) Faith + * \author Jeff Hartmann + * \author Keith Whitwell + * \author Gareth Hughes */ #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 c3811fe..5b8f156 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 180c123..7a1799b 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 99a23fe..16dfd44 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 e7921bd..273854c 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 b8fe48d..304d9ff 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 c3811fe..4934414 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; -- 2.7.4