blob: 7d5c192a150588023b6ce62c6817e4ef06aa4399 [file] [log] [blame]
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -04001/*
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
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -040015#define DRV_NAME "xen-pciback"
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -040016
17struct vpci_dev_data {
18 /* Access to dev_list must be protected by lock */
19 struct list_head dev_list[PCI_SLOT_MAX];
20 spinlock_t lock;
21};
22
23static inline struct list_head *list_first(struct list_head *head)
24{
25 return head->next;
26}
27
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -040028struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
29 unsigned int domain, unsigned int bus,
30 unsigned int devfn)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -040031{
32 struct pci_dev_entry *entry;
33 struct pci_dev *dev = NULL;
34 struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
35 unsigned long flags;
36
37 if (domain != 0 || bus != 0)
38 return NULL;
39
40 if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
41 spin_lock_irqsave(&vpci_dev->lock, flags);
42
43 list_for_each_entry(entry,
44 &vpci_dev->dev_list[PCI_SLOT(devfn)],
45 list) {
46 if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
47 dev = entry->dev;
48 break;
49 }
50 }
51
52 spin_unlock_irqrestore(&vpci_dev->lock, flags);
53 }
54 return dev;
55}
56
57static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
58{
59 if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
60 && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
61 return 1;
62
63 return 0;
64}
65
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -040066int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev,
67 int devid, publish_pci_dev_cb publish_cb)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -040068{
69 int err = 0, slot, func = -1;
70 struct pci_dev_entry *t, *dev_entry;
71 struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
72 unsigned long flags;
73
74 if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
75 err = -EFAULT;
76 xenbus_dev_fatal(pdev->xdev, err,
77 "Can't export bridges on the virtual PCI bus");
78 goto out;
79 }
80
81 dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
82 if (!dev_entry) {
83 err = -ENOMEM;
84 xenbus_dev_fatal(pdev->xdev, err,
85 "Error adding entry to virtual PCI bus");
86 goto out;
87 }
88
89 dev_entry->dev = dev;
90
91 spin_lock_irqsave(&vpci_dev->lock, flags);
92
93 /* Keep multi-function devices together on the virtual PCI bus */
94 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
95 if (!list_empty(&vpci_dev->dev_list[slot])) {
96 t = list_entry(list_first(&vpci_dev->dev_list[slot]),
97 struct pci_dev_entry, list);
98
99 if (match_slot(dev, t->dev)) {
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400100 pr_info(DRV_NAME ": vpci: %s: "
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400101 "assign to virtual slot %d func %d\n",
102 pci_name(dev), slot,
103 PCI_FUNC(dev->devfn));
104 list_add_tail(&dev_entry->list,
105 &vpci_dev->dev_list[slot]);
106 func = PCI_FUNC(dev->devfn);
107 goto unlock;
108 }
109 }
110 }
111
112 /* Assign to a new slot on the virtual PCI bus */
113 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
114 if (list_empty(&vpci_dev->dev_list[slot])) {
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400115 printk(KERN_INFO DRV_NAME
116 ": vpci: %s: assign to virtual slot %d\n",
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400117 pci_name(dev), slot);
118 list_add_tail(&dev_entry->list,
119 &vpci_dev->dev_list[slot]);
120 func = PCI_FUNC(dev->devfn);
121 goto unlock;
122 }
123 }
124
125 err = -ENOMEM;
126 xenbus_dev_fatal(pdev->xdev, err,
127 "No more space on root virtual PCI bus");
128
129unlock:
130 spin_unlock_irqrestore(&vpci_dev->lock, flags);
131
132 /* Publish this device. */
133 if (!err)
134 err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
135
136out:
137 return err;
138}
139
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400140void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
141 struct pci_dev *dev)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400142{
143 int slot;
144 struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
145 struct pci_dev *found_dev = NULL;
146 unsigned long flags;
147
148 spin_lock_irqsave(&vpci_dev->lock, flags);
149
150 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
151 struct pci_dev_entry *e, *tmp;
152 list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
153 list) {
154 if (e->dev == dev) {
155 list_del(&e->list);
156 found_dev = e->dev;
157 kfree(e);
158 goto out;
159 }
160 }
161 }
162
163out:
164 spin_unlock_irqrestore(&vpci_dev->lock, flags);
165
166 if (found_dev)
167 pcistub_put_pci_dev(found_dev);
168}
169
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400170int xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400171{
172 int slot;
173 struct vpci_dev_data *vpci_dev;
174
175 vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
176 if (!vpci_dev)
177 return -ENOMEM;
178
179 spin_lock_init(&vpci_dev->lock);
180
181 for (slot = 0; slot < PCI_SLOT_MAX; slot++)
182 INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
183
184 pdev->pci_dev_data = vpci_dev;
185
186 return 0;
187}
188
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400189int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
190 publish_pci_root_cb publish_cb)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400191{
192 /* The Virtual PCI bus has only one root */
193 return publish_cb(pdev, 0, 0);
194}
195
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400196void xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400197{
198 int slot;
199 struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
200
201 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
202 struct pci_dev_entry *e, *tmp;
203 list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
204 list) {
205 list_del(&e->list);
206 pcistub_put_pci_dev(e->dev);
207 kfree(e);
208 }
209 }
210
211 kfree(vpci_dev);
212 pdev->pci_dev_data = NULL;
213}
214
Konrad Rzeszutek Wilka92336a2011-07-19 19:40:51 -0400215int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
216 struct xen_pcibk_device *pdev,
217 unsigned int *domain, unsigned int *bus,
218 unsigned int *devfn)
Konrad Rzeszutek Wilk30edc142009-10-13 17:22:20 -0400219{
220 struct pci_dev_entry *entry;
221 struct pci_dev *dev = NULL;
222 struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
223 unsigned long flags;
224 int found = 0, slot;
225
226 spin_lock_irqsave(&vpci_dev->lock, flags);
227 for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
228 list_for_each_entry(entry,
229 &vpci_dev->dev_list[slot],
230 list) {
231 dev = entry->dev;
232 if (dev && dev->bus->number == pcidev->bus->number
233 && pci_domain_nr(dev->bus) ==
234 pci_domain_nr(pcidev->bus)
235 && dev->devfn == pcidev->devfn) {
236 found = 1;
237 *domain = 0;
238 *bus = 0;
239 *devfn = PCI_DEVFN(slot,
240 PCI_FUNC(pcidev->devfn));
241 }
242 }
243 }
244 spin_unlock_irqrestore(&vpci_dev->lock, flags);
245 return found;
246}