From patchwork Thu Mar 7 16:23:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabien DESSENNE X-Patchwork-Id: 10843317 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0586314DE for ; Thu, 7 Mar 2019 16:24:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8006D1FE8B for ; Thu, 7 Mar 2019 16:24:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7E6232F5F6; Thu, 7 Mar 2019 16:24:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DBD572F5E2 for ; Thu, 7 Mar 2019 16:24:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=IU1SjYLbwtHS0NEdMfGZEgkPotqnBEMWMxp2Ejr8uXE=; b=lGY9yt30gIj2C7 hVxq4F8E+wE2sFzb2ZxhxtTa8cEnnoJf1GR2NKfvB32KqvV1+q56yDT46S6F3iL/6yKYYVpBPdxpo rHnsgZLoK7V813g6rImlWqG8qtPO3JY+8FhsYAxJIVGPOg+EgvC2YbOLN9sf7o7XCxltoK7597lg/ w/obCXVKD1GAwGqnDY3vwsVD/jEqbRMTNc3CsHv9Hs/gJbIYP2YA25yWcttm9le0CxTny+jn3m2tZ TFD3ISkkGLk9ZHs2MGoOSxrxh65zsaaCwkVzhGE9vXZ0VVAqc8SPRVKkF80EgKL6j+n+TDiC0rMts Vrw/ZmwREWPh8xphCniA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1h1voW-0000YB-3R; Thu, 07 Mar 2019 16:24:08 +0000 Received: from mx07-00178001.pphosted.com ([62.209.51.94]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1h1voS-0000XX-72 for linux-arm-kernel@lists.infradead.org; Thu, 07 Mar 2019 16:24:06 +0000 Received: from pps.filterd (m0046037.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x27GBGfO011976; Thu, 7 Mar 2019 17:23:55 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2r315ut3eq-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Thu, 07 Mar 2019 17:23:55 +0100 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 435AE31; Thu, 7 Mar 2019 16:23:55 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas22.st.com [10.75.90.92]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 12F8F53E5; Thu, 7 Mar 2019 16:23:55 +0000 (GMT) Received: from SAFEX1HUBCAS23.st.com (10.75.90.47) by Safex1hubcas22.st.com (10.75.90.92) with Microsoft SMTP Server (TLS) id 14.3.361.1; Thu, 7 Mar 2019 17:23:55 +0100 Received: from localhost (10.129.4.33) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.361.1; Thu, 7 Mar 2019 17:23:54 +0100 From: Fabien Dessenne To: Thomas Gleixner , Jason Cooper , Marc Zyngier , Maxime Coquelin , Alexandre Torgue , , , Subject: [PATCH] irqchip: stm32: add a second level init to request hwspinlock Date: Thu, 7 Mar 2019 17:23:49 +0100 Message-ID: <1551975829-16350-1-git-send-email-fabien.dessenne@st.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 X-Originating-IP: [10.129.4.33] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-03-07_08:, , signatures=0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190307_082404_553049_B8F5E483 X-CRM114-Status: GOOD ( 20.87 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Benjamin Gaignard , Fabien Dessenne Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Requesting hwspinlock, at the first time it is used, is not correct: indeed, at that moment we are under raw_spin_lock_irqsave() context and hwspin_lock_request_specific() may sleep ("BUG: sleeping function called from invalid context"). Requesting hwspinlock during the init (stm32*_exti_of_init()) is also not possible (the hwspinlock framework is not ready at that stage of the kernel init). As a consequence, add a second level init (probed with arch_initcall) where we can safely request hwspinlock. Signed-off-by: Fabien Dessenne --- drivers/irqchip/irq-stm32-exti.c | 160 +++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 58 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 6edfd4b..2a5cc00 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -37,12 +39,6 @@ struct stm32_exti_bank { #define UNDEF_REG ~0 -enum stm32_exti_hwspinlock { - HWSPINLOCK_UNKNOWN, - HWSPINLOCK_NONE, - HWSPINLOCK_READY, -}; - struct stm32_desc_irq { u32 exti; u32 irq_parent; @@ -69,8 +65,6 @@ struct stm32_exti_host_data { void __iomem *base; struct stm32_exti_chip_data *chips_data; const struct stm32_exti_drv_data *drv_data; - struct device_node *node; - enum stm32_exti_hwspinlock hwlock_state; struct hwspinlock *hwlock; }; @@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d, static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) { - struct stm32_exti_host_data *host_data = chip_data->host_data; - struct hwspinlock *hwlock; - int id, ret = 0, timeout = 0; - - /* first time, check for hwspinlock availability */ - if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) { - id = of_hwspin_lock_get_id(host_data->node, 0); - if (id >= 0) { - hwlock = hwspin_lock_request_specific(id); - if (hwlock) { - /* found valid hwspinlock */ - host_data->hwlock_state = HWSPINLOCK_READY; - host_data->hwlock = hwlock; - pr_debug("%s hwspinlock = %d\n", __func__, id); - } else { - host_data->hwlock_state = HWSPINLOCK_NONE; - } - } else if (id != -EPROBE_DEFER) { - host_data->hwlock_state = HWSPINLOCK_NONE; - } else { - /* hwspinlock driver shall be ready at that stage */ - ret = -EPROBE_DEFER; - } - } + int ret, timeout = 0; - if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) { - /* - * Use the x_raw API since we are under spin_lock protection. - * Do not use the x_timeout API because we are under irq_disable - * mode (see __setup_irq()) - */ - do { - ret = hwspin_trylock_raw(host_data->hwlock); - if (!ret) - return 0; - - udelay(HWSPNLCK_RETRY_DELAY); - timeout += HWSPNLCK_RETRY_DELAY; - } while (timeout < HWSPNLCK_TIMEOUT); - - if (ret == -EBUSY) - ret = -ETIMEDOUT; - } + if (!chip_data->host_data->hwlock) + return 0; + + /* + * Use the x_raw API since we are under spin_lock protection. + * Do not use the x_timeout API because we are under irq_disable + * mode (see __setup_irq()) + */ + do { + ret = hwspin_trylock_raw(chip_data->host_data->hwlock); + if (!ret) + return 0; + + udelay(HWSPNLCK_RETRY_DELAY); + timeout += HWSPNLCK_RETRY_DELAY; + } while (timeout < HWSPNLCK_TIMEOUT); + + if (ret == -EBUSY) + ret = -ETIMEDOUT; if (ret) pr_err("%s can't get hwspinlock (%d)\n", __func__, ret); @@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) { - if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY)) + if (chip_data->host_data->hwlock) hwspin_unlock_raw(chip_data->host_data->hwlock); } @@ -683,8 +655,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, return NULL; host_data->drv_data = dd; - host_data->node = node; - host_data->hwlock_state = HWSPINLOCK_UNKNOWN; host_data->chips_data = kcalloc(dd->bank_nr, sizeof(struct stm32_exti_chip_data), GFP_KERNEL); @@ -711,7 +681,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, static struct stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, - u32 bank_idx) + u32 bank_idx, + struct device_node *node) { const struct stm32_exti_bank *stm32_bank; struct stm32_exti_chip_data *chip_data; @@ -741,7 +712,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, if (stm32_bank->fpr_ofst != UNDEF_REG) writel_relaxed(~0UL, base + stm32_bank->fpr_ofst); - pr_info("%pOF: bank%d\n", h_data->node, bank_idx); + pr_info("%pOF: bank%d\n", node, bank_idx); return chip_data; } @@ -781,7 +752,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, struct stm32_exti_chip_data *chip_data; stm32_bank = drv_data->exti_banks[i]; - chip_data = stm32_exti_chip_init(host_data, i); + chip_data = stm32_exti_chip_init(host_data, i, node); gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); @@ -844,7 +815,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, return -ENOMEM; for (i = 0; i < drv_data->bank_nr; i++) - stm32_exti_chip_init(host_data, i); + stm32_exti_chip_init(host_data, i, node); domain = irq_domain_add_hierarchy(parent_domain, 0, drv_data->bank_nr * IRQS_PER_BANK, @@ -868,6 +839,71 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, return ret; } +/* Note : stm32_exti_probe() is called after stm32*_exti_of_init() */ +static int stm32_exti_probe(struct platform_device *pdev) +{ + int id, ret = 0; + + id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); + + if (id == -EPROBE_DEFER) + /* hwspinlock framework not ready */ + return -EPROBE_DEFER; + + if (id == -ENOENT) + /* no hwspinlock defined (not an error, it is optional) */ + return 0; + + if (id >= 0) { + stm32_host_data->hwlock = hwspin_lock_request_specific(id); + if (!stm32_host_data->hwlock) { + dev_err(&pdev->dev, "Failed to request hwspinlock\n"); + ret = -EINVAL; + } + } else { + dev_err(&pdev->dev, "Failed to get hwspinlock\n"); + ret = id; + } + + return ret; +} + +static int stm32_exti_remove(struct platform_device *pdev) +{ + if (stm32_host_data->hwlock) + return hwspin_lock_free(stm32_host_data->hwlock); + + return 0; +} + +static const struct of_device_id stm32_exti_ids[] = { + { .compatible = "st,stm32mp1-exti", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_exti_ids); + +static struct platform_driver stm32_exti_driver = { + .probe = stm32_exti_probe, + .remove = stm32_exti_remove, + .driver = { + .name = "stm32_exti", + .of_match_table = stm32_exti_ids, + }, +}; + +static int __init stm32_exti_arch_init(void) +{ + return platform_driver_register(&stm32_exti_driver); +} + +static void __exit stm32_exti_arch_exit(void) +{ + return platform_driver_unregister(&stm32_exti_driver); +} + +arch_initcall(stm32_exti_arch_init); +module_exit(stm32_exti_arch_exit); + static int __init stm32f4_exti_of_init(struct device_node *np, struct device_node *parent) { @@ -887,7 +923,15 @@ IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); static int __init stm32mp1_exti_of_init(struct device_node *np, struct device_node *parent) { - return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); + int ret; + + ret = stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); + + /* Clear the OF_POPULATED flag so that stm32_exti_probe can be called */ + if (!ret) + of_node_clear_flag(np, OF_POPULATED); + + return ret; } IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);