cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_pci.c (7315B)


      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_drv.h>
     34#include <drm/drm_print.h>
     35
     36#include "drm_internal.h"
     37#include "drm_legacy.h"
     38
     39#ifdef CONFIG_DRM_LEGACY
     40/* List of devices hanging off drivers with stealth attach. */
     41static LIST_HEAD(legacy_dev_list);
     42static DEFINE_MUTEX(legacy_dev_list_lock);
     43#endif
     44
     45static int drm_get_pci_domain(struct drm_device *dev)
     46{
     47#ifndef __alpha__
     48	/* For historical reasons, drm_get_pci_domain() is busticated
     49	 * on most archs and has to remain so for userspace interface
     50	 * < 1.4, except on alpha which was right from the beginning
     51	 */
     52	if (dev->if_version < 0x10004)
     53		return 0;
     54#endif /* __alpha__ */
     55
     56	return pci_domain_nr(to_pci_dev(dev->dev)->bus);
     57}
     58
     59int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
     60{
     61	struct pci_dev *pdev = to_pci_dev(dev->dev);
     62
     63	master->unique = kasprintf(GFP_KERNEL, "pci:%04x:%02x:%02x.%d",
     64					drm_get_pci_domain(dev),
     65					pdev->bus->number,
     66					PCI_SLOT(pdev->devfn),
     67					PCI_FUNC(pdev->devfn));
     68	if (!master->unique)
     69		return -ENOMEM;
     70
     71	master->unique_len = strlen(master->unique);
     72	return 0;
     73}
     74
     75#ifdef CONFIG_DRM_LEGACY
     76
     77static int drm_legacy_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
     78{
     79	struct pci_dev *pdev = to_pci_dev(dev->dev);
     80
     81	if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
     82	    (p->busnum & 0xff) != pdev->bus->number ||
     83	    p->devnum != PCI_SLOT(pdev->devfn) || p->funcnum != PCI_FUNC(pdev->devfn))
     84		return -EINVAL;
     85
     86	p->irq = pdev->irq;
     87
     88	DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
     89		  p->irq);
     90	return 0;
     91}
     92
     93/**
     94 * drm_legacy_irq_by_busid - Get interrupt from bus ID
     95 * @dev: DRM device
     96 * @data: IOCTL parameter pointing to a drm_irq_busid structure
     97 * @file_priv: DRM file private.
     98 *
     99 * Finds the PCI device with the specified bus id and gets its IRQ number.
    100 * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
    101 * to that of the device that this DRM instance attached to.
    102 *
    103 * Return: 0 on success or a negative error code on failure.
    104 */
    105int drm_legacy_irq_by_busid(struct drm_device *dev, void *data,
    106			    struct drm_file *file_priv)
    107{
    108	struct drm_irq_busid *p = data;
    109
    110	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
    111		return -EOPNOTSUPP;
    112
    113	/* UMS was only ever support on PCI devices. */
    114	if (WARN_ON(!dev_is_pci(dev->dev)))
    115		return -EINVAL;
    116
    117	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
    118		return -EOPNOTSUPP;
    119
    120	return drm_legacy_pci_irq_by_busid(dev, p);
    121}
    122
    123void drm_legacy_pci_agp_destroy(struct drm_device *dev)
    124{
    125	if (dev->agp) {
    126		arch_phys_wc_del(dev->agp->agp_mtrr);
    127		drm_legacy_agp_clear(dev);
    128		kfree(dev->agp);
    129		dev->agp = NULL;
    130	}
    131}
    132
    133static void drm_legacy_pci_agp_init(struct drm_device *dev)
    134{
    135	if (drm_core_check_feature(dev, DRIVER_USE_AGP)) {
    136		if (pci_find_capability(to_pci_dev(dev->dev), PCI_CAP_ID_AGP))
    137			dev->agp = drm_legacy_agp_init(dev);
    138		if (dev->agp) {
    139			dev->agp->agp_mtrr = arch_phys_wc_add(
    140				dev->agp->agp_info.aper_base,
    141				dev->agp->agp_info.aper_size *
    142				1024 * 1024);
    143		}
    144	}
    145}
    146
    147static int drm_legacy_get_pci_dev(struct pci_dev *pdev,
    148				  const struct pci_device_id *ent,
    149				  const struct drm_driver *driver)
    150{
    151	struct drm_device *dev;
    152	int ret;
    153
    154	DRM_DEBUG("\n");
    155
    156	dev = drm_dev_alloc(driver, &pdev->dev);
    157	if (IS_ERR(dev))
    158		return PTR_ERR(dev);
    159
    160	ret = pci_enable_device(pdev);
    161	if (ret)
    162		goto err_free;
    163
    164#ifdef __alpha__
    165	dev->hose = pdev->sysdata;
    166#endif
    167
    168	drm_legacy_pci_agp_init(dev);
    169
    170	ret = drm_dev_register(dev, ent->driver_data);
    171	if (ret)
    172		goto err_agp;
    173
    174	if (drm_core_check_feature(dev, DRIVER_LEGACY)) {
    175		mutex_lock(&legacy_dev_list_lock);
    176		list_add_tail(&dev->legacy_dev_list, &legacy_dev_list);
    177		mutex_unlock(&legacy_dev_list_lock);
    178	}
    179
    180	return 0;
    181
    182err_agp:
    183	drm_legacy_pci_agp_destroy(dev);
    184	pci_disable_device(pdev);
    185err_free:
    186	drm_dev_put(dev);
    187	return ret;
    188}
    189
    190/**
    191 * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver
    192 * @driver: DRM device driver
    193 * @pdriver: PCI device driver
    194 *
    195 * This is only used by legacy dri1 drivers and deprecated.
    196 *
    197 * Return: 0 on success or a negative error code on failure.
    198 */
    199int drm_legacy_pci_init(const struct drm_driver *driver,
    200			struct pci_driver *pdriver)
    201{
    202	struct pci_dev *pdev = NULL;
    203	const struct pci_device_id *pid;
    204	int i;
    205
    206	DRM_DEBUG("\n");
    207
    208	if (WARN_ON(!(driver->driver_features & DRIVER_LEGACY)))
    209		return -EINVAL;
    210
    211	/* If not using KMS, fall back to stealth mode manual scanning. */
    212	for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
    213		pid = &pdriver->id_table[i];
    214
    215		/* Loop around setting up a DRM device for each PCI device
    216		 * matching our ID and device class.  If we had the internal
    217		 * function that pci_get_subsys and pci_get_class used, we'd
    218		 * be able to just pass pid in instead of doing a two-stage
    219		 * thing.
    220		 */
    221		pdev = NULL;
    222		while ((pdev =
    223			pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
    224				       pid->subdevice, pdev)) != NULL) {
    225			if ((pdev->class & pid->class_mask) != pid->class)
    226				continue;
    227
    228			/* stealth mode requires a manual probe */
    229			pci_dev_get(pdev);
    230			drm_legacy_get_pci_dev(pdev, pid, driver);
    231		}
    232	}
    233	return 0;
    234}
    235EXPORT_SYMBOL(drm_legacy_pci_init);
    236
    237/**
    238 * drm_legacy_pci_exit - unregister shadow-attach legacy DRM driver
    239 * @driver: DRM device driver
    240 * @pdriver: PCI device driver
    241 *
    242 * Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This
    243 * is deprecated and only used by dri1 drivers.
    244 */
    245void drm_legacy_pci_exit(const struct drm_driver *driver,
    246			 struct pci_driver *pdriver)
    247{
    248	struct drm_device *dev, *tmp;
    249
    250	DRM_DEBUG("\n");
    251
    252	if (!(driver->driver_features & DRIVER_LEGACY)) {
    253		WARN_ON(1);
    254	} else {
    255		mutex_lock(&legacy_dev_list_lock);
    256		list_for_each_entry_safe(dev, tmp, &legacy_dev_list,
    257					 legacy_dev_list) {
    258			if (dev->driver == driver) {
    259				list_del(&dev->legacy_dev_list);
    260				drm_put_dev(dev);
    261			}
    262		}
    263		mutex_unlock(&legacy_dev_list_lock);
    264	}
    265	DRM_INFO("Module unloaded\n");
    266}
    267EXPORT_SYMBOL(drm_legacy_pci_exit);
    268
    269#endif