From patchwork Wed Mar 13 15:50:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabien DESSENNE X-Patchwork-Id: 10851405 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 6621E1390 for ; Wed, 13 Mar 2019 15:51:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 487DA29D83 for ; Wed, 13 Mar 2019 15:51:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3C43D29FFC; Wed, 13 Mar 2019 15:51:30 +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 73BC429DBE for ; Wed, 13 Mar 2019 15:51:29 +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:References:In-Reply-To: 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: List-Owner; bh=mHYZsK7jw8nR469E3iZzYoK1ZLpWSvFsFTV9Dp39sZc=; b=A3A2AgV2hakkvA 6Z3436ZHnH2cURD9dHMYx4pLrvakAjR5ULXkKHk/+HxiSjIbsK6PKDmoCLyltpb7hSvOQXufH/rh8 0yiriPzD8O3rgJgvwCuc+EgDGDkCvKOURO42j0oDqZLMrccOpngwRkp+tPZFJ5xfI9dHDUh/Vp1Jk Nayb3wsPBt0WiWt+545fzLKL/CZcd5u3q6hy/uHMjl6pyTl7oT37Xbg7YSF+hw1trkcrsRcgIWfHI 3ubdSKqjCeju/2hp/XYL1yHhyD/hvCVZNTXSYx+ByX3ozfyk1PrvKLLdGyvP1o8NYVVB2+QsVPTdA DDvk50nPG0Xr0WR+VBeg==; 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 1h46A7-0007pM-OC; Wed, 13 Mar 2019 15:51:23 +0000 Received: from mx08-00178001.pphosted.com ([91.207.212.93] helo=mx07-00178001.pphosted.com) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1h469w-0007dH-RF for linux-arm-kernel@lists.infradead.org; Wed, 13 Mar 2019 15:51:14 +0000 Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x2DFp5fs012433; Wed, 13 Mar 2019 16:51:05 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2r458mjyf5-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Wed, 13 Mar 2019 16:51:05 +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 6B0A53A; Wed, 13 Mar 2019 15:51:04 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas24.st.com [10.75.90.94]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 4061253EF; Wed, 13 Mar 2019 15:51:04 +0000 (GMT) Received: from SAFEX1HUBCAS22.st.com (10.75.90.93) by Safex1hubcas24.st.com (10.75.90.94) with Microsoft SMTP Server (TLS) id 14.3.435.0; Wed, 13 Mar 2019 16:51:04 +0100 Received: from localhost (10.201.23.25) by Webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.361.1; Wed, 13 Mar 2019 16:51:03 +0100 From: Fabien Dessenne To: Ohad Ben-Cohen , Bjorn Andersson , Rob Herring , Mark Rutland , Maxime Coquelin , Alexandre Torgue , Jonathan Corbet , , , , , , Subject: [PATCH 2/6] hwspinlock: allow sharing of hwspinlocks Date: Wed, 13 Mar 2019 16:50:33 +0100 Message-ID: <1552492237-28810-3-git-send-email-fabien.dessenne@st.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1552492237-28810-1-git-send-email-fabien.dessenne@st.com> References: <1552492237-28810-1-git-send-email-fabien.dessenne@st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.23.25] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-03-13_09:, , signatures=0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190313_085113_171758_CFD98464 X-CRM114-Status: GOOD ( 23.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 The current implementation does not allow different devices to use a common hwspinlock. Offer the possibility to use the same hwspinlock by several users. If a device registers to the framework with #hwlock-cells = 2, then the second parameter of the 'hwlocks' DeviceTree property defines whether an hwlock is requested for an exclusive or a shared usage. If a device registers with #hwlock-cells = 1, then all the hwlocks are for an exclusive usage. Signed-off-by: Fabien Dessenne Acked-by: Loic Pallardy --- Documentation/hwspinlock.txt | 10 ++-- drivers/hwspinlock/hwspinlock_core.c | 82 +++++++++++++++++++++++++------- drivers/hwspinlock/hwspinlock_internal.h | 2 + 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt index ed640a2..e6ce2dd 100644 --- a/Documentation/hwspinlock.txt +++ b/Documentation/hwspinlock.txt @@ -54,9 +54,11 @@ Should be called from a process context (might sleep). struct hwspinlock *hwspin_lock_request_specific(unsigned int id); Assign a specific hwspinlock id and return its address, or NULL -if that hwspinlock is already in use. Usually board code will -be calling this function in order to reserve specific hwspinlock -ids for predefined purposes. +if that hwspinlock is already in use and not shared. If that specific +hwspinlock is declared as shared, it can be requested and used by +several users. +Usually board code will be calling this function in order to reserve +specific hwspinlock ids for predefined purposes. Should be called from a process context (might sleep). @@ -368,11 +370,13 @@ of which represents a single hardware lock:: * struct hwspinlock - this struct represents a single hwspinlock instance * @bank: the hwspinlock_device structure which owns this lock * @lock: initialized and used by hwspinlock core + * @refcount: number of users (when shared) * @priv: private data, owned by the underlying platform-specific hwspinlock drv */ struct hwspinlock { struct hwspinlock_device *bank; spinlock_t lock; + unsigned int refcount; void *priv; }; diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 2bad40d..53afdeb 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -25,6 +25,8 @@ /* radix tree tags */ #define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused */ +#define HWSPINLOCK_EXCLUSIVE (1) /* tags an hwspinlock as exclusive */ +#define HWSPINLOCK_SHARED (2) /* tags an hwspinlock as shared */ /* * A radix tree is used to maintain the available hwspinlock instances. @@ -291,7 +293,7 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock); * @hwlock_spec: hwlock specifier as found in the device tree * * This is a simple translation function, suitable for hwspinlock platform - * drivers that only has a lock specifier length of 1. + * drivers that only has a lock specifier length of 1 or 2. * * Returns a relative index of the lock within a specified bank on success, * or -EINVAL on invalid specifier cell count. @@ -299,7 +301,8 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock); static inline int of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) { - if (WARN_ON(hwlock_spec->args_count != 1)) + if (WARN_ON(hwlock_spec->args_count != 1 && + hwlock_spec->args_count != 2)) return -EINVAL; return hwlock_spec->args[0]; @@ -322,11 +325,12 @@ of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) int of_hwspin_lock_get_id(struct device_node *np, int index) { struct of_phandle_args args; - struct hwspinlock *hwlock; + struct hwspinlock *hwlock, *tmp; struct radix_tree_iter iter; void **slot; int id; int ret; + unsigned int tag; ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, &args); @@ -361,6 +365,37 @@ int of_hwspin_lock_get_id(struct device_node *np, int index) } id += hwlock->bank->base_id; + /* Set the EXCLUSIVE / SHARED tag */ + if (args.args_count == 2 && args.args[1]) { + /* Tag SHARED unless already tagged EXCLUSIVE */ + if (radix_tree_tag_get(&hwspinlock_tree, id, + HWSPINLOCK_EXCLUSIVE)) { + ret = -EINVAL; + goto out; + } + tag = HWSPINLOCK_SHARED; + } else { + /* Tag EXCLUSIVE unless already tagged SHARED */ + if (radix_tree_tag_get(&hwspinlock_tree, id, + HWSPINLOCK_SHARED)) { + ret = -EINVAL; + goto out; + } + tag = HWSPINLOCK_EXCLUSIVE; + } + + /* mark this hwspinlock */ + hwlock = radix_tree_lookup(&hwspinlock_tree, id); + if (!hwlock) { + ret = -EINVAL; + goto out; + } + + tmp = radix_tree_tag_set(&hwspinlock_tree, id, tag); + + /* self-sanity check which should never fail */ + WARN_ON(tmp != hwlock); + out: of_node_put(args.np); return ret ? ret : id; @@ -483,6 +518,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev, spin_lock_init(&hwlock->lock); hwlock->bank = bank; + hwlock->refcount = 0; ret = hwspin_lock_register_single(hwlock, base_id + i); if (ret) @@ -625,7 +661,7 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock) { struct device *dev = hwlock->bank->dev; struct hwspinlock *tmp; - int ret; + int ret, id; /* prevent underlying implementation from being removed */ if (!try_module_get(dev->driver->owner)) { @@ -642,13 +678,18 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock) return ret; } + /* update shareable refcount */ + id = hwlock_to_id(hwlock); + if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && + hwlock->refcount++) + goto out; + /* mark hwspinlock as used, should not fail */ - tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock), - HWSPINLOCK_UNUSED); + tmp = radix_tree_tag_clear(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); /* self-sanity check that should never fail */ WARN_ON(tmp != hwlock); - +out: return ret; } @@ -742,9 +783,9 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) /* sanity check (this shouldn't happen) */ WARN_ON(hwlock_to_id(hwlock) != id); - /* make sure this hwspinlock is unused */ - ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); - if (ret == 0) { + /* make sure this hwspinlock is unused or shareable */ + if (!radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && + !radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED)) { pr_warn("hwspinlock %u is already in use\n", id); hwlock = NULL; goto out; @@ -777,7 +818,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock) { struct device *dev; struct hwspinlock *tmp; - int ret; + int ret, id; if (!hwlock) { pr_err("invalid hwlock\n"); @@ -788,30 +829,35 @@ int hwspin_lock_free(struct hwspinlock *hwlock) mutex_lock(&hwspinlock_tree_lock); /* make sure the hwspinlock is used */ - ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock), - HWSPINLOCK_UNUSED); + id = hwlock_to_id(hwlock); + ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); if (ret == 1) { dev_err(dev, "%s: hwlock is already free\n", __func__); dump_stack(); ret = -EINVAL; - goto out; + goto unlock; } /* notify the underlying device that power is not needed */ ret = pm_runtime_put(dev); if (ret < 0) - goto out; + goto unlock; + + /* update shareable refcount */ + if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED) && + --hwlock->refcount) + goto put; /* mark this hwspinlock as available */ - tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock), - HWSPINLOCK_UNUSED); + tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); /* sanity check (this shouldn't happen) */ WARN_ON(tmp != hwlock); +put: module_put(dev->driver->owner); -out: +unlock: mutex_unlock(&hwspinlock_tree_lock); return ret; } diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h index 9eb6bd0..c808e11 100644 --- a/drivers/hwspinlock/hwspinlock_internal.h +++ b/drivers/hwspinlock/hwspinlock_internal.h @@ -35,11 +35,13 @@ struct hwspinlock_ops { * struct hwspinlock - this struct represents a single hwspinlock instance * @bank: the hwspinlock_device structure which owns this lock * @lock: initialized and used by hwspinlock core + * @refcount: number of users (when shared) * @priv: private data, owned by the underlying platform-specific hwspinlock drv */ struct hwspinlock { struct hwspinlock_device *bank; spinlock_t lock; + unsigned int refcount; void *priv; };