[PATCH V6 2/5] rpmsg: Guard against null endpoint ops in destroy
From: Chris Lew In RPMSG GLINK the chrdev device will allocate an ept as part of the rpdev creation. This device will not register endpoint ops even though it has an allocated ept. Protect against the case where the device is being destroyed. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index e330ec4..d6c3275 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -81,7 +81,7 @@ EXPORT_SYMBOL(rpmsg_create_ept); */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - if (ept) + if (ept && ept->ops) ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); -- 2.7.4
[PATCH V6 3/5] rpmsg: glink: Add support for rpmsg glink chrdev
From: Chris Lew RPMSG provides a char device interface to userspace. Probe the rpmsg chrdev channel to enable the rpmsg_ctrl device creation on glink transports. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 38 ++ 1 file changed, 38 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index ea2f33f..b85433c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1574,6 +1574,40 @@ static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) kfree(dcmd); } +static void qcom_glink_device_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_channel *channel = to_glink_channel(rpdev->ept); + + /* Release qcom_glink_alloc_channel() reference */ + kref_put(>refcount, qcom_glink_channel_release); + kfree(rpdev); +} + +static int qcom_glink_create_chrdev(struct qcom_glink *glink) +{ + struct rpmsg_device *rpdev; + struct glink_channel *channel; + + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + channel = qcom_glink_alloc_channel(glink, "rpmsg_chrdev"); + if (IS_ERR(channel)) { + kfree(rpdev); + return PTR_ERR(channel); + } + channel->rpdev = rpdev; + + rpdev->ept = >ept; + rpdev->ops = _device_ops; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = qcom_glink_device_release; + + return rpmsg_chrdev_register_device(rpdev); +} + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -1633,6 +1667,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (ret) return ERR_PTR(ret); + ret = qcom_glink_create_chrdev(glink); + if (ret) + dev_err(glink->dev, "failed to register chrdev\n"); + return glink; } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); -- 2.7.4
[PATCH V6 5/5] rpmsg: glink: unregister rpmsg device during endpoint destroy
Rpmsg device unregister is not happening if channel close is triggered from local side and causing re-registration of device failures. Unregister rpmsg device for local close in endpoint destroy path. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 2b5368b..53b90a1 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1207,6 +1207,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(>recv_lock, flags); @@ -1214,6 +1215,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(>recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { + strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, ); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); @@ -1477,6 +1485,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) rpmsg_unregister_device(glink->dev, ); } + channel->rpdev = NULL; qcom_glink_send_close_ack(glink, channel->rcid); -- 2.7.4
[PATCH V6 1/5] rpmsg: glink: Use complete_all for open states
From: Chris Lew The open_req and open_ack completion variables are the state variables to represent a remote channel as open. Use complete_all so there are no races with waiters and using completion_done. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 1995f5b..ea2f33f 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -970,7 +970,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return -EINVAL; } - complete(>open_ack); + complete_all(>open_ack); return 0; } @@ -1178,7 +1178,7 @@ static int qcom_glink_announce_create(struct rpmsg_device *rpdev) __be32 *val = defaults; int size; - if (glink->intentless) +if (glink->intentless || !completion_done(>open_ack)) return 0; prop = of_find_property(np, "qcom,intents", NULL); @@ -1413,7 +1413,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, channel->rcid = ret; spin_unlock_irqrestore(>idr_lock, flags); - complete(>open_req); + complete_all(>open_req); if (create_device) { rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); -- 2.7.4
[PATCH V5 0/5] Add chrdev and name query support for GLINK
Add support for the GLINK rpmsg transport to register a rpmsg chrdev. This will create the rpmsg_ctrl nodes for userspace clients to open rpmsg epts. The rpmsg chrdev allocation is done by allocating a local channel which also allocates an ept. We need to add some guards against edge cases for this chrdev because it will never fully open. Changes since v5: - Re-orange the completion_done code Changes since v4: - Resending by removing approved patches Changes since v3: - Change to device_add_group for rpmsg name attr - Add patch to unregister the rpmsg device - Add patch to support compat ioctl for rpmsg char driver Changes since v2: - Revert change to make glink attribute table const Changes since v1: - Add explanation to dt-bindings commit message - Add patch complete_all the open_req/ack variables - Add patch to prevent null pointer dereference in chrdev channel release - Change chrdev allocation to use glink channel allocation - Change glink attr struct to const Arun Kumar Neelakantam (1): rpmsg: glink: unregister rpmsg device during endpoint destroy Chris Lew (4): rpmsg: glink: Use complete_all for open states rpmsg: Guard against null endpoint ops in destroy rpmsg: glink: Add support for rpmsg glink chrdev rpmsg: glink: Expose rpmsg name attr for glink drivers/rpmsg/qcom_glink_native.c | 79 +-- drivers/rpmsg/rpmsg_core.c| 2 +- 2 files changed, 77 insertions(+), 4 deletions(-) -- 2.7.4
[PATCH V6 4/5] rpmsg: glink: Expose rpmsg name attr for glink
From: Chris Lew Expose the name field as an attr so clients listening to uevents for rpmsg can identify the edge the events correspond to. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 26 ++ 1 file changed, 26 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index b85433c..2b5368b 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1574,6 +1574,26 @@ static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) kfree(dcmd); } +static ssize_t rpmsg_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + const char *name; + + ret = of_property_read_string(dev->of_node, "label", ); + if (ret < 0) + name = dev->of_node->name; + + return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name); +} +static DEVICE_ATTR_RO(rpmsg_name); + +static struct attribute *qcom_glink_attrs[] = { + _attr_rpmsg_name.attr, + NULL +}; +ATTRIBUTE_GROUPS(qcom_glink); + static void qcom_glink_device_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); @@ -1638,6 +1658,12 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, idr_init(>lcids); idr_init(>rcids); + glink->dev->groups = qcom_glink_groups; + + ret = device_add_groups(dev, qcom_glink_groups); + if (ret) + dev_err(dev, "failed to add groups\n"); + ret = of_property_read_string(dev->of_node, "label", >name); if (ret < 0) glink->name = dev->of_node->name; -- 2.7.4
Re: [PATCH V5 5/5] rpmsg: glink: unregister rpmsg device during endpoint destroy
On 5/14/2020 3:43 AM, Mathieu Poirier wrote: On Wed, May 13, 2020 at 10:40:06AM +0530, Arun Kumar Neelakantam wrote: Rpmsg device unregister is not happening if channel close is triggered from local side and causing re-registration of device failures. Unregister rpmsg device for local close in endpoint destroy path. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 0e8a28c0..fc8ef66 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1207,6 +1207,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(>recv_lock, flags); @@ -1214,6 +1215,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(>recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { If we proceed this way no other channel can have an rpdev. I would hope that unregistration of rpdev would be more symetrical to what is done in patch 03. Thanks, Mathieu Unregister here also required along with in qcom_glink_rx_close() otherwise if the remote open the channel again it map to stale rpmsg device. + strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, ); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); @@ -1477,6 +1485,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) rpmsg_unregister_device(glink->dev, ); } + channel->rpdev = NULL; qcom_glink_send_close_ack(glink, channel->rcid); -- 2.7.4
Re: [PATCH V5 1/5] rpmsg: glink: Use complete_all for open states
On 5/14/2020 2:29 AM, Mathieu Poirier wrote: Hi Arun, On Wed, May 13, 2020 at 10:40:02AM +0530, Arun Kumar Neelakantam wrote: From: Chris Lew The open_req and open_ack completion variables are the state variables to represet a remote channel as open. Use complete_all so there are no s/represet/represent done added in patch set 6 races with waiters and using completion_done. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 1995f5b..604f11f 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -970,7 +970,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return -EINVAL; } - complete(>open_ack); + complete_all(>open_ack); If you do this and as per the note in the comment section above completion_done(), there shouldn't be a need to call completion_done() in qcom_glink_announce_create(). Thanks, Mathieu the completion_done() check still required to avoid sending intent request on channel which only opened by remote. return 0; } @@ -1413,7 +1413,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, channel->rcid = ret; spin_unlock_irqrestore(>idr_lock, flags); - complete(>open_req); + complete_all(>open_req); if (create_device) { rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); -- 2.7.4
[PATCH V4 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 126 ++ 1 file changed, 126 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index fc8ef66..68e039a 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops; #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -975,6 +989,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1036,6 +1120,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); +
[RESEND PATCH V4 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v3: - Correct the TICOMGET case handling as per new rpmsg_get_signals prototype - Update the rpmsg_get_signals function header Changes since v2: - Modify the rpmsg_get_signals function prototype Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 126 ++ drivers/rpmsg/rpmsg_char.c| 75 ++- drivers/rpmsg/rpmsg_core.c| 41 + drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 26 5 files changed, 270 insertions(+), 3 deletions(-) -- 2.7.4
[PATCH V4 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index e2f92f3..ae15d4f 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,19 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +154,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -156,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ skb_queue_purge(>queue); @@ -266,6 +284,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -309,6 +330,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept); if (ret >= 0) ret = put_user(ret, (int __user *)arg); -- 2.7.4
[PATCH V4 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 41 + drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 26 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index d6c3275..453790b 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -283,6 +284,42 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * + * Returns signal bits on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + /* * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels @@ -468,6 +505,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 3fc83cd..8958d6c 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -47,6 +48,8 @@ struct rpmsg_device_ops { * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional * @poll: see @rpmsg_poll(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -66,6 +69,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..48c8ae3 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.
[PATCH V4 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 53 +++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 4bbbacd..e2f92f3 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -269,15 +271,60 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- 2.7.4
[PATCH V5 0/5] Add chrdev and name query support for GLINK
Add support for the GLINK rpmsg transport to register a rpmsg chrdev. This will create the rpmsg_ctrl nodes for userspace clients to open rpmsg epts. The rpmsg chrdev allocation is done by allocating a local channel which also allocates an ept. We need to add some guards against edge cases for this chrdev because it will never fully open. Changes since v4: - Resending by removing approved patches Changes since v3: - Change to device_add_group for rpmsg name attr - Add patch to unregister the rpmsg device - Add patch to support compat ioctl for rpmsg char driver Changes since v2: - Revert change to make glink attribute table const Changes since v1: - Add explanation to dt-bindings commit message - Add patch complete_all the open_req/ack variables - Add patch to prevent null pointer dereference in chrdev channel release - Change chrdev allocation to use glink channel allocation - Change glink attr struct to const Arun Kumar Neelakantam (1): rpmsg: glink: unregister rpmsg device during endpoint destroy Chris Lew (4): rpmsg: glink: Use complete_all for open states rpmsg: Guard against null endpoint ops in destroy rpmsg: glink: Add support for rpmsg glink chrdev rpmsg: glink: Expose rpmsg name attr for glink drivers/rpmsg/qcom_glink_native.c | 79 +-- drivers/rpmsg/rpmsg_core.c| 2 +- 2 files changed, 77 insertions(+), 4 deletions(-) -- 2.7.4
[PATCH V5 2/5] rpmsg: Guard against null endpoint ops in destroy
From: Chris Lew In RPMSG GLINK the chrdev device will allocate an ept as part of the rpdev creation. This device will not register endpoint ops even though it has an allocated ept. Protect against the case where the device is being destroyed. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index e330ec4..d6c3275 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -81,7 +81,7 @@ EXPORT_SYMBOL(rpmsg_create_ept); */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - if (ept) + if (ept && ept->ops) ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); -- 2.7.4
[PATCH V5 3/5] rpmsg: glink: Add support for rpmsg glink chrdev
From: Chris Lew RPMSG provides a char device interface to userspace. Probe the rpmsg chrdev channel to enable the rpmsg_ctrl device creation on glink transports. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 40 ++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 604f11f..3a7f87c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1178,7 +1178,7 @@ static int qcom_glink_announce_create(struct rpmsg_device *rpdev) __be32 *val = defaults; int size; - if (glink->intentless) + if (glink->intentless || !completion_done(>open_ack)) return 0; prop = of_find_property(np, "qcom,intents", NULL); @@ -1574,6 +1574,40 @@ static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) kfree(dcmd); } +static void qcom_glink_device_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_channel *channel = to_glink_channel(rpdev->ept); + + /* Release qcom_glink_alloc_channel() reference */ + kref_put(>refcount, qcom_glink_channel_release); + kfree(rpdev); +} + +static int qcom_glink_create_chrdev(struct qcom_glink *glink) +{ + struct rpmsg_device *rpdev; + struct glink_channel *channel; + + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + channel = qcom_glink_alloc_channel(glink, "rpmsg_chrdev"); + if (IS_ERR(channel)) { + kfree(rpdev); + return PTR_ERR(channel); + } + channel->rpdev = rpdev; + + rpdev->ept = >ept; + rpdev->ops = _device_ops; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = qcom_glink_device_release; + + return rpmsg_chrdev_register_device(rpdev); +} + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -1633,6 +1667,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (ret) return ERR_PTR(ret); + ret = qcom_glink_create_chrdev(glink); + if (ret) + dev_err(glink->dev, "failed to register chrdev\n"); + return glink; } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); -- 2.7.4
[PATCH V5 1/5] rpmsg: glink: Use complete_all for open states
From: Chris Lew The open_req and open_ack completion variables are the state variables to represet a remote channel as open. Use complete_all so there are no races with waiters and using completion_done. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 1995f5b..604f11f 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -970,7 +970,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return -EINVAL; } - complete(>open_ack); + complete_all(>open_ack); return 0; } @@ -1413,7 +1413,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, channel->rcid = ret; spin_unlock_irqrestore(>idr_lock, flags); - complete(>open_req); + complete_all(>open_req); if (create_device) { rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); -- 2.7.4
[PATCH V5 4/5] rpmsg: glink: Expose rpmsg name attr for glink
From: Chris Lew Expose the name field as an attr so clients listening to uevents for rpmsg can identify the edge the events correspond to. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 26 ++ 1 file changed, 26 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 3a7f87c..0e8a28c0 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1574,6 +1574,26 @@ static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) kfree(dcmd); } +static ssize_t rpmsg_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + const char *name; + + ret = of_property_read_string(dev->of_node, "label", ); + if (ret < 0) + name = dev->of_node->name; + + return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name); +} +static DEVICE_ATTR_RO(rpmsg_name); + +static struct attribute *qcom_glink_attrs[] = { + _attr_rpmsg_name.attr, + NULL +}; +ATTRIBUTE_GROUPS(qcom_glink); + static void qcom_glink_device_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); @@ -1638,6 +1658,12 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, idr_init(>lcids); idr_init(>rcids); + glink->dev->groups = qcom_glink_groups; + + ret = device_add_groups(dev, qcom_glink_groups); + if (ret) + dev_err(dev, "failed to add groups\n"); + ret = of_property_read_string(dev->of_node, "label", >name); if (ret < 0) glink->name = dev->of_node->name; -- 2.7.4
[PATCH V5 5/5] rpmsg: glink: unregister rpmsg device during endpoint destroy
Rpmsg device unregister is not happening if channel close is triggered from local side and causing re-registration of device failures. Unregister rpmsg device for local close in endpoint destroy path. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 0e8a28c0..fc8ef66 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1207,6 +1207,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(>recv_lock, flags); @@ -1214,6 +1215,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(>recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { + strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, ); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); @@ -1477,6 +1485,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) rpmsg_unregister_device(glink->dev, ); } + channel->rpdev = NULL; qcom_glink_send_close_ack(glink, channel->rcid); -- 2.7.4
Re: [PATCH v7 2/4] soc: qcom: Add AOSS QMP driver
Hi Bjorn, On 5/1/2019 10:07 AM, Bjorn Andersson wrote: The Always On Subsystem (AOSS) Qualcomm Messaging Protocol (QMP) driver is used to communicate with the AOSS for certain side-channel requests, that are not available through the RPMh interface. The communication is a very simple synchronous mechanism of messages being written in message RAM and a doorbell in the AOSS is rung. As the AOSS has processed the message length is cleared and an interrupt is fired by the AOSS as acknowledgment. The driver exposes the QDSS clock as a clock and the low-power state associated with the remoteprocs in the system as a set of power-domains. Signed-off-by: Bjorn Andersson --- Changes since v6: - Squash the pd into the same driver as the communication, to simplify the interaction. - Representing the QDSS clocks as a clock/power domain turns out to cascade into a request to make all Coresight drivers have a secondary compatible to replace the required bus clock with a required power domain. So in v7 this is exposed as a clock instead. - Some error checking updates, as reported by Doug. drivers/soc/qcom/Kconfig | 11 + drivers/soc/qcom/Makefile| 1 + drivers/soc/qcom/qcom_aoss.c | 473 +++ 3 files changed, 485 insertions(+) create mode 100644 drivers/soc/qcom/qcom_aoss.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 1ee298f6bf17..3e460b334b47 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -3,6 +3,17 @@ # menu "Qualcomm SoC drivers" +config QCOM_AOSS_QMP + tristate "Qualcomm AOSS Driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on MAILBOX + select PM_GENERIC_DOMAINS + help + This driver provides the means of communicating with and controlling + the low-power state for resources related to the remoteproc + subsystems as well as controlling the debug clocks exposed by the Always On + Subsystem (AOSS) using Qualcomm Messaging Protocol (QMP). + config QCOM_COMMAND_DB bool "Qualcomm Command DB" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index ffe519b0cb66..eeb088beb15f 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS_rpmh-rsc.o := -I$(src) +obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c new file mode 100644 index ..f1fc26ab2e36 --- /dev/null +++ b/drivers/soc/qcom/qcom_aoss.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Linaro Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define QMP_DESC_MAGIC 0x0 +#define QMP_DESC_VERSION 0x4 +#define QMP_DESC_FEATURES 0x8 + +/* AOP-side offsets */ +#define QMP_DESC_UCORE_LINK_STATE 0xc +#define QMP_DESC_UCORE_LINK_STATE_ACK 0x10 +#define QMP_DESC_UCORE_CH_STATE0x14 +#define QMP_DESC_UCORE_CH_STATE_ACK0x18 +#define QMP_DESC_UCORE_MBOX_SIZE 0x1c +#define QMP_DESC_UCORE_MBOX_OFFSET 0x20 + +/* Linux-side offsets */ +#define QMP_DESC_MCORE_LINK_STATE 0x24 +#define QMP_DESC_MCORE_LINK_STATE_ACK 0x28 +#define QMP_DESC_MCORE_CH_STATE0x2c +#define QMP_DESC_MCORE_CH_STATE_ACK0x30 +#define QMP_DESC_MCORE_MBOX_SIZE 0x34 +#define QMP_DESC_MCORE_MBOX_OFFSET 0x38 + +#define QMP_STATE_UP 0x +#define QMP_STATE_DOWN 0x + +#define QMP_MAGIC 0x4d41494c +#define QMP_VERSION1 + +/* Requests are expected to be 96 bytes long */ +#define QMP_MSG_LEN96 + +/** + * struct qmp - driver state for QMP implementation + * @msgram: iomem referencing the message RAM used for communication + * @dev: reference to QMP device + * @mbox_client: mailbox client used to ring the doorbell on transmit + * @mbox_chan: mailbox channel used to ring the doorbell on transmit + * @offset: offset within @msgram where messages should be written + * @size: maximum size of the messages to be transmitted + * @event: wait_queue for synchronization with the IRQ + * @tx_lock: provides syncrhonization between multiple callers of qmp_send() + * @qdss_clk: QDSS clock hw struct + * @pd_data: genpd data + */ +struct qmp { + void __iomem *msgram; + struct device *dev; + + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + + size_t offset; + size_t size; + + wait_queue_head_t event; + + struct mutex tx_lock; + + struct clk_hw qdss_clk; + struct genpd_onecell_data pd_data; +}; + +struct qmp_pd { + struct qmp *qmp; + struct generic_pm_domain pd; +}; + +#define
Re: [PATCH v2 2/7] soc: qcom: Add AOSS QMP communication driver
On 1/6/2019 1:39 PM, Bjorn Andersson wrote: The AOSS QMP driver is used to communicate with the AOSS for certain side-channel requests, that are not enabled through the RPMh interface. The communication is a very simple synchronous mechanism of messages being written in message RAM and a doorbell in the AOSS is rung. As the AOSS has processed the message length is cleared and an interrupt is fired by the AOSS as acknowledgment. Signed-off-by: Bjorn Andersson --- Reviewed-by: Arun Kumar Neelakantam Changes since v1: - Skip check in send for empty TX buffer - Don't follow WARN_ON() with dev_err() - Register platform_device rather than populate based on of-children drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/aoss-qmp.c | 313 ++ include/linux/soc/qcom/aoss-qmp.h | 12 ++ 4 files changed, 335 insertions(+) create mode 100644 drivers/soc/qcom/aoss-qmp.c create mode 100644 include/linux/soc/qcom/aoss-qmp.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index a51458022d21..dda19471057f 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -3,6 +3,15 @@ # menu "Qualcomm SoC drivers" +config QCOM_AOSS_QMP + tristate "Qualcomm AOSS Messaging Driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on MAILBOX + help + This driver provides the means for communicating with the + micro-controller in the AOSS, using QMP, to control certain resource + that are not exposed through RPMh. + config QCOM_COMMAND_DB bool "Qualcomm Command DB" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 67cb85d0373c..d0d7fdc94d9a 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS_rpmh-rsc.o := -I$(src) +obj-$(CONFIG_QCOM_AOSS_QMP) += aoss-qmp.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o diff --git a/drivers/soc/qcom/aoss-qmp.c b/drivers/soc/qcom/aoss-qmp.c new file mode 100644 index ..de52703b96b6 --- /dev/null +++ b/drivers/soc/qcom/aoss-qmp.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, Linaro Ltd + */ +#include +#include +#include +#include +#include +#include + +#define QMP_DESC_MAGIC 0x0 +#define QMP_DESC_VERSION 0x4 +#define QMP_DESC_FEATURES 0x8 + +#define QMP_DESC_UCORE_LINK_STATE 0xc +#define QMP_DESC_UCORE_LINK_STATE_ACK 0x10 +#define QMP_DESC_UCORE_CH_STATE0x14 +#define QMP_DESC_UCORE_CH_STATE_ACK0x18 +#define QMP_DESC_UCORE_MBOX_SIZE 0x1c +#define QMP_DESC_UCORE_MBOX_OFFSET 0x20 + +#define QMP_DESC_MCORE_LINK_STATE 0x24 +#define QMP_DESC_MCORE_LINK_STATE_ACK 0x28 +#define QMP_DESC_MCORE_CH_STATE0x2c +#define QMP_DESC_MCORE_CH_STATE_ACK0x30 +#define QMP_DESC_MCORE_MBOX_SIZE 0x34 +#define QMP_DESC_MCORE_MBOX_OFFSET 0x38 + +#define QMP_STATE_UP 0x +#define QMP_STATE_DOWN 0x + +#define QMP_MAGIC 0x4d41494c +#define QMP_VERSION1 + +/** + * struct qmp - driver state for QMP implementation + * @msgram: iomem referencing the message RAM used for communication + * @dev: reference to QMP device + * @mbox_client: mailbox client used to ring the doorbell on transmit + * @mbox_chan: mailbox channel used to ring the doorbell on transmit + * @offset: offset within @msgram where messages should be written + * @size: maximum size of the messages to be transmitted + * @event: wait_queue for synchronization with the IRQ + * @tx_lock: provides syncrhonization between multiple callers of qmp_send() + * @pd_pdev: platform device for the power-domain child device + */ +struct qmp { + void __iomem *msgram; + struct device *dev; + + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + + size_t offset; + size_t size; + + wait_queue_head_t event; + + struct mutex tx_lock; + + struct platform_device *pd_pdev; +}; + +static void qmp_kick(struct qmp *qmp) +{ + mbox_send_message(qmp->mbox_chan, NULL); + mbox_client_txdone(qmp->mbox_chan, 0); +} + +static bool qmp_magic_valid(struct qmp *qmp) +{ + return readl(qmp->msgram + QMP_DESC_MAGIC) == QMP_MAGIC; +} + +static bool qmp_link_acked(struct qmp *qmp) +{ + return readl(qmp->msgram + QMP_DESC_MCORE_LINK_STATE_ACK) == QMP_STATE_UP; +} + +static bool qmp_mcore_channel_acked(struct qmp *qmp) +{ + return readl(qmp->msgram + QMP_DESC_MCORE_CH_STATE_ACK) == QMP_STATE_UP; +} + +static bool qmp_ucore_channel_up(struct qmp *qmp) +{ + return readl(qmp->msgram + QMP_DESC_UCORE_CH_STATE) == QMP_STATE_UP; +} + +static
Re: [PATCH 2/3] soc: qcom: Add AOSS QMP communication driver
On 12/27/2018 1:58 AM, Bjorn Andersson wrote: On Tue 20 Nov 04:22 PST 2018, Arun Kumar Neelakantam wrote: Thanks for the review Arun. On 11/12/2018 1:35 PM, Bjorn Andersson wrote: [..] +int qmp_send(struct qmp *qmp, const void *data, size_t len) +{ + int ret; + + if (WARN_ON(len + sizeof(u32) > qmp->size)) { + dev_err(qmp->dev, "message too long\n"); + return -EINVAL; + } + + if (WARN_ON(len % sizeof(u32))) { + dev_err(qmp->dev, "message not 32-bit aligned\n"); + return -EINVAL; + } + + mutex_lock(>tx_lock); + + if (!qmp_message_empty(qmp)) { + dev_err(qmp->dev, "mailbox left busy\n"); + ret = -EINVAL; should it be -EBUSY ? That makes more sense. And qmp_messge_empty will be done either by remote if it process the data else by this driver in TIMEOUT case, so does we need this check for every TX ? I think we can just reset to Zero once in open time. Didn't think about that, should we really make the QMP link ready again when we get a timeout? Can we expect that the firmware of the remote side is ready to serve future messages? Should we keep this check and remove the writel() below? I prefer we can just remove this check and keep writel() below same as down stream. + goto out_unlock; + } + + /* The message RAM only implements 32-bit accesses */ + __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32), +data, len / sizeof(u32)); + writel(len, qmp->msgram + qmp->offset); + qmp_kick(qmp); + + ret = wait_event_interruptible_timeout(qmp->event, + qmp_message_empty(qmp), HZ); + if (!ret) { + dev_err(qmp->dev, "ucore did not ack channel\n"); + ret = -ETIMEDOUT; + + writel(0, qmp->msgram + qmp->offset); + } else { + ret = 0; + } + +out_unlock: + mutex_unlock(>tx_lock); + + return ret; +} Regards, Bjorn
[PATCH V4 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index b136684..8a3cbe9 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -306,6 +326,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept); if (ret >= 0) ret = put_user(ret, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index b136684..8a3cbe9 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -306,6 +326,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept); if (ret >= 0) ret = put_user(ret, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 53 +++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..b136684 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,60 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 53 +++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..b136684 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,60 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 126 ++ 1 file changed, 126 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..e90f543 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V4 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Changes since v2: - Modify the rpmsg_get_signals function prototype Changes since v3: - Correct the TICOMGET case handling as per new rpmsg_get_signals prototype - Update the rpmsg_get_signals function header Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 126 ++ drivers/rpmsg/rpmsg_char.c| 74 +- drivers/rpmsg/rpmsg_core.c| 41 + drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 26 5 files changed, 269 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 126 ++ 1 file changed, 126 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..e90f543 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V4 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Changes since v2: - Modify the rpmsg_get_signals function prototype Changes since v3: - Correct the TICOMGET case handling as per new rpmsg_get_signals prototype - Update the rpmsg_get_signals function header Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 126 ++ drivers/rpmsg/rpmsg_char.c| 74 +- drivers/rpmsg/rpmsg_core.c| 41 + drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 26 5 files changed, 269 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 41 + drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 26 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..3d7458a 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -283,6 +284,42 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * + * Returns signal bits on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + /* * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels @@ -468,6 +505,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..033656d 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..48c8ae3 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg c
[PATCH V4 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 41 + drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 26 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..3d7458a 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -283,6 +284,42 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * + * Returns signal bits on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + /* * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels @@ -468,6 +505,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..033656d 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..48c8ae3 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg c
[PATCH V3 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 53 +++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..16978f7b 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,60 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept); + if (!ret) + ret = put_user(ret, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 16978f7b..a5855f7 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -306,6 +326,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept); if (!ret) ret = put_user(ret, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 53 +++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..16978f7b 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,60 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept); + if (!ret) + ret = put_user(ret, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 16978f7b..a5855f7 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -306,6 +326,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept); if (!ret) ret = put_user(ret, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 126 ++ 1 file changed, 126 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..e90f543 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V3 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 126 ++ 1 file changed, 126 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..e90f543 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V3 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 41 + drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 26 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..e9b719b 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -283,6 +284,42 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + /* * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels @@ -468,6 +505,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..033656d 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..48c8ae3 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg channel is r
[PATCH V3 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Changes since v2: - Modify the rpmsg_get_signals function prototype Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 126 ++ drivers/rpmsg/rpmsg_char.c| 74 +- drivers/rpmsg/rpmsg_core.c| 41 + drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 26 5 files changed, 269 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 41 + drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 26 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..e9b719b 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -283,6 +284,42 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + /* * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels @@ -468,6 +505,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..033656d 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..48c8ae3 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg channel is r
[PATCH V3 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Changes since v2: - Modify the rpmsg_get_signals function prototype Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 126 ++ drivers/rpmsg/rpmsg_char.c| 74 +- drivers/rpmsg/rpmsg_core.c| 41 + drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 26 5 files changed, 269 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 130 ++ drivers/rpmsg/rpmsg_char.c| 75 +- drivers/rpmsg/rpmsg_core.c| 42 drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 27 5 files changed, 276 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 0/4] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Changes since v1: - Split the patches as per functional areas like core, char, glink - Add set, clear mask for TIOCMSET - Merge the char signal callback and POLLPRI patches Arun Kumar Neelakantam (4): rpmsg: core: Add signal API support rpmsg: glink: Add support to handle signals command rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support rpmsg: char: Add signal callback and POLLPRI support drivers/rpmsg/qcom_glink_native.c | 130 ++ drivers/rpmsg/rpmsg_char.c| 75 +- drivers/rpmsg/rpmsg_core.c| 42 drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 27 5 files changed, 276 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 54 +++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..9380c6e 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,61 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept, , ); + if (!ret) + ret = put_user(rsigs, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 3/4] rpmsg: char: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 54 +++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..9380c6e 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek * Copyright (c) 2012, PetaLogix @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -266,15 +268,61 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +int __user *arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 set, clear, val; + int ret; + + ret = get_user(val, arg); + if (ret) + return ret; + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; + + return rpmsg_set_signals(eptdev->ept, set, clear); +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_signals(eptdev->ept, , ); + if (!ret) + ret = put_user(rsigs, (int __user *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, (int __user *)arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 130 ++ 1 file changed, 130 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..35e2009 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V2 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 9380c6e..194d54a 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -307,6 +327,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept, , ); if (!ret) ret = put_user(rsigs, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 42 ++ drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 27 +++ 3 files changed, 74 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..9efcd26 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -177,6 +178,43 @@ int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, EXPORT_SYMBOL(rpmsg_send_offchannel); /** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * @sigs: serial signals bitmask + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept, u32 *lsigs, u32 *rsigs) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept, lsigs, rsigs); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + +/** * rpmsg_send() - send a message across to the remote processor * @ept: the rpmsg endpoint * @data: payload of message @@ -468,6 +506,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..0a37d9bf 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept, u32 *lsigs, u32 *rsigs); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..4e50d57 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a
[PATCH V2 2/4] rpmsg: glink: Add support to handle signals command
Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and convert the signals from NATIVE to TIOCM while receiving and vice versa while sending. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 130 ++ 1 file changed, 130 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e2ce4e6..35e2009 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018, The Linux Foundation. * Copyright (c) 2016-2017, Linaro Ltd */ @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: local side signals + * @rsigs: remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +185,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; + }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,9 +209,15 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -957,6 +971,76 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + + channel->rsigs = signals; + + if (channel->ept.sig_cb) { + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + } + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1018,6 +1102,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance
[PATCH V2 4/4] rpmsg: char: Add signal callback and POLLPRI support
Register a callback to get the signal notifications from rpmsg and send POLLPRI mask to indicate the signal change in POLL system call. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 9380c6e..194d54a 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + bool sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -122,6 +125,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->sig_pending = true; + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -138,6 +153,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; @@ -157,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + eptdev->sig_pending = false; /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -263,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->sig_pending) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -307,6 +327,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case TIOCMGET: + eptdev->sig_pending = false; ret = rpmsg_get_signals(eptdev->ept, , ); if (!ret) ret = put_user(rsigs, (int __user *)arg); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 1/4] rpmsg: core: Add signal API support
Some transports like Glink support the state notifications between clients using signals similar to serial protocol signals. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 42 ++ drivers/rpmsg/rpmsg_internal.h | 5 + include/linux/rpmsg.h | 27 +++ 3 files changed, 74 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 8122807..9efcd26 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -2,6 +2,7 @@ /* * remote processor messaging bus * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -177,6 +178,43 @@ int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, EXPORT_SYMBOL(rpmsg_send_offchannel); /** + * rpmsg_get_signals() - get the signals for this endpoint + * @ept: the rpmsg endpoint + * @sigs: serial signals bitmask + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_get_signals(struct rpmsg_endpoint *ept, u32 *lsigs, u32 *rsigs) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->get_signals) + return -EOPNOTSUPP; + + return ept->ops->get_signals(ept, lsigs, rsigs); +} +EXPORT_SYMBOL(rpmsg_get_signals); + +/** + * rpmsg_set_signals() - set the remote signals for this endpoint + * @ept: the rpmsg endpoint + * @set: set mask for signals + * @clear: clear mask for signals + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_signals) + return -EOPNOTSUPP; + + return ept->ops->set_signals(ept, set, clear); +} +EXPORT_SYMBOL(rpmsg_set_signals); + +/** * rpmsg_send() - send a message across to the remote processor * @ept: the rpmsg endpoint * @data: payload of message @@ -468,6 +506,10 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + if (rpdrv->signals) + ept->sig_cb = rpdrv->signals; + } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 0d791c3..0a37d9bf 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -2,6 +2,7 @@ /* * remote processor messaging bus internals * + * Copyright (c) 2018, The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * @@ -46,6 +47,8 @@ struct rpmsg_device_ops { * @trysend: see @rpmsg_trysend(), required * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional + * @get_signals: see @rpmsg_get_signals(), optional + * @set_signals: see @rpmsg_set_signals(), optional * * Indirection table for the operations that a rpmsg backend should implement. * In addition to @destroy_ept, the backend must at least implement @send and @@ -65,6 +68,8 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*get_signals)(struct rpmsg_endpoint *ept, u32 *lsigs, u32 *rsigs); + int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 9fe156d..4e50d57 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -2,6 +2,7 @@ /* * Remote processor messaging * + * Copyright (c) 2018 The Linux Foundation. * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * All rights reserved. @@ -60,6 +61,7 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user @@ -67,6 +69,7 @@ struct rpmsg_device { * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb + * @sig_cb: rx serial signal handler * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -89,6 +92,7 @@ struct rpmsg_endpoint { struct kref refcount; rpmsg_rx_cb_t cb; struct mutex cb_lock; + rpmsg_rx_sig_t sig_cb; u32 addr; void *priv; @@ -102,6 +106,7 @@ struct rpmsg_endpoint { * @probe: invoked when a
[PATCH] rpmsg: glink: smem: Support rx peak for size less than 4 bytes
The current rx peak function fails to read the data if size is less than 4bytes. Use memcpy_fromio to support data reads of size less than 4 bytes. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_smem.c | 12 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 2b5cf27..7b65443 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -89,15 +89,11 @@ static void glink_smem_rx_peak(struct qcom_glink_pipe *np, tail -= pipe->native.length; len = min_t(size_t, count, pipe->native.length - tail); - if (len) { - __ioread32_copy(data, pipe->fifo + tail, - len / sizeof(u32)); - } + if (len) + memcpy_fromio(data, pipe->fifo + tail, len); - if (len != count) { - __ioread32_copy(data + len, pipe->fifo, - (count - len) / sizeof(u32)); - } + if (len != count) + memcpy_fromio(data + len, pipe->fifo, (count - len)); } static void glink_smem_rx_advance(struct qcom_glink_pipe *np, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] rpmsg: glink: smem: Support rx peak for size less than 4 bytes
The current rx peak function fails to read the data if size is less than 4bytes. Use memcpy_fromio to support data reads of size less than 4 bytes. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_smem.c | 12 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 2b5cf27..7b65443 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -89,15 +89,11 @@ static void glink_smem_rx_peak(struct qcom_glink_pipe *np, tail -= pipe->native.length; len = min_t(size_t, count, pipe->native.length - tail); - if (len) { - __ioread32_copy(data, pipe->fifo + tail, - len / sizeof(u32)); - } + if (len) + memcpy_fromio(data, pipe->fifo + tail, len); - if (len != count) { - __ioread32_copy(data + len, pipe->fifo, - (count - len) / sizeof(u32)); - } + if (len != count) + memcpy_fromio(data + len, pipe->fifo, (count - len)); } static void glink_smem_rx_advance(struct qcom_glink_pipe *np, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 4/5] rpmsg: wakeup poll to notify signal update
Add support to wait on poll to get signal notifications. Send POLLPRI mask to indicate the signal change. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index c983d6c..aee5561 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + atomic_t sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -125,6 +128,12 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, u32 old, u32 new) { + struct rpmsg_eptdev *eptdev = priv; + + atomic_set(>sig_pending, 1); + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); return 0; } @@ -164,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + atomic_set(>sig_pending, 0); /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -270,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (atomic_read(>sig_pending)) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -318,6 +331,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, ret = rpmsg_get_sigs(eptdev->ept, , ); if (!ret) ret = put_user(rsigs, (u32 *)arg); + atomic_set(>sig_pending, 0); break; case TIOCMSET: case TIOCMBIS: -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 3/5] rpmsg: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 54 +++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 86003d5..c983d6c 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -274,15 +275,62 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +unsigned long arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs, val; + int ret; + + ret = get_user(val, (u32 *)arg); + if (ret) + return ret; + + ret = rpmsg_get_sigs(eptdev->ept, , ); + if (ret < 0) + return ret; + + switch (cmd) { + case TIOCMBIS: + lsigs |= val; + break; + case TIOCMBIC: + lsigs &= ~val; + break; + case TIOCMSET: + lsigs = val; + break; + } + + ret = rpmsg_set_sigs(eptdev->ept, lsigs); + return ret; +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_sigs(eptdev->ept, , ); + if (!ret) + ret = put_user(rsigs, (u32 *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 4/5] rpmsg: wakeup poll to notify signal update
Add support to wait on poll to get signal notifications. Send POLLPRI mask to indicate the signal change. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index c983d6c..aee5561 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -64,6 +64,7 @@ struct rpmsg_ctrldev { * @queue_lock:synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue + * @sig_pending:state of signal notification */ struct rpmsg_eptdev { struct device dev; @@ -78,6 +79,8 @@ struct rpmsg_eptdev { spinlock_t queue_lock; struct sk_buff_head queue; wait_queue_head_t readq; + + atomic_t sig_pending; }; static int rpmsg_eptdev_destroy(struct device *dev, void *data) @@ -125,6 +128,12 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, u32 old, u32 new) { + struct rpmsg_eptdev *eptdev = priv; + + atomic_set(>sig_pending, 1); + + /* wake up any blocking processes, waiting for signal notification */ + wake_up_interruptible(>readq); return 0; } @@ -164,6 +173,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(>ept_lock); + atomic_set(>sig_pending, 0); /* Discard all SKBs */ while (!skb_queue_empty(>queue)) { @@ -270,6 +280,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(>queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (atomic_read(>sig_pending)) + mask |= POLLPRI; + mask |= rpmsg_poll(eptdev->ept, filp, wait); return mask; @@ -318,6 +331,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, ret = rpmsg_get_sigs(eptdev->ept, , ); if (!ret) ret = put_user(rsigs, (u32 *)arg); + atomic_set(>sig_pending, 0); break; case TIOCMSET: case TIOCMBIS: -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 3/5] rpmsg: Add TIOCMGET/TIOCMSET ioctl support
Add TICOMGET and TIOCMSET ioctl support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 54 +++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 86003d5..c983d6c 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -274,15 +275,62 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) return mask; } +static int rpmsg_eptdev_tiocmset(struct file *fp, unsigned int cmd, +unsigned long arg) +{ + struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs, val; + int ret; + + ret = get_user(val, (u32 *)arg); + if (ret) + return ret; + + ret = rpmsg_get_sigs(eptdev->ept, , ); + if (ret < 0) + return ret; + + switch (cmd) { + case TIOCMBIS: + lsigs |= val; + break; + case TIOCMBIC: + lsigs &= ~val; + break; + case TIOCMSET: + lsigs = val; + break; + } + + ret = rpmsg_set_sigs(eptdev->ept, lsigs); + return ret; +} + static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { struct rpmsg_eptdev *eptdev = fp->private_data; + u32 lsigs, rsigs; + int ret; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + switch (cmd) { + case TIOCMGET: + ret = rpmsg_get_sigs(eptdev->ept, , ); + if (!ret) + ret = put_user(rsigs, (u32 *)arg); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + ret = rpmsg_eptdev_tiocmset(fp, cmd, arg); + break; + case RPMSG_DESTROY_EPT_IOCTL: + ret = rpmsg_eptdev_destroy(>dev, NULL); + default: + ret = -EINVAL; + } - return rpmsg_eptdev_destroy(>dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 5/5] rpmsg: glink: Convert the native signals to TIOCM
Native signals over SMEM transport are different from Linux TIOCM signals. Add a macro to convert signals when sent or received from clients. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 29 + 1 file changed, 29 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index ff8751b..3054c86 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -211,6 +212,11 @@ struct glink_channel { #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -998,6 +1004,18 @@ static int qcom_glink_handle_signals(struct qcom_glink *glink, } old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + channel->rsigs = signals; if (channel->ept.sig_cb) @@ -1387,6 +1405,17 @@ static int qcom_glink_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) channel->lsigs = sigs; + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + return qcom_glink_send_signals(glink, channel, sigs); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 5/5] rpmsg: glink: Convert the native signals to TIOCM
Native signals over SMEM transport are different from Linux TIOCM signals. Add a macro to convert signals when sent or received from clients. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 29 + 1 file changed, 29 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index ff8751b..3054c86 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -211,6 +212,11 @@ struct glink_channel { #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG BIT(31) +#define NATIVE_CTS_SIG BIT(30) +#define NATIVE_CD_SIG BIT(29) +#define NATIVE_RI_SIG BIT(28) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -998,6 +1004,18 @@ static int qcom_glink_handle_signals(struct qcom_glink *glink, } old = channel->rsigs; + + /* convert signals from NATIVE to TIOCM */ + if (signals & NATIVE_DTR_SIG) + signals |= TIOCM_DSR; + if (signals & NATIVE_CTS_SIG) + signals |= TIOCM_CTS; + if (signals & NATIVE_CD_SIG) + signals |= TIOCM_CD; + if (signals & NATIVE_RI_SIG) + signals |= TIOCM_RI; + signals &= 0x0fff; + channel->rsigs = signals; if (channel->ept.sig_cb) @@ -1387,6 +1405,17 @@ static int qcom_glink_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) channel->lsigs = sigs; + /* convert signals from TIOCM to NATIVE */ + sigs &= 0x0fff; + if (sigs & TIOCM_DTR) + sigs |= NATIVE_DTR_SIG; + if (sigs & TIOCM_RTS) + sigs |= NATIVE_CTS_SIG; + if (sigs & TIOCM_CD) + sigs |= NATIVE_CD_SIG; + if (sigs & TIOCM_RI) + sigs |= NATIVE_RI_SIG; + return qcom_glink_send_signals(glink, channel, sigs); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 0/5] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Arun Kumar Neelakantam (5): rpmsg: glink: Add GLINK signal support for RPMSG rpmsg: Add signal callback to rpmsg char device rpmsg: Add TIOCMGET/TIOCMSET ioctl support rpmsg: wakeup poll to notify signal update rpmsg: glink: Convert the native signals to TIOCM drivers/rpmsg/qcom_glink_native.c | 109 ++ drivers/rpmsg/rpmsg_char.c| 76 -- drivers/rpmsg/rpmsg_core.c| 41 ++ drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 25 + 5 files changed, 253 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/5] rpmsg: Add signal callback to rpmsg char device
Register a callback to get the signal notifications from rpmsg. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..86003d5 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -5,6 +5,7 @@ * Copyright (c) 2012, PetaLogix * Copyright (c) 2011, Texas Instruments, Inc. * Copyright (c) 2011, Google, Inc. + * Copyright (c) 2018, The Linux Foundation. * * Based on rpmsg performance statistics driver by Michal Simek, which in turn * was based on TI & Google OMX rpmsg driver. @@ -120,6 +121,12 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -136,6 +143,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 0/5] Add TIOCM Signals support for RPMSG char devices
Glink transport support signals to exchange state notification between local and remote side clients. Adding support to send/receive the signal command and notify the clients through callback and POLL notification. Arun Kumar Neelakantam (5): rpmsg: glink: Add GLINK signal support for RPMSG rpmsg: Add signal callback to rpmsg char device rpmsg: Add TIOCMGET/TIOCMSET ioctl support rpmsg: wakeup poll to notify signal update rpmsg: glink: Convert the native signals to TIOCM drivers/rpmsg/qcom_glink_native.c | 109 ++ drivers/rpmsg/rpmsg_char.c| 76 -- drivers/rpmsg/rpmsg_core.c| 41 ++ drivers/rpmsg/rpmsg_internal.h| 5 ++ include/linux/rpmsg.h | 25 + 5 files changed, 253 insertions(+), 3 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/5] rpmsg: Add signal callback to rpmsg char device
Register a callback to get the signal notifications from rpmsg. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a76b963..86003d5 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -5,6 +5,7 @@ * Copyright (c) 2012, PetaLogix * Copyright (c) 2011, Texas Instruments, Inc. * Copyright (c) 2011, Google, Inc. + * Copyright (c) 2018, The Linux Foundation. * * Based on rpmsg performance statistics driver by Michal Simek, which in turn * was based on TI & Google OMX rpmsg driver. @@ -120,6 +121,12 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_sigs_cb(struct rpmsg_device *rpdev, void *priv, +u32 old, u32 new) +{ + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -136,6 +143,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->sig_cb = rpmsg_sigs_cb; eptdev->ept = ept; filp->private_data = eptdev; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/5] rpmsg: glink: Add GLINK signal support for RPMSG
Add support to handle SMD signals to RPMSG over GLINK. SMD signals mimic serial protocol signals to notify of ports opening and closing. This change affects the rpmsg core, rpmsg char and glink drivers. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 80 +++ drivers/rpmsg/rpmsg_core.c| 41 drivers/rpmsg/rpmsg_internal.h| 5 +++ include/linux/rpmsg.h | 25 4 files changed, 151 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f6988fd..ff8751b 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2017, Linaro Ltd + * Copyright (c) 2018, The Linux Foundation. */ #include @@ -150,6 +151,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: Local side signals + * @rsigs: Remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +184,9 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,6 +207,7 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) @@ -954,6 +961,52 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + channel->rsigs = signals; + + if (channel->ept.sig_cb) + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1015,6 +1068,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); + break; default: dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd); ret = -EINVAL; @@ -1312,6 +1369,27 @@ static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len) return __qcom_glink_send(channel, data, len, false); } +static int qcom_glink_get_sigs(struct rpmsg_endpoint *ept, + u32 *lsigs, u32 *rsigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + + *lsigs = channel->lsigs; + *rsigs = channel->rsigs; + + return 0; +} + +static int qcom_glink_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + struct qcom_glink *glink = channel->glink; + + channel->lsigs = sigs; + + return qcom_glink_send_signals(glink, channel, sigs); +} + /* * Finds the device_node for the glink chi
[PATCH 1/5] rpmsg: glink: Add GLINK signal support for RPMSG
Add support to handle SMD signals to RPMSG over GLINK. SMD signals mimic serial protocol signals to notify of ports opening and closing. This change affects the rpmsg core, rpmsg char and glink drivers. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 80 +++ drivers/rpmsg/rpmsg_core.c| 41 drivers/rpmsg/rpmsg_internal.h| 5 +++ include/linux/rpmsg.h | 25 4 files changed, 151 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f6988fd..ff8751b 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2017, Linaro Ltd + * Copyright (c) 2018, The Linux Foundation. */ #include @@ -150,6 +151,8 @@ enum { * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling + * @lsigs: Local side signals + * @rsigs: Remote side signals */ struct glink_channel { struct rpmsg_endpoint ept; @@ -181,6 +184,9 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + + unsigned int lsigs; + unsigned int rsigs; }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -201,6 +207,7 @@ struct glink_channel { #define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_RX_DONE_W_REUSE14 +#define RPM_CMD_SIGNALS15 #define GLINK_FEATURE_INTENTLESS BIT(1) @@ -954,6 +961,52 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_send_signals(struct qcom_glink *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, , sizeof(msg), NULL, 0, true); +} + +static int qcom_glink_handle_signals(struct qcom_glink *glink, +unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + channel->rsigs = signals; + + if (channel->ept.sig_cb) + channel->ept.sig_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->rsigs); + + return 0; +} + static irqreturn_t qcom_glink_native_intr(int irq, void *data) { struct qcom_glink *glink = data; @@ -1015,6 +1068,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case RPM_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); + break; default: dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd); ret = -EINVAL; @@ -1312,6 +1369,27 @@ static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len) return __qcom_glink_send(channel, data, len, false); } +static int qcom_glink_get_sigs(struct rpmsg_endpoint *ept, + u32 *lsigs, u32 *rsigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + + *lsigs = channel->lsigs; + *rsigs = channel->rsigs; + + return 0; +} + +static int qcom_glink_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + struct qcom_glink *glink = channel->glink; + + channel->lsigs = sigs; + + return qcom_glink_send_signals(glink, channel, sigs); +} + /* * Finds the device_node for the glink chi
[PATCH V4 8/9] rpmsg: glink: unregister rpmsg device during endpoint destroy
Rpmsg device unregister is not happening if channel close is triggered from local side and causing re-registration of device failures. Unregister rpmsg device for local close in endpoint destroy path. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 484b427..d849bc4 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1184,6 +1184,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(>recv_lock, flags); @@ -1191,6 +1192,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(>recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { + strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, ); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); @@ -1456,6 +1464,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) rpmsg_unregister_device(glink->dev, ); } + channel->rpdev = NULL; qcom_glink_send_close_ack(glink, channel->rcid); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 8/9] rpmsg: glink: unregister rpmsg device during endpoint destroy
Rpmsg device unregister is not happening if channel close is triggered from local side and causing re-registration of device failures. Unregister rpmsg device for local close in endpoint destroy path. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 484b427..d849bc4 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1184,6 +1184,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) { struct glink_channel *channel = to_glink_channel(ept); struct qcom_glink *glink = channel->glink; + struct rpmsg_channel_info chinfo; unsigned long flags; spin_lock_irqsave(>recv_lock, flags); @@ -1191,6 +1192,13 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept) spin_unlock_irqrestore(>recv_lock, flags); /* Decouple the potential rpdev from the channel */ + if (channel->rpdev) { + strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, ); + } channel->rpdev = NULL; qcom_glink_send_close_req(glink, channel); @@ -1456,6 +1464,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) rpmsg_unregister_device(glink->dev, ); } + channel->rpdev = NULL; qcom_glink_send_close_ack(glink, channel->rcid); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 9/9] rpmsg: Add compat ioctl for rpmsg char driver
Add compat ioctl callback to support 32bit user space applications. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 76a4477..a76b963 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -285,6 +285,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, .write = rpmsg_eptdev_write, .poll = rpmsg_eptdev_poll, .unlocked_ioctl = rpmsg_eptdev_ioctl, + .compat_ioctl = rpmsg_eptdev_ioctl, }; static ssize_t name_show(struct device *dev, struct device_attribute *attr, @@ -445,6 +446,7 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd, .open = rpmsg_ctrldev_open, .release = rpmsg_ctrldev_release, .unlocked_ioctl = rpmsg_ctrldev_ioctl, + .compat_ioctl = rpmsg_ctrldev_ioctl, }; static void rpmsg_ctrldev_release_device(struct device *dev) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 3/9] rpmsg: glink: Use complete_all for open states
From: Chris Lew The open_req and open_ack completion variables are the state variables to represet a remote channel as open. Use complete_all so there are no races with waiters and using completion_done. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 22a3cac..f43341d 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -949,7 +949,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return -EINVAL; } - complete(>open_ack); + complete_all(>open_ack); return 0; } @@ -1393,7 +1393,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, channel->rcid = ret; spin_unlock_irqrestore(>idr_lock, flags); - complete(>open_req); + complete_all(>open_req); if (create_device) { rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 9/9] rpmsg: Add compat ioctl for rpmsg char driver
Add compat ioctl callback to support 32bit user space applications. Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_char.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 76a4477..a76b963 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -285,6 +285,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, .write = rpmsg_eptdev_write, .poll = rpmsg_eptdev_poll, .unlocked_ioctl = rpmsg_eptdev_ioctl, + .compat_ioctl = rpmsg_eptdev_ioctl, }; static ssize_t name_show(struct device *dev, struct device_attribute *attr, @@ -445,6 +446,7 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd, .open = rpmsg_ctrldev_open, .release = rpmsg_ctrldev_release, .unlocked_ioctl = rpmsg_ctrldev_ioctl, + .compat_ioctl = rpmsg_ctrldev_ioctl, }; static void rpmsg_ctrldev_release_device(struct device *dev) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 3/9] rpmsg: glink: Use complete_all for open states
From: Chris Lew The open_req and open_ack completion variables are the state variables to represet a remote channel as open. Use complete_all so there are no races with waiters and using completion_done. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 22a3cac..f43341d 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -949,7 +949,7 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return -EINVAL; } - complete(>open_ack); + complete_all(>open_ack); return 0; } @@ -1393,7 +1393,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, channel->rcid = ret; spin_unlock_irqrestore(>idr_lock, flags); - complete(>open_req); + complete_all(>open_req); if (create_device) { rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 6/9] rpmsg: glink: Expose rpmsg name attr for glink
From: Chris Lew Expose the name field as an attr so clients listening to uevents for rpmsg can identify the edge the events correspond to. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 26 ++ 1 file changed, 26 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 9f3d026..7b4ffa0 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1544,6 +1544,26 @@ static void qcom_glink_work(struct work_struct *work) } } +static ssize_t rpmsg_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + const char *name; + + ret = of_property_read_string(dev->of_node, "label", ); + if (ret < 0) + name = dev->of_node->name; + + return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name); +} +static DEVICE_ATTR_RO(rpmsg_name); + +static struct attribute *qcom_glink_attrs[] = { + _attr_rpmsg_name.attr, + NULL +}; +ATTRIBUTE_GROUPS(qcom_glink); + static void qcom_glink_device_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); @@ -1593,6 +1613,12 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, return ERR_PTR(-ENOMEM); glink->dev = dev; + glink->dev->groups = qcom_glink_groups; + + ret = device_add_groups(dev, qcom_glink_groups); + if (ret) + dev_err(dev, "failed to add groups\n"); + glink->tx_pipe = tx; glink->rx_pipe = rx; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/9] rpmsg: glink: Store edge name for glink device
From: Chris Lew Channels may need to identify the edge their channel was probed for. Store the edge name by reading the label property from device tree or default to the node name. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f505f58..22a3cac 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -93,6 +93,8 @@ struct glink_core_rx_intent { struct qcom_glink { struct device *dev; + const char *name; + struct mbox_client mbox_client; struct mbox_chan *mbox_chan; @@ -1572,6 +1574,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, idr_init(>lcids); idr_init(>rcids); + ret = of_property_read_string(dev->of_node, "label", >name); + if (ret < 0) + glink->name = dev->of_node->name; + glink->mbox_client.dev = dev; glink->mbox_client.knows_txdone = true; glink->mbox_chan = mbox_request_channel(>mbox_client, 0); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 7/9] rpmsg: glink: Remove chunk size word align warning
From: Chris Lew It is possible for the chunk sizes coming from the non RPM remote procs to not be word aligned. Remove the alignment warning and continue to read from the FIFO so execution is not stalled. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 7b4ffa0..484b427 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -789,9 +789,6 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return -EAGAIN; } - if (WARN(chunk_size % 4, "Incoming data must be word aligned\n")) - return -EINVAL; - rcid = le16_to_cpu(hdr.msg.param1); spin_lock_irqsave(>idr_lock, flags); channel = idr_find(>rcids, rcid); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 6/9] rpmsg: glink: Expose rpmsg name attr for glink
From: Chris Lew Expose the name field as an attr so clients listening to uevents for rpmsg can identify the edge the events correspond to. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 26 ++ 1 file changed, 26 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 9f3d026..7b4ffa0 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1544,6 +1544,26 @@ static void qcom_glink_work(struct work_struct *work) } } +static ssize_t rpmsg_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + const char *name; + + ret = of_property_read_string(dev->of_node, "label", ); + if (ret < 0) + name = dev->of_node->name; + + return snprintf(buf, RPMSG_NAME_SIZE, "%s\n", name); +} +static DEVICE_ATTR_RO(rpmsg_name); + +static struct attribute *qcom_glink_attrs[] = { + _attr_rpmsg_name.attr, + NULL +}; +ATTRIBUTE_GROUPS(qcom_glink); + static void qcom_glink_device_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); @@ -1593,6 +1613,12 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, return ERR_PTR(-ENOMEM); glink->dev = dev; + glink->dev->groups = qcom_glink_groups; + + ret = device_add_groups(dev, qcom_glink_groups); + if (ret) + dev_err(dev, "failed to add groups\n"); + glink->tx_pipe = tx; glink->rx_pipe = rx; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/9] rpmsg: glink: Store edge name for glink device
From: Chris Lew Channels may need to identify the edge their channel was probed for. Store the edge name by reading the label property from device tree or default to the node name. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f505f58..22a3cac 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -93,6 +93,8 @@ struct glink_core_rx_intent { struct qcom_glink { struct device *dev; + const char *name; + struct mbox_client mbox_client; struct mbox_chan *mbox_chan; @@ -1572,6 +1574,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, idr_init(>lcids); idr_init(>rcids); + ret = of_property_read_string(dev->of_node, "label", >name); + if (ret < 0) + glink->name = dev->of_node->name; + glink->mbox_client.dev = dev; glink->mbox_client.knows_txdone = true; glink->mbox_chan = mbox_request_channel(>mbox_client, 0); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 7/9] rpmsg: glink: Remove chunk size word align warning
From: Chris Lew It is possible for the chunk sizes coming from the non RPM remote procs to not be word aligned. Remove the alignment warning and continue to read from the FIFO so execution is not stalled. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 7b4ffa0..484b427 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -789,9 +789,6 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return -EAGAIN; } - if (WARN(chunk_size % 4, "Incoming data must be word aligned\n")) - return -EINVAL; - rcid = le16_to_cpu(hdr.msg.param1); spin_lock_irqsave(>idr_lock, flags); channel = idr_find(>rcids, rcid); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 4/9] rpmsg: Guard against null endpoint ops in destroy
From: Chris Lew In RPMSG GLINK the chrdev device will allocate an ept as part of the rpdev creation. This device will not register endpoint ops even though it has an allocated ept. Protect against the case where the device is being destroyed. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index b714a54..0860328 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -80,7 +80,7 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - if (ept) + if (ept && ept->ops) ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 5/9] rpmsg: glink: Add support for rpmsg glink chrdev
From: Chris Lew RPMSG provides a char device interface to userspace. Probe the rpmsg chrdev channel to enable the rpmsg_ctrl device creation on glink transports. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 40 ++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f43341d..9f3d026 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1158,7 +1158,7 @@ static int qcom_glink_announce_create(struct rpmsg_device *rpdev) __be32 *val = defaults; int size; - if (glink->intentless) + if (glink->intentless || !completion_done(>open_ack)) return 0; prop = of_find_property(np, "qcom,intents", NULL); @@ -1544,6 +1544,40 @@ static void qcom_glink_work(struct work_struct *work) } } +static void qcom_glink_device_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_channel *channel = to_glink_channel(rpdev->ept); + + /* Release qcom_glink_alloc_channel() reference */ + kref_put(>refcount, qcom_glink_channel_release); + kfree(rpdev); +} + +static int qcom_glink_create_chrdev(struct qcom_glink *glink) +{ + struct rpmsg_device *rpdev; + struct glink_channel *channel; + + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + channel = qcom_glink_alloc_channel(glink, "rpmsg_chrdev"); + if (IS_ERR(channel)) { + kfree(rpdev); + return PTR_ERR(channel); + } + channel->rpdev = rpdev; + + rpdev->ept = >ept; + rpdev->ops = _device_ops; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = qcom_glink_device_release; + + return rpmsg_chrdev_register_device(rpdev); +} + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -1603,6 +1637,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (ret) return ERR_PTR(ret); + ret = qcom_glink_create_chrdev(glink); + if (ret) + dev_err(glink->dev, "failed to register chrdev\n"); + return glink; } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/9] dt-bindings: soc: qcom: Add label for GLINK bindings
From: Chris Lew There are GLINK clients who open the same channel on multiple GLINK links. These clients need a way to distinguish which remoteproc they are communicating to. Add a label property to identify the edge this node represents. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt | 5 + 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt index 9663cab..0b8cc53 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt @@ -10,6 +10,11 @@ edge. Value type: Definition: must be "qcom,glink-rpm" +- label: + Usage: optional + Value type: + Definition: should specify the subsystem name this edge corresponds to. + - interrupts: Usage: required Value type: -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 4/9] rpmsg: Guard against null endpoint ops in destroy
From: Chris Lew In RPMSG GLINK the chrdev device will allocate an ept as part of the rpdev creation. This device will not register endpoint ops even though it has an allocated ept. Protect against the case where the device is being destroyed. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index b714a54..0860328 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -80,7 +80,7 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - if (ept) + if (ept && ept->ops) ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 5/9] rpmsg: glink: Add support for rpmsg glink chrdev
From: Chris Lew RPMSG provides a char device interface to userspace. Probe the rpmsg chrdev channel to enable the rpmsg_ctrl device creation on glink transports. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 40 ++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index f43341d..9f3d026 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1158,7 +1158,7 @@ static int qcom_glink_announce_create(struct rpmsg_device *rpdev) __be32 *val = defaults; int size; - if (glink->intentless) + if (glink->intentless || !completion_done(>open_ack)) return 0; prop = of_find_property(np, "qcom,intents", NULL); @@ -1544,6 +1544,40 @@ static void qcom_glink_work(struct work_struct *work) } } +static void qcom_glink_device_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_channel *channel = to_glink_channel(rpdev->ept); + + /* Release qcom_glink_alloc_channel() reference */ + kref_put(>refcount, qcom_glink_channel_release); + kfree(rpdev); +} + +static int qcom_glink_create_chrdev(struct qcom_glink *glink) +{ + struct rpmsg_device *rpdev; + struct glink_channel *channel; + + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + channel = qcom_glink_alloc_channel(glink, "rpmsg_chrdev"); + if (IS_ERR(channel)) { + kfree(rpdev); + return PTR_ERR(channel); + } + channel->rpdev = rpdev; + + rpdev->ept = >ept; + rpdev->ops = _device_ops; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = qcom_glink_device_release; + + return rpmsg_chrdev_register_device(rpdev); +} + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -1603,6 +1637,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (ret) return ERR_PTR(ret); + ret = qcom_glink_create_chrdev(glink); + if (ret) + dev_err(glink->dev, "failed to register chrdev\n"); + return glink; } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/9] dt-bindings: soc: qcom: Add label for GLINK bindings
From: Chris Lew There are GLINK clients who open the same channel on multiple GLINK links. These clients need a way to distinguish which remoteproc they are communicating to. Add a label property to identify the edge this node represents. Signed-off-by: Chris Lew Signed-off-by: Arun Kumar Neelakantam --- Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt | 5 + 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt index 9663cab..0b8cc53 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt @@ -10,6 +10,11 @@ edge. Value type: Definition: must be "qcom,glink-rpm" +- label: + Usage: optional + Value type: + Definition: should specify the subsystem name this edge corresponds to. + - interrupts: Usage: required Value type: -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 0/9] Add chrdev and name query support for GLINK
Add support for the GLINK rpmsg transport to register a rpmsg chrdev. This will create the rpmsg_ctrl nodes for userspace clients to open rpmsg epts. Create a label property that will help userspace clients distinguish between the different GLINK links. The rpmsg chrdev allocation is done by allocating a local channel which also allocates an ept. We need to add some guards against edge cases for this chrdev because it will never fully open. Changes since v3: - Change to device_add_group for rpmsg name attr - Add patch to unregister the rpmsg device - Add patch to support compat ioctl for rpmsg char driver Changes since v2: - Revert change to make glink attribute table const Changes since v1: - Add explanation to dt-bindings commit message - Add patch complete_all the open_req/ack variables - Add patch to prevent null pointer dereference in chrdev channel release - Change chrdev allocation to use glink channel allocation - Change glink attr struct to const Arun Kumar Neelakantam (2): rpmsg: glink: unregister rpmsg device during endpoint destroy rpmsg: Add compat ioctl for rpmsg char driver Chris Lew (7): dt-bindings: soc: qcom: Add label for GLINK bindings rpmsg: glink: Store edge name for glink device rpmsg: glink: Use complete_all for open states rpmsg: Guard against null endpoint ops in destroy rpmsg: glink: Add support for rpmsg glink chrdev rpmsg: glink: Expose rpmsg name attr for glink rpmsg: glink: Remove chunk size word align warning .../devicetree/bindings/soc/qcom/qcom,glink.txt| 5 ++ drivers/rpmsg/qcom_glink_native.c | 88 -- drivers/rpmsg/rpmsg_char.c | 2 + drivers/rpmsg/rpmsg_core.c | 2 +- 4 files changed, 90 insertions(+), 7 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 0/9] Add chrdev and name query support for GLINK
Add support for the GLINK rpmsg transport to register a rpmsg chrdev. This will create the rpmsg_ctrl nodes for userspace clients to open rpmsg epts. Create a label property that will help userspace clients distinguish between the different GLINK links. The rpmsg chrdev allocation is done by allocating a local channel which also allocates an ept. We need to add some guards against edge cases for this chrdev because it will never fully open. Changes since v3: - Change to device_add_group for rpmsg name attr - Add patch to unregister the rpmsg device - Add patch to support compat ioctl for rpmsg char driver Changes since v2: - Revert change to make glink attribute table const Changes since v1: - Add explanation to dt-bindings commit message - Add patch complete_all the open_req/ack variables - Add patch to prevent null pointer dereference in chrdev channel release - Change chrdev allocation to use glink channel allocation - Change glink attr struct to const Arun Kumar Neelakantam (2): rpmsg: glink: unregister rpmsg device during endpoint destroy rpmsg: Add compat ioctl for rpmsg char driver Chris Lew (7): dt-bindings: soc: qcom: Add label for GLINK bindings rpmsg: glink: Store edge name for glink device rpmsg: glink: Use complete_all for open states rpmsg: Guard against null endpoint ops in destroy rpmsg: glink: Add support for rpmsg glink chrdev rpmsg: glink: Expose rpmsg name attr for glink rpmsg: glink: Remove chunk size word align warning .../devicetree/bindings/soc/qcom/qcom,glink.txt| 5 ++ drivers/rpmsg/qcom_glink_native.c | 88 -- drivers/rpmsg/rpmsg_char.c | 2 + drivers/rpmsg/rpmsg_core.c | 2 +- 4 files changed, 90 insertions(+), 7 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH] soc: qcom: smp2p: Access APCS as mailbox client
On 11/16/2017 12:48 PM, Bjorn Andersson wrote: Attempt to acquire the APCS IPC through the mailbox framework and fall back to the old syscon based approach, to allow us to move away from using the syscon. Signed-off-by: Bjorn Andersson--- drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/smp2p.c | 38 -- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b00bccddcd3b..e67d9534fca0 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -64,6 +64,7 @@ config QCOM_SMEM_STATE config QCOM_SMP2P tristate "Qualcomm Shared Memory Point to Point support" + depends on MAILBOX depends on QCOM_SMEM select QCOM_SMEM_STATE help diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index f51fb2ea7200..7fdbb64142a0 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,8 @@ struct smp2p_entry { * @ipc_regmap: regmap for the outbound ipc * @ipc_offset: offset within the regmap * @ipc_bit: bit in regmap@offset to kick to signal remote processor + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @inbound: list of inbound entries * @outbound: list of outbound entries */ @@ -146,6 +149,9 @@ struct qcom_smp2p { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head inbound; struct list_head outbound; }; @@ -154,7 +160,13 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) { /* Make sure any updated data is written before the kick */ wmb(); - regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + + if (smp2p->mbox_chan) { + mbox_send_message(smp2p->mbox_chan, NULL); + mbox_client_txdone(smp2p->mbox_chan, 0); + } else { + regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + } } /** @@ -453,10 +465,6 @@ static int qcom_smp2p_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smp2p); - ret = smp2p_parse_ipc(smp2p); - if (ret) - return ret; - key = "qcom,smem"; ret = of_property_read_u32_array(pdev->dev.of_node, key, smp2p->smem_items, 2); @@ -483,9 +491,22 @@ static int qcom_smp2p_probe(struct platform_device *pdev) return irq; } + smp2p->mbox_client.dev = >dev; + smp2p->mbox_chan = mbox_request_channel(>mbox_client, 0); any reason why we are not using "knows_txdone = true" for SMP2P but using for only SMD drivers + if (IS_ERR(smp2p->mbox_chan)) { + if (PTR_ERR(smp2p->mbox_chan) != -ENODEV) + return PTR_ERR(smp2p->mbox_chan); + + smp2p->mbox_chan = NULL; + + ret = smp2p_parse_ipc(smp2p); + if (ret) + return ret; + } + ret = qcom_smp2p_alloc_outbound_item(smp2p); if (ret < 0) - return ret; + goto release_mbox; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = devm_kzalloc(>dev, sizeof(*entry), GFP_KERNEL); @@ -540,6 +561,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev) smp2p->out->valid_entries = 0; +release_mbox: + mbox_free_channel(smp2p->mbox_chan); + return ret; } @@ -554,6 +578,8 @@ static int qcom_smp2p_remove(struct platform_device *pdev) list_for_each_entry(entry, >outbound, node) qcom_smem_state_unregister(entry->state); + mbox_free_channel(smp2p->mbox_chan); + smp2p->out->valid_entries = 0; return 0;
Re: [PATCH] soc: qcom: smp2p: Access APCS as mailbox client
On 11/16/2017 12:48 PM, Bjorn Andersson wrote: Attempt to acquire the APCS IPC through the mailbox framework and fall back to the old syscon based approach, to allow us to move away from using the syscon. Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/smp2p.c | 38 -- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b00bccddcd3b..e67d9534fca0 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -64,6 +64,7 @@ config QCOM_SMEM_STATE config QCOM_SMP2P tristate "Qualcomm Shared Memory Point to Point support" + depends on MAILBOX depends on QCOM_SMEM select QCOM_SMEM_STATE help diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index f51fb2ea7200..7fdbb64142a0 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,8 @@ struct smp2p_entry { * @ipc_regmap: regmap for the outbound ipc * @ipc_offset: offset within the regmap * @ipc_bit: bit in regmap@offset to kick to signal remote processor + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @inbound: list of inbound entries * @outbound: list of outbound entries */ @@ -146,6 +149,9 @@ struct qcom_smp2p { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head inbound; struct list_head outbound; }; @@ -154,7 +160,13 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) { /* Make sure any updated data is written before the kick */ wmb(); - regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + + if (smp2p->mbox_chan) { + mbox_send_message(smp2p->mbox_chan, NULL); + mbox_client_txdone(smp2p->mbox_chan, 0); + } else { + regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + } } /** @@ -453,10 +465,6 @@ static int qcom_smp2p_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smp2p); - ret = smp2p_parse_ipc(smp2p); - if (ret) - return ret; - key = "qcom,smem"; ret = of_property_read_u32_array(pdev->dev.of_node, key, smp2p->smem_items, 2); @@ -483,9 +491,22 @@ static int qcom_smp2p_probe(struct platform_device *pdev) return irq; } + smp2p->mbox_client.dev = >dev; + smp2p->mbox_chan = mbox_request_channel(>mbox_client, 0); any reason why we are not using "knows_txdone = true" for SMP2P but using for only SMD drivers + if (IS_ERR(smp2p->mbox_chan)) { + if (PTR_ERR(smp2p->mbox_chan) != -ENODEV) + return PTR_ERR(smp2p->mbox_chan); + + smp2p->mbox_chan = NULL; + + ret = smp2p_parse_ipc(smp2p); + if (ret) + return ret; + } + ret = qcom_smp2p_alloc_outbound_item(smp2p); if (ret < 0) - return ret; + goto release_mbox; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = devm_kzalloc(>dev, sizeof(*entry), GFP_KERNEL); @@ -540,6 +561,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev) smp2p->out->valid_entries = 0; +release_mbox: + mbox_free_channel(smp2p->mbox_chan); + return ret; } @@ -554,6 +578,8 @@ static int qcom_smp2p_remove(struct platform_device *pdev) list_for_each_entry(entry, >outbound, node) qcom_smem_state_unregister(entry->state); + mbox_free_channel(smp2p->mbox_chan); + smp2p->out->valid_entries = 0; return 0;
Re: [PATCH] rpmsg: qcom_smd: Access APCS through mailbox framework
On 11/16/2017 12:38 PM, Bjorn Andersson wrote: Attempt to acquire the APCS IPC through the mailbox framework and fall back to the old syscon based approach, to allow us to move away from using the syscon. Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org> Reviewed-by: Arun Kumar Neelakantam <ane...@codeaurora.org> --- drivers/rpmsg/qcom_smd.c | 62 +--- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index b01774e9fac0..ef2a526ebc8f 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -107,6 +108,8 @@ static const struct { * @ipc_regmap: regmap handle holding the outgoing ipc register * @ipc_offset: offset within @ipc_regmap of the register for ipc * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @channels: list of all channels detected on this edge * @channels_lock:guard for modifications of @channels * @allocated:array of bitmaps representing already allocated channels @@ -129,6 +132,9 @@ struct qcom_smd_edge { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head channels; spinlock_t channels_lock; @@ -365,7 +371,12 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel) { struct qcom_smd_edge *edge = channel->edge; - regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + if (edge->mbox_chan) { + mbox_send_message(edge->mbox_chan, NULL); + mbox_client_txdone(edge->mbox_chan, 0); + } else { + regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + } } /* @@ -1268,27 +1279,37 @@ static int qcom_smd_parse_edge(struct device *dev, key = "qcom,remote-pid"; of_property_read_u32(node, key, >remote_pid); - syscon_np = of_parse_phandle(node, "qcom,ipc", 0); - if (!syscon_np) { - dev_err(dev, "no qcom,ipc node\n"); - return -ENODEV; - } + edge->mbox_client.dev = dev; + edge->mbox_client.knows_txdone = true; + edge->mbox_chan = mbox_request_channel(>mbox_client, 0); + if (IS_ERR(edge->mbox_chan)) { + if (PTR_ERR(edge->mbox_chan) != -ENODEV) + return PTR_ERR(edge->mbox_chan); - edge->ipc_regmap = syscon_node_to_regmap(syscon_np); - if (IS_ERR(edge->ipc_regmap)) - return PTR_ERR(edge->ipc_regmap); + edge->mbox_chan = NULL; - key = "qcom,ipc"; - ret = of_property_read_u32_index(node, key, 1, >ipc_offset); - if (ret < 0) { - dev_err(dev, "no offset in %s\n", key); - return -EINVAL; - } + syscon_np = of_parse_phandle(node, "qcom,ipc", 0); + if (!syscon_np) { + dev_err(dev, "no qcom,ipc node\n"); + return -ENODEV; + } - ret = of_property_read_u32_index(node, key, 2, >ipc_bit); - if (ret < 0) { - dev_err(dev, "no bit in %s\n", key); - return -EINVAL; + edge->ipc_regmap = syscon_node_to_regmap(syscon_np); + if (IS_ERR(edge->ipc_regmap)) + return PTR_ERR(edge->ipc_regmap); + + key = "qcom,ipc"; + ret = of_property_read_u32_index(node, key, 1, >ipc_offset); + if (ret < 0) { + dev_err(dev, "no offset in %s\n", key); + return -EINVAL; + } + + ret = of_property_read_u32_index(node, key, 2, >ipc_bit); + if (ret < 0) { + dev_err(dev, "no bit in %s\n", key); + return -EINVAL; + } } ret = of_property_read_string(node, "label", >name); @@ -1394,6 +1415,8 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, return edge; unregister_dev: + if (!IS_ERR_OR_NULL(edge->mbox_chan)) + mbox_free_channel(edge->mbox_chan); put_device(>dev); return ERR_PTR(ret); } @@ -1422,6 +1445,7 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) if (ret) dev_warn(>dev, "can't remove smd device: %d\n", ret); + mbox_free_channel(edge->mbox_chan); device_unregister(>dev); return 0;
Re: [PATCH] rpmsg: qcom_smd: Access APCS through mailbox framework
On 11/16/2017 12:38 PM, Bjorn Andersson wrote: Attempt to acquire the APCS IPC through the mailbox framework and fall back to the old syscon based approach, to allow us to move away from using the syscon. Signed-off-by: Bjorn Andersson Reviewed-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_smd.c | 62 +--- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index b01774e9fac0..ef2a526ebc8f 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -107,6 +108,8 @@ static const struct { * @ipc_regmap: regmap handle holding the outgoing ipc register * @ipc_offset: offset within @ipc_regmap of the register for ipc * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @channels: list of all channels detected on this edge * @channels_lock:guard for modifications of @channels * @allocated:array of bitmaps representing already allocated channels @@ -129,6 +132,9 @@ struct qcom_smd_edge { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head channels; spinlock_t channels_lock; @@ -365,7 +371,12 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel) { struct qcom_smd_edge *edge = channel->edge; - regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + if (edge->mbox_chan) { + mbox_send_message(edge->mbox_chan, NULL); + mbox_client_txdone(edge->mbox_chan, 0); + } else { + regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + } } /* @@ -1268,27 +1279,37 @@ static int qcom_smd_parse_edge(struct device *dev, key = "qcom,remote-pid"; of_property_read_u32(node, key, >remote_pid); - syscon_np = of_parse_phandle(node, "qcom,ipc", 0); - if (!syscon_np) { - dev_err(dev, "no qcom,ipc node\n"); - return -ENODEV; - } + edge->mbox_client.dev = dev; + edge->mbox_client.knows_txdone = true; + edge->mbox_chan = mbox_request_channel(>mbox_client, 0); + if (IS_ERR(edge->mbox_chan)) { + if (PTR_ERR(edge->mbox_chan) != -ENODEV) + return PTR_ERR(edge->mbox_chan); - edge->ipc_regmap = syscon_node_to_regmap(syscon_np); - if (IS_ERR(edge->ipc_regmap)) - return PTR_ERR(edge->ipc_regmap); + edge->mbox_chan = NULL; - key = "qcom,ipc"; - ret = of_property_read_u32_index(node, key, 1, >ipc_offset); - if (ret < 0) { - dev_err(dev, "no offset in %s\n", key); - return -EINVAL; - } + syscon_np = of_parse_phandle(node, "qcom,ipc", 0); + if (!syscon_np) { + dev_err(dev, "no qcom,ipc node\n"); + return -ENODEV; + } - ret = of_property_read_u32_index(node, key, 2, >ipc_bit); - if (ret < 0) { - dev_err(dev, "no bit in %s\n", key); - return -EINVAL; + edge->ipc_regmap = syscon_node_to_regmap(syscon_np); + if (IS_ERR(edge->ipc_regmap)) + return PTR_ERR(edge->ipc_regmap); + + key = "qcom,ipc"; + ret = of_property_read_u32_index(node, key, 1, >ipc_offset); + if (ret < 0) { + dev_err(dev, "no offset in %s\n", key); + return -EINVAL; + } + + ret = of_property_read_u32_index(node, key, 2, >ipc_bit); + if (ret < 0) { + dev_err(dev, "no bit in %s\n", key); + return -EINVAL; + } } ret = of_property_read_string(node, "label", >name); @@ -1394,6 +1415,8 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, return edge; unregister_dev: + if (!IS_ERR_OR_NULL(edge->mbox_chan)) + mbox_free_channel(edge->mbox_chan); put_device(>dev); return ERR_PTR(ret); } @@ -1422,6 +1445,7 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) if (ret) dev_warn(>dev, "can't remove smd device: %d\n", ret); + mbox_free_channel(edge->mbox_chan); device_unregister(>dev); return 0;
Re: [PATCH v2 2/5] soc: qcom: Introduce QMI helpers
On 11/7/2017 10:50 AM, Bjorn Andersson wrote: Drivers that needs to communicate with a remote QMI service all has to perform the operations of discovering the service, encoding and decoding the messages and operate the socket. This introduces an abstraction for these common operations, reducing most of the duplication in such cases. Signed-off-by: Bjorn Andersson--- Changes since v1: - Squashed notion of qmi vs qrtr in interface, to simplify client code - Lookup and service registration is cached and handled by core on ENETRESET - Introduce callbacks for BYE and DEL_CLIENT control messages - Revisited locking for socket and transaction objects, squashed a few races and made it possible to send "indication" messages from message handlers. - kerneldoc updates - Moved handling of net_reset from clients to this code, greatly simplifies typical drivers and reduces duplication - Pass transaction id of QMI message to handlers even though it's not a response, allows sending a response with the txn id of an incoming request. - Split qmi_send_message() in three, instead of passing type as parameter - to clean up handling of "indication" messages. drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/Makefile| 1 + drivers/soc/qcom/qmi_interface.c | 849 +++ include/linux/soc/qcom/qmi.h | 157 4 files changed, 1008 insertions(+) create mode 100644 drivers/soc/qcom/qmi_interface.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 91b70b170a82..9718f1c41e3d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -37,6 +37,7 @@ config QCOM_PM config QCOM_QMI_HELPERS tristate + depends on ARCH_QCOM I feel It should depend on QRTR instead of ARCH_QCOM help Helper library for handling QMI encoded messages. QMI encoded messages are used in communication between the majority of QRTR diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 625750acfeef..b04b5044775f 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_QMI_HELPERS)+= qmi_helpers.o qmi_helpers-y += qmi_encdec.o +qmi_helpers-y += qmi_interface.o obj-$(CONFIG_QCOM_SMD_RPM)+= smd-rpm.o obj-$(CONFIG_QCOM_SMEM) +=smem.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c new file mode 100644 index ..d7885f9b072b --- /dev/null +++ b/drivers/soc/qcom/qmi_interface.c @@ -0,0 +1,849 @@ +/* + * Copyright (C) 2017 Linaro Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +static struct socket *qmi_sock_create(struct qmi_handle *qmi, + struct sockaddr_qrtr *sq); + +/** + * qmi_recv_new_server() - handler of NEW_SERVER control message + * @qmi: qmi handle + * @node: node of the new server + * @port: port of the new server + * + * Calls the new_server callback to inform the client about a newly registered + * server matching the currently registered service lookup. + */ +static void qmi_recv_new_server(struct qmi_handle *qmi, + unsigned int service, unsigned int instance, + unsigned int node, unsigned int port) +{ + struct qmi_ops *ops = >ops; + struct qmi_service *svc; + int ret; + + if (!ops->new_server) + return; + + /* Ignore EOF marker */ + if (!node && !port) + return; + + svc = kzalloc(sizeof(*svc), GFP_KERNEL); + if (!svc) + return; + + svc->service = service; + svc->version = instance & 0xff; + svc->instance = instance >> 8; + svc->node = node; + svc->port = port; + + ret = ops->new_server(qmi, svc); + if (ret < 0) + kfree(svc); + else + list_add(>list_node, >lookup_results); +} + +/** + * qmi_recv_del_server() - handler of DEL_SERVER control message + * @qmi: qmi handle + * @node: node of the dying server, a value of -1 matches all nodes + * @port: port of the dying server, a value of -1 matches all ports + * + * Calls the del_server callback for
Re: [PATCH v2 2/5] soc: qcom: Introduce QMI helpers
On 11/7/2017 10:50 AM, Bjorn Andersson wrote: Drivers that needs to communicate with a remote QMI service all has to perform the operations of discovering the service, encoding and decoding the messages and operate the socket. This introduces an abstraction for these common operations, reducing most of the duplication in such cases. Signed-off-by: Bjorn Andersson --- Changes since v1: - Squashed notion of qmi vs qrtr in interface, to simplify client code - Lookup and service registration is cached and handled by core on ENETRESET - Introduce callbacks for BYE and DEL_CLIENT control messages - Revisited locking for socket and transaction objects, squashed a few races and made it possible to send "indication" messages from message handlers. - kerneldoc updates - Moved handling of net_reset from clients to this code, greatly simplifies typical drivers and reduces duplication - Pass transaction id of QMI message to handlers even though it's not a response, allows sending a response with the txn id of an incoming request. - Split qmi_send_message() in three, instead of passing type as parameter - to clean up handling of "indication" messages. drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/Makefile| 1 + drivers/soc/qcom/qmi_interface.c | 849 +++ include/linux/soc/qcom/qmi.h | 157 4 files changed, 1008 insertions(+) create mode 100644 drivers/soc/qcom/qmi_interface.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 91b70b170a82..9718f1c41e3d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -37,6 +37,7 @@ config QCOM_PM config QCOM_QMI_HELPERS tristate + depends on ARCH_QCOM I feel It should depend on QRTR instead of ARCH_QCOM help Helper library for handling QMI encoded messages. QMI encoded messages are used in communication between the majority of QRTR diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 625750acfeef..b04b5044775f 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_QMI_HELPERS)+= qmi_helpers.o qmi_helpers-y += qmi_encdec.o +qmi_helpers-y += qmi_interface.o obj-$(CONFIG_QCOM_SMD_RPM)+= smd-rpm.o obj-$(CONFIG_QCOM_SMEM) +=smem.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c new file mode 100644 index ..d7885f9b072b --- /dev/null +++ b/drivers/soc/qcom/qmi_interface.c @@ -0,0 +1,849 @@ +/* + * Copyright (C) 2017 Linaro Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +static struct socket *qmi_sock_create(struct qmi_handle *qmi, + struct sockaddr_qrtr *sq); + +/** + * qmi_recv_new_server() - handler of NEW_SERVER control message + * @qmi: qmi handle + * @node: node of the new server + * @port: port of the new server + * + * Calls the new_server callback to inform the client about a newly registered + * server matching the currently registered service lookup. + */ +static void qmi_recv_new_server(struct qmi_handle *qmi, + unsigned int service, unsigned int instance, + unsigned int node, unsigned int port) +{ + struct qmi_ops *ops = >ops; + struct qmi_service *svc; + int ret; + + if (!ops->new_server) + return; + + /* Ignore EOF marker */ + if (!node && !port) + return; + + svc = kzalloc(sizeof(*svc), GFP_KERNEL); + if (!svc) + return; + + svc->service = service; + svc->version = instance & 0xff; + svc->instance = instance >> 8; + svc->node = node; + svc->port = port; + + ret = ops->new_server(qmi, svc); + if (ret < 0) + kfree(svc); + else + list_add(>list_node, >lookup_results); +} + +/** + * qmi_recv_del_server() - handler of DEL_SERVER control message + * @qmi: qmi handle + * @node: node of the dying server, a value of -1 matches all nodes + * @port: port of the dying server, a value of -1 matches all ports + * + * Calls the del_server callback for each previously seen server,
[PATCH V1] rpmsg: glink: Initialize the "intent_req_comp" completion variable
The "intent_req_comp" variable is used without initialization which results in NULL pointer dereference in qcom_glink_request_intent(). we need to initialize the completion variable before using it. Fixes: 27b9c5b66b23 ("rpmsg: glink: Request for intents when unavailable") Signed-off-by: Arun Kumar Neelakantam <ane...@codeaurora.org> --- drivers/rpmsg/qcom_glink_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 5dcc9bf..fcd46ab 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(>open_req); init_completion(>open_ack); + init_completion(>intent_req_comp); INIT_LIST_HEAD(>done_intents); INIT_WORK(>intent_work, qcom_glink_rx_done_work); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1] rpmsg: glink: Initialize the "intent_req_comp" completion variable
The "intent_req_comp" variable is used without initialization which results in NULL pointer dereference in qcom_glink_request_intent(). we need to initialize the completion variable before using it. Fixes: 27b9c5b66b23 ("rpmsg: glink: Request for intents when unavailable") Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 5dcc9bf..fcd46ab 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(>open_req); init_completion(>open_ack); + init_completion(>intent_req_comp); INIT_LIST_HEAD(>done_intents); INIT_WORK(>intent_work, qcom_glink_rx_done_work); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] rpmsg: glink: Initialize the "intent_req_comp" completion variable
The "intent_req_comp" variable is used without initialization which results in NULL pointer derefernce in qcom_glink_request_intent(). we need to initialize the completion variable before using it. Fixes: 27b9c5b66b23 ("rpmsg: glink: Request for intents when unavailable") Signed-off-by: Arun Kumar Neelakantam <ane...@codeaurora.org> --- drivers/rpmsg/qcom_glink_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 5dcc9bf..fcd46ab 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(>open_req); init_completion(>open_ack); + init_completion(>intent_req_comp); INIT_LIST_HEAD(>done_intents); INIT_WORK(>intent_work, qcom_glink_rx_done_work); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] rpmsg: glink: Initialize the "intent_req_comp" completion variable
The "intent_req_comp" variable is used without initialization which results in NULL pointer derefernce in qcom_glink_request_intent(). we need to initialize the completion variable before using it. Fixes: 27b9c5b66b23 ("rpmsg: glink: Request for intents when unavailable") Signed-off-by: Arun Kumar Neelakantam --- drivers/rpmsg/qcom_glink_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 5dcc9bf..fcd46ab 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(>open_req); init_completion(>open_ack); + init_completion(>intent_req_comp); INIT_LIST_HEAD(>done_intents); INIT_WORK(>intent_work, qcom_glink_rx_done_work); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v2 17/20] rpmsg: glink: Receive and store the remote intent buffers
On 8/24/2017 12:51 PM, Sricharan R wrote: Just like we allocating and sending intent ids to remote, remote side allocates and sends us the intents as well. So save the intent ids and use it later while sending data targeting the appropriate intents based on the size. Signed-off-by: Sricharan R <sricha...@codeaurora.org> Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org> Acked-by: Arun Kumar Neelakantam <ane...@codeaurora.org> Regards, Arun N --- drivers/rpmsg/qcom_glink_native.c | 71 ++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 76ee86e..d93d651 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -139,8 +139,9 @@ enum { * @name: unique channel name/identifier * @lcid: channel id, in local space * @rcid: channel id, in remote space - * @intent_lock: lock for protection of @liids + * @intent_lock: lock for protection of @liids, @riids * @liids:idr of all local intents + * @riids: idr of all remote intents * @intent_work: worker responsible for transmitting rx_done packets * @done_intents: list of intents that needs to be announced rx_done * @buf: receive buffer, for gathering fragments @@ -165,6 +166,7 @@ struct glink_channel { spinlock_t intent_lock; struct idr liids; + struct idr riids; struct work_struct intent_work; struct list_head done_intents; @@ -222,6 +224,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, INIT_WORK(>intent_work, qcom_glink_rx_done_work); idr_init(>liids); + idr_init(>riids); kref_init(>refcount); return channel; @@ -235,6 +238,7 @@ static void qcom_glink_channel_release(struct kref *ref) spin_lock_irqsave(>intent_lock, flags); idr_destroy(>liids); + idr_destroy(>riids); spin_unlock_irqrestore(>intent_lock, flags); kfree(channel->name); @@ -806,6 +810,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return ret; } +static void qcom_glink_handle_intent(struct qcom_glink *glink, +unsigned int cid, +unsigned int count, +size_t avail) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + struct intent_pair { + __le32 size; + __le32 iid; + }; + + struct { + struct glink_msg msg; + struct intent_pair intents[]; + } __packed * msg; + + const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count; + int ret; + int i; + unsigned long flags; + + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return; + } + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, cid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "intents for non-existing channel\n"); + return; + } + + msg = kmalloc(msglen, GFP_ATOMIC); + if (!msg) + return; + + qcom_glink_rx_peak(glink, msg, 0, msglen); + + for (i = 0; i < count; ++i) { + intent = kzalloc(sizeof(*intent), GFP_ATOMIC); + if (!intent) + break; + + intent->id = le32_to_cpu(msg->intents[i].iid); + intent->size = le32_to_cpu(msg->intents[i].size); + + spin_lock_irqsave(>intent_lock, flags); + ret = idr_alloc(>riids, intent, + intent->id, intent->id + 1, GFP_ATOMIC); + spin_unlock_irqrestore(>intent_lock, flags); + + if (ret < 0) + dev_err(glink->dev, "failed to store remote intent\n"); + } + + kfree(msg); + qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); +} + static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) { struct glink_channel *channel; @@ -871,6 +937,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) ret = 0; break; + case RPM_CMD_INTENT: + qcom_glink_handle_intent(glink, param1, param2, avail); + break; default: qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
Re: [PATCH v2 17/20] rpmsg: glink: Receive and store the remote intent buffers
On 8/24/2017 12:51 PM, Sricharan R wrote: Just like we allocating and sending intent ids to remote, remote side allocates and sends us the intents as well. So save the intent ids and use it later while sending data targeting the appropriate intents based on the size. Signed-off-by: Sricharan R Signed-off-by: Bjorn Andersson Acked-by: Arun Kumar Neelakantam Regards, Arun N --- drivers/rpmsg/qcom_glink_native.c | 71 ++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 76ee86e..d93d651 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -139,8 +139,9 @@ enum { * @name: unique channel name/identifier * @lcid: channel id, in local space * @rcid: channel id, in remote space - * @intent_lock: lock for protection of @liids + * @intent_lock: lock for protection of @liids, @riids * @liids:idr of all local intents + * @riids: idr of all remote intents * @intent_work: worker responsible for transmitting rx_done packets * @done_intents: list of intents that needs to be announced rx_done * @buf: receive buffer, for gathering fragments @@ -165,6 +166,7 @@ struct glink_channel { spinlock_t intent_lock; struct idr liids; + struct idr riids; struct work_struct intent_work; struct list_head done_intents; @@ -222,6 +224,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, INIT_WORK(>intent_work, qcom_glink_rx_done_work); idr_init(>liids); + idr_init(>riids); kref_init(>refcount); return channel; @@ -235,6 +238,7 @@ static void qcom_glink_channel_release(struct kref *ref) spin_lock_irqsave(>intent_lock, flags); idr_destroy(>liids); + idr_destroy(>riids); spin_unlock_irqrestore(>intent_lock, flags); kfree(channel->name); @@ -806,6 +810,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return ret; } +static void qcom_glink_handle_intent(struct qcom_glink *glink, +unsigned int cid, +unsigned int count, +size_t avail) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + struct intent_pair { + __le32 size; + __le32 iid; + }; + + struct { + struct glink_msg msg; + struct intent_pair intents[]; + } __packed * msg; + + const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count; + int ret; + int i; + unsigned long flags; + + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return; + } + + spin_lock_irqsave(>idr_lock, flags); + channel = idr_find(>rcids, cid); + spin_unlock_irqrestore(>idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "intents for non-existing channel\n"); + return; + } + + msg = kmalloc(msglen, GFP_ATOMIC); + if (!msg) + return; + + qcom_glink_rx_peak(glink, msg, 0, msglen); + + for (i = 0; i < count; ++i) { + intent = kzalloc(sizeof(*intent), GFP_ATOMIC); + if (!intent) + break; + + intent->id = le32_to_cpu(msg->intents[i].iid); + intent->size = le32_to_cpu(msg->intents[i].size); + + spin_lock_irqsave(>intent_lock, flags); + ret = idr_alloc(>riids, intent, + intent->id, intent->id + 1, GFP_ATOMIC); + spin_unlock_irqrestore(>intent_lock, flags); + + if (ret < 0) + dev_err(glink->dev, "failed to store remote intent\n"); + } + + kfree(msg); + qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); +} + static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) { struct glink_channel *channel; @@ -871,6 +937,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) ret = 0; break; + case RPM_CMD_INTENT: + qcom_glink_handle_intent(glink, param1, param2, avail); + break; default: qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
Re: [PATCH v2 11/20] rpmsg: glink: Fix idr_lock from mutex to spinlock
On 8/24/2017 12:51 PM, Sricharan R wrote: The channel members lcids, rcids synchronised using the idr_lock is accessed in both atomic/non-atomic contexts. The readers are not currently synchronised. That no correct, so add the readers as well under the lock and use a spinlock. Signed-off-by: Sricharan R <sricha...@codeaurora.org> Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org> Acked-by: Arun Kumar Neelakantam <ane...@codeaurora.org> Regards, Arun N --- drivers/rpmsg/qcom_glink_native.c | 58 +++ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 777ac6b..588a56c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -92,7 +92,7 @@ struct qcom_glink { struct mutex tx_lock; - struct mutex idr_lock; + spinlock_t idr_lock; struct idr lcids; struct idr rcids; unsigned long features; @@ -309,14 +309,15 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink, int name_len = strlen(channel->name) + 1; int req_len = ALIGN(sizeof(req.msg) + name_len, 8); int ret; + unsigned long flags; kref_get(>refcount); - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); ret = idr_alloc_cyclic(>lcids, channel, RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX, GFP_KERNEL); - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); if (ret < 0) return ret; @@ -334,10 +335,10 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink, return 0; remove_idr: - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); idr_remove(>lcids, channel->lcid); channel->lcid = 0; - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); return ret; } @@ -463,6 +464,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) unsigned int chunk_size; unsigned int left_size; unsigned int rcid; + unsigned long flags; if (avail < sizeof(hdr)) { dev_dbg(glink->dev, "Not enough data in fifo\n"); @@ -482,7 +484,9 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return -EINVAL; rcid = le16_to_cpu(hdr.msg.param1); + spin_lock_irqsave(>idr_lock, flags); channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); if (!channel) { dev_dbg(glink->dev, "Data on non-existing channel\n"); @@ -543,11 +547,13 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) { struct glink_channel *channel; + spin_lock(>idr_lock); channel = idr_find(>lcids, lcid); if (!channel) { dev_err(glink->dev, "Invalid open ack packet\n"); return -EINVAL; } + spin_unlock(>idr_lock); complete(>open_ack); @@ -621,6 +627,7 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink, { struct glink_channel *channel; int ret; + unsigned long flags; channel = qcom_glink_alloc_channel(glink, name); if (IS_ERR(channel)) @@ -644,9 +651,9 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink, err_timeout: /* qcom_glink_send_open_req() did register the channel in lcids*/ - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); idr_remove(>lcids, channel->lcid); - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); release_channel: /* Release qcom_glink_send_open_req() reference */ @@ -703,11 +710,14 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev, const char *name = chinfo.name; int cid; int ret; + unsigned long flags; + spin_lock_irqsave(>idr_lock, flags); idr_for_each_entry(>rcids, channel, cid) { if (!strcmp(channel->name, name)) break; } + spin_unlock_irqrestore(>idr_lock, flags); if (!channel) { channel = qcom_glink_create_local(glink, name); @@ -829,11 +839,14 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, struct device_node *node; int lcid; int ret; + unsigned long flags; + spin_lock_irqsave(>idr_lock, flags); idr_for_each_entry(>lcids, channel, lcid) { if (!strcmp(channel->name, name)) break; } + spin_unlock_irqr
Re: [PATCH v2 11/20] rpmsg: glink: Fix idr_lock from mutex to spinlock
On 8/24/2017 12:51 PM, Sricharan R wrote: The channel members lcids, rcids synchronised using the idr_lock is accessed in both atomic/non-atomic contexts. The readers are not currently synchronised. That no correct, so add the readers as well under the lock and use a spinlock. Signed-off-by: Sricharan R Signed-off-by: Bjorn Andersson Acked-by: Arun Kumar Neelakantam Regards, Arun N --- drivers/rpmsg/qcom_glink_native.c | 58 +++ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 777ac6b..588a56c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -92,7 +92,7 @@ struct qcom_glink { struct mutex tx_lock; - struct mutex idr_lock; + spinlock_t idr_lock; struct idr lcids; struct idr rcids; unsigned long features; @@ -309,14 +309,15 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink, int name_len = strlen(channel->name) + 1; int req_len = ALIGN(sizeof(req.msg) + name_len, 8); int ret; + unsigned long flags; kref_get(>refcount); - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); ret = idr_alloc_cyclic(>lcids, channel, RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX, GFP_KERNEL); - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); if (ret < 0) return ret; @@ -334,10 +335,10 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink, return 0; remove_idr: - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); idr_remove(>lcids, channel->lcid); channel->lcid = 0; - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); return ret; } @@ -463,6 +464,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) unsigned int chunk_size; unsigned int left_size; unsigned int rcid; + unsigned long flags; if (avail < sizeof(hdr)) { dev_dbg(glink->dev, "Not enough data in fifo\n"); @@ -482,7 +484,9 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) return -EINVAL; rcid = le16_to_cpu(hdr.msg.param1); + spin_lock_irqsave(>idr_lock, flags); channel = idr_find(>rcids, rcid); + spin_unlock_irqrestore(>idr_lock, flags); if (!channel) { dev_dbg(glink->dev, "Data on non-existing channel\n"); @@ -543,11 +547,13 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) { struct glink_channel *channel; + spin_lock(>idr_lock); channel = idr_find(>lcids, lcid); if (!channel) { dev_err(glink->dev, "Invalid open ack packet\n"); return -EINVAL; } + spin_unlock(>idr_lock); complete(>open_ack); @@ -621,6 +627,7 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink, { struct glink_channel *channel; int ret; + unsigned long flags; channel = qcom_glink_alloc_channel(glink, name); if (IS_ERR(channel)) @@ -644,9 +651,9 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink, err_timeout: /* qcom_glink_send_open_req() did register the channel in lcids*/ - mutex_lock(>idr_lock); + spin_lock_irqsave(>idr_lock, flags); idr_remove(>lcids, channel->lcid); - mutex_unlock(>idr_lock); + spin_unlock_irqrestore(>idr_lock, flags); release_channel: /* Release qcom_glink_send_open_req() reference */ @@ -703,11 +710,14 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev, const char *name = chinfo.name; int cid; int ret; + unsigned long flags; + spin_lock_irqsave(>idr_lock, flags); idr_for_each_entry(>rcids, channel, cid) { if (!strcmp(channel->name, name)) break; } + spin_unlock_irqrestore(>idr_lock, flags); if (!channel) { channel = qcom_glink_create_local(glink, name); @@ -829,11 +839,14 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, struct device_node *node; int lcid; int ret; + unsigned long flags; + spin_lock_irqsave(>idr_lock, flags); idr_for_each_entry(>lcids, channel, lcid) { if (!strcmp(channel->name, name)) break; } + spin_unlock_irqrestore(>idr_lock, flags); if (!channel) { channel = qcom_glink_alloc