Loading drivers/rpmsg/qcom_glink_native.c +75 −28 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ struct glink_core_rx_intent { * @idr_lock: synchronizes @lcids and @rcids modifications * @lcids: idr of all channels with a known local channel id * @rcids: idr of all channels with a known remote channel id * @in_reset: reset status of this edge * @ilc: ipc logging context reference */ struct qcom_glink { Loading Loading @@ -151,6 +152,8 @@ struct qcom_glink { spinlock_t idr_lock; struct idr lcids; struct idr rcids; atomic_t in_reset; unsigned long features; bool intentless; Loading Loading @@ -187,7 +190,8 @@ enum { * @open_req: completed once open-request has been received * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling * @intent_req_comp: Status of intent request completion * @intent_req_event: Waitqueue for @intent_req_comp */ struct glink_channel { struct rpmsg_endpoint ept; Loading Loading @@ -221,7 +225,8 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; atomic_t intent_req_comp; wait_queue_head_t intent_req_event; }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) Loading Loading @@ -267,7 +272,8 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->open_req); init_completion(&channel->open_ack); init_completion(&channel->intent_req_comp); atomic_set(&channel->intent_req_comp, 0); init_waitqueue_head(&channel->intent_req_event); INIT_LIST_HEAD(&channel->done_intents); kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work); Loading @@ -286,6 +292,7 @@ static void qcom_glink_channel_release(struct kref *ref) unsigned long flags; CH_INFO(channel, "\n"); wake_up(&channel->intent_req_event); kthread_cancel_work_sync(&channel->intent_work); spin_lock_irqsave(&channel->intent_lock, flags); Loading Loading @@ -354,6 +361,11 @@ static int qcom_glink_tx(struct qcom_glink *glink, goto out; } if (atomic_read(&glink->in_reset)) { ret = -ECONNRESET; goto out; } /* Wait without holding the tx_lock */ spin_unlock_irqrestore(&glink->tx_lock, flags); Loading Loading @@ -425,7 +437,8 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, } channel->intent_req_result = granted; complete(&channel->intent_req_comp); atomic_inc(&channel->intent_req_comp); wake_up(&channel->intent_req_event); CH_INFO(channel, "\n"); } Loading Loading @@ -512,40 +525,54 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink, qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true); } static void qcom_glink_rx_done_work(struct kthread_work *work) static int __qcom_glink_rx_done(struct qcom_glink *glink, struct glink_channel *channel, struct glink_core_rx_intent *intent, bool wait) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); struct qcom_glink *glink = channel->glink; struct glink_core_rx_intent *intent, *tmp; struct { u16 id; u16 lcid; u32 liid; } __packed cmd; unsigned int cid = channel->lcid; unsigned int iid; bool reuse; unsigned long flags; spin_lock_irqsave(&channel->intent_lock, flags); list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) { list_del(&intent->node); spin_unlock_irqrestore(&channel->intent_lock, flags); iid = intent->id; reuse = intent->reuse; unsigned int iid = intent->id; bool reuse = intent->reuse; int ret; cmd.id = reuse ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE; cmd.lcid = cid; cmd.liid = iid; CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true); ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, wait); if (ret) return ret; if (!reuse) { kfree(intent->data); kfree(intent); } CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); return 0; } static void qcom_glink_rx_done_work(struct kthread_work *work) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); struct qcom_glink *glink = channel->glink; struct glink_core_rx_intent *intent, *tmp; unsigned long flags; spin_lock_irqsave(&channel->intent_lock, flags); list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) { list_del(&intent->node); spin_unlock_irqrestore(&channel->intent_lock, flags); __qcom_glink_rx_done(glink, channel, intent, true); spin_lock_irqsave(&channel->intent_lock, flags); } spin_unlock_irqrestore(&channel->intent_lock, flags); Loading @@ -555,6 +582,8 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, struct glink_channel *channel, struct glink_core_rx_intent *intent) { int ret = -EAGAIN; /* We don't send RX_DONE to intentless systems */ if (glink->intentless) { kfree(intent->data); Loading @@ -571,11 +600,15 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, /* Schedule the sending of a rx_done indication */ spin_lock(&channel->intent_lock); list_add_tail(&intent->node, &channel->done_intents); spin_unlock(&channel->intent_lock); if (list_empty(&channel->done_intents)) ret = __qcom_glink_rx_done(glink, channel, intent, false); if (ret) { list_add_tail(&intent->node, &channel->done_intents); kthread_queue_work(&glink->kworker, &channel->intent_work); } spin_unlock(&channel->intent_lock); } /** * qcom_glink_receive_version() - receive version/features from remote system Loading Loading @@ -1351,7 +1384,7 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, mutex_lock(&channel->intent_req_lock); reinit_completion(&channel->intent_req_comp); atomic_set(&channel->intent_req_comp, 0); cmd.id = RPM_CMD_RX_INTENT_REQ; cmd.cid = channel->lcid; Loading @@ -1363,10 +1396,15 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, if (ret) goto unlock; ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); ret = wait_event_timeout(channel->intent_req_event, atomic_read(&channel->intent_req_comp) || atomic_read(&glink->in_reset), 10 * HZ); if (!ret) { dev_err(glink->dev, "intent request timed out\n"); ret = -ETIMEDOUT; } else if (atomic_read(&glink->in_reset)) { CH_INFO(channel, "ssr detected\n"); ret = -ECONNRESET; } else { ret = channel->intent_req_result ? 0 : -ECANCELED; } Loading Loading @@ -1794,6 +1832,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, spin_lock_init(&glink->idr_lock); idr_init(&glink->lcids); idr_init(&glink->rcids); atomic_set(&glink->in_reset, 0); ret = of_property_read_string(dev->of_node, "label", &glink->name); if (ret < 0) Loading Loading @@ -1859,9 +1898,17 @@ void qcom_glink_native_remove(struct qcom_glink *glink) int ret; unsigned long flags; atomic_inc(&glink->in_reset); disable_irq(glink->irq); cancel_work_sync(&glink->rx_work); /* Signal all threads to cancel tx */ spin_lock_irqsave(&glink->idr_lock, flags); idr_for_each_entry(&glink->lcids, channel, cid) { wake_up(&channel->intent_req_event); } spin_unlock_irqrestore(&glink->idr_lock, flags); ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device); if (ret) dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); Loading drivers/soc/qcom/glink_probe.c +3 −1 Original line number Diff line number Diff line Loading @@ -118,9 +118,11 @@ static int glink_ssr_ssr_cb(struct notifier_block *this, ssr->seq_num); ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); if (ret) if (ret) { GLINK_ERR(dev, "fail to send do cleanup to %s %d\n", nb->ssr_label, ret); return NOTIFY_DONE; } ret = wait_for_completion_timeout(&ssr->completion, HZ); if (!ret) Loading Loading
drivers/rpmsg/qcom_glink_native.c +75 −28 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ struct glink_core_rx_intent { * @idr_lock: synchronizes @lcids and @rcids modifications * @lcids: idr of all channels with a known local channel id * @rcids: idr of all channels with a known remote channel id * @in_reset: reset status of this edge * @ilc: ipc logging context reference */ struct qcom_glink { Loading Loading @@ -151,6 +152,8 @@ struct qcom_glink { spinlock_t idr_lock; struct idr lcids; struct idr rcids; atomic_t in_reset; unsigned long features; bool intentless; Loading Loading @@ -187,7 +190,8 @@ enum { * @open_req: completed once open-request has been received * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling * @intent_req_comp: Status of intent request completion * @intent_req_event: Waitqueue for @intent_req_comp */ struct glink_channel { struct rpmsg_endpoint ept; Loading Loading @@ -221,7 +225,8 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; atomic_t intent_req_comp; wait_queue_head_t intent_req_event; }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) Loading Loading @@ -267,7 +272,8 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->open_req); init_completion(&channel->open_ack); init_completion(&channel->intent_req_comp); atomic_set(&channel->intent_req_comp, 0); init_waitqueue_head(&channel->intent_req_event); INIT_LIST_HEAD(&channel->done_intents); kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work); Loading @@ -286,6 +292,7 @@ static void qcom_glink_channel_release(struct kref *ref) unsigned long flags; CH_INFO(channel, "\n"); wake_up(&channel->intent_req_event); kthread_cancel_work_sync(&channel->intent_work); spin_lock_irqsave(&channel->intent_lock, flags); Loading Loading @@ -354,6 +361,11 @@ static int qcom_glink_tx(struct qcom_glink *glink, goto out; } if (atomic_read(&glink->in_reset)) { ret = -ECONNRESET; goto out; } /* Wait without holding the tx_lock */ spin_unlock_irqrestore(&glink->tx_lock, flags); Loading Loading @@ -425,7 +437,8 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, } channel->intent_req_result = granted; complete(&channel->intent_req_comp); atomic_inc(&channel->intent_req_comp); wake_up(&channel->intent_req_event); CH_INFO(channel, "\n"); } Loading Loading @@ -512,40 +525,54 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink, qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true); } static void qcom_glink_rx_done_work(struct kthread_work *work) static int __qcom_glink_rx_done(struct qcom_glink *glink, struct glink_channel *channel, struct glink_core_rx_intent *intent, bool wait) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); struct qcom_glink *glink = channel->glink; struct glink_core_rx_intent *intent, *tmp; struct { u16 id; u16 lcid; u32 liid; } __packed cmd; unsigned int cid = channel->lcid; unsigned int iid; bool reuse; unsigned long flags; spin_lock_irqsave(&channel->intent_lock, flags); list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) { list_del(&intent->node); spin_unlock_irqrestore(&channel->intent_lock, flags); iid = intent->id; reuse = intent->reuse; unsigned int iid = intent->id; bool reuse = intent->reuse; int ret; cmd.id = reuse ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE; cmd.lcid = cid; cmd.liid = iid; CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true); ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, wait); if (ret) return ret; if (!reuse) { kfree(intent->data); kfree(intent); } CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); return 0; } static void qcom_glink_rx_done_work(struct kthread_work *work) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); struct qcom_glink *glink = channel->glink; struct glink_core_rx_intent *intent, *tmp; unsigned long flags; spin_lock_irqsave(&channel->intent_lock, flags); list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) { list_del(&intent->node); spin_unlock_irqrestore(&channel->intent_lock, flags); __qcom_glink_rx_done(glink, channel, intent, true); spin_lock_irqsave(&channel->intent_lock, flags); } spin_unlock_irqrestore(&channel->intent_lock, flags); Loading @@ -555,6 +582,8 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, struct glink_channel *channel, struct glink_core_rx_intent *intent) { int ret = -EAGAIN; /* We don't send RX_DONE to intentless systems */ if (glink->intentless) { kfree(intent->data); Loading @@ -571,11 +600,15 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, /* Schedule the sending of a rx_done indication */ spin_lock(&channel->intent_lock); list_add_tail(&intent->node, &channel->done_intents); spin_unlock(&channel->intent_lock); if (list_empty(&channel->done_intents)) ret = __qcom_glink_rx_done(glink, channel, intent, false); if (ret) { list_add_tail(&intent->node, &channel->done_intents); kthread_queue_work(&glink->kworker, &channel->intent_work); } spin_unlock(&channel->intent_lock); } /** * qcom_glink_receive_version() - receive version/features from remote system Loading Loading @@ -1351,7 +1384,7 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, mutex_lock(&channel->intent_req_lock); reinit_completion(&channel->intent_req_comp); atomic_set(&channel->intent_req_comp, 0); cmd.id = RPM_CMD_RX_INTENT_REQ; cmd.cid = channel->lcid; Loading @@ -1363,10 +1396,15 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, if (ret) goto unlock; ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); ret = wait_event_timeout(channel->intent_req_event, atomic_read(&channel->intent_req_comp) || atomic_read(&glink->in_reset), 10 * HZ); if (!ret) { dev_err(glink->dev, "intent request timed out\n"); ret = -ETIMEDOUT; } else if (atomic_read(&glink->in_reset)) { CH_INFO(channel, "ssr detected\n"); ret = -ECONNRESET; } else { ret = channel->intent_req_result ? 0 : -ECANCELED; } Loading Loading @@ -1794,6 +1832,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, spin_lock_init(&glink->idr_lock); idr_init(&glink->lcids); idr_init(&glink->rcids); atomic_set(&glink->in_reset, 0); ret = of_property_read_string(dev->of_node, "label", &glink->name); if (ret < 0) Loading Loading @@ -1859,9 +1898,17 @@ void qcom_glink_native_remove(struct qcom_glink *glink) int ret; unsigned long flags; atomic_inc(&glink->in_reset); disable_irq(glink->irq); cancel_work_sync(&glink->rx_work); /* Signal all threads to cancel tx */ spin_lock_irqsave(&glink->idr_lock, flags); idr_for_each_entry(&glink->lcids, channel, cid) { wake_up(&channel->intent_req_event); } spin_unlock_irqrestore(&glink->idr_lock, flags); ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device); if (ret) dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); Loading
drivers/soc/qcom/glink_probe.c +3 −1 Original line number Diff line number Diff line Loading @@ -118,9 +118,11 @@ static int glink_ssr_ssr_cb(struct notifier_block *this, ssr->seq_num); ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); if (ret) if (ret) { GLINK_ERR(dev, "fail to send do cleanup to %s %d\n", nb->ssr_label, ret); return NOTIFY_DONE; } ret = wait_for_completion_timeout(&ssr->completion, HZ); if (!ret) Loading