Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
587 | giacomo | 1 | /* |
2 | * drivers/pci/bus.c |
||
3 | * |
||
4 | * From setup-res.c, by: |
||
5 | * Dave Rusling (david.rusling@reo.mts.dec.com) |
||
6 | * David Mosberger (davidm@cs.arizona.edu) |
||
7 | * David Miller (davem@redhat.com) |
||
8 | * Ivan Kokshaysky (ink@jurassic.park.msu.ru) |
||
9 | */ |
||
10 | #include <linuxcomp.h> |
||
11 | |||
12 | #include <linux/module.h> |
||
13 | #include <linux/kernel.h> |
||
14 | #include <linux/pci.h> |
||
15 | #include <linux/errno.h> |
||
16 | #include <linux/ioport.h> |
||
17 | #include <linux/proc_fs.h> |
||
18 | #include <linux/init.h> |
||
19 | |||
20 | #include "pci.h" |
||
21 | |||
22 | /** |
||
23 | * pci_bus_alloc_resource - allocate a resource from a parent bus |
||
24 | * @bus: PCI bus |
||
25 | * @res: resource to allocate |
||
26 | * @size: size of resource to allocate |
||
27 | * @align: alignment of resource to allocate |
||
28 | * @min: minimum /proc/iomem address to allocate |
||
29 | * @type_mask: IORESOURCE_* type flags |
||
30 | * @alignf: resource alignment function |
||
31 | * @alignf_data: data argument for resource alignment function |
||
32 | * |
||
33 | * Given the PCI bus a device resides on, the size, minimum address, |
||
34 | * alignment and type, try to find an acceptable resource allocation |
||
35 | * for a specific device resource. |
||
36 | */ |
||
37 | int |
||
38 | pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, |
||
39 | unsigned long size, unsigned long align, unsigned long min, |
||
40 | unsigned int type_mask, |
||
41 | void (*alignf)(void *, struct resource *, |
||
42 | unsigned long, unsigned long), |
||
43 | void *alignf_data) |
||
44 | { |
||
45 | int i, ret = -ENOMEM; |
||
46 | |||
47 | type_mask |= IORESOURCE_IO | IORESOURCE_MEM; |
||
48 | |||
49 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { |
||
50 | struct resource *r = bus->resource[i]; |
||
51 | if (!r) |
||
52 | continue; |
||
53 | |||
54 | /* type_mask must match */ |
||
55 | if ((res->flags ^ r->flags) & type_mask) |
||
56 | continue; |
||
57 | |||
58 | /* We cannot allocate a non-prefetching resource |
||
59 | from a pre-fetching area */ |
||
60 | if ((r->flags & IORESOURCE_PREFETCH) && |
||
61 | !(res->flags & IORESOURCE_PREFETCH)) |
||
62 | continue; |
||
63 | |||
64 | /* Ok, try it out.. */ |
||
65 | ret = allocate_resource(r, res, size, min, -1, align, |
||
66 | alignf, alignf_data); |
||
67 | if (ret == 0) |
||
68 | break; |
||
69 | } |
||
70 | return ret; |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * pci_bus_add_devices - insert newly discovered PCI devices |
||
75 | * @bus: bus to check for new devices |
||
76 | * |
||
77 | * Add newly discovered PCI devices (which are on the bus->devices |
||
78 | * list) to the global PCI device list, add the sysfs and procfs |
||
79 | * entries. Where a bridge is found, add the discovered bus to |
||
80 | * the parents list of child buses, and recurse (breadth-first |
||
81 | * to be compatible with 2.4) |
||
82 | * |
||
83 | * Call hotplug for each new devices. |
||
84 | */ |
||
85 | void __devinit pci_bus_add_devices(struct pci_bus *bus) |
||
86 | { |
||
87 | struct pci_dev *dev; |
||
88 | |||
89 | list_for_each_entry(dev, &bus->devices, bus_list) { |
||
90 | /* |
||
91 | * Skip already-present devices (which are on the |
||
92 | * global device list.) |
||
93 | */ |
||
94 | |||
95 | if (!list_empty(&dev->global_list)) |
||
96 | continue; |
||
97 | |||
98 | device_add(&dev->dev); |
||
99 | |||
100 | spin_lock(&pci_bus_lock); |
||
101 | list_add_tail(&dev->global_list, &pci_devices); |
||
102 | spin_unlock(&pci_bus_lock); |
||
103 | |||
104 | pci_proc_attach_device(dev); |
||
105 | |||
106 | } |
||
107 | |||
108 | list_for_each_entry(dev, &bus->devices, bus_list) { |
||
109 | |||
110 | BUG_ON(list_empty(&dev->global_list)); |
||
111 | |||
112 | /* |
||
113 | * If there is an unattached subordinate bus, attach |
||
114 | * it and then scan for unattached PCI devices. |
||
115 | */ |
||
116 | if (dev->subordinate && list_empty(&dev->subordinate->node)) { |
||
117 | |||
118 | spin_lock(&pci_bus_lock); |
||
119 | list_add_tail(&dev->subordinate->node, &dev->bus->children); |
||
120 | spin_unlock(&pci_bus_lock); |
||
121 | pci_bus_add_devices(dev->subordinate); |
||
122 | |||
123 | } |
||
124 | } |
||
125 | } |
||
126 | |||
127 | void pci_enable_bridges(struct pci_bus *bus) |
||
128 | { |
||
129 | struct pci_dev *dev; |
||
130 | |||
131 | list_for_each_entry(dev, &bus->devices, bus_list) { |
||
132 | if (dev->subordinate) { |
||
133 | pci_enable_device(dev); |
||
134 | pci_set_master(dev); |
||
135 | pci_enable_bridges(dev->subordinate); |
||
136 | } |
||
137 | } |
||
138 | } |
||
139 | |||
140 | EXPORT_SYMBOL(pci_bus_add_devices); |
||
141 | EXPORT_SYMBOL(pci_enable_bridges); |