1 // SPDX-License-Identifier: GPL-2.0
3 * PCI Backend - Provides restricted access to the real PCI bus topology
6 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
9 #include <linux/list.h>
10 #include <linux/pci.h>
11 #include <linux/mutex.h>
14 struct passthrough_dev_data
{
15 /* Access to dev_list must be protected by lock */
16 struct list_head dev_list
;
20 static struct pci_dev
*__xen_pcibk_get_pci_dev(struct xen_pcibk_device
*pdev
,
25 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
26 struct pci_dev_entry
*dev_entry
;
27 struct pci_dev
*dev
= NULL
;
29 mutex_lock(&dev_data
->lock
);
31 list_for_each_entry(dev_entry
, &dev_data
->dev_list
, list
) {
32 if (domain
== (unsigned int)pci_domain_nr(dev_entry
->dev
->bus
)
33 && bus
== (unsigned int)dev_entry
->dev
->bus
->number
34 && devfn
== dev_entry
->dev
->devfn
) {
40 mutex_unlock(&dev_data
->lock
);
45 static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device
*pdev
,
47 int devid
, publish_pci_dev_cb publish_cb
)
49 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
50 struct pci_dev_entry
*dev_entry
;
51 unsigned int domain
, bus
, devfn
;
54 dev_entry
= kmalloc(sizeof(*dev_entry
), GFP_KERNEL
);
59 mutex_lock(&dev_data
->lock
);
60 list_add_tail(&dev_entry
->list
, &dev_data
->dev_list
);
61 mutex_unlock(&dev_data
->lock
);
63 /* Publish this device. */
64 domain
= (unsigned int)pci_domain_nr(dev
->bus
);
65 bus
= (unsigned int)dev
->bus
->number
;
67 err
= publish_cb(pdev
, domain
, bus
, devfn
, devid
);
72 static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device
*pdev
,
73 struct pci_dev
*dev
, bool lock
)
75 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
76 struct pci_dev_entry
*dev_entry
, *t
;
77 struct pci_dev
*found_dev
= NULL
;
79 mutex_lock(&dev_data
->lock
);
81 list_for_each_entry_safe(dev_entry
, t
, &dev_data
->dev_list
, list
) {
82 if (dev_entry
->dev
== dev
) {
83 list_del(&dev_entry
->list
);
84 found_dev
= dev_entry
->dev
;
89 mutex_unlock(&dev_data
->lock
);
93 device_lock(&found_dev
->dev
);
94 pcistub_put_pci_dev(found_dev
);
96 device_unlock(&found_dev
->dev
);
100 static int __xen_pcibk_init_devices(struct xen_pcibk_device
*pdev
)
102 struct passthrough_dev_data
*dev_data
;
104 dev_data
= kmalloc(sizeof(*dev_data
), GFP_KERNEL
);
108 mutex_init(&dev_data
->lock
);
110 INIT_LIST_HEAD(&dev_data
->dev_list
);
112 pdev
->pci_dev_data
= dev_data
;
117 static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device
*pdev
,
118 publish_pci_root_cb publish_root_cb
)
121 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
122 struct pci_dev_entry
*dev_entry
, *e
;
125 unsigned int domain
, bus
;
127 mutex_lock(&dev_data
->lock
);
129 list_for_each_entry(dev_entry
, &dev_data
->dev_list
, list
) {
130 /* Only publish this device as a root if none of its
131 * parent bridges are exported
134 dev
= dev_entry
->dev
->bus
->self
;
135 for (; !found
&& dev
!= NULL
; dev
= dev
->bus
->self
) {
136 list_for_each_entry(e
, &dev_data
->dev_list
, list
) {
144 domain
= (unsigned int)pci_domain_nr(dev_entry
->dev
->bus
);
145 bus
= (unsigned int)dev_entry
->dev
->bus
->number
;
148 err
= publish_root_cb(pdev
, domain
, bus
);
154 mutex_unlock(&dev_data
->lock
);
159 static void __xen_pcibk_release_devices(struct xen_pcibk_device
*pdev
)
161 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
162 struct pci_dev_entry
*dev_entry
, *t
;
164 list_for_each_entry_safe(dev_entry
, t
, &dev_data
->dev_list
, list
) {
165 struct pci_dev
*dev
= dev_entry
->dev
;
166 list_del(&dev_entry
->list
);
167 device_lock(&dev
->dev
);
168 pcistub_put_pci_dev(dev
);
169 device_unlock(&dev
->dev
);
174 pdev
->pci_dev_data
= NULL
;
177 static int __xen_pcibk_get_pcifront_dev(struct pci_dev
*pcidev
,
178 struct xen_pcibk_device
*pdev
,
179 unsigned int *domain
, unsigned int *bus
,
182 *domain
= pci_domain_nr(pcidev
->bus
);
183 *bus
= pcidev
->bus
->number
;
184 *devfn
= pcidev
->devfn
;
188 const struct xen_pcibk_backend xen_pcibk_passthrough_backend
= {
189 .name
= "passthrough",
190 .init
= __xen_pcibk_init_devices
,
191 .free
= __xen_pcibk_release_devices
,
192 .find
= __xen_pcibk_get_pcifront_dev
,
193 .publish
= __xen_pcibk_publish_pci_roots
,
194 .release
= __xen_pcibk_release_pci_dev
,
195 .add
= __xen_pcibk_add_pci_dev
,
196 .get
= __xen_pcibk_get_pci_dev
,