Loading drivers/mailbox/mailbox.c +11 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ static void msg_submit(struct mbox_chan *chan) void *data; int err = -EBUSY; again: spin_lock_irqsave(&chan->lock, flags); if (!chan->msg_count || chan->active_req) Loading @@ -85,6 +86,16 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); /* * If the controller returns -EAGAIN, then it means, our spinlock * here is preventing the controller from receiving its interrupt, * that would help clear the controller channels that are currently * blocked waiting on the interrupt response. * Unlock and retry again. */ if (err == -EAGAIN) goto again; if (!err && (chan->txdone_method & TXDONE_BY_POLL)) /* kick start the timer immediately to avoid delays */ hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0), Loading drivers/mailbox/qti-tcs.c +107 −42 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <asm-generic/io.h> Loading Loading @@ -95,10 +94,10 @@ struct tcs_response { struct mbox_chan *chan; struct tcs_mbox_msg *msg; u32 m; /* m-th TCS */ struct tasklet_struct tasklet; int err; int idx; bool in_use; struct list_head list; }; struct tcs_response_pool { Loading @@ -122,16 +121,18 @@ struct tcs_mbox { /* One per MBOX controller */ struct tcs_drv { struct mbox_controller mbox; const char *name; void *base; /* start address of the RSC's registers */ void *reg_base; /* start address for DRV specific register */ void __iomem *base; /* start address of the RSC's registers */ void __iomem *reg_base; /* start address for DRV specific register */ int drv_id; struct platform_device *pdev; struct mbox_controller mbox; struct tcs_mbox tcs[TCS_TYPE_NR]; int num_assigned; int num_tcs; struct workqueue_struct *wq; struct tasklet_struct tasklet; struct list_head response_pending; spinlock_t drv_lock; struct tcs_response_pool *resp_pool; atomic_t tcs_in_use[MAX_POOL_SIZE]; /* Debug info */ Loading @@ -141,8 +142,6 @@ struct tcs_drv { atomic_t tcs_irq_count[MAX_POOL_SIZE]; }; static void tcs_notify_tx_done(unsigned long data); static int tcs_response_pool_init(struct tcs_drv *drv) { struct tcs_response_pool *pool; Loading @@ -153,11 +152,10 @@ static int tcs_response_pool_init(struct tcs_drv *drv) return -ENOMEM; for (i = 0; i < MAX_POOL_SIZE; i++) { tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done, (unsigned long) &pool->resp[i]); pool->resp[i].drv = drv; pool->resp[i].idx = i; pool->resp[i].m = TCS_M_INIT; INIT_LIST_HEAD(&pool->resp[i].list); } spin_lock_init(&pool->lock); Loading Loading @@ -188,6 +186,9 @@ static struct tcs_response *setup_response(struct tcs_drv *drv, } spin_unlock_irqrestore(&pool->lock, flags); if (pos == MAX_POOL_SIZE) pr_err("response pool is full\n"); return resp; } Loading Loading @@ -240,11 +241,11 @@ static void print_response(struct tcs_drv *drv, int m) return; msg = resp->msg; pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n", pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n", resp->idx, resp->m, resp->in_use); pr_info("Msg: state=%d\n", msg->state); pr_debug("Msg: state=%d\n", msg->state); for (i = 0; i < msg->num_payload; i++) pr_info("addr=0x%x data=0x%x complete=0x%x\n", pr_debug("addr=0x%x data=0x%x complete=0x%x\n", msg->payload[i].addr, msg->payload[i].data, msg->payload[i].complete); Loading Loading @@ -364,7 +365,15 @@ static inline struct tcs_mbox *get_tcs_for_msg(struct tcs_drv *drv, static inline void send_tcs_response(struct tcs_response *resp) { tasklet_schedule(&resp->tasklet); struct tcs_drv *drv = resp->drv; unsigned long flags; spin_lock_irqsave(&drv->drv_lock, flags); INIT_LIST_HEAD(&resp->list); list_add_tail(&resp->list, &drv->response_pending); spin_unlock_irqrestore(&drv->drv_lock, flags); tasklet_schedule(&drv->tasklet); } static inline void enable_tcs_irq(struct tcs_drv *drv, int m, bool enable) Loading Loading @@ -455,12 +464,12 @@ static irqreturn_t tcs_irq_handler(int irq, void *p) /* Clear the TCS IRQ status */ write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m)); /* Notify the client that this request is completed. */ atomic_set(&drv->tcs_in_use[m], 0); /* Clean up response object and notify mbox in tasklet */ if (resp) send_tcs_response(resp); /* Notify the client that this request is completed. */ atomic_set(&drv->tcs_in_use[m], 0); } return IRQ_HANDLED; Loading @@ -475,19 +484,38 @@ static inline void mbox_notify_tx_done(struct mbox_chan *chan, mbox_chan_txdone(chan, err); } /** * tcs_notify_tx_done: TX Done for requests that do not trigger TCS */ static void tcs_notify_tx_done(unsigned long data) static void respond_tx_done(struct tcs_response *resp) { struct tcs_response *resp = (struct tcs_response *) data; struct mbox_chan *chan = resp->chan; struct tcs_mbox_msg *msg = resp->msg; int err = resp->err; int m = resp->m; mbox_notify_tx_done(chan, msg, m, err); free_response(resp); mbox_notify_tx_done(chan, msg, m, err); } /** * tcs_notify_tx_done: TX Done for requests that do not trigger TCS */ static void tcs_notify_tx_done(unsigned long data) { struct tcs_drv *drv = (struct tcs_drv *)data; struct tcs_response *resp; unsigned long flags; do { spin_lock_irqsave(&drv->drv_lock, flags); if (list_empty(&drv->response_pending)) { spin_unlock_irqrestore(&drv->drv_lock, flags); break; } resp = list_first_entry(&drv->response_pending, struct tcs_response, list); list_del(&resp->list); spin_unlock_irqrestore(&drv->drv_lock, flags); respond_tx_done(resp); } while (1); } static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n, Loading Loading @@ -673,8 +701,11 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, if (IS_ERR(tcs)) return PTR_ERR(tcs); if (trigger) if (trigger) { resp = setup_response(drv, msg, chan, TCS_M_INIT, 0); if (IS_ERR_OR_NULL(resp)) return -EBUSY; } /* Identify the sequential slots that we can write to */ spin_lock_irqsave(&tcs->tcs_lock, flags); Loading @@ -686,28 +717,21 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, return slot; } /* Figure out the TCS-m and CMD-n to write to */ offset = slot / tcs->ncpt; m = offset + tcs->tcs_offset; n = slot % tcs->ncpt; if (trigger) { /* Block, if we have an address from the msg in flight */ ret = check_for_req_inflight(drv, tcs, msg); if (ret) { spin_unlock_irqrestore(&tcs->tcs_lock, flags); if (resp) free_response(resp); return ret; } } /* Mark the slots as in-use, before we unlock */ if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS) bitmap_set(tcs->slots, slot, msg->num_payload); /* Copy the addresses of the resources over to the slots */ for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++) tcs->cmd_addr[slot + i] = msg->payload[i].addr; offset = slot / tcs->ncpt; m = offset + tcs->tcs_offset; n = slot % tcs->ncpt; /* Block, if we have an address from the msg in flight */ if (trigger) { resp->m = m; /* Mark the TCS as busy */ atomic_set(&drv->tcs_in_use[m], 1); Loading @@ -716,6 +740,14 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, if (tcs->type != ACTIVE_TCS) enable_tcs_irq(drv, m, true); drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct(); } else { /* Mark the slots as in-use, before we unlock */ if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS) bitmap_set(tcs->slots, slot, msg->num_payload); /* Copy the addresses of the resources over to the slots */ for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++) tcs->cmd_addr[slot + i] = msg->payload[i].addr; } /* Write to the TCS or AMC */ Loading Loading @@ -758,6 +790,32 @@ static int tcs_mbox_invalidate(struct mbox_chan *chan) return 0; } static void print_tcs_regs(struct tcs_drv *drv, int m) { int n; struct tcs_mbox *tcs = get_tcs_from_index(drv, m); void __iomem *base = drv->reg_base; u32 enable, addr, data, msgid; if (!tcs || tcs_is_free(drv, m)) return; enable = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0); if (!enable) return; pr_debug("TCS-%d contents:\n", m); for (n = 0; n < tcs->ncpt; n++) { if (!(enable & BIT(n))) continue; addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n); data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n); msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n); pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n", n, addr, data, msgid); } } static void dump_tcs_stats(struct tcs_drv *drv) { int i; Loading @@ -766,12 +824,13 @@ static void dump_tcs_stats(struct tcs_drv *drv) for (i = 0; i < drv->num_tcs; i++) { if (!atomic_read(&drv->tcs_in_use[i])) continue; pr_info("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n", pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n", curr, i, atomic_read(&drv->tcs_send_count[i]), drv->tcs_last_sent_ts[i], atomic_read(&drv->tcs_irq_count[i]), drv->tcs_last_recv_ts[i]); print_tcs_regs(drv, i); print_response(drv, i); } } Loading Loading @@ -840,7 +899,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) if (ret != -EBUSY) break; udelay(100); } while (++count < 10); } while (++count < 100); tx_fail: /* If there was an error in the request, schedule a response */ Loading @@ -849,6 +908,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) drv, msg, chan, TCS_M_INIT, ret); dev_err(dev, "Error sending RPMH message %d\n", ret); if (resp) send_tcs_response(resp); ret = 0; } Loading @@ -857,6 +917,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) if (ret == -EBUSY) { dev_err(dev, "TCS Busy, retrying RPMH message send\n"); dump_tcs_stats(drv); ret = -EAGAIN; } return ret; Loading Loading @@ -967,6 +1028,7 @@ static struct mbox_chan *of_tcs_mbox_xlate(struct mbox_controller *mbox, } chan = &mbox->chans[drv->num_assigned++]; chan->con_priv = drv; return chan; } Loading Loading @@ -1108,6 +1170,9 @@ static int tcs_drv_probe(struct platform_device *pdev) drv->mbox.is_idle = tcs_drv_is_idle; drv->num_tcs = st; drv->pdev = pdev; INIT_LIST_HEAD(&drv->response_pending); spin_lock_init(&drv->drv_lock); tasklet_init(&drv->tasklet, tcs_notify_tx_done, (unsigned long)drv); drv->name = of_get_property(pdev->dev.of_node, "label", NULL); if (!drv->name) Loading drivers/soc/qcom/rpmh.c +51 −42 Original line number Diff line number Diff line Loading @@ -35,13 +35,17 @@ #define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \ struct rpmh_msg name = { \ .msg = { 0 }, \ .msg.state = s, \ .msg.is_complete = true, \ .msg.payload = name.cmd, \ .msg.num_payload = 0, \ .msg = { \ .state = s, \ .payload = name.cmd, \ .num_payload = 0, \ .is_read = false, \ .is_control = false, \ .is_complete = true, \ .invalidate = false, \ }, \ .cmd = { { 0 } }, \ .waitq = q, \ .completion = q, \ .wait_count = c, \ .rc = rc, \ .bit = -1, \ Loading @@ -57,7 +61,7 @@ struct rpmh_req { struct rpmh_msg { struct tcs_mbox_msg msg; struct tcs_cmd cmd[MAX_RPMH_PAYLOAD]; wait_queue_head_t *waitq; struct completion *completion; atomic_t *wait_count; struct rpmh_client *rc; int bit; Loading Loading @@ -106,21 +110,31 @@ static struct rpmh_msg *get_msg_from_pool(struct rpmh_client *rc) return msg; } static void free_msg_to_pool(struct rpmh_msg *rpm_msg) { struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; unsigned long flags; /* If we allocated the pool, set it as available */ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) { spin_lock_irqsave(&rpm->lock, flags); bitmap_clear(rpm->fast_req, rpm_msg->bit, 1); 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); wake_up(rpm_msg->waitq); } 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); struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; atomic_t *wc = rpm_msg->wait_count; wait_queue_head_t *waitq = rpm_msg->waitq; unsigned long flags; struct completion *compl = rpm_msg->completion; rpm_msg->err = r; Loading @@ -144,18 +158,12 @@ static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r) * into an issue that the stack allocated parent object may be * invalid before we can check the ->bit value. */ /* If we allocated the pool, set it as available */ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) { spin_lock_irqsave(&rpm->lock, flags); bitmap_clear(rpm->fast_req, rpm_msg->bit, 1); spin_unlock_irqrestore(&rpm->lock, flags); } free_msg_to_pool(rpm_msg); /* Signal the blocking thread we are done */ if (wc && atomic_dec_and_test(wc)) if (waitq) wake_up(waitq); if (compl) complete(compl); } static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr) Loading Loading @@ -312,9 +320,9 @@ EXPORT_SYMBOL(rpmh_write_single_async); int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state, u32 addr, u32 data) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg); DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg); int ret; if (IS_ERR_OR_NULL(rc)) Loading @@ -333,7 +341,7 @@ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state, if (ret < 0) return ret; wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); return rpm_msg.err; } Loading Loading @@ -408,9 +416,9 @@ EXPORT_SYMBOL(rpmh_write_async); int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int n) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg); 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) Loading @@ -428,7 +436,7 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, if (ret) return ret; wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); return rpm_msg.err; } Loading @@ -454,7 +462,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int *n) { struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH]; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */ int count = 0; int ret, i, j, k; Loading Loading @@ -507,9 +515,8 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, 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])) { /* Clean up our call by spoofing tx_done */ for (j = 0 ; j < i; j++) rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, 0); free_msg_to_pool(rpm_msg[j]); return PTR_ERR(rpm_msg[i]); } cmd += n[i]; Loading @@ -520,7 +527,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, might_sleep(); atomic_set(&wait_count, count); for (i = 0; i < count; i++) { rpm_msg[i]->waitq = &waitq; 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); Loading @@ -530,15 +537,17 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, break; } } wait_event(waitq, atomic_read(&wait_count) == (count - i)); /* 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_completion(&compl); } else { /* Send Sleep requests to the controller, expect no response */ for (i = 0; i < count; i++) { rpm_msg[i]->waitq = NULL; rpm_msg[i]->completion = NULL; ret = mbox_send_controller_data(rc->chan, &rpm_msg[i]->msg); /* Clean up our call by spoofing tx_done */ rpmh_tx_done(&rc->client, &rpm_msg[i]->msg, ret); free_msg_to_pool(rpm_msg[i]); } return 0; } Loading Loading @@ -660,10 +669,10 @@ EXPORT_SYMBOL(rpmh_invalidate); int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp) { int ret; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); 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, &waitq, &wait_count, rpm_msg); &compl, &wait_count, rpm_msg); if (IS_ERR_OR_NULL(rc) || !resp) return -EINVAL; Loading @@ -684,7 +693,7 @@ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp) return ret; /* Wait until the response is received from RPMH */ wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); /* Read the data back from the tcs_mbox_msg structrure */ *resp = rpm_msg.cmd[0].data; Loading Loading
drivers/mailbox/mailbox.c +11 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ static void msg_submit(struct mbox_chan *chan) void *data; int err = -EBUSY; again: spin_lock_irqsave(&chan->lock, flags); if (!chan->msg_count || chan->active_req) Loading @@ -85,6 +86,16 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); /* * If the controller returns -EAGAIN, then it means, our spinlock * here is preventing the controller from receiving its interrupt, * that would help clear the controller channels that are currently * blocked waiting on the interrupt response. * Unlock and retry again. */ if (err == -EAGAIN) goto again; if (!err && (chan->txdone_method & TXDONE_BY_POLL)) /* kick start the timer immediately to avoid delays */ hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0), Loading
drivers/mailbox/qti-tcs.c +107 −42 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <asm-generic/io.h> Loading Loading @@ -95,10 +94,10 @@ struct tcs_response { struct mbox_chan *chan; struct tcs_mbox_msg *msg; u32 m; /* m-th TCS */ struct tasklet_struct tasklet; int err; int idx; bool in_use; struct list_head list; }; struct tcs_response_pool { Loading @@ -122,16 +121,18 @@ struct tcs_mbox { /* One per MBOX controller */ struct tcs_drv { struct mbox_controller mbox; const char *name; void *base; /* start address of the RSC's registers */ void *reg_base; /* start address for DRV specific register */ void __iomem *base; /* start address of the RSC's registers */ void __iomem *reg_base; /* start address for DRV specific register */ int drv_id; struct platform_device *pdev; struct mbox_controller mbox; struct tcs_mbox tcs[TCS_TYPE_NR]; int num_assigned; int num_tcs; struct workqueue_struct *wq; struct tasklet_struct tasklet; struct list_head response_pending; spinlock_t drv_lock; struct tcs_response_pool *resp_pool; atomic_t tcs_in_use[MAX_POOL_SIZE]; /* Debug info */ Loading @@ -141,8 +142,6 @@ struct tcs_drv { atomic_t tcs_irq_count[MAX_POOL_SIZE]; }; static void tcs_notify_tx_done(unsigned long data); static int tcs_response_pool_init(struct tcs_drv *drv) { struct tcs_response_pool *pool; Loading @@ -153,11 +152,10 @@ static int tcs_response_pool_init(struct tcs_drv *drv) return -ENOMEM; for (i = 0; i < MAX_POOL_SIZE; i++) { tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done, (unsigned long) &pool->resp[i]); pool->resp[i].drv = drv; pool->resp[i].idx = i; pool->resp[i].m = TCS_M_INIT; INIT_LIST_HEAD(&pool->resp[i].list); } spin_lock_init(&pool->lock); Loading Loading @@ -188,6 +186,9 @@ static struct tcs_response *setup_response(struct tcs_drv *drv, } spin_unlock_irqrestore(&pool->lock, flags); if (pos == MAX_POOL_SIZE) pr_err("response pool is full\n"); return resp; } Loading Loading @@ -240,11 +241,11 @@ static void print_response(struct tcs_drv *drv, int m) return; msg = resp->msg; pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n", pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n", resp->idx, resp->m, resp->in_use); pr_info("Msg: state=%d\n", msg->state); pr_debug("Msg: state=%d\n", msg->state); for (i = 0; i < msg->num_payload; i++) pr_info("addr=0x%x data=0x%x complete=0x%x\n", pr_debug("addr=0x%x data=0x%x complete=0x%x\n", msg->payload[i].addr, msg->payload[i].data, msg->payload[i].complete); Loading Loading @@ -364,7 +365,15 @@ static inline struct tcs_mbox *get_tcs_for_msg(struct tcs_drv *drv, static inline void send_tcs_response(struct tcs_response *resp) { tasklet_schedule(&resp->tasklet); struct tcs_drv *drv = resp->drv; unsigned long flags; spin_lock_irqsave(&drv->drv_lock, flags); INIT_LIST_HEAD(&resp->list); list_add_tail(&resp->list, &drv->response_pending); spin_unlock_irqrestore(&drv->drv_lock, flags); tasklet_schedule(&drv->tasklet); } static inline void enable_tcs_irq(struct tcs_drv *drv, int m, bool enable) Loading Loading @@ -455,12 +464,12 @@ static irqreturn_t tcs_irq_handler(int irq, void *p) /* Clear the TCS IRQ status */ write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m)); /* Notify the client that this request is completed. */ atomic_set(&drv->tcs_in_use[m], 0); /* Clean up response object and notify mbox in tasklet */ if (resp) send_tcs_response(resp); /* Notify the client that this request is completed. */ atomic_set(&drv->tcs_in_use[m], 0); } return IRQ_HANDLED; Loading @@ -475,19 +484,38 @@ static inline void mbox_notify_tx_done(struct mbox_chan *chan, mbox_chan_txdone(chan, err); } /** * tcs_notify_tx_done: TX Done for requests that do not trigger TCS */ static void tcs_notify_tx_done(unsigned long data) static void respond_tx_done(struct tcs_response *resp) { struct tcs_response *resp = (struct tcs_response *) data; struct mbox_chan *chan = resp->chan; struct tcs_mbox_msg *msg = resp->msg; int err = resp->err; int m = resp->m; mbox_notify_tx_done(chan, msg, m, err); free_response(resp); mbox_notify_tx_done(chan, msg, m, err); } /** * tcs_notify_tx_done: TX Done for requests that do not trigger TCS */ static void tcs_notify_tx_done(unsigned long data) { struct tcs_drv *drv = (struct tcs_drv *)data; struct tcs_response *resp; unsigned long flags; do { spin_lock_irqsave(&drv->drv_lock, flags); if (list_empty(&drv->response_pending)) { spin_unlock_irqrestore(&drv->drv_lock, flags); break; } resp = list_first_entry(&drv->response_pending, struct tcs_response, list); list_del(&resp->list); spin_unlock_irqrestore(&drv->drv_lock, flags); respond_tx_done(resp); } while (1); } static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n, Loading Loading @@ -673,8 +701,11 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, if (IS_ERR(tcs)) return PTR_ERR(tcs); if (trigger) if (trigger) { resp = setup_response(drv, msg, chan, TCS_M_INIT, 0); if (IS_ERR_OR_NULL(resp)) return -EBUSY; } /* Identify the sequential slots that we can write to */ spin_lock_irqsave(&tcs->tcs_lock, flags); Loading @@ -686,28 +717,21 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, return slot; } /* Figure out the TCS-m and CMD-n to write to */ offset = slot / tcs->ncpt; m = offset + tcs->tcs_offset; n = slot % tcs->ncpt; if (trigger) { /* Block, if we have an address from the msg in flight */ ret = check_for_req_inflight(drv, tcs, msg); if (ret) { spin_unlock_irqrestore(&tcs->tcs_lock, flags); if (resp) free_response(resp); return ret; } } /* Mark the slots as in-use, before we unlock */ if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS) bitmap_set(tcs->slots, slot, msg->num_payload); /* Copy the addresses of the resources over to the slots */ for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++) tcs->cmd_addr[slot + i] = msg->payload[i].addr; offset = slot / tcs->ncpt; m = offset + tcs->tcs_offset; n = slot % tcs->ncpt; /* Block, if we have an address from the msg in flight */ if (trigger) { resp->m = m; /* Mark the TCS as busy */ atomic_set(&drv->tcs_in_use[m], 1); Loading @@ -716,6 +740,14 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg, if (tcs->type != ACTIVE_TCS) enable_tcs_irq(drv, m, true); drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct(); } else { /* Mark the slots as in-use, before we unlock */ if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS) bitmap_set(tcs->slots, slot, msg->num_payload); /* Copy the addresses of the resources over to the slots */ for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++) tcs->cmd_addr[slot + i] = msg->payload[i].addr; } /* Write to the TCS or AMC */ Loading Loading @@ -758,6 +790,32 @@ static int tcs_mbox_invalidate(struct mbox_chan *chan) return 0; } static void print_tcs_regs(struct tcs_drv *drv, int m) { int n; struct tcs_mbox *tcs = get_tcs_from_index(drv, m); void __iomem *base = drv->reg_base; u32 enable, addr, data, msgid; if (!tcs || tcs_is_free(drv, m)) return; enable = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0); if (!enable) return; pr_debug("TCS-%d contents:\n", m); for (n = 0; n < tcs->ncpt; n++) { if (!(enable & BIT(n))) continue; addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n); data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n); msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n); pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n", n, addr, data, msgid); } } static void dump_tcs_stats(struct tcs_drv *drv) { int i; Loading @@ -766,12 +824,13 @@ static void dump_tcs_stats(struct tcs_drv *drv) for (i = 0; i < drv->num_tcs; i++) { if (!atomic_read(&drv->tcs_in_use[i])) continue; pr_info("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n", pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n", curr, i, atomic_read(&drv->tcs_send_count[i]), drv->tcs_last_sent_ts[i], atomic_read(&drv->tcs_irq_count[i]), drv->tcs_last_recv_ts[i]); print_tcs_regs(drv, i); print_response(drv, i); } } Loading Loading @@ -840,7 +899,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) if (ret != -EBUSY) break; udelay(100); } while (++count < 10); } while (++count < 100); tx_fail: /* If there was an error in the request, schedule a response */ Loading @@ -849,6 +908,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) drv, msg, chan, TCS_M_INIT, ret); dev_err(dev, "Error sending RPMH message %d\n", ret); if (resp) send_tcs_response(resp); ret = 0; } Loading @@ -857,6 +917,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data) if (ret == -EBUSY) { dev_err(dev, "TCS Busy, retrying RPMH message send\n"); dump_tcs_stats(drv); ret = -EAGAIN; } return ret; Loading Loading @@ -967,6 +1028,7 @@ static struct mbox_chan *of_tcs_mbox_xlate(struct mbox_controller *mbox, } chan = &mbox->chans[drv->num_assigned++]; chan->con_priv = drv; return chan; } Loading Loading @@ -1108,6 +1170,9 @@ static int tcs_drv_probe(struct platform_device *pdev) drv->mbox.is_idle = tcs_drv_is_idle; drv->num_tcs = st; drv->pdev = pdev; INIT_LIST_HEAD(&drv->response_pending); spin_lock_init(&drv->drv_lock); tasklet_init(&drv->tasklet, tcs_notify_tx_done, (unsigned long)drv); drv->name = of_get_property(pdev->dev.of_node, "label", NULL); if (!drv->name) Loading
drivers/soc/qcom/rpmh.c +51 −42 Original line number Diff line number Diff line Loading @@ -35,13 +35,17 @@ #define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name) \ struct rpmh_msg name = { \ .msg = { 0 }, \ .msg.state = s, \ .msg.is_complete = true, \ .msg.payload = name.cmd, \ .msg.num_payload = 0, \ .msg = { \ .state = s, \ .payload = name.cmd, \ .num_payload = 0, \ .is_read = false, \ .is_control = false, \ .is_complete = true, \ .invalidate = false, \ }, \ .cmd = { { 0 } }, \ .waitq = q, \ .completion = q, \ .wait_count = c, \ .rc = rc, \ .bit = -1, \ Loading @@ -57,7 +61,7 @@ struct rpmh_req { struct rpmh_msg { struct tcs_mbox_msg msg; struct tcs_cmd cmd[MAX_RPMH_PAYLOAD]; wait_queue_head_t *waitq; struct completion *completion; atomic_t *wait_count; struct rpmh_client *rc; int bit; Loading Loading @@ -106,21 +110,31 @@ static struct rpmh_msg *get_msg_from_pool(struct rpmh_client *rc) return msg; } static void free_msg_to_pool(struct rpmh_msg *rpm_msg) { struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; unsigned long flags; /* If we allocated the pool, set it as available */ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) { spin_lock_irqsave(&rpm->lock, flags); bitmap_clear(rpm->fast_req, rpm_msg->bit, 1); 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); wake_up(rpm_msg->waitq); } 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); struct rpmh_mbox *rpm = rpm_msg->rc->rpmh; atomic_t *wc = rpm_msg->wait_count; wait_queue_head_t *waitq = rpm_msg->waitq; unsigned long flags; struct completion *compl = rpm_msg->completion; rpm_msg->err = r; Loading @@ -144,18 +158,12 @@ static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r) * into an issue that the stack allocated parent object may be * invalid before we can check the ->bit value. */ /* If we allocated the pool, set it as available */ if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) { spin_lock_irqsave(&rpm->lock, flags); bitmap_clear(rpm->fast_req, rpm_msg->bit, 1); spin_unlock_irqrestore(&rpm->lock, flags); } free_msg_to_pool(rpm_msg); /* Signal the blocking thread we are done */ if (wc && atomic_dec_and_test(wc)) if (waitq) wake_up(waitq); if (compl) complete(compl); } static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr) Loading Loading @@ -312,9 +320,9 @@ EXPORT_SYMBOL(rpmh_write_single_async); int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state, u32 addr, u32 data) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg); DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg); int ret; if (IS_ERR_OR_NULL(rc)) Loading @@ -333,7 +341,7 @@ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state, if (ret < 0) return ret; wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); return rpm_msg.err; } Loading Loading @@ -408,9 +416,9 @@ EXPORT_SYMBOL(rpmh_write_async); int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int n) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(1); DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg); 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) Loading @@ -428,7 +436,7 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state, if (ret) return ret; wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); return rpm_msg.err; } Loading @@ -454,7 +462,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, struct tcs_cmd *cmd, int *n) { struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH]; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); DECLARE_COMPLETION_ONSTACK(compl); atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */ int count = 0; int ret, i, j, k; Loading Loading @@ -507,9 +515,8 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, 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])) { /* Clean up our call by spoofing tx_done */ for (j = 0 ; j < i; j++) rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, 0); free_msg_to_pool(rpm_msg[j]); return PTR_ERR(rpm_msg[i]); } cmd += n[i]; Loading @@ -520,7 +527,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, might_sleep(); atomic_set(&wait_count, count); for (i = 0; i < count; i++) { rpm_msg[i]->waitq = &waitq; 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); Loading @@ -530,15 +537,17 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state, break; } } wait_event(waitq, atomic_read(&wait_count) == (count - i)); /* 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_completion(&compl); } else { /* Send Sleep requests to the controller, expect no response */ for (i = 0; i < count; i++) { rpm_msg[i]->waitq = NULL; rpm_msg[i]->completion = NULL; ret = mbox_send_controller_data(rc->chan, &rpm_msg[i]->msg); /* Clean up our call by spoofing tx_done */ rpmh_tx_done(&rc->client, &rpm_msg[i]->msg, ret); free_msg_to_pool(rpm_msg[i]); } return 0; } Loading Loading @@ -660,10 +669,10 @@ EXPORT_SYMBOL(rpmh_invalidate); int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp) { int ret; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); 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, &waitq, &wait_count, rpm_msg); &compl, &wait_count, rpm_msg); if (IS_ERR_OR_NULL(rc) || !resp) return -EINVAL; Loading @@ -684,7 +693,7 @@ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp) return ret; /* Wait until the response is received from RPMH */ wait_event(waitq, atomic_read(&wait_count) == 0); wait_for_completion(&compl); /* Read the data back from the tcs_mbox_msg structrure */ *resp = rpm_msg.cmd[0].data; Loading