18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCI Backend - Provides a Virtual PCI bus (with real devices) 48c2ecf20Sopenharmony_ci * to the frontend 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 108c2ecf20Sopenharmony_ci#define dev_fmt pr_fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include "pciback.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define PCI_SLOT_MAX 32 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct vpci_dev_data { 218c2ecf20Sopenharmony_ci /* Access to dev_list must be protected by lock */ 228c2ecf20Sopenharmony_ci struct list_head dev_list[PCI_SLOT_MAX]; 238c2ecf20Sopenharmony_ci struct mutex lock; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic inline struct list_head *list_first(struct list_head *head) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return head->next; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, 328c2ecf20Sopenharmony_ci unsigned int domain, 338c2ecf20Sopenharmony_ci unsigned int bus, 348c2ecf20Sopenharmony_ci unsigned int devfn) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct pci_dev_entry *entry; 378c2ecf20Sopenharmony_ci struct pci_dev *dev = NULL; 388c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (domain != 0 || bus != 0) 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { 448c2ecf20Sopenharmony_ci mutex_lock(&vpci_dev->lock); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci list_for_each_entry(entry, 478c2ecf20Sopenharmony_ci &vpci_dev->dev_list[PCI_SLOT(devfn)], 488c2ecf20Sopenharmony_ci list) { 498c2ecf20Sopenharmony_ci if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) { 508c2ecf20Sopenharmony_ci dev = entry->dev; 518c2ecf20Sopenharmony_ci break; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci mutex_unlock(&vpci_dev->lock); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci return dev; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic inline int match_slot(struct pci_dev *l, struct pci_dev *r) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) 638c2ecf20Sopenharmony_ci && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) 648c2ecf20Sopenharmony_ci return 1; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, 708c2ecf20Sopenharmony_ci struct pci_dev *dev, int devid, 718c2ecf20Sopenharmony_ci publish_pci_dev_cb publish_cb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int err = 0, slot, func = PCI_FUNC(dev->devfn); 748c2ecf20Sopenharmony_ci struct pci_dev_entry *t, *dev_entry; 758c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { 788c2ecf20Sopenharmony_ci err = -EFAULT; 798c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 808c2ecf20Sopenharmony_ci "Can't export bridges on the virtual PCI bus"); 818c2ecf20Sopenharmony_ci goto out; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); 858c2ecf20Sopenharmony_ci if (!dev_entry) { 868c2ecf20Sopenharmony_ci err = -ENOMEM; 878c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 888c2ecf20Sopenharmony_ci "Error adding entry to virtual PCI bus"); 898c2ecf20Sopenharmony_ci goto out; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci dev_entry->dev = dev; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mutex_lock(&vpci_dev->lock); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * Keep multi-function devices together on the virtual PCI bus, except 988c2ecf20Sopenharmony_ci * that we want to keep virtual functions at func 0 on their own. They 998c2ecf20Sopenharmony_ci * aren't multi-function devices and hence their presence at func 0 1008c2ecf20Sopenharmony_ci * may cause guests to not scan the other functions. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci if (!dev->is_virtfn || func) { 1038c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 1048c2ecf20Sopenharmony_ci if (list_empty(&vpci_dev->dev_list[slot])) 1058c2ecf20Sopenharmony_ci continue; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci t = list_entry(list_first(&vpci_dev->dev_list[slot]), 1088c2ecf20Sopenharmony_ci struct pci_dev_entry, list); 1098c2ecf20Sopenharmony_ci if (t->dev->is_virtfn && !PCI_FUNC(t->dev->devfn)) 1108c2ecf20Sopenharmony_ci continue; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (match_slot(dev, t->dev)) { 1138c2ecf20Sopenharmony_ci dev_info(&dev->dev, "vpci: assign to virtual slot %d func %d\n", 1148c2ecf20Sopenharmony_ci slot, func); 1158c2ecf20Sopenharmony_ci list_add_tail(&dev_entry->list, 1168c2ecf20Sopenharmony_ci &vpci_dev->dev_list[slot]); 1178c2ecf20Sopenharmony_ci goto unlock; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Assign to a new slot on the virtual PCI bus */ 1238c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 1248c2ecf20Sopenharmony_ci if (list_empty(&vpci_dev->dev_list[slot])) { 1258c2ecf20Sopenharmony_ci dev_info(&dev->dev, "vpci: assign to virtual slot %d\n", 1268c2ecf20Sopenharmony_ci slot); 1278c2ecf20Sopenharmony_ci list_add_tail(&dev_entry->list, 1288c2ecf20Sopenharmony_ci &vpci_dev->dev_list[slot]); 1298c2ecf20Sopenharmony_ci goto unlock; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci err = -ENOMEM; 1348c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 1358c2ecf20Sopenharmony_ci "No more space on root virtual PCI bus"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciunlock: 1388c2ecf20Sopenharmony_ci mutex_unlock(&vpci_dev->lock); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Publish this device. */ 1418c2ecf20Sopenharmony_ci if (!err) 1428c2ecf20Sopenharmony_ci err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid); 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci kfree(dev_entry); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciout: 1478c2ecf20Sopenharmony_ci return err; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, 1518c2ecf20Sopenharmony_ci struct pci_dev *dev, bool lock) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int slot; 1548c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 1558c2ecf20Sopenharmony_ci struct pci_dev *found_dev = NULL; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci mutex_lock(&vpci_dev->lock); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 1608c2ecf20Sopenharmony_ci struct pci_dev_entry *e; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci list_for_each_entry(e, &vpci_dev->dev_list[slot], list) { 1638c2ecf20Sopenharmony_ci if (e->dev == dev) { 1648c2ecf20Sopenharmony_ci list_del(&e->list); 1658c2ecf20Sopenharmony_ci found_dev = e->dev; 1668c2ecf20Sopenharmony_ci kfree(e); 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciout: 1738c2ecf20Sopenharmony_ci mutex_unlock(&vpci_dev->lock); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (found_dev) { 1768c2ecf20Sopenharmony_ci if (lock) 1778c2ecf20Sopenharmony_ci device_lock(&found_dev->dev); 1788c2ecf20Sopenharmony_ci pcistub_put_pci_dev(found_dev); 1798c2ecf20Sopenharmony_ci if (lock) 1808c2ecf20Sopenharmony_ci device_unlock(&found_dev->dev); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci int slot; 1878c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); 1908c2ecf20Sopenharmony_ci if (!vpci_dev) 1918c2ecf20Sopenharmony_ci return -ENOMEM; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mutex_init(&vpci_dev->lock); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) 1968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci pdev->pci_dev_data = vpci_dev; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, 2048c2ecf20Sopenharmony_ci publish_pci_root_cb publish_cb) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci /* The Virtual PCI bus has only one root */ 2078c2ecf20Sopenharmony_ci return publish_cb(pdev, 0, 0); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci int slot; 2138c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 2168c2ecf20Sopenharmony_ci struct pci_dev_entry *e, *tmp; 2178c2ecf20Sopenharmony_ci list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], 2188c2ecf20Sopenharmony_ci list) { 2198c2ecf20Sopenharmony_ci struct pci_dev *dev = e->dev; 2208c2ecf20Sopenharmony_ci list_del(&e->list); 2218c2ecf20Sopenharmony_ci device_lock(&dev->dev); 2228c2ecf20Sopenharmony_ci pcistub_put_pci_dev(dev); 2238c2ecf20Sopenharmony_ci device_unlock(&dev->dev); 2248c2ecf20Sopenharmony_ci kfree(e); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci kfree(vpci_dev); 2298c2ecf20Sopenharmony_ci pdev->pci_dev_data = NULL; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, 2338c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev, 2348c2ecf20Sopenharmony_ci unsigned int *domain, unsigned int *bus, 2358c2ecf20Sopenharmony_ci unsigned int *devfn) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct pci_dev_entry *entry; 2388c2ecf20Sopenharmony_ci struct pci_dev *dev = NULL; 2398c2ecf20Sopenharmony_ci struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 2408c2ecf20Sopenharmony_ci int found = 0, slot; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci mutex_lock(&vpci_dev->lock); 2438c2ecf20Sopenharmony_ci for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 2448c2ecf20Sopenharmony_ci list_for_each_entry(entry, 2458c2ecf20Sopenharmony_ci &vpci_dev->dev_list[slot], 2468c2ecf20Sopenharmony_ci list) { 2478c2ecf20Sopenharmony_ci dev = entry->dev; 2488c2ecf20Sopenharmony_ci if (dev && dev->bus->number == pcidev->bus->number 2498c2ecf20Sopenharmony_ci && pci_domain_nr(dev->bus) == 2508c2ecf20Sopenharmony_ci pci_domain_nr(pcidev->bus) 2518c2ecf20Sopenharmony_ci && dev->devfn == pcidev->devfn) { 2528c2ecf20Sopenharmony_ci found = 1; 2538c2ecf20Sopenharmony_ci *domain = 0; 2548c2ecf20Sopenharmony_ci *bus = 0; 2558c2ecf20Sopenharmony_ci *devfn = PCI_DEVFN(slot, 2568c2ecf20Sopenharmony_ci PCI_FUNC(pcidev->devfn)); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci mutex_unlock(&vpci_dev->lock); 2618c2ecf20Sopenharmony_ci return found; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciconst struct xen_pcibk_backend xen_pcibk_vpci_backend = { 2658c2ecf20Sopenharmony_ci .name = "vpci", 2668c2ecf20Sopenharmony_ci .init = __xen_pcibk_init_devices, 2678c2ecf20Sopenharmony_ci .free = __xen_pcibk_release_devices, 2688c2ecf20Sopenharmony_ci .find = __xen_pcibk_get_pcifront_dev, 2698c2ecf20Sopenharmony_ci .publish = __xen_pcibk_publish_pci_roots, 2708c2ecf20Sopenharmony_ci .release = __xen_pcibk_release_pci_dev, 2718c2ecf20Sopenharmony_ci .add = __xen_pcibk_add_pci_dev, 2728c2ecf20Sopenharmony_ci .get = __xen_pcibk_get_pci_dev, 2738c2ecf20Sopenharmony_ci}; 274