From 28149075f5e265145c8f406f9d574aa13f3c8b90 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 10:03:12 -0800 Subject: [PATCH 1/5] rpmsg: glink: Move glink packet driver Move the glink packet driver from soc/qcom to rpmsg. The RPMSG char driver is under rpmsg and the glink packet driver mirrors the RPMSG char driver. Change-Id: I4d1c5abbe656e4c54da74769067d35cd513f3b75 Signed-off-by: Chris Lew --- drivers/rpmsg/Kconfig | 9 +++++++++ drivers/rpmsg/Makefile | 1 + drivers/{soc/qcom => rpmsg}/glink_pkt.c | 0 drivers/soc/qcom/Kconfig | 9 --------- drivers/soc/qcom/Makefile | 1 - 5 files changed, 10 insertions(+), 10 deletions(-) rename drivers/{soc/qcom => rpmsg}/glink_pkt.c (100%) diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 8b408b418fa3..6e5b52251bae 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -76,6 +76,15 @@ config RPMSG_QCOM_GLINK_SPSS region with the remote proc by writing the smem descriptor location and size into shared registers. +config QCOM_GLINK_PKT + tristate "Enable device interface for GLINK packet channels" + depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SLATECOM + help + G-link packet driver provides the interface for the userspace + clients to communicate over G-Link via device nodes. + This enable the userspace clients to read and write to + some glink packets channel. + config RPMSG_QCOM_SMD tristate "Qualcomm Shared Memory Driver (SMD)" depends on MAILBOX diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index b5e6ab4f6eb9..5e2ac18f871c 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPSS) += qcom_glink_spss.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o +obj-$(CONFIG_QCOM_GLINK_PKT) += glink_pkt.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/soc/qcom/glink_pkt.c b/drivers/rpmsg/glink_pkt.c similarity index 100% rename from drivers/soc/qcom/glink_pkt.c rename to drivers/rpmsg/glink_pkt.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 069d4272d88f..6f1f69150cae 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -369,15 +369,6 @@ config QCOM_GLINK all the edges present in the device. Say M if you want to enable this module. -config QCOM_GLINK_PKT - tristate "Enable device interface for GLINK packet channels" - depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SLATECOM - help - G-link packet driver provides the interface for the userspace - clients to communicate over G-Link via device nodes. - This enable the userspace clients to read and write to - some glink packets channel. - config QTI_PMIC_GLINK tristate "Enable support for PMIC GLINK" depends on RPMSG diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 267df035ba26..4f4114464532 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SMP2P_SLEEPSTATE) += smp2p_sleepstate.o obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o obj-$(CONFIG_QCOM_GLINK) += glink_probe.o -obj-$(CONFIG_QCOM_GLINK_PKT) += glink_pkt.o obj-$(CONFIG_QTI_PMIC_GLINK) += pmic_glink.o obj-$(CONFIG_QTI_BATTERY_GLINK_DEBUG) += qti_battery_debug.o obj-$(CONFIG_QTI_CHARGER_ULOG_GLINK) += charger-ulog-glink.o From d19561af429aad0ba28a53d92f6bc03d1023a566 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 10:50:24 -0800 Subject: [PATCH 2/5] rpmsg: glink: Use irqsave/irqrestore spin locks The glink rx done function can be called from both soft irq and hard irq context. To avoid any potential deadlock scenarios, use the irq save and restore variants of the spin locks. Change-Id: Id85367226a16db1c0e44f8e00c7b7f74f4c8b8fd Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 49898b18dce1..8de9481c078a 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -642,6 +642,7 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, struct glink_channel *channel, struct glink_core_rx_intent *intent) { + unsigned long flags; int ret = -EAGAIN; /* We don't send RX_DONE to intentless systems */ @@ -653,13 +654,13 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, /* Take it off the tree of receive intents */ if (!intent->reuse) { - spin_lock(&channel->intent_lock); + spin_lock_irqsave(&channel->intent_lock, flags); idr_remove(&channel->liids, intent->id); - spin_unlock(&channel->intent_lock); + spin_unlock_irqrestore(&channel->intent_lock, flags); } /* Schedule the sending of a rx_done indication */ - spin_lock(&channel->intent_lock); + spin_lock_irqsave(&channel->intent_lock, flags); if (list_empty(&channel->done_intents)) ret = __qcom_glink_rx_done(glink, channel, intent, false); @@ -667,7 +668,7 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, list_add_tail(&intent->node, &channel->done_intents); kthread_queue_work(&glink->kworker, &channel->intent_work); } - spin_unlock(&channel->intent_lock); + spin_unlock_irqrestore(&channel->intent_lock, flags); } /** From da8adeaf3617ccd4a83fab6277ce30e3c229789f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 11:00:54 -0800 Subject: [PATCH 3/5] rpmsg: glink: Cancel sending on processor reset Unblock threads waiting for space in the smem fifo when the peer remote processor reset is detected. This will allow processes to unblock and cleanup instead of waiting for a 10 second timeout. Change-Id: I1a033a81424dd0c40dd4aa709c4fb9a89e2fa124 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 8de9481c078a..d4457bb6e83c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -422,7 +422,8 @@ static int qcom_glink_tx(struct qcom_glink *glink, spin_unlock_irqrestore(&glink->tx_lock, flags); wait_event_timeout(glink->tx_avail_notify, - qcom_glink_tx_avail(glink) >= tlen, 10 * HZ); + qcom_glink_tx_avail(glink) >= tlen || + atomic_read(&glink->in_reset), 10 * HZ); spin_lock_irqsave(&glink->tx_lock, flags); From 172a5750a16deabde6b74ec23d4e2e2bac86ba6d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 15:01:05 -0800 Subject: [PATCH 4/5] 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 From a0c597c83f63386da3fbec1c9be06da11741de3c Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 8 Nov 2022 15:23:15 -0800 Subject: [PATCH 5/5] defconfig: Enable glink pkt and probe for pineapple Enable the GLINK PKT and GLINK PROBE drivers to provide rpmsg glink access to userspace. Change-Id: I5d74241425cb935f33e8567abc33defbb4360da0 Signed-off-by: Chris Lew --- arch/arm64/configs/vendor/pineapple_GKI.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index c5903404597e..d68a2c6e0fad 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -103,6 +103,8 @@ CONFIG_QCOM_DMABUF_HEAPS_SYSTEM_SECURE=y CONFIG_QCOM_DMABUF_HEAPS_UBWCP=y CONFIG_QCOM_EUD=m CONFIG_QCOM_GDSC_REGULATOR=m +CONFIG_QCOM_GLINK=m +CONFIG_QCOM_GLINK_PKT=m CONFIG_QCOM_IOMMU_DEBUG=m CONFIG_QCOM_IOMMU_UTIL=m # CONFIG_QCOM_IPA is not set