lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250721023052.3586000-5-ew.kim@samsung.com>
Date: Mon, 21 Jul 2025 11:30:47 +0900
From: ew kim <ew.kim@...sung.com>
To: broonie@...nel.org, s.nawrocki@...sung.com, robh@...nel.org,
	krzk+dt@...nel.org
Cc: lgirdwood@...il.com, tiwai@...e.com, perex@...ex.cz,
	conor+dt@...nel.org, alim.akhtar@...sung.com, linux-sound@...r.kernel.org,
	devicetree@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
	linux-samsung-soc@...r.kernel.org, linux-kernel@...r.kernel.org, ew kim
	<ew.kim@...sung.com>
Subject: [PATCH 4/9] ASoC: samsung: abox: Add IPC generic support for
 message forwarding

This adds the IPC generic driver as a child module of abox_generic
to handle bidirectional IPC message and IRQ routing between the
generic fixed layer and the SoC-specific audio side.

The driver:
- Registers a shared IRQ handler to allow SoC (variable part) to notify
  the generic layer of IPC messages.
- Exports a registration interface to allow the generic layer to send
  IPC messages to the SoC side.
- Uses a global singleton (non-DT) to coordinate state and callback
  registration between the layers, due to lack of direct parent-child
  linkage.

The driver is not a standalone module, and is built as part of the
snd-soc-samsung-abox-generic.ko module.

Signed-off-by: ew kim <ew.kim@...sung.com>
---
 sound/soc/samsung/auto_abox/Kconfig           |  19 +-
 sound/soc/samsung/auto_abox/generic/Kbuild    |   3 +-
 .../samsung/auto_abox/generic/abox_generic.c  |  13 +-
 .../auto_abox/generic/abox_ipc_generic.c      | 218 ++++++++++++++++++
 .../auto_abox/generic/include/abox_generic.h  |   2 +-
 .../generic/include/abox_ipc_generic.h        | 181 +++++++++++++++
 6 files changed, 421 insertions(+), 15 deletions(-)
 create mode 100644 sound/soc/samsung/auto_abox/generic/abox_ipc_generic.c
 create mode 100644 sound/soc/samsung/auto_abox/generic/include/abox_ipc_generic.h

diff --git a/sound/soc/samsung/auto_abox/Kconfig b/sound/soc/samsung/auto_abox/Kconfig
index d22b54fb785f..55755b4166b8 100644
--- a/sound/soc/samsung/auto_abox/Kconfig
+++ b/sound/soc/samsung/auto_abox/Kconfig
@@ -10,13 +10,20 @@ config SND_SOC_SAMSUNG_AUTO_ABOX
 		audio block on Samsung SoCs.
 
 		The design splits the ABOX support into:
-		- Fixed generic driver
-		- SoC-specific hardware drivers
+			- A fixed generic control layer (ABOX Generic)
+			- SoC-specific hardware drivers (e.g., IPC, PCM, Backend)
 
-		These parts are independent modules without parent-child
-		binding. The generic driver therefore exposes a global
-		accessor via EXPORT_SYMBOL so that variable parts can share
-		state and callbacks safely.
+		These components are tightly coupled and share internal data
+		and callbacks. To ensure correct symbol resolution and
+		initialization ordering, all drivers are built together into
+		a single kernel object: snd-soc-samsung-abox-generic.ko
+
+		The sub-drivers are registered internally from the generic
+		driver's probe using platform_register_drivers(), rather than
+		being standalone platform drivers with independent module init.
+
+		This approach ensures integration consistency for fixed and
+		variable components across different automotive SoCs.
 
 endmenu
 
diff --git a/sound/soc/samsung/auto_abox/generic/Kbuild b/sound/soc/samsung/auto_abox/generic/Kbuild
index fa6ba7091730..6a63d0609930 100644
--- a/sound/soc/samsung/auto_abox/generic/Kbuild
+++ b/sound/soc/samsung/auto_abox/generic/Kbuild
@@ -2,7 +2,8 @@
 # Exynosauto Automotive Abox Driver Support
 
 snd-soc-samsung-abox-generic-$(CONFIG_SND_SOC_SAMSUNG_AUTO_ABOX) := \
-	abox_generic.o
+	abox_generic.o \
+	abox_ipc_generic.o
 
 ccflags-y += -I./include
 
diff --git a/sound/soc/samsung/auto_abox/generic/abox_generic.c b/sound/soc/samsung/auto_abox/generic/abox_generic.c
index e1e14750ac8d..2c3f5ea910a2 100644
--- a/sound/soc/samsung/auto_abox/generic/abox_generic.c
+++ b/sound/soc/samsung/auto_abox/generic/abox_generic.c
@@ -13,7 +13,9 @@
 #include <sound/soc-dapm.h>
 
 #include "include/abox_generic.h"
+#include "include/abox_ipc_generic.h"
 
+extern struct platform_driver samsung_abox_ipc_generic_driver;
 /**
  * abox_generic_data_global - Shared state for ABOX generic driver.
  *
@@ -264,9 +266,6 @@ int abox_generic_request_soc_ioctl(struct device *generic_dev, enum abox_soc_ioc
 	return generic_data->soc_ioctl(soc_dev, cmd, data);
 }
 
-static struct platform_driver *abox_generic_sub_drivers[] = {
-};
-
 static int abox_generic_read_property_from_dt(struct device *dev, struct abox_generic_data *data)
 {
 	struct device_node *np = dev->of_node;
@@ -308,6 +307,10 @@ static int abox_generic_allocate_memory(struct device *dev, struct abox_generic_
 	return 0;
 }
 
+static struct platform_driver *abox_generic_sub_drivers[] = {
+	&samsung_abox_ipc_generic_driver,
+};
+
 static int samsung_abox_generic_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -344,14 +347,10 @@ static int samsung_abox_generic_probe(struct platform_device *pdev)
 
 static void samsung_abox_generic_remove(struct platform_device *pdev)
 {
-	struct abox_generic_data *data = platform_get_drvdata(pdev);
-
 	platform_unregister_drivers(abox_generic_sub_drivers,
 					ARRAY_SIZE(abox_generic_sub_drivers));
 
 	g_abox_generic_data = NULL;
-
-	return 0;
 }
 
 static void samsung_abox_generic_shutdown(struct platform_device *pdev)
diff --git a/sound/soc/samsung/auto_abox/generic/abox_ipc_generic.c b/sound/soc/samsung/auto_abox/generic/abox_ipc_generic.c
new file mode 100644
index 000000000000..58d765cd5bfa
--- /dev/null
+++ b/sound/soc/samsung/auto_abox/generic/abox_ipc_generic.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ * Author: Eunwoo Kim <ew.kim@...sung.com>
+ *
+ * EXYNOS Automotive Abox IPC Generic Driver - abox_ipc_generic.c
+ *
+ * This driver is part of the ABOX generic audio stack and provides
+ * IPC message/IRQ handling between the fixed (generic) layer and the
+ * SoC-specific variable layer.
+ *
+ * It is a child driver managed by abox_generic, and is built as part
+ * of a single kernel module (snd-soc-samsung-abox-generic.ko) along with
+ * other related drivers.
+ *
+ * The IPC generic driver is registered independently as a platform
+ * driver and uses a global singleton to expose callback interfaces.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include "include/abox_ipc_generic.h"
+
+struct abox_ipc_generic_irq_handler_t {
+	ipc_generic_irq_handler_t handler;
+	struct device *dev;
+};
+
+/*
+ * Singleton instance for ABOX IPC Generic driver.
+ *
+ * The generic layer and SoC-specific IPC driver are independent modules,
+ * not in a parent-child device relationship. A global symbol is used to
+ * expose internal state and register callbacks.
+ *
+ * Only one instance is supported. Accessed via exported helper functions.
+ */
+static struct abox_ipc_generic_data *g_abox_ipc_generic_data;
+
+static struct abox_ipc_generic_data *abox_ipc_generic_get_data(void)
+{
+	return g_abox_ipc_generic_data;
+}
+
+static irqreturn_t abox_ipc_generic_pcm_dev_irq_handler(struct device *ipc_generic_dev, int irq_id,
+							struct _abox_inter_ipc_msg *pmsg)
+{
+	struct device *pcm_dev;
+	struct abox_ipc_generic_data *data;
+	struct abox_ipc_generic_irq_handler_t *pcm_dev_irq_handler;
+
+	if (!ipc_generic_dev)
+		return IRQ_NONE;
+
+	data = dev_get_drvdata(ipc_generic_dev);
+	if (!data || irq_id >= data->num_irq)
+		return IRQ_NONE;
+
+	pcm_dev_irq_handler = &data->pcm_dev_irq_handler[irq_id];
+	if (!pcm_dev_irq_handler)
+		return IRQ_NONE;
+
+	if (!pcm_dev_irq_handler->handler)
+		return IRQ_NONE;
+
+	pcm_dev = pcm_dev_irq_handler->dev;
+	if (!pcm_dev)
+		return IRQ_NONE;
+
+	return pcm_dev_irq_handler->handler(pcm_dev, irq_id, pmsg);
+}
+
+static int abox_ipc_generic_read_property_from_dt(struct platform_device *pdev,
+						struct abox_ipc_generic_data *data)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+
+	ret = of_property_read_u32(np, "samsung,num-of-irq", &data->num_irq);
+	if (ret < 0) {
+		dev_err(dev, "%s property reading fail\n", "samsung,num-of-irq");
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * abox_ipc_generic_get_pcm_dev_handler_callback() - Register IRQ handler to receive IPCs from SoC
+ * @dev_ipc_gen: [out] pointer to the generic device
+ * @handler: [out] function pointer to be called on IPC IRQ
+ *
+ * This function is used by SoC-specific drivers to register the IRQ
+ * handler provided by the generic layer, enabling upward message passing.
+ *
+ * Return: 0 on success, -EINVAL on failure
+ */
+int abox_ipc_generic_get_pcm_dev_handler_callback(struct device **dev_ipc_gen,
+						ipc_generic_irq_handler_t *handler)
+{
+	struct abox_ipc_generic_data *data = NULL;
+
+	data = abox_ipc_generic_get_data();
+	if (!data)
+		return -EINVAL;
+
+	*dev_ipc_gen = &data->pdev->dev;
+	*handler = abox_ipc_generic_pcm_dev_irq_handler;
+
+	return 0;
+}
+EXPORT_SYMBOL(abox_ipc_generic_get_pcm_dev_handler_callback);
+
+/**
+ * abox_ipc_generic_register_xfer_callback() - Register callback to send IPC to SoC
+ * @xfer: SoC-provided IPC transmission function
+ *
+ * Used by the generic layer to send IPC messages to the hardware
+ * through the SoC-specific xfer function.
+ *
+ * Return: 0 on success, -EINVAL on failure
+ */
+int abox_ipc_generic_register_xfer_callback(ipc_gen_request_xfer_t xfer)
+{
+	struct abox_ipc_generic_data *data = NULL;
+
+	data = abox_ipc_generic_get_data();
+	if (!data)
+		return -EINVAL;
+
+	data->request_xfer = xfer;
+
+	return 0;
+}
+EXPORT_SYMBOL(abox_ipc_generic_register_xfer_callback);
+
+int abox_ipc_generic_request_xfer(enum INTER_IPC_ID ipc_id, struct _abox_inter_ipc_msg *pmsg,
+				bool sync, struct __abox_inter_ipc_ret *ipc_ret,
+				unsigned int adsp)
+{
+	struct abox_ipc_generic_data *data = NULL;
+
+	data = abox_ipc_generic_get_data();
+	if (!data || !data->request_xfer)
+		return -EINVAL;
+
+	return data->request_xfer(ipc_id, pmsg, sync, ipc_ret, adsp);
+}
+
+static int samsung_abox_ipc_generic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct abox_ipc_generic_data *data;
+	int ret = 0;
+
+	data = devm_kzalloc(dev, sizeof(struct abox_ipc_generic_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->pdev = pdev;
+	platform_set_drvdata(pdev, data);
+	g_abox_ipc_generic_data = data;
+
+	ret = abox_ipc_generic_read_property_from_dt(pdev, data);
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+				"%s Failed to read property ret:%d\n", __func__, ret);
+
+	data->pcm_dev_irq_handler = devm_kcalloc(dev, data->num_irq,
+						sizeof(struct abox_ipc_generic_irq_handler_t),
+						GFP_KERNEL);
+	if (!data->pcm_dev_irq_handler)
+		return dev_err_probe(dev, -ENOMEM,
+				"%s Failed to alloc memory for pcm_dev_irq_handler\n", __func__);
+
+	return ret;
+}
+
+static void samsung_abox_ipc_generic_remove(struct platform_device *pdev)
+{
+	struct abox_ipc_generic_data *data = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < data->num_irq; ++i) {
+		data->pcm_dev_irq_handler[i].handler = NULL;
+		data->pcm_dev_irq_handler[i].dev = NULL;
+	}
+	g_abox_ipc_generic_data = NULL;
+}
+
+static void samsung_abox_ipc_generic_shutdown(struct platform_device *pdev)
+{
+}
+
+static const struct of_device_id samsung_abox_ipc_generic_of_match[] = {
+	{
+		.compatible = "samsung,abox_ipc_generic",
+	},
+	{}
+};
+
+struct platform_driver samsung_abox_ipc_generic_driver = {
+	.probe  = samsung_abox_ipc_generic_probe,
+	.remove = samsung_abox_ipc_generic_remove,
+	.shutdown = samsung_abox_ipc_generic_shutdown,
+	.driver = {
+		.name = "samsung-abox-ipc-generic",
+		.of_match_table = of_match_ptr(samsung_abox_ipc_generic_of_match),
+	},
+};
+
diff --git a/sound/soc/samsung/auto_abox/generic/include/abox_generic.h b/sound/soc/samsung/auto_abox/generic/include/abox_generic.h
index b2a3f32ac577..b1e6d9b9345d 100644
--- a/sound/soc/samsung/auto_abox/generic/include/abox_generic.h
+++ b/sound/soc/samsung/auto_abox/generic/include/abox_generic.h
@@ -30,7 +30,7 @@ enum abox_soc_ioctl_cmd {
 };
 
 /**
- * SOC_IOCTL - SoC-specific callback prototype
+ * soc_ioctl_fn - SoC-specific callback prototype
  * @soc_dev: SoC device pointer
  * @cmd: Command to handle (enum abox_soc_ioctl_cmd)
  * @data: Additional argument, type depends on command
diff --git a/sound/soc/samsung/auto_abox/generic/include/abox_ipc_generic.h b/sound/soc/samsung/auto_abox/generic/include/abox_ipc_generic.h
new file mode 100644
index 000000000000..c28a72306340
--- /dev/null
+++ b/sound/soc/samsung/auto_abox/generic/include/abox_ipc_generic.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ * Author: Eunwoo Kim <ew.kim@...sung.com>
+ *
+ * ALSA SoC - Samsung ABOX IPC Generic Interface Header
+ *
+ * This header defines IPC message types, data structures, and
+ * interfaces shared between the ABOX generic layer and
+ * SoC-specific IPC handlers.
+ */
+
+#ifndef __SND_SOC_ABOX_IPC_GENERIC_H
+#define __SND_SOC_ABOX_IPC_GENERIC_H
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+/************ IPC DEFINITION ***************/
+/* Categorized IPC, */
+enum INTER_IPC_ID {
+	INTER_NOT_USED0 = BIT(0),
+	INTER_NOT_USED1 = BIT(1),
+	INTER_IPC_PCMPLAYBACK = BIT(2),
+	INTER_IPC_PCMCAPTURE = BIT(3),
+	INTER_IPC_OFFLOAD = BIT(4),
+	INTER_IPC_DMA_INTR = BIT(5),
+	INTER_NOT_USED6 = BIT(6),
+	INTER_NOT_USED7 = BIT(7),
+	INTER_NOT_USED8 = BIT(8),
+	INTER_NOT_USED9 = BIT(9),
+	INTER_NOT_USED10 = BIT(10),
+	INTER_NOT_USED11 = BIT(11),
+	INTER_NOT_USED12 = BIT(12),
+	INTER_NOT_USED13 = BIT(13),
+	INTER_NOT_USED14 = BIT(14),
+	INTER_NOT_USED15 = BIT(15),
+	INTER_IPC_ID_COUNT = 16,
+	INTER_IPC_ID_COUNT_BIT = BIT(INTER_IPC_ID_COUNT),
+};
+
+struct __abox_inter_ipc_ret {
+	int param1;
+};
+
+/******** PCMTASK IPC ***********************/
+enum INTER_PCMMSG {
+	INTER_PCM_PLTDAI_OPEN		= 11,
+	INTER_PCM_PLTDAI_CLOSE		= 12,
+	INTER_PCM_PLTDAI_IOCTL		= 13,
+	INTER_PCM_PLTDAI_HW_PARAMS	= 14,
+	INTER_PCM_PLTDAI_HW_FREE	= 15,
+	INTER_PCM_PLTDAI_PREPARE	= 16,
+	INTER_PCM_PLTDAI_TRIGGER	= 17,
+	INTER_PCM_PLTDAI_POINTER	= 18,
+	INTER_PCM_SET_BUFFER		= 20,
+	INTER_PCM_SET_FW_INTR_GAP_LOG	= 51,
+	INTER_PCMMSG_MAX	= 52,
+};
+
+struct PCMTASK_HW_PARAMS {
+	int sample_rate;
+	int bit_depth;
+	int channels;
+};
+
+struct PCMTASK_SET_BUFFER {
+	int phyaddr;
+	int size;
+	int count;
+};
+
+struct PCMTASK_DMA_TRIGGER {
+	int trigger;
+	int rbuf_offset;
+	int rbuf_cnt;
+	bool is_real_dma;
+};
+
+/* Parameter of the PCMTASK command */
+struct INTER_IPC_PCMTASK_MSG {
+	enum INTER_PCMMSG msgtype;
+	int pcm_alsa_id;
+	int pcm_device_id;
+	int hw_dma_id;           // should know ??
+	int irq_id;
+	unsigned int domain_id;  // SMH - should be removed
+	unsigned int adsp;
+	unsigned long start_threshold;
+	union {
+		struct PCMTASK_HW_PARAMS hw_params;
+		struct PCMTASK_SET_BUFFER setbuff;
+		struct PCMTASK_DMA_TRIGGER dma_trigger;
+	} param;
+};
+
+/* The parameter of the set_param */
+struct OFFLOAD_SET_PARAM {
+	int sample_rate;
+	int bit_depth;
+	int channels;
+	int phyaddr;
+	int chunk_size;
+};
+
+/* The parameter of the start */
+struct OFFLOAD_START {
+	int id;
+};
+
+/* The parameter of the write */
+struct OFFLOAD_WRITE {
+	int id;
+	int buff;
+	int size;
+};
+
+/******** OFFLOAD IPC ***********************/
+enum OFFLOADMSG {
+	OFFLOAD_OPEN = 1,
+	OFFLOAD_CLOSE,
+	OFFLOAD_SETPARAM,
+	OFFLOAD_START,
+	OFFLOAD_WRITE,
+	OFFLOAD_PAUSE,
+	OFFLOAD_STOP,
+};
+
+/* Parameter of the OFFLOADTASK command */
+struct INTER_IPC_OFFLOADTASK_MSG {
+	enum OFFLOADMSG msgtype;
+	int codec_id;
+	int pcm_device_id;
+	int hw_dma_id;
+	int irq_id;
+	int pcm_alsa_id;
+	int direction;
+	int domain_id;
+	union {
+		struct OFFLOAD_SET_PARAM setparam;
+		struct OFFLOAD_START start;
+		struct OFFLOAD_WRITE write;
+		struct PCMTASK_DMA_TRIGGER dma_trigger;
+	} param;
+};
+
+struct _abox_inter_ipc_msg {
+	enum INTER_IPC_ID ipcid;
+	int task_id;
+	union INTER_IPC_MSG {
+		struct INTER_IPC_PCMTASK_MSG pcmtask;
+		struct INTER_IPC_OFFLOADTASK_MSG offload_task;
+	} msg;
+};
+
+typedef irqreturn_t (*ipc_generic_irq_handler_t)(struct device *dev, int irq_id,
+	struct _abox_inter_ipc_msg *pmsg);
+
+typedef int (*ipc_gen_request_xfer_t)(enum INTER_IPC_ID ipc_id, struct _abox_inter_ipc_msg *pmsg,
+	bool sync, struct __abox_inter_ipc_ret *ipc_ret, unsigned int adsp);
+
+struct abox_ipc_generic_irq_handler_t;
+
+struct abox_ipc_generic_data {
+	struct platform_device *pdev;
+	unsigned int num_irq;
+	struct abox_ipc_generic_irq_handler_t *pcm_dev_irq_handler;
+	ipc_gen_request_xfer_t request_xfer;
+};
+
+int abox_ipc_generic_get_pcm_dev_handler_callback(struct device **dev_ipc_generic,
+	ipc_generic_irq_handler_t *handler);
+int abox_ipc_generic_register_xfer_callback(ipc_gen_request_xfer_t xfer);
+int abox_ipc_generic_register_pcm_dev_handler(struct device *dev_pcm, unsigned int irq_id,
+	ipc_generic_irq_handler_t handler);
+int abox_ipc_generic_request_xfer(enum INTER_IPC_ID ipc_id, struct _abox_inter_ipc_msg *pmsg,
+	bool sync, struct __abox_inter_ipc_ret *ipc_ret, unsigned int adsp);
+
+
+#endif /* __SND_SOC_ABOX_IPC_GENERIC_H */
+
-- 
2.25.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ