From 172a5750a16deabde6b74ec23d4e2e2bac86ba6d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 15:01:05 -0800 Subject: [PATCH] rpmsg: glink: Temporarily expose signals for glink Expose a direct interface for the signal interface from the glink transport. This is required for tethered data call functionality. This change should be reverted once the patch to add the signal interface into rpmsg is merged upstream. Change-Id: I1df466579352660a276312a304c9eac88f113c60 Signed-off-by: Chris Lew --- drivers/rpmsg/glink_pkt.c | 40 ++++---- drivers/rpmsg/qcom_glink_native.c | 153 ++++++++++++++++++++++++++++++ drivers/rpmsg/qcom_glink_native.h | 8 ++ 3 files changed, 182 insertions(+), 19 deletions(-) diff --git a/drivers/rpmsg/glink_pkt.c b/drivers/rpmsg/glink_pkt.c index e6c9c8dead71..1449fda27978 100644 --- a/drivers/rpmsg/glink_pkt.c +++ b/drivers/rpmsg/glink_pkt.c @@ -17,6 +17,8 @@ #include #include +#include "qcom_glink_native.h" + /* Define IPC Logging Macros */ #define GLINK_PKT_IPC_LOG_PAGE_CNT 2 static void *glink_pkt_ilctxt; @@ -132,22 +134,6 @@ static ssize_t open_timeout_show(struct device *dev, static DEVICE_ATTR_RW(open_timeout); -static int glink_pkt_rpdev_probe(struct rpmsg_device *rpdev) -{ - struct device_driver *drv = rpdev->dev.driver; - struct rpmsg_driver *rpdrv = drv_to_rpdrv(drv); - struct glink_pkt_device *gpdev = rpdrv_to_gpdev(rpdrv); - - mutex_lock(&gpdev->lock); - gpdev->rpdev = rpdev; - mutex_unlock(&gpdev->lock); - - dev_set_drvdata(&rpdev->dev, gpdev); - complete_all(&gpdev->ch_open); - - return 0; -} - static int glink_pkt_rpdev_cb(struct rpmsg_device *rpdev, void *buf, int len, void *priv, u32 addr) { @@ -194,6 +180,23 @@ static int glink_pkt_rpdev_sigs(struct rpmsg_device *rpdev, void *priv, return 0; } +static int glink_pkt_rpdev_probe(struct rpmsg_device *rpdev) +{ + struct device_driver *drv = rpdev->dev.driver; + struct rpmsg_driver *rpdrv = drv_to_rpdrv(drv); + struct glink_pkt_device *gpdev = rpdrv_to_gpdev(rpdrv); + + mutex_lock(&gpdev->lock); + gpdev->rpdev = rpdev; + qcom_glink_register_signals_cb(rpdev->ept, glink_pkt_rpdev_sigs); + mutex_unlock(&gpdev->lock); + + dev_set_drvdata(&rpdev->dev, gpdev); + complete_all(&gpdev->ch_open); + + return 0; +} + static void glink_pkt_rpdev_remove(struct rpmsg_device *rpdev) { struct device_driver *drv = rpdev->dev.driver; @@ -558,7 +561,7 @@ static int glink_pkt_tiocmset(struct glink_pkt_device *gpdev, unsigned int cmd, clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_CD | TIOCM_RI; GLINK_PKT_INFO("set[0x%x] clear[0x%x]\n", set, clear); - return rpmsg_set_signals(gpdev->rpdev->ept, set, clear); + return qcom_glink_set_signals(gpdev->rpdev->ept, set, clear); } /** @@ -598,7 +601,7 @@ static long glink_pkt_ioctl(struct file *file, unsigned int cmd, gpdev->sig_change = false; spin_unlock_irqrestore(&gpdev->queue_lock, flags); - ret = rpmsg_get_signals(gpdev->rpdev->ept); + ret = qcom_glink_get_signals(gpdev->rpdev->ept); if (ret >= 0) ret = put_user(ret, (int __user *)arg); break; @@ -727,7 +730,6 @@ static int glink_pkt_init_rpmsg(struct glink_pkt_device *gpdev) rpdrv->probe = glink_pkt_rpdev_probe; rpdrv->remove = glink_pkt_rpdev_remove; rpdrv->callback = glink_pkt_rpdev_cb; - rpdrv->signals = glink_pkt_rpdev_sigs; rpdrv->id_table = match; rpdrv->drv.name = drv_name; diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index d4457bb6e83c..c6bdb5162536 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "rpmsg_internal.h" @@ -200,6 +201,9 @@ enum { * @intent_req_completed: Status of intent request completion * @intent_req_ack: Waitqueue for @intent_req_acked * @intent_req_comp: Waitqueue for @intent_req_completed + * @local_signals: local side signals + * @remote_sigalss: remote side signals + * @signals_cb: client callback for notifying signal change */ struct glink_channel { struct rpmsg_endpoint ept; @@ -235,6 +239,10 @@ struct glink_channel { atomic_t intent_req_completed; wait_queue_head_t intent_req_ack; wait_queue_head_t intent_req_comp; + + unsigned int local_signals; + unsigned int remote_signals; + int (*signals_cb)(struct rpmsg_device *dev, void *priv, u32 old, u32 new); }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -255,9 +263,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_REUSE 14 +#define RPM_CMD_SIGNALS 15 #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 kthread_work *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -1183,6 +1197,77 @@ 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 + * @signals: 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 signals) +{ + struct glink_msg msg; + + /* convert signals from TIOCM to NATIVE */ + signals &= 0x0fff; + if (signals & TIOCM_DTR) + signals |= NATIVE_DTR_SIG; + if (signals & TIOCM_RTS) + signals |= NATIVE_CTS_SIG; + if (signals & TIOCM_CD) + signals |= NATIVE_CD_SIG; + if (signals & TIOCM_RI) + signals |= NATIVE_RI_SIG; + + msg.cmd = cpu_to_le16(RPM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(signals); + + GLINK_INFO(glink->ilc, "signals:%d\n", signals); + return qcom_glink_tx(glink, &msg, 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(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->remote_signals; + + /* 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->remote_signals = signals; + + CH_INFO(channel, "old:%d new:%d\n", old, channel->remote_signals); + if (channel->signals_cb) + channel->signals_cb(channel->ept.rpdev, channel->ept.priv, + old, channel->remote_signals); + + return 0; +} + static int qcom_glink_native_rx(struct qcom_glink *glink, int iterations) { struct glink_msg msg; @@ -1263,6 +1348,10 @@ static int qcom_glink_native_rx(struct qcom_glink *glink, int iterations) 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; @@ -1693,6 +1782,70 @@ static int qcom_glink_trysendto(struct rpmsg_endpoint *ept, void *data, int len, return __qcom_glink_send(channel, data, len, false); } +int qcom_glink_get_signals(struct rpmsg_endpoint *ept) +{ + struct glink_channel *channel; + + if (!ept) + return 0; + + channel = to_glink_channel(ept); + + return channel->remote_signals; +} +EXPORT_SYMBOL(qcom_glink_get_signals); + +int qcom_glink_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) +{ + struct glink_channel *channel; + struct qcom_glink *glink; + u32 signals; + + if (!ept) + return -EINVAL; + + channel = to_glink_channel(ept); + glink = channel->glink; + signals = channel->local_signals; + + if (set & TIOCM_DTR) + signals |= TIOCM_DTR; + if (set & TIOCM_RTS) + signals |= TIOCM_RTS; + if (set & TIOCM_CD) + signals |= TIOCM_CD; + if (set & TIOCM_RI) + signals |= TIOCM_RI; + if (clear & TIOCM_DTR) + signals &= ~TIOCM_DTR; + if (clear & TIOCM_RTS) + signals &= ~TIOCM_RTS; + if (clear & TIOCM_CD) + signals &= ~TIOCM_CD; + if (clear & TIOCM_RI) + signals &= ~TIOCM_RI; + + channel->local_signals = signals; + + return qcom_glink_send_signals(glink, channel, signals); +} +EXPORT_SYMBOL(qcom_glink_set_signals); + +int qcom_glink_register_signals_cb(struct rpmsg_endpoint *ept, + int (*cb)(struct rpmsg_device *, void *, u32, u32)) +{ + struct glink_channel *channel; + + if (!ept || !cb) + return -EINVAL; + + channel = to_glink_channel(ept); + channel->signals_cb = cb; + + return 0; +} +EXPORT_SYMBOL(qcom_glink_register_signals_cb); + /* * Finds the device_node for the glink child interested in this channel. */ diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h index a3be0f5cfaf4..aeb6a0bc0343 100644 --- a/drivers/rpmsg/qcom_glink_native.h +++ b/drivers/rpmsg/qcom_glink_native.h @@ -6,6 +6,8 @@ #ifndef __QCOM_GLINK_NATIVE_H__ #define __QCOM_GLINK_NATIVE_H__ +#include + #define GLINK_FEATURE_INTENT_REUSE BIT(0) #define GLINK_FEATURE_MIGRATION BIT(1) #define GLINK_FEATURE_TRACER_PKT BIT(2) @@ -38,4 +40,10 @@ int qcom_glink_native_start(struct qcom_glink *glink); void qcom_glink_native_remove(struct qcom_glink *glink); void qcom_glink_native_unregister(struct qcom_glink *glink); + +/* These operations are temporarily exposing signal interfaces */ +int qcom_glink_get_signals(struct rpmsg_endpoint *ept); +int qcom_glink_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear); +int qcom_glink_register_signals_cb(struct rpmsg_endpoint *ept, + int (*signals_cb)(struct rpmsg_device *dev, void *priv, u32 old, u32 new)); #endif