This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / pciback / vpci.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>
6  */
7
8 #include <linux/list.h>
9 #include <linux/slab.h>
10 #include <linux/pci.h>
11 #include <linux/spinlock.h>
12 #include "pciback.h"
13
14 #define PCI_SLOT_MAX 32
15
16 struct vpci_dev_data {
17         /* Access to dev_list must be protected by lock */
18         struct list_head dev_list[PCI_SLOT_MAX];
19         spinlock_t lock;
20 };
21
22 static inline struct list_head *list_first(struct list_head *head)
23 {
24         return head->next;
25 }
26
27 struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
28                                     unsigned int domain, unsigned int bus,
29                                     unsigned int devfn)
30 {
31         struct pci_dev_entry *entry;
32         struct pci_dev *dev = NULL;
33         struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
34         unsigned long flags;
35
36         if (domain != 0 || bus != 0)
37                 return NULL;
38
39         if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
40                 spin_lock_irqsave(&vpci_dev->lock, flags);
41
42                 list_for_each_entry(entry,
43                                     &vpci_dev->dev_list[PCI_SLOT(devfn)],
44                                     list) {
45                         if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
46                                 dev = entry->dev;
47                                 break;
48                         }
49                 }
50
51                 spin_unlock_irqrestore(&vpci_dev->lock, flags);
52         }
53         return dev;
54 }
55
56 static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
57 {
58         if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
59             && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
60                 return 1;
61
62         return 0;
63 }
64
65 int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
66 {
67         int err = 0, slot;
68         struct pci_dev_entry *t, *dev_entry;
69         struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
70         unsigned long flags;
71
72         if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
73                 err = -EFAULT;
74                 xenbus_dev_fatal(pdev->xdev, err,
75                                  "Can't export bridges on the virtual PCI bus");
76                 goto out;
77         }
78
79         dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
80         if (!dev_entry) {
81                 err = -ENOMEM;
82                 xenbus_dev_fatal(pdev->xdev, err,
83                                  "Error adding entry to virtual PCI bus");
84                 goto out;
85         }
86
87         dev_entry->dev = dev;
88
89         spin_lock_irqsave(&vpci_dev->lock, flags);
90
91         /* Keep multi-function devices together on the virtual PCI bus */
92         for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
93                 if (!list_empty(&vpci_dev->dev_list[slot])) {
94                         t = list_entry(list_first(&vpci_dev->dev_list[slot]),
95                                        struct pci_dev_entry, list);
96
97                         if (match_slot(dev, t->dev)) {
98                                 pr_info("pciback: vpci: %s: "
99                                         "assign to virtual slot %d func %d\n",
100                                         pci_name(dev), slot,
101                                         PCI_FUNC(dev->devfn));
102                                 list_add_tail(&dev_entry->list,
103                                               &vpci_dev->dev_list[slot]);
104                                 goto unlock;
105                         }
106                 }
107         }
108
109         /* Assign to a new slot on the virtual PCI bus */
110         for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
111                 if (list_empty(&vpci_dev->dev_list[slot])) {
112                         printk(KERN_INFO
113                                "pciback: vpci: %s: assign to virtual slot %d\n",
114                                pci_name(dev), slot);
115                         list_add_tail(&dev_entry->list,
116                                       &vpci_dev->dev_list[slot]);
117                         goto unlock;
118                 }
119         }
120
121         err = -ENOMEM;
122         xenbus_dev_fatal(pdev->xdev, err,
123                          "No more space on root virtual PCI bus");
124
125       unlock:
126         spin_unlock_irqrestore(&vpci_dev->lock, flags);
127       out:
128         return err;
129 }
130
131 void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
132 {
133         int slot;
134         struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
135         struct pci_dev *found_dev = NULL;
136         unsigned long flags;
137
138         spin_lock_irqsave(&vpci_dev->lock, flags);
139
140         for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
141                 struct pci_dev_entry *e, *tmp;
142                 list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
143                                          list) {
144                         if (e->dev == dev) {
145                                 list_del(&e->list);
146                                 found_dev = e->dev;
147                                 kfree(e);
148                                 goto out;
149                         }
150                 }
151         }
152
153       out:
154         spin_unlock_irqrestore(&vpci_dev->lock, flags);
155
156         if (found_dev)
157                 pcistub_put_pci_dev(found_dev);
158 }
159
160 int pciback_init_devices(struct pciback_device *pdev)
161 {
162         int slot;
163         struct vpci_dev_data *vpci_dev;
164
165         vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
166         if (!vpci_dev)
167                 return -ENOMEM;
168
169         spin_lock_init(&vpci_dev->lock);
170
171         for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
172                 INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
173         }
174
175         pdev->pci_dev_data = vpci_dev;
176
177         return 0;
178 }
179
180 int pciback_publish_pci_roots(struct pciback_device *pdev,
181                               publish_pci_root_cb publish_cb)
182 {
183         /* The Virtual PCI bus has only one root */
184         return publish_cb(pdev, 0, 0);
185 }
186
187 void pciback_release_devices(struct pciback_device *pdev)
188 {
189         int slot;
190         struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
191
192         for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
193                 struct pci_dev_entry *e, *tmp;
194                 list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
195                                          list) {
196                         list_del(&e->list);
197                         pcistub_put_pci_dev(e->dev);
198                         kfree(e);
199                 }
200         }
201
202         kfree(vpci_dev);
203         pdev->pci_dev_data = NULL;
204 }