diff options
Diffstat (limited to 'drivers/xen/pci.c')
-rw-r--r-- | drivers/xen/pci.c | 105 |
1 files changed, 91 insertions, 14 deletions
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index cef4bafc07dc..66057075d6e2 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/acpi.h> | ||
21 | #include <xen/xen.h> | 22 | #include <xen/xen.h> |
22 | #include <xen/interface/physdev.h> | 23 | #include <xen/interface/physdev.h> |
23 | #include <xen/interface/xen.h> | 24 | #include <xen/interface/xen.h> |
@@ -26,26 +27,85 @@ | |||
26 | #include <asm/xen/hypercall.h> | 27 | #include <asm/xen/hypercall.h> |
27 | #include "../pci/pci.h" | 28 | #include "../pci/pci.h" |
28 | 29 | ||
30 | static bool __read_mostly pci_seg_supported = true; | ||
31 | |||
29 | static int xen_add_device(struct device *dev) | 32 | static int xen_add_device(struct device *dev) |
30 | { | 33 | { |
31 | int r; | 34 | int r; |
32 | struct pci_dev *pci_dev = to_pci_dev(dev); | 35 | struct pci_dev *pci_dev = to_pci_dev(dev); |
36 | #ifdef CONFIG_PCI_IOV | ||
37 | struct pci_dev *physfn = pci_dev->physfn; | ||
38 | #endif | ||
39 | |||
40 | if (pci_seg_supported) { | ||
41 | struct physdev_pci_device_add add = { | ||
42 | .seg = pci_domain_nr(pci_dev->bus), | ||
43 | .bus = pci_dev->bus->number, | ||
44 | .devfn = pci_dev->devfn | ||
45 | }; | ||
46 | #ifdef CONFIG_ACPI | ||
47 | acpi_handle handle; | ||
48 | #endif | ||
49 | |||
50 | #ifdef CONFIG_PCI_IOV | ||
51 | if (pci_dev->is_virtfn) { | ||
52 | add.flags = XEN_PCI_DEV_VIRTFN; | ||
53 | add.physfn.bus = physfn->bus->number; | ||
54 | add.physfn.devfn = physfn->devfn; | ||
55 | } else | ||
56 | #endif | ||
57 | if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) | ||
58 | add.flags = XEN_PCI_DEV_EXTFN; | ||
59 | |||
60 | #ifdef CONFIG_ACPI | ||
61 | handle = DEVICE_ACPI_HANDLE(&pci_dev->dev); | ||
62 | if (!handle) | ||
63 | handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge); | ||
64 | #ifdef CONFIG_PCI_IOV | ||
65 | if (!handle && pci_dev->is_virtfn) | ||
66 | handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge); | ||
67 | #endif | ||
68 | if (handle) { | ||
69 | acpi_status status; | ||
70 | |||
71 | do { | ||
72 | unsigned long long pxm; | ||
73 | |||
74 | status = acpi_evaluate_integer(handle, "_PXM", | ||
75 | NULL, &pxm); | ||
76 | if (ACPI_SUCCESS(status)) { | ||
77 | add.optarr[0] = pxm; | ||
78 | add.flags |= XEN_PCI_DEV_PXM; | ||
79 | break; | ||
80 | } | ||
81 | status = acpi_get_parent(handle, &handle); | ||
82 | } while (ACPI_SUCCESS(status)); | ||
83 | } | ||
84 | #endif /* CONFIG_ACPI */ | ||
85 | |||
86 | r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add); | ||
87 | if (r != -ENOSYS) | ||
88 | return r; | ||
89 | pci_seg_supported = false; | ||
90 | } | ||
33 | 91 | ||
92 | if (pci_domain_nr(pci_dev->bus)) | ||
93 | r = -ENOSYS; | ||
34 | #ifdef CONFIG_PCI_IOV | 94 | #ifdef CONFIG_PCI_IOV |
35 | if (pci_dev->is_virtfn) { | 95 | else if (pci_dev->is_virtfn) { |
36 | struct physdev_manage_pci_ext manage_pci_ext = { | 96 | struct physdev_manage_pci_ext manage_pci_ext = { |
37 | .bus = pci_dev->bus->number, | 97 | .bus = pci_dev->bus->number, |
38 | .devfn = pci_dev->devfn, | 98 | .devfn = pci_dev->devfn, |
39 | .is_virtfn = 1, | 99 | .is_virtfn = 1, |
40 | .physfn.bus = pci_dev->physfn->bus->number, | 100 | .physfn.bus = physfn->bus->number, |
41 | .physfn.devfn = pci_dev->physfn->devfn, | 101 | .physfn.devfn = physfn->devfn, |
42 | }; | 102 | }; |
43 | 103 | ||
44 | r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, | 104 | r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, |
45 | &manage_pci_ext); | 105 | &manage_pci_ext); |
46 | } else | 106 | } |
47 | #endif | 107 | #endif |
48 | if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { | 108 | else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { |
49 | struct physdev_manage_pci_ext manage_pci_ext = { | 109 | struct physdev_manage_pci_ext manage_pci_ext = { |
50 | .bus = pci_dev->bus->number, | 110 | .bus = pci_dev->bus->number, |
51 | .devfn = pci_dev->devfn, | 111 | .devfn = pci_dev->devfn, |
@@ -71,13 +131,27 @@ static int xen_remove_device(struct device *dev) | |||
71 | { | 131 | { |
72 | int r; | 132 | int r; |
73 | struct pci_dev *pci_dev = to_pci_dev(dev); | 133 | struct pci_dev *pci_dev = to_pci_dev(dev); |
74 | struct physdev_manage_pci manage_pci; | ||
75 | 134 | ||
76 | manage_pci.bus = pci_dev->bus->number; | 135 | if (pci_seg_supported) { |
77 | manage_pci.devfn = pci_dev->devfn; | 136 | struct physdev_pci_device device = { |
137 | .seg = pci_domain_nr(pci_dev->bus), | ||
138 | .bus = pci_dev->bus->number, | ||
139 | .devfn = pci_dev->devfn | ||
140 | }; | ||
78 | 141 | ||
79 | r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, | 142 | r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove, |
80 | &manage_pci); | 143 | &device); |
144 | } else if (pci_domain_nr(pci_dev->bus)) | ||
145 | r = -ENOSYS; | ||
146 | else { | ||
147 | struct physdev_manage_pci manage_pci = { | ||
148 | .bus = pci_dev->bus->number, | ||
149 | .devfn = pci_dev->devfn | ||
150 | }; | ||
151 | |||
152 | r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, | ||
153 | &manage_pci); | ||
154 | } | ||
81 | 155 | ||
82 | return r; | 156 | return r; |
83 | } | 157 | } |
@@ -96,13 +170,16 @@ static int xen_pci_notifier(struct notifier_block *nb, | |||
96 | r = xen_remove_device(dev); | 170 | r = xen_remove_device(dev); |
97 | break; | 171 | break; |
98 | default: | 172 | default: |
99 | break; | 173 | return NOTIFY_DONE; |
100 | } | 174 | } |
101 | 175 | if (r) | |
102 | return r; | 176 | dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n", |
177 | action == BUS_NOTIFY_ADD_DEVICE ? "add" : | ||
178 | (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?")); | ||
179 | return NOTIFY_OK; | ||
103 | } | 180 | } |
104 | 181 | ||
105 | struct notifier_block device_nb = { | 182 | static struct notifier_block device_nb = { |
106 | .notifier_call = xen_pci_notifier, | 183 | .notifier_call = xen_pci_notifier, |
107 | }; | 184 | }; |
108 | 185 | ||