This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / pciback / slot.c
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  */
8
9 #include <linux/list.h>
10 #include <linux/slab.h>
11 #include <linux/pci.h>
12 #include <linux/spinlock.h>
13 #include "pciback.h"
14
15 /* There are at most 32 slots in a pci bus.  */
16 #define PCI_SLOT_MAX 32
17
18 #define PCI_BUS_NBR 2
19
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 };
25
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;
33
34         if (domain != 0 || PCI_FUNC(devfn) != 0)
35                 return NULL;
36
37         if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
38                 return NULL;
39
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);
43
44         return dev;
45 }
46
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;
52
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         }
59
60         spin_lock_irqsave(&slot_dev->lock, flags);
61
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                 }
73
74         err = -ENOMEM;
75         xenbus_dev_fatal(pdev->xdev, err,
76                          "No more space on root virtual PCI bus");
77
78       unlock:
79         spin_unlock_irqrestore(&slot_dev->lock, flags);
80       out:
81         return err;
82 }
83
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;
90
91         spin_lock_irqsave(&slot_dev->lock, flags);
92
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                 }
101
102       out:
103         spin_unlock_irqrestore(&slot_dev->lock, flags);
104
105         if (found_dev)
106                 pcistub_put_pci_dev(found_dev);
107 }
108
109 int pciback_init_devices(struct pciback_device *pdev)
110 {
111         int slot, bus;
112         struct slot_dev_data *slot_dev;
113
114         slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
115         if (!slot_dev)
116                 return -ENOMEM;
117
118         spin_lock_init(&slot_dev->lock);
119
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;
123
124         pdev->pci_dev_data = slot_dev;
125
126         return 0;
127 }
128
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 }
135
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;
141
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                 }
148
149         kfree(slot_dev);
150         pdev->pci_dev_data = NULL;
151 }