mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 12:35:52 +02:00
ASoC: SOF: Intel: hda: fix MSI issues by merging ipc and stream irq handlers
The existing code uses two handlers for a shared edge-based MSI interrupts. In corner cases, interrupts are lost, leading to IPC timeouts. Those timeouts do not appear in legacy mode. This patch merges the two handlers into a single one. Follow-up patches will extend this work to SoundWire interrupts which are also shared with IPC and stream interrupts. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
This commit is contained in:
parent
2824abb095
commit
dbf48060e3
|
|
@ -42,7 +42,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
|
|||
.block_write = sof_block_write,
|
||||
|
||||
/* doorbell */
|
||||
.irq_handler = hda_dsp_ipc_irq_handler,
|
||||
.irq_thread = hda_dsp_ipc_irq_thread,
|
||||
|
||||
/* ipc */
|
||||
|
|
|
|||
|
|
@ -232,7 +232,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
|
|||
.block_write = sof_block_write,
|
||||
|
||||
/* doorbell */
|
||||
.irq_handler = hda_dsp_ipc_irq_handler,
|
||||
.irq_thread = cnl_ipc_irq_thread,
|
||||
|
||||
/* ipc */
|
||||
|
|
|
|||
|
|
@ -237,14 +237,14 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* is this IRQ for ADSP ? - we only care about IPC here */
|
||||
irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
|
||||
/* Check if it is an IPC and disable IPC interrupt if yes */
|
||||
bool check_ipc(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
int ret = IRQ_NONE;
|
||||
bool ret = false;
|
||||
u32 irq_status;
|
||||
|
||||
spin_lock(&sdev->hw_lock);
|
||||
/* The function can be called at irq thread, so use spin_lock_irq */
|
||||
spin_lock_irq(&sdev->hw_lock);
|
||||
|
||||
/* store status */
|
||||
irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
|
||||
|
|
@ -260,11 +260,11 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
|
|||
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
|
||||
HDA_DSP_REG_ADSPIC,
|
||||
HDA_DSP_ADSPIC_IPC, 0);
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&sdev->hw_lock);
|
||||
spin_unlock_irq(&sdev->hw_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -550,22 +550,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
|
||||
bool is_stream_irq(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct hdac_bus *bus = context;
|
||||
int ret = IRQ_WAKE_THREAD;
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
bool ret = true;
|
||||
u32 status;
|
||||
|
||||
spin_lock(&bus->reg_lock);
|
||||
/* The function can be called at irq thread, so use spin_lock_irq */
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
|
||||
status = snd_hdac_chip_readl(bus, INTSTS);
|
||||
dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status);
|
||||
|
||||
/* Register inaccessible, ignore it.*/
|
||||
if (status == 0xffffffff)
|
||||
ret = IRQ_NONE;
|
||||
ret = false;
|
||||
|
||||
spin_unlock(&bus->reg_lock);
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -603,7 +604,8 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
|
|||
|
||||
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
|
||||
{
|
||||
struct hdac_bus *bus = context;
|
||||
struct snd_sof_dev *sdev = context;
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
u32 rirb_status;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -402,6 +402,28 @@ static const struct sof_intel_dsp_desc
|
|||
return chip_info;
|
||||
}
|
||||
|
||||
irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
|
||||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
|
||||
if (check_ipc(sdev) || is_stream_irq(sdev))
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
|
||||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
|
||||
if (check_ipc(sdev))
|
||||
sof_ops(sdev)->irq_thread(irq, sdev);
|
||||
if (is_stream_irq(sdev))
|
||||
hda_dsp_stream_threaded_handler(irq, sdev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(sdev->dev);
|
||||
|
|
@ -506,9 +528,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
|||
*/
|
||||
if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) {
|
||||
dev_info(sdev->dev, "use msi interrupt mode\n");
|
||||
hdev->irq = pci_irq_vector(pci, 0);
|
||||
/* ipc irq number is the same of hda irq */
|
||||
sdev->ipc_irq = hdev->irq;
|
||||
sdev->ipc_irq = pci_irq_vector(pci, 0);
|
||||
/* initialised to "false" by kzalloc() */
|
||||
sdev->msi_enabled = true;
|
||||
}
|
||||
|
|
@ -519,28 +539,17 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
|||
* in IO-APIC mode, hda->irq and ipc_irq are using the same
|
||||
* irq number of pci->irq
|
||||
*/
|
||||
hdev->irq = pci->irq;
|
||||
sdev->ipc_irq = pci->irq;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq);
|
||||
ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt,
|
||||
hda_dsp_stream_threaded_handler,
|
||||
IRQF_SHARED, "AudioHDA", bus);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n",
|
||||
hdev->irq);
|
||||
goto free_irq_vector;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq);
|
||||
ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler,
|
||||
sof_ops(sdev)->irq_thread, IRQF_SHARED,
|
||||
"AudioDSP", sdev);
|
||||
ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_interrupt_handler,
|
||||
hda_dsp_interrupt_thread,
|
||||
IRQF_SHARED, "AudioDSP", sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n",
|
||||
sdev->ipc_irq);
|
||||
goto free_hda_irq;
|
||||
goto free_irq_vector;
|
||||
}
|
||||
|
||||
pci_set_master(pci);
|
||||
|
|
@ -571,8 +580,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
|||
|
||||
free_ipc_irq:
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
free_hda_irq:
|
||||
free_irq(hdev->irq, bus);
|
||||
free_irq_vector:
|
||||
if (sdev->msi_enabled)
|
||||
pci_free_irq_vectors(pci);
|
||||
|
|
@ -618,7 +625,6 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
|
|||
SOF_HDA_PPCTL_GPROCEN, 0);
|
||||
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
free_irq(hda->irq, bus);
|
||||
if (sdev->msi_enabled)
|
||||
pci_free_irq_vectors(pci);
|
||||
|
||||
|
|
|
|||
|
|
@ -406,8 +406,6 @@ struct sof_intel_hda_dev {
|
|||
/* the maximum number of streams (playback + capture) supported */
|
||||
u32 stream_max;
|
||||
|
||||
int irq;
|
||||
|
||||
/* PM related */
|
||||
bool l1_support_changed;/* during suspend, is L1SEN changed or not */
|
||||
|
||||
|
|
@ -511,11 +509,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
|
|||
struct snd_pcm_hw_params *params);
|
||||
int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
|
||||
struct hdac_ext_stream *stream, int cmd);
|
||||
irqreturn_t hda_dsp_stream_interrupt(int irq, void *context);
|
||||
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context);
|
||||
int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
|
||||
struct snd_dma_buffer *dmab,
|
||||
struct hdac_stream *stream);
|
||||
bool check_ipc(struct snd_sof_dev *sdev);
|
||||
bool is_stream_irq(struct snd_sof_dev *sdev);
|
||||
|
||||
struct hdac_ext_stream *
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
|
||||
|
|
@ -540,7 +539,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev);
|
|||
int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
|
||||
int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
|
||||
|
||||
irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context);
|
||||
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context);
|
||||
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user