This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / pci / hotplug / rpaphp_pci.c
index 0dd2d23..6f5b61b 100644 (file)
  */
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
-#include <asm/rtas.h>
 #include "../pci.h"            /* for pci_add_new_bus */
 
 #include "rpaphp.h"
 
 struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
 {
-       struct pci_dev *retval_dev = NULL, *dev = NULL;
+       struct pci_dev *retval_dev = NULL, *dev;
        char bus_id[BUS_ID_SIZE];
 
        sprintf(bus_id, "%04x:%02x:%02x.%d",dn->phb->global_number,
                dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn));
+
+       dbg("Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s\n", 
+               dn->full_name, bus_id);
+       
        while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               if (!strcmp(pci_name(dev), bus_id)) {
+               if (!strcmp(pci_name(dev), bus_id)) {
                        retval_dev = dev;
+                       dbg("rpaphp_find_pci_dev(): found dev=%p\n\n", dev);
                        break;
                }
        }
        return retval_dev;
+
 }
 
 EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
@@ -74,6 +79,11 @@ static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
        return rpaphp_find_pci_dev(slot->dn);
 }
 
+static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
+{
+       return rpaphp_find_pci_dev(slot->dn->child);
+}
+
 static int rpaphp_get_sensor_state(struct slot *slot, int *state)
 {
        int rc;
@@ -134,8 +144,7 @@ int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
                        else if (rpaphp_find_pci_dev(slot->dn->child))
                                *value = CONFIGURED;
                        else {
-                               err("%s: can't find pdev of adapter in slot[%s]\n", 
-                                       __FUNCTION__, slot->dn->full_name);
+                               dbg("%s: can't find pdev of adapter in slot[%s]\n", __FUNCTION__, slot->name);
                                *value = NOT_CONFIGURED;
                        }
                }
@@ -149,8 +158,7 @@ exit:
 }
 
 /* Must be called before pci_bus_add_devices */
-static void 
-rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+static void rpaphp_fixup_new_pci_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -161,9 +169,8 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
                 */
                if (list_empty(&dev->global_list)) {
                        int i;
-                       
-                       if(fix_bus)
-                               pcibios_fixup_device_resources(dev, bus);
+
+                       pcibios_fixup_device_resources(dev, bus);
                        pci_read_irq_line(dev);
                        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                                struct resource *r = &dev->resource[i];
@@ -176,139 +183,69 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
        }
 }
 
-static int rpaphp_pci_config_bridge(struct pci_dev *dev);
-
-/*****************************************************************************
- rpaphp_pci_config_slot() will  configure all devices under the 
- given slot->dn and return the the first pci_dev.
- *****************************************************************************/
-static struct pci_dev *
-rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus)
+static void
+rpaphp_pci_config_device(struct pci_bus *pci_bus, struct device_node *dn)
 {
-       struct device_node *eads_first_child = dn->child;
-       struct pci_dev *dev;
        int num;
-       
-       dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
-
-       if (eads_first_child) {
-               /* pci_scan_slot should find all children of EADs */
-               num = pci_scan_slot(bus, PCI_DEVFN(PCI_SLOT(eads_first_child->devfn), 0));
-               if (num) {
-                       rpaphp_fixup_new_pci_devices(bus, 1); 
-                       pci_bus_add_devices(bus);
-               }
-               dev = rpaphp_find_pci_dev(eads_first_child);
-               if (!dev) {
-                       err("No new device found\n");
-                       return NULL;
-               }
-               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 
-                       rpaphp_pci_config_bridge(dev);
-       }
-       return dev;
-}
-
-static int rpaphp_pci_config_bridge(struct pci_dev *dev)
-{
-       u8 sec_busno;
-       struct pci_bus *child_bus;
-       struct pci_dev *child_dev;
-
-       dbg("Enter %s:  BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
 
-       /* get busno of downstream bus */
-       pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
-               
-       /* add to children of PCI bridge dev->bus */
-       child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
-       if (!child_bus) {
-               err("%s: could not add second bus\n", __FUNCTION__);
-               return -EIO;
-       }
-       sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
-       /* do pci_scan_child_bus */
-       pci_scan_child_bus(child_bus);
-
-       list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
-               eeh_add_device_late(child_dev);
+       num = pci_scan_slot(pci_bus, PCI_DEVFN(PCI_SLOT(dn->devfn), 0));
+       if (num) {
+               rpaphp_fixup_new_pci_devices(pci_bus);
+               pci_bus_add_devices(pci_bus);
        }
-
-        /* fixup new pci devices without touching bus struct */
-       rpaphp_fixup_new_pci_devices(child_bus, 0);
-
-       /* Make the discovered devices available */
-       pci_bus_add_devices(child_bus);
-       return 0;
 }
 
-static void enable_eeh(struct device_node *dn)
-{
-       struct device_node *sib;
+static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn);
 
-       for (sib = dn->child; sib; sib = sib->sibling) 
-               enable_eeh(sib);
-       eeh_add_device_early(dn);
-       return;
-       
-}
-
-#ifdef DEBUG
-static void print_slot_pci_funcs(struct slot *slot)
+/*****************************************************************************
+ rpaphp_pci_config_dn() will recursively configure all devices under the 
+ given slot->dn and return the dn's pci_dev.
+ *****************************************************************************/
+static struct pci_dev *
+rpaphp_pci_config_dn(struct device_node *dn, struct pci_bus *bus)
 {
-       struct list_head *l;
-
-       if (slot->dev_type == PCI_DEV) {
-               printk("pci_funcs of slot[%s]\n", slot->name);
-               if (list_empty(&slot->dev.pci_funcs))
-                       printk("        pci_funcs is EMPTY\n");
+       struct device_node *local;
+       struct pci_dev *dev;
 
-               list_for_each (l, &slot->dev.pci_funcs) {
-                       struct rpaphp_pci_func *func =
-                               list_entry(l, struct rpaphp_pci_func, sibling);
-                       printk("        FOUND dev=%s\n", pci_name(func->pci_dev));
-               }
+       for (local = dn->child; local; local = local->sibling) {
+               rpaphp_pci_config_device(bus, local);
+               dev = rpaphp_find_pci_dev(local);
+               if (!rpaphp_pci_config_bridge(dev, local))
+                       return NULL;
        }
-       return;
-}
-#else
-static void print_slot_pci_funcs(struct slot *slot)
-{
-       return;
+
+       return dev;
 }
-#endif
 
-static int init_slot_pci_funcs(struct slot *slot)
+static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn)
 {
-       struct device_node *child;
-
-       for (child = slot->dn->child; child != NULL; child = child->sibling) {
-               struct pci_dev *pdev = rpaphp_find_pci_dev(child);
-
-               if (pdev) {
-                       struct rpaphp_pci_func *func;
-                       func = kmalloc(sizeof(struct rpaphp_pci_func), GFP_KERNEL);
-                       if (!func) 
-                               return -ENOMEM;
-                       memset(func, 0, sizeof(struct rpaphp_pci_func));
-                       INIT_LIST_HEAD(&func->sibling);
-                       func->pci_dev = pdev;
-                       list_add_tail(&func->sibling, &slot->dev.pci_funcs);
-                       print_slot_pci_funcs(slot);
-               } else {
-                       err("%s: dn=%s has no pci_dev\n", 
-                               __FUNCTION__, child->full_name);
-                       return -EIO;
+       if (dev && dn->child) { /* dn is a PCI bridge node */
+               struct pci_bus *child;
+               u8 sec_busno;
+
+               /* get busno of downstream bus */
+               pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+
+               /* add to children of PCI bridge dev->bus */
+               child = pci_add_new_bus(dev->bus, dev, sec_busno);
+               if (!child) {
+                       err("%s: could not add second bus\n", __FUNCTION__);
+                       return 0;
                }
+               sprintf(child->name, "PCI Bus #%02x", child->number);
+               /* Fixup subordinate bridge bases and resureces */
+               pcibios_fixup_bus(child);
+
+               /* may need do more stuff here */
+               rpaphp_pci_config_dn(dn, dev->subordinate);
        }
-       return 0;
+       return 1;
 }
 
-static int rpaphp_config_pci_adapter(struct slot *slot)
+static struct pci_dev *rpaphp_config_pci_adapter(struct slot *slot)
 {
        struct pci_bus *pci_bus;
-       struct pci_dev *dev;
-       int rc = -ENODEV;
+       struct pci_dev *dev = NULL;
 
        dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
 
@@ -319,74 +256,38 @@ static int rpaphp_config_pci_adapter(struct slot *slot)
                        err("%s: can't find bus structure\n", __FUNCTION__);
                        goto exit;
                }
-               enable_eeh(slot->dn);
-               dev = rpaphp_pci_config_slot(slot->dn, pci_bus);
-               if (!dev) {
-                       err("%s: can't find any devices.\n", __FUNCTION__);
-                       goto exit;
-               }
-               /* associate corresponding pci_dev */   
-               rc = init_slot_pci_funcs(slot);
-               if (rc)
-                       goto exit;
-               print_slot_pci_funcs(slot);
-               if (!list_empty(&slot->dev.pci_funcs)) 
-                       rc = 0;
+
+               eeh_add_device_early(slot->dn->child);
+               dev = rpaphp_pci_config_dn(slot->dn, pci_bus);
+               eeh_add_device_late(dev);
        } else {
                /* slot is not enabled */
                err("slot doesn't have pci_dev structure\n");
+               dev = NULL;
        }
-exit:
-       dbg("Exit %s:  rc=%d\n", __FUNCTION__, rc);
-       return rc;
-}
 
-
-static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
-{
-       eeh_remove_device(dev);
-       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-               struct pci_bus *bus = dev->subordinate;
-               struct list_head *ln;
-               if (!bus)
-                       return; 
-               for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-                       struct pci_dev *pdev = pci_dev_b(ln);
-                       if (pdev)
-                               rpaphp_eeh_remove_bus_device(pdev);
-               }
-
-       }
-       return;
+exit:
+       dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev ? "found" : "not found");
+       return dev;
 }
 
 int rpaphp_unconfig_pci_adapter(struct slot *slot)
 {
        int retval = 0;
-       struct list_head *ln;
 
        dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
-       if (list_empty(&slot->dev.pci_funcs)) {
-               err("%s: slot[%s] doesn't have any devices.\n", __FUNCTION__, 
-                       slot->name);
+       if (!slot->dev.pci_dev) {
+               info("%s: no card in slot[%s]\n", __FUNCTION__, slot->name);
 
                retval = -EINVAL;
                goto exit;
        }
-       /* remove the devices from the pci core */
-       list_for_each (ln, &slot->dev.pci_funcs) {
-               struct rpaphp_pci_func *func;
-       
-               func = list_entry(ln, struct rpaphp_pci_func, sibling);
-               if (func->pci_dev) {
-                       pci_remove_bus_device(func->pci_dev); 
-                       rpaphp_eeh_remove_bus_device(func->pci_dev);
-               }
-               kfree(func);
-       }
-       INIT_LIST_HEAD(&slot->dev.pci_funcs);
+       /* remove the device from the pci core */
+       eeh_remove_device(slot->dev.pci_dev);
+       pci_remove_bus_device(slot->dev.pci_dev);
+
        slot->state = NOT_CONFIGURED;
-       info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
+       info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__,
             slot->name);
 exit:
        dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
@@ -402,7 +303,7 @@ static int setup_pci_hotplug_slot_info(struct slot *slot)
                                      &slot->hotplug_slot->info->
                                      adapter_status);
        if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
-               err("%s: NOT_VALID: skip dn->full_name=%s\n",
+               dbg("%s: NOT_VALID: skip dn->full_name=%s\n",
                    __FUNCTION__, slot->dn->full_name);
                return -1;
        }
@@ -413,41 +314,35 @@ static int setup_pci_slot(struct slot *slot)
 {
        slot->bridge = rpaphp_find_bridge_pdev(slot);
        if (!slot->bridge) {    /* slot being added doesn't have pci_dev yet */
-               err("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name);
-               goto exit_rc;
+               dbg("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name);
+               dealloc_slot_struct(slot);
+               return 1;
        }
-       dbg("%s set slot->name to %s\n",  __FUNCTION__, pci_name(slot->bridge));
+       
        strcpy(slot->name, pci_name(slot->bridge));
-
        /* find slot's pci_dev if it's not empty */
        if (slot->hotplug_slot->info->adapter_status == EMPTY) {
                slot->state = EMPTY;    /* slot is empty */
+               slot->dev.pci_dev = NULL;
        } else {
                /* slot is occupied */
                if (!(slot->dn->child)) {
                        /* non-empty slot has to have child */
-                       err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 
-                               __FUNCTION__, slot->name);
-                       goto exit_rc;
+                       err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __FUNCTION__, slot->name);
+                       dealloc_slot_struct(slot);
+                       return 1;
                }
-               if (init_slot_pci_funcs(slot)) {
-                       err("%s: init_slot_pci_funcs failed\n", __FUNCTION__);
-                       goto exit_rc;
-               }
-               print_slot_pci_funcs(slot);
-               if (!list_empty(&slot->dev.pci_funcs)) {
+               slot->dev.pci_dev = rpaphp_find_adapter_pdev(slot);
+               if (slot->dev.pci_dev) {
                        slot->state = CONFIGURED;
-       
+               
                } else {
                        /* DLPAR add as opposed to 
-                        * boot time */
+                        * boot time */
                        slot->state = NOT_CONFIGURED;
                }
        }
        return 0;
-exit_rc:
-       dealloc_slot_struct(slot);
-       return 1;
 }
 
 int register_pci_slot(struct slot *slot)
@@ -455,17 +350,14 @@ int register_pci_slot(struct slot *slot)
        int rc = 1;
 
        slot->dev_type = PCI_DEV;
-       if (slot->type == EMBEDDED)
-               slot->removable = EMBEDDED;
-       else
-               slot->removable = HOTPLUG;
-       INIT_LIST_HEAD(&slot->dev.pci_funcs);
        if (setup_pci_hotplug_slot_info(slot))
                goto exit_rc;
        if (setup_pci_slot(slot))
                goto exit_rc;
        rc = register_slot(slot);
 exit_rc:
+       if (rc)
+               dealloc_slot_struct(slot);
        return rc;
 }
 
@@ -479,12 +371,12 @@ int rpaphp_enable_pci_slot(struct slot *slot)
        dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
        /* if slot is not empty, enable the adapter */
        if (state == PRESENT) {
-               dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
-               retval = rpaphp_config_pci_adapter(slot);
-               if (!retval) {
+               dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name);
+               if ((slot->dev.pci_dev =
+                    rpaphp_config_pci_adapter(slot)) != NULL) {
                        slot->state = CONFIGURED;
-                       dbg("%s: PCI devices in slot[%s] has been configured\n", 
-                               __FUNCTION__, slot->name);
+                       dbg("%s: PCI adapter %s in slot[%s] has been configured\n", 
+                               __FUNCTION__, pci_name(slot->dev.pci_dev), slot->name);
                } else {
                        slot->state = NOT_CONFIGURED;
                        dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
@@ -500,40 +392,10 @@ int rpaphp_enable_pci_slot(struct slot *slot)
                retval = -EINVAL;
        }
 exit:
+       if (slot->state != NOT_VALID)
+               rpaphp_set_attention_status(slot, LED_ON);
+       else
+               rpaphp_set_attention_status(slot, LED_ID);
        dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
        return retval;
 }
-
-struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev)
-{
-       struct list_head        *tmp, *n;
-       struct slot             *slot;
-
-       list_for_each_safe(tmp, n, &rpaphp_slot_head) {
-               struct pci_bus *bus;
-               struct list_head *ln;
-
-               slot = list_entry(tmp, struct slot, rpaphp_slot_list);
-               if (slot->bridge == NULL) {
-                       if (slot->dev_type == PCI_DEV) {
-                               printk(KERN_WARNING "PCI slot missing bridge %s %s \n", 
-                                                   slot->name, slot->location);
-                       }
-                       continue;
-               }
-
-               bus = slot->bridge->subordinate;
-               if (!bus) {
-                       continue;  /* should never happen? */
-               }
-               for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-                                struct pci_dev *pdev = pci_dev_b(ln);
-                               if (pdev == dev)
-                                       return slot->hotplug_slot;
-               }
-       }
-
-       return NULL;
-}
-
-EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot);