ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/pciback/slot.c @ 10997:9e061d0dc394

[PCI] back: New virtual pci backend: slot

This backend use a slot per pci device. Contrary to vpci two functions from
one slot appear as two slots. This is useful on ia64 because it doesn't scan
functions > 0 if function 0 does not exist.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author kaf24@firebug.cl.cam.ac.uk
date Tue Aug 08 10:17:42 2006 +0100 (2006-08-08)
parents
children
line source
1 /*
2 * PCI Backend - Provides a Virtual PCI bus (with real devices)
3 * to the frontend
4 *
5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c)
6 * Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c
7 */
9 #include <linux/list.h>
10 #include <linux/slab.h>
11 #include <linux/pci.h>
12 #include <linux/spinlock.h>
13 #include "pciback.h"
15 /* There are at most 32 slots in a pci bus. */
16 #define PCI_SLOT_MAX 32
18 #define PCI_BUS_NBR 2
20 struct slot_dev_data {
21 /* Access to dev_list must be protected by lock */
22 struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
23 spinlock_t lock;
24 };
26 struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
27 unsigned int domain, unsigned int bus,
28 unsigned int devfn)
29 {
30 struct pci_dev *dev = NULL;
31 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
32 unsigned long flags;
34 if (domain != 0 || PCI_FUNC(devfn) != 0)
35 return NULL;
37 if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
38 return NULL;
40 spin_lock_irqsave(&slot_dev->lock, flags);
41 dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
42 spin_unlock_irqrestore(&slot_dev->lock, flags);
44 return dev;
45 }
47 int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
48 {
49 int err = 0, slot, bus;
50 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
51 unsigned long flags;
53 if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
54 err = -EFAULT;
55 xenbus_dev_fatal(pdev->xdev, err,
56 "Can't export bridges on the virtual PCI bus");
57 goto out;
58 }
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 printk(KERN_INFO
67 "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
68 pci_name(dev), slot, bus);
69 slot_dev->slots[bus][slot] = dev;
70 goto unlock;
71 }
72 }
74 err = -ENOMEM;
75 xenbus_dev_fatal(pdev->xdev, err,
76 "No more space on root virtual PCI bus");
78 unlock:
79 spin_unlock_irqrestore(&slot_dev->lock, flags);
80 out:
81 return err;
82 }
84 void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
85 {
86 int slot, bus;
87 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
88 struct pci_dev *found_dev = NULL;
89 unsigned long flags;
91 spin_lock_irqsave(&slot_dev->lock, flags);
93 for (bus = 0; bus < PCI_BUS_NBR; bus++)
94 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
95 if (slot_dev->slots[bus][slot] == dev) {
96 slot_dev->slots[bus][slot] = NULL;
97 found_dev = dev;
98 goto out;
99 }
100 }
102 out:
103 spin_unlock_irqrestore(&slot_dev->lock, flags);
105 if (found_dev)
106 pcistub_put_pci_dev(found_dev);
107 }
109 int pciback_init_devices(struct pciback_device *pdev)
110 {
111 int slot, bus;
112 struct slot_dev_data *slot_dev;
114 slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
115 if (!slot_dev)
116 return -ENOMEM;
118 spin_lock_init(&slot_dev->lock);
120 for (bus = 0; bus < PCI_BUS_NBR; bus++)
121 for (slot = 0; slot < PCI_SLOT_MAX; slot++)
122 slot_dev->slots[bus][slot] = NULL;
124 pdev->pci_dev_data = slot_dev;
126 return 0;
127 }
129 int pciback_publish_pci_roots(struct pciback_device *pdev,
130 publish_pci_root_cb publish_cb)
131 {
132 /* The Virtual PCI bus has only one root */
133 return publish_cb(pdev, 0, 0);
134 }
136 void pciback_release_devices(struct pciback_device *pdev)
137 {
138 int slot, bus;
139 struct slot_dev_data *slot_dev = pdev->pci_dev_data;
140 struct pci_dev *dev;
142 for (bus = 0; bus < PCI_BUS_NBR; bus++)
143 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
144 dev = slot_dev->slots[bus][slot];
145 if (dev != NULL)
146 pcistub_put_pci_dev(dev);
147 }
149 kfree(slot_dev);
150 pdev->pci_dev_data = NULL;
151 }