Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCI Backend - Provides restricted access to the real PCI bus topology
0004  *               to the frontend
0005  *
0006  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
0007  */
0008 
0009 #include <linux/list.h>
0010 #include <linux/pci.h>
0011 #include <linux/mutex.h>
0012 #include "pciback.h"
0013 
0014 struct passthrough_dev_data {
0015     /* Access to dev_list must be protected by lock */
0016     struct list_head dev_list;
0017     struct mutex lock;
0018 };
0019 
0020 static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
0021                            unsigned int domain,
0022                            unsigned int bus,
0023                            unsigned int devfn)
0024 {
0025     struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
0026     struct pci_dev_entry *dev_entry;
0027     struct pci_dev *dev = NULL;
0028 
0029     mutex_lock(&dev_data->lock);
0030 
0031     list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
0032         if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
0033             && bus == (unsigned int)dev_entry->dev->bus->number
0034             && devfn == dev_entry->dev->devfn) {
0035             dev = dev_entry->dev;
0036             break;
0037         }
0038     }
0039 
0040     mutex_unlock(&dev_data->lock);
0041 
0042     return dev;
0043 }
0044 
0045 static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
0046                    struct pci_dev *dev,
0047                    int devid, publish_pci_dev_cb publish_cb)
0048 {
0049     struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
0050     struct pci_dev_entry *dev_entry;
0051     unsigned int domain, bus, devfn;
0052     int err;
0053 
0054     dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
0055     if (!dev_entry)
0056         return -ENOMEM;
0057     dev_entry->dev = dev;
0058 
0059     mutex_lock(&dev_data->lock);
0060     list_add_tail(&dev_entry->list, &dev_data->dev_list);
0061     mutex_unlock(&dev_data->lock);
0062 
0063     /* Publish this device. */
0064     domain = (unsigned int)pci_domain_nr(dev->bus);
0065     bus = (unsigned int)dev->bus->number;
0066     devfn = dev->devfn;
0067     err = publish_cb(pdev, domain, bus, devfn, devid);
0068 
0069     return err;
0070 }
0071 
0072 static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
0073                     struct pci_dev *dev, bool lock)
0074 {
0075     struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
0076     struct pci_dev_entry *dev_entry, *t;
0077     struct pci_dev *found_dev = NULL;
0078 
0079     mutex_lock(&dev_data->lock);
0080 
0081     list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
0082         if (dev_entry->dev == dev) {
0083             list_del(&dev_entry->list);
0084             found_dev = dev_entry->dev;
0085             kfree(dev_entry);
0086         }
0087     }
0088 
0089     mutex_unlock(&dev_data->lock);
0090 
0091     if (found_dev) {
0092         if (lock)
0093             device_lock(&found_dev->dev);
0094         pcistub_put_pci_dev(found_dev);
0095         if (lock)
0096             device_unlock(&found_dev->dev);
0097     }
0098 }
0099 
0100 static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
0101 {
0102     struct passthrough_dev_data *dev_data;
0103 
0104     dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
0105     if (!dev_data)
0106         return -ENOMEM;
0107 
0108     mutex_init(&dev_data->lock);
0109 
0110     INIT_LIST_HEAD(&dev_data->dev_list);
0111 
0112     pdev->pci_dev_data = dev_data;
0113 
0114     return 0;
0115 }
0116 
0117 static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
0118                      publish_pci_root_cb publish_root_cb)
0119 {
0120     int err = 0;
0121     struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
0122     struct pci_dev_entry *dev_entry, *e;
0123     struct pci_dev *dev;
0124     int found;
0125     unsigned int domain, bus;
0126 
0127     mutex_lock(&dev_data->lock);
0128 
0129     list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
0130         /* Only publish this device as a root if none of its
0131          * parent bridges are exported
0132          */
0133         found = 0;
0134         dev = dev_entry->dev->bus->self;
0135         for (; !found && dev != NULL; dev = dev->bus->self) {
0136             list_for_each_entry(e, &dev_data->dev_list, list) {
0137                 if (dev == e->dev) {
0138                     found = 1;
0139                     break;
0140                 }
0141             }
0142         }
0143 
0144         domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
0145         bus = (unsigned int)dev_entry->dev->bus->number;
0146 
0147         if (!found) {
0148             err = publish_root_cb(pdev, domain, bus);
0149             if (err)
0150                 break;
0151         }
0152     }
0153 
0154     mutex_unlock(&dev_data->lock);
0155 
0156     return err;
0157 }
0158 
0159 static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
0160 {
0161     struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
0162     struct pci_dev_entry *dev_entry, *t;
0163 
0164     list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
0165         struct pci_dev *dev = dev_entry->dev;
0166         list_del(&dev_entry->list);
0167         device_lock(&dev->dev);
0168         pcistub_put_pci_dev(dev);
0169         device_unlock(&dev->dev);
0170         kfree(dev_entry);
0171     }
0172 
0173     kfree(dev_data);
0174     pdev->pci_dev_data = NULL;
0175 }
0176 
0177 static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
0178                     struct xen_pcibk_device *pdev,
0179                     unsigned int *domain, unsigned int *bus,
0180                     unsigned int *devfn)
0181 {
0182     *domain = pci_domain_nr(pcidev->bus);
0183     *bus = pcidev->bus->number;
0184     *devfn = pcidev->devfn;
0185     return 1;
0186 }
0187 
0188 const struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
0189     .name           = "passthrough",
0190     .init           = __xen_pcibk_init_devices,
0191     .free       = __xen_pcibk_release_devices,
0192     .find           = __xen_pcibk_get_pcifront_dev,
0193     .publish        = __xen_pcibk_publish_pci_roots,
0194     .release        = __xen_pcibk_release_pci_dev,
0195     .add            = __xen_pcibk_add_pci_dev,
0196     .get            = __xen_pcibk_get_pci_dev,
0197 };