Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2009, Intel Corporation.
0004  *
0005  * Author: Weidong Han <weidong.han@intel.com>
0006  */
0007 
0008 #include <linux/pci.h>
0009 #include <linux/acpi.h>
0010 #include <linux/pci-acpi.h>
0011 #include <xen/pci.h>
0012 #include <xen/xen.h>
0013 #include <xen/interface/physdev.h>
0014 #include <xen/interface/xen.h>
0015 
0016 #include <asm/xen/hypervisor.h>
0017 #include <asm/xen/hypercall.h>
0018 #include "../pci/pci.h"
0019 #ifdef CONFIG_PCI_MMCONFIG
0020 #include <asm/pci_x86.h>
0021 
0022 static int xen_mcfg_late(void);
0023 #endif
0024 
0025 static bool __read_mostly pci_seg_supported = true;
0026 
0027 static int xen_add_device(struct device *dev)
0028 {
0029     int r;
0030     struct pci_dev *pci_dev = to_pci_dev(dev);
0031 #ifdef CONFIG_PCI_IOV
0032     struct pci_dev *physfn = pci_dev->physfn;
0033 #endif
0034 #ifdef CONFIG_PCI_MMCONFIG
0035     static bool pci_mcfg_reserved = false;
0036     /*
0037      * Reserve MCFG areas in Xen on first invocation due to this being
0038      * potentially called from inside of acpi_init immediately after
0039      * MCFG table has been finally parsed.
0040      */
0041     if (!pci_mcfg_reserved) {
0042         xen_mcfg_late();
0043         pci_mcfg_reserved = true;
0044     }
0045 #endif
0046     if (pci_seg_supported) {
0047         struct {
0048             struct physdev_pci_device_add add;
0049             uint32_t pxm;
0050         } add_ext = {
0051             .add.seg = pci_domain_nr(pci_dev->bus),
0052             .add.bus = pci_dev->bus->number,
0053             .add.devfn = pci_dev->devfn
0054         };
0055         struct physdev_pci_device_add *add = &add_ext.add;
0056 
0057 #ifdef CONFIG_ACPI
0058         acpi_handle handle;
0059 #endif
0060 
0061 #ifdef CONFIG_PCI_IOV
0062         if (pci_dev->is_virtfn) {
0063             add->flags = XEN_PCI_DEV_VIRTFN;
0064             add->physfn.bus = physfn->bus->number;
0065             add->physfn.devfn = physfn->devfn;
0066         } else
0067 #endif
0068         if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
0069             add->flags = XEN_PCI_DEV_EXTFN;
0070 
0071 #ifdef CONFIG_ACPI
0072         handle = ACPI_HANDLE(&pci_dev->dev);
0073 #ifdef CONFIG_PCI_IOV
0074         if (!handle && pci_dev->is_virtfn)
0075             handle = ACPI_HANDLE(physfn->bus->bridge);
0076 #endif
0077         if (!handle) {
0078             /*
0079              * This device was not listed in the ACPI name space at
0080              * all. Try to get acpi handle of parent pci bus.
0081              */
0082             struct pci_bus *pbus;
0083             for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) {
0084                 handle = acpi_pci_get_bridge_handle(pbus);
0085                 if (handle)
0086                     break;
0087             }
0088         }
0089         if (handle) {
0090             acpi_status status;
0091 
0092             do {
0093                 unsigned long long pxm;
0094 
0095                 status = acpi_evaluate_integer(handle, "_PXM",
0096                                    NULL, &pxm);
0097                 if (ACPI_SUCCESS(status)) {
0098                     add->optarr[0] = pxm;
0099                     add->flags |= XEN_PCI_DEV_PXM;
0100                     break;
0101                 }
0102                 status = acpi_get_parent(handle, &handle);
0103             } while (ACPI_SUCCESS(status));
0104         }
0105 #endif /* CONFIG_ACPI */
0106 
0107         r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add);
0108         if (r != -ENOSYS)
0109             return r;
0110         pci_seg_supported = false;
0111     }
0112 
0113     if (pci_domain_nr(pci_dev->bus))
0114         r = -ENOSYS;
0115 #ifdef CONFIG_PCI_IOV
0116     else if (pci_dev->is_virtfn) {
0117         struct physdev_manage_pci_ext manage_pci_ext = {
0118             .bus        = pci_dev->bus->number,
0119             .devfn      = pci_dev->devfn,
0120             .is_virtfn  = 1,
0121             .physfn.bus = physfn->bus->number,
0122             .physfn.devfn   = physfn->devfn,
0123         };
0124 
0125         r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
0126             &manage_pci_ext);
0127     }
0128 #endif
0129     else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
0130         struct physdev_manage_pci_ext manage_pci_ext = {
0131             .bus        = pci_dev->bus->number,
0132             .devfn      = pci_dev->devfn,
0133             .is_extfn   = 1,
0134         };
0135 
0136         r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
0137             &manage_pci_ext);
0138     } else {
0139         struct physdev_manage_pci manage_pci = {
0140             .bus    = pci_dev->bus->number,
0141             .devfn  = pci_dev->devfn,
0142         };
0143 
0144         r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
0145             &manage_pci);
0146     }
0147 
0148     return r;
0149 }
0150 
0151 static int xen_remove_device(struct device *dev)
0152 {
0153     int r;
0154     struct pci_dev *pci_dev = to_pci_dev(dev);
0155 
0156     if (pci_seg_supported) {
0157         struct physdev_pci_device device = {
0158             .seg = pci_domain_nr(pci_dev->bus),
0159             .bus = pci_dev->bus->number,
0160             .devfn = pci_dev->devfn
0161         };
0162 
0163         r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
0164                       &device);
0165     } else if (pci_domain_nr(pci_dev->bus))
0166         r = -ENOSYS;
0167     else {
0168         struct physdev_manage_pci manage_pci = {
0169             .bus = pci_dev->bus->number,
0170             .devfn = pci_dev->devfn
0171         };
0172 
0173         r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
0174                       &manage_pci);
0175     }
0176 
0177     return r;
0178 }
0179 
0180 static int xen_pci_notifier(struct notifier_block *nb,
0181                 unsigned long action, void *data)
0182 {
0183     struct device *dev = data;
0184     int r = 0;
0185 
0186     switch (action) {
0187     case BUS_NOTIFY_ADD_DEVICE:
0188         r = xen_add_device(dev);
0189         break;
0190     case BUS_NOTIFY_DEL_DEVICE:
0191         r = xen_remove_device(dev);
0192         break;
0193     default:
0194         return NOTIFY_DONE;
0195     }
0196     if (r)
0197         dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
0198             action == BUS_NOTIFY_ADD_DEVICE ? "add" :
0199             (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
0200     return NOTIFY_OK;
0201 }
0202 
0203 static struct notifier_block device_nb = {
0204     .notifier_call = xen_pci_notifier,
0205 };
0206 
0207 static int __init register_xen_pci_notifier(void)
0208 {
0209     if (!xen_initial_domain())
0210         return 0;
0211 
0212     return bus_register_notifier(&pci_bus_type, &device_nb);
0213 }
0214 
0215 arch_initcall(register_xen_pci_notifier);
0216 
0217 #ifdef CONFIG_PCI_MMCONFIG
0218 static int xen_mcfg_late(void)
0219 {
0220     struct pci_mmcfg_region *cfg;
0221     int rc;
0222 
0223     if (!xen_initial_domain())
0224         return 0;
0225 
0226     if ((pci_probe & PCI_PROBE_MMCONF) == 0)
0227         return 0;
0228 
0229     if (list_empty(&pci_mmcfg_list))
0230         return 0;
0231 
0232     /* Check whether they are in the right area. */
0233     list_for_each_entry(cfg, &pci_mmcfg_list, list) {
0234         struct physdev_pci_mmcfg_reserved r;
0235 
0236         r.address = cfg->address;
0237         r.segment = cfg->segment;
0238         r.start_bus = cfg->start_bus;
0239         r.end_bus = cfg->end_bus;
0240         r.flags = XEN_PCI_MMCFG_RESERVED;
0241 
0242         rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r);
0243         switch (rc) {
0244         case 0:
0245         case -ENOSYS:
0246             continue;
0247 
0248         default:
0249             pr_warn("Failed to report MMCONFIG reservation"
0250                 " state for %s to hypervisor"
0251                 " (%d)\n",
0252                 cfg->name, rc);
0253         }
0254     }
0255     return 0;
0256 }
0257 #endif
0258 
0259 #ifdef CONFIG_XEN_DOM0
0260 struct xen_device_domain_owner {
0261     domid_t domain;
0262     struct pci_dev *dev;
0263     struct list_head list;
0264 };
0265 
0266 static DEFINE_SPINLOCK(dev_domain_list_spinlock);
0267 static LIST_HEAD(dev_domain_list);
0268 
0269 static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
0270 {
0271     struct xen_device_domain_owner *owner;
0272 
0273     list_for_each_entry(owner, &dev_domain_list, list) {
0274         if (owner->dev == dev)
0275             return owner;
0276     }
0277     return NULL;
0278 }
0279 
0280 int xen_find_device_domain_owner(struct pci_dev *dev)
0281 {
0282     struct xen_device_domain_owner *owner;
0283     int domain = -ENODEV;
0284 
0285     spin_lock(&dev_domain_list_spinlock);
0286     owner = find_device(dev);
0287     if (owner)
0288         domain = owner->domain;
0289     spin_unlock(&dev_domain_list_spinlock);
0290     return domain;
0291 }
0292 EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
0293 
0294 int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
0295 {
0296     struct xen_device_domain_owner *owner;
0297 
0298     owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
0299     if (!owner)
0300         return -ENODEV;
0301 
0302     spin_lock(&dev_domain_list_spinlock);
0303     if (find_device(dev)) {
0304         spin_unlock(&dev_domain_list_spinlock);
0305         kfree(owner);
0306         return -EEXIST;
0307     }
0308     owner->domain = domain;
0309     owner->dev = dev;
0310     list_add_tail(&owner->list, &dev_domain_list);
0311     spin_unlock(&dev_domain_list_spinlock);
0312     return 0;
0313 }
0314 EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
0315 
0316 int xen_unregister_device_domain_owner(struct pci_dev *dev)
0317 {
0318     struct xen_device_domain_owner *owner;
0319 
0320     spin_lock(&dev_domain_list_spinlock);
0321     owner = find_device(dev);
0322     if (!owner) {
0323         spin_unlock(&dev_domain_list_spinlock);
0324         return -ENODEV;
0325     }
0326     list_del(&owner->list);
0327     spin_unlock(&dev_domain_list_spinlock);
0328     kfree(owner);
0329     return 0;
0330 }
0331 EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
0332 #endif