From patchwork Mon Nov 24 22:49:24 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gavin Shan X-Patchwork-Id: 5370511 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9AE269F2F5 for ; Mon, 24 Nov 2014 22:49:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 59D2B20145 for ; Mon, 24 Nov 2014 22:49:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F320120154 for ; Mon, 24 Nov 2014 22:49:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750881AbaKXWtf (ORCPT ); Mon, 24 Nov 2014 17:49:35 -0500 Received: from e23smtp07.au.ibm.com ([202.81.31.140]:35835 "EHLO e23smtp07.au.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750789AbaKXWtc (ORCPT ); Mon, 24 Nov 2014 17:49:32 -0500 Received: from /spool/local by e23smtp07.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Nov 2014 08:49:30 +1000 Received: from d23dlp01.au.ibm.com (202.81.31.203) by e23smtp07.au.ibm.com (202.81.31.204) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 25 Nov 2014 08:49:29 +1000 Received: from d23relay10.au.ibm.com (d23relay10.au.ibm.com [9.190.26.77]) by d23dlp01.au.ibm.com (Postfix) with ESMTP id C7C002CE806C for ; Tue, 25 Nov 2014 09:49:28 +1100 (EST) Received: from d23av02.au.ibm.com (d23av02.au.ibm.com [9.190.235.138]) by d23relay10.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id sAOMnSgX34209926 for ; Tue, 25 Nov 2014 09:49:28 +1100 Received: from d23av02.au.ibm.com (localhost [127.0.0.1]) by d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id sAOMnRCV025606 for ; Tue, 25 Nov 2014 09:49:28 +1100 Received: from shangw (haven.au.ibm.com [9.192.253.15]) by d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id sAOMnRAg025599; Tue, 25 Nov 2014 09:49:27 +1100 Received: by shangw (Postfix, from userid 1000) id 4E2A13E047A; Tue, 25 Nov 2014 09:49:27 +1100 (EST) From: Gavin Shan To: linux-pci@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org, benh@kernel.crashing.org, mpe@ellerman.id.au, Gavin Shan Subject: [PATCH 7/8] PCI/hotplug/rpa: Hierarchial slots Date: Tue, 25 Nov 2014 09:49:24 +1100 Message-Id: <1416869365-7671-8-git-send-email-gwshan@linux.vnet.ibm.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1416869365-7671-1-git-send-email-gwshan@linux.vnet.ibm.com> References: <1416869365-7671-1-git-send-email-gwshan@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 14112422-0025-0000-0000-00000092A61C Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The direct or indirect parent of hotpluggable slot has possibility to be hotpluggable. Unfortunately, current implementation doesn't cover it. The patch fixes the issue: * When adding slots based on the given device node, the child device nodes are scanned to see if they're hotpluggable and add slots for them if applicable. * When unregistering slot, its children slots will be removed automatically. * Parent slot is added prior to child slots in addition path, while child slots should be removed before parent slot in removal path. Signed-off-by: Gavin Shan --- drivers/pci/hotplug/rpadlpar_core.c | 6 +-- drivers/pci/hotplug/rpaphp.h | 22 ++++---- drivers/pci/hotplug/rpaphp_core.c | 105 ++++++++++++++++++++++++------------ 3 files changed, 85 insertions(+), 48 deletions(-) diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index a36d2c9..f375e92 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -119,11 +119,9 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) */ static struct rpa_php_slot *find_php_slot(struct device_node *dn) { - struct list_head *tmp, *n; - struct rpa_php_slot *slot; + struct rpa_php_slot *slot, *tmp; - list_for_each_safe(tmp, n, &rpaphp_slot_head) { - slot = list_entry(tmp, struct rpa_php_slot, rpaphp_slot_list); + list_for_each_entry_safe(slot, tmp, &rpaphp_slot_head, link) { if (slot->dn == dn) return slot; } diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 09dd516..0354572 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -57,19 +57,21 @@ extern bool rpaphp_debug; #define RPA_PHP_SLOT_PRESENT 1 /* Presented */ struct rpa_php_slot { - struct list_head rpaphp_slot_list; - int state; + char *name; + 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; - char *name; - struct device_node *dn; - struct pci_bus *bus; - struct list_head *pci_devs; - struct hotplug_slot *hotplug_slot; + u32 index; + u32 type; + u32 power_domain; + struct device_node *dn; + struct pci_bus *bus; + struct list_head *pci_devs; + struct hotplug_slot *hotplug_slot; + struct list_head link; + struct list_head list; + struct list_head children; }; extern struct list_head rpaphp_slot_head; diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 91eff8f..ba28212 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,9 @@ struct rpa_php_slot *alloc_slot_struct(struct device_node *dn, slot->power_domain = power_domain; slot->hotplug_slot->private = slot; slot->hotplug_slot->release = &rpaphp_release_slot; + INIT_LIST_HEAD(&slot->link); + INIT_LIST_HEAD(&slot->list); + INIT_LIST_HEAD(&slot->children); slot->hotplug_slot->info->power_status = RPA_PHP_SLOT_POWER_ON; slot->hotplug_slot->info->attention_status = RPA_PHP_SLOT_ATTEN_OFF; @@ -107,16 +111,17 @@ error_nomem: int rpaphp_register_slot(struct rpa_php_slot *slot) { + struct device_node *dn; struct hotplug_slot *php_slot = slot->hotplug_slot; - struct rpa_php_slot *tmp; - int slotno, retval; + struct rpa_php_slot *parent, *tmp; + int slotno, ret; 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) { + list_for_each_entry(tmp, &rpaphp_slot_head, link) { if (!strcmp(tmp->name, slot->name)) { err("%s: Slot[%s] is already registered\n", __func__, slot->name); @@ -127,34 +132,62 @@ int rpaphp_register_slot(struct rpa_php_slot *slot) 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; + ret = pci_hp_register(php_slot, slot->bus, slotno, slot->name); + if (ret) { + err("pci_hp_register failed with error %d\n", ret); + return ret; + } + + /* Search parent slot */ + parent = NULL; + dn = slot->dn; + while (!parent && (dn = of_get_parent(dn))) { + if (!PCI_DN(dn)) { + of_node_put(dn); + break; + } + + list_for_each_entry(tmp, &rpaphp_slot_head, link) { + if (tmp->dn != dn) { + parent = tmp; + break; + } + } } - /* add slot to our internal list */ - list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); + /* Add slot to parent list */ + if (parent) + list_add(&slot->list, &parent->children); + + /* Add slot to global list */ + list_add(&slot->link, &rpaphp_slot_head); info("Slot [%s] registered\n", slot->name); return 0; } int rpaphp_deregister_slot(struct rpa_php_slot *slot) { + struct rpa_php_slot *child, *tmp; struct hotplug_slot *php_slot = slot->hotplug_slot; - int retval = 0; + int ret; - dbg("%s - Entry: deregistering slot=%s\n", - __func__, slot->name); + /* Unregister children firstly */ + list_for_each_entry_safe(child, tmp, &slot->children, list) { + ret = rpaphp_deregister_slot(child); + if (ret) + return ret; + } - list_del(&slot->rpaphp_slot_list); + /* Remove from the parent and global lists */ + list_del(&slot->list); + list_del(&slot->link); - retval = pci_hp_deregister(php_slot); - if (retval) - err("Problem unregistering a slot %s\n", slot->name); + ret = pci_hp_deregister(php_slot); + if (ret) + err("%s: Error %d unregistering slot[%s]\n", + __func__, ret, slot->name); - dbg("%s - Exit: rc[%d]\n", __func__, retval); - return retval; + return ret; } EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); @@ -176,24 +209,31 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); */ int rpaphp_add_slot(struct device_node *dn) { + struct device_node *child; struct rpa_php_slot *slot = NULL; int ret; /* Create slot */ if (machine_is(pseries)) slot = rpaphp_rtas_add_slot(dn); - if (!slot) - return -EIO; - /* Enable slot */ - ret = slot->hotplug_slot->ops->enable_slot(slot->hotplug_slot); - if (ret) - goto fail; + if (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; + /* Register slot */ + ret = rpaphp_register_slot(slot); + if (ret) + goto fail; + } + + for_each_child_of_node(dn, child) { + ret = rpaphp_add_slot(child); + if (ret) + return ret; + } return 0; fail: @@ -204,18 +244,15 @@ EXPORT_SYMBOL_GPL(rpaphp_add_slot); static void __exit cleanup_slots(void) { - struct list_head *tmp, *n; - struct rpa_php_slot *slot; + struct rpa_php_slot *slot, *tmp; /* * Unregister all of our slots with the pci_hotplug subsystem, * and free up all memory that we had allocated. * memory will be freed in release_slot callback. */ - - list_for_each_safe(tmp, n, &rpaphp_slot_head) { - slot = list_entry(tmp, struct rpa_php_slot, rpaphp_slot_list); - list_del(&slot->rpaphp_slot_list); + list_for_each_entry_safe(slot, tmp, &rpaphp_slot_head, link) { + list_del(&slot->link); pci_hp_deregister(slot->hotplug_slot); } }