- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / pci.c
1 /*
2  * Copyright (c) 2009, Intel Corporation.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307 USA.
16  *
17  * Author: Weidong Han <weidong.han@intel.com>
18  */
19
20 #include <linux/pci.h>
21 #include <linux/acpi.h>
22 #include <xen/xen.h>
23 #include <xen/interface/physdev.h>
24 #include <xen/interface/xen.h>
25
26 #ifdef CONFIG_PARAVIRT_XEN
27 #define CONFIG_XEN_COMPAT 0x040000
28 #include <asm/xen/hypervisor.h>
29 #include <asm/xen/hypercall.h>
30 #else
31 #include <asm/hypervisor.h>
32 #endif
33 #include "../pci/pci.h"
34
35 #if CONFIG_XEN_COMPAT < 0x040200
36 static bool __read_mostly pci_seg_supported = true;
37 #else
38 #define pci_seg_supported true
39 #endif
40
41 static int xen_add_device(struct device *dev)
42 {
43         int r;
44         struct pci_dev *pci_dev = to_pci_dev(dev);
45 #ifdef CONFIG_PCI_IOV
46         struct pci_dev *physfn = pci_dev->physfn;
47 #endif
48
49         if (pci_seg_supported) {
50                 struct physdev_pci_device_add add = {
51                         .seg = pci_domain_nr(pci_dev->bus),
52                         .bus = pci_dev->bus->number,
53                         .devfn = pci_dev->devfn
54                 };
55 #ifdef CONFIG_ACPI
56                 acpi_handle handle;
57 #endif
58
59 #ifdef CONFIG_PCI_IOV
60                 if (pci_dev->is_virtfn) {
61                         add.flags = XEN_PCI_DEV_VIRTFN;
62                         add.physfn.bus = physfn->bus->number;
63                         add.physfn.devfn = physfn->devfn;
64                 } else
65 #endif
66                 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
67                         add.flags = XEN_PCI_DEV_EXTFN;
68
69 #ifdef CONFIG_ACPI
70                 handle = DEVICE_ACPI_HANDLE(&pci_dev->dev);
71                 if (!handle)
72                         handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge);
73 #ifdef CONFIG_PCI_IOV
74                 if (!handle && pci_dev->is_virtfn)
75                         handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge);
76 #endif
77                 if (handle) {
78                         acpi_status status;
79
80                         do {
81                                 unsigned long long pxm;
82
83                                 status = acpi_evaluate_integer(handle, "_PXM",
84                                                                NULL, &pxm);
85                                 if (ACPI_SUCCESS(status)) {
86                                         add.optarr[0] = pxm;
87                                         add.flags |= XEN_PCI_DEV_PXM;
88                                         break;
89                                 }
90                                 status = acpi_get_parent(handle, &handle);
91                         } while (ACPI_SUCCESS(status));
92                 }
93 #endif /* CONFIG_ACPI */
94
95                 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add);
96                 if (r != -ENOSYS)
97                         return r;
98 #if CONFIG_XEN_COMPAT < 0x040200
99                 pci_seg_supported = false;
100 #endif
101         }
102
103         if (pci_domain_nr(pci_dev->bus))
104                 r = -ENOSYS;
105 #ifdef CONFIG_PCI_IOV
106         else if (pci_dev->is_virtfn) {
107                 struct physdev_manage_pci_ext manage_pci_ext = {
108                         .bus            = pci_dev->bus->number,
109                         .devfn          = pci_dev->devfn,
110                         .is_virtfn      = 1,
111                         .physfn.bus     = physfn->bus->number,
112                         .physfn.devfn   = physfn->devfn,
113                 };
114
115                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
116                         &manage_pci_ext);
117         }
118 #endif
119         else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
120                 struct physdev_manage_pci_ext manage_pci_ext = {
121                         .bus            = pci_dev->bus->number,
122                         .devfn          = pci_dev->devfn,
123                         .is_extfn       = 1,
124                 };
125
126                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
127                         &manage_pci_ext);
128         } else {
129                 struct physdev_manage_pci manage_pci = {
130                         .bus    = pci_dev->bus->number,
131                         .devfn  = pci_dev->devfn,
132                 };
133
134                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
135                         &manage_pci);
136         }
137
138         return r;
139 }
140
141 static int xen_remove_device(struct device *dev)
142 {
143         int r;
144         struct pci_dev *pci_dev = to_pci_dev(dev);
145
146         if (pci_seg_supported) {
147                 struct physdev_pci_device device = {
148                         .seg = pci_domain_nr(pci_dev->bus),
149                         .bus = pci_dev->bus->number,
150                         .devfn = pci_dev->devfn
151                 };
152
153                 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
154                                           &device);
155         } else if (pci_domain_nr(pci_dev->bus))
156                 r = -ENOSYS;
157         else {
158                 struct physdev_manage_pci manage_pci = {
159                         .bus = pci_dev->bus->number,
160                         .devfn = pci_dev->devfn
161                 };
162
163                 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
164                                           &manage_pci);
165         }
166
167         return r;
168 }
169
170 static int xen_pci_notifier(struct notifier_block *nb,
171                             unsigned long action, void *data)
172 {
173         struct device *dev = data;
174         int r = 0;
175
176         switch (action) {
177         case BUS_NOTIFY_ADD_DEVICE:
178                 r = xen_add_device(dev);
179                 break;
180         case BUS_NOTIFY_DEL_DEVICE:
181                 r = xen_remove_device(dev);
182                 break;
183         default:
184                 return NOTIFY_DONE;
185         }
186         if (r)
187                 dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
188                         action == BUS_NOTIFY_ADD_DEVICE ? "add" :
189                         (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
190         return NOTIFY_OK;
191 }
192
193 static struct notifier_block device_nb = {
194         .notifier_call = xen_pci_notifier,
195 };
196
197 static int __init register_xen_pci_notifier(void)
198 {
199         if (!xen_initial_domain())
200                 return 0;
201
202         return bus_register_notifier(&pci_bus_type, &device_nb);
203 }
204
205 arch_initcall(register_xen_pci_notifier);