aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/rpaphp_pci.c
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2006-02-02 01:12:54 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-02-02 01:12:54 -0500
commit18ee3610040a4c008ce08a40a5dd025241cc7e97 (patch)
tree32a996a5123726b63c31a1522f230933fb967a32 /drivers/pci/hotplug/rpaphp_pci.c
parente4e7b89280d1d666e2c09e5ad36cf071796c4c7e (diff)
parentb4103333d7904310d34de18d85e51e3d74f00a3b (diff)
Merge branch 'master'
Diffstat (limited to 'drivers/pci/hotplug/rpaphp_pci.c')
-rw-r--r--drivers/pci/hotplug/rpaphp_pci.c267
1 files changed, 6 insertions, 261 deletions
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 396b54b0c847..6f6cbede5135 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -32,37 +32,7 @@
32#include "../pci.h" /* for pci_add_new_bus */ 32#include "../pci.h" /* for pci_add_new_bus */
33#include "rpaphp.h" 33#include "rpaphp.h"
34 34
35static struct pci_bus *find_bus_among_children(struct pci_bus *bus, 35int rpaphp_get_sensor_state(struct slot *slot, int *state)
36 struct device_node *dn)
37{
38 struct pci_bus *child = NULL;
39 struct list_head *tmp;
40 struct device_node *busdn;
41
42 busdn = pci_bus_to_OF_node(bus);
43 if (busdn == dn)
44 return bus;
45
46 list_for_each(tmp, &bus->children) {
47 child = find_bus_among_children(pci_bus_b(tmp), dn);
48 if (child)
49 break;
50 }
51 return child;
52}
53
54struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
55{
56 struct pci_dn *pdn = dn->data;
57
58 if (!pdn || !pdn->phb || !pdn->phb->bus)
59 return NULL;
60
61 return find_bus_among_children(pdn->phb->bus, dn);
62}
63EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
64
65static int rpaphp_get_sensor_state(struct slot *slot, int *state)
66{ 36{
67 int rc; 37 int rc;
68 int setlevel; 38 int setlevel;
@@ -120,7 +90,7 @@ int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
120 /* config/unconfig adapter */ 90 /* config/unconfig adapter */
121 *value = slot->state; 91 *value = slot->state;
122 } else { 92 } else {
123 bus = rpaphp_find_pci_bus(slot->dn); 93 bus = pcibios_find_pci_bus(slot->dn);
124 if (bus && !list_empty(&bus->devices)) 94 if (bus && !list_empty(&bus->devices))
125 *value = CONFIGURED; 95 *value = CONFIGURED;
126 else 96 else
@@ -131,140 +101,6 @@ exit:
131 return rc; 101 return rc;
132} 102}
133 103
134/* Must be called before pci_bus_add_devices */
135void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
136{
137 struct pci_dev *dev;
138
139 list_for_each_entry(dev, &bus->devices, bus_list) {
140 /*
141 * Skip already-present devices (which are on the
142 * global device list.)
143 */
144 if (list_empty(&dev->global_list)) {
145 int i;
146
147 /* Need to setup IOMMU tables */
148 ppc_md.iommu_dev_setup(dev);
149
150 if(fix_bus)
151 pcibios_fixup_device_resources(dev, bus);
152 pci_read_irq_line(dev);
153 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
154 struct resource *r = &dev->resource[i];
155
156 if (r->parent || !r->start || !r->flags)
157 continue;
158 pci_claim_resource(dev, i);
159 }
160 }
161 }
162}
163
164static void rpaphp_eeh_add_bus_device(struct pci_bus *bus)
165{
166 struct pci_dev *dev;
167
168 list_for_each_entry(dev, &bus->devices, bus_list) {
169 eeh_add_device_late(dev);
170 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
171 struct pci_bus *subbus = dev->subordinate;
172 if (subbus)
173 rpaphp_eeh_add_bus_device (subbus);
174 }
175 }
176}
177
178static int rpaphp_pci_config_bridge(struct pci_dev *dev)
179{
180 u8 sec_busno;
181 struct pci_bus *child_bus;
182 struct pci_dev *child_dev;
183
184 dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
185
186 /* get busno of downstream bus */
187 pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
188
189 /* add to children of PCI bridge dev->bus */
190 child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
191 if (!child_bus) {
192 err("%s: could not add second bus\n", __FUNCTION__);
193 return -EIO;
194 }
195 sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
196 /* do pci_scan_child_bus */
197 pci_scan_child_bus(child_bus);
198
199 list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
200 eeh_add_device_late(child_dev);
201 }
202
203 /* fixup new pci devices without touching bus struct */
204 rpaphp_fixup_new_pci_devices(child_bus, 0);
205
206 /* Make the discovered devices available */
207 pci_bus_add_devices(child_bus);
208 return 0;
209}
210
211void rpaphp_init_new_devs(struct pci_bus *bus)
212{
213 rpaphp_fixup_new_pci_devices(bus, 0);
214 rpaphp_eeh_add_bus_device(bus);
215}
216EXPORT_SYMBOL_GPL(rpaphp_init_new_devs);
217
218/*****************************************************************************
219 rpaphp_pci_config_slot() will configure all devices under the
220 given slot->dn and return the the first pci_dev.
221 *****************************************************************************/
222static struct pci_dev *
223rpaphp_pci_config_slot(struct pci_bus *bus)
224{
225 struct device_node *dn = pci_bus_to_OF_node(bus);
226 struct pci_dev *dev = NULL;
227 int slotno;
228 int num;
229
230 dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
231 if (!dn || !dn->child)
232 return NULL;
233
234 if (_machine == PLATFORM_PSERIES_LPAR) {
235 of_scan_bus(dn, bus);
236 if (list_empty(&bus->devices)) {
237 err("%s: No new device found\n", __FUNCTION__);
238 return NULL;
239 }
240
241 rpaphp_init_new_devs(bus);
242 pci_bus_add_devices(bus);
243 dev = list_entry(&bus->devices, struct pci_dev, bus_list);
244 } else {
245 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
246
247 /* pci_scan_slot should find all children */
248 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
249 if (num) {
250 rpaphp_fixup_new_pci_devices(bus, 1);
251 pci_bus_add_devices(bus);
252 }
253 if (list_empty(&bus->devices)) {
254 err("%s: No new device found\n", __FUNCTION__);
255 return NULL;
256 }
257 list_for_each_entry(dev, &bus->devices, bus_list) {
258 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
259 rpaphp_pci_config_bridge(dev);
260
261 rpaphp_eeh_add_bus_device(bus);
262 }
263 }
264
265 return dev;
266}
267
268static void print_slot_pci_funcs(struct pci_bus *bus) 104static void print_slot_pci_funcs(struct pci_bus *bus)
269{ 105{
270 struct device_node *dn; 106 struct device_node *dn;
@@ -280,60 +116,6 @@ static void print_slot_pci_funcs(struct pci_bus *bus)
280 return; 116 return;
281} 117}
282 118
283int rpaphp_config_pci_adapter(struct pci_bus *bus)
284{
285 struct device_node *dn = pci_bus_to_OF_node(bus);
286 struct pci_dev *dev;
287 int rc = -ENODEV;
288
289 dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name);
290 if (!dn)
291 goto exit;
292
293 eeh_add_device_tree_early(dn);
294 dev = rpaphp_pci_config_slot(bus);
295 if (!dev) {
296 err("%s: can't find any devices.\n", __FUNCTION__);
297 goto exit;
298 }
299 print_slot_pci_funcs(bus);
300 rc = 0;
301exit:
302 dbg("Exit %s: rc=%d\n", __FUNCTION__, rc);
303 return rc;
304}
305EXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter);
306
307static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
308{
309 eeh_remove_device(dev);
310 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
311 struct pci_bus *bus = dev->subordinate;
312 struct list_head *ln;
313 if (!bus)
314 return;
315 for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
316 struct pci_dev *pdev = pci_dev_b(ln);
317 if (pdev)
318 rpaphp_eeh_remove_bus_device(pdev);
319 }
320
321 }
322 return;
323}
324
325int rpaphp_unconfig_pci_adapter(struct pci_bus *bus)
326{
327 struct pci_dev *dev, *tmp;
328
329 list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
330 rpaphp_eeh_remove_bus_device(dev);
331 pci_remove_bus_device(dev);
332 }
333 return 0;
334}
335EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter);
336
337static int setup_pci_hotplug_slot_info(struct slot *slot) 119static int setup_pci_hotplug_slot_info(struct slot *slot)
338{ 120{
339 struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info; 121 struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
@@ -370,7 +152,7 @@ static int setup_pci_slot(struct slot *slot)
370 struct pci_bus *bus; 152 struct pci_bus *bus;
371 153
372 BUG_ON(!dn); 154 BUG_ON(!dn);
373 bus = rpaphp_find_pci_bus(dn); 155 bus = pcibios_find_pci_bus(dn);
374 if (!bus) { 156 if (!bus) {
375 err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); 157 err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
376 goto exit_rc; 158 goto exit_rc;
@@ -395,10 +177,7 @@ static int setup_pci_slot(struct slot *slot)
395 if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { 177 if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
396 dbg("%s CONFIGURING pci adapter in slot[%s]\n", 178 dbg("%s CONFIGURING pci adapter in slot[%s]\n",
397 __FUNCTION__, slot->name); 179 __FUNCTION__, slot->name);
398 if (rpaphp_config_pci_adapter(slot->bus)) { 180 pcibios_add_pci_devices(slot->bus);
399 err("%s: CONFIG pci adapter failed\n", __FUNCTION__);
400 goto exit_rc;
401 }
402 181
403 } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { 182 } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
404 err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", 183 err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
@@ -420,7 +199,7 @@ exit_rc:
420 return -EINVAL; 199 return -EINVAL;
421} 200}
422 201
423int register_pci_slot(struct slot *slot) 202int rpaphp_register_pci_slot(struct slot *slot)
424{ 203{
425 int rc = -EINVAL; 204 int rc = -EINVAL;
426 205
@@ -428,42 +207,8 @@ int register_pci_slot(struct slot *slot)
428 goto exit_rc; 207 goto exit_rc;
429 if (setup_pci_slot(slot)) 208 if (setup_pci_slot(slot))
430 goto exit_rc; 209 goto exit_rc;
431 rc = register_slot(slot); 210 rc = rpaphp_register_slot(slot);
432exit_rc: 211exit_rc:
433 return rc; 212 return rc;
434} 213}
435 214
436int rpaphp_enable_pci_slot(struct slot *slot)
437{
438 int retval = 0, state;
439
440 retval = rpaphp_get_sensor_state(slot, &state);
441 if (retval)
442 goto exit;
443 dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
444 /* if slot is not empty, enable the adapter */
445 if (state == PRESENT) {
446 dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
447 retval = rpaphp_config_pci_adapter(slot->bus);
448 if (!retval) {
449 slot->state = CONFIGURED;
450 info("%s: devices in slot[%s] configured\n",
451 __FUNCTION__, slot->name);
452 } else {
453 slot->state = NOT_CONFIGURED;
454 dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
455 __FUNCTION__, slot->name);
456 }
457 } else if (state == EMPTY) {
458 dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
459 slot->state = EMPTY;
460 } else {
461 err("%s: slot[%s] is in invalid state\n", __FUNCTION__,
462 slot->name);
463 slot->state = NOT_VALID;
464 retval = -EINVAL;
465 }
466exit:
467 dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
468 return retval;
469}