2 * PCI Backend - Provides a Virtual PCI bus (with real devices)
5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c)
6 * Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c
9 #include <linux/spinlock.h>
12 /* There are at most 32 slots in a pci bus. */
13 #define PCI_SLOT_MAX 32
17 struct slot_dev_data {
18 /* Access to dev_list must be protected by lock */
19 struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
23 static struct pci_dev *_xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
28 struct pci_dev *dev = NULL;
29 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
32 if (domain != 0 || PCI_FUNC(devfn) != 0)
35 if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
38 spin_lock_irqsave(&slot_dev->lock, flags);
39 dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
40 spin_unlock_irqrestore(&slot_dev->lock, flags);
45 static int _xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
46 struct pci_dev *dev, int devid,
47 publish_pci_dev_cb publish_cb)
49 int err = 0, slot, bus;
50 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
53 if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
55 xenbus_dev_fatal(pdev->xdev, err,
56 "Can't export bridges on the virtual PCI bus");
60 spin_lock_irqsave(&slot_dev->lock, flags);
62 /* Assign to a new slot on the virtual PCI bus */
63 for (bus = 0; bus < PCI_BUS_NBR; bus++)
64 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
65 if (slot_dev->slots[bus][slot] == NULL) {
66 pr_info("pciback: slot: %s: assign to"
67 " virtual slot %d, bus %d\n",
68 pci_name(dev), slot, bus);
69 slot_dev->slots[bus][slot] = dev;
75 xenbus_dev_fatal(pdev->xdev, err,
76 "No more space on root virtual PCI bus");
79 spin_unlock_irqrestore(&slot_dev->lock, flags);
81 /* Publish this device. */
83 err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
89 static void _xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
93 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
94 struct pci_dev *found_dev = NULL;
97 spin_lock_irqsave(&slot_dev->lock, flags);
99 for (bus = 0; bus < PCI_BUS_NBR; bus++)
100 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
101 if (slot_dev->slots[bus][slot] == dev) {
102 slot_dev->slots[bus][slot] = NULL;
109 spin_unlock_irqrestore(&slot_dev->lock, flags);
112 pcistub_put_pci_dev(found_dev);
115 static int _xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
118 struct slot_dev_data *slot_dev;
120 slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
124 spin_lock_init(&slot_dev->lock);
126 for (bus = 0; bus < PCI_BUS_NBR; bus++)
127 for (slot = 0; slot < PCI_SLOT_MAX; slot++)
128 slot_dev->slots[bus][slot] = NULL;
130 pdev->pci_dev_data = slot_dev;
135 static int _xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
136 publish_pci_root_cb publish_cb)
138 /* The Virtual PCI bus has only one root */
139 return publish_cb(pdev, 0, 0);
142 static void _xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
145 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
148 for (bus = 0; bus < PCI_BUS_NBR; bus++)
149 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
150 dev = slot_dev->slots[bus][slot];
152 pcistub_put_pci_dev(dev);
156 pdev->pci_dev_data = NULL;
159 static int _xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
160 struct xen_pcibk_device *pdev,
161 unsigned int *domain,
162 unsigned int *bus, unsigned int *devfn)
165 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
170 spin_lock_irqsave(&slot_dev->lock, flags);
172 for (busnr = 0; busnr < PCI_BUS_NBR; bus++)
173 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
174 dev = slot_dev->slots[busnr][slot];
175 if (dev && dev->bus->number == pcidev->bus->number
176 && dev->devfn == pcidev->devfn
177 && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)) {
181 *devfn = PCI_DEVFN(slot,0);
186 spin_unlock_irqrestore(&slot_dev->lock, flags);
191 const struct xen_pcibk_backend xen_pcibk_slot_backend = {
193 .init = _xen_pcibk_init_devices,
194 .free = _xen_pcibk_release_devices,
195 .find = _xen_pcibk_get_pcifront_dev,
196 .publish = _xen_pcibk_publish_pci_roots,
197 .release = _xen_pcibk_release_pci_dev,
198 .add = _xen_pcibk_add_pci_dev,
199 .get = _xen_pcibk_get_pci_dev,