Received: by 10.223.185.116 with SMTP id b49csp533428wrg; Fri, 16 Feb 2018 03:08:00 -0800 (PST) X-Google-Smtp-Source: AH8x22545IUj1yrKIIR+YajZlvrrwTJOEMCjDifHPLYwjqFBX3AuMtc1uVUl9vpohVDU3cN4BRnz X-Received: by 10.98.12.1 with SMTP id u1mr5815663pfi.192.1518779280330; Fri, 16 Feb 2018 03:08:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518779280; cv=none; d=google.com; s=arc-20160816; b=nKgtfh/0GWhL1gd0Yize8YCfOWAOfQ7PWeD7/BhZEfrYCiHiWcPM8UKFdTQGNNrk48 Kxk1rqJov5MkrnG3addbKPc5yegVuWe+8dm++NvEiDc+cvIEnJObq5sFez/6dQJdeziA kKh4LjJNuatgszn5lKjrk+4PnAxGsHHjpiyYtlGX6KaON/qOxUx4HLbQav5KNl4M97el YSCUCho1gEL3Vp1ckHZRUfDqKdMksy/bxeVoWlMKLwVIY1g1WbJlFIYJstinHVuO2DNw TqJTfkPuisBoVYqDcLnEq6/Hc0bFEdq1HZscZE6s/aHLceWWYy4+gT+AA6S5oLh7XWVl C00A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dmarc-filter:dkim-signature:dkim-signature :arc-authentication-results; bh=ba9/d12qWWebtAWyC/oPhMAkjditsRY0yFplg9NzH+s=; b=uewntf25Vlngbg4Y7ER+u2dbZPEfAHWKbieOBKpwdXFiw+f1Neqgm+hl7h7Aa8RfAE P2RHzBkQn4nXIcYPvwfJMW8ViH6CkCXgqBDp/3OZie+jv1346qlqlPSYSp7PqTYCpKiK BFoiDgnnXmAh8hm0s5EweXsC9VHj8bd/D7NX3rbtC0VVvn5DBfcnuo78d5oMLY5bnXVG n/VqbaPFxO+aCKwU1HPRMM+/EJN+aYXliuamCvPj8jrlAwh1w0o2mZU2/BhtMwx5FepO C21xlJ7ObPFO9WdB39Q5tVyI2I6utKZn+G2TH8k/rhACkBjKzsq6cZGJjKUtE+JYIdDW qXYw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=bBE7xwIY; dkim=pass header.i=@codeaurora.org header.s=default header.b=o8UrjFgl; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s9-v6si2474707plr.579.2018.02.16.03.07.45; Fri, 16 Feb 2018 03:08:00 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=bBE7xwIY; dkim=pass header.i=@codeaurora.org header.s=default header.b=o8UrjFgl; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1427497AbeBORhD (ORCPT + 99 others); Thu, 15 Feb 2018 12:37:03 -0500 Received: from smtp.codeaurora.org ([198.145.29.96]:43442 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1427401AbeBORf1 (ORCPT ); Thu, 15 Feb 2018 12:35:27 -0500 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 461BE60D81; Thu, 15 Feb 2018 17:35:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1518716126; bh=HdCmcpUb0N4oKBvtnVa9jYNEVkWCE+5kTvBpjPxIoQU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bBE7xwIYoU3XjM5x/6rhU58KL9KnnpKxWHKPriS6/3LpvnuRlpwPKxPJjmFv0CY3B OkddYo1Hz+ERLY/XtfX937v3ZBoPOA7UsDQ4yWhfd3Nz/k/sYvOJwHS9IQVR07HzrZ GKiDuZyo+9tCx8by59TuQ187p29XEj+PsLG0WzOM= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from codeaurora.org (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: ilina@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id C6E8E60960; Thu, 15 Feb 2018 17:35:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1518716125; bh=HdCmcpUb0N4oKBvtnVa9jYNEVkWCE+5kTvBpjPxIoQU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o8UrjFgltP4dYdzPWppX7LCR0e3t+2W/R/YBUooQYBBg6vwqBbFeTYvfFDkW6Fd7o v5e5Kf6rjjGzjFXRrC3wHKpexlaKZcRn10VtOopboC4kj2l/8UWYxqyuP5gTHFpmdQ nIcjDHa5wwsjBkHg0BQ62LRDqNcBXq17bZyYDq1w= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org C6E8E60960 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=ilina@codeaurora.org From: Lina Iyer To: andy.gross@linaro.org, david.brown@linaro.org, linux-arm-msm@vger.kernel.org, linux-soc@vger.kernel.org Cc: rnayak@codeaurora.org, bjorn.andersson@linaro.org, linux-kernel@vger.kernel.org, Lina Iyer Subject: [PATCH v2 07/10] drivers: qcom: rpmh: cache sleep/wake state requests Date: Thu, 15 Feb 2018 10:35:04 -0700 Message-Id: <20180215173507.10989-8-ilina@codeaurora.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180215173507.10989-1-ilina@codeaurora.org> References: <20180215173507.10989-1-ilina@codeaurora.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Active state requests are sent immediately to the mailbox controller, while sleep and wake state requests are cached in this driver to avoid taxing the mailbox controller repeatedly. The cached values will be sent to the controller when the rpmh_flush() is called. Generally, flushing is a system PM activity and may be called from the system PM drivers when the system is entering suspend or deeper sleep modes during cpuidle. Also allow invalidating the cached requests, so they may be re-populated again. Signed-off-by: Lina Iyer --- drivers/soc/qcom/rpmh.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++- include/soc/qcom/rpmh.h | 10 +++ 2 files changed, 222 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index d95ea3fa8b67..671bc03ad77a 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -35,6 +37,22 @@ .rc = rc, \ } + +/** + * cache_req : the request object for caching + * + * @addr: the address of the resource + * @sleep_val: the sleep vote + * @wake_val: the wake vote + * @list: linked list obj + */ +struct cache_req { + u32 addr; + u32 sleep_val; + u32 wake_val; + struct list_head list; +}; + /** * rpmh_request: the message to be sent to rpmh-rsc * @@ -57,9 +75,15 @@ struct rpmh_request { * rpmh_ctrlr: our representation of the controller * * @drv: the controller instance + * @cache: the list of cached requests + * @lock: synchronize access to the controller data + * @dirty: was the cache updated since flush */ struct rpmh_ctrlr { struct rsc_drv *drv; + struct list_head cache; + spinlock_t lock; + bool dirty; }; /** @@ -123,17 +147,91 @@ static int wait_for_tx_done(struct rpmh_client *rc, return (ret > 0) ? 0 : -ETIMEDOUT; } +static struct cache_req *__find_req(struct rpmh_client *rc, u32 addr) +{ + struct cache_req *p, *req = NULL; + + list_for_each_entry(p, &rc->ctrlr->cache, list) { + if (p->addr == addr) { + req = p; + break; + } + } + + return req; +} + +static struct cache_req *cache_rpm_request(struct rpmh_client *rc, + enum rpmh_state state, + struct tcs_cmd *cmd) +{ + struct cache_req *req; + struct rpmh_ctrlr *rpm = rc->ctrlr; + unsigned long flags; + + spin_lock_irqsave(&rpm->lock, flags); + req = __find_req(rc, cmd->addr); + if (req) + goto existing; + + req = kzalloc(sizeof(*req), GFP_ATOMIC); + if (!req) { + req = ERR_PTR(-ENOMEM); + goto unlock; + } + + req->addr = cmd->addr; + req->sleep_val = req->wake_val = UINT_MAX; + INIT_LIST_HEAD(&req->list); + list_add_tail(&req->list, &rpm->cache); + +existing: + switch (state) { + case RPMH_ACTIVE_ONLY_STATE: + if (req->sleep_val != UINT_MAX) + req->wake_val = cmd->data; + break; + case RPMH_WAKE_ONLY_STATE: + req->wake_val = cmd->data; + break; + case RPMH_SLEEP_STATE: + req->sleep_val = cmd->data; + break; + default: + break; + }; + + rpm->dirty = true; +unlock: + spin_unlock_irqrestore(&rpm->lock, flags); + + return req; +} + /** - * __rpmh_write: send the RPMH request + * __rpmh_write: Cache and send the RPMH request * * @rc: The RPMH client * @state: Active/Sleep request type * @rpm_msg: The data that needs to be sent (payload). + * + * Cache the RPMH request and send if the state is ACTIVE_ONLY. + * SLEEP/WAKE_ONLY requests are not sent to the controller at + * this time. Use rpmh_flush() to send them to the controller. */ static int __rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct rpmh_request *rpm_msg) { int ret = -EFAULT; + struct cache_req *req; + int i; + + /* Cache the request in our store and link the payload */ + for (i = 0; i < rpm_msg->msg.num_payload; i++) { + req = cache_rpm_request(rc, state, &rpm_msg->msg.payload[i]); + if (IS_ERR(req)) + return PTR_ERR(req); + } rpm_msg->msg.state = state; @@ -150,6 +248,10 @@ static int __rpmh_write(struct rpmh_client *rc, enum rpmh_state state, "Error in RPMH request addr=0x%x, data=0x%x\n", rpm_msg->msg.payload[0].addr, rpm_msg->msg.payload[0].data); + } else { + ret = rpmh_rsc_write_ctrl_data(rc->ctrlr->drv, &rpm_msg->msg); + /* Clean up our call by spoofing tx_done */ + rpmh_tx_done(&rpm_msg->msg, ret); } return ret; @@ -189,6 +291,113 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, } EXPORT_SYMBOL(rpmh_write); +static int is_req_valid(struct cache_req *req) +{ + return (req->sleep_val != UINT_MAX && + req->wake_val != UINT_MAX && + req->sleep_val != req->wake_val); +} + +static int send_single(struct rpmh_client *rc, enum rpmh_state state, + u32 addr, u32 data) +{ + DEFINE_RPMH_MSG_ONSTACK(rc, state, NULL, NULL, rpm_msg); + + /* Wake sets are always complete and sleep sets are not */ + rpm_msg.msg.is_complete = (state == RPMH_WAKE_ONLY_STATE); + rpm_msg.cmd[0].addr = addr; + rpm_msg.cmd[0].data = data; + rpm_msg.msg.num_payload = 1; + rpm_msg.msg.is_complete = false; + + return rpmh_rsc_write_ctrl_data(rc->ctrlr->drv, &rpm_msg.msg); +} + +/** + * rpmh_flush: Flushes the buffered active and sleep sets to TCS + * + * @rc: The RPMh handle got from rpmh_get_dev_channel + * + * This function is generally called from the sleep code from the last CPU + * that is powering down the entire system. + * + * Returns -EBUSY if the controller is busy, probably waiting on a response + * to a RPMH request sent earlier. + */ +int rpmh_flush(struct rpmh_client *rc) +{ + struct cache_req *p; + struct rpmh_ctrlr *rpm = rc->ctrlr; + int ret; + unsigned long flags; + + if (IS_ERR_OR_NULL(rc)) + return -EINVAL; + + spin_lock_irqsave(&rpm->lock, flags); + if (!rpm->dirty) { + pr_debug("Skipping flush, TCS has latest data.\n"); + spin_unlock_irqrestore(&rpm->lock, flags); + return 0; + } + spin_unlock_irqrestore(&rpm->lock, flags); + + /* + * Nobody else should be calling this function other than system PM,, + * hence we can run without locks. + */ + list_for_each_entry(p, &rc->ctrlr->cache, list) { + if (!is_req_valid(p)) { + pr_debug("%s: skipping RPMH req: a:0x%x s:0x%x w:0x%x", + __func__, p->addr, p->sleep_val, p->wake_val); + continue; + } + ret = send_single(rc, RPMH_SLEEP_STATE, p->addr, p->sleep_val); + if (ret) + return ret; + ret = send_single(rc, RPMH_WAKE_ONLY_STATE, p->addr, + p->wake_val); + if (ret) + return ret; + } + + spin_lock_irqsave(&rpm->lock, flags); + rpm->dirty = false; + spin_unlock_irqrestore(&rpm->lock, flags); + + return 0; +} +EXPORT_SYMBOL(rpmh_flush); + +/** + * rpmh_invalidate: Invalidate all sleep and active sets + * sets. + * + * @rc: The RPMh handle got from rpmh_get_dev_channel + * + * Invalidate the sleep and active values in the TCS blocks. + */ +int rpmh_invalidate(struct rpmh_client *rc) +{ + struct rpmh_ctrlr *rpm = rc->ctrlr; + int ret; + unsigned long flags; + + if (IS_ERR_OR_NULL(rc)) + return -EINVAL; + + spin_lock_irqsave(&rpm->lock, flags); + rpm->dirty = true; + spin_unlock_irqrestore(&rpm->lock, flags); + + do { + ret = rpmh_rsc_invalidate(rc->ctrlr->drv); + } while (ret == -EAGAIN); + + return ret; +} +EXPORT_SYMBOL(rpmh_invalidate); + static struct rpmh_ctrlr *get_rpmh_ctrlr(struct platform_device *pdev) { int i; @@ -210,6 +419,8 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(struct platform_device *pdev) if (rpmh_rsc[i].drv == NULL) { ctrlr = &rpmh_rsc[i]; ctrlr->drv = drv; + spin_lock_init(&ctrlr->lock); + INIT_LIST_HEAD(&ctrlr->cache); break; } } diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h index 53cc145990c2..a3f1246ce49a 100644 --- a/include/soc/qcom/rpmh.h +++ b/include/soc/qcom/rpmh.h @@ -17,6 +17,10 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct rpmh_client *rpmh_get_client(struct platform_device *pdev); +int rpmh_flush(struct rpmh_client *rc); + +int rpmh_invalidate(struct rpmh_client *rc); + void rpmh_release(struct rpmh_client *rc); #else @@ -28,6 +32,12 @@ static inline int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, static inline struct rpmh_client *rpmh_get_client(struct platform_device *pdev) { return ERR_PTR(-ENODEV); } +static inline int rpmh_flush(struct rpmh_client *rc) +{ return -ENODEV; } + +static inline int rpmh_invalidate(struct rpmh_client *rc) +{ return -ENODEV; } + static inline void rpmh_release(struct rpmh_client *rc) { } #endif /* CONFIG_QCOM_RPMH */ -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project