firmware: arm_scmi: Use asynchronous CLOCK_RATE_SET when possible
authorSudeep Holla <sudeep.holla@arm.com>
Mon, 8 Jul 2019 13:42:16 +0000 (14:42 +0100)
committerSudeep Holla <sudeep.holla@arm.com>
Mon, 12 Aug 2019 11:23:01 +0000 (12:23 +0100)
CLOCK_PROTOCOL_ATTRIBUTES provides attributes to indicate the maximum
number of pending asynchronous clock rate changes supported by the
platform. If it's non-zero, then we should be able to use asynchronous
clock rate set for any clocks until the maximum limit is reached.

Tracking the current count of pending asynchronous clock set rate
requests, we can decide if the incoming/new request for clock set rate
can be handled asynchronously or not until the maximum limit is
reached.

Cc: linux-clk@vger.kernel.org
Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_scmi/clock.c

index dd215bd11a58a9c2db0aad54b6f9f0deef5fbb4a..4a32ae1822a37c13a338b58343d37480d2501593 100644 (file)
@@ -56,7 +56,7 @@ struct scmi_msg_resp_clock_describe_rates {
 struct scmi_clock_set_rate {
        __le32 flags;
 #define CLOCK_SET_ASYNC                BIT(0)
-#define CLOCK_SET_DELAYED      BIT(1)
+#define CLOCK_SET_IGNORE_RESP  BIT(1)
 #define CLOCK_SET_ROUND_UP     BIT(2)
 #define CLOCK_SET_ROUND_AUTO   BIT(3)
        __le32 id;
@@ -67,6 +67,7 @@ struct scmi_clock_set_rate {
 struct clock_info {
        int num_clocks;
        int max_async_req;
+       atomic_t cur_async_req;
        struct scmi_clock_info *clk;
 };
 
@@ -221,21 +222,33 @@ static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id,
                               u64 rate)
 {
        int ret;
+       u32 flags = 0;
        struct scmi_xfer *t;
        struct scmi_clock_set_rate *cfg;
+       struct clock_info *ci = handle->clk_priv;
 
        ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK,
                                 sizeof(*cfg), 0, &t);
        if (ret)
                return ret;
 
+       if (ci->max_async_req &&
+           atomic_inc_return(&ci->cur_async_req) < ci->max_async_req)
+               flags |= CLOCK_SET_ASYNC;
+
        cfg = t->tx.buf;
-       cfg->flags = cpu_to_le32(0);
+       cfg->flags = cpu_to_le32(flags);
        cfg->id = cpu_to_le32(clk_id);
        cfg->value_low = cpu_to_le32(rate & 0xffffffff);
        cfg->value_high = cpu_to_le32(rate >> 32);
 
-       ret = scmi_do_xfer(handle, t);
+       if (flags & CLOCK_SET_ASYNC)
+               ret = scmi_do_xfer_with_response(handle, t);
+       else
+               ret = scmi_do_xfer(handle, t);
+
+       if (ci->max_async_req)
+               atomic_dec(&ci->cur_async_req);
 
        scmi_xfer_put(handle, t);
        return ret;