]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
30edc14b KRW |
2 | /* |
3 | * PCI Backend - Provides a Virtual PCI bus (with real devices) | |
4 | * to the frontend | |
5 | * | |
6 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> | |
7 | */ | |
8 | ||
283c0972 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
69049454 | 10 | #define dev_fmt pr_fmt |
283c0972 | 11 | |
30edc14b KRW |
12 | #include <linux/list.h> |
13 | #include <linux/slab.h> | |
14 | #include <linux/pci.h> | |
74d33ded | 15 | #include <linux/mutex.h> |
30edc14b KRW |
16 | #include "pciback.h" |
17 | ||
18 | #define PCI_SLOT_MAX 32 | |
19 | ||
20 | struct vpci_dev_data { | |
21 | /* Access to dev_list must be protected by lock */ | |
22 | struct list_head dev_list[PCI_SLOT_MAX]; | |
74d33ded | 23 | struct mutex lock; |
30edc14b KRW |
24 | }; |
25 | ||
26 | static inline struct list_head *list_first(struct list_head *head) | |
27 | { | |
28 | return head->next; | |
29 | } | |
30 | ||
2ebdc426 KRW |
31 | static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, |
32 | unsigned int domain, | |
33 | unsigned int bus, | |
34 | unsigned int devfn) | |
30edc14b KRW |
35 | { |
36 | struct pci_dev_entry *entry; | |
37 | struct pci_dev *dev = NULL; | |
38 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | |
30edc14b KRW |
39 | |
40 | if (domain != 0 || bus != 0) | |
41 | return NULL; | |
42 | ||
43 | if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { | |
74d33ded | 44 | mutex_lock(&vpci_dev->lock); |
30edc14b KRW |
45 | |
46 | list_for_each_entry(entry, | |
47 | &vpci_dev->dev_list[PCI_SLOT(devfn)], | |
48 | list) { | |
49 | if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) { | |
50 | dev = entry->dev; | |
51 | break; | |
52 | } | |
53 | } | |
54 | ||
74d33ded | 55 | mutex_unlock(&vpci_dev->lock); |
30edc14b KRW |
56 | } |
57 | return dev; | |
58 | } | |
59 | ||
60 | static inline int match_slot(struct pci_dev *l, struct pci_dev *r) | |
61 | { | |
62 | if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) | |
63 | && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) | |
64 | return 1; | |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
2ebdc426 KRW |
69 | static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, |
70 | struct pci_dev *dev, int devid, | |
71 | publish_pci_dev_cb publish_cb) | |
30edc14b | 72 | { |
4ba50e7c | 73 | int err = 0, slot, func = PCI_FUNC(dev->devfn); |
30edc14b KRW |
74 | struct pci_dev_entry *t, *dev_entry; |
75 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | |
30edc14b KRW |
76 | |
77 | if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { | |
78 | err = -EFAULT; | |
79 | xenbus_dev_fatal(pdev->xdev, err, | |
80 | "Can't export bridges on the virtual PCI bus"); | |
81 | goto out; | |
82 | } | |
83 | ||
84 | dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); | |
85 | if (!dev_entry) { | |
86 | err = -ENOMEM; | |
87 | xenbus_dev_fatal(pdev->xdev, err, | |
88 | "Error adding entry to virtual PCI bus"); | |
89 | goto out; | |
90 | } | |
91 | ||
92 | dev_entry->dev = dev; | |
93 | ||
74d33ded | 94 | mutex_lock(&vpci_dev->lock); |
30edc14b | 95 | |
8a5248fe LE |
96 | /* |
97 | * Keep multi-function devices together on the virtual PCI bus, except | |
4ba50e7c JB |
98 | * that we want to keep virtual functions at func 0 on their own. They |
99 | * aren't multi-function devices and hence their presence at func 0 | |
100 | * may cause guests to not scan the other functions. | |
8a5248fe | 101 | */ |
4ba50e7c | 102 | if (!dev->is_virtfn || func) { |
8a5248fe LE |
103 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
104 | if (list_empty(&vpci_dev->dev_list[slot])) | |
105 | continue; | |
106 | ||
30edc14b KRW |
107 | t = list_entry(list_first(&vpci_dev->dev_list[slot]), |
108 | struct pci_dev_entry, list); | |
4ba50e7c JB |
109 | if (t->dev->is_virtfn && !PCI_FUNC(t->dev->devfn)) |
110 | continue; | |
30edc14b KRW |
111 | |
112 | if (match_slot(dev, t->dev)) { | |
69049454 | 113 | dev_info(&dev->dev, "vpci: assign to virtual slot %d func %d\n", |
4ba50e7c | 114 | slot, func); |
30edc14b KRW |
115 | list_add_tail(&dev_entry->list, |
116 | &vpci_dev->dev_list[slot]); | |
30edc14b KRW |
117 | goto unlock; |
118 | } | |
119 | } | |
120 | } | |
121 | ||
122 | /* Assign to a new slot on the virtual PCI bus */ | |
123 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { | |
124 | if (list_empty(&vpci_dev->dev_list[slot])) { | |
69049454 BH |
125 | dev_info(&dev->dev, "vpci: assign to virtual slot %d\n", |
126 | slot); | |
30edc14b KRW |
127 | list_add_tail(&dev_entry->list, |
128 | &vpci_dev->dev_list[slot]); | |
30edc14b KRW |
129 | goto unlock; |
130 | } | |
131 | } | |
132 | ||
133 | err = -ENOMEM; | |
134 | xenbus_dev_fatal(pdev->xdev, err, | |
135 | "No more space on root virtual PCI bus"); | |
136 | ||
137 | unlock: | |
74d33ded | 138 | mutex_unlock(&vpci_dev->lock); |
30edc14b KRW |
139 | |
140 | /* Publish this device. */ | |
141 | if (!err) | |
142 | err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid); | |
cea37f87 DY |
143 | else |
144 | kfree(dev_entry); | |
30edc14b KRW |
145 | |
146 | out: | |
147 | return err; | |
148 | } | |
149 | ||
2ebdc426 | 150 | static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
e8801a74 | 151 | struct pci_dev *dev, bool lock) |
30edc14b KRW |
152 | { |
153 | int slot; | |
154 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | |
155 | struct pci_dev *found_dev = NULL; | |
30edc14b | 156 | |
74d33ded | 157 | mutex_lock(&vpci_dev->lock); |
30edc14b KRW |
158 | |
159 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { | |
402c5e15 JB |
160 | struct pci_dev_entry *e; |
161 | ||
162 | list_for_each_entry(e, &vpci_dev->dev_list[slot], list) { | |
30edc14b KRW |
163 | if (e->dev == dev) { |
164 | list_del(&e->list); | |
165 | found_dev = e->dev; | |
166 | kfree(e); | |
167 | goto out; | |
168 | } | |
169 | } | |
170 | } | |
171 | ||
172 | out: | |
74d33ded | 173 | mutex_unlock(&vpci_dev->lock); |
30edc14b | 174 | |
e8801a74 KRW |
175 | if (found_dev) { |
176 | if (lock) | |
177 | device_lock(&found_dev->dev); | |
30edc14b | 178 | pcistub_put_pci_dev(found_dev); |
e8801a74 KRW |
179 | if (lock) |
180 | device_unlock(&found_dev->dev); | |
181 | } | |
30edc14b KRW |
182 | } |
183 | ||
2ebdc426 | 184 | static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) |
30edc14b KRW |
185 | { |
186 | int slot; | |
187 | struct vpci_dev_data *vpci_dev; | |
188 | ||
189 | vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); | |
190 | if (!vpci_dev) | |
191 | return -ENOMEM; | |
192 | ||
74d33ded | 193 | mutex_init(&vpci_dev->lock); |
30edc14b KRW |
194 | |
195 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) | |
196 | INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); | |
197 | ||
198 | pdev->pci_dev_data = vpci_dev; | |
199 | ||
200 | return 0; | |
201 | } | |
202 | ||
2ebdc426 KRW |
203 | static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, |
204 | publish_pci_root_cb publish_cb) | |
30edc14b KRW |
205 | { |
206 | /* The Virtual PCI bus has only one root */ | |
207 | return publish_cb(pdev, 0, 0); | |
208 | } | |
209 | ||
2ebdc426 | 210 | static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) |
30edc14b KRW |
211 | { |
212 | int slot; | |
213 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; | |
214 | ||
215 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { | |
216 | struct pci_dev_entry *e, *tmp; | |
217 | list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], | |
218 | list) { | |
e8801a74 | 219 | struct pci_dev *dev = e->dev; |
30edc14b | 220 | list_del(&e->list); |
e8801a74 KRW |
221 | device_lock(&dev->dev); |
222 | pcistub_put_pci_dev(dev); | |
223 | device_unlock(&dev->dev); | |
30edc14b KRW |
224 | kfree(e); |
225 | } | |
226 | } | |
227 | ||
228 | kfree(vpci_dev); | |
229 | pdev->pci_dev_data = NULL; | |
230 | } | |
231 | ||
2ebdc426 KRW |
232 | static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, |
233 | struct xen_pcibk_device *pdev, | |
234 | unsigned int *domain, unsigned int *bus, | |
235 | unsigned int *devfn) | |
30edc14b KRW |
236 | { |
237 | struct pci_dev_entry *entry; | |
30edc14b | 238 | struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; |
30edc14b KRW |
239 | int found = 0, slot; |
240 | ||
74d33ded | 241 | mutex_lock(&vpci_dev->lock); |
30edc14b KRW |
242 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
243 | list_for_each_entry(entry, | |
244 | &vpci_dev->dev_list[slot], | |
245 | list) { | |
a929e124 | 246 | if (entry->dev == pcidev) { |
30edc14b KRW |
247 | found = 1; |
248 | *domain = 0; | |
249 | *bus = 0; | |
250 | *devfn = PCI_DEVFN(slot, | |
251 | PCI_FUNC(pcidev->devfn)); | |
252 | } | |
253 | } | |
254 | } | |
e1db4cef | 255 | mutex_unlock(&vpci_dev->lock); |
30edc14b KRW |
256 | return found; |
257 | } | |
2ebdc426 | 258 | |
402c5e15 | 259 | const struct xen_pcibk_backend xen_pcibk_vpci_backend = { |
2ebdc426 KRW |
260 | .name = "vpci", |
261 | .init = __xen_pcibk_init_devices, | |
262 | .free = __xen_pcibk_release_devices, | |
263 | .find = __xen_pcibk_get_pcifront_dev, | |
264 | .publish = __xen_pcibk_publish_pci_roots, | |
265 | .release = __xen_pcibk_release_pci_dev, | |
266 | .add = __xen_pcibk_add_pci_dev, | |
267 | .get = __xen_pcibk_get_pci_dev, | |
268 | }; |