Loading drivers/mailbox/msm_qmp.c +52 −17 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/kthread.h> #include <linux/workqueue.h> #include <linux/mailbox/qmp.h> #include <linux/ipc_logging.h> #define QMP_MAGIC 0x4d41494c /* MAIL */ #define QMP_VERSION 0x1 Loading @@ -37,6 +38,20 @@ #define MSG_RAM_ALIGN_BYTES 3 #define QMP_IPC_LOG_PAGE_CNT 2 #define QMP_INFO(ctxt, x, ...) \ do { \ if (ctxt) \ ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \ } while (0) #define QMP_ERR(ctxt, x, ...) \ do { \ pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__); \ if (ctxt) \ ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \ } while (0) /** * enum qmp_local_state - definition of the local state machine * @LINK_DISCONNECTED: Init state, waiting for ucore to start Loading Loading @@ -172,6 +187,7 @@ struct qmp_mbox { * @rx_work: Work to be executed when an irq is received * @tx_irq_count: Number of tx interrupts triggered * @rx_irq_count: Number of rx interrupts received * @ilc: IPC logging context */ struct qmp_device { struct device *dev; Loading @@ -190,6 +206,8 @@ struct qmp_device { u32 rx_irq_line; u32 tx_irq_count; u32 rx_irq_count; void *ilc; }; /** Loading Loading @@ -247,7 +265,7 @@ static void qmp_notify_timeout(struct work_struct *work) spin_unlock_irqrestore(&mbox->tx_lock, flags); return; } pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight); QMP_ERR(mbox->mdev->ilc, "tx timeout for %d\n", mbox->idx_in_flight); iowrite32(0, mbox->mdev->msgram + mbox->mcore_mbox_offset); mbox->tx_sent = false; spin_unlock_irqrestore(&mbox->tx_lock, flags); Loading Loading @@ -380,6 +398,8 @@ static int qmp_send_data(struct mbox_chan *chan, void *data) if (chan == &mbox->ctrl.chans[i]) mbox->idx_in_flight = i; } QMP_INFO(mdev->ilc, "Copied buffer to msgram sz:%d i:%d\n", pkt->size, mbox->idx_in_flight); send_irq(mdev); qmp_schedule_tx_timeout(mbox); spin_unlock_irqrestore(&mbox->tx_lock, flags); Loading Loading @@ -453,13 +473,14 @@ static void qmp_recv_data(struct qmp_mbox *mbox, u32 mbox_of) pkt->size = ioread32(addr); if (pkt->size > mbox->mcore_mbox_size) pr_err("%s: Invalid mailbox packet\n", __func__); QMP_ERR(mbox->mdev->ilc, "Invalid mailbox packet\n"); else { memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size); mbox_chan_received_data(&mbox->ctrl.chans[mbox->idx_in_flight], pkt); } iowrite32(0, addr); QMP_INFO(mbox->mdev->ilc, "recv sz:%d\n", pkt->size); send_irq(mbox->mdev); } Loading Loading @@ -530,61 +551,67 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) desc.ucore.mailbox_size, GFP_KERNEL); if (!mbox->rx_pkt.data) { pr_err("In %s: failed to allocate rx pkt\n", __func__); QMP_ERR(mdev->ilc, "Failed to allocate rx pkt\n"); break; } QMP_INFO(mdev->ilc, "Set to link negotiation\n"); send_irq(mdev); break; case LINK_NEGOTIATION: if (desc.mcore.link_state_ack != QMP_MBOX_LINK_UP || desc.mcore.link_state != QMP_MBOX_LINK_UP) { pr_err("In %s: rx interrupt without negotiation ack\n", __func__); QMP_ERR(mdev->ilc, "RX int without negotiation ack\n"); break; } mbox->local_state = LINK_CONNECTED; complete_all(&mbox->link_complete); QMP_INFO(mdev->ilc, "Set to link connected\n"); break; case LINK_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { pr_err("In %s: rx interrupt without channel open\n", __func__); QMP_ERR(mdev->ilc, "RX int without ch open\n"); break; } set_ucore_ch_ack(mbox, desc.ucore.ch_state); send_irq(mdev); QMP_INFO(mdev->ilc, "Received remote ch open\n"); break; case LOCAL_CONNECTING: if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED && desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED) desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED) { mbox->local_state = LOCAL_CONNECTED; QMP_INFO(mdev->ilc, "Received local ch open ack\n"); } if (desc.ucore.ch_state != desc.ucore.ch_state_ack) { set_ucore_ch_ack(mbox, desc.ucore.ch_state); send_irq(mdev); QMP_INFO(mdev->ilc, "Received remote channel open\n"); } if (mbox->local_state == LOCAL_CONNECTED && desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED && desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) { mbox->local_state = CHANNEL_CONNECTED; complete_all(&mbox->ch_complete); QMP_INFO(mdev->ilc, "Set to channel connected\n"); } break; case LOCAL_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { pr_err("In %s: rx interrupt without remote channel open\n", __func__); QMP_ERR(mdev->ilc, "RX int without remote ch open\n"); break; } set_ucore_ch_ack(mbox, desc.ucore.ch_state); mbox->local_state = CHANNEL_CONNECTED; send_irq(mdev); complete_all(&mbox->ch_complete); QMP_INFO(mdev->ilc, "Set to channel connected\n"); break; case CHANNEL_CONNECTED: if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) { set_ucore_ch_ack(mbox, desc.ucore.ch_state); mbox->local_state = LOCAL_CONNECTED; QMP_INFO(mdev->ilc, "REMOTE DISCONNECT\n"); send_irq(mdev); } Loading @@ -600,6 +627,9 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) if (msg_len == 0) { mbox->tx_sent = false; cancel_delayed_work(&mbox->dwork); QMP_INFO(mdev->ilc, "TX flag cleared, idx%d\n", idx); spin_unlock_irqrestore(&mbox->tx_lock, flags); mbox_chan_txdone(&mbox->ctrl.chans[idx], 0); spin_lock_irqsave(&mbox->tx_lock, flags); Loading @@ -609,12 +639,15 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) break; case LOCAL_DISCONNECTING: if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED && desc.mcore.ch_state == desc.mcore.ch_state_ack) desc.mcore.ch_state == desc.mcore.ch_state_ack) { mbox->local_state = LINK_CONNECTED; QMP_INFO(mdev->ilc, "Channel closed\n"); reinit_completion(&mbox->ch_complete); } break; default: pr_err("In %s: Local Channel State corrupted\n", __func__); QMP_ERR(mdev->ilc, "Local Channel State corrupted\n"); } mutex_unlock(&mbox->state_lock); } Loading Loading @@ -903,6 +936,8 @@ static int qmp_mbox_probe(struct platform_device *pdev) if (ret) return ret; mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0); kthread_init_work(&mdev->kwork, rx_worker); kthread_init_worker(&mdev->kworker); mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s", Loading @@ -913,13 +948,13 @@ static int qmp_mbox_probe(struct platform_device *pdev) edge_node->name, mdev); if (ret < 0) { qmp_mbox_remove(pdev); pr_err("%s: request irq on %d failed: %d\n", __func__, QMP_ERR(mdev->ilc, "request irq on %d failed: %d\n", mdev->rx_irq_line, ret); return ret; } ret = enable_irq_wake(mdev->rx_irq_line); if (ret < 0) pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__, QMP_ERR(mdev->ilc, "enable_irq_wake on %d failed: %d\n", mdev->rx_irq_line, ret); /* Trigger fake RX in case of missed interrupt */ Loading Loading
drivers/mailbox/msm_qmp.c +52 −17 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/kthread.h> #include <linux/workqueue.h> #include <linux/mailbox/qmp.h> #include <linux/ipc_logging.h> #define QMP_MAGIC 0x4d41494c /* MAIL */ #define QMP_VERSION 0x1 Loading @@ -37,6 +38,20 @@ #define MSG_RAM_ALIGN_BYTES 3 #define QMP_IPC_LOG_PAGE_CNT 2 #define QMP_INFO(ctxt, x, ...) \ do { \ if (ctxt) \ ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \ } while (0) #define QMP_ERR(ctxt, x, ...) \ do { \ pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__); \ if (ctxt) \ ipc_log_string(ctxt, "[%s]: "x, __func__, ##__VA_ARGS__); \ } while (0) /** * enum qmp_local_state - definition of the local state machine * @LINK_DISCONNECTED: Init state, waiting for ucore to start Loading Loading @@ -172,6 +187,7 @@ struct qmp_mbox { * @rx_work: Work to be executed when an irq is received * @tx_irq_count: Number of tx interrupts triggered * @rx_irq_count: Number of rx interrupts received * @ilc: IPC logging context */ struct qmp_device { struct device *dev; Loading @@ -190,6 +206,8 @@ struct qmp_device { u32 rx_irq_line; u32 tx_irq_count; u32 rx_irq_count; void *ilc; }; /** Loading Loading @@ -247,7 +265,7 @@ static void qmp_notify_timeout(struct work_struct *work) spin_unlock_irqrestore(&mbox->tx_lock, flags); return; } pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight); QMP_ERR(mbox->mdev->ilc, "tx timeout for %d\n", mbox->idx_in_flight); iowrite32(0, mbox->mdev->msgram + mbox->mcore_mbox_offset); mbox->tx_sent = false; spin_unlock_irqrestore(&mbox->tx_lock, flags); Loading Loading @@ -380,6 +398,8 @@ static int qmp_send_data(struct mbox_chan *chan, void *data) if (chan == &mbox->ctrl.chans[i]) mbox->idx_in_flight = i; } QMP_INFO(mdev->ilc, "Copied buffer to msgram sz:%d i:%d\n", pkt->size, mbox->idx_in_flight); send_irq(mdev); qmp_schedule_tx_timeout(mbox); spin_unlock_irqrestore(&mbox->tx_lock, flags); Loading Loading @@ -453,13 +473,14 @@ static void qmp_recv_data(struct qmp_mbox *mbox, u32 mbox_of) pkt->size = ioread32(addr); if (pkt->size > mbox->mcore_mbox_size) pr_err("%s: Invalid mailbox packet\n", __func__); QMP_ERR(mbox->mdev->ilc, "Invalid mailbox packet\n"); else { memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size); mbox_chan_received_data(&mbox->ctrl.chans[mbox->idx_in_flight], pkt); } iowrite32(0, addr); QMP_INFO(mbox->mdev->ilc, "recv sz:%d\n", pkt->size); send_irq(mbox->mdev); } Loading Loading @@ -530,61 +551,67 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) desc.ucore.mailbox_size, GFP_KERNEL); if (!mbox->rx_pkt.data) { pr_err("In %s: failed to allocate rx pkt\n", __func__); QMP_ERR(mdev->ilc, "Failed to allocate rx pkt\n"); break; } QMP_INFO(mdev->ilc, "Set to link negotiation\n"); send_irq(mdev); break; case LINK_NEGOTIATION: if (desc.mcore.link_state_ack != QMP_MBOX_LINK_UP || desc.mcore.link_state != QMP_MBOX_LINK_UP) { pr_err("In %s: rx interrupt without negotiation ack\n", __func__); QMP_ERR(mdev->ilc, "RX int without negotiation ack\n"); break; } mbox->local_state = LINK_CONNECTED; complete_all(&mbox->link_complete); QMP_INFO(mdev->ilc, "Set to link connected\n"); break; case LINK_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { pr_err("In %s: rx interrupt without channel open\n", __func__); QMP_ERR(mdev->ilc, "RX int without ch open\n"); break; } set_ucore_ch_ack(mbox, desc.ucore.ch_state); send_irq(mdev); QMP_INFO(mdev->ilc, "Received remote ch open\n"); break; case LOCAL_CONNECTING: if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED && desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED) desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED) { mbox->local_state = LOCAL_CONNECTED; QMP_INFO(mdev->ilc, "Received local ch open ack\n"); } if (desc.ucore.ch_state != desc.ucore.ch_state_ack) { set_ucore_ch_ack(mbox, desc.ucore.ch_state); send_irq(mdev); QMP_INFO(mdev->ilc, "Received remote channel open\n"); } if (mbox->local_state == LOCAL_CONNECTED && desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED && desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) { mbox->local_state = CHANNEL_CONNECTED; complete_all(&mbox->ch_complete); QMP_INFO(mdev->ilc, "Set to channel connected\n"); } break; case LOCAL_CONNECTED: if (desc.ucore.ch_state == desc.ucore.ch_state_ack) { pr_err("In %s: rx interrupt without remote channel open\n", __func__); QMP_ERR(mdev->ilc, "RX int without remote ch open\n"); break; } set_ucore_ch_ack(mbox, desc.ucore.ch_state); mbox->local_state = CHANNEL_CONNECTED; send_irq(mdev); complete_all(&mbox->ch_complete); QMP_INFO(mdev->ilc, "Set to channel connected\n"); break; case CHANNEL_CONNECTED: if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) { set_ucore_ch_ack(mbox, desc.ucore.ch_state); mbox->local_state = LOCAL_CONNECTED; QMP_INFO(mdev->ilc, "REMOTE DISCONNECT\n"); send_irq(mdev); } Loading @@ -600,6 +627,9 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) if (msg_len == 0) { mbox->tx_sent = false; cancel_delayed_work(&mbox->dwork); QMP_INFO(mdev->ilc, "TX flag cleared, idx%d\n", idx); spin_unlock_irqrestore(&mbox->tx_lock, flags); mbox_chan_txdone(&mbox->ctrl.chans[idx], 0); spin_lock_irqsave(&mbox->tx_lock, flags); Loading @@ -609,12 +639,15 @@ static void __qmp_rx_worker(struct qmp_mbox *mbox) break; case LOCAL_DISCONNECTING: if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED && desc.mcore.ch_state == desc.mcore.ch_state_ack) desc.mcore.ch_state == desc.mcore.ch_state_ack) { mbox->local_state = LINK_CONNECTED; QMP_INFO(mdev->ilc, "Channel closed\n"); reinit_completion(&mbox->ch_complete); } break; default: pr_err("In %s: Local Channel State corrupted\n", __func__); QMP_ERR(mdev->ilc, "Local Channel State corrupted\n"); } mutex_unlock(&mbox->state_lock); } Loading Loading @@ -903,6 +936,8 @@ static int qmp_mbox_probe(struct platform_device *pdev) if (ret) return ret; mdev->ilc = ipc_log_context_create(QMP_IPC_LOG_PAGE_CNT, mdev->name, 0); kthread_init_work(&mdev->kwork, rx_worker); kthread_init_worker(&mdev->kworker); mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s", Loading @@ -913,13 +948,13 @@ static int qmp_mbox_probe(struct platform_device *pdev) edge_node->name, mdev); if (ret < 0) { qmp_mbox_remove(pdev); pr_err("%s: request irq on %d failed: %d\n", __func__, QMP_ERR(mdev->ilc, "request irq on %d failed: %d\n", mdev->rx_irq_line, ret); return ret; } ret = enable_irq_wake(mdev->rx_irq_line); if (ret < 0) pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__, QMP_ERR(mdev->ilc, "enable_irq_wake on %d failed: %d\n", mdev->rx_irq_line, ret); /* Trigger fake RX in case of missed interrupt */ Loading