mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 18:12:25 -04:00
ASoC: Intel: Remove unused code
After removal of Skylake driver there is no users left for sst-dsp and sst-ipc interfaces. Remove them. Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com> Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com> Link: https://patch.msgid.link/20241009083419.319038-1-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
f8199bbca5
commit
970d299b0a
@@ -15,9 +15,6 @@ config SND_SOC_INTEL_SST_TOPLEVEL
|
||||
|
||||
if SND_SOC_INTEL_SST_TOPLEVEL
|
||||
|
||||
config SND_SOC_INTEL_SST
|
||||
tristate
|
||||
|
||||
config SND_SOC_INTEL_CATPT
|
||||
tristate "Haswell and Broadwell"
|
||||
depends on ACPI || COMPILE_TEST
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
snd-soc-sst-dsp-y := sst-dsp.o
|
||||
snd-soc-sst-ipc-y := sst-ipc.o
|
||||
snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \
|
||||
soc-acpi-intel-hsw-bdw-match.o \
|
||||
soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
|
||||
@@ -18,5 +16,4 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc
|
||||
|
||||
snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
|
||||
obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel Smart Sound Technology
|
||||
*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_SST_DSP_PRIV_H
|
||||
#define __SOUND_SOC_SST_DSP_PRIV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "../skylake/skl-sst-dsp.h"
|
||||
|
||||
/*
|
||||
* DSP Operations exported by platform Audio DSP driver.
|
||||
*/
|
||||
struct sst_ops {
|
||||
/* Shim IO */
|
||||
void (*write)(void __iomem *addr, u32 offset, u32 value);
|
||||
u32 (*read)(void __iomem *addr, u32 offset);
|
||||
|
||||
/* IRQ handlers */
|
||||
irqreturn_t (*irq_handler)(int irq, void *context);
|
||||
|
||||
/* SST init and free */
|
||||
int (*init)(struct sst_dsp *sst);
|
||||
void (*free)(struct sst_dsp *sst);
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP memory offsets and addresses.
|
||||
*/
|
||||
struct sst_addr {
|
||||
u32 sram0_base;
|
||||
u32 sram1_base;
|
||||
u32 w0_stat_sz;
|
||||
u32 w0_up_sz;
|
||||
void __iomem *lpe;
|
||||
void __iomem *shim;
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP Mailbox configuration.
|
||||
*/
|
||||
struct sst_mailbox {
|
||||
void __iomem *in_base;
|
||||
void __iomem *out_base;
|
||||
size_t in_size;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic SST Shim Interface.
|
||||
*/
|
||||
struct sst_dsp {
|
||||
|
||||
/* Shared for all platforms */
|
||||
|
||||
/* runtime */
|
||||
struct sst_dsp_device *sst_dev;
|
||||
spinlock_t spinlock; /* IPC locking */
|
||||
struct mutex mutex; /* DSP FW lock */
|
||||
struct device *dev;
|
||||
void *thread_context;
|
||||
int irq;
|
||||
u32 id;
|
||||
|
||||
/* operations */
|
||||
struct sst_ops *ops;
|
||||
|
||||
/* debug FS */
|
||||
struct dentry *debugfs_root;
|
||||
|
||||
/* base addresses */
|
||||
struct sst_addr addr;
|
||||
|
||||
/* mailbox */
|
||||
struct sst_mailbox mailbox;
|
||||
|
||||
/* SST FW files loaded and their modules */
|
||||
struct list_head module_list;
|
||||
|
||||
/* SKL data */
|
||||
|
||||
const char *fw_name;
|
||||
|
||||
/* To allocate CL dma buffers */
|
||||
struct skl_dsp_loader_ops dsp_ops;
|
||||
struct skl_dsp_fw_ops fw_ops;
|
||||
int sst_state;
|
||||
struct skl_cl_dev cl_dev;
|
||||
u32 intr_status;
|
||||
const struct firmware *fw;
|
||||
struct snd_dma_buffer dmab;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,250 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel Smart Sound Technology (SST) DSP Core Driver
|
||||
*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "sst-dsp.h"
|
||||
#include "sst-dsp-priv.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/intel-sst.h>
|
||||
|
||||
/* Internal generic low-level SST IO functions - can be overidden */
|
||||
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_shim32_write);
|
||||
|
||||
u32 sst_shim32_read(void __iomem *addr, u32 offset)
|
||||
{
|
||||
return readl(addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_shim32_read);
|
||||
|
||||
void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
|
||||
{
|
||||
writeq(value, addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_shim32_write64);
|
||||
|
||||
u64 sst_shim32_read64(void __iomem *addr, u32 offset)
|
||||
{
|
||||
return readq(addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_shim32_read64);
|
||||
|
||||
/* Public API */
|
||||
void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sst->spinlock, flags);
|
||||
sst->ops->write(sst->addr.shim, offset, value);
|
||||
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
|
||||
|
||||
u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&sst->spinlock, flags);
|
||||
val = sst->ops->read(sst->addr.shim, offset);
|
||||
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
|
||||
|
||||
void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
|
||||
{
|
||||
sst->ops->write(sst->addr.shim, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
|
||||
|
||||
u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
|
||||
{
|
||||
return sst->ops->read(sst->addr.shim, offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
|
||||
|
||||
int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
bool change;
|
||||
unsigned int old, new;
|
||||
u32 ret;
|
||||
|
||||
ret = sst_dsp_shim_read_unlocked(sst, offset);
|
||||
|
||||
old = ret;
|
||||
new = (old & (~mask)) | (value & mask);
|
||||
|
||||
change = (old != new);
|
||||
if (change)
|
||||
sst_dsp_shim_write_unlocked(sst, offset, new);
|
||||
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
|
||||
|
||||
/* This is for registers bits with attribute RWC */
|
||||
void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
unsigned int old, new;
|
||||
u32 ret;
|
||||
|
||||
ret = sst_dsp_shim_read_unlocked(sst, offset);
|
||||
|
||||
old = ret;
|
||||
new = (old & (~mask)) | (value & mask);
|
||||
|
||||
sst_dsp_shim_write_unlocked(sst, offset, new);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
|
||||
|
||||
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool change;
|
||||
|
||||
spin_lock_irqsave(&sst->spinlock, flags);
|
||||
change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
|
||||
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
|
||||
|
||||
/* This is for registers bits with attribute RWC */
|
||||
void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sst->spinlock, flags);
|
||||
sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
|
||||
spin_unlock_irqrestore(&sst->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
|
||||
|
||||
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
||||
u32 target, u32 time, char *operation)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned long timeout;
|
||||
int k = 0, s = 500;
|
||||
|
||||
/*
|
||||
* split the loop into sleeps of varying resolution. more accurately,
|
||||
* the range of wakeups are:
|
||||
* Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
|
||||
* Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
|
||||
* (usleep_range (500, 1000) and usleep_range(5000, 10000) are
|
||||
* both possible in this phase depending on whether k > 10 or not).
|
||||
* Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
|
||||
*/
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(time);
|
||||
while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
|
||||
&& time_before(jiffies, timeout)) {
|
||||
k++;
|
||||
if (k > 10)
|
||||
s = 5000;
|
||||
|
||||
usleep_range(s, 2*s);
|
||||
}
|
||||
|
||||
if ((reg & mask) == target) {
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
|
||||
reg, operation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n",
|
||||
reg, operation);
|
||||
return -ETIME;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
|
||||
|
||||
int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
|
||||
u32 outbox_offset, size_t outbox_size)
|
||||
{
|
||||
sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
|
||||
sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
|
||||
sst->mailbox.in_size = inbox_size;
|
||||
sst->mailbox.out_size = outbox_size;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
|
||||
|
||||
void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
trace_sst_ipc_outbox_write(bytes);
|
||||
|
||||
memcpy_toio(sst->mailbox.out_base, message, bytes);
|
||||
|
||||
for (i = 0; i < bytes; i += 4)
|
||||
trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
|
||||
|
||||
void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
trace_sst_ipc_outbox_read(bytes);
|
||||
|
||||
memcpy_fromio(message, sst->mailbox.out_base, bytes);
|
||||
|
||||
for (i = 0; i < bytes; i += 4)
|
||||
trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
|
||||
|
||||
void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
trace_sst_ipc_inbox_write(bytes);
|
||||
|
||||
memcpy_toio(sst->mailbox.in_base, message, bytes);
|
||||
|
||||
for (i = 0; i < bytes; i += 4)
|
||||
trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
|
||||
|
||||
void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
trace_sst_ipc_inbox_read(bytes);
|
||||
|
||||
memcpy_fromio(message, sst->mailbox.in_base, bytes);
|
||||
|
||||
for (i = 0; i < bytes; i += 4)
|
||||
trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Liam Girdwood");
|
||||
MODULE_DESCRIPTION("Intel SST Core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,61 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel Smart Sound Technology (SST) Core
|
||||
*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_SST_DSP_H
|
||||
#define __SOUND_SOC_SST_DSP_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
struct sst_dsp;
|
||||
|
||||
/*
|
||||
* SST Device.
|
||||
*
|
||||
* This structure is populated by the SST core driver.
|
||||
*/
|
||||
struct sst_dsp_device {
|
||||
/* Mandatory fields */
|
||||
struct sst_ops *ops;
|
||||
irqreturn_t (*thread)(int irq, void *context);
|
||||
void *thread_context;
|
||||
};
|
||||
|
||||
/* SHIM Read / Write */
|
||||
void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
|
||||
u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
|
||||
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value);
|
||||
void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value);
|
||||
|
||||
/* SHIM Read / Write Unlocked for callers already holding sst lock */
|
||||
void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
|
||||
u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
|
||||
int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value);
|
||||
void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
|
||||
u32 mask, u32 value);
|
||||
|
||||
/* Internal generic low-level SST IO functions - can be overidden */
|
||||
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
|
||||
u32 sst_shim32_read(void __iomem *addr, u32 offset);
|
||||
void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
|
||||
u64 sst_shim32_read64(void __iomem *addr, u32 offset);
|
||||
|
||||
/* Mailbox management */
|
||||
int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset,
|
||||
size_t inbox_size, u32 outbox_offset, size_t outbox_size);
|
||||
void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes);
|
||||
void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes);
|
||||
void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes);
|
||||
void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes);
|
||||
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
||||
u32 target, u32 time, char *operation);
|
||||
|
||||
#endif
|
||||
@@ -1,294 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel SST generic IPC Support
|
||||
*
|
||||
* Copyright (C) 2015, Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/asound.h>
|
||||
|
||||
#include "sst-dsp.h"
|
||||
#include "sst-dsp-priv.h"
|
||||
#include "sst-ipc.h"
|
||||
|
||||
/* IPC message timeout (msecs) */
|
||||
#define IPC_TIMEOUT_MSECS 300
|
||||
|
||||
#define IPC_EMPTY_LIST_SIZE 8
|
||||
|
||||
/* locks held by caller */
|
||||
static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc)
|
||||
{
|
||||
struct ipc_message *msg = NULL;
|
||||
|
||||
if (!list_empty(&ipc->empty_list)) {
|
||||
msg = list_first_entry(&ipc->empty_list, struct ipc_message,
|
||||
list);
|
||||
list_del(&msg->list);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int tx_wait_done(struct sst_generic_ipc *ipc,
|
||||
struct ipc_message *msg, struct sst_ipc_message *reply)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* wait for DSP completion (in all cases atm inc pending) */
|
||||
ret = wait_event_timeout(msg->waitq, msg->complete,
|
||||
msecs_to_jiffies(IPC_TIMEOUT_MSECS));
|
||||
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
if (ret == 0) {
|
||||
if (ipc->ops.shim_dbg != NULL)
|
||||
ipc->ops.shim_dbg(ipc, "message timeout");
|
||||
|
||||
list_del(&msg->list);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
|
||||
/* copy the data returned from DSP */
|
||||
if (reply) {
|
||||
reply->header = msg->rx.header;
|
||||
if (reply->data)
|
||||
memcpy(reply->data, msg->rx.data, msg->rx.size);
|
||||
}
|
||||
ret = msg->errno;
|
||||
}
|
||||
|
||||
list_add_tail(&msg->list, &ipc->empty_list);
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipc_tx_message(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request,
|
||||
struct sst_ipc_message *reply, int wait)
|
||||
{
|
||||
struct ipc_message *msg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
|
||||
msg = msg_get_empty(ipc);
|
||||
if (msg == NULL) {
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
msg->tx.header = request.header;
|
||||
msg->tx.size = request.size;
|
||||
msg->rx.header = 0;
|
||||
msg->rx.size = reply ? reply->size : 0;
|
||||
msg->wait = wait;
|
||||
msg->errno = 0;
|
||||
msg->pending = false;
|
||||
msg->complete = false;
|
||||
|
||||
if ((request.size) && (ipc->ops.tx_data_copy != NULL))
|
||||
ipc->ops.tx_data_copy(msg, request.data, request.size);
|
||||
|
||||
list_add_tail(&msg->list, &ipc->tx_list);
|
||||
schedule_work(&ipc->kwork);
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
|
||||
if (wait)
|
||||
return tx_wait_done(ipc, msg, reply);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msg_empty_list_init(struct sst_generic_ipc *ipc)
|
||||
{
|
||||
int i;
|
||||
|
||||
ipc->msg = kcalloc(IPC_EMPTY_LIST_SIZE, sizeof(struct ipc_message),
|
||||
GFP_KERNEL);
|
||||
if (ipc->msg == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
|
||||
ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL);
|
||||
if (ipc->msg[i].tx.data == NULL)
|
||||
goto free_mem;
|
||||
|
||||
ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL);
|
||||
if (ipc->msg[i].rx.data == NULL) {
|
||||
kfree(ipc->msg[i].tx.data);
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&ipc->msg[i].waitq);
|
||||
list_add(&ipc->msg[i].list, &ipc->empty_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_mem:
|
||||
while (i > 0) {
|
||||
kfree(ipc->msg[i-1].tx.data);
|
||||
kfree(ipc->msg[i-1].rx.data);
|
||||
--i;
|
||||
}
|
||||
kfree(ipc->msg);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void ipc_tx_msgs(struct work_struct *work)
|
||||
{
|
||||
struct sst_generic_ipc *ipc =
|
||||
container_of(work, struct sst_generic_ipc, kwork);
|
||||
struct ipc_message *msg;
|
||||
|
||||
spin_lock_irq(&ipc->dsp->spinlock);
|
||||
|
||||
while (!list_empty(&ipc->tx_list) && !ipc->pending) {
|
||||
/* if the DSP is busy, we will TX messages after IRQ.
|
||||
* also postpone if we are in the middle of processing
|
||||
* completion irq
|
||||
*/
|
||||
if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
|
||||
dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
|
||||
break;
|
||||
}
|
||||
|
||||
msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
|
||||
list_move(&msg->list, &ipc->rx_list);
|
||||
|
||||
if (ipc->ops.tx_msg != NULL)
|
||||
ipc->ops.tx_msg(ipc, msg);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&ipc->dsp->spinlock);
|
||||
}
|
||||
|
||||
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request, struct sst_ipc_message *reply)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* DSP maybe in lower power active state, so
|
||||
* check if the DSP supports DSP lp On method
|
||||
* if so invoke that before sending IPC
|
||||
*/
|
||||
if (ipc->ops.check_dsp_lp_on)
|
||||
if (ipc->ops.check_dsp_lp_on(ipc->dsp, true))
|
||||
return -EIO;
|
||||
|
||||
ret = ipc_tx_message(ipc, request, reply, 1);
|
||||
|
||||
if (ipc->ops.check_dsp_lp_on)
|
||||
if (ipc->ops.check_dsp_lp_on(ipc->dsp, false))
|
||||
return -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
|
||||
|
||||
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request)
|
||||
{
|
||||
return ipc_tx_message(ipc, request, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
|
||||
|
||||
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request, struct sst_ipc_message *reply)
|
||||
{
|
||||
return ipc_tx_message(ipc, request, reply, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm);
|
||||
|
||||
struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
|
||||
u64 header)
|
||||
{
|
||||
struct ipc_message *msg;
|
||||
u64 mask;
|
||||
|
||||
if (ipc->ops.reply_msg_match != NULL)
|
||||
header = ipc->ops.reply_msg_match(header, &mask);
|
||||
else
|
||||
mask = (u64)-1;
|
||||
|
||||
if (list_empty(&ipc->rx_list)) {
|
||||
dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n",
|
||||
header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(msg, &ipc->rx_list, list) {
|
||||
if ((msg->tx.header & mask) == header)
|
||||
return msg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg);
|
||||
|
||||
/* locks held by caller */
|
||||
void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
|
||||
struct ipc_message *msg)
|
||||
{
|
||||
msg->complete = true;
|
||||
|
||||
if (!msg->wait)
|
||||
list_add_tail(&msg->list, &ipc->empty_list);
|
||||
else
|
||||
wake_up(&msg->waitq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete);
|
||||
|
||||
int sst_ipc_init(struct sst_generic_ipc *ipc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&ipc->tx_list);
|
||||
INIT_LIST_HEAD(&ipc->rx_list);
|
||||
INIT_LIST_HEAD(&ipc->empty_list);
|
||||
init_waitqueue_head(&ipc->wait_txq);
|
||||
|
||||
ret = msg_empty_list_init(ipc);
|
||||
if (ret < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&ipc->kwork, ipc_tx_msgs);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_init);
|
||||
|
||||
void sst_ipc_fini(struct sst_generic_ipc *ipc)
|
||||
{
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&ipc->kwork);
|
||||
|
||||
if (ipc->msg) {
|
||||
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
|
||||
kfree(ipc->msg[i].tx.data);
|
||||
kfree(ipc->msg[i].rx.data);
|
||||
}
|
||||
kfree(ipc->msg);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_ipc_fini);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Jin Yao");
|
||||
MODULE_DESCRIPTION("Intel SST IPC generic");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,86 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel SST generic IPC Support
|
||||
*
|
||||
* Copyright (C) 2015, Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SST_GENERIC_IPC_H
|
||||
#define __SST_GENERIC_IPC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
struct sst_ipc_message {
|
||||
u64 header;
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct ipc_message {
|
||||
struct list_head list;
|
||||
struct sst_ipc_message tx;
|
||||
struct sst_ipc_message rx;
|
||||
|
||||
wait_queue_head_t waitq;
|
||||
bool pending;
|
||||
bool complete;
|
||||
bool wait;
|
||||
int errno;
|
||||
};
|
||||
|
||||
struct sst_generic_ipc;
|
||||
struct sst_dsp;
|
||||
|
||||
struct sst_plat_ipc_ops {
|
||||
void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *);
|
||||
void (*shim_dbg)(struct sst_generic_ipc *, const char *);
|
||||
void (*tx_data_copy)(struct ipc_message *, char *, size_t);
|
||||
u64 (*reply_msg_match)(u64 header, u64 *mask);
|
||||
bool (*is_dsp_busy)(struct sst_dsp *dsp);
|
||||
int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state);
|
||||
};
|
||||
|
||||
/* SST generic IPC data */
|
||||
struct sst_generic_ipc {
|
||||
struct device *dev;
|
||||
struct sst_dsp *dsp;
|
||||
|
||||
/* IPC messaging */
|
||||
struct list_head tx_list;
|
||||
struct list_head rx_list;
|
||||
struct list_head empty_list;
|
||||
wait_queue_head_t wait_txq;
|
||||
struct task_struct *tx_thread;
|
||||
struct work_struct kwork;
|
||||
bool pending;
|
||||
struct ipc_message *msg;
|
||||
int tx_data_max_size;
|
||||
int rx_data_max_size;
|
||||
|
||||
struct sst_plat_ipc_ops ops;
|
||||
};
|
||||
|
||||
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request, struct sst_ipc_message *reply);
|
||||
|
||||
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request);
|
||||
|
||||
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
|
||||
struct sst_ipc_message request, struct sst_ipc_message *reply);
|
||||
|
||||
struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
|
||||
u64 header);
|
||||
|
||||
void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
|
||||
struct ipc_message *msg);
|
||||
|
||||
int sst_ipc_init(struct sst_generic_ipc *ipc);
|
||||
void sst_ipc_fini(struct sst_generic_ipc *ipc);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user