diff options
Diffstat (limited to 'drivers/pci/hotplug/rpadlpar_core.c')
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_core.c | 154 |
1 files changed, 78 insertions, 76 deletions
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index f2a73f70e58..4ada15111af 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -26,6 +26,8 @@ static DECLARE_MUTEX(rpadlpar_sem); +#define DLPAR_MODULE_NAME "rpadlpar_io" + #define NODE_TYPE_VIO 1 #define NODE_TYPE_SLOT 2 #define NODE_TYPE_PHB 3 @@ -93,14 +95,14 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) return NULL; } -static struct slot *find_slot(char *drc_name) +static struct slot *find_slot(struct device_node *dn) { struct list_head *tmp, *n; struct slot *slot; list_for_each_safe(tmp, n, &rpaphp_slot_head) { slot = list_entry(tmp, struct slot, rpaphp_slot_list); - if (strcmp(slot->location, drc_name) == 0) + if (slot->dn == dn) return slot; } @@ -214,6 +216,9 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) struct pci_dev *dev; int rc; + if (rpaphp_find_pci_bus(dn)) + return -EINVAL; + /* Add pci bus */ dev = dlpar_pci_add_bus(dn); if (!dev) { @@ -261,36 +266,32 @@ static int dlpar_remove_root_bus(struct pci_controller *phb) return 0; } -static int dlpar_remove_phb(struct slot *slot) +static int dlpar_remove_phb(char *drc_name, struct device_node *dn) { - struct pci_controller *phb; - struct device_node *dn; + struct slot *slot; int rc = 0; - dn = slot->dn; - if (!dn) { - printk(KERN_ERR "%s: unexpected NULL slot device node\n", - __FUNCTION__); - return -EIO; - } - - phb = dn->phb; - if (!phb) { - printk(KERN_ERR "%s: unexpected NULL phb pointer\n", - __FUNCTION__); - return -EIO; - } + if (!rpaphp_find_pci_bus(dn)) + return -EINVAL; - if (rpaphp_remove_slot(slot)) { - printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", - __FUNCTION__, slot->location); - return -EIO; + slot = find_slot(dn); + if (slot) { + /* Remove hotplug slot */ + if (rpaphp_remove_slot(slot)) { + printk(KERN_ERR + "%s: unable to remove hotplug slot %s\n", + __FUNCTION__, drc_name); + return -EIO; + } } - rc = dlpar_remove_root_bus(phb); + BUG_ON(!dn->phb); + rc = dlpar_remove_root_bus(dn->phb); if (rc < 0) return rc; + dn->phb = NULL; + return 0; } @@ -298,9 +299,14 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) { struct pci_controller *phb; + if (dn->phb) { + /* PHB already exists */ + return -EINVAL; + } + phb = init_phb_dynamic(dn); if (!phb) - return -EINVAL; + return -EIO; if (rpaphp_add_slot(dn)) { printk(KERN_ERR "%s: unable to add hotplug slot %s\n", @@ -310,6 +316,20 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) return 0; } +static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn) +{ + if (vio_find_node(dn)) + return -EINVAL; + + if (!vio_register_device_node(dn)) { + printk(KERN_ERR + "%s: failed to register vio node %s\n", + __FUNCTION__, drc_name); + return -EIO; + } + return 0; +} + /** * dlpar_add_slot - DLPAR add an I/O Slot * @drc_name: drc-name of newly added slot @@ -327,17 +347,11 @@ int dlpar_add_slot(char *drc_name) { struct device_node *dn = NULL; int node_type; - int rc; + int rc = -EIO; if (down_interruptible(&rpadlpar_sem)) return -ERESTARTSYS; - /* Check for existing hotplug slot */ - if (find_slot(drc_name)) { - rc = -EINVAL; - goto exit; - } - /* Find newly added node */ dn = find_dlpar_node(drc_name, &node_type); if (!dn) { @@ -345,32 +359,19 @@ int dlpar_add_slot(char *drc_name) goto exit; } - rc = -EIO; switch (node_type) { case NODE_TYPE_VIO: - if (!vio_register_device_node(dn)) { - printk(KERN_ERR - "%s: failed to register vio node %s\n", - __FUNCTION__, drc_name); - goto exit; - } + rc = dlpar_add_vio_slot(drc_name, dn); break; case NODE_TYPE_SLOT: rc = dlpar_add_pci_slot(drc_name, dn); - if (rc) - goto exit; break; case NODE_TYPE_PHB: rc = dlpar_add_phb(drc_name, dn); - if (rc) - goto exit; break; - default: - printk("%s: unexpected node type\n", __FUNCTION__); - goto exit; } - rc = 0; + printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name); exit: up(&rpadlpar_sem); return rc; @@ -384,18 +385,15 @@ exit: * of an I/O Slot. * Return Codes: * 0 Success - * -EIO Internal Error + * -EINVAL Vio dev doesn't exist */ -static int dlpar_remove_vio_slot(struct device_node *dn, char *drc_name) +static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn) { struct vio_dev *vio_dev; vio_dev = vio_find_node(dn); - if (!vio_dev) { - printk(KERN_ERR "%s: %s does not correspond to a vio dev\n", - __FUNCTION__, drc_name); - return -EIO; - } + if (!vio_dev) + return -EINVAL; vio_unregister_device(vio_dev); return 0; @@ -412,15 +410,24 @@ static int dlpar_remove_vio_slot(struct device_node *dn, char *drc_name) * -ENODEV Not a valid drc_name * -EIO Internal PCI Error */ -int dlpar_remove_pci_slot(struct slot *slot, char *drc_name) +int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) { - struct pci_bus *bus = slot->bus; + struct pci_bus *bus; + struct slot *slot; - /* Remove hotplug slot */ - if (rpaphp_remove_slot(slot)) { - printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", - __FUNCTION__, drc_name); - return -EIO; + bus = rpaphp_find_pci_bus(dn); + if (!bus) + return -EINVAL; + + slot = find_slot(dn); + if (slot) { + /* Remove hotplug slot */ + if (rpaphp_remove_slot(slot)) { + printk(KERN_ERR + "%s: unable to remove hotplug slot %s\n", + __FUNCTION__, drc_name); + return -EIO; + } } if (unmap_bus_range(bus)) { @@ -450,7 +457,6 @@ int dlpar_remove_pci_slot(struct slot *slot, char *drc_name) int dlpar_remove_slot(char *drc_name) { struct device_node *dn; - struct slot *slot; int node_type; int rc = 0; @@ -463,22 +469,18 @@ int dlpar_remove_slot(char *drc_name) goto exit; } - if (node_type == NODE_TYPE_VIO) { - rc = dlpar_remove_vio_slot(dn, drc_name); - } else { - slot = find_slot(drc_name); - if (!slot) { - rc = -EINVAL; - goto exit; - } - - if (node_type == NODE_TYPE_PHB) - rc = dlpar_remove_phb(slot); - else { - /* NODE_TYPE_SLOT */ - rc = dlpar_remove_pci_slot(slot, drc_name); - } + switch (node_type) { + case NODE_TYPE_VIO: + rc = dlpar_remove_vio_slot(drc_name, dn); + break; + case NODE_TYPE_PHB: + rc = dlpar_remove_phb(drc_name, dn); + break; + case NODE_TYPE_SLOT: + rc = dlpar_remove_pci_slot(drc_name, dn); + break; } + printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name); exit: up(&rpadlpar_sem); return rc; |