1 /* 2 * Copyright 2003 José Fonseca. 3 * Copyright 2003 Leif Delgass. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <linux/dma-mapping.h> 26 #include <linux/export.h> 27 #include <linux/list.h> 28 #include <linux/mutex.h> 29 #include <linux/pci.h> 30 #include <linux/slab.h> 31 32 #include <drm/drm.h> 33 #include <drm/drm_agpsupport.h> 34 #include <drm/drm_drv.h> 35 #include <drm/drm_print.h> 36 37 #include "drm_internal.h" 38 #include "drm_legacy.h" 39 40 #ifdef CONFIG_DRM_LEGACY 41 /* List of devices hanging off drivers with stealth attach. */ 42 static LIST_HEAD(legacy_dev_list); 43 static DEFINE_MUTEX(legacy_dev_list_lock); 44 45 /** 46 * drm_pci_alloc - Allocate a PCI consistent memory block, for DMA. 47 * @dev: DRM device 48 * @size: size of block to allocate 49 * @align: alignment of block 50 * 51 * FIXME: This is a needless abstraction of the Linux dma-api and should be 52 * removed. 53 * 54 * Return: A handle to the allocated memory block on success or NULL on 55 * failure. 56 */ 57 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) 58 { 59 drm_dma_handle_t *dmah; 60 61 /* pci_alloc_consistent only guarantees alignment to the smallest 62 * PAGE_SIZE order which is greater than or equal to the requested size. 63 * Return NULL here for now to make sure nobody tries for larger alignment 64 */ 65 if (align > size) 66 return NULL; 67 68 dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); 69 if (!dmah) 70 return NULL; 71 72 dmah->size = size; 73 dmah->vaddr = dma_alloc_coherent(dev->dev, size, 74 &dmah->busaddr, 75 GFP_KERNEL); 76 77 if (dmah->vaddr == NULL) { 78 kfree(dmah); 79 return NULL; 80 } 81 82 return dmah; 83 } 84 EXPORT_SYMBOL(drm_pci_alloc); 85 86 /** 87 * drm_pci_free - Free a PCI consistent memory block 88 * @dev: DRM device 89 * @dmah: handle to memory block 90 * 91 * FIXME: This is a needless abstraction of the Linux dma-api and should be 92 * removed. 93 */ 94 void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) 95 { 96 dma_free_coherent(dev->dev, dmah->size, dmah->vaddr, 97 dmah->busaddr); 98 kfree(dmah); 99 } 100 101 EXPORT_SYMBOL(drm_pci_free); 102 #endif 103 104 static int drm_get_pci_domain(struct drm_device *dev) 105 { 106 #ifndef __alpha__ 107 /* For historical reasons, drm_get_pci_domain() is busticated 108 * on most archs and has to remain so for userspace interface 109 * < 1.4, except on alpha which was right from the beginning 110 */ 111 if (dev->if_version < 0x10004) 112 return 0; 113 #endif /* __alpha__ */ 114 115 return pci_domain_nr(to_pci_dev(dev->dev)->bus); 116 } 117 118 int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) 119 { 120 struct pci_dev *pdev = to_pci_dev(dev->dev); 121 122 master->unique = kasprintf(GFP_KERNEL, "pci:%04x:%02x:%02x.%d", 123 drm_get_pci_domain(dev), 124 pdev->bus->number, 125 PCI_SLOT(pdev->devfn), 126 PCI_FUNC(pdev->devfn)); 127 if (!master->unique) 128 return -ENOMEM; 129 130 master->unique_len = strlen(master->unique); 131 return 0; 132 } 133 134 static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) 135 { 136 struct pci_dev *pdev = to_pci_dev(dev->dev); 137 138 if ((p->busnum >> 8) != drm_get_pci_domain(dev) || 139 (p->busnum & 0xff) != pdev->bus->number || 140 p->devnum != PCI_SLOT(pdev->devfn) || p->funcnum != PCI_FUNC(pdev->devfn)) 141 return -EINVAL; 142 143 p->irq = pdev->irq; 144 145 DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, 146 p->irq); 147 return 0; 148 } 149 150 /** 151 * drm_legacy_irq_by_busid - Get interrupt from bus ID 152 * @dev: DRM device 153 * @data: IOCTL parameter pointing to a drm_irq_busid structure 154 * @file_priv: DRM file private. 155 * 156 * Finds the PCI device with the specified bus id and gets its IRQ number. 157 * This IOCTL is deprecated, and will now return EINVAL for any busid not equal 158 * to that of the device that this DRM instance attached to. 159 * 160 * Return: 0 on success or a negative error code on failure. 161 */ 162 int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, 163 struct drm_file *file_priv) 164 { 165 struct drm_irq_busid *p = data; 166 167 if (!drm_core_check_feature(dev, DRIVER_LEGACY)) 168 return -EOPNOTSUPP; 169 170 /* UMS was only ever support on PCI devices. */ 171 if (WARN_ON(!dev_is_pci(dev->dev))) 172 return -EINVAL; 173 174 if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 175 return -EOPNOTSUPP; 176 177 return drm_pci_irq_by_busid(dev, p); 178 } 179 180 void drm_pci_agp_destroy(struct drm_device *dev) 181 { 182 if (dev->agp) { 183 arch_phys_wc_del(dev->agp->agp_mtrr); 184 drm_legacy_agp_clear(dev); 185 kfree(dev->agp); 186 dev->agp = NULL; 187 } 188 } 189 190 #ifdef CONFIG_DRM_LEGACY 191 192 static void drm_pci_agp_init(struct drm_device *dev) 193 { 194 if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { 195 if (pci_find_capability(to_pci_dev(dev->dev), PCI_CAP_ID_AGP)) 196 dev->agp = drm_agp_init(dev); 197 if (dev->agp) { 198 dev->agp->agp_mtrr = arch_phys_wc_add( 199 dev->agp->agp_info.aper_base, 200 dev->agp->agp_info.aper_size * 201 1024 * 1024); 202 } 203 } 204 } 205 206 static int drm_get_pci_dev(struct pci_dev *pdev, 207 const struct pci_device_id *ent, 208 const struct drm_driver *driver) 209 { 210 struct drm_device *dev; 211 int ret; 212 213 DRM_DEBUG("\n"); 214 215 dev = drm_dev_alloc(driver, &pdev->dev); 216 if (IS_ERR(dev)) 217 return PTR_ERR(dev); 218 219 ret = pci_enable_device(pdev); 220 if (ret) 221 goto err_free; 222 223 dev->pdev = pdev; 224 #ifdef __alpha__ 225 dev->hose = pdev->sysdata; 226 #endif 227 228 if (drm_core_check_feature(dev, DRIVER_MODESET)) 229 pci_set_drvdata(pdev, dev); 230 231 drm_pci_agp_init(dev); 232 233 ret = drm_dev_register(dev, ent->driver_data); 234 if (ret) 235 goto err_agp; 236 237 if (drm_core_check_feature(dev, DRIVER_LEGACY)) { 238 mutex_lock(&legacy_dev_list_lock); 239 list_add_tail(&dev->legacy_dev_list, &legacy_dev_list); 240 mutex_unlock(&legacy_dev_list_lock); 241 } 242 243 return 0; 244 245 err_agp: 246 drm_pci_agp_destroy(dev); 247 pci_disable_device(pdev); 248 err_free: 249 drm_dev_put(dev); 250 return ret; 251 } 252 253 /** 254 * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver 255 * @driver: DRM device driver 256 * @pdriver: PCI device driver 257 * 258 * This is only used by legacy dri1 drivers and deprecated. 259 * 260 * Return: 0 on success or a negative error code on failure. 261 */ 262 int drm_legacy_pci_init(const struct drm_driver *driver, 263 struct pci_driver *pdriver) 264 { 265 struct pci_dev *pdev = NULL; 266 const struct pci_device_id *pid; 267 int i; 268 269 DRM_DEBUG("\n"); 270 271 if (WARN_ON(!(driver->driver_features & DRIVER_LEGACY))) 272 return -EINVAL; 273 274 /* If not using KMS, fall back to stealth mode manual scanning. */ 275 for (i = 0; pdriver->id_table[i].vendor != 0; i++) { 276 pid = &pdriver->id_table[i]; 277 278 /* Loop around setting up a DRM device for each PCI device 279 * matching our ID and device class. If we had the internal 280 * function that pci_get_subsys and pci_get_class used, we'd 281 * be able to just pass pid in instead of doing a two-stage 282 * thing. 283 */ 284 pdev = NULL; 285 while ((pdev = 286 pci_get_subsys(pid->vendor, pid->device, pid->subvendor, 287 pid->subdevice, pdev)) != NULL) { 288 if ((pdev->class & pid->class_mask) != pid->class) 289 continue; 290 291 /* stealth mode requires a manual probe */ 292 pci_dev_get(pdev); 293 drm_get_pci_dev(pdev, pid, driver); 294 } 295 } 296 return 0; 297 } 298 EXPORT_SYMBOL(drm_legacy_pci_init); 299 300 /** 301 * drm_legacy_pci_exit - unregister shadow-attach legacy DRM driver 302 * @driver: DRM device driver 303 * @pdriver: PCI device driver 304 * 305 * Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This 306 * is deprecated and only used by dri1 drivers. 307 */ 308 void drm_legacy_pci_exit(const struct drm_driver *driver, 309 struct pci_driver *pdriver) 310 { 311 struct drm_device *dev, *tmp; 312 313 DRM_DEBUG("\n"); 314 315 if (!(driver->driver_features & DRIVER_LEGACY)) { 316 WARN_ON(1); 317 } else { 318 mutex_lock(&legacy_dev_list_lock); 319 list_for_each_entry_safe(dev, tmp, &legacy_dev_list, 320 legacy_dev_list) { 321 if (dev->driver == driver) { 322 list_del(&dev->legacy_dev_list); 323 drm_put_dev(dev); 324 } 325 } 326 mutex_unlock(&legacy_dev_list_lock); 327 } 328 DRM_INFO("Module unloaded\n"); 329 } 330 EXPORT_SYMBOL(drm_legacy_pci_exit); 331 332 #endif 333