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