Home | History | Annotate | Line # | Download | only in drm
drm_pci.c revision 1.6
      1 /*	$NetBSD: drm_pci.c,v 1.6 2018/08/27 04:58:19 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2003 Jos Fonseca.
      5  * Copyright 2003 Leif Delgass.
      6  * All Rights Reserved.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the next
     16  * paragraph) shall be included in all copies or substantial portions of the
     17  * Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     22  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  */
     26 
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: drm_pci.c,v 1.6 2018/08/27 04:58:19 riastradh Exp $");
     29 
     30 #include <linux/pci.h>
     31 #include <linux/slab.h>
     32 #include <linux/dma-mapping.h>
     33 #include <linux/export.h>
     34 #include <drm/drmP.h>
     35 #include "drm_internal.h"
     36 #include "drm_legacy.h"
     37 
     38 /**
     39  * drm_pci_alloc - Allocate a PCI consistent memory block, for DMA.
     40  * @dev: DRM device
     41  * @size: size of block to allocate
     42  * @align: alignment of block
     43  *
     44  * Return: A handle to the allocated memory block on success or NULL on
     45  * failure.
     46  */
     47 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
     48 {
     49 	drm_dma_handle_t *dmah;
     50 	unsigned long addr;
     51 	size_t sz;
     52 
     53 	/* pci_alloc_consistent only guarantees alignment to the smallest
     54 	 * PAGE_SIZE order which is greater than or equal to the requested size.
     55 	 * Return NULL here for now to make sure nobody tries for larger alignment
     56 	 */
     57 	if (align > size)
     58 		return NULL;
     59 
     60 	dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
     61 	if (!dmah)
     62 		return NULL;
     63 
     64 	dmah->size = size;
     65 	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
     66 
     67 	if (dmah->vaddr == NULL) {
     68 		kfree(dmah);
     69 		return NULL;
     70 	}
     71 
     72 	memset(dmah->vaddr, 0, size);
     73 
     74 	/* XXX - Is virt_to_page() legal for consistent mem? */
     75 	/* Reserve */
     76 	for (addr = (unsigned long)dmah->vaddr, sz = size;
     77 	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
     78 		SetPageReserved(virt_to_page((void *)addr));
     79 	}
     80 
     81 	return dmah;
     82 }
     83 
     84 EXPORT_SYMBOL(drm_pci_alloc);
     85 
     86 /*
     87  * Free a PCI consistent memory block without freeing its descriptor.
     88  *
     89  * This function is for internal use in the Linux-specific DRM core code.
     90  */
     91 void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
     92 {
     93 	unsigned long addr;
     94 	size_t sz;
     95 
     96 	if (dmah->vaddr) {
     97 		/* XXX - Is virt_to_page() legal for consistent mem? */
     98 		/* Unreserve */
     99 		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
    100 		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
    101 			ClearPageReserved(virt_to_page((void *)addr));
    102 		}
    103 		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
    104 				  dmah->busaddr);
    105 	}
    106 }
    107 
    108 /**
    109  * drm_pci_free - Free a PCI consistent memory block
    110  * @dev: DRM device
    111  * @dmah: handle to memory block
    112  */
    113 void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
    114 {
    115 	__drm_legacy_pci_free(dev, dmah);
    116 	kfree(dmah);
    117 }
    118 
    119 EXPORT_SYMBOL(drm_pci_free);
    120 
    121 #ifdef CONFIG_PCI
    122 
    123 static int drm_get_pci_domain(struct drm_device *dev)
    124 {
    125 #ifndef __alpha__
    126 	/* For historical reasons, drm_get_pci_domain() is busticated
    127 	 * on most archs and has to remain so for userspace interface
    128 	 * < 1.4, except on alpha which was right from the beginning
    129 	 */
    130 	if (dev->if_version < 0x10004)
    131 		return 0;
    132 #endif /* __alpha__ */
    133 
    134 	return pci_domain_nr(dev->pdev->bus);
    135 }
    136 
    137 int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
    138 {
    139 	master->unique = kasprintf(GFP_KERNEL, "pci:%04x:%02x:%02x.%d",
    140 					drm_get_pci_domain(dev),
    141 					dev->pdev->bus->number,
    142 					PCI_SLOT(dev->pdev->devfn),
    143 					PCI_FUNC(dev->pdev->devfn));
    144 	if (!master->unique)
    145 		return -ENOMEM;
    146 
    147 	master->unique_len = strlen(master->unique);
    148 	return 0;
    149 }
    150 EXPORT_SYMBOL(drm_pci_set_busid);
    151 
    152 int drm_pci_set_unique(struct drm_device *dev,
    153 		       struct drm_master *master,
    154 		       struct drm_unique *u)
    155 {
    156 	int domain, bus, slot, func, ret;
    157 
    158 	master->unique_len = u->unique_len;
    159 	master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
    160 	if (!master->unique) {
    161 		ret = -ENOMEM;
    162 		goto err;
    163 	}
    164 
    165 	if (copy_from_user(master->unique, u->unique, master->unique_len)) {
    166 		ret = -EFAULT;
    167 		goto err;
    168 	}
    169 
    170 	master->unique[master->unique_len] = '\0';
    171 
    172 	/* Return error if the busid submitted doesn't match the device's actual
    173 	 * busid.
    174 	 */
    175 	ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
    176 	if (ret != 3) {
    177 		ret = -EINVAL;
    178 		goto err;
    179 	}
    180 
    181 	domain = bus >> 8;
    182 	bus &= 0xff;
    183 
    184 	if ((domain != drm_get_pci_domain(dev)) ||
    185 	    (bus != dev->pdev->bus->number) ||
    186 	    (slot != PCI_SLOT(dev->pdev->devfn)) ||
    187 	    (func != PCI_FUNC(dev->pdev->devfn))) {
    188 		ret = -EINVAL;
    189 		goto err;
    190 	}
    191 	return 0;
    192 err:
    193 	return ret;
    194 }
    195 
    196 static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
    197 {
    198 	if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
    199 	    (p->busnum & 0xff) != dev->pdev->bus->number ||
    200 	    p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
    201 		return -EINVAL;
    202 
    203 	p->irq = dev->pdev->irq;
    204 
    205 	DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
    206 		  p->irq);
    207 	return 0;
    208 }
    209 
    210 /**
    211  * drm_irq_by_busid - Get interrupt from bus ID
    212  * @dev: DRM device
    213  * @data: IOCTL parameter pointing to a drm_irq_busid structure
    214  * @file_priv: DRM file private.
    215  *
    216  * Finds the PCI device with the specified bus id and gets its IRQ number.
    217  * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
    218  * to that of the device that this DRM instance attached to.
    219  *
    220  * Return: 0 on success or a negative error code on failure.
    221  */
    222 int drm_irq_by_busid(struct drm_device *dev, void *data,
    223 		     struct drm_file *file_priv)
    224 {
    225 	struct drm_irq_busid *p = data;
    226 
    227 	if (drm_core_check_feature(dev, DRIVER_MODESET))
    228 		return -EINVAL;
    229 
    230 	/* UMS was only ever support on PCI devices. */
    231 	if (WARN_ON(!dev->pdev))
    232 		return -EINVAL;
    233 
    234 	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
    235 		return -EINVAL;
    236 
    237 	return drm_pci_irq_by_busid(dev, p);
    238 }
    239 
    240 static void drm_pci_agp_init(struct drm_device *dev)
    241 {
    242 	if (drm_core_check_feature(dev, DRIVER_USE_AGP)) {
    243 		if (drm_pci_device_is_agp(dev))
    244 			dev->agp = drm_agp_init(dev);
    245 		if (dev->agp) {
    246 			dev->agp->agp_mtrr = arch_phys_wc_add(
    247 				dev->agp->agp_info.aper_base,
    248 				dev->agp->agp_info.aper_size *
    249 				1024 * 1024);
    250 		}
    251 	}
    252 }
    253 
    254 void drm_pci_agp_destroy(struct drm_device *dev)
    255 {
    256 	if (dev->agp) {
    257 		arch_phys_wc_del(dev->agp->agp_mtrr);
    258 		drm_agp_clear(dev);
    259 		kfree(dev->agp);
    260 		dev->agp = NULL;
    261 	}
    262 }
    263 
    264 /**
    265  * drm_get_pci_dev - Register a PCI device with the DRM subsystem
    266  * @pdev: PCI device
    267  * @ent: entry from the PCI ID table that matches @pdev
    268  * @driver: DRM device driver
    269  *
    270  * Attempt to gets inter module "drm" information. If we are first
    271  * then register the character device and inter module information.
    272  * Try and register, if we fail to register, backout previous work.
    273  *
    274  * NOTE: This function is deprecated, please use drm_dev_alloc() and
    275  * drm_dev_register() instead and remove your ->load() callback.
    276  *
    277  * Return: 0 on success or a negative error code on failure.
    278  */
    279 int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
    280 		    struct drm_driver *driver)
    281 {
    282 	struct drm_device *dev;
    283 	int ret;
    284 
    285 	DRM_DEBUG("\n");
    286 
    287 	dev = drm_dev_alloc(driver, &pdev->dev);
    288 	if (!dev)
    289 		return -ENOMEM;
    290 
    291 	ret = pci_enable_device(pdev);
    292 	if (ret)
    293 		goto err_free;
    294 
    295 	dev->pdev = pdev;
    296 #ifdef __alpha__
    297 	dev->hose = pdev->sysdata;
    298 #endif
    299 
    300 	if (drm_core_check_feature(dev, DRIVER_MODESET))
    301 		pci_set_drvdata(pdev, dev);
    302 
    303 	drm_pci_agp_init(dev);
    304 
    305 	ret = drm_dev_register(dev, ent->driver_data);
    306 	if (ret)
    307 		goto err_agp;
    308 
    309 	DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
    310 		 driver->name, driver->major, driver->minor, driver->patchlevel,
    311 		 driver->date, pci_name(pdev), dev->primary->index);
    312 
    313 	/* No locking needed since shadow-attach is single-threaded since it may
    314 	 * only be called from the per-driver module init hook. */
    315 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
    316 		list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);
    317 
    318 	return 0;
    319 
    320 err_agp:
    321 	drm_pci_agp_destroy(dev);
    322 	pci_disable_device(pdev);
    323 err_free:
    324 	drm_dev_unref(dev);
    325 	return ret;
    326 }
    327 EXPORT_SYMBOL(drm_get_pci_dev);
    328 
    329 /**
    330  * drm_pci_init - Register matching PCI devices with the DRM subsystem
    331  * @driver: DRM device driver
    332  * @pdriver: PCI device driver
    333  *
    334  * Initializes a drm_device structures, registering the stubs and initializing
    335  * the AGP device.
    336  *
    337  * NOTE: This function is deprecated. Modern modesetting drm drivers should use
    338  * pci_register_driver() directly, this function only provides shadow-binding
    339  * support for old legacy drivers on top of that core pci function.
    340  *
    341  * Return: 0 on success or a negative error code on failure.
    342  */
    343 int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
    344 {
    345 	struct pci_dev *pdev = NULL;
    346 	const struct pci_device_id *pid;
    347 	int i;
    348 
    349 	DRM_DEBUG("\n");
    350 
    351 	if (driver->driver_features & DRIVER_MODESET)
    352 		return pci_register_driver(pdriver);
    353 
    354 	/* If not using KMS, fall back to stealth mode manual scanning. */
    355 	INIT_LIST_HEAD(&driver->legacy_dev_list);
    356 	for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
    357 		pid = &pdriver->id_table[i];
    358 
    359 		/* Loop around setting up a DRM device for each PCI device
    360 		 * matching our ID and device class.  If we had the internal
    361 		 * function that pci_get_subsys and pci_get_class used, we'd
    362 		 * be able to just pass pid in instead of doing a two-stage
    363 		 * thing.
    364 		 */
    365 		pdev = NULL;
    366 		while ((pdev =
    367 			pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
    368 				       pid->subdevice, pdev)) != NULL) {
    369 			if ((pdev->class & pid->class_mask) != pid->class)
    370 				continue;
    371 
    372 			/* stealth mode requires a manual probe */
    373 			pci_dev_get(pdev);
    374 			drm_get_pci_dev(pdev, pid, driver);
    375 		}
    376 	}
    377 	return 0;
    378 }
    379 
    380 int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
    381 {
    382 	struct pci_dev *root;
    383 	u32 lnkcap, lnkcap2;
    384 
    385 	*mask = 0;
    386 	if (!dev->pdev)
    387 		return -EINVAL;
    388 
    389 	root = dev->pdev->bus->self;
    390 
    391 	/* we've been informed via and serverworks don't make the cut */
    392 	if (root->vendor == PCI_VENDOR_ID_VIA ||
    393 	    root->vendor == PCI_VENDOR_ID_SERVERWORKS)
    394 		return -EINVAL;
    395 
    396 	pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
    397 	pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2);
    398 
    399 	if (lnkcap2) {	/* PCIe r3.0-compliant */
    400 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
    401 			*mask |= DRM_PCIE_SPEED_25;
    402 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
    403 			*mask |= DRM_PCIE_SPEED_50;
    404 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
    405 			*mask |= DRM_PCIE_SPEED_80;
    406 	} else {	/* pre-r3.0 */
    407 		if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
    408 			*mask |= DRM_PCIE_SPEED_25;
    409 		if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
    410 			*mask |= (DRM_PCIE_SPEED_25 | DRM_PCIE_SPEED_50);
    411 	}
    412 
    413 	DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", root->vendor, root->device, lnkcap, lnkcap2);
    414 	return 0;
    415 }
    416 EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
    417 
    418 #else
    419 
    420 int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
    421 {
    422 	return -1;
    423 }
    424 
    425 void drm_pci_agp_destroy(struct drm_device *dev) {}
    426 
    427 int drm_irq_by_busid(struct drm_device *dev, void *data,
    428 		     struct drm_file *file_priv)
    429 {
    430 	return -EINVAL;
    431 }
    432 
    433 int drm_pci_set_unique(struct drm_device *dev,
    434 		       struct drm_master *master,
    435 		       struct drm_unique *u)
    436 {
    437 	return -EINVAL;
    438 }
    439 #endif
    440 
    441 EXPORT_SYMBOL(drm_pci_init);
    442 
    443 /**
    444  * drm_pci_exit - Unregister matching PCI devices from the DRM subsystem
    445  * @driver: DRM device driver
    446  * @pdriver: PCI device driver
    447  *
    448  * Unregisters one or more devices matched by a PCI driver from the DRM
    449  * subsystem.
    450  *
    451  * NOTE: This function is deprecated. Modern modesetting drm drivers should use
    452  * pci_unregister_driver() directly, this function only provides shadow-binding
    453  * support for old legacy drivers on top of that core pci function.
    454  */
    455 void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
    456 {
    457 	struct drm_device *dev, *tmp;
    458 	DRM_DEBUG("\n");
    459 
    460 	if (driver->driver_features & DRIVER_MODESET) {
    461 		pci_unregister_driver(pdriver);
    462 	} else {
    463 		list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
    464 					 legacy_dev_list) {
    465 			list_del(&dev->legacy_dev_list);
    466 			drm_put_dev(dev);
    467 		}
    468 	}
    469 	DRM_INFO("Module unloaded\n");
    470 }
    471 EXPORT_SYMBOL(drm_pci_exit);
    472