linux/drivers/xen/xen-pciback/passthrough.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCI Backend - Provides restricted access to the real PCI bus topology
   4 *               to the frontend
   5 *
   6 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
   7 */
   8
   9#include <linux/list.h>
  10#include <linux/pci.h>
  11#include <linux/mutex.h>
  12#include "pciback.h"
  13
  14struct passthrough_dev_data {
  15        /* Access to dev_list must be protected by lock */
  16        struct list_head dev_list;
  17        struct mutex lock;
  18};
  19
  20static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
  21                                               unsigned int domain,
  22                                               unsigned int bus,
  23                                               unsigned int devfn)
  24{
  25        struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
  26        struct pci_dev_entry *dev_entry;
  27        struct pci_dev *dev = NULL;
  28
  29        mutex_lock(&dev_data->lock);
  30
  31        list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
  32                if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
  33                    && bus == (unsigned int)dev_entry->dev->bus->number
  34                    && devfn == dev_entry->dev->devfn) {
  35                        dev = dev_entry->dev;
  36                        break;
  37                }
  38        }
  39
  40        mutex_unlock(&dev_data->lock);
  41
  42        return dev;
  43}
  44
  45static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
  46                                   struct pci_dev *dev,
  47                                   int devid, publish_pci_dev_cb publish_cb)
  48{
  49        struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
  50        struct pci_dev_entry *dev_entry;
  51        unsigned int domain, bus, devfn;
  52        int err;
  53
  54        dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
  55        if (!dev_entry)
  56                return -ENOMEM;
  57        dev_entry->dev = dev;
  58
  59        mutex_lock(&dev_data->lock);
  60        list_add_tail(&dev_entry->list, &dev_data->dev_list);
  61        mutex_unlock(&dev_data->lock);
  62
  63        /* Publish this device. */
  64        domain = (unsigned int)pci_domain_nr(dev->bus);
  65        bus = (unsigned int)dev->bus->number;
  66        devfn = dev->devfn;
  67        err = publish_cb(pdev, domain, bus, devfn, devid);
  68
  69        return err;
  70}
  71
  72static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
  73                                        struct pci_dev *dev, bool lock)
  74{
  75        struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
  76        struct pci_dev_entry *dev_entry, *t;
  77        struct pci_dev *found_dev = NULL;
  78
  79        mutex_lock(&dev_data->lock);
  80
  81        list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
  82                if (dev_entry->dev == dev) {
  83                        list_del(&dev_entry->list);
  84                        found_dev = dev_entry->dev;
  85                        kfree(dev_entry);
  86                }
  87        }
  88
  89        mutex_unlock(&dev_data->lock);
  90
  91        if (found_dev) {
  92                if (lock)
  93                        device_lock(&found_dev->dev);
  94                pcistub_put_pci_dev(found_dev);
  95                if (lock)
  96                        device_unlock(&found_dev->dev);
  97        }
  98}
  99
 100static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
 101{
 102        struct passthrough_dev_data *dev_data;
 103
 104        dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
 105        if (!dev_data)
 106                return -ENOMEM;
 107
 108        mutex_init(&dev_data->lock);
 109
 110        INIT_LIST_HEAD(&dev_data->dev_list);
 111
 112        pdev->pci_dev_data = dev_data;
 113
 114        return 0;
 115}
 116
 117static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
 118                                         publish_pci_root_cb publish_root_cb)
 119{
 120        int err = 0;
 121        struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 122        struct pci_dev_entry *dev_entry, *e;
 123        struct pci_dev *dev;
 124        int found;
 125        unsigned int domain, bus;
 126
 127        mutex_lock(&dev_data->lock);
 128
 129        list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
 130                /* Only publish this device as a root if none of its
 131                 * parent bridges are exported
 132                 */
 133                found = 0;
 134                dev = dev_entry->dev->bus->self;
 135                for (; !found && dev != NULL; dev = dev->bus->self) {
 136                        list_for_each_entry(e, &dev_data->dev_list, list) {
 137                                if (dev == e->dev) {
 138                                        found = 1;
 139                                        break;
 140                                }
 141                        }
 142                }
 143
 144                domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
 145                bus = (unsigned int)dev_entry->dev->bus->number;
 146
 147                if (!found) {
 148                        err = publish_root_cb(pdev, domain, bus);
 149                        if (err)
 150                                break;
 151                }
 152        }
 153
 154        mutex_unlock(&dev_data->lock);
 155
 156        return err;
 157}
 158
 159static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
 160{
 161        struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
 162        struct pci_dev_entry *dev_entry, *t;
 163
 164        list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
 165                struct pci_dev *dev = dev_entry->dev;
 166                list_del(&dev_entry->list);
 167                device_lock(&dev->dev);
 168                pcistub_put_pci_dev(dev);
 169                device_unlock(&dev->dev);
 170                kfree(dev_entry);
 171        }
 172
 173        kfree(dev_data);
 174        pdev->pci_dev_data = NULL;
 175}
 176
 177static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
 178                                        struct xen_pcibk_device *pdev,
 179                                        unsigned int *domain, unsigned int *bus,
 180                                        unsigned int *devfn)
 181{
 182        *domain = pci_domain_nr(pcidev->bus);
 183        *bus = pcidev->bus->number;
 184        *devfn = pcidev->devfn;
 185        return 1;
 186}
 187
 188const struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
 189        .name           = "passthrough",
 190        .init           = __xen_pcibk_init_devices,
 191        .free           = __xen_pcibk_release_devices,
 192        .find           = __xen_pcibk_get_pcifront_dev,
 193        .publish        = __xen_pcibk_publish_pci_roots,
 194        .release        = __xen_pcibk_release_pci_dev,
 195        .add            = __xen_pcibk_add_pci_dev,
 196        .get            = __xen_pcibk_get_pci_dev,
 197};
 198