/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RPMH_MAX_MBOXES 2 #define RPMH_MAX_FAST_RES 32 #define RPMH_MAX_REQ_IN_BATCH 10 #define RPMH_TIMEOUT msecs_to_jiffies(10000) #define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \ struct rpmh_msg name = { \ .msg = { \ .state = s, \ .payload = name.cmd, \ .num_payload = 0, \ .is_read = false, \ .is_control = false, \ .is_complete = true, \ .invalidate = false, \ }, \ .cmd = { { 0 } }, \ .completion = q, \ .wait_count = c, \ .rc = rc, \ .bit = -1, \ } struct rpmh_req { u32 addr; u32 sleep_val; u32 wake_val; struct list_head list; }; struct rpmh_msg { struct tcs_mbox_msg msg; struct tcs_cmd cmd[MAX_RPMH_PAYLOAD]; struct completion *completion; atomic_t *wait_count; struct rpmh_client *rc; int bit; int err; /* relay error from mbox for sync calls */ }; struct rpmh_mbox { struct device_node *mbox_dn; struct list_head resources; spinlock_t lock; struct rpmh_msg *msg_pool; DECLARE_BITMAP(fast_req, RPMH_MAX_FAST_RES); bool dirty; bool in_solver_mode; /* Cache sleep and wake requests sent as passthru */ struct rpmh_msg *passthru_cache[2 * RPMH_MAX_REQ_IN_BATCH]; }; struct rpmh_client { struct device *dev; struct mbox_client client; struct mbox_chan *chan; struct rpmh_mbox *rpmh; }; static struct rpmh_mbox mbox_ctrlr[RPMH_MAX_MBOXES]; DEFINE_MUTEX(rpmh_mbox_mutex); bool rpmh_standalone; static struct rpmh_msg *get_msg_from_pool(struct rpmh_client *rc) { struct rpmh_mbox *rpm = rc->rpmh; struct rpmh_msg *msg = NULL; int pos; unsigned long flags; spin_lock_irqsave(&rpm->lock, flags); pos = find_first_zero_bit(rpm->fast_req, RPMH_MAX_FAST_RES); if (pos != RPMH_MAX_FAST_RES) { bitmap_set(rpm->fast_req, pos, 1); msg = &rpm->msg_pool[pos]; memset(msg, 0, sizeof(*msg)); msg->bit = pos; msg->rc = rc; } spin_unlock_irqrestore(&rpm->lock, flags); return msg; } static void __free_msg_to_pool(struct rpmh_msg *rpm_msg) { struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; /* If we allocated the pool, set it as available */ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) bitmap_clear(rpm->fast_req, rpm_msg->bit, 1); } static void free_msg_to_pool(struct rpmh_msg *rpm_msg) { struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; unsigned long flags; spin_lock_irqsave(&rpm->lock, flags); __free_msg_to_pool(rpm_msg); spin_unlock_irqrestore(&rpm->lock, flags); } static void rpmh_rx_cb(struct mbox_client *cl, void *msg) { struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg); atomic_dec(rpm_msg->wait_count); } static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r) { struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg); atomic_t *wc = rpm_msg->wait_count; struct completion *compl = rpm_msg->completion; rpm_msg->err = r; if (r) { dev_err(rpm_msg->rc->dev, "RPMH TX fail in msg addr 0x%x, err=%d\n", rpm_msg->msg.payload[0].addr, r); /* * If we fail TX for a read, call then we won't get * a rx_callback. Force a rx_cb. */ if (rpm_msg->msg.is_read) rpmh_rx_cb(cl, msg); } /* * Copy the child object pointers before freeing up the parent, * This way even if the parent (rpm_msg) object gets reused, we * can free up the child objects (wq/wc) parallely. * If you free up the children before the parent, then we run * into an issue that the stack allocated parent object may be * invalid before we can check the ->bit value. */ free_msg_to_pool(rpm_msg); /* Signal the blocking thread we are done */ if (wc && atomic_dec_and_test(wc)) if (compl) complete(compl); } /** * wait_for_tx_done: Wait forever until the response is received. * * @rc: The RPMH client * @compl: The completion object * @addr: An addr that we sent in that request * @data: The data for the address in that request * */ static inline void wait_for_tx_done(struct rpmh_client *rc, struct completion *compl, u32 addr, u32 data) { int ret; int count = 4; int skip = 0; do { ret = wait_for_completion_timeout(compl, RPMH_TIMEOUT); if (ret) { if (count != 4) dev_notice(rc->dev, "RPMH response received addr=0x%x data=0x%x\n", addr, data); return; } if (!count) { if (skip++ % 100) continue; dev_err(rc->dev, "RPMH waiting for interrupt from AOSS\n"); mbox_chan_debug(rc->chan); BUG(); } else { dev_err(rc->dev, "RPMH response timeout (%d) addr=0x%x,data=0x%x\n", count, addr, data); count--; } } while (true); } static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr) { struct rpmh_req *p, *req = NULL; list_for_each_entry(p, &rc->rpmh->resources, list) { if (p->addr == addr) { req = p; break; } } return req; } static struct rpmh_req *cache_rpm_request(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd) { struct rpmh_req *req; struct rpmh_mbox *rpm = rc->rpmh; 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->resources); existing: switch (state) { case RPMH_ACTIVE_ONLY_STATE: case RPMH_AWAKE_STATE: if (req->sleep_val != UINT_MAX) { req->wake_val = cmd->data; rpm->dirty = true; } break; case RPMH_WAKE_ONLY_STATE: if (req->wake_val != cmd->data) { req->wake_val = cmd->data; rpm->dirty = true; } break; case RPMH_SLEEP_STATE: if (req->sleep_val != cmd->data) { req->sleep_val = cmd->data; rpm->dirty = true; } break; default: break; }; unlock: spin_unlock_irqrestore(&rpm->lock, flags); return req; } static int check_ctrlr_state(struct rpmh_client *rc, enum rpmh_state state) { struct rpmh_mbox *rpm = rc->rpmh; unsigned long flags; int ret = 0; /* Do not allow setting active votes when in solver mode */ spin_lock_irqsave(&rpm->lock, flags); if (rpm->in_solver_mode && (state == RPMH_AWAKE_STATE || state == RPMH_ACTIVE_ONLY_STATE)) ret = -EBUSY; spin_unlock_irqrestore(&rpm->lock, flags); return ret; } /** * __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. */ int __rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct rpmh_msg *rpm_msg) { struct rpmh_req *req; int ret = 0; 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; /* Send to mailbox only if active or awake */ if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) { ret = mbox_send_message(rc->chan, &rpm_msg->msg); if (ret > 0) ret = 0; } else { /* Clean up our call by spoofing tx_done */ rpmh_tx_done(&rc->client, &rpm_msg->msg, ret); } return ret; } /** * rpmh_write_single_async: Write a single RPMH command * * @rc: The RPMh handle got from rpmh_get_dev_channel * @state: Active/sleep set * @addr: The ePCB address * @data: The data * * Write a single value in fast-path. Fire and forget. * May be called from atomic contexts. */ int rpmh_write_single_async(struct rpmh_client *rc, enum rpmh_state state, u32 addr, u32 data) { struct rpmh_msg *rpm_msg; int ret; if (IS_ERR_OR_NULL(rc)) return -EINVAL; if (rpmh_standalone) return 0; ret = check_ctrlr_state(rc, state); if (ret) return ret; rpm_msg = get_msg_from_pool(rc); if (!rpm_msg) return -ENOMEM; rpm_msg->cmd[0].addr = addr; rpm_msg->cmd[0].data = data; rpm_msg->msg.payload = rpm_msg->cmd; rpm_msg->msg.num_payload = 1; return __rpmh_write(rc, state, rpm_msg); } EXPORT_SYMBOL(rpmh_write_single_async); /** * rpmh_write_single: Write a single RPMH command and * wait for completion of the command. * * @rc: The RPMh handle got from rpmh_get_dev_channel * @state: Active/sleep set * @addr: The ePCB address * @offset: Offset of the resource * @data: The data * * Write a single value in slow-path and wait for the request to be * complete. Blocks until the request is completed on the accelerator. * Do not call from atomic contexts. */ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state, u32 addr, u32 data) { DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg); int ret; if (IS_ERR_OR_NULL(rc)) return -EINVAL; might_sleep(); if (rpmh_standalone) return 0; ret = check_ctrlr_state(rc, state); if (ret) return ret; rpm_msg.cmd[0].addr = addr; rpm_msg.cmd[0].data = data; rpm_msg.msg.num_payload = 1; ret = __rpmh_write(rc, state, &rpm_msg); if (ret < 0) return ret; wait_for_tx_done(rc, &compl, addr, data); return rpm_msg.err; } EXPORT_SYMBOL(rpmh_write_single); struct rpmh_msg *__get_rpmh_msg_async(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int n) { struct rpmh_msg *rpm_msg; if (IS_ERR_OR_NULL(rc) || !cmd || n <= 0 || n > MAX_RPMH_PAYLOAD) return ERR_PTR(-EINVAL); rpm_msg = get_msg_from_pool(rc); if (!rpm_msg) return ERR_PTR(-ENOMEM); memcpy(rpm_msg->cmd, cmd, n * sizeof(*cmd)); rpm_msg->msg.state = state; rpm_msg->msg.payload = rpm_msg->cmd; rpm_msg->msg.num_payload = n; return rpm_msg; } /** * rpmh_write_async: Write a batch of RPMH commands * * @rc: The RPMh handle got from rpmh_get_dev_channel * @state: Active/sleep set * @cmd: The payload data * @n: The number of elements in payload * * Write a batch of RPMH commands, the order of commands is maintained * and will be sent as a single shot. By default the entire set of commands * are considered active only (i.e, will not be cached in wake set, unless * all of them have their corresponding sleep requests). */ int rpmh_write_async(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int n) { struct rpmh_msg *rpm_msg; int ret; if (rpmh_standalone) return 0; ret = check_ctrlr_state(rc, state); if (ret) return ret; rpm_msg = __get_rpmh_msg_async(rc, state, cmd, n); if (IS_ERR(rpm_msg)) return PTR_ERR(rpm_msg); return __rpmh_write(rc, state, rpm_msg); } EXPORT_SYMBOL(rpmh_write_async); /** * rpmh_write: Write a batch of RPMH commands * * @rc: The RPMh handle got from rpmh_get_dev_channel * @state: Active/sleep set * @cmd: The payload data * @n: The number of elements in payload * * Write a batch of RPMH commands, the order of commands is maintained * and will be sent as a single shot. By default the entire set of commands * are considered active only (i.e, will not be cached in wake set, unless * all of them have their corresponding sleep requests). All requests are * sent as slow path requests. * * May sleep. Do not call from atomic contexts. */ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int n) { DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg); int ret; if (IS_ERR_OR_NULL(rc) || !cmd || n <= 0 || n > MAX_RPMH_PAYLOAD) return -EINVAL; might_sleep(); if (rpmh_standalone) return 0; ret = check_ctrlr_state(rc, state); if (ret) return ret; memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd)); rpm_msg.msg.num_payload = n; ret = __rpmh_write(rc, state, &rpm_msg); if (ret) return ret; wait_for_tx_done(rc, &compl, cmd[0].addr, cmd[0].data); return rpm_msg.err; } EXPORT_SYMBOL(rpmh_write); static int cache_passthru(struct rpmh_client *rc, struct rpmh_msg **rpm_msg, int count) { struct rpmh_mbox *rpm = rc->rpmh; unsigned long flags; int ret = 0; int index = 0; int i; spin_lock_irqsave(&rpm->lock, flags); while (rpm->passthru_cache[index]) index++; if (index + count >= 2 * RPMH_MAX_REQ_IN_BATCH) { ret = -ENOMEM; goto fail; } for (i = 0; i < count; i++) rpm->passthru_cache[index + i] = rpm_msg[i]; fail: spin_unlock_irqrestore(&rpm->lock, flags); return ret; } static int flush_passthru(struct rpmh_client *rc) { struct rpmh_mbox *rpm = rc->rpmh; struct rpmh_msg *rpm_msg; unsigned long flags; int ret = 0; int i; /* Send Sleep/Wake requests to the controller, expect no response */ spin_lock_irqsave(&rpm->lock, flags); for (i = 0; rpm->passthru_cache[i]; i++) { rpm_msg = rpm->passthru_cache[i]; ret = mbox_send_controller_data(rc->chan, &rpm_msg->msg); if (ret) goto fail; } fail: spin_unlock_irqrestore(&rpm->lock, flags); return ret; } static void invalidate_passthru(struct rpmh_client *rc) { struct rpmh_mbox *rpm = rc->rpmh; unsigned long flags; int index = 0; int i; spin_lock_irqsave(&rpm->lock, flags); while (rpm->passthru_cache[index]) index++; for (i = 0; i < index; i++) { __free_msg_to_pool(rpm->passthru_cache[i]); rpm->passthru_cache[i] = NULL; } spin_unlock_irqrestore(&rpm->lock, flags); } /** * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the * batch to finish. * * @rc: The RPMh handle got from rpmh_get_dev_channel * @state: Active/sleep set * @cmd: The payload data * @n: The array of count of elements in each batch, 0 terminated. * * Write a request to the mailbox controller without caching. If the request * state is ACTIVE or AWAKE, then the requests are treated as completion request * and sent to the controller immediately. The function waits until all the * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the * request is sent as fire-n-forget and no ack is expected. * * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests. */ int rpmh_write_batch(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int *n) { struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH] = { NULL }; DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */ int count = 0; int ret, i, j, k; bool complete_set; u32 addr, data; if (IS_ERR_OR_NULL(rc) || !cmd || !n) return -EINVAL; if (rpmh_standalone) return 0; ret = check_ctrlr_state(rc, state); if (ret) return ret; while (n[count++] > 0) ; count--; if (!count || count > RPMH_MAX_REQ_IN_BATCH) return -EINVAL; if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) { /* * Ensure the 'complete' bit is set for atleast one command in * each set for active/awake requests. */ for (i = 0, k = 0; i < count; i++, k += n[i]) { complete_set = false; for (j = 0; j < n[i]; j++) { if (cmd[k + j].complete) { complete_set = true; break; } } if (!complete_set) { dev_err(rc->dev, "No completion set for batch"); return -EINVAL; } } } addr = cmd[0].addr; data = cmd[0].data; /* Create async request batches */ for (i = 0; i < count; i++) { rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]); if (IS_ERR_OR_NULL(rpm_msg[i])) { for (j = 0 ; j < i; j++) free_msg_to_pool(rpm_msg[j]); return PTR_ERR(rpm_msg[i]); } cmd += n[i]; } /* Send if Active or Awake and wait for the whole set to complete */ if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) { might_sleep(); atomic_set(&wait_count, count); for (i = 0; i < count; i++) { rpm_msg[i]->completion = &compl; rpm_msg[i]->wait_count = &wait_count; /* Bypass caching and write to mailbox directly */ ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg); if (ret < 0) { pr_err("Error(%d) sending RPM message addr=0x%x\n", ret, rpm_msg[i]->msg.payload[0].addr); break; } } /* For those unsent requests, spoof tx_done */ for (j = i; j < count; j++) rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret); wait_for_tx_done(rc, &compl, addr, data); } else { /* * Cache sleep/wake data in store. * But flush passthru first before flushing all other data. */ return cache_passthru(rc, rpm_msg, count); } return 0; } EXPORT_SYMBOL(rpmh_write_batch); /** * rpmh_mode_solver_set: Indicate that the RSC controller hardware has * been configured to be in solver mode * * @rc: The RPMH handle * @enable: Boolean value indicating if the controller is in solver mode. * * When solver mode is enabled, passthru API will not be able to send wake * votes, just awake and active votes. */ int rpmh_mode_solver_set(struct rpmh_client *rc, bool enable) { struct rpmh_mbox *rpm; unsigned long flags; if (IS_ERR_OR_NULL(rc)) return -EINVAL; if (rpmh_standalone) return 0; rpm = rc->rpmh; do { spin_lock_irqsave(&rpm->lock, flags); if (mbox_controller_is_idle(rc->chan)) { rpm->in_solver_mode = enable; spin_unlock_irqrestore(&rpm->lock, flags); break; } spin_unlock_irqrestore(&rpm->lock, flags); udelay(10); } while (1); return 0; } EXPORT_SYMBOL(rpmh_mode_solver_set); /** * rpmh_write_control: Write async control commands to the controller * * @rc: The RPMh handle got from rpmh_get_dev_channel * @cmd: The payload data * @n: The number of elements in payload * * Write control commands to the controller. The messages are always sent * async. * * May be called from atomic contexts. */ int rpmh_write_control(struct rpmh_client *rc, struct tcs_cmd *cmd, int n) { DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg); if (IS_ERR_OR_NULL(rc) || n <= 0 || n > MAX_RPMH_PAYLOAD) return -EINVAL; if (rpmh_standalone) return 0; memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd)); rpm_msg.msg.num_payload = n; rpm_msg.msg.is_control = true; rpm_msg.msg.is_complete = false; return mbox_send_controller_data(rc->chan, &rpm_msg.msg); } EXPORT_SYMBOL(rpmh_write_control); /** * 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. * Nothing to do here. */ int rpmh_invalidate(struct rpmh_client *rc) { DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg); struct rpmh_mbox *rpm; unsigned long flags; if (IS_ERR_OR_NULL(rc)) return -EINVAL; if (rpmh_standalone) return 0; invalidate_passthru(rc); rpm = rc->rpmh; rpm_msg.msg.invalidate = true; rpm_msg.msg.is_complete = false; spin_lock_irqsave(&rpm->lock, flags); rpm->dirty = true; spin_unlock_irqrestore(&rpm->lock, flags); return mbox_send_controller_data(rc->chan, &rpm_msg.msg); } EXPORT_SYMBOL(rpmh_invalidate); /** * rpmh_read: Read a resource value * * @rc: The RPMh handle got from rpmh_get_dev_channel * @addr: The ePCB address * @resp: The store for the response received from RPMH * * Read a resource value from RPMH. */ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp) { int ret; DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(2); /* wait for rx_cb and tx_done */ DEFINE_RPMH_MSG_ONSTACK(rc, RPMH_ACTIVE_ONLY_STATE, &compl, &wait_count, rpm_msg); if (IS_ERR_OR_NULL(rc) || !resp) return -EINVAL; might_sleep(); if (rpmh_standalone) return 0; rpm_msg.cmd[0].addr = addr; rpm_msg.cmd[0].data = 0; rpm_msg.msg.num_payload = 1; rpm_msg.msg.is_read = true; ret = mbox_send_message(rc->chan, &rpm_msg.msg); if (ret < 0) return ret; /* Wait until the response is received from RPMH */ wait_for_tx_done(rc, &compl, addr, 0); /* Read the data back from the tcs_mbox_msg structrure */ *resp = rpm_msg.cmd[0].data; return rpm_msg.err; } EXPORT_SYMBOL(rpmh_read); /** * rpmh_ctrlr_idle: Check if the controller is idle * * @rc: The RPMH handle got from rpmh_get_dev_channel * * Returns if the controller is idle or not. */ int rpmh_ctrlr_idle(struct rpmh_client *rc) { if (IS_ERR_OR_NULL(rc)) return -EINVAL; if (rpmh_standalone) return 0; if (!mbox_controller_is_idle(rc->chan)) return -EBUSY; return 0; } EXPORT_SYMBOL(rpmh_ctrlr_idle); static inline int is_req_valid(struct rpmh_req *req) { return (req->sleep_val != UINT_MAX && req->wake_val != UINT_MAX && req->sleep_val != req->wake_val); } 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; return mbox_send_controller_data(rc->chan, &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) { DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg); struct rpmh_req *p; struct rpmh_mbox *rpm = rc->rpmh; int ret; unsigned long flags; if (IS_ERR_OR_NULL(rc)) return -EINVAL; if (rpmh_standalone) return 0; if (!mbox_controller_is_idle(rc->chan)) return -EBUSY; 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); /* Invalidate sleep and wake TCS */ rpm_msg.msg.invalidate = true; rpm_msg.msg.is_complete = false; ret = mbox_send_controller_data(rc->chan, &rpm_msg.msg); if (ret) return ret; /* First flush the cached passthru's */ ret = flush_passthru(rc); if (ret) return ret; /* * Nobody else should be calling this function other than sleep, * hence we can run without locks. */ list_for_each_entry(p, &rc->rpmh->resources, 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); /** * get_mbox: Get the MBOX controller * @pdev: the platform device * @name: the MBOX name as specified in DT for the device. * @index: the index in the mboxes property if name is not provided. * * Get the MBOX Device node. We will use that to know which * MBOX controller this platform device is intending to talk * to. */ static struct rpmh_mbox *get_mbox(struct platform_device *pdev, const char *name, int index) { int i; struct property *prop; struct of_phandle_args spec; const char *mbox_name; struct rpmh_mbox *rpmh; if (index < 0) { if (!name || !name[0]) return ERR_PTR(-EINVAL); index = 0; of_property_for_each_string(pdev->dev.of_node, "mbox-names", prop, mbox_name) { if (!strcmp(name, mbox_name)) break; index++; } } if (of_parse_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells", index, &spec)) { dev_dbg(&pdev->dev, "%s: can't parse mboxes property\n", __func__); return ERR_PTR(-ENODEV); } for (i = 0; i < RPMH_MAX_MBOXES; i++) if (mbox_ctrlr[i].mbox_dn == spec.np) { rpmh = &mbox_ctrlr[i]; goto found; } /* A new MBOX */ for (i = 0; i < RPMH_MAX_MBOXES; i++) if (!mbox_ctrlr[i].mbox_dn) break; /* More controllers than expected - not recoverable */ WARN_ON(i == RPMH_MAX_MBOXES); rpmh = &mbox_ctrlr[i]; rpmh->msg_pool = kzalloc(sizeof(struct rpmh_msg) * RPMH_MAX_FAST_RES, GFP_KERNEL); if (!rpmh->msg_pool) { of_node_put(spec.np); return ERR_PTR(-ENOMEM); } rpmh->mbox_dn = spec.np; INIT_LIST_HEAD(&rpmh->resources); spin_lock_init(&rpmh->lock); found: of_node_put(spec.np); return rpmh; } static struct rpmh_client *get_rpmh_client(struct platform_device *pdev, const char *name, int index) { struct rpmh_client *rc; int ret = 0; ret = cmd_db_ready(); if (ret) return ERR_PTR(ret); rc = kzalloc(sizeof(*rc), GFP_KERNEL); if (!rc) return ERR_PTR(-ENOMEM); rc->client.rx_callback = rpmh_rx_cb; rc->client.tx_prepare = NULL; rc->client.tx_done = rpmh_tx_done; rc->client.tx_block = false; rc->client.knows_txdone = false; rc->client.dev = &pdev->dev; rc->dev = &pdev->dev; rc->chan = ERR_PTR(-EINVAL); /* Initialize by index or name, whichever is present */ if (index >= 0) rc->chan = mbox_request_channel(&rc->client, index); else if (name) rc->chan = mbox_request_channel_byname(&rc->client, name); if (IS_ERR_OR_NULL(rc->chan)) { ret = PTR_ERR(rc->chan); goto cleanup; } mutex_lock(&rpmh_mbox_mutex); rc->rpmh = get_mbox(pdev, name, index); rpmh_standalone = (cmd_db_is_standalone() > 0); mutex_unlock(&rpmh_mbox_mutex); if (IS_ERR(rc->rpmh)) { ret = PTR_ERR(rc->rpmh); mbox_free_channel(rc->chan); goto cleanup; } return rc; cleanup: kfree(rc); return ERR_PTR(ret); } /** * rpmh_get_byname: Get the RPMh handle by mbox name * * @pdev: the platform device which needs to communicate with RPM * accelerators * @name: The mbox-name assigned to the client's mailbox handle * * May sleep. */ struct rpmh_client *rpmh_get_byname(struct platform_device *pdev, const char *name) { return get_rpmh_client(pdev, name, -1); } EXPORT_SYMBOL(rpmh_get_byname); /** * rpmh_get_byindex: Get the RPMh handle by mbox index * * @pdev: the platform device which needs to communicate with RPM * accelerators * @index : The index of the mbox tuple as specified in order in DT * * May sleep. */ struct rpmh_client *rpmh_get_byindex(struct platform_device *pdev, int index) { return get_rpmh_client(pdev, NULL, index); } EXPORT_SYMBOL(rpmh_get_byindex); /** * rpmh_release: Release the RPMH client * * @rc: The RPMh handle to be freed. */ void rpmh_release(struct rpmh_client *rc) { if (rc && !IS_ERR_OR_NULL(rc->chan)) mbox_free_channel(rc->chan); kfree(rc); } EXPORT_SYMBOL(rpmh_release);