2  * \file drm_agpsupport.h
 
   3  * DRM support for AGP/GART backend
 
   5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
 
   6  * \author Gareth Hughes <gareth@valinux.com>
 
  10  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 
  11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 
  12  * All Rights Reserved.
 
  14  * Permission is hereby granted, free of charge, to any person obtaining a
 
  15  * copy of this software and associated documentation files (the "Software"),
 
  16  * to deal in the Software without restriction, including without limitation
 
  17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
  18  * and/or sell copies of the Software, and to permit persons to whom the
 
  19  * Software is furnished to do so, subject to the following conditions:
 
  21  * The above copyright notice and this permission notice (including the next
 
  22  * paragraph) shall be included in all copies or substantial portions of the
 
  25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
  26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
  27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
  28  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
  29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
  30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
  31  * OTHER DEALINGS IN THE SOFTWARE.
 
  35 #include <linux/module.h>
 
  40  * Get AGP information.
 
  42  * \param inode device inode.
 
  43  * \param filp file pointer.
 
  45  * \param arg pointer to a (output) drm_agp_info structure.
 
  46  * \return zero on success or a negative number on failure.
 
  48  * Verifies the AGP device has been initialized and acquired and fills in the
 
  49  * drm_agp_info structure with the information in drm_agp_head::agp_info.
 
  51 int drm_agp_info(drm_device_t * dev, drm_agp_info_t * info)
 
  55         if (!dev->agp || !dev->agp->acquired)
 
  58         kern = &dev->agp->agp_info;
 
  59         info->agp_version_major = kern->version.major;
 
  60         info->agp_version_minor = kern->version.minor;
 
  61         info->mode = kern->mode;
 
  62         info->aperture_base = kern->aper_base;
 
  63         info->aperture_size = kern->aper_size * 1024 * 1024;
 
  64         info->memory_allowed = kern->max_memory << PAGE_SHIFT;
 
  65         info->memory_used = kern->current_memory << PAGE_SHIFT;
 
  66         info->id_vendor = kern->device->vendor;
 
  67         info->id_device = kern->device->device;
 
  72 EXPORT_SYMBOL(drm_agp_info);
 
  74 int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
 
  75                        unsigned int cmd, unsigned long arg)
 
  77         drm_file_t *priv = filp->private_data;
 
  78         drm_device_t *dev = priv->head->dev;
 
  82         err = drm_agp_info(dev, &info);
 
  86         if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info)))
 
  92  * Acquire the AGP device.
 
  94  * \param dev DRM device that is to acquire AGP
 
  95  * \return zero on success or a negative number on failure.
 
  97  * Verifies the AGP device hasn't been acquired before and calls
 
  98  * \c agp_backend_acquire.
 
 100 int drm_agp_acquire(drm_device_t * dev)
 
 104         if (dev->agp->acquired)
 
 106         if (!(dev->agp->bridge = agp_backend_acquire(dev->pdev)))
 
 108         dev->agp->acquired = 1;
 
 112 EXPORT_SYMBOL(drm_agp_acquire);
 
 115  * Acquire the AGP device (ioctl).
 
 117  * \param inode device inode.
 
 118  * \param filp file pointer.
 
 119  * \param cmd command.
 
 120  * \param arg user argument.
 
 121  * \return zero on success or a negative number on failure.
 
 123  * Verifies the AGP device hasn't been acquired before and calls
 
 124  * \c agp_backend_acquire.
 
 126 int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
 
 127                           unsigned int cmd, unsigned long arg)
 
 129         drm_file_t *priv = filp->private_data;
 
 131         return drm_agp_acquire((drm_device_t *) priv->head->dev);
 
 135  * Release the AGP device.
 
 137  * \param dev DRM device that is to release AGP
 
 138  * \return zero on success or a negative number on failure.
 
 140  * Verifies the AGP device has been acquired and calls \c agp_backend_release.
 
 142 int drm_agp_release(drm_device_t * dev)
 
 144         if (!dev->agp || !dev->agp->acquired)
 
 146         agp_backend_release(dev->agp->bridge);
 
 147         dev->agp->acquired = 0;
 
 151 EXPORT_SYMBOL(drm_agp_release);
 
 153 int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
 
 154                           unsigned int cmd, unsigned long arg)
 
 156         drm_file_t *priv = filp->private_data;
 
 157         drm_device_t *dev = priv->head->dev;
 
 159         return drm_agp_release(dev);
 
 163  * Enable the AGP bus.
 
 165  * \param dev DRM device that has previously acquired AGP.
 
 166  * \param mode Requested AGP mode.
 
 167  * \return zero on success or a negative number on failure.
 
 169  * Verifies the AGP device has been acquired but not enabled, and calls
 
 172 int drm_agp_enable(drm_device_t * dev, drm_agp_mode_t mode)
 
 174         if (!dev->agp || !dev->agp->acquired)
 
 177         dev->agp->mode = mode.mode;
 
 178         agp_enable(dev->agp->bridge, mode.mode);
 
 179         dev->agp->base = dev->agp->agp_info.aper_base;
 
 180         dev->agp->enabled = 1;
 
 184 EXPORT_SYMBOL(drm_agp_enable);
 
 186 int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
 
 187                          unsigned int cmd, unsigned long arg)
 
 189         drm_file_t *priv = filp->private_data;
 
 190         drm_device_t *dev = priv->head->dev;
 
 193         if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode)))
 
 196         return drm_agp_enable(dev, mode);
 
 200  * Allocate AGP memory.
 
 202  * \param inode device inode.
 
 203  * \param filp file pointer.
 
 204  * \param cmd command.
 
 205  * \param arg pointer to a drm_agp_buffer structure.
 
 206  * \return zero on success or a negative number on failure.
 
 208  * Verifies the AGP device is present and has been acquired, allocates the
 
 209  * memory via alloc_agp() and creates a drm_agp_mem entry for it.
 
 211 int drm_agp_alloc(struct inode *inode, struct file *filp,
 
 212                   unsigned int cmd, unsigned long arg)
 
 214         drm_file_t *priv = filp->private_data;
 
 215         drm_device_t *dev = priv->head->dev;
 
 216         drm_agp_buffer_t request;
 
 217         drm_agp_mem_t *entry;
 
 221         drm_agp_buffer_t __user *argp = (void __user *)arg;
 
 223         if (!dev->agp || !dev->agp->acquired)
 
 225         if (copy_from_user(&request, argp, sizeof(request)))
 
 227         if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS)))
 
 230         memset(entry, 0, sizeof(*entry));
 
 232         pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
 
 233         type = (u32) request.type;
 
 235         if (!(memory = drm_alloc_agp(dev, pages, type))) {
 
 236                 drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
 
 240         entry->handle = (unsigned long)memory->key + 1;
 
 241         entry->memory = memory;
 
 243         entry->pages = pages;
 
 245         entry->next = dev->agp->memory;
 
 246         if (dev->agp->memory)
 
 247                 dev->agp->memory->prev = entry;
 
 248         dev->agp->memory = entry;
 
 250         request.handle = entry->handle;
 
 251         request.physical = memory->physical;
 
 253         if (copy_to_user(argp, &request, sizeof(request))) {
 
 254                 dev->agp->memory = entry->next;
 
 255                 dev->agp->memory->prev = NULL;
 
 256                 drm_free_agp(memory, pages);
 
 257                 drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
 
 264  * Search for the AGP memory entry associated with a handle.
 
 266  * \param dev DRM device structure.
 
 267  * \param handle AGP memory handle.
 
 268  * \return pointer to the drm_agp_mem structure associated with \p handle.
 
 270  * Walks through drm_agp_head::memory until finding a matching handle.
 
 272 static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev,
 
 273                                            unsigned long handle)
 
 275         drm_agp_mem_t *entry;
 
 277         for (entry = dev->agp->memory; entry; entry = entry->next) {
 
 278                 if (entry->handle == handle)
 
 285  * Unbind AGP memory from the GATT (ioctl).
 
 287  * \param inode device inode.
 
 288  * \param filp file pointer.
 
 289  * \param cmd command.
 
 290  * \param arg pointer to a drm_agp_binding structure.
 
 291  * \return zero on success or a negative number on failure.
 
 293  * Verifies the AGP device is present and acquired, looks-up the AGP memory
 
 294  * entry and passes it to the unbind_agp() function.
 
 296 int drm_agp_unbind(struct inode *inode, struct file *filp,
 
 297                    unsigned int cmd, unsigned long arg)
 
 299         drm_file_t *priv = filp->private_data;
 
 300         drm_device_t *dev = priv->head->dev;
 
 301         drm_agp_binding_t request;
 
 302         drm_agp_mem_t *entry;
 
 305         if (!dev->agp || !dev->agp->acquired)
 
 308             (&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
 
 310         if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
 
 314         ret = drm_unbind_agp(entry->memory);
 
 321  * Bind AGP memory into the GATT (ioctl)
 
 323  * \param inode device inode.
 
 324  * \param filp file pointer.
 
 325  * \param cmd command.
 
 326  * \param arg pointer to a drm_agp_binding structure.
 
 327  * \return zero on success or a negative number on failure.
 
 329  * Verifies the AGP device is present and has been acquired and that no memory
 
 330  * is currently bound into the GATT. Looks-up the AGP memory entry and passes
 
 331  * it to bind_agp() function.
 
 333 int drm_agp_bind(struct inode *inode, struct file *filp,
 
 334                  unsigned int cmd, unsigned long arg)
 
 336         drm_file_t *priv = filp->private_data;
 
 337         drm_device_t *dev = priv->head->dev;
 
 338         drm_agp_binding_t request;
 
 339         drm_agp_mem_t *entry;
 
 343         if (!dev->agp || !dev->agp->acquired)
 
 346             (&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
 
 348         if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
 
 352         page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
 
 353         if ((retcode = drm_bind_agp(entry->memory, page)))
 
 355         entry->bound = dev->agp->base + (page << PAGE_SHIFT);
 
 356         DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
 
 357                   dev->agp->base, entry->bound);
 
 362  * Free AGP memory (ioctl).
 
 364  * \param inode device inode.
 
 365  * \param filp file pointer.
 
 366  * \param cmd command.
 
 367  * \param arg pointer to a drm_agp_buffer structure.
 
 368  * \return zero on success or a negative number on failure.
 
 370  * Verifies the AGP device is present and has been acquired and looks up the
 
 371  * AGP memory entry. If the memory it's currently bound, unbind it via
 
 372  * unbind_agp(). Frees it via free_agp() as well as the entry itself
 
 373  * and unlinks from the doubly linked list it's inserted in.
 
 375 int drm_agp_free(struct inode *inode, struct file *filp,
 
 376                  unsigned int cmd, unsigned long arg)
 
 378         drm_file_t *priv = filp->private_data;
 
 379         drm_device_t *dev = priv->head->dev;
 
 380         drm_agp_buffer_t request;
 
 381         drm_agp_mem_t *entry;
 
 383         if (!dev->agp || !dev->agp->acquired)
 
 386             (&request, (drm_agp_buffer_t __user *) arg, sizeof(request)))
 
 388         if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
 
 391                 drm_unbind_agp(entry->memory);
 
 394                 entry->prev->next = entry->next;
 
 396                 dev->agp->memory = entry->next;
 
 399                 entry->next->prev = entry->prev;
 
 401         drm_free_agp(entry->memory, entry->pages);
 
 402         drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
 
 407  * Initialize the AGP resources.
 
 409  * \return pointer to a drm_agp_head structure.
 
 412 drm_agp_head_t *drm_agp_init(drm_device_t * dev)
 
 414         drm_agp_head_t *head = NULL;
 
 416         if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
 
 418         memset((void *)head, 0, sizeof(*head));
 
 419         head->bridge = agp_find_bridge(dev->pdev);
 
 421                 if (!(head->bridge = agp_backend_acquire(dev->pdev))) {
 
 422                         drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
 
 425                 agp_copy_info(head->bridge, &head->agp_info);
 
 426                 agp_backend_release(head->bridge);
 
 428                 agp_copy_info(head->bridge, &head->agp_info);
 
 430         if (head->agp_info.chipset == NOT_SUPPORTED) {
 
 431                 drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
 
 435         head->cant_use_aperture = head->agp_info.cant_use_aperture;
 
 436         head->page_mask = head->agp_info.page_mask;
 
 441 /** Calls agp_allocate_memory() */
 
 442 DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data * bridge,
 
 443                                      size_t pages, u32 type)
 
 445         return agp_allocate_memory(bridge, pages, type);
 
 448 /** Calls agp_free_memory() */
 
 449 int drm_agp_free_memory(DRM_AGP_MEM * handle)
 
 453         agp_free_memory(handle);
 
 457 /** Calls agp_bind_memory() */
 
 458 int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
 
 462         return agp_bind_memory(handle, start);
 
 465 EXPORT_SYMBOL(drm_agp_bind_memory);
 
 467 /** Calls agp_unbind_memory() */
 
 468 int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
 
 472         return agp_unbind_memory(handle);
 
 475 #endif                          /* __OS_HAS_AGP */