Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / xen / pci.c
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