diff options
Diffstat (limited to 'drivers/soc/qcom/rpmh.c')
-rw-r--r-- | drivers/soc/qcom/rpmh.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index c355ba13e73f..1e3d34876af1 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -34,6 +34,7 @@ .cmd = { { 0 } }, \ .completion = q, \ .dev = dev, \ + .needs_free = false, \ } #define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client) @@ -75,6 +76,9 @@ void rpmh_tx_done(const struct tcs_request *msg, int r) /* Signal the blocking thread we are done */ if (compl) complete(compl); + + if (rpm_msg->needs_free) + kfree(rpm_msg); } static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr) @@ -180,6 +184,53 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state, return ret; } +static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state, + const struct tcs_cmd *cmd, u32 n) +{ + if (!cmd || !n || n > MAX_RPMH_PAYLOAD) + return -EINVAL; + + memcpy(req->cmd, cmd, n * sizeof(*cmd)); + + req->msg.state = state; + req->msg.cmds = req->cmd; + req->msg.num_cmds = n; + + return 0; +} + +/** + * rpmh_write_async: Write a set of RPMH commands + * + * @dev: The device making the request + * @state: Active/sleep set + * @cmd: The payload data + * @n: The number of elements in payload + * + * Write a set of RPMH commands, the order of commands is maintained + * and will be sent as a single shot. + */ +int rpmh_write_async(const struct device *dev, enum rpmh_state state, + const struct tcs_cmd *cmd, u32 n) +{ + struct rpmh_request *rpm_msg; + int ret; + + rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC); + if (!rpm_msg) + return -ENOMEM; + rpm_msg->needs_free = true; + + ret = __fill_rpmh_msg(rpm_msg, state, cmd, n); + if (ret) { + kfree(rpm_msg); + return ret; + } + + return __rpmh_write(dev, state, rpm_msg); +} +EXPORT_SYMBOL(rpmh_write_async); + /** * rpmh_write: Write a set of RPMH commands and block until response * |