Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * \file drm_agpsupport.c
0003  * DRM support for AGP/GART backend
0004  *
0005  * \author Rickard E. (Rik) Faith <faith@valinux.com>
0006  * \author Gareth Hughes <gareth@valinux.com>
0007  */
0008 
0009 /*
0010  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
0011  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
0012  * All Rights Reserved.
0013  *
0014  * Permission is hereby granted, free of charge, to any person obtaining a
0015  * copy of this software and associated documentation files (the "Software"),
0016  * to deal in the Software without restriction, including without limitation
0017  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0018  * and/or sell copies of the Software, and to permit persons to whom the
0019  * Software is furnished to do so, subject to the following conditions:
0020  *
0021  * The above copyright notice and this permission notice (including the next
0022  * paragraph) shall be included in all copies or substantial portions of the
0023  * Software.
0024  *
0025  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0026  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0027  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0028  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0029  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0030  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0031  * OTHER DEALINGS IN THE SOFTWARE.
0032  */
0033 
0034 #include <linux/module.h>
0035 #include <linux/pci.h>
0036 #include <linux/slab.h>
0037 
0038 #if IS_ENABLED(CONFIG_AGP)
0039 #include <asm/agp.h>
0040 #endif
0041 
0042 #include <drm/drm_device.h>
0043 #include <drm/drm_drv.h>
0044 #include <drm/drm_file.h>
0045 #include <drm/drm_print.h>
0046 
0047 #include "drm_legacy.h"
0048 
0049 #if IS_ENABLED(CONFIG_AGP)
0050 
0051 /*
0052  * Get AGP information.
0053  *
0054  * \return zero on success or a negative number on failure.
0055  *
0056  * Verifies the AGP device has been initialized and acquired and fills in the
0057  * drm_agp_info structure with the information in drm_agp_head::agp_info.
0058  */
0059 int drm_legacy_agp_info(struct drm_device *dev, struct drm_agp_info *info)
0060 {
0061     struct agp_kern_info *kern;
0062 
0063     if (!dev->agp || !dev->agp->acquired)
0064         return -EINVAL;
0065 
0066     kern = &dev->agp->agp_info;
0067     info->agp_version_major = kern->version.major;
0068     info->agp_version_minor = kern->version.minor;
0069     info->mode = kern->mode;
0070     info->aperture_base = kern->aper_base;
0071     info->aperture_size = kern->aper_size * 1024 * 1024;
0072     info->memory_allowed = kern->max_memory << PAGE_SHIFT;
0073     info->memory_used = kern->current_memory << PAGE_SHIFT;
0074     info->id_vendor = kern->device->vendor;
0075     info->id_device = kern->device->device;
0076 
0077     return 0;
0078 }
0079 EXPORT_SYMBOL(drm_legacy_agp_info);
0080 
0081 int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data,
0082                   struct drm_file *file_priv)
0083 {
0084     struct drm_agp_info *info = data;
0085     int err;
0086 
0087     err = drm_legacy_agp_info(dev, info);
0088     if (err)
0089         return err;
0090 
0091     return 0;
0092 }
0093 
0094 /*
0095  * Acquire the AGP device.
0096  *
0097  * \param dev DRM device that is to acquire AGP.
0098  * \return zero on success or a negative number on failure.
0099  *
0100  * Verifies the AGP device hasn't been acquired before and calls
0101  * \c agp_backend_acquire.
0102  */
0103 int drm_legacy_agp_acquire(struct drm_device *dev)
0104 {
0105     struct pci_dev *pdev = to_pci_dev(dev->dev);
0106 
0107     if (!dev->agp)
0108         return -ENODEV;
0109     if (dev->agp->acquired)
0110         return -EBUSY;
0111     dev->agp->bridge = agp_backend_acquire(pdev);
0112     if (!dev->agp->bridge)
0113         return -ENODEV;
0114     dev->agp->acquired = 1;
0115     return 0;
0116 }
0117 EXPORT_SYMBOL(drm_legacy_agp_acquire);
0118 
0119 /*
0120  * Acquire the AGP device (ioctl).
0121  *
0122  * \return zero on success or a negative number on failure.
0123  *
0124  * Verifies the AGP device hasn't been acquired before and calls
0125  * \c agp_backend_acquire.
0126  */
0127 int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data,
0128                  struct drm_file *file_priv)
0129 {
0130     return drm_legacy_agp_acquire((struct drm_device *)file_priv->minor->dev);
0131 }
0132 
0133 /*
0134  * Release the AGP device.
0135  *
0136  * \param dev DRM device that is to release AGP.
0137  * \return zero on success or a negative number on failure.
0138  *
0139  * Verifies the AGP device has been acquired and calls \c agp_backend_release.
0140  */
0141 int drm_legacy_agp_release(struct drm_device *dev)
0142 {
0143     if (!dev->agp || !dev->agp->acquired)
0144         return -EINVAL;
0145     agp_backend_release(dev->agp->bridge);
0146     dev->agp->acquired = 0;
0147     return 0;
0148 }
0149 EXPORT_SYMBOL(drm_legacy_agp_release);
0150 
0151 int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data,
0152                  struct drm_file *file_priv)
0153 {
0154     return drm_legacy_agp_release(dev);
0155 }
0156 
0157 /*
0158  * Enable the AGP bus.
0159  *
0160  * \param dev DRM device that has previously acquired AGP.
0161  * \param mode Requested AGP mode.
0162  * \return zero on success or a negative number on failure.
0163  *
0164  * Verifies the AGP device has been acquired but not enabled, and calls
0165  * \c agp_enable.
0166  */
0167 int drm_legacy_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
0168 {
0169     if (!dev->agp || !dev->agp->acquired)
0170         return -EINVAL;
0171 
0172     dev->agp->mode = mode.mode;
0173     agp_enable(dev->agp->bridge, mode.mode);
0174     dev->agp->enabled = 1;
0175     return 0;
0176 }
0177 EXPORT_SYMBOL(drm_legacy_agp_enable);
0178 
0179 int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data,
0180                 struct drm_file *file_priv)
0181 {
0182     struct drm_agp_mode *mode = data;
0183 
0184     return drm_legacy_agp_enable(dev, *mode);
0185 }
0186 
0187 /*
0188  * Allocate AGP memory.
0189  *
0190  * \return zero on success or a negative number on failure.
0191  *
0192  * Verifies the AGP device is present and has been acquired, allocates the
0193  * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
0194  */
0195 int drm_legacy_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
0196 {
0197     struct drm_agp_mem *entry;
0198     struct agp_memory *memory;
0199     unsigned long pages;
0200     u32 type;
0201 
0202     if (!dev->agp || !dev->agp->acquired)
0203         return -EINVAL;
0204     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0205     if (!entry)
0206         return -ENOMEM;
0207 
0208     pages = DIV_ROUND_UP(request->size, PAGE_SIZE);
0209     type = (u32) request->type;
0210     memory = agp_allocate_memory(dev->agp->bridge, pages, type);
0211     if (!memory) {
0212         kfree(entry);
0213         return -ENOMEM;
0214     }
0215 
0216     entry->handle = (unsigned long)memory->key + 1;
0217     entry->memory = memory;
0218     entry->bound = 0;
0219     entry->pages = pages;
0220     list_add(&entry->head, &dev->agp->memory);
0221 
0222     request->handle = entry->handle;
0223     request->physical = memory->physical;
0224 
0225     return 0;
0226 }
0227 EXPORT_SYMBOL(drm_legacy_agp_alloc);
0228 
0229 
0230 int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data,
0231             struct drm_file *file_priv)
0232 {
0233     struct drm_agp_buffer *request = data;
0234 
0235     return drm_legacy_agp_alloc(dev, request);
0236 }
0237 
0238 /*
0239  * Search for the AGP memory entry associated with a handle.
0240  *
0241  * \param dev DRM device structure.
0242  * \param handle AGP memory handle.
0243  * \return pointer to the drm_agp_mem structure associated with \p handle.
0244  *
0245  * Walks through drm_agp_head::memory until finding a matching handle.
0246  */
0247 static struct drm_agp_mem *drm_legacy_agp_lookup_entry(struct drm_device *dev,
0248                                unsigned long handle)
0249 {
0250     struct drm_agp_mem *entry;
0251 
0252     list_for_each_entry(entry, &dev->agp->memory, head) {
0253         if (entry->handle == handle)
0254             return entry;
0255     }
0256     return NULL;
0257 }
0258 
0259 /*
0260  * Unbind AGP memory from the GATT (ioctl).
0261  *
0262  * \return zero on success or a negative number on failure.
0263  *
0264  * Verifies the AGP device is present and acquired, looks-up the AGP memory
0265  * entry and passes it to the unbind_agp() function.
0266  */
0267 int drm_legacy_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
0268 {
0269     struct drm_agp_mem *entry;
0270     int ret;
0271 
0272     if (!dev->agp || !dev->agp->acquired)
0273         return -EINVAL;
0274     entry = drm_legacy_agp_lookup_entry(dev, request->handle);
0275     if (!entry || !entry->bound)
0276         return -EINVAL;
0277     ret = agp_unbind_memory(entry->memory);
0278     if (ret == 0)
0279         entry->bound = 0;
0280     return ret;
0281 }
0282 EXPORT_SYMBOL(drm_legacy_agp_unbind);
0283 
0284 
0285 int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data,
0286                 struct drm_file *file_priv)
0287 {
0288     struct drm_agp_binding *request = data;
0289 
0290     return drm_legacy_agp_unbind(dev, request);
0291 }
0292 
0293 /*
0294  * Bind AGP memory into the GATT (ioctl)
0295  *
0296  * \return zero on success or a negative number on failure.
0297  *
0298  * Verifies the AGP device is present and has been acquired and that no memory
0299  * is currently bound into the GATT. Looks-up the AGP memory entry and passes
0300  * it to bind_agp() function.
0301  */
0302 int drm_legacy_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
0303 {
0304     struct drm_agp_mem *entry;
0305     int retcode;
0306     int page;
0307 
0308     if (!dev->agp || !dev->agp->acquired)
0309         return -EINVAL;
0310     entry = drm_legacy_agp_lookup_entry(dev, request->handle);
0311     if (!entry || entry->bound)
0312         return -EINVAL;
0313     page = DIV_ROUND_UP(request->offset, PAGE_SIZE);
0314     retcode = agp_bind_memory(entry->memory, page);
0315     if (retcode)
0316         return retcode;
0317     entry->bound = dev->agp->base + (page << PAGE_SHIFT);
0318     DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
0319           dev->agp->base, entry->bound);
0320     return 0;
0321 }
0322 EXPORT_SYMBOL(drm_legacy_agp_bind);
0323 
0324 
0325 int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data,
0326                   struct drm_file *file_priv)
0327 {
0328     struct drm_agp_binding *request = data;
0329 
0330     return drm_legacy_agp_bind(dev, request);
0331 }
0332 
0333 /*
0334  * Free AGP memory (ioctl).
0335  *
0336  * \return zero on success or a negative number on failure.
0337  *
0338  * Verifies the AGP device is present and has been acquired and looks up the
0339  * AGP memory entry. If the memory is currently bound, unbind it via
0340  * unbind_agp(). Frees it via free_agp() as well as the entry itself
0341  * and unlinks from the doubly linked list it's inserted in.
0342  */
0343 int drm_legacy_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
0344 {
0345     struct drm_agp_mem *entry;
0346 
0347     if (!dev->agp || !dev->agp->acquired)
0348         return -EINVAL;
0349     entry = drm_legacy_agp_lookup_entry(dev, request->handle);
0350     if (!entry)
0351         return -EINVAL;
0352     if (entry->bound)
0353         agp_unbind_memory(entry->memory);
0354 
0355     list_del(&entry->head);
0356 
0357     agp_free_memory(entry->memory);
0358     kfree(entry);
0359     return 0;
0360 }
0361 EXPORT_SYMBOL(drm_legacy_agp_free);
0362 
0363 
0364 int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data,
0365                   struct drm_file *file_priv)
0366 {
0367     struct drm_agp_buffer *request = data;
0368 
0369     return drm_legacy_agp_free(dev, request);
0370 }
0371 
0372 /*
0373  * Initialize the AGP resources.
0374  *
0375  * \return pointer to a drm_agp_head structure.
0376  *
0377  * Gets the drm_agp_t structure which is made available by the agpgart module
0378  * via the inter_module_* functions. Creates and initializes a drm_agp_head
0379  * structure.
0380  *
0381  * Note that final cleanup of the kmalloced structure is directly done in
0382  * drm_pci_agp_destroy.
0383  */
0384 struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev)
0385 {
0386     struct pci_dev *pdev = to_pci_dev(dev->dev);
0387     struct drm_agp_head *head = NULL;
0388 
0389     head = kzalloc(sizeof(*head), GFP_KERNEL);
0390     if (!head)
0391         return NULL;
0392     head->bridge = agp_find_bridge(pdev);
0393     if (!head->bridge) {
0394         head->bridge = agp_backend_acquire(pdev);
0395         if (!head->bridge) {
0396             kfree(head);
0397             return NULL;
0398         }
0399         agp_copy_info(head->bridge, &head->agp_info);
0400         agp_backend_release(head->bridge);
0401     } else {
0402         agp_copy_info(head->bridge, &head->agp_info);
0403     }
0404     if (head->agp_info.chipset == NOT_SUPPORTED) {
0405         kfree(head);
0406         return NULL;
0407     }
0408     INIT_LIST_HEAD(&head->memory);
0409     head->cant_use_aperture = head->agp_info.cant_use_aperture;
0410     head->page_mask = head->agp_info.page_mask;
0411     head->base = head->agp_info.aper_base;
0412     return head;
0413 }
0414 /* Only exported for i810.ko */
0415 EXPORT_SYMBOL(drm_legacy_agp_init);
0416 
0417 /**
0418  * drm_legacy_agp_clear - Clear AGP resource list
0419  * @dev: DRM device
0420  *
0421  * Iterate over all AGP resources and remove them. But keep the AGP head
0422  * intact so it can still be used. It is safe to call this if AGP is disabled or
0423  * was already removed.
0424  *
0425  * Cleanup is only done for drivers who have DRIVER_LEGACY set.
0426  */
0427 void drm_legacy_agp_clear(struct drm_device *dev)
0428 {
0429     struct drm_agp_mem *entry, *tempe;
0430 
0431     if (!dev->agp)
0432         return;
0433     if (!drm_core_check_feature(dev, DRIVER_LEGACY))
0434         return;
0435 
0436     list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
0437         if (entry->bound)
0438             agp_unbind_memory(entry->memory);
0439         agp_free_memory(entry->memory);
0440         kfree(entry);
0441     }
0442     INIT_LIST_HEAD(&dev->agp->memory);
0443 
0444     if (dev->agp->acquired)
0445         drm_legacy_agp_release(dev);
0446 
0447     dev->agp->acquired = 0;
0448     dev->agp->enabled = 0;
0449 }
0450 
0451 #endif