Unverified Commit 7ce6ceeb authored by Cezary Rojewski's avatar Cezary Rojewski Committed by Mark Brown
Browse files

ASoC: Intel: avs: New IRQ handling implementation



The existing code can be both improved and simplified. To make this
change easier to manage, first add new implementation and then remove
deadcode in a separate patch.

Simplification achieved with:
- reduce the amount of resources requested by the driver i.e.: IPC and
  CLDMA request_irq() merged into one
- reduce the number of DSP ops from 2 to 1:
  irq_handler/thread() vs dsp_interrupt()
- drop ambiguity around CLDMA interrupt, let skl.c handle that
  explicitly as it is the only user

Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20240419084857.2719593-2-cezary.rojewski@intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 9be51470
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -8,11 +8,28 @@

#include <linux/devcoredump.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "messages.h"
#include "path.h"
#include "topology.h"

static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev)
{
	u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
	irqreturn_t ret = IRQ_NONE;

	if (adspis == UINT_MAX)
		return ret;

	if (adspis & AVS_ADSP_ADSPIS_IPC) {
		avs_skl_ipc_interrupt(adev);
		ret = IRQ_HANDLED;
	}

	return ret;
}

#ifdef CONFIG_DEBUG_FS
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
			u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
@@ -237,6 +254,7 @@ const struct avs_dsp_ops avs_apl_dsp_ops = {
	.power = avs_dsp_core_power,
	.reset = avs_dsp_core_reset,
	.stall = avs_dsp_core_stall,
	.dsp_interrupt = avs_apl_dsp_interrupt,
	.irq_handler = avs_irq_handler,
	.irq_thread = avs_skl_irq_thread,
	.int_control = avs_dsp_interrupt_control,
+3 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct avs_dsp_ops {
	int (* const power)(struct avs_dev *, u32, bool);
	int (* const reset)(struct avs_dev *, u32, bool);
	int (* const stall)(struct avs_dev *, u32, bool);
	irqreturn_t (* const dsp_interrupt)(struct avs_dev *);
	irqreturn_t (* const irq_handler)(struct avs_dev *);
	irqreturn_t (* const irq_thread)(struct avs_dev *);
	void (* const int_control)(struct avs_dev *, bool);
@@ -269,6 +270,8 @@ int avs_dsp_enable_d0ix(struct avs_dev *adev);

irqreturn_t avs_skl_irq_thread(struct avs_dev *adev);
irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev);
void avs_skl_ipc_interrupt(struct avs_dev *adev);
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev);
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
			u32 fifo_full_period, unsigned long resource_mask, u32 *priorities);
int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+11 −0
Original line number Diff line number Diff line
@@ -270,6 +270,17 @@ static irqreturn_t cldma_irq_handler(int irq, void *dev_id)
	return IRQ_HANDLED;
}

void hda_cldma_interrupt(struct hda_cldma *cl)
{
	/* disable CLDMA interrupt */
	snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);

	cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
	dev_dbg(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);

	complete(&cl->completion);
}

int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
		   unsigned int buffer_size)
{
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ int hda_cldma_reset(struct hda_cldma *cl);

void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size);
void hda_cldma_setup(struct hda_cldma *cl);
void hda_cldma_interrupt(struct hda_cldma *cl);
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
		   unsigned int buffer_size);
void hda_cldma_free(struct hda_cldma *cl);
+63 −0
Original line number Diff line number Diff line
@@ -42,10 +42,73 @@ irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev)
	return IRQ_HANDLED;
}

static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
{
	const struct avs_spec *spec = adev->spec;
	u32 hipc_ack, hipc_rsp;

	snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);

	hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
	hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);

	/* DSP acked host's request. */
	if (hipc_ack & spec->hipc->ack_done_mask) {
		complete(&adev->ipc->done_completion);

		/* Tell DSP it has our attention. */
		snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
				      spec->hipc->ack_done_mask);
	}

	/* DSP sent new response to process. */
	if (hipc_rsp & spec->hipc->rsp_busy_mask) {
		union avs_reply_msg msg;
		u32 hipctda;

		msg.primary = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR);
		msg.ext.val = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD);

		avs_dsp_process_response(adev, msg.val);

		/* Tell DSP we accepted its message. */
		snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR,
				      CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY);
		/* Ack this response. */
		snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA,
				      CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE);
		/* HW might have been clock gated, give some time for change to propagate. */
		snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda,
					 !(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000);
	}

	snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
}

irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev)
{
	u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
	irqreturn_t ret = IRQ_NONE;

	if (adspis == UINT_MAX)
		return ret;

	if (adspis & AVS_ADSP_ADSPIS_IPC) {
		avs_cnl_ipc_interrupt(adev);
		ret = IRQ_HANDLED;
	}

	return ret;
}

const struct avs_dsp_ops avs_cnl_dsp_ops = {
	.power = avs_dsp_core_power,
	.reset = avs_dsp_core_reset,
	.stall = avs_dsp_core_stall,
	.dsp_interrupt = avs_cnl_dsp_interrupt,
	.irq_handler = avs_irq_handler,
	.irq_thread = avs_cnl_irq_thread,
	.int_control = avs_dsp_interrupt_control,
Loading