Add samsung specific changes

This commit is contained in:
2025-08-11 14:29:00 +02:00
parent c66122e619
commit 4d134a1294
2688 changed files with 1127995 additions and 11475 deletions

View File

@@ -31,6 +31,16 @@ config RPMSG_NS
channel that probes the associated RPMsg device on remote endpoint
service announcement.
config MSM_RPM_SMD
tristate "RPM driver using SMD protocol"
select RPMSG
help
RPM is the dedicated hardware engine for managing shared SoC
resources. This config adds driver support for using SMD as a
transport layer communication with RPM hardware. It also selects
the MSM_MPM config that programs the MPM module to monitor interrupts
during sleep modes.
config RPMSG_MTK_SCP
tristate "MediaTek SCP"
depends on MTK_SCP
@@ -44,6 +54,15 @@ config RPMSG_QCOM_GLINK
tristate
select RPMSG
config RPMSG_QCOM_GLINK_DEBUG
bool "Qualcomm Technologies, Inc. Glink driver debug support"
depends on RPMSG_QCOM_GLINK
help
Say y here to enable GLINK debugging features. This currently includes
an assert in the intent timeout case to catch issues with unresponsive
remote processors. Future debug enhancements can be switched on and off
with this config.
config RPMSG_QCOM_GLINK_RPM
tristate "Qualcomm RPM Glink driver"
select RPMSG_QCOM_GLINK
@@ -64,6 +83,27 @@ config RPMSG_QCOM_GLINK_SMEM
which provides support for using the GLINK communication protocol
over SMEM.
config RPMSG_QCOM_GLINK_SPSS
tristate "QTI SPSS Glink driver"
select RPMSG_QCOM_GLINK_NATIVE
depends on MAILBOX
depends on QCOM_SMEM
help
Say y here to enable support for the GLINK SPSS communication driver,
which provides support for using the GLINK communication protocol
over SMEM. This protocol maps the smem and then shares the mapped
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

View File

@@ -5,8 +5,12 @@ obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o
obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o
qcom_glink-objs += qcom_glink_memshare.o
obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o
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
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o

1361
drivers/rpmsg/glink_pkt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/slab.h>
struct qcom_glink_mem_entry {
struct device *dev;
void *va;
dma_addr_t dma;
size_t len;
u32 da;
struct list_head node;
};
static DEFINE_SPINLOCK(qcom_glink_mem_entry_lock);
static LIST_HEAD(qcom_glink_mem_entries);
struct qcom_glink_mem_entry *
qcom_glink_mem_entry_init(struct device *dev, void *va, dma_addr_t dma, size_t len, u32 da)
{
struct qcom_glink_mem_entry *mem = NULL;
unsigned long flags;
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem)
return mem;
mem->dev = dev;
mem->va = va;
mem->dma = dma;
mem->da = da;
mem->len = len;
INIT_LIST_HEAD(&mem->node);
spin_lock_irqsave(&qcom_glink_mem_entry_lock, flags);
list_add_tail(&mem->node, &qcom_glink_mem_entries);
spin_unlock_irqrestore(&qcom_glink_mem_entry_lock, flags);
return mem;
}
EXPORT_SYMBOL_GPL(qcom_glink_mem_entry_init);
void qcom_glink_mem_entry_free(struct qcom_glink_mem_entry *mem)
{
struct qcom_glink_mem_entry *entry, *tmp;
unsigned long flags;
spin_lock_irqsave(&qcom_glink_mem_entry_lock, flags);
list_for_each_entry_safe(entry, tmp, &qcom_glink_mem_entries, node) {
if (entry == mem) {
list_del(&mem->node);
break;
}
}
spin_unlock_irqrestore(&qcom_glink_mem_entry_lock, flags);
kfree(mem);
}
EXPORT_SYMBOL_GPL(qcom_glink_mem_entry_free);
void *qcom_glink_prepare_da_for_cpu(u64 da, size_t len)
{
struct qcom_glink_mem_entry *mem;
unsigned long flags;
void *ptr = NULL;
spin_lock_irqsave(&qcom_glink_mem_entry_lock, flags);
list_for_each_entry(mem, &qcom_glink_mem_entries, node) {
int offset = da - mem->da;
if (!mem->va)
continue;
if (offset < 0)
continue;
if (offset + len > mem->len)
continue;
ptr = mem->va + offset;
dma_sync_single_for_cpu(mem->dev, da, len, DMA_FROM_DEVICE);
break;
}
spin_unlock_irqrestore(&qcom_glink_mem_entry_lock, flags);
return ptr;
}
EXPORT_SYMBOL_GPL(qcom_glink_prepare_da_for_cpu);

File diff suppressed because it is too large Load Diff

View File

@@ -7,10 +7,25 @@
#define __QCOM_GLINK_NATIVE_H__
#include <linux/types.h>
#include <linux/rpmsg.h>
#define GLINK_FEATURE_INTENT_REUSE BIT(0)
#define GLINK_FEATURE_MIGRATION BIT(1)
#define GLINK_FEATURE_TRACER_PKT BIT(2)
#define GLINK_FEATURE_ZERO_COPY BIT(3)
#define GLINK_FEATURE_ZERO_COPY_POOLS BIT(4)
/**
* rpmsg rx callback return definitions
* @RPMSG_HANDLED: rpmsg user is done processing data, framework can free the
* resources related to the buffer
* @RPMSG_DEFER: rpmsg user is not done processing data, framework will hold
* onto resources related to the buffer until rpmsg_rx_done is
* called. User should check their endpoint to see if rx_done
* is a supported operation.
*/
#define RPMSG_HANDLED 0
#define RPMSG_DEFER 1
struct qcom_glink_pipe {
size_t length;
@@ -29,13 +44,27 @@ struct qcom_glink_pipe {
struct device;
struct qcom_glink;
extern const struct dev_pm_ops glink_native_pm_ops;
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
unsigned long features,
struct qcom_glink_pipe *rx,
struct qcom_glink_pipe *tx,
bool intentless);
int qcom_glink_native_start(struct qcom_glink *glink);
void qcom_glink_native_remove(struct qcom_glink *glink);
void qcom_glink_native_rx(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));
/* These operations are temporarily exposing deferred freeing interfaces */
bool qcom_glink_rx_done_supported(struct rpmsg_endpoint *ept);
int qcom_glink_rx_done(struct rpmsg_endpoint *ept, void *data);
void *qcom_glink_prepare_da_for_cpu(u64 da, size_t len);
#endif

View File

@@ -358,7 +358,9 @@ static int glink_rpm_probe(struct platform_device *pdev)
enable_irq(rpm->irq);
return 0;
ret = qcom_glink_native_start(glink);
return ret;
}
static void glink_rpm_remove(struct platform_device *pdev)
@@ -385,6 +387,7 @@ static struct platform_driver glink_rpm_driver = {
.driver = {
.name = "qcom_glink_rpm",
.of_match_table = glink_rpm_of_match,
.pm = &glink_native_pm_ops,
},
};

View File

@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/ipc_logging.h>
#include <linux/rpmsg/qcom_glink.h>
@@ -39,6 +40,7 @@ struct qcom_glink_smem {
struct device dev;
int irq;
char irqname[32];
struct qcom_glink *glink;
struct mbox_client mbox_client;
@@ -46,6 +48,12 @@ struct qcom_glink_smem {
u32 remote_pid;
};
/* Define IPC Logging Macros */
#define GLINK_SMEM_IPC_LOG_PAGE_CNT 32
static void *glink_ilctxt;
#define GLINK_SMEM_INFO(x, ...) \
ipc_log_string(glink_ilctxt, "[%s]: "x, __func__, ##__VA_ARGS__)
struct glink_smem_pipe {
struct qcom_glink_pipe native;
@@ -86,29 +94,53 @@ static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
tail = le32_to_cpu(*pipe->tail);
if (head < tail)
return pipe->native.length - tail + head;
len = pipe->native.length - tail + head;
else
return head - tail;
len = head - tail;
if (WARN_ON_ONCE(len > pipe->native.length))
len = 0;
return len;
}
static void glink_smem_rx_peek(struct qcom_glink_pipe *np,
void *data, unsigned int offset, size_t count)
{
struct glink_smem_pipe *pipe = to_smem_pipe(np);
unsigned char *bytedata = (unsigned char *)data;
struct qcom_glink_smem *smem = pipe->smem;
size_t len;
u32 tail;
tail = le32_to_cpu(*pipe->tail);
if (WARN_ON_ONCE(tail > pipe->native.length))
return;
tail += offset;
if (tail >= pipe->native.length)
tail -= pipe->native.length;
/* Update the tail pointer and add a memory barrier to ensure
* consistent read/write between the APPS and the remote.
* This prevents the APPS from reading stale data from the FIFO.
*/
mb();
len = min_t(size_t, count, pipe->native.length - tail);
if (len)
memcpy_fromio(data, pipe->fifo + tail, len);
if (len != count)
memcpy_fromio(data + len, pipe->fifo, (count - len));
if (count == 1)
GLINK_SMEM_INFO("RX: remote-pid=%d, head=0x%x, tail=0x%x, [%02x]\n",
smem->remote_pid, le32_to_cpu(*pipe->head), tail, bytedata[0]);
if (count > 1)
GLINK_SMEM_INFO("RX: remote-pid=%d, head=0x%x, tail=0x%x, [%02x %02x]\n",
smem->remote_pid, le32_to_cpu(*pipe->head), tail, bytedata[1], bytedata[0]);
}
static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
@@ -121,7 +153,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
tail += count;
if (tail >= pipe->native.length)
tail -= pipe->native.length;
tail %= pipe->native.length;
*pipe->tail = cpu_to_le32(tail);
}
@@ -146,6 +178,9 @@ static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
else
avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
if (WARN_ON_ONCE(avail > pipe->native.length))
avail = 0;
return avail;
}
@@ -155,6 +190,9 @@ static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
{
size_t len;
if (WARN_ON_ONCE(head > pipe->native.length))
return head;
len = min_t(size_t, count, pipe->native.length - head);
if (len)
memcpy(pipe->fifo + head, data, len);
@@ -174,6 +212,7 @@ static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
const void *data, size_t dlen)
{
struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
struct qcom_glink_smem *smem = pipe->smem;
unsigned int head;
head = le32_to_cpu(*pipe->head);
@@ -189,6 +228,8 @@ static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
/* Ensure ordering of fifo and head update */
wmb();
GLINK_SMEM_INFO("TX: remote-pid=%d, head=0x%x, tail=0x%x\n",
smem->remote_pid, head, le32_to_cpu(*pipe->tail));
*pipe->head = cpu_to_le32(head);
}
@@ -304,10 +345,11 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent,
goto err_put_dev;
}
scnprintf(smem->irqname, 32, "glink-native-%u", remote_pid);
smem->irq = of_irq_get(smem->dev.of_node, 0);
ret = devm_request_irq(&smem->dev, smem->irq, qcom_glink_smem_intr,
IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
"glink-smem", smem);
smem->irqname, smem);
if (ret) {
dev_err(&smem->dev, "failed to request IRQ\n");
goto err_put_dev;
@@ -336,7 +378,7 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent,
*tx_pipe->head = 0;
glink = qcom_glink_native_probe(dev,
GLINK_FEATURE_INTENT_REUSE,
GLINK_FEATURE_INTENT_REUSE | GLINK_FEATURE_ZERO_COPY,
&rx_pipe->native, &tx_pipe->native,
false);
if (IS_ERR(glink)) {
@@ -344,6 +386,9 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent,
goto err_free_mbox;
}
if (!glink_ilctxt)
glink_ilctxt = ipc_log_context_create(GLINK_SMEM_IPC_LOG_PAGE_CNT,
"glink_smem", 0);
smem->glink = glink;
enable_irq(smem->irq);
@@ -360,9 +405,19 @@ err_put_dev:
}
EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
int qcom_glink_smem_start(struct qcom_glink_smem *smem)
{
return qcom_glink_native_start(smem->glink);
}
EXPORT_SYMBOL(qcom_glink_smem_start);
void qcom_glink_smem_unregister(struct qcom_glink_smem *smem)
{
struct qcom_glink *glink = smem->glink;
struct qcom_glink *glink;
if (!smem)
return;
glink = smem->glink;
disable_irq(smem->irq);

View File

@@ -0,0 +1,431 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/mailbox_client.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sizes.h>
#include <linux/soc/qcom/smem.h>
#include <linux/rpmsg/qcom_glink.h>
#include "qcom_glink_native.h"
#define FIFO_FULL_RESERVE 8
#define FIFO_ALIGNMENT 8
#define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
#define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR 478
#define SPSS_TX_FIFO_SIZE SZ_2K
#define SPSS_RX_FIFO_SIZE SZ_2K
struct glink_spss_cfg {
__le32 tx_tail;
__le32 tx_head;
__le32 tx_fifo_size;
__le32 rx_tail;
__le32 rx_head;
__le32 rx_fifo_size;
};
struct glink_spss_pipe {
struct qcom_glink_pipe native;
__le32 *tail;
__le32 *head;
void *fifo;
struct qcom_glink_spss *spss;
};
struct qcom_glink_spss {
struct device dev;
int irq;
char irqname[32];
struct qcom_glink *glink;
struct mbox_client mbox_client;
struct mbox_chan *mbox_chan;
struct glink_spss_pipe *tx_pipe;
struct glink_spss_pipe *rx_pipe;
u32 remote_pid;
};
#define to_spss_pipe(p) container_of(p, struct glink_spss_pipe, native)
static void glink_spss_reset(struct glink_spss_pipe *np)
{
*np->head = cpu_to_le32(0);
*np->tail = cpu_to_le32(0);
}
static size_t glink_spss_rx_avail(struct qcom_glink_pipe *np)
{
struct glink_spss_pipe *pipe = to_spss_pipe(np);
u32 head;
u32 tail;
head = le32_to_cpu(*pipe->head);
tail = le32_to_cpu(*pipe->tail);
if (head < tail)
return pipe->native.length - tail + head;
else
return head - tail;
}
static void glink_spss_rx_peek(struct qcom_glink_pipe *np,
void *data, unsigned int offset, size_t count)
{
struct glink_spss_pipe *pipe = to_spss_pipe(np);
size_t len;
u32 tail;
tail = le32_to_cpu(*pipe->tail);
tail += offset;
if (tail >= pipe->native.length)
tail -= pipe->native.length;
len = min_t(size_t, count, pipe->native.length - tail);
if (len)
memcpy_fromio(data, pipe->fifo + tail, len);
if (len != count)
memcpy_fromio(data + len, pipe->fifo, count - len);
}
static void glink_spss_rx_advance(struct qcom_glink_pipe *np,
size_t count)
{
struct glink_spss_pipe *pipe = to_spss_pipe(np);
u32 tail;
tail = le32_to_cpu(*pipe->tail);
tail += count;
if (tail >= pipe->native.length)
tail -= pipe->native.length;
*pipe->tail = cpu_to_le32(tail);
}
static size_t glink_spss_tx_avail(struct qcom_glink_pipe *np)
{
struct glink_spss_pipe *pipe = to_spss_pipe(np);
u32 head;
u32 tail;
u32 avail;
head = le32_to_cpu(*pipe->head);
tail = le32_to_cpu(*pipe->tail);
if (tail <= head)
avail = pipe->native.length - head + tail;
else
avail = tail - head;
if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
avail = 0;
else
avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
return avail;
}
static unsigned int glink_spss_tx_write_one(struct glink_spss_pipe *pipe,
unsigned int head,
const void *data, size_t count)
{
size_t len;
len = min_t(size_t, count, pipe->native.length - head);
if (len)
memcpy(pipe->fifo + head, data, len);
if (len != count)
memcpy(pipe->fifo, data + len, count - len);
head += count;
if (head >= pipe->native.length)
head -= pipe->native.length;
return head;
}
static void glink_spss_tx_write(struct qcom_glink_pipe *glink_pipe,
const void *hdr, size_t hlen,
const void *data, size_t dlen)
{
struct glink_spss_pipe *pipe = to_spss_pipe(glink_pipe);
unsigned int head;
head = le32_to_cpu(*pipe->head);
head = glink_spss_tx_write_one(pipe, head, hdr, hlen);
head = glink_spss_tx_write_one(pipe, head, data, dlen);
/* Ensure head is always aligned to 8 bytes */
head = ALIGN(head, 8);
if (head >= pipe->native.length)
head -= pipe->native.length;
/* Ensure ordering of fifo and head update */
wmb();
*pipe->head = cpu_to_le32(head);
}
static void glink_spss_tx_kick(struct qcom_glink_pipe *glink_pipe)
{
struct glink_spss_pipe *pipe = to_spss_pipe(glink_pipe);
struct qcom_glink_spss *spss = pipe->spss;
mbox_send_message(spss->mbox_chan, NULL);
mbox_client_txdone(spss->mbox_chan, 0);
}
static irqreturn_t qcom_glink_spss_intr(int irq, void *data)
{
struct qcom_glink_spss *spss = data;
qcom_glink_native_rx(spss->glink);
return IRQ_HANDLED;
}
static void qcom_glink_spss_release(struct device *dev)
{
struct qcom_glink_spss *spss = container_of(dev, struct qcom_glink_spss, dev);
kfree(spss);
}
static int glink_spss_advertise_cfg(struct device *dev,
u32 size, phys_addr_t addr)
{
struct device_node *np = dev->of_node;
__le64 __iomem *spss_addr;
__le32 __iomem *spss_size;
struct resource addr_r;
struct resource size_r;
int addr_idx;
int size_idx;
addr_idx = of_property_match_string(np, "reg-names", "qcom,spss-addr");
size_idx = of_property_match_string(np, "reg-names", "qcom,spss-size");
if (addr_idx < 0 || size_idx < 0) {
dev_err(dev, "failed to find location registers\n");
return -EINVAL;
}
if (of_address_to_resource(np, addr_idx, &addr_r))
return -ENOMEM;
spss_addr = ioremap(addr_r.start, resource_size(&addr_r));
if (IS_ERR_OR_NULL(spss_addr)) {
dev_err(dev, "failed to map spss addr resource\n");
return -ENOMEM;
}
if (of_address_to_resource(np, size_idx, &size_r)) {
iounmap(spss_addr);
return -ENOMEM;
}
spss_size = ioremap(size_r.start, resource_size(&size_r));
if (IS_ERR_OR_NULL(spss_size)) {
iounmap(spss_addr);
dev_err(dev, "failed to map spss size resource\n");
return -ENOMEM;
}
writeq_relaxed(addr, spss_addr);
writel_relaxed(size, spss_size);
iounmap(spss_addr);
iounmap(spss_size);
return 0;
}
struct qcom_glink_spss *qcom_glink_spss_register(struct device *parent,
struct device_node *node)
{
struct glink_spss_pipe *rx_pipe;
struct glink_spss_pipe *tx_pipe;
struct qcom_glink_spss *spss;
struct glink_spss_cfg *cfg;
struct qcom_glink *glink;
struct device *dev;
u32 remote_pid;
size_t tx_size;
size_t rx_size;
size_t size;
int ret;
spss = kzalloc(sizeof(*spss), GFP_KERNEL);
if (!spss)
return ERR_PTR(-ENOMEM);
dev = &spss->dev;
dev->parent = parent;
dev->of_node = node;
dev->release = qcom_glink_spss_release;
dev_set_name(dev, "%s:%pOFn", dev_name(parent->parent), node);
ret = device_register(dev);
if (ret) {
pr_err("failed to register glink edge\n");
put_device(dev);
return ERR_PTR(ret);
}
ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
&remote_pid);
if (ret) {
dev_err(dev, "failed to parse qcom,remote-pid\n");
goto err_put_dev;
}
spss->remote_pid = remote_pid;
rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
if (!rx_pipe || !tx_pipe) {
ret = -ENOMEM;
goto err_put_dev;
}
tx_size = SPSS_TX_FIFO_SIZE;
rx_size = SPSS_RX_FIFO_SIZE;
size = tx_size + rx_size + sizeof(*cfg);
ret = qcom_smem_alloc(remote_pid,
SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, size);
if (ret && ret != -EEXIST) {
dev_err(dev, "failed to allocate glink descriptors\n");
goto err_put_dev;
}
cfg = qcom_smem_get(remote_pid,
SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
if (IS_ERR(cfg)) {
dev_err(dev, "failed to acquire xprt descriptor\n");
ret = PTR_ERR(cfg);
goto err_put_dev;
}
if (size != tx_size + rx_size + sizeof(*cfg)) {
dev_err(dev, "glink descriptor of invalid size\n");
ret = -EINVAL;
goto err_put_dev;
}
scnprintf(spss->irqname, 32, "glink-native-%u", remote_pid);
spss->irq = of_irq_get(spss->dev.of_node, 0);
ret = devm_request_irq(&spss->dev, spss->irq, qcom_glink_spss_intr,
IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
spss->irqname, spss);
if (ret) {
dev_err(&spss->dev, "failed to request IRQ\n");
goto err_put_dev;
}
spss->mbox_client.dev = &spss->dev;
spss->mbox_client.knows_txdone = true;
spss->mbox_chan = mbox_request_channel(&spss->mbox_client, 0);
if (IS_ERR(spss->mbox_chan)) {
ret = dev_err_probe(&spss->dev, PTR_ERR(spss->mbox_chan),
"failed to acquire IPC channel\n");
goto err_put_dev;
}
cfg->tx_fifo_size = cpu_to_le32(tx_size);
cfg->rx_fifo_size = cpu_to_le32(rx_size);
tx_pipe->spss = spss;
spss->tx_pipe = tx_pipe;
tx_pipe->tail = &cfg->tx_tail;
tx_pipe->head = &cfg->tx_head;
tx_pipe->native.length = tx_size;
tx_pipe->fifo = (u8 *)cfg + sizeof(*cfg);
rx_pipe->spss = spss;
spss->rx_pipe = rx_pipe;
rx_pipe->tail = &cfg->rx_tail;
rx_pipe->head = &cfg->rx_head;
rx_pipe->native.length = rx_size;
rx_pipe->fifo = (u8 *)cfg + sizeof(*cfg) + tx_size;
rx_pipe->native.avail = glink_spss_rx_avail;
rx_pipe->native.peek = glink_spss_rx_peek;
rx_pipe->native.advance = glink_spss_rx_advance;
tx_pipe->native.avail = glink_spss_tx_avail;
tx_pipe->native.write = glink_spss_tx_write;
tx_pipe->native.kick = glink_spss_tx_kick;
*rx_pipe->tail = 0;
*tx_pipe->head = 0;
ret = glink_spss_advertise_cfg(dev, size, qcom_smem_virt_to_phys(cfg));
if (ret)
goto err_free_mbox;
glink = qcom_glink_native_probe(dev,
GLINK_FEATURE_INTENT_REUSE,
&rx_pipe->native, &tx_pipe->native,
false);
if (IS_ERR(glink)) {
ret = PTR_ERR(glink);
goto err_free_mbox;
}
spss->glink = glink;
enable_irq(spss->irq);
ret = qcom_glink_native_start(glink);
if (ret)
goto err_free_mbox;
return spss;
err_free_mbox:
mbox_free_channel(spss->mbox_chan);
err_put_dev:
put_device(dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(qcom_glink_spss_register);
void qcom_glink_spss_unregister(struct qcom_glink_spss *spss)
{
if (!spss)
return;
disable_irq(spss->irq);
qcom_glink_native_remove(spss->glink);
mbox_free_channel(spss->mbox_chan);
glink_spss_reset(spss->tx_pipe);
glink_spss_reset(spss->rx_pipe);
device_unregister(&spss->dev);
}
EXPORT_SYMBOL_GPL(qcom_glink_spss_unregister);
MODULE_DESCRIPTION("QTI GLINK SPSS driver");
MODULE_LICENSE("GPL");

1701
drivers/rpmsg/rpm-smd.c Normal file

File diff suppressed because it is too large Load Diff