source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/drivers/xen/pciback/slot.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 3.6 KB
Line 
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
20struct 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
26struct 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
47int 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
84void 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
109int 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
129int 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
136void 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}
Note: See TracBrowser for help on using the repository browser.