162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCI Backend - Provides restricted access to the real PCI bus topology 462306a36Sopenharmony_ci * to the frontend 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/list.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/mutex.h> 1262306a36Sopenharmony_ci#include "pciback.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistruct passthrough_dev_data { 1562306a36Sopenharmony_ci /* Access to dev_list must be protected by lock */ 1662306a36Sopenharmony_ci struct list_head dev_list; 1762306a36Sopenharmony_ci struct mutex lock; 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, 2162306a36Sopenharmony_ci unsigned int domain, 2262306a36Sopenharmony_ci unsigned int bus, 2362306a36Sopenharmony_ci unsigned int devfn) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 2662306a36Sopenharmony_ci struct pci_dev_entry *dev_entry; 2762306a36Sopenharmony_ci struct pci_dev *dev = NULL; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci mutex_lock(&dev_data->lock); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci list_for_each_entry(dev_entry, &dev_data->dev_list, list) { 3262306a36Sopenharmony_ci if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus) 3362306a36Sopenharmony_ci && bus == (unsigned int)dev_entry->dev->bus->number 3462306a36Sopenharmony_ci && devfn == dev_entry->dev->devfn) { 3562306a36Sopenharmony_ci dev = dev_entry->dev; 3662306a36Sopenharmony_ci break; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci mutex_unlock(&dev_data->lock); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return dev; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, 4662306a36Sopenharmony_ci struct pci_dev *dev, 4762306a36Sopenharmony_ci int devid, publish_pci_dev_cb publish_cb) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 5062306a36Sopenharmony_ci struct pci_dev_entry *dev_entry; 5162306a36Sopenharmony_ci unsigned int domain, bus, devfn; 5262306a36Sopenharmony_ci int err; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); 5562306a36Sopenharmony_ci if (!dev_entry) 5662306a36Sopenharmony_ci return -ENOMEM; 5762306a36Sopenharmony_ci dev_entry->dev = dev; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci mutex_lock(&dev_data->lock); 6062306a36Sopenharmony_ci list_add_tail(&dev_entry->list, &dev_data->dev_list); 6162306a36Sopenharmony_ci mutex_unlock(&dev_data->lock); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Publish this device. */ 6462306a36Sopenharmony_ci domain = (unsigned int)pci_domain_nr(dev->bus); 6562306a36Sopenharmony_ci bus = (unsigned int)dev->bus->number; 6662306a36Sopenharmony_ci devfn = dev->devfn; 6762306a36Sopenharmony_ci err = publish_cb(pdev, domain, bus, devfn, devid); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return err; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, 7362306a36Sopenharmony_ci struct pci_dev *dev, bool lock) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 7662306a36Sopenharmony_ci struct pci_dev_entry *dev_entry, *t; 7762306a36Sopenharmony_ci struct pci_dev *found_dev = NULL; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci mutex_lock(&dev_data->lock); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { 8262306a36Sopenharmony_ci if (dev_entry->dev == dev) { 8362306a36Sopenharmony_ci list_del(&dev_entry->list); 8462306a36Sopenharmony_ci found_dev = dev_entry->dev; 8562306a36Sopenharmony_ci kfree(dev_entry); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci mutex_unlock(&dev_data->lock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (found_dev) { 9262306a36Sopenharmony_ci if (lock) 9362306a36Sopenharmony_ci device_lock(&found_dev->dev); 9462306a36Sopenharmony_ci pcistub_put_pci_dev(found_dev); 9562306a36Sopenharmony_ci if (lock) 9662306a36Sopenharmony_ci device_unlock(&found_dev->dev); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct passthrough_dev_data *dev_data; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); 10562306a36Sopenharmony_ci if (!dev_data) 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci mutex_init(&dev_data->lock); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci INIT_LIST_HEAD(&dev_data->dev_list); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci pdev->pci_dev_data = dev_data; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, 11862306a36Sopenharmony_ci publish_pci_root_cb publish_root_cb) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci int err = 0; 12162306a36Sopenharmony_ci struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 12262306a36Sopenharmony_ci struct pci_dev_entry *dev_entry, *e; 12362306a36Sopenharmony_ci struct pci_dev *dev; 12462306a36Sopenharmony_ci int found; 12562306a36Sopenharmony_ci unsigned int domain, bus; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci mutex_lock(&dev_data->lock); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci list_for_each_entry(dev_entry, &dev_data->dev_list, list) { 13062306a36Sopenharmony_ci /* Only publish this device as a root if none of its 13162306a36Sopenharmony_ci * parent bridges are exported 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci found = 0; 13462306a36Sopenharmony_ci dev = dev_entry->dev->bus->self; 13562306a36Sopenharmony_ci for (; !found && dev != NULL; dev = dev->bus->self) { 13662306a36Sopenharmony_ci list_for_each_entry(e, &dev_data->dev_list, list) { 13762306a36Sopenharmony_ci if (dev == e->dev) { 13862306a36Sopenharmony_ci found = 1; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus); 14562306a36Sopenharmony_ci bus = (unsigned int)dev_entry->dev->bus->number; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!found) { 14862306a36Sopenharmony_ci err = publish_root_cb(pdev, domain, bus); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mutex_unlock(&dev_data->lock); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 16262306a36Sopenharmony_ci struct pci_dev_entry *dev_entry, *t; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { 16562306a36Sopenharmony_ci struct pci_dev *dev = dev_entry->dev; 16662306a36Sopenharmony_ci list_del(&dev_entry->list); 16762306a36Sopenharmony_ci device_lock(&dev->dev); 16862306a36Sopenharmony_ci pcistub_put_pci_dev(dev); 16962306a36Sopenharmony_ci device_unlock(&dev->dev); 17062306a36Sopenharmony_ci kfree(dev_entry); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci kfree(dev_data); 17462306a36Sopenharmony_ci pdev->pci_dev_data = NULL; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, 17862306a36Sopenharmony_ci struct xen_pcibk_device *pdev, 17962306a36Sopenharmony_ci unsigned int *domain, unsigned int *bus, 18062306a36Sopenharmony_ci unsigned int *devfn) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci *domain = pci_domain_nr(pcidev->bus); 18362306a36Sopenharmony_ci *bus = pcidev->bus->number; 18462306a36Sopenharmony_ci *devfn = pcidev->devfn; 18562306a36Sopenharmony_ci return 1; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciconst struct xen_pcibk_backend xen_pcibk_passthrough_backend = { 18962306a36Sopenharmony_ci .name = "passthrough", 19062306a36Sopenharmony_ci .init = __xen_pcibk_init_devices, 19162306a36Sopenharmony_ci .free = __xen_pcibk_release_devices, 19262306a36Sopenharmony_ci .find = __xen_pcibk_get_pcifront_dev, 19362306a36Sopenharmony_ci .publish = __xen_pcibk_publish_pci_roots, 19462306a36Sopenharmony_ci .release = __xen_pcibk_release_pci_dev, 19562306a36Sopenharmony_ci .add = __xen_pcibk_add_pci_dev, 19662306a36Sopenharmony_ci .get = __xen_pcibk_get_pci_dev, 19762306a36Sopenharmony_ci}; 198