root/drivers/xen/pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xen_add_device
  2. xen_remove_device
  3. xen_pci_notifier
  4. register_xen_pci_notifier
  5. xen_mcfg_late

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2009, Intel Corporation.
   4  *
   5  * Author: Weidong Han <weidong.han@intel.com>
   6  */
   7 
   8 #include <linux/pci.h>
   9 #include <linux/acpi.h>
  10 #include <linux/pci-acpi.h>
  11 #include <xen/xen.h>
  12 #include <xen/interface/physdev.h>
  13 #include <xen/interface/xen.h>
  14 
  15 #include <asm/xen/hypervisor.h>
  16 #include <asm/xen/hypercall.h>
  17 #include "../pci/pci.h"
  18 #ifdef CONFIG_PCI_MMCONFIG
  19 #include <asm/pci_x86.h>
  20 
  21 static int xen_mcfg_late(void);
  22 #endif
  23 
  24 static bool __read_mostly pci_seg_supported = true;
  25 
  26 static int xen_add_device(struct device *dev)
  27 {
  28         int r;
  29         struct pci_dev *pci_dev = to_pci_dev(dev);
  30 #ifdef CONFIG_PCI_IOV
  31         struct pci_dev *physfn = pci_dev->physfn;
  32 #endif
  33 #ifdef CONFIG_PCI_MMCONFIG
  34         static bool pci_mcfg_reserved = false;
  35         /*
  36          * Reserve MCFG areas in Xen on first invocation due to this being
  37          * potentially called from inside of acpi_init immediately after
  38          * MCFG table has been finally parsed.
  39          */
  40         if (!pci_mcfg_reserved) {
  41                 xen_mcfg_late();
  42                 pci_mcfg_reserved = true;
  43         }
  44 #endif
  45         if (pci_seg_supported) {
  46                 struct {
  47                         struct physdev_pci_device_add add;
  48                         uint32_t pxm;
  49                 } add_ext = {
  50                         .add.seg = pci_domain_nr(pci_dev->bus),
  51                         .add.bus = pci_dev->bus->number,
  52                         .add.devfn = pci_dev->devfn
  53                 };
  54                 struct physdev_pci_device_add *add = &add_ext.add;
  55 
  56 #ifdef CONFIG_ACPI
  57                 acpi_handle handle;
  58 #endif
  59 
  60 #ifdef CONFIG_PCI_IOV
  61                 if (pci_dev->is_virtfn) {
  62                         add->flags = XEN_PCI_DEV_VIRTFN;
  63                         add->physfn.bus = physfn->bus->number;
  64                         add->physfn.devfn = physfn->devfn;
  65                 } else
  66 #endif
  67                 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
  68                         add->flags = XEN_PCI_DEV_EXTFN;
  69 
  70 #ifdef CONFIG_ACPI
  71                 handle = ACPI_HANDLE(&pci_dev->dev);
  72 #ifdef CONFIG_PCI_IOV
  73                 if (!handle && pci_dev->is_virtfn)
  74                         handle = ACPI_HANDLE(physfn->bus->bridge);
  75 #endif
  76                 if (!handle) {
  77                         /*
  78                          * This device was not listed in the ACPI name space at
  79                          * all. Try to get acpi handle of parent pci bus.
  80                          */
  81                         struct pci_bus *pbus;
  82                         for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) {
  83                                 handle = acpi_pci_get_bridge_handle(pbus);
  84                                 if (handle)
  85                                         break;
  86                         }
  87                 }
  88                 if (handle) {
  89                         acpi_status status;
  90 
  91                         do {
  92                                 unsigned long long pxm;
  93 
  94                                 status = acpi_evaluate_integer(handle, "_PXM",
  95                                                                NULL, &pxm);
  96                                 if (ACPI_SUCCESS(status)) {
  97                                         add->optarr[0] = pxm;
  98                                         add->flags |= XEN_PCI_DEV_PXM;
  99                                         break;
 100                                 }
 101                                 status = acpi_get_parent(handle, &handle);
 102                         } while (ACPI_SUCCESS(status));
 103                 }
 104 #endif /* CONFIG_ACPI */
 105 
 106                 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add);
 107                 if (r != -ENOSYS)
 108                         return r;
 109                 pci_seg_supported = false;
 110         }
 111 
 112         if (pci_domain_nr(pci_dev->bus))
 113                 r = -ENOSYS;
 114 #ifdef CONFIG_PCI_IOV
 115         else if (pci_dev->is_virtfn) {
 116                 struct physdev_manage_pci_ext manage_pci_ext = {
 117                         .bus            = pci_dev->bus->number,
 118                         .devfn          = pci_dev->devfn,
 119                         .is_virtfn      = 1,
 120                         .physfn.bus     = physfn->bus->number,
 121                         .physfn.devfn   = physfn->devfn,
 122                 };
 123 
 124                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
 125                         &manage_pci_ext);
 126         }
 127 #endif
 128         else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
 129                 struct physdev_manage_pci_ext manage_pci_ext = {
 130                         .bus            = pci_dev->bus->number,
 131                         .devfn          = pci_dev->devfn,
 132                         .is_extfn       = 1,
 133                 };
 134 
 135                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
 136                         &manage_pci_ext);
 137         } else {
 138                 struct physdev_manage_pci manage_pci = {
 139                         .bus    = pci_dev->bus->number,
 140                         .devfn  = pci_dev->devfn,
 141                 };
 142 
 143                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
 144                         &manage_pci);
 145         }
 146 
 147         return r;
 148 }
 149 
 150 static int xen_remove_device(struct device *dev)
 151 {
 152         int r;
 153         struct pci_dev *pci_dev = to_pci_dev(dev);
 154 
 155         if (pci_seg_supported) {
 156                 struct physdev_pci_device device = {
 157                         .seg = pci_domain_nr(pci_dev->bus),
 158                         .bus = pci_dev->bus->number,
 159                         .devfn = pci_dev->devfn
 160                 };
 161 
 162                 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
 163                                           &device);
 164         } else if (pci_domain_nr(pci_dev->bus))
 165                 r = -ENOSYS;
 166         else {
 167                 struct physdev_manage_pci manage_pci = {
 168                         .bus = pci_dev->bus->number,
 169                         .devfn = pci_dev->devfn
 170                 };
 171 
 172                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
 173                                           &manage_pci);
 174         }
 175 
 176         return r;
 177 }
 178 
 179 static int xen_pci_notifier(struct notifier_block *nb,
 180                             unsigned long action, void *data)
 181 {
 182         struct device *dev = data;
 183         int r = 0;
 184 
 185         switch (action) {
 186         case BUS_NOTIFY_ADD_DEVICE:
 187                 r = xen_add_device(dev);
 188                 break;
 189         case BUS_NOTIFY_DEL_DEVICE:
 190                 r = xen_remove_device(dev);
 191                 break;
 192         default:
 193                 return NOTIFY_DONE;
 194         }
 195         if (r)
 196                 dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
 197                         action == BUS_NOTIFY_ADD_DEVICE ? "add" :
 198                         (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
 199         return NOTIFY_OK;
 200 }
 201 
 202 static struct notifier_block device_nb = {
 203         .notifier_call = xen_pci_notifier,
 204 };
 205 
 206 static int __init register_xen_pci_notifier(void)
 207 {
 208         if (!xen_initial_domain())
 209                 return 0;
 210 
 211         return bus_register_notifier(&pci_bus_type, &device_nb);
 212 }
 213 
 214 arch_initcall(register_xen_pci_notifier);
 215 
 216 #ifdef CONFIG_PCI_MMCONFIG
 217 static int xen_mcfg_late(void)
 218 {
 219         struct pci_mmcfg_region *cfg;
 220         int rc;
 221 
 222         if (!xen_initial_domain())
 223                 return 0;
 224 
 225         if ((pci_probe & PCI_PROBE_MMCONF) == 0)
 226                 return 0;
 227 
 228         if (list_empty(&pci_mmcfg_list))
 229                 return 0;
 230 
 231         /* Check whether they are in the right area. */
 232         list_for_each_entry(cfg, &pci_mmcfg_list, list) {
 233                 struct physdev_pci_mmcfg_reserved r;
 234 
 235                 r.address = cfg->address;
 236                 r.segment = cfg->segment;
 237                 r.start_bus = cfg->start_bus;
 238                 r.end_bus = cfg->end_bus;
 239                 r.flags = XEN_PCI_MMCFG_RESERVED;
 240 
 241                 rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r);
 242                 switch (rc) {
 243                 case 0:
 244                 case -ENOSYS:
 245                         continue;
 246 
 247                 default:
 248                         pr_warn("Failed to report MMCONFIG reservation"
 249                                 " state for %s to hypervisor"
 250                                 " (%d)\n",
 251                                 cfg->name, rc);
 252                 }
 253         }
 254         return 0;
 255 }
 256 #endif

/* [<][>][^][v][top][bottom][index][help] */