2 * PCI Backend - Provides restricted access to the real PCI bus topology
5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
8 #include <linux/list.h>
10 #include <linux/spinlock.h>
13 struct passthrough_dev_data
{
14 /* Access to dev_list must be protected by lock */
15 struct list_head dev_list
;
19 static struct pci_dev
*__xen_pcibk_get_pci_dev(struct xen_pcibk_device
*pdev
,
24 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
25 struct pci_dev_entry
*dev_entry
;
26 struct pci_dev
*dev
= NULL
;
29 spin_lock_irqsave(&dev_data
->lock
, flags
);
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 spin_unlock_irqrestore(&dev_data
->lock
, flags
);
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
;
52 unsigned int domain
, bus
, devfn
;
55 dev_entry
= kmalloc(sizeof(*dev_entry
), GFP_KERNEL
);
60 spin_lock_irqsave(&dev_data
->lock
, flags
);
61 list_add_tail(&dev_entry
->list
, &dev_data
->dev_list
);
62 spin_unlock_irqrestore(&dev_data
->lock
, flags
);
64 /* Publish this device. */
65 domain
= (unsigned int)pci_domain_nr(dev
->bus
);
66 bus
= (unsigned int)dev
->bus
->number
;
68 err
= publish_cb(pdev
, domain
, bus
, devfn
, devid
);
73 static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device
*pdev
,
76 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
77 struct pci_dev_entry
*dev_entry
, *t
;
78 struct pci_dev
*found_dev
= NULL
;
81 spin_lock_irqsave(&dev_data
->lock
, flags
);
83 list_for_each_entry_safe(dev_entry
, t
, &dev_data
->dev_list
, list
) {
84 if (dev_entry
->dev
== dev
) {
85 list_del(&dev_entry
->list
);
86 found_dev
= dev_entry
->dev
;
91 spin_unlock_irqrestore(&dev_data
->lock
, flags
);
94 pcistub_put_pci_dev(found_dev
);
97 static int __xen_pcibk_init_devices(struct xen_pcibk_device
*pdev
)
99 struct passthrough_dev_data
*dev_data
;
101 dev_data
= kmalloc(sizeof(*dev_data
), GFP_KERNEL
);
105 spin_lock_init(&dev_data
->lock
);
107 INIT_LIST_HEAD(&dev_data
->dev_list
);
109 pdev
->pci_dev_data
= dev_data
;
114 static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device
*pdev
,
115 publish_pci_root_cb publish_root_cb
)
118 struct passthrough_dev_data
*dev_data
= pdev
->pci_dev_data
;
119 struct pci_dev_entry
*dev_entry
, *e
, *tmp
;
122 unsigned int domain
, bus
;
124 spin_lock(&dev_data
->lock
);
126 list_for_each_entry_safe(dev_entry
, tmp
, &dev_data
->dev_list
, list
) {
127 /* Only publish this device as a root if none of its
128 * parent bridges are exported
131 dev
= dev_entry
->dev
->bus
->self
;
132 for (; !found
&& dev
!= NULL
; dev
= dev
->bus
->self
) {
133 list_for_each_entry(e
, &dev_data
->dev_list
, list
) {
141 domain
= (unsigned int)pci_domain_nr(dev_entry
->dev
->bus
);
142 bus
= (unsigned int)dev_entry
->dev
->bus
->number
;
145 spin_unlock(&dev_data
->lock
);
146 err
= publish_root_cb(pdev
, domain
, bus
);
149 spin_lock(&dev_data
->lock
);
154 spin_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 list_del(&dev_entry
->list
);
166 pcistub_put_pci_dev(dev_entry
->dev
);
171 pdev
->pci_dev_data
= NULL
;
174 static int __xen_pcibk_get_pcifront_dev(struct pci_dev
*pcidev
,
175 struct xen_pcibk_device
*pdev
,
176 unsigned int *domain
, unsigned int *bus
,
179 *domain
= pci_domain_nr(pcidev
->bus
);
180 *bus
= pcidev
->bus
->number
;
181 *devfn
= pcidev
->devfn
;
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
,