blob: 49e4d10a6488ea79dadb4f4ee324b5ef361e0966 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
3 * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
4 *
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Send feedback to <lxie@us.ibm.com>
23 *
24 */
25#include <linux/pci.h>
26#include <asm/pci-bridge.h>
27#include <asm/rtas.h>
28#include <asm/machdep.h>
29#include "../pci.h" /* for pci_add_new_bus */
30
31#include "rpaphp.h"
32
John Rose0945cd52005-07-25 10:16:53 -050033static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
John Rose9c209c92005-07-25 11:13:38 -050034 struct device_node *dn)
35{
36 struct pci_bus *child = NULL;
37 struct list_head *tmp;
38 struct device_node *busdn;
39
40 busdn = pci_bus_to_OF_node(bus);
41 if (busdn == dn)
42 return bus;
43
44 list_for_each(tmp, &bus->children) {
45 child = find_bus_among_children(pci_bus_b(tmp), dn);
46 if (child)
47 break;
48 }
49 return child;
50}
51
John Rose56d84562005-07-25 10:17:03 -050052struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
John Rose9c209c92005-07-25 11:13:38 -050053{
Paul Mackerras16353172005-09-06 13:17:54 +100054 struct pci_dn *pdn = dn->data;
55
56 if (!pdn || !pdn->phb || !pdn->phb->bus)
John Rose0945cd52005-07-25 10:16:53 -050057 return NULL;
John Rose9c209c92005-07-25 11:13:38 -050058
Paul Mackerras16353172005-09-06 13:17:54 +100059 return find_bus_among_children(pdn->phb->bus, dn);
John Rose9c209c92005-07-25 11:13:38 -050060}
John Rose56d84562005-07-25 10:17:03 -050061EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
John Rose9c209c92005-07-25 11:13:38 -050062
Linus Torvalds1da177e2005-04-16 15:20:36 -070063int rpaphp_claim_resource(struct pci_dev *dev, int resource)
64{
65 struct resource *res = &dev->resource[resource];
66 struct resource *root = pci_find_parent_resource(dev, res);
67 char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
68 int err = -EINVAL;
69
70 if (root != NULL) {
71 err = request_resource(root, res);
72 }
73
74 if (err) {
75 err("PCI: %s region %d of %s %s [%lx:%lx]\n",
76 root ? "Address space collision on" :
77 "No parent found for",
78 resource, dtype, pci_name(dev), res->start, res->end);
79 }
80 return err;
81}
82
83EXPORT_SYMBOL_GPL(rpaphp_claim_resource);
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static int rpaphp_get_sensor_state(struct slot *slot, int *state)
86{
87 int rc;
88 int setlevel;
89
90 rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
91
92 if (rc < 0) {
93 if (rc == -EFAULT || rc == -EEXIST) {
94 dbg("%s: slot must be power up to get sensor-state\n",
95 __FUNCTION__);
96
97 /* some slots have to be powered up
98 * before get-sensor will succeed.
99 */
100 rc = rtas_set_power_level(slot->power_domain, POWER_ON,
101 &setlevel);
102 if (rc < 0) {
103 dbg("%s: power on slot[%s] failed rc=%d.\n",
104 __FUNCTION__, slot->name, rc);
105 } else {
106 rc = rtas_get_sensor(DR_ENTITY_SENSE,
107 slot->index, state);
108 }
109 } else if (rc == -ENODEV)
110 info("%s: slot is unusable\n", __FUNCTION__);
111 else
112 err("%s failed to get sensor state\n", __FUNCTION__);
113 }
114 return rc;
115}
116
117/**
118 * get_pci_adapter_status - get the status of a slot
119 *
120 * 0-- slot is empty
121 * 1-- adapter is configured
122 * 2-- adapter is not configured
123 * 3-- not valid
124 */
125int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
126{
John Rose0945cd52005-07-25 10:16:53 -0500127 struct pci_bus *bus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 int state, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130 *value = NOT_VALID;
131 rc = rpaphp_get_sensor_state(slot, &state);
132 if (rc)
133 goto exit;
134
John Rose56d84562005-07-25 10:17:03 -0500135 if (state == EMPTY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 *value = EMPTY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 else if (state == PRESENT) {
138 if (!is_init) {
139 /* at run-time slot->state can be changed by */
140 /* config/unconfig adapter */
141 *value = slot->state;
142 } else {
John Rose0945cd52005-07-25 10:16:53 -0500143 bus = rpaphp_find_pci_bus(slot->dn);
144 if (bus && !list_empty(&bus->devices))
145 *value = CONFIGURED;
146 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 *value = NOT_CONFIGURED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
149 }
150exit:
151 return rc;
152}
153
154/* Must be called before pci_bus_add_devices */
155static void
156rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
157{
158 struct pci_dev *dev;
159
160 list_for_each_entry(dev, &bus->devices, bus_list) {
161 /*
162 * Skip already-present devices (which are on the
163 * global device list.)
164 */
165 if (list_empty(&dev->global_list)) {
166 int i;
167
168 /* Need to setup IOMMU tables */
169 ppc_md.iommu_dev_setup(dev);
170
171 if(fix_bus)
172 pcibios_fixup_device_resources(dev, bus);
173 pci_read_irq_line(dev);
174 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
175 struct resource *r = &dev->resource[i];
176
177 if (r->parent || !r->start || !r->flags)
178 continue;
179 rpaphp_claim_resource(dev, i);
180 }
181 }
182 }
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int rpaphp_pci_config_bridge(struct pci_dev *dev)
186{
187 u8 sec_busno;
188 struct pci_bus *child_bus;
189 struct pci_dev *child_dev;
190
191 dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
192
193 /* get busno of downstream bus */
194 pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
195
196 /* add to children of PCI bridge dev->bus */
197 child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
198 if (!child_bus) {
199 err("%s: could not add second bus\n", __FUNCTION__);
200 return -EIO;
201 }
202 sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
203 /* do pci_scan_child_bus */
204 pci_scan_child_bus(child_bus);
205
206 list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
207 eeh_add_device_late(child_dev);
208 }
209
210 /* fixup new pci devices without touching bus struct */
211 rpaphp_fixup_new_pci_devices(child_bus, 0);
212
213 /* Make the discovered devices available */
214 pci_bus_add_devices(child_bus);
215 return 0;
216}
217
John Rosebde16842005-07-25 10:16:37 -0500218/*****************************************************************************
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 *
John Rose940903c2005-07-25 10:16:58 -0500223rpaphp_pci_config_slot(struct pci_bus *bus)
John Rosebde16842005-07-25 10:16:37 -0500224{
John Rose940903c2005-07-25 10:16:58 -0500225 struct device_node *dn = pci_bus_to_OF_node(bus);
John Rosebde16842005-07-25 10:16:37 -0500226 struct pci_dev *dev = NULL;
John Rose9c209c92005-07-25 11:13:38 -0500227 int slotno;
John Rosebde16842005-07-25 10:16:37 -0500228 int num;
229
230 dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
John Rose940903c2005-07-25 10:16:58 -0500231 if (!dn || !dn->child)
John Rose0945cd52005-07-25 10:16:53 -0500232 return NULL;
John Rosebde16842005-07-25 10:16:37 -0500233
Paul Mackerras16353172005-09-06 13:17:54 +1000234 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
John Rose9c209c92005-07-25 11:13:38 -0500235
John Rose0945cd52005-07-25 10:16:53 -0500236 /* pci_scan_slot should find all children */
237 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
238 if (num) {
239 rpaphp_fixup_new_pci_devices(bus, 1);
240 pci_bus_add_devices(bus);
241 }
242 if (list_empty(&bus->devices)) {
243 err("%s: No new device found\n", __FUNCTION__);
244 return NULL;
245 }
246 list_for_each_entry(dev, &bus->devices, bus_list) {
John Rosebde16842005-07-25 10:16:37 -0500247 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
248 rpaphp_pci_config_bridge(dev);
249 }
John Rose0945cd52005-07-25 10:16:53 -0500250
John Rosebde16842005-07-25 10:16:37 -0500251 return dev;
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254static void enable_eeh(struct device_node *dn)
255{
256 struct device_node *sib;
257
258 for (sib = dn->child; sib; sib = sib->sibling)
259 enable_eeh(sib);
260 eeh_add_device_early(dn);
261 return;
262
263}
264
John Rose940903c2005-07-25 10:16:58 -0500265static void print_slot_pci_funcs(struct pci_bus *bus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
John Rose940903c2005-07-25 10:16:58 -0500267 struct device_node *dn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 struct pci_dev *dev;
269
John Rose940903c2005-07-25 10:16:58 -0500270 dn = pci_bus_to_OF_node(bus);
271 if (!dn)
272 return;
273
274 dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name);
275 list_for_each_entry (dev, &bus->devices, bus_list)
John Rose5eeb8c62005-07-25 10:16:42 -0500276 dbg("\t%s\n", pci_name(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return;
278}
279
John Rose940903c2005-07-25 10:16:58 -0500280int rpaphp_config_pci_adapter(struct pci_bus *bus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
John Rose940903c2005-07-25 10:16:58 -0500282 struct device_node *dn = pci_bus_to_OF_node(bus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 struct pci_dev *dev;
284 int rc = -ENODEV;
285
John Rose940903c2005-07-25 10:16:58 -0500286 dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name);
287 if (!dn)
288 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
John Rose940903c2005-07-25 10:16:58 -0500290 enable_eeh(dn);
291 dev = rpaphp_pci_config_slot(bus);
John Rose9c209c92005-07-25 11:13:38 -0500292 if (!dev) {
293 err("%s: can't find any devices.\n", __FUNCTION__);
294 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
John Rose940903c2005-07-25 10:16:58 -0500296 print_slot_pci_funcs(bus);
John Rose9c209c92005-07-25 11:13:38 -0500297 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298exit:
299 dbg("Exit %s: rc=%d\n", __FUNCTION__, rc);
300 return rc;
301}
John Rose940903c2005-07-25 10:16:58 -0500302EXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
305{
306 eeh_remove_device(dev);
307 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
308 struct pci_bus *bus = dev->subordinate;
309 struct list_head *ln;
310 if (!bus)
311 return;
312 for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
313 struct pci_dev *pdev = pci_dev_b(ln);
314 if (pdev)
315 rpaphp_eeh_remove_bus_device(pdev);
316 }
317
318 }
319 return;
320}
321
322int rpaphp_unconfig_pci_adapter(struct slot *slot)
323{
John Rose9c209c92005-07-25 11:13:38 -0500324 struct pci_dev *dev, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 int retval = 0;
326
John Rose9c209c92005-07-25 11:13:38 -0500327 list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 rpaphp_eeh_remove_bus_device(dev);
John Rose9c209c92005-07-25 11:13:38 -0500329 pci_remove_bus_device(dev);
330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 slot->state = NOT_CONFIGURED;
333 info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
334 slot->name);
335 return retval;
336}
337
338static int setup_pci_hotplug_slot_info(struct slot *slot)
339{
340 dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
341 __FUNCTION__);
342 rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status);
343 rpaphp_get_pci_adapter_status(slot, 1,
344 &slot->hotplug_slot->info->
345 adapter_status);
346 if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
347 err("%s: NOT_VALID: skip dn->full_name=%s\n",
348 __FUNCTION__, slot->dn->full_name);
349 return -EINVAL;
350 }
351 return 0;
352}
353
John Rose9c209c92005-07-25 11:13:38 -0500354static void set_slot_name(struct slot *slot)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
John Rose9c209c92005-07-25 11:13:38 -0500356 struct pci_bus *bus = slot->bus;
357 struct pci_dev *bridge;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
John Rose9c209c92005-07-25 11:13:38 -0500359 bridge = bus->self;
360 if (bridge)
361 strcpy(slot->name, pci_name(bridge));
362 else
363 sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus),
364 bus->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
367static int setup_pci_slot(struct slot *slot)
368{
John Rose9c209c92005-07-25 11:13:38 -0500369 struct device_node *dn = slot->dn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 struct pci_bus *bus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
John Rose9c209c92005-07-25 11:13:38 -0500372 BUG_ON(!dn);
373 bus = rpaphp_find_pci_bus(dn);
374 if (!bus) {
375 err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
376 goto exit_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378
John Rose9c209c92005-07-25 11:13:38 -0500379 slot->bus = bus;
380 slot->pci_devs = &bus->devices;
381 set_slot_name(slot);
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* find slot's pci_dev if it's not empty */
384 if (slot->hotplug_slot->info->adapter_status == EMPTY) {
385 slot->state = EMPTY; /* slot is empty */
386 } else {
387 /* slot is occupied */
John Rose9c209c92005-07-25 11:13:38 -0500388 if (!dn->child) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /* non-empty slot has to have child */
390 err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
391 __FUNCTION__, slot->name);
392 goto exit_rc;
393 }
394
395 if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
396 dbg("%s CONFIGURING pci adapter in slot[%s]\n",
397 __FUNCTION__, slot->name);
John Rose940903c2005-07-25 10:16:58 -0500398 if (rpaphp_config_pci_adapter(slot->bus)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 err("%s: CONFIG pci adapter failed\n", __FUNCTION__);
400 goto exit_rc;
401 }
402
403 } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
404 err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
405 __FUNCTION__, slot->name);
406 goto exit_rc;
407 }
John Rose940903c2005-07-25 10:16:58 -0500408 print_slot_pci_funcs(slot->bus);
John Rose5eeb8c62005-07-25 10:16:42 -0500409 if (!list_empty(slot->pci_devs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 slot->state = CONFIGURED;
411 } else {
412 /* DLPAR add as opposed to
413 * boot time */
414 slot->state = NOT_CONFIGURED;
415 }
416 }
417 return 0;
418exit_rc:
419 dealloc_slot_struct(slot);
420 return -EINVAL;
421}
422
423int register_pci_slot(struct slot *slot)
424{
425 int rc = -EINVAL;
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 if (setup_pci_hotplug_slot_info(slot))
428 goto exit_rc;
429 if (setup_pci_slot(slot))
430 goto exit_rc;
431 rc = register_slot(slot);
432exit_rc:
433 return rc;
434}
435
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);
John Rose940903c2005-07-25 10:16:58 -0500447 retval = rpaphp_config_pci_adapter(slot->bus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (!retval) {
449 slot->state = CONFIGURED;
450 dbg("%s: PCI devices in slot[%s] has been 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}