Commit fe89e9b1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rpmsg-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux

Pull rpmsg updates from Bjorn Andersson:
 "The remove functions of the Qualcomm SMD and GLINK RPM platform
  drivers are transitioned to the new void returning prototype. Likewise
  is qcom_smd_unregister_edge() transitioned to void, as it
  unconditionally returned 0.

  An assumption about the ordering of the intent request acknowledgement
  and advertisement of a new intent in the GLINK implementation is
  corrected. Faulty error handling is corrected is improved in the TX
  path, and duplicated code, in the same path, is cleaned up"

* tag 'rpmsg-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux:
  rpmsg: glink: Consolidate TX_DATA and TX_DATA_CONT
  rpmsg: glink: Propagate TX failures in intentless mode as well
  rpmsg: glink: Wait for intent, not just request ack
  rpmsg: glink: Transition intent request signaling to wait queue
  rpmsg: qcom_smd: Convert to platform remove callback returning void
  rpmsg: qcom_glink_rpm: Convert to platform remove callback returning void
  rpmsg: qcom_smd: Make qcom_smd_unregister_edge() return void
parents c5c06e27 ba7a4754
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/rpmsg.h> #include <linux/rpmsg.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/mailbox_client.h> #include <linux/mailbox_client.h>
...@@ -145,7 +146,8 @@ enum { ...@@ -145,7 +146,8 @@ enum {
* @open_req: completed once open-request has been received * @open_req: completed once open-request has been received
* @intent_req_lock: Synchronises multiple intent requests * @intent_req_lock: Synchronises multiple intent requests
* @intent_req_result: Result of intent request * @intent_req_result: Result of intent request
* @intent_req_comp: Completion for intent_req signalling * @intent_received: flag indicating that an intent has been received
* @intent_req_wq: wait queue for intent_req signalling
*/ */
struct glink_channel { struct glink_channel {
struct rpmsg_endpoint ept; struct rpmsg_endpoint ept;
...@@ -175,8 +177,9 @@ struct glink_channel { ...@@ -175,8 +177,9 @@ struct glink_channel {
struct completion open_req; struct completion open_req;
struct mutex intent_req_lock; struct mutex intent_req_lock;
bool intent_req_result; int intent_req_result;
struct completion intent_req_comp; bool intent_received;
wait_queue_head_t intent_req_wq;
}; };
#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
...@@ -221,7 +224,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, ...@@ -221,7 +224,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
init_completion(&channel->open_req); init_completion(&channel->open_req);
init_completion(&channel->open_ack); init_completion(&channel->open_ack);
init_completion(&channel->intent_req_comp); init_waitqueue_head(&channel->intent_req_wq);
INIT_LIST_HEAD(&channel->done_intents); INIT_LIST_HEAD(&channel->done_intents);
INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work); INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
...@@ -419,14 +422,14 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, ...@@ -419,14 +422,14 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
return; return;
} }
channel->intent_req_result = granted; WRITE_ONCE(channel->intent_req_result, granted);
complete(&channel->intent_req_comp); wake_up_all(&channel->intent_req_wq);
} }
static void qcom_glink_intent_req_abort(struct glink_channel *channel) static void qcom_glink_intent_req_abort(struct glink_channel *channel)
{ {
channel->intent_req_result = 0; WRITE_ONCE(channel->intent_req_result, 0);
complete(&channel->intent_req_comp); wake_up_all(&channel->intent_req_wq);
} }
/** /**
...@@ -756,6 +759,11 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink, ...@@ -756,6 +759,11 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
kfree(intent); kfree(intent);
} }
spin_unlock_irqrestore(&channel->intent_lock, flags); spin_unlock_irqrestore(&channel->intent_lock, flags);
if (reuse) {
WRITE_ONCE(channel->intent_received, true);
wake_up_all(&channel->intent_req_wq);
}
} }
/** /**
...@@ -993,6 +1001,9 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink, ...@@ -993,6 +1001,9 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,
dev_err(glink->dev, "failed to store remote intent\n"); dev_err(glink->dev, "failed to store remote intent\n");
} }
WRITE_ONCE(channel->intent_received, true);
wake_up_all(&channel->intent_req_wq);
kfree(msg); kfree(msg);
qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
} }
...@@ -1271,7 +1282,8 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, ...@@ -1271,7 +1282,8 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
mutex_lock(&channel->intent_req_lock); mutex_lock(&channel->intent_req_lock);
reinit_completion(&channel->intent_req_comp); WRITE_ONCE(channel->intent_req_result, -1);
WRITE_ONCE(channel->intent_received, false);
cmd.id = GLINK_CMD_RX_INTENT_REQ; cmd.id = GLINK_CMD_RX_INTENT_REQ;
cmd.cid = channel->lcid; cmd.cid = channel->lcid;
...@@ -1281,12 +1293,15 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, ...@@ -1281,12 +1293,15 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
if (ret) if (ret)
goto unlock; goto unlock;
ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); ret = wait_event_timeout(channel->intent_req_wq,
READ_ONCE(channel->intent_req_result) >= 0 &&
READ_ONCE(channel->intent_received),
10 * HZ);
if (!ret) { if (!ret) {
dev_err(glink->dev, "intent request timed out\n"); dev_err(glink->dev, "intent request timed out\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} else { } else {
ret = channel->intent_req_result ? 0 : -ECANCELED; ret = READ_ONCE(channel->intent_req_result) ? 0 : -ECANCELED;
} }
unlock: unlock:
...@@ -1309,7 +1324,7 @@ static int __qcom_glink_send(struct glink_channel *channel, ...@@ -1309,7 +1324,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
int ret; int ret;
unsigned long flags; unsigned long flags;
int chunk_size = len; int chunk_size = len;
int left_size = 0; size_t offset = 0;
if (!glink->intentless) { if (!glink->intentless) {
while (!intent) { while (!intent) {
...@@ -1343,47 +1358,29 @@ static int __qcom_glink_send(struct glink_channel *channel, ...@@ -1343,47 +1358,29 @@ static int __qcom_glink_send(struct glink_channel *channel,
iid = intent->id; iid = intent->id;
} }
if (wait && chunk_size > SZ_8K) { while (offset < len) {
chunk_size = SZ_8K; chunk_size = len - offset;
left_size = len - chunk_size; if (chunk_size > SZ_8K && wait)
}
req.msg.cmd = cpu_to_le16(GLINK_CMD_TX_DATA);
req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid);
req.chunk_size = cpu_to_le32(chunk_size);
req.left_size = cpu_to_le32(left_size);
ret = qcom_glink_tx(glink, &req, sizeof(req), data, chunk_size, wait);
/* Mark intent available if we failed */
if (ret && intent) {
intent->in_use = false;
return ret;
}
while (left_size > 0) {
data = (void *)((char *)data + chunk_size);
chunk_size = left_size;
if (chunk_size > SZ_8K)
chunk_size = SZ_8K; chunk_size = SZ_8K;
left_size -= chunk_size;
req.msg.cmd = cpu_to_le16(GLINK_CMD_TX_DATA_CONT); req.msg.cmd = cpu_to_le16(offset == 0 ? GLINK_CMD_TX_DATA : GLINK_CMD_TX_DATA_CONT);
req.msg.param1 = cpu_to_le16(channel->lcid); req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid); req.msg.param2 = cpu_to_le32(iid);
req.chunk_size = cpu_to_le32(chunk_size); req.chunk_size = cpu_to_le32(chunk_size);
req.left_size = cpu_to_le32(left_size); req.left_size = cpu_to_le32(len - offset - chunk_size);
ret = qcom_glink_tx(glink, &req, sizeof(req), data,
chunk_size, wait);
/* Mark intent available if we failed */ ret = qcom_glink_tx(glink, &req, sizeof(req), data + offset, chunk_size, wait);
if (ret && intent) { if (ret) {
intent->in_use = false; /* Mark intent available if we failed */
break; if (intent)
intent->in_use = false;
return ret;
} }
offset += chunk_size;
} }
return ret;
return 0;
} }
static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len) static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
......
...@@ -361,7 +361,7 @@ static int glink_rpm_probe(struct platform_device *pdev) ...@@ -361,7 +361,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int glink_rpm_remove(struct platform_device *pdev) static void glink_rpm_remove(struct platform_device *pdev)
{ {
struct glink_rpm *rpm = platform_get_drvdata(pdev); struct glink_rpm *rpm = platform_get_drvdata(pdev);
struct qcom_glink *glink = rpm->glink; struct qcom_glink *glink = rpm->glink;
...@@ -371,8 +371,6 @@ static int glink_rpm_remove(struct platform_device *pdev) ...@@ -371,8 +371,6 @@ static int glink_rpm_remove(struct platform_device *pdev)
qcom_glink_native_remove(glink); qcom_glink_native_remove(glink);
mbox_free_channel(rpm->mbox_chan); mbox_free_channel(rpm->mbox_chan);
return 0;
} }
static const struct of_device_id glink_rpm_of_match[] = { static const struct of_device_id glink_rpm_of_match[] = {
...@@ -383,7 +381,7 @@ MODULE_DEVICE_TABLE(of, glink_rpm_of_match); ...@@ -383,7 +381,7 @@ MODULE_DEVICE_TABLE(of, glink_rpm_of_match);
static struct platform_driver glink_rpm_driver = { static struct platform_driver glink_rpm_driver = {
.probe = glink_rpm_probe, .probe = glink_rpm_probe,
.remove = glink_rpm_remove, .remove_new = glink_rpm_remove,
.driver = { .driver = {
.name = "qcom_glink_rpm", .name = "qcom_glink_rpm",
.of_match_table = glink_rpm_of_match, .of_match_table = glink_rpm_of_match,
......
...@@ -1533,7 +1533,7 @@ static int qcom_smd_remove_device(struct device *dev, void *data) ...@@ -1533,7 +1533,7 @@ static int qcom_smd_remove_device(struct device *dev, void *data)
* qcom_smd_unregister_edge() - release an edge and its children * qcom_smd_unregister_edge() - release an edge and its children
* @edge: edge reference acquired from qcom_smd_register_edge * @edge: edge reference acquired from qcom_smd_register_edge
*/ */
int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) void qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
{ {
int ret; int ret;
...@@ -1547,8 +1547,6 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) ...@@ -1547,8 +1547,6 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
mbox_free_channel(edge->mbox_chan); mbox_free_channel(edge->mbox_chan);
device_unregister(&edge->dev); device_unregister(&edge->dev);
return 0;
} }
EXPORT_SYMBOL(qcom_smd_unregister_edge); EXPORT_SYMBOL(qcom_smd_unregister_edge);
...@@ -1572,22 +1570,22 @@ static int qcom_smd_remove_edge(struct device *dev, void *data) ...@@ -1572,22 +1570,22 @@ static int qcom_smd_remove_edge(struct device *dev, void *data)
{ {
struct qcom_smd_edge *edge = to_smd_edge(dev); struct qcom_smd_edge *edge = to_smd_edge(dev);
return qcom_smd_unregister_edge(edge); qcom_smd_unregister_edge(edge);
return 0;
} }
/* /*
* Shut down all smd clients by making sure that each edge stops processing * Shut down all smd clients by making sure that each edge stops processing
* events and scanning for new channels, then call destroy on the devices. * events and scanning for new channels, then call destroy on the devices.
*/ */
static int qcom_smd_remove(struct platform_device *pdev) static void qcom_smd_remove(struct platform_device *pdev)
{ {
int ret; /*
* qcom_smd_remove_edge always returns zero, so there is no need to
ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge); * check the return value of device_for_each_child.
if (ret) */
dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret); device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge);
return ret;
} }
static const struct of_device_id qcom_smd_of_match[] = { static const struct of_device_id qcom_smd_of_match[] = {
...@@ -1598,7 +1596,7 @@ MODULE_DEVICE_TABLE(of, qcom_smd_of_match); ...@@ -1598,7 +1596,7 @@ MODULE_DEVICE_TABLE(of, qcom_smd_of_match);
static struct platform_driver qcom_smd_driver = { static struct platform_driver qcom_smd_driver = {
.probe = qcom_smd_probe, .probe = qcom_smd_probe,
.remove = qcom_smd_remove, .remove_new = qcom_smd_remove,
.driver = { .driver = {
.name = "qcom-smd", .name = "qcom-smd",
.of_match_table = qcom_smd_of_match, .of_match_table = qcom_smd_of_match,
......
...@@ -11,7 +11,7 @@ struct qcom_smd_edge; ...@@ -11,7 +11,7 @@ struct qcom_smd_edge;
struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
struct device_node *node); struct device_node *node);
int qcom_smd_unregister_edge(struct qcom_smd_edge *edge); void qcom_smd_unregister_edge(struct qcom_smd_edge *edge);
#else #else
...@@ -22,9 +22,8 @@ qcom_smd_register_edge(struct device *parent, ...@@ -22,9 +22,8 @@ qcom_smd_register_edge(struct device *parent,
return NULL; return NULL;
} }
static inline int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) static inline void qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
{ {
return 0;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment