On Wed, Nov 26, 2014 at 10:04:36AM +1100, Benjamin Herrenschmidt wrote: >On Tue, 2014-11-25 at 09:49 +1100, Gavin Shan wrote: >> The patch splits the code into 2 parts: RPA PCI hotplug slot >> management and RTAS backend. It enables us to support PowerNV, >> which is built on top of OPAL firmware in future. >> >> The patch also refactors the code for a bit: >> >> * Rename "struct slot" to "struct rpa_php_slot" >> * All macros have prefix "RPA_PHP_SLOT" >> * rpaphp_slot.c is removed and all logics moved to rpaphp_core.c > > >I don't see the point of this. rpaphp is already itself a "backend", so >we end up with yet another layer. > Yes, that's what I did. >Just create a powernv-php or opal-php and if there is common code, >factor it into a common helper but I wouldn't bother too much initially >unless there is a lot of it. > Ok. I'll create powernv-php. Thanks, Gavin >> Signed-off-by: Gavin Shan <gwshan@xxxxxxxxxxxxxxxxxx> >> --- >> drivers/pci/hotplug/Makefile | 3 +- >> drivers/pci/hotplug/rpadlpar_core.c | 10 +- >> drivers/pci/hotplug/rpaphp.h | 64 +++---- >> drivers/pci/hotplug/rpaphp_core.c | 347 +++++++++++------------------------- >> drivers/pci/hotplug/rpaphp_pci.c | 136 -------------- >> drivers/pci/hotplug/rpaphp_rtas.c | 320 +++++++++++++++++++++++++++++++++ >> drivers/pci/hotplug/rpaphp_slot.c | 140 --------------- >> 7 files changed, 459 insertions(+), 561 deletions(-) >> delete mode 100644 drivers/pci/hotplug/rpaphp_pci.c >> create mode 100644 drivers/pci/hotplug/rpaphp_rtas.c >> delete mode 100644 drivers/pci/hotplug/rpaphp_slot.c >> >> diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile >> index 4a9aa08..630313da 100644 >> --- a/drivers/pci/hotplug/Makefile >> +++ b/drivers/pci/hotplug/Makefile >> @@ -51,8 +51,7 @@ acpiphp-objs := acpiphp_core.o \ >> acpiphp_glue.o >> >> rpaphp-objs := rpaphp_core.o \ >> - rpaphp_pci.o \ >> - rpaphp_slot.o >> + rpaphp_rtas.o >> >> rpadlpar_io-objs := rpadlpar_core.o \ >> rpadlpar_sysfs.o >> diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c >> index 35da3b3..a36d2c9 100644 >> --- a/drivers/pci/hotplug/rpadlpar_core.c >> +++ b/drivers/pci/hotplug/rpadlpar_core.c >> @@ -117,13 +117,13 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) >> * may be dlpar-able, but not hot-pluggable, so this routine >> * will return NULL for built-in PCI slots. >> */ >> -static struct slot *find_php_slot(struct device_node *dn) >> +static struct rpa_php_slot *find_php_slot(struct device_node *dn) >> { >> struct list_head *tmp, *n; >> - struct slot *slot; >> + struct rpa_php_slot *slot; >> >> list_for_each_safe(tmp, n, &rpaphp_slot_head) { >> - slot = list_entry(tmp, struct slot, rpaphp_slot_list); >> + slot = list_entry(tmp, struct rpa_php_slot, rpaphp_slot_list); >> if (slot->dn == dn) >> return slot; >> } >> @@ -214,7 +214,7 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) >> >> static int dlpar_remove_phb(char *drc_name, struct device_node *dn) >> { >> - struct slot *slot; >> + struct rpa_php_slot *slot; >> struct pci_dn *pdn; >> int rc = 0; >> >> @@ -359,7 +359,7 @@ static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn) >> int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) >> { >> struct pci_bus *bus; >> - struct slot *slot; >> + struct rpa_php_slot *slot; >> int ret = 0; >> >> pci_lock_rescan_remove(); >> diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h >> index 39ddbdf..09dd516 100644 >> --- a/drivers/pci/hotplug/rpaphp.h >> +++ b/drivers/pci/hotplug/rpaphp.h >> @@ -30,21 +30,6 @@ >> #include <linux/pci.h> >> #include <linux/pci_hotplug.h> >> >> -#define DR_INDICATOR 9002 >> -#define DR_ENTITY_SENSE 9003 >> - >> -#define POWER_ON 100 >> -#define POWER_OFF 0 >> - >> -#define LED_OFF 0 >> -#define LED_ON 1 /* continuous on */ >> -#define LED_ID 2 /* slow blinking */ >> -#define LED_ACTION 3 /* fast blinking */ >> - >> -/* Sensor values from rtas_get-sensor */ >> -#define EMPTY 0 /* No card in slot */ >> -#define PRESENT 1 /* Card in slot */ >> - >> #define MY_NAME "rpaphp" >> extern bool rpaphp_debug; >> #define dbg(format, arg...) \ >> @@ -57,19 +42,26 @@ extern bool rpaphp_debug; >> #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) >> #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) >> >> -/* slot states */ >> +/* Power */ >> +#define RPA_PHP_SLOT_POWER_ON 1 /* On */ >> +#define RPA_PHP_SLOT_POWER_OFF 0 /* Off */ >> >> -#define NOT_VALID 3 >> -#define NOT_CONFIGURED 2 >> -#define CONFIGURED 1 >> -#define EMPTY 0 >> +/* Attention */ >> +#define RPA_PHP_SLOT_ATTEN_OFF 0 /* Off */ >> +#define RPA_PHP_SLOT_ATTEN_ON 1 /* On */ >> +#define RPA_PHP_SLOT_ATTEN_IND 2 /* Slow blinking */ >> +#define RPA_PHP_SLOT_ATTEN_ACT 3 /* Fast blinking */ >> >> -/* >> - * struct slot - slot information for each *physical* slot >> - */ >> -struct slot { >> +/* Presence */ >> +#define RPA_PHP_SLOT_EMPTY 0 /* No card */ >> +#define RPA_PHP_SLOT_PRESENT 1 /* Presented */ >> + >> +struct rpa_php_slot { >> struct list_head rpaphp_slot_list; >> int state; >> +#define RPA_PHP_SLOT_NOT_CONFIGURED 0 >> +#define RPA_PHP_SLOT_CONFIGURED 1 >> +#define RPA_PHP_SLOT_NOT_VALID 2 >> u32 index; >> u32 type; >> u32 power_domain; >> @@ -80,24 +72,20 @@ struct slot { >> struct hotplug_slot *hotplug_slot; >> }; >> >> -extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; >> extern struct list_head rpaphp_slot_head; >> >> -/* function prototypes */ >> - >> -/* rpaphp_pci.c */ >> -int rpaphp_enable_slot(struct slot *slot); >> -int rpaphp_get_sensor_state(struct slot *slot, int *state); >> - >> /* rpaphp_core.c */ >> int rpaphp_add_slot(struct device_node *dn); >> -int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, >> - char **drc_name, char **drc_type, int *drc_power); >> +void dealloc_slot_struct(struct rpa_php_slot *slot); >> +struct rpa_php_slot *alloc_slot_struct(struct device_node *dn, int drc_index, >> + char *drc_name, int power_domain); >> +int rpaphp_register_slot(struct rpa_php_slot *slot); >> +int rpaphp_deregister_slot(struct rpa_php_slot *slot); >> +int rpaphp_add_slot(struct device_node *dn); >> >> -/* rpaphp_slot.c */ >> -void dealloc_slot_struct(struct slot *slot); >> -struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); >> -int rpaphp_register_slot(struct slot *slot); >> -int rpaphp_deregister_slot(struct slot *slot); >> +/* rpaphp_rtas.c */ >> +int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, >> + char **drc_name, char **drc_type, int *drc_power); >> +struct rpa_php_slot *rpaphp_rtas_add_slot(struct device_node *dn); >> >> #endif /* _PPC64PHP_H */ >> diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c >> index a639c5c..91eff8f 100644 >> --- a/drivers/pci/hotplug/rpaphp_core.c >> +++ b/drivers/pci/hotplug/rpaphp_core.c >> @@ -45,194 +45,118 @@ EXPORT_SYMBOL_GPL(rpaphp_slot_head); >> #define DRIVER_AUTHOR "Linda Xie <lxie@xxxxxxxxxx>" >> #define DRIVER_DESC "RPA HOT Plug PCI Controller Driver" >> >> -#define MAX_LOC_CODE 128 >> - >> -MODULE_AUTHOR(DRIVER_AUTHOR); >> -MODULE_DESCRIPTION(DRIVER_DESC); >> -MODULE_LICENSE("GPL"); >> - >> module_param_named(debug, rpaphp_debug, bool, 0644); >> >> -/** >> - * set_attention_status - set attention LED >> - * @hotplug_slot: target &hotplug_slot >> - * @value: LED control value >> - * >> - * echo 0 > attention -- set LED OFF >> - * echo 1 > attention -- set LED ON >> - * echo 2 > attention -- set LED ID(identify, light is blinking) >> - */ >> -static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) >> +/* free up the memory used by a slot */ >> +static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) >> { >> - int rc; >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - >> - switch (value) { >> - case 0: >> - case 1: >> - case 2: >> - break; >> - default: >> - value = 1; >> - } >> + struct rpa_php_slot *slot = hotplug_slot->private; >> >> - rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); >> - if (!rc) >> - hotplug_slot->info->attention_status = value; >> - >> - return rc; >> + dealloc_slot_struct(slot); >> } >> >> -/** >> - * get_power_status - get power status of a slot >> - * @hotplug_slot: slot to get status >> - * @value: pointer to store status >> - */ >> -static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) >> +void dealloc_slot_struct(struct rpa_php_slot *slot) >> { >> - int retval, level; >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - >> - retval = rtas_get_power_level(slot->power_domain, &level); >> - if (!retval) >> - *value = level; >> - return retval; >> + kfree(slot->hotplug_slot->info); >> + kfree(slot->name); >> + kfree(slot->hotplug_slot); >> + kfree(slot); >> } >> >> -/** >> - * get_attention_status - get attention LED status >> - * @hotplug_slot: slot to get status >> - * @value: pointer to store status >> - */ >> -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) >> +struct rpa_php_slot *alloc_slot_struct(struct device_node *dn, >> + int drc_index, char *drc_name, >> + int power_domain) >> { >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - *value = slot->hotplug_slot->info->attention_status; >> - return 0; >> -} >> - >> -static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) >> -{ >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - int rc, state; >> - >> - rc = rpaphp_get_sensor_state(slot, &state); >> - >> - *value = NOT_VALID; >> - if (rc) >> - return rc; >> + struct rpa_php_slot *slot; >> >> - if (state == EMPTY) >> - *value = EMPTY; >> - else if (state == PRESENT) >> - *value = slot->state; >> - >> - return 0; >> + slot = kzalloc(sizeof(*slot), GFP_KERNEL); >> + if (!slot) >> + goto error_nomem; >> + slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); >> + if (!slot->hotplug_slot) >> + goto error_slot; >> + slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), >> + GFP_KERNEL); >> + if (!slot->hotplug_slot->info) >> + goto error_hpslot; >> + slot->name = kstrdup(drc_name, GFP_KERNEL); >> + if (!slot->name) >> + goto error_info; >> + slot->dn = dn; >> + slot->index = drc_index; >> + slot->power_domain = power_domain; >> + slot->hotplug_slot->private = slot; >> + slot->hotplug_slot->release = &rpaphp_release_slot; >> + >> + slot->hotplug_slot->info->power_status = RPA_PHP_SLOT_POWER_ON; >> + slot->hotplug_slot->info->attention_status = RPA_PHP_SLOT_ATTEN_OFF; >> + slot->hotplug_slot->info->adapter_status = RPA_PHP_SLOT_EMPTY; >> + slot->state = RPA_PHP_SLOT_NOT_VALID; >> + >> + return slot; >> + >> +error_info: >> + kfree(slot->hotplug_slot->info); >> +error_hpslot: >> + kfree(slot->hotplug_slot); >> +error_slot: >> + kfree(slot); >> +error_nomem: >> + return NULL; >> } >> >> -static enum pci_bus_speed get_max_bus_speed(struct slot *slot) >> +int rpaphp_register_slot(struct rpa_php_slot *slot) >> { >> - enum pci_bus_speed speed; >> - switch (slot->type) { >> - case 1: >> - case 2: >> - case 3: >> - case 4: >> - case 5: >> - case 6: >> - speed = PCI_SPEED_33MHz; /* speed for case 1-6 */ >> - break; >> - case 7: >> - case 8: >> - speed = PCI_SPEED_66MHz; >> - break; >> - case 11: >> - case 14: >> - speed = PCI_SPEED_66MHz_PCIX; >> - break; >> - case 12: >> - case 15: >> - speed = PCI_SPEED_100MHz_PCIX; >> - break; >> - case 13: >> - case 16: >> - speed = PCI_SPEED_133MHz_PCIX; >> - break; >> - default: >> - speed = PCI_SPEED_UNKNOWN; >> + struct hotplug_slot *php_slot = slot->hotplug_slot; >> + struct rpa_php_slot *tmp; >> + int slotno, retval; >> + >> + dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", >> + __func__, slot->dn->full_name, slot->index, slot->name, >> + slot->power_domain, slot->type); >> + >> + /* Should not try to register the same slot twice */ >> + list_for_each_entry(tmp, &rpaphp_slot_head, rpaphp_slot_list) { >> + if (!strcmp(tmp->name, slot->name)) { >> + err("%s: Slot[%s] is already registered\n", >> + __func__, slot->name); >> + return -EAGAIN; >> + } >> + } >> + if (slot->dn->child) >> + slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); >> + else >> + slotno = -1; >> + retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name); >> + if (retval) { >> + err("pci_hp_register failed with error %d\n", retval); >> + return retval; >> } >> >> - return speed; >> + /* add slot to our internal list */ >> + list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); >> + info("Slot [%s] registered\n", slot->name); >> + return 0; >> } >> >> -static int parse_drc_props(struct device_node *dn, u32 drc_index, >> - char **drc_name, char **drc_type, u32 *drc_power) >> +int rpaphp_deregister_slot(struct rpa_php_slot *slot) >> { >> - const u32 *indexes, *names, *types, *domains; >> - char *name, *type; >> - struct device_node *parent = dn; >> - u32 i; >> - >> - while ((parent = of_get_parent(parent))) { >> - indexes = of_get_property(parent, "ibm,drc-indexes", NULL); >> - names = of_get_property(parent, "ibm,drc-names", NULL); >> - types = of_get_property(parent, "ibm,drc-types", NULL); >> - domains = of_get_property(parent, "ibm,drc-power-domains", NULL); >> - >> - if (!indexes || !names || !types || !domains) { >> - of_node_put(parent); >> - continue; >> - } >> + struct hotplug_slot *php_slot = slot->hotplug_slot; >> + int retval = 0; >> >> - name = (char *)&names[1]; >> - type = (char *)&types[1]; >> - for (i = 0; i < be32_to_cpu(indexes[0]); i++) { >> - if (be32_to_cpu(indexes[i + 1]) != drc_index) { >> - name += (strlen(name) + 1); >> - type += (strlen(type) + 1); >> - continue; >> - } >> - >> - /* Matched index */ >> - if (drc_name) >> - *drc_name = name; >> - if (drc_type) >> - *drc_type = type; >> - if (drc_power) >> - *drc_power = be32_to_cpu(domains[i + 1]); >> - >> - of_node_put(parent); >> - return 0; >> - } >> - >> - /* Next level parent */ >> - of_node_put(parent); >> - } >> + dbg("%s - Entry: deregistering slot=%s\n", >> + __func__, slot->name); >> >> - return -ENODEV; >> -} >> + list_del(&slot->rpaphp_slot_list); >> >> -/* >> - * To get the DRC props describing the current node, first obtain it's >> - * my-drc-index property. Next obtain the DRC list from it's parent. Use >> - * the my-drc-index for correlation, and obtain the requested properties. >> - */ >> -int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, >> - char **drc_name, char **drc_type, int *drc_power) >> -{ >> - const u32 *my_index; >> - >> - /* Check if node is capable of hotplug */ >> - my_index = of_get_property(dn, "ibm,my-drc-index", NULL); >> - if (!my_index) >> - return -EINVAL; >> - if (drc_index) >> - *drc_index = be32_to_cpu(*my_index); >> + retval = pci_hp_deregister(php_slot); >> + if (retval) >> + err("Problem unregistering a slot %s\n", slot->name); >> >> - return parse_drc_props(dn, be32_to_cpu(*my_index), >> - drc_name, drc_type, drc_power); >> + dbg("%s - Exit: rc[%d]\n", __func__, retval); >> + return retval; >> } >> -EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); >> +EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); >> >> /** >> * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. >> @@ -252,29 +176,22 @@ EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); >> */ >> int rpaphp_add_slot(struct device_node *dn) >> { >> - char *name, *type, *endptr; >> - int index, power_domain; >> - struct slot *slot; >> - int val, ret; >> - >> - /* Get and parse the hotplug properties */ >> - ret = rpaphp_get_drc_props(dn, &index, &name, &type, &power_domain); >> - if (ret) >> - return ret; >> - >> - /* PCI Hotplug nodes have an integer for drc_type */ >> - val = simple_strtoul(type, &endptr, 10); >> - if (endptr == type) >> - return -EINVAL; >> + struct rpa_php_slot *slot = NULL; >> + int ret; >> >> - slot = alloc_slot_struct(dn, index, name, power_domain); >> + /* Create slot */ >> + if (machine_is(pseries)) >> + slot = rpaphp_rtas_add_slot(dn); >> if (!slot) >> - return -ENOMEM; >> + return -EIO; >> >> - slot->type = val; >> - ret = rpaphp_enable_slot(slot); >> - if (!ret) >> - ret = rpaphp_register_slot(slot); >> + /* Enable slot */ >> + ret = slot->hotplug_slot->ops->enable_slot(slot->hotplug_slot); >> + if (ret) >> + goto fail; >> + >> + /* Register slot */ >> + ret = rpaphp_register_slot(slot); >> if (ret) >> goto fail; >> >> @@ -288,7 +205,7 @@ EXPORT_SYMBOL_GPL(rpaphp_add_slot); >> static void __exit cleanup_slots(void) >> { >> struct list_head *tmp, *n; >> - struct slot *slot; >> + struct rpa_php_slot *slot; >> >> /* >> * Unregister all of our slots with the pci_hotplug subsystem, >> @@ -297,7 +214,7 @@ static void __exit cleanup_slots(void) >> */ >> >> list_for_each_safe(tmp, n, &rpaphp_slot_head) { >> - slot = list_entry(tmp, struct slot, rpaphp_slot_list); >> + slot = list_entry(tmp, struct rpa_php_slot, rpaphp_slot_list); >> list_del(&slot->rpaphp_slot_list); >> pci_hp_deregister(slot->hotplug_slot); >> } >> @@ -320,59 +237,9 @@ static void __exit rpaphp_exit(void) >> cleanup_slots(); >> } >> >> -static int enable_slot(struct hotplug_slot *hotplug_slot) >> -{ >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - int state; >> - int retval; >> - >> - if (slot->state == CONFIGURED) >> - return 0; >> - >> - retval = rpaphp_get_sensor_state(slot, &state); >> - if (retval) >> - return retval; >> - >> - if (state == PRESENT) { >> - pci_lock_rescan_remove(); >> - pcibios_add_pci_devices(slot->bus); >> - pci_unlock_rescan_remove(); >> - slot->state = CONFIGURED; >> - } else if (state == EMPTY) { >> - slot->state = EMPTY; >> - } else { >> - err("%s: slot[%s] is in invalid state\n", __func__, slot->name); >> - slot->state = NOT_VALID; >> - return -EINVAL; >> - } >> - >> - slot->bus->max_bus_speed = get_max_bus_speed(slot); >> - return 0; >> -} >> - >> -static int disable_slot(struct hotplug_slot *hotplug_slot) >> -{ >> - struct slot *slot = (struct slot *)hotplug_slot->private; >> - if (slot->state == NOT_CONFIGURED) >> - return -EINVAL; >> - >> - pci_lock_rescan_remove(); >> - pcibios_remove_pci_devices(slot->bus); >> - pci_unlock_rescan_remove(); >> - vm_unmap_aliases(); >> - >> - slot->state = NOT_CONFIGURED; >> - return 0; >> -} >> - >> -struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { >> - .enable_slot = enable_slot, >> - .disable_slot = disable_slot, >> - .set_attention_status = set_attention_status, >> - .get_power_status = get_power_status, >> - .get_attention_status = get_attention_status, >> - .get_adapter_status = get_adapter_status, >> -}; >> - >> module_init(rpaphp_init); >> module_exit(rpaphp_exit); >> + >> +MODULE_AUTHOR(DRIVER_AUTHOR); >> +MODULE_DESCRIPTION(DRIVER_DESC); >> +MODULE_LICENSE("GPL"); >> diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c >> deleted file mode 100644 >> index a4aa65c..0000000 >> --- a/drivers/pci/hotplug/rpaphp_pci.c >> +++ /dev/null >> @@ -1,136 +0,0 @@ >> -/* >> - * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform. >> - * Copyright (C) 2003 Linda Xie <lxie@xxxxxxxxxx> >> - * >> - * All rights reserved. >> - * >> - * This program is free software; you can redistribute it and/or modify >> - * it under the terms of the GNU General Public License as published by >> - * the Free Software Foundation; either version 2 of the License, or (at >> - * your option) any later version. >> - * >> - * This program is distributed in the hope that it will be useful, but >> - * WITHOUT ANY WARRANTY; without even the implied warranty of >> - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or >> - * NON INFRINGEMENT. See the GNU General Public License for more >> - * details. >> - * >> - * You should have received a copy of the GNU General Public License >> - * along with this program; if not, write to the Free Software >> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >> - * >> - * Send feedback to <lxie@xxxxxxxxxx> >> - * >> - */ >> -#include <linux/pci.h> >> -#include <linux/string.h> >> - >> -#include <asm/pci-bridge.h> >> -#include <asm/rtas.h> >> -#include <asm/machdep.h> >> - >> -#include "../pci.h" /* for pci_add_new_bus */ >> -#include "rpaphp.h" >> - >> -int rpaphp_get_sensor_state(struct slot *slot, int *state) >> -{ >> - int rc; >> - int setlevel; >> - >> - rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state); >> - if (rc >= 0) >> - return rc; >> - if (rc != -EFAULT && rc != -EEXIST) { >> - err("%s: Failure %d getting sensor state on slot[%s]\n", >> - __func__, rc, slot->name); >> - return rc; >> - } >> - >> - >> - /* >> - * Some slots have to be powered up before >> - * get-sensor will succeed >> - */ >> - dbg("%s: Slot[%s] must be power up to get sensor-state\n", >> - __func__, slot->name); >> - rc = rtas_set_power_level(slot->power_domain, POWER_ON, >> - &setlevel); >> - if (rc < 0) { >> - dbg("%s: Failure %d powerng on slot[%s]\n", >> - __func__, rc, slot->name); >> - return rc; >> - } >> - >> - return rtas_get_sensor(DR_ENTITY_SENSE, >> - slot->index, state); >> -} >> - >> -/** >> - * rpaphp_enable_slot - record slot state, config pci device >> - * @slot: target &slot >> - * >> - * Initialize values in the slot, and the hotplug_slot info >> - * structures to indicate if there is a pci card plugged into >> - * the slot. If the slot is not empty, run the pcibios routine >> - * to get pcibios stuff correctly set up. >> - */ >> -int rpaphp_enable_slot(struct slot *slot) >> -{ >> - int rc, level, state; >> - struct pci_bus *bus; >> - struct hotplug_slot_info *info = slot->hotplug_slot->info; >> - >> - info->adapter_status = NOT_VALID; >> - slot->state = EMPTY; >> - >> - /* Find out if the power is turned on for the slot */ >> - rc = rtas_get_power_level(slot->power_domain, &level); >> - if (rc) >> - return rc; >> - info->power_status = level; >> - >> - /* Figure out if there is an adapter in the slot */ >> - rc = rpaphp_get_sensor_state(slot, &state); >> - if (rc) >> - return rc; >> - >> - bus = pcibios_find_pci_bus(slot->dn); >> - if (!bus) { >> - err("%s: no pci_bus for dn %s\n", __func__, slot->dn->full_name); >> - return -EINVAL; >> - } >> - >> - info->adapter_status = EMPTY; >> - slot->bus = bus; >> - slot->pci_devs = &bus->devices; >> - >> - /* if there's an adapter in the slot, go add the pci devices */ >> - if (state == PRESENT) { >> - info->adapter_status = NOT_CONFIGURED; >> - slot->state = NOT_CONFIGURED; >> - >> - /* non-empty slot has to have child */ >> - if (!slot->dn->child) { >> - err("%s: slot[%s]'s device_node doesn't have child for adapter\n", >> - __func__, slot->name); >> - return -EINVAL; >> - } >> - >> - if (list_empty(&bus->devices)) >> - pcibios_add_pci_devices(bus); >> - >> - if (!list_empty(&bus->devices)) { >> - info->adapter_status = CONFIGURED; >> - slot->state = CONFIGURED; >> - } >> - >> - if (rpaphp_debug) { >> - struct pci_dev *dev; >> - dbg("%s: pci_devs of slot[%s]\n", __func__, slot->dn->full_name); >> - list_for_each_entry (dev, &bus->devices, bus_list) >> - dbg("\t%s\n", pci_name(dev)); >> - } >> - } >> - >> - return 0; >> -} >> diff --git a/drivers/pci/hotplug/rpaphp_rtas.c b/drivers/pci/hotplug/rpaphp_rtas.c >> new file mode 100644 >> index 0000000..74f024a >> --- /dev/null >> +++ b/drivers/pci/hotplug/rpaphp_rtas.c >> @@ -0,0 +1,320 @@ >> +/* >> + * RTAS backend for RPA-compliant PP64 platform >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or (at >> + * your option) any later version. >> + */ >> + >> +#include <linux/kernel.h> >> +#include <linux/module.h> >> +#include <linux/moduleparam.h> >> +#include <linux/pci.h> >> +#include <linux/pci_hotplug.h> >> +#include <linux/smp.h> >> +#include <linux/init.h> >> +#include <linux/vmalloc.h> >> +#include <asm/eeh.h> >> +#include <asm/rtas.h> >> +#include <asm/pci-bridge.h> >> + >> +#include "../pci.h" >> +#include "rpaphp.h" >> + >> +#define RPA_PHP_DR_INDICATOR 9002 >> +#define RPA_PHP_DR_ENTITY_SENSE 9003 >> + >> +static int get_power_status(struct hotplug_slot *hp_slot, u8 *val) >> +{ >> + struct rpa_php_slot *slot = hp_slot->private; >> + int state, ret; >> + >> + /* By default, the power is on */ >> + *val = RPA_PHP_SLOT_POWER_ON; >> + >> + /* Retrieve power state from firmware, which might fail */ >> + ret = rtas_get_power_level(slot->power_domain, &state); >> + if (!ret) { >> + if (state > 0) >> + hp_slot->info->power_status = RPA_PHP_SLOT_POWER_ON; >> + else >> + hp_slot->info->power_status = RPA_PHP_SLOT_POWER_OFF; >> + *val = hp_slot->info->power_status; >> + } >> + >> + return 0; >> +} >> + >> +static int get_adapter_status(struct hotplug_slot *hp_slot, u8 *val) >> +{ >> + struct rpa_php_slot *slot = hp_slot->private; >> + int state, ret; >> + >> + /* By default, the slot is empty */ >> + *val = RPA_PHP_SLOT_EMPTY; >> + >> + /* Retrieve presence from firmware */ >> + ret = rtas_get_sensor(RPA_PHP_DR_ENTITY_SENSE, slot->index, &state); >> + if (ret >= 0) { >> + if (state > 0) >> + hp_slot->info->adapter_status = RPA_PHP_SLOT_PRESENT; >> + else >> + hp_slot->info->adapter_status = RPA_PHP_SLOT_EMPTY; >> + *val = hp_slot->info->adapter_status; >> + return 0; >> + } >> + >> + /* Check if we need power slot on and retry */ >> + if (ret != -EFAULT && ret != -EEXIST) { >> + err("%s: Error %d getting slot[%s] presence\n", >> + __func__, ret, slot->name); >> + return ret; >> + } >> + >> + /* Power slot on, which might fail */ >> + ret = rtas_set_power_level(slot->power_domain, >> + RPA_PHP_SLOT_POWER_ON, &state); >> + if (!ret) >> + hp_slot->info->power_status = RPA_PHP_SLOT_POWER_ON; >> + >> + /* Recheck the presence */ >> + ret = rtas_get_sensor(RPA_PHP_DR_ENTITY_SENSE, slot->index, &state); >> + if (ret >= 0) { >> + if (state > 0) >> + hp_slot->info->adapter_status = RPA_PHP_SLOT_PRESENT; >> + else >> + hp_slot->info->adapter_status = RPA_PHP_SLOT_EMPTY; >> + *val = hp_slot->info->adapter_status; >> + } >> + >> + return 0; >> +} >> + >> +static int set_attention_status(struct hotplug_slot *hp_slot, u8 val) >> +{ >> + struct rpa_php_slot *slot = hp_slot->private; >> + int ret; >> + >> + /* >> + * The default operation would to turn on >> + * the attention >> + */ >> + switch (val) { >> + case RPA_PHP_SLOT_ATTEN_OFF: >> + case RPA_PHP_SLOT_ATTEN_ON: >> + case RPA_PHP_SLOT_ATTEN_IND: >> + case RPA_PHP_SLOT_ATTEN_ACT: >> + break; >> + default: >> + val = RPA_PHP_SLOT_ATTEN_ON; >> + } >> + >> + /* Set the attention */ >> + ret = rtas_set_indicator(RPA_PHP_DR_INDICATOR, slot->index, val); >> + if (!ret) >> + hp_slot->info->attention_status = val; >> + >> + return ret; >> +} >> + >> +static enum pci_bus_speed get_max_bus_speed(struct rpa_php_slot *slot) >> +{ >> + enum pci_bus_speed speed; >> + >> + switch (slot->type) { >> + case 1 ... 6: >> + speed = PCI_SPEED_33MHz; >> + break; >> + case 7 ... 8: >> + speed = PCI_SPEED_66MHz; >> + break; >> + case 11: >> + case 14: >> + speed = PCI_SPEED_66MHz_PCIX; >> + break; >> + case 12: >> + case 15: >> + speed = PCI_SPEED_100MHz_PCIX; >> + break; >> + case 13: >> + case 16: >> + speed = PCI_SPEED_133MHz_PCIX; >> + break; >> + default: >> + speed = PCI_SPEED_UNKNOWN; >> + } >> + >> + return speed; >> +} >> + >> +static int enable_slot(struct hotplug_slot *hp_slot) >> +{ >> + struct rpa_php_slot *slot = hp_slot->private; >> + uint8_t presence; >> + int ret; >> + >> + /* Check if the slot has been configured */ >> + if (slot->state == RPA_PHP_SLOT_CONFIGURED) >> + return 0; >> + >> + /* Retrieve slot presence status */ >> + ret = hp_slot->ops->get_adapter_status(hp_slot, &presence); >> + if (ret) >> + return ret; >> + >> + switch (presence) { >> + case RPA_PHP_SLOT_PRESENT: >> + pci_lock_rescan_remove(); >> + pcibios_add_pci_devices(slot->bus); >> + pci_unlock_rescan_remove(); >> + slot->state = RPA_PHP_SLOT_CONFIGURED; >> + break; >> + case RPA_PHP_SLOT_EMPTY: >> + slot->state = RPA_PHP_SLOT_NOT_CONFIGURED; >> + break; >> + default: >> + slot->state = RPA_PHP_SLOT_NOT_VALID; >> + return -EINVAL; >> + } >> + >> + /* Fix the bus maximal speed */ >> + slot->bus->max_bus_speed = get_max_bus_speed(slot); >> + return 0; >> +} >> + >> +static int disable_slot(struct hotplug_slot *hp_slot) >> +{ >> + struct rpa_php_slot *slot = hp_slot->private; >> + >> + if (slot->state != RPA_PHP_SLOT_CONFIGURED) >> + return 0; >> + >> + pci_lock_rescan_remove(); >> + pcibios_remove_pci_devices(slot->bus); >> + pci_unlock_rescan_remove(); >> + vm_unmap_aliases(); >> + >> + slot->state = RPA_PHP_SLOT_NOT_CONFIGURED; >> + return 0; >> +} >> + >> +static struct hotplug_slot_ops rpaphp_rtas_ops = { >> + .enable_slot = enable_slot, >> + .disable_slot = disable_slot, >> + .set_attention_status = set_attention_status, >> + .get_power_status = get_power_status, >> + .get_adapter_status = get_adapter_status, >> +}; >> + >> +static int parse_drc_props(struct device_node *dn, u32 drc_index, >> + char **drc_name, char **drc_type, u32 *drc_power) >> +{ >> + const u32 *indexes, *names, *types, *domains; >> + char *name, *type; >> + struct device_node *parent = dn; >> + u32 i; >> + >> + while ((parent = of_get_parent(parent))) { >> + indexes = of_get_property(parent, "ibm,drc-indexes", NULL); >> + names = of_get_property(parent, "ibm,drc-names", NULL); >> + types = of_get_property(parent, "ibm,drc-types", NULL); >> + domains = of_get_property(parent, "ibm,drc-power-domains", NULL); >> + >> + if (!indexes || !names || !types || !domains) { >> + of_node_put(parent); >> + continue; >> + } >> + >> + name = (char *)&names[1]; >> + type = (char *)&types[1]; >> + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { >> + if (be32_to_cpu(indexes[i + 1]) != drc_index) { >> + name += (strlen(name) + 1); >> + type += (strlen(type) + 1); >> + continue; >> + } >> + >> + /* Matched index */ >> + if (drc_name) >> + *drc_name = name; >> + if (drc_type) >> + *drc_type = type; >> + if (drc_power) >> + *drc_power = be32_to_cpu(domains[i + 1]); >> + >> + of_node_put(parent); >> + return 0; >> + } >> + >> + /* Next level parent */ >> + of_node_put(parent); >> + } >> + >> + return -ENODEV; >> +} >> + >> +/* >> + * To get the DRC props describing the current node, first obtain it's >> + * my-drc-index property. Next obtain the DRC list from it's parent. Use >> + * the my-drc-index for correlation, and obtain the requested properties. >> + */ >> +int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, >> + char **drc_name, char **drc_type, int *drc_power) >> +{ >> + const u32 *my_index; >> + >> + /* Check if node is capable of hotplug */ >> + my_index = of_get_property(dn, "ibm,my-drc-index", NULL); >> + if (!my_index) >> + return -EINVAL; >> + if (drc_index) >> + *drc_index = be32_to_cpu(*my_index); >> + >> + return parse_drc_props(dn, be32_to_cpu(*my_index), >> + drc_name, drc_type, drc_power); >> +} >> +EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); >> + >> +struct rpa_php_slot *rpaphp_rtas_add_slot(struct device_node *dn) >> +{ >> + char *name, *type, *endptr; >> + int index, power_domain; >> + struct rpa_php_slot *slot; >> + struct pci_bus *bus; >> + int val, ret; >> + >> + /* Get and parse the hotplug properties */ >> + ret = rpaphp_get_drc_props(dn, &index, &name, &type, &power_domain); >> + if (ret) >> + return NULL; >> + >> + /* >> + * PCI hotplug slots have integer DRC type. That of >> + * PHB slot is fixed to "PHB" >> + */ >> + val = simple_strtoul(type, &endptr, 10); >> + if (strcmp(type, "PHB") && (endptr == type)) >> + return NULL; >> + >> + slot = alloc_slot_struct(dn, index, name, power_domain); >> + if (!slot) >> + return NULL; >> + >> + /* The slot should have an associated bus */ >> + bus = pcibios_find_pci_bus(dn); >> + if (!bus) { >> + err("%s: No PCI bus for device node %s\n", >> + __func__, dn->full_name); >> + goto fail; >> + } >> + >> + slot->hotplug_slot->ops = &rpaphp_rtas_ops; >> + slot->type = val; >> + slot->bus = bus; >> + slot->pci_devs = &bus->devices; >> + return slot; >> +fail: >> + dealloc_slot_struct(slot); >> + return NULL; >> +} >> diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c >> deleted file mode 100644 >> index be48e69..0000000 >> --- a/drivers/pci/hotplug/rpaphp_slot.c >> +++ /dev/null >> @@ -1,140 +0,0 @@ >> -/* >> - * RPA Virtual I/O device functions >> - * Copyright (C) 2004 Linda Xie <lxie@xxxxxxxxxx> >> - * >> - * All rights reserved. >> - * >> - * This program is free software; you can redistribute it and/or modify >> - * it under the terms of the GNU General Public License as published by >> - * the Free Software Foundation; either version 2 of the License, or (at >> - * your option) any later version. >> - * >> - * This program is distributed in the hope that it will be useful, but >> - * WITHOUT ANY WARRANTY; without even the implied warranty of >> - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or >> - * NON INFRINGEMENT. See the GNU General Public License for more >> - * details. >> - * >> - * You should have received a copy of the GNU General Public License >> - * along with this program; if not, write to the Free Software >> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >> - * >> - * Send feedback to <lxie@xxxxxxxxxx> >> - * >> - */ >> -#include <linux/kernel.h> >> -#include <linux/module.h> >> -#include <linux/sysfs.h> >> -#include <linux/pci.h> >> -#include <linux/string.h> >> -#include <linux/slab.h> >> - >> -#include <asm/rtas.h> >> -#include "rpaphp.h" >> - >> -/* free up the memory used by a slot */ >> -static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) >> -{ >> - struct slot *slot = (struct slot *) hotplug_slot->private; >> - dealloc_slot_struct(slot); >> -} >> - >> -void dealloc_slot_struct(struct slot *slot) >> -{ >> - kfree(slot->hotplug_slot->info); >> - kfree(slot->name); >> - kfree(slot->hotplug_slot); >> - kfree(slot); >> -} >> - >> -struct slot *alloc_slot_struct(struct device_node *dn, >> - int drc_index, char *drc_name, int power_domain) >> -{ >> - struct slot *slot; >> - >> - slot = kzalloc(sizeof(struct slot), GFP_KERNEL); >> - if (!slot) >> - goto error_nomem; >> - slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); >> - if (!slot->hotplug_slot) >> - goto error_slot; >> - slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), >> - GFP_KERNEL); >> - if (!slot->hotplug_slot->info) >> - goto error_hpslot; >> - slot->name = kstrdup(drc_name, GFP_KERNEL); >> - if (!slot->name) >> - goto error_info; >> - slot->dn = dn; >> - slot->index = drc_index; >> - slot->power_domain = power_domain; >> - slot->hotplug_slot->private = slot; >> - slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; >> - slot->hotplug_slot->release = &rpaphp_release_slot; >> - >> - return slot; >> - >> -error_info: >> - kfree(slot->hotplug_slot->info); >> -error_hpslot: >> - kfree(slot->hotplug_slot); >> -error_slot: >> - kfree(slot); >> -error_nomem: >> - return NULL; >> -} >> - >> -int rpaphp_deregister_slot(struct slot *slot) >> -{ >> - int retval = 0; >> - struct hotplug_slot *php_slot = slot->hotplug_slot; >> - >> - dbg("%s - Entry: deregistering slot=%s\n", >> - __func__, slot->name); >> - >> - list_del(&slot->rpaphp_slot_list); >> - >> - retval = pci_hp_deregister(php_slot); >> - if (retval) >> - err("Problem unregistering a slot %s\n", slot->name); >> - >> - dbg("%s - Exit: rc[%d]\n", __func__, retval); >> - return retval; >> -} >> -EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); >> - >> -int rpaphp_register_slot(struct slot *slot) >> -{ >> - struct hotplug_slot *php_slot = slot->hotplug_slot; >> - struct slot *tmp; >> - int retval; >> - int slotno; >> - >> - dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", >> - __func__, slot->dn->full_name, slot->index, slot->name, >> - slot->power_domain, slot->type); >> - >> - /* Should not try to register the same slot twice */ >> - list_for_each_entry(tmp, &rpaphp_slot_head, rpaphp_slot_list) { >> - if (!strcmp(tmp->name, slot->name)) { >> - err("%s: Slot[%s] is already registered\n", >> - __func__, slot->name); >> - return -EAGAIN; >> - } >> - } >> - >> - if (slot->dn->child) >> - slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); >> - else >> - slotno = -1; >> - retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name); >> - if (retval) { >> - err("pci_hp_register failed with error %d\n", retval); >> - return retval; >> - } >> - >> - /* add slot to our internal list */ >> - list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); >> - info("Slot [%s] registered\n", slot->name); >> - return 0; >> -} > > > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html