diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index b854fdfd75b5..a717bc3061de 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -104,6 +104,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 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 99% rename from drivers/soc/qcom/glink_pkt.c rename to drivers/rpmsg/glink_pkt.c index e6c9c8dead71..1449fda27978 100644 --- a/drivers/soc/qcom/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 49898b18dce1..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, @@ -422,7 +436,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); @@ -642,6 +657,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 +669,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 +683,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); } /** @@ -1181,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; @@ -1261,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; @@ -1691,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 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