diff options
-rw-r--r-- | drivers/xen/Kconfig | 32 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/Makefile | 5 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/passthrough.c | 43 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/pciback.h | 94 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/vpci.c | 43 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/xenbus.c | 21 |
6 files changed, 166 insertions, 72 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 0b6989f92041..9b700b4a987a 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -109,34 +109,22 @@ config XEN_PCIDEV_BACKEND | |||
109 | tristate "Xen PCI-device backend driver" | 109 | tristate "Xen PCI-device backend driver" |
110 | depends on PCI && X86 && XEN | 110 | depends on PCI && X86 && XEN |
111 | depends on XEN_BACKEND | 111 | depends on XEN_BACKEND |
112 | default m | ||
112 | help | 113 | help |
113 | The PCI device backend driver allows the kernel to export arbitrary | 114 | The PCI device backend driver allows the kernel to export arbitrary |
114 | PCI devices to other guests. If you select this to be a module, you | 115 | PCI devices to other guests. If you select this to be a module, you |
115 | will need to make sure no other driver has bound to the device(s) | 116 | will need to make sure no other driver has bound to the device(s) |
116 | you want to make visible to other guests. | 117 | you want to make visible to other guests. |
117 | 118 | ||
118 | choice | 119 | The parameter "passthrough" allows you specify how you want the PCI |
119 | prompt "PCI Backend Mode" | 120 | devices to appear in the guest. You can choose the default (0) where |
120 | depends on XEN_PCIDEV_BACKEND | 121 | PCI topology starts at 00.00.0, or (1) for passthrough if you want |
121 | 122 | the PCI devices topology appear the same as in the host. | |
122 | config XEN_PCIDEV_BACKEND_VPCI | ||
123 | bool "Virtual PCI" | ||
124 | help | ||
125 | This PCI Backend hides the true PCI topology and makes the frontend | ||
126 | think there is a single PCI bus with only the exported devices on it. | ||
127 | For example, a device at 03:05.0 will be re-assigned to 00:00.0. A | ||
128 | second device at 02:1a.1 will be re-assigned to 00:01.1. | ||
129 | |||
130 | config XEN_PCIDEV_BACKEND_PASS | ||
131 | bool "Passthrough" | ||
132 | help | ||
133 | This PCI Backend provides a real view of the PCI topology to the | ||
134 | frontend (for example, a device at 06:01.b will still appear at | ||
135 | 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed | ||
136 | PCI devices to its driver domains. This may be required for drivers | ||
137 | which depend on finding their hardward in certain bus/slot | ||
138 | locations. | ||
139 | 123 | ||
140 | endchoice | 124 | The "hide" parameter (only applicable if backend driver is compiled |
125 | into the kernel) allows you to bind the PCI devices to this module | ||
126 | from the default device drivers. The argument is the list of PCI BDFs: | ||
127 | xen-pciback.hide=(03:00.0)(04:00.0) | ||
141 | 128 | ||
129 | If in doubt, say m. | ||
142 | endmenu | 130 | endmenu |
diff --git a/drivers/xen/xen-pciback/Makefile b/drivers/xen/xen-pciback/Makefile index 290396766f07..ffe0ad3438bd 100644 --- a/drivers/xen/xen-pciback/Makefile +++ b/drivers/xen/xen-pciback/Makefile | |||
@@ -3,6 +3,5 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o | |||
3 | xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o | 3 | xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o |
4 | xen-pciback-y += conf_space.o conf_space_header.o \ | 4 | xen-pciback-y += conf_space.o conf_space_header.o \ |
5 | conf_space_capability.o \ | 5 | conf_space_capability.o \ |
6 | conf_space_quirks.o | 6 | conf_space_quirks.o vpci.o \ |
7 | xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o | 7 | passthrough.o |
8 | xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o | ||
diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c index b451cb8dd2ff..1d32a9a42c01 100644 --- a/drivers/xen/xen-pciback/passthrough.c +++ b/drivers/xen/xen-pciback/passthrough.c | |||
@@ -16,9 +16,10 @@ struct passthrough_dev_data { | |||
16 | spinlock_t lock; | 16 | spinlock_t lock; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, | 19 | static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, |
20 | unsigned int domain, unsigned int bus, | 20 | unsigned int domain, |
21 | unsigned int devfn) | 21 | unsigned int bus, |
22 | unsigned int devfn) | ||
22 | { | 23 | { |
23 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 24 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
24 | struct pci_dev_entry *dev_entry; | 25 | struct pci_dev_entry *dev_entry; |
@@ -41,8 +42,9 @@ struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, | |||
41 | return dev; | 42 | return dev; |
42 | } | 43 | } |
43 | 44 | ||
44 | int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, | 45 | static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, |
45 | int devid, publish_pci_dev_cb publish_cb) | 46 | struct pci_dev *dev, |
47 | int devid, publish_pci_dev_cb publish_cb) | ||
46 | { | 48 | { |
47 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 49 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
48 | struct pci_dev_entry *dev_entry; | 50 | struct pci_dev_entry *dev_entry; |
@@ -68,8 +70,8 @@ int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, | |||
68 | return err; | 70 | return err; |
69 | } | 71 | } |
70 | 72 | ||
71 | void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 73 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
72 | struct pci_dev *dev) | 74 | struct pci_dev *dev) |
73 | { | 75 | { |
74 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 76 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
75 | struct pci_dev_entry *dev_entry, *t; | 77 | struct pci_dev_entry *dev_entry, *t; |
@@ -92,7 +94,7 @@ void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | |||
92 | pcistub_put_pci_dev(found_dev); | 94 | pcistub_put_pci_dev(found_dev); |
93 | } | 95 | } |
94 | 96 | ||
95 | int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | 97 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) |
96 | { | 98 | { |
97 | struct passthrough_dev_data *dev_data; | 99 | struct passthrough_dev_data *dev_data; |
98 | 100 | ||
@@ -109,8 +111,8 @@ int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | |||
109 | return 0; | 111 | return 0; |
110 | } | 112 | } |
111 | 113 | ||
112 | int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, | 114 | static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, |
113 | publish_pci_root_cb publish_root_cb) | 115 | publish_pci_root_cb publish_root_cb) |
114 | { | 116 | { |
115 | int err = 0; | 117 | int err = 0; |
116 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 118 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
@@ -154,7 +156,7 @@ int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, | |||
154 | return err; | 156 | return err; |
155 | } | 157 | } |
156 | 158 | ||
157 | void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | 159 | static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) |
158 | { | 160 | { |
159 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; | 161 | struct passthrough_dev_data *dev_data = pdev->pci_dev_data; |
160 | struct pci_dev_entry *dev_entry, *t; | 162 | struct pci_dev_entry *dev_entry, *t; |
@@ -169,13 +171,24 @@ void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | |||
169 | pdev->pci_dev_data = NULL; | 171 | pdev->pci_dev_data = NULL; |
170 | } | 172 | } |
171 | 173 | ||
172 | int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, | 174 | static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, |
173 | struct xen_pcibk_device *pdev, | 175 | struct xen_pcibk_device *pdev, |
174 | unsigned int *domain, unsigned int *bus, | 176 | unsigned int *domain, unsigned int *bus, |
175 | unsigned int *devfn) | 177 | unsigned int *devfn) |
176 | { | 178 | { |
177 | *domain = pci_domain_nr(pcidev->bus); | 179 | *domain = pci_domain_nr(pcidev->bus); |
178 | *bus = pcidev->bus->number; | 180 | *bus = pcidev->bus->number; |
179 | *devfn = pcidev->devfn; | 181 | *devfn = pcidev->devfn; |
180 | return 1; | 182 | return 1; |
181 | } | 183 | } |
184 | |||
185 | struct xen_pcibk_backend xen_pcibk_passthrough_backend = { | ||
186 | .name = "passthrough", | ||
187 | .init = __xen_pcibk_init_devices, | ||
188 | .free = __xen_pcibk_release_devices, | ||
189 | .find = __xen_pcibk_get_pcifront_dev, | ||
190 | .publish = __xen_pcibk_publish_pci_roots, | ||
191 | .release = __xen_pcibk_release_pci_dev, | ||
192 | .add = __xen_pcibk_add_pci_dev, | ||
193 | .get = __xen_pcibk_get_pci_dev, | ||
194 | }; | ||
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h index 427b7fd01356..a0e131a81503 100644 --- a/drivers/xen/xen-pciback/pciback.h +++ b/drivers/xen/xen-pciback/pciback.h | |||
@@ -83,30 +83,90 @@ typedef int (*publish_pci_dev_cb) (struct xen_pcibk_device *pdev, | |||
83 | unsigned int devfn, unsigned int devid); | 83 | unsigned int devfn, unsigned int devid); |
84 | typedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev, | 84 | typedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev, |
85 | unsigned int domain, unsigned int bus); | 85 | unsigned int domain, unsigned int bus); |
86 | int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, | ||
87 | int devid, publish_pci_dev_cb publish_cb); | ||
88 | void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | ||
89 | struct pci_dev *dev); | ||
90 | struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, | ||
91 | unsigned int domain, unsigned int bus, | ||
92 | unsigned int devfn); | ||
93 | 86 | ||
87 | /* Backend registration for the two types of BDF representation: | ||
88 | * vpci - BDFs start at 00 | ||
89 | * passthrough - BDFs are exactly like in the host. | ||
90 | */ | ||
91 | struct xen_pcibk_backend { | ||
92 | char *name; | ||
93 | int (*init)(struct xen_pcibk_device *pdev); | ||
94 | void (*free)(struct xen_pcibk_device *pdev); | ||
95 | int (*find)(struct pci_dev *pcidev, struct xen_pcibk_device *pdev, | ||
96 | unsigned int *domain, unsigned int *bus, | ||
97 | unsigned int *devfn); | ||
98 | int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb); | ||
99 | void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev); | ||
100 | int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev, | ||
101 | int devid, publish_pci_dev_cb publish_cb); | ||
102 | struct pci_dev *(*get)(struct xen_pcibk_device *pdev, | ||
103 | unsigned int domain, unsigned int bus, | ||
104 | unsigned int devfn); | ||
105 | }; | ||
106 | |||
107 | extern struct xen_pcibk_backend xen_pcibk_vpci_backend; | ||
108 | extern struct xen_pcibk_backend xen_pcibk_passthrough_backend; | ||
109 | extern struct xen_pcibk_backend *xen_pcibk_backend; | ||
110 | |||
111 | static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, | ||
112 | struct pci_dev *dev, | ||
113 | int devid, | ||
114 | publish_pci_dev_cb publish_cb) | ||
115 | { | ||
116 | if (xen_pcibk_backend && xen_pcibk_backend->add) | ||
117 | return xen_pcibk_backend->add(pdev, dev, devid, publish_cb); | ||
118 | return -1; | ||
119 | }; | ||
120 | static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | ||
121 | struct pci_dev *dev) | ||
122 | { | ||
123 | if (xen_pcibk_backend && xen_pcibk_backend->free) | ||
124 | return xen_pcibk_backend->release(pdev, dev); | ||
125 | }; | ||
126 | |||
127 | static inline struct pci_dev * | ||
128 | xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain, | ||
129 | unsigned int bus, unsigned int devfn) | ||
130 | { | ||
131 | if (xen_pcibk_backend && xen_pcibk_backend->get) | ||
132 | return xen_pcibk_backend->get(pdev, domain, bus, devfn); | ||
133 | return NULL; | ||
134 | }; | ||
94 | /** | 135 | /** |
95 | * Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk | 136 | * Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk |
96 | * before sending aer request to pcifront, so that guest could identify | 137 | * before sending aer request to pcifront, so that guest could identify |
97 | * device, coopearte with xen_pcibk to finish aer recovery job if device driver | 138 | * device, coopearte with xen_pcibk to finish aer recovery job if device driver |
98 | * has the capability | 139 | * has the capability |
99 | */ | 140 | */ |
100 | 141 | static inline int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, | |
101 | int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, | 142 | struct xen_pcibk_device *pdev, |
102 | struct xen_pcibk_device *pdev, | 143 | unsigned int *domain, |
103 | unsigned int *domain, unsigned int *bus, | 144 | unsigned int *bus, |
104 | unsigned int *devfn); | 145 | unsigned int *devfn) |
105 | int xen_pcibk_init_devices(struct xen_pcibk_device *pdev); | 146 | { |
106 | int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, | 147 | if (xen_pcibk_backend && xen_pcibk_backend->find) |
107 | publish_pci_root_cb cb); | 148 | return xen_pcibk_backend->find(pcidev, pdev, domain, bus, |
108 | void xen_pcibk_release_devices(struct xen_pcibk_device *pdev); | 149 | devfn); |
109 | 150 | return -1; | |
151 | }; | ||
152 | static inline int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | ||
153 | { | ||
154 | if (xen_pcibk_backend && xen_pcibk_backend->init) | ||
155 | return xen_pcibk_backend->init(pdev); | ||
156 | return -1; | ||
157 | }; | ||
158 | static inline int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, | ||
159 | publish_pci_root_cb cb) | ||
160 | { | ||
161 | if (xen_pcibk_backend && xen_pcibk_backend->publish) | ||
162 | return xen_pcibk_backend->publish(pdev, cb); | ||
163 | return -1; | ||
164 | }; | ||
165 | static inline void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | ||
166 | { | ||
167 | if (xen_pcibk_backend && xen_pcibk_backend->free) | ||
168 | return xen_pcibk_backend->free(pdev); | ||
169 | }; | ||
110 | /* Handles events from front-end */ | 170 | /* Handles events from front-end */ |
111 | irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id); | 171 | irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id); |
112 | void xen_pcibk_do_op(struct work_struct *data); | 172 | void xen_pcibk_do_op(struct work_struct *data); |
diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c index 7d5c192a1505..4a42cfb0959d 100644 --- a/drivers/xen/xen-pciback/vpci.c +++ b/drivers/xen/xen-pciback/vpci.c | |||
@@ -25,9 +25,10 @@ static inline struct list_head *list_first(struct list_head *head) | |||
25 | return head->next; | 25 | return head->next; |
26 | } | 26 | } |
27 | 27 | ||
28 | struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, | 28 | static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, |
29 | unsigned int domain, unsigned int bus, | 29 | unsigned int domain, |
30 | unsigned int devfn) | 30 | unsigned int bus, |
31 | unsigned int devfn) | ||
31 | { | 32 | { |
32 | struct pci_dev_entry *entry; | 33 | struct pci_dev_entry *entry; |
33 | struct pci_dev *dev = NULL; | 34 | struct pci_dev *dev = NULL; |
@@ -63,8 +64,9 @@ static inline int match_slot(struct pci_dev *l, struct pci_dev *r) | |||
63 | return 0; | 64 | return 0; |
64 | } | 65 | } |
65 | 66 | ||
66 | int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, | 67 | static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, |
67 | int devid, publish_pci_dev_cb publish_cb) | 68 | struct pci_dev *dev, int devid, |
69 | publish_pci_dev_cb publish_cb) | ||
68 | { | 70 | { |
69 | int err = 0, slot, func = -1; | 71 | int err = 0, slot, func = -1; |
70 | struct pci_dev_entry *t, *dev_entry; | 72 | struct pci_dev_entry *t, *dev_entry; |
@@ -137,8 +139,8 @@ out: | |||
137 | return err; | 139 | return err; |
138 | } | 140 | } |
139 | 141 | ||
140 | void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 142 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
141 | struct pci_dev *dev) | 143 | struct pci_dev *dev) |
142 | { | 144 | { |
143 | int slot; | 145 | int slot; |
144 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | 146 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; |
@@ -167,7 +169,7 @@ out: | |||
167 | pcistub_put_pci_dev(found_dev); | 169 | pcistub_put_pci_dev(found_dev); |
168 | } | 170 | } |
169 | 171 | ||
170 | int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | 172 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) |
171 | { | 173 | { |
172 | int slot; | 174 | int slot; |
173 | struct vpci_dev_data *vpci_dev; | 175 | struct vpci_dev_data *vpci_dev; |
@@ -186,14 +188,14 @@ int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) | |||
186 | return 0; | 188 | return 0; |
187 | } | 189 | } |
188 | 190 | ||
189 | int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, | 191 | static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, |
190 | publish_pci_root_cb publish_cb) | 192 | publish_pci_root_cb publish_cb) |
191 | { | 193 | { |
192 | /* The Virtual PCI bus has only one root */ | 194 | /* The Virtual PCI bus has only one root */ |
193 | return publish_cb(pdev, 0, 0); | 195 | return publish_cb(pdev, 0, 0); |
194 | } | 196 | } |
195 | 197 | ||
196 | void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | 198 | static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) |
197 | { | 199 | { |
198 | int slot; | 200 | int slot; |
199 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | 201 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; |
@@ -212,10 +214,10 @@ void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) | |||
212 | pdev->pci_dev_data = NULL; | 214 | pdev->pci_dev_data = NULL; |
213 | } | 215 | } |
214 | 216 | ||
215 | int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, | 217 | static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, |
216 | struct xen_pcibk_device *pdev, | 218 | struct xen_pcibk_device *pdev, |
217 | unsigned int *domain, unsigned int *bus, | 219 | unsigned int *domain, unsigned int *bus, |
218 | unsigned int *devfn) | 220 | unsigned int *devfn) |
219 | { | 221 | { |
220 | struct pci_dev_entry *entry; | 222 | struct pci_dev_entry *entry; |
221 | struct pci_dev *dev = NULL; | 223 | struct pci_dev *dev = NULL; |
@@ -244,3 +246,14 @@ int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, | |||
244 | spin_unlock_irqrestore(&vpci_dev->lock, flags); | 246 | spin_unlock_irqrestore(&vpci_dev->lock, flags); |
245 | return found; | 247 | return found; |
246 | } | 248 | } |
249 | |||
250 | struct xen_pcibk_backend xen_pcibk_vpci_backend = { | ||
251 | .name = "vpci", | ||
252 | .init = __xen_pcibk_init_devices, | ||
253 | .free = __xen_pcibk_release_devices, | ||
254 | .find = __xen_pcibk_get_pcifront_dev, | ||
255 | .publish = __xen_pcibk_publish_pci_roots, | ||
256 | .release = __xen_pcibk_release_pci_dev, | ||
257 | .add = __xen_pcibk_add_pci_dev, | ||
258 | .get = __xen_pcibk_get_pci_dev, | ||
259 | }; | ||
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index 1e5ba85c0d33..206c4ce030bc 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c | |||
@@ -18,6 +18,21 @@ | |||
18 | #define INVALID_EVTCHN_IRQ (-1) | 18 | #define INVALID_EVTCHN_IRQ (-1) |
19 | struct workqueue_struct *xen_pcibk_wq; | 19 | struct workqueue_struct *xen_pcibk_wq; |
20 | 20 | ||
21 | static int __read_mostly passthrough; | ||
22 | module_param(passthrough, bool, S_IRUGO); | ||
23 | MODULE_PARM_DESC(passthrough, | ||
24 | "Option to specify how to export PCI topology to guest:\n"\ | ||
25 | " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ | ||
26 | " there is a single PCI bus with only the exported devices on it.\n"\ | ||
27 | " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ | ||
28 | " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ | ||
29 | " 1 - Passthrough provides a real view of the PCI topology to the\n"\ | ||
30 | " frontend (for example, a device at 06:01.b will still appear at\n"\ | ||
31 | " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ | ||
32 | " exposed PCI devices to its driver domains. This may be required\n"\ | ||
33 | " for drivers which depend on finding their hardward in certain\n"\ | ||
34 | " bus/slot locations."); | ||
35 | |||
21 | static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) | 36 | static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) |
22 | { | 37 | { |
23 | struct xen_pcibk_device *pdev; | 38 | struct xen_pcibk_device *pdev; |
@@ -710,6 +725,8 @@ static struct xenbus_driver xenbus_xen_pcibk_driver = { | |||
710 | .otherend_changed = xen_pcibk_frontend_changed, | 725 | .otherend_changed = xen_pcibk_frontend_changed, |
711 | }; | 726 | }; |
712 | 727 | ||
728 | struct xen_pcibk_backend *xen_pcibk_backend; | ||
729 | |||
713 | int __init xen_pcibk_xenbus_register(void) | 730 | int __init xen_pcibk_xenbus_register(void) |
714 | { | 731 | { |
715 | xen_pcibk_wq = create_workqueue("xen_pciback_workqueue"); | 732 | xen_pcibk_wq = create_workqueue("xen_pciback_workqueue"); |
@@ -718,6 +735,10 @@ int __init xen_pcibk_xenbus_register(void) | |||
718 | "xen_pciback_workqueue failed\n", __func__); | 735 | "xen_pciback_workqueue failed\n", __func__); |
719 | return -EFAULT; | 736 | return -EFAULT; |
720 | } | 737 | } |
738 | xen_pcibk_backend = &xen_pcibk_vpci_backend; | ||
739 | if (passthrough) | ||
740 | xen_pcibk_backend = &xen_pcibk_passthrough_backend; | ||
741 | pr_info(DRV_NAME ": backend is %s\n", xen_pcibk_backend->name); | ||
721 | return xenbus_register_backend(&xenbus_xen_pcibk_driver); | 742 | return xenbus_register_backend(&xenbus_xen_pcibk_driver); |
722 | } | 743 | } |
723 | 744 | ||