From: Michael R. <md...@li...> - 2015-05-18 23:55:49
|
The following patches address a number of issue that arise when unplugging PHBs from a QEMU/PowerKVM pSeries guest. Most are due to minor differences in how PHBs are allocated in QEMU (lots of empty PCI slots) vs. PowerVM (1 slot per PHB, generally pre-populated with a device). The last patch is to simplify automation of PHB unplug/hotplug in rtas_errd, which currently relies on numerical DRC indexes for PCI/LMB hotplug (patch not yet posted, as it relies on these changes), as well as for parity with current drmgr functionality with PCI/LMB command syntax. QEMU patches for PHB hotplug are available here: http://thread.gmane.org/gmane.comp.emulators.qemu/333360 There are still in review, but the powerpc-utils bits are not expected to change and follow the same format as PCI/LMB. |
From: Michael R. <md...@li...> - 2015-05-18 23:55:51
|
Current code assumes that slots under a PHB are populated during PHB removal. As a result, we attempt to unconfigure the slot/adapter by powering it off, then checking for an 'unconfigured' state via get_hp_adaptor_status/DR_ENTITY_SENSE. However, if the slot is empty well get an 'emtpy' state instead. We can avoid this by simply not attempting to unconfigure/poweroff an adapter if the slot is empty, but it's possible we rely on this in some cases to safely power-off slots. Instead, simply allow DR_ENTITY_SENSE to report 'empty' after power-off in addition to 'unconfigured'. Signed-by-off: Michael Roth <md...@li...> --- src/drmgr/common_pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c index 64ca08f..119c352 100644 --- a/src/drmgr/common_pci.c +++ b/src/drmgr/common_pci.c @@ -1492,9 +1492,12 @@ enable_hp_children(char *drc_name) int disable_hp_children(char *drc_name) { if (get_hp_adapter_status(drc_name) != NOT_CONFIG) { + int status; + set_hp_adapter_status(PHP_UNCONFIG_ADAPTER, drc_name); + status = get_hp_adapter_status(drc_name); - if (get_hp_adapter_status(drc_name) != NOT_CONFIG) + if (status != NOT_CONFIG && status != EMPTY) return 1; } return 0; -- 1.9.1 |
[Powerpc-utils-devel] [PATCH 2/4] drmgr: improve PHB removal
performance by avoiding hp_list rebuild
From: Michael R. <md...@li...> - 2015-05-18 23:55:52
|
Signed-off-by: Michael Roth <md...@li...> --- src/drmgr/common_pci.c | 35 +++++++++++++++++++++++++++-------- src/drmgr/drpci.h | 1 + src/drmgr/drslot_chrp_phb.c | 13 ++++++++++++- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c index 119c352..04a8a35 100644 --- a/src/drmgr/common_pci.c +++ b/src/drmgr/common_pci.c @@ -1433,6 +1433,28 @@ release_hp_resource(struct dr_node *node) } /** + * release_hp_children_from_node + * + * @param parent_slot dr_node of slot to release children from + * @returns 0 on success, !0 otherwise + */ +int +release_hp_children_from_node(struct dr_node *slot) +{ + struct dr_node *child; + int rc; + + for (child = slot->children; child; child = child->next) { + rc = release_hp_resource(child); + if (rc) + return rc; + } + + return 0; +} + + +/** * release_hp_children * * @param parent_drc_name @@ -1441,7 +1463,7 @@ release_hp_resource(struct dr_node *node) int release_hp_children(char *parent_drc_name) { - struct dr_node *hp_list, *slot, *child; + struct dr_node *hp_list, *slot; int rc; hp_list = get_hp_nodes(); @@ -1450,16 +1472,13 @@ release_hp_children(char *parent_drc_name) break; if (slot == NULL) { - free_node(hp_list); - return -EINVAL; + rc = -EINVAL; + goto out; } - for (child = slot->children; child; child = child->next) { - rc = release_hp_resource(child); - if (rc) - return rc; - } + rc = release_hp_children_from_node(slot); +out: free_node(hp_list); return (rc < 0) ? rc : 0; } diff --git a/src/drmgr/drpci.h b/src/drmgr/drpci.h index f5221fc..b103c96 100644 --- a/src/drmgr/drpci.h +++ b/src/drmgr/drpci.h @@ -65,6 +65,7 @@ int get_hp_adapter_status(char *); int set_hp_adapter_status(uint, char *); int pci_rescan_bus(); int pci_remove_device(struct dr_node *); +int release_hp_children_from_node(struct dr_node *); int release_hp_children(char *); int dlpar_remove_slot(const char *); int dlpar_add_slot(const char *); diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c index 466ed11..eda10eb 100644 --- a/src/drmgr/drslot_chrp_phb.c +++ b/src/drmgr/drslot_chrp_phb.c @@ -247,6 +247,7 @@ remove_phb(struct options *opts) { struct dr_node *phb; struct dr_node *child; + struct dr_node *hp_list; int rc = 0; phb = get_node_by_name(opts->usr_drc_name, PHB_NODES); @@ -262,14 +263,24 @@ remove_phb(struct options *opts) } /* Now, disable any hotplug children */ + hp_list = get_hp_nodes(); + for (child = phb->children; child; child = child->next) { + struct dr_node *slot; + if (child->dev_type == PCI_HP_DEV) { rc = disable_hp_children(child->drc_name); if (rc) say(ERROR, "failed to disable hotplug children\n"); - rc = release_hp_children(child->drc_name); + /* find dr_node corresponding to child slot's drc_name */ + for (slot = hp_list; slot; slot = slot->next) + if (!strcmp(child->drc_name, slot->drc_name)) + break; + + /* release any hp children from the slot */ + rc = release_hp_children_from_node(slot); if (rc && rc != -EINVAL) { say(ERROR, "failed to release hotplug children\n"); -- 1.9.1 |
From: Michael R. <md...@li...> - 2015-05-18 23:55:54
|
Currently we fail to release a PHB to firmware if we're unable to remove the PHB's interrupt-controller node from the guest device tree. However, according to update_phb_ic_info(): "... there can be more ICs than PHBs on a system. In this case, some ICs won't have my-drc-index." In such cases, we don't assign the 'interrupt-controller*' path to the PHB's OF node, so simply skip the IC node removal (it either doesn't exist, or is not not owned by this PHB) when this occurs and proceed with releasing the PHB. Signed-off-by: Michael Roth <md...@li...> --- src/drmgr/drslot_chrp_phb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c index eda10eb..5fb25cb 100644 --- a/src/drmgr/drslot_chrp_phb.c +++ b/src/drmgr/drslot_chrp_phb.c @@ -75,9 +75,11 @@ release_phb(struct dr_node *phb) if (rc) return rc; - rc = remove_device_tree_nodes(phb->phb_ic_ofdt_path); - if (rc) - return rc; + if (phb->phb_ic_ofdt_path[0] != '\0') { + rc = remove_device_tree_nodes(phb->phb_ic_ofdt_path); + if (rc) + return rc; + } rc = release_drc(phb->drc_index, PHB_DEV); -- 1.9.1 |
From: Michael R. <md...@li...> - 2015-05-18 23:55:56
|
For each invocation involving '-c phb', if a numerical value is given for -s do a lookup through PHB list to find the corresponding DRC name. Signed-off-by: Michael Roth <md...@li...> --- src/drmgr/drslot_chrp_phb.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c index 5fb25cb..3ed109c 100644 --- a/src/drmgr/drslot_chrp_phb.c +++ b/src/drmgr/drslot_chrp_phb.c @@ -456,8 +456,14 @@ phb_add_error: int valid_phb_options(struct options *opts) { - if (opts->usr_drc_name == NULL) { - say(ERROR, "A drc name must be specified\n"); + /* The -s option can specify a drc name or drc index */ + if (opts->usr_drc_name && !strncmp(opts->usr_drc_name, "0x", 2)) { + opts->usr_drc_index = strtoul(opts->usr_drc_name, NULL, 16); + opts->usr_drc_name = NULL; + } + + if (opts->usr_drc_name == NULL && !opts->usr_drc_index) { + say(ERROR, "A drc name or index must be specified\n"); return -1; } @@ -482,6 +488,18 @@ drslot_chrp_phb(struct options *opts) return rc; } + if (!opts->usr_drc_name) { + struct dr_connector *drc_list = get_drc_info(OFDT_BASE); + opts->usr_drc_name = drc_index_to_name(opts->usr_drc_index, + drc_list); + if (!opts->usr_drc_name) { + say(ERROR, + "Could not locate DRC name for DRC index: 0x%x", + opts->usr_drc_index); + return -1; + } + } + switch(opts->action) { case ADD: rc = add_phb(opts); -- 1.9.1 |