Commit 4a98a6b2 authored by Bard Liao's avatar Bard Liao Committed by Vinod Koul

soundwire: intel/cadence: merge Soundwire interrupt handlers/threads

The existing code uses one pair of interrupt handler/thread per link
but at the hardware level the interrupt is shared. This works fine for
legacy PCI interrupts, but leads to timeouts in MSI (Message-Signaled
Interrupt) mode, likely due to edges being lost.

This patch unifies interrupt handling for all links. The dedicated
handler is removed since we use a common one for all shared interrupt
sources, and the thread function takes care of dealing with interrupt
sources. This partition follows the model used for the SOF IPC on
HDaudio platforms, where similar timeout issues were noticed and doing
all the interrupt handling/clearing in the thread improved
reliability/stability.

Validation results with 4 links active in parallel show a night-and-day
improvement with no timeouts noticed even during stress tests. Latency
and quality of service are not affected by the change - mostly because
events on a SoundWire link are throttled by the bus frame rate
(typically 8..48kHz).
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20200716150947.22119-8-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 8459cea7
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/workqueue.h>
#include "bus.h" #include "bus.h"
#include "cadence_master.h" #include "cadence_master.h"
...@@ -790,7 +791,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) ...@@ -790,7 +791,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
CDNS_MCP_INT_SLAVE_MASK, 0); CDNS_MCP_INT_SLAVE_MASK, 0);
int_status &= ~CDNS_MCP_INT_SLAVE_MASK; int_status &= ~CDNS_MCP_INT_SLAVE_MASK;
ret = IRQ_WAKE_THREAD; schedule_work(&cdns->work);
} }
cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status); cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);
...@@ -799,13 +800,15 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) ...@@ -799,13 +800,15 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
EXPORT_SYMBOL(sdw_cdns_irq); EXPORT_SYMBOL(sdw_cdns_irq);
/** /**
* sdw_cdns_thread() - Cadence irq thread handler * To update slave status in a work since we will need to handle
* @irq: irq number * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
* @dev_id: irq context * process.
* @work: cdns worker thread
*/ */
irqreturn_t sdw_cdns_thread(int irq, void *dev_id) static void cdns_update_slave_status_work(struct work_struct *work)
{ {
struct sdw_cdns *cdns = dev_id; struct sdw_cdns *cdns =
container_of(work, struct sdw_cdns, work);
u32 slave0, slave1; u32 slave0, slave1;
dev_dbg_ratelimited(cdns->dev, "Slave status change\n"); dev_dbg_ratelimited(cdns->dev, "Slave status change\n");
...@@ -822,9 +825,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id) ...@@ -822,9 +825,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
cdns_updatel(cdns, CDNS_MCP_INTMASK, cdns_updatel(cdns, CDNS_MCP_INTMASK,
CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK); CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);
return IRQ_HANDLED;
} }
EXPORT_SYMBOL(sdw_cdns_thread);
/* /*
* init routines * init routines
...@@ -1427,6 +1428,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns) ...@@ -1427,6 +1428,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns)
init_completion(&cdns->tx_complete); init_completion(&cdns->tx_complete);
cdns->bus.port_ops = &cdns_port_ops; cdns->bus.port_ops = &cdns_port_ops;
INIT_WORK(&cdns->work, cdns_update_slave_status_work);
return 0; return 0;
} }
EXPORT_SYMBOL(sdw_cdns_probe); EXPORT_SYMBOL(sdw_cdns_probe);
......
...@@ -129,6 +129,10 @@ struct sdw_cdns { ...@@ -129,6 +129,10 @@ struct sdw_cdns {
bool link_up; bool link_up;
unsigned int msg_count; unsigned int msg_count;
struct work_struct work;
struct list_head list;
}; };
#define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus) #define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus)
......
...@@ -1258,21 +1258,7 @@ static int intel_master_probe(struct platform_device *pdev) ...@@ -1258,21 +1258,7 @@ static int intel_master_probe(struct platform_device *pdev)
"SoundWire master %d is disabled, will be ignored\n", "SoundWire master %d is disabled, will be ignored\n",
bus->link_id); bus->link_id);
/* Acquire IRQ */
ret = request_threaded_irq(sdw->link_res->irq,
sdw_cdns_irq, sdw_cdns_thread,
IRQF_SHARED, KBUILD_MODNAME, cdns);
if (ret < 0) {
dev_err(dev, "unable to grab IRQ %d, disabling device\n",
sdw->link_res->irq);
goto err_init;
}
return 0; return 0;
err_init:
sdw_bus_master_delete(bus);
return ret;
} }
int intel_master_startup(struct platform_device *pdev) int intel_master_startup(struct platform_device *pdev)
...@@ -1344,7 +1330,6 @@ static int intel_master_remove(struct platform_device *pdev) ...@@ -1344,7 +1330,6 @@ static int intel_master_remove(struct platform_device *pdev)
if (!bus->prop.hw_disabled) { if (!bus->prop.hw_disabled) {
intel_debugfs_exit(sdw); intel_debugfs_exit(sdw);
sdw_cdns_enable_interrupt(cdns, false); sdw_cdns_enable_interrupt(cdns, false);
free_irq(sdw->link_res->irq, sdw);
snd_soc_unregister_component(dev); snd_soc_unregister_component(dev);
} }
sdw_bus_master_delete(bus); sdw_bus_master_delete(bus);
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
* @dev: device implementing hw_params and free callbacks * @dev: device implementing hw_params and free callbacks
* @shim_lock: mutex to handle access to shared SHIM registers * @shim_lock: mutex to handle access to shared SHIM registers
* @shim_mask: global pointer to check SHIM register initialization * @shim_mask: global pointer to check SHIM register initialization
* @cdns: Cadence master descriptor
* @list: used to walk-through all masters exposed by the same controller
*/ */
struct sdw_intel_link_res { struct sdw_intel_link_res {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -29,6 +31,8 @@ struct sdw_intel_link_res { ...@@ -29,6 +31,8 @@ struct sdw_intel_link_res {
struct device *dev; struct device *dev;
struct mutex *shim_lock; /* protect shared registers */ struct mutex *shim_lock; /* protect shared registers */
u32 *shim_mask; u32 *shim_mask;
struct sdw_cdns *cdns;
struct list_head list;
}; };
struct sdw_intel { struct sdw_intel {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -166,6 +167,19 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) ...@@ -166,6 +167,19 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
} }
EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
irqreturn_t sdw_intel_thread(int irq, void *dev_id)
{
struct sdw_intel_ctx *ctx = dev_id;
struct sdw_intel_link_res *link;
list_for_each_entry(link, &ctx->link_list, list)
sdw_cdns_irq(irq, link->cdns);
sdw_intel_enable_irq(ctx->mmio_base, true);
return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
static struct sdw_intel_ctx static struct sdw_intel_ctx
*sdw_intel_probe_controller(struct sdw_intel_res *res) *sdw_intel_probe_controller(struct sdw_intel_res *res)
{ {
...@@ -209,6 +223,8 @@ static struct sdw_intel_ctx ...@@ -209,6 +223,8 @@ static struct sdw_intel_ctx
link = ctx->links; link = ctx->links;
link_mask = ctx->link_mask; link_mask = ctx->link_mask;
INIT_LIST_HEAD(&ctx->link_list);
/* Create SDW Master devices */ /* Create SDW Master devices */
for (i = 0; i < count; i++, link++) { for (i = 0; i < count; i++, link++) {
if (!(link_mask & BIT(i))) { if (!(link_mask & BIT(i))) {
...@@ -246,6 +262,9 @@ static struct sdw_intel_ctx ...@@ -246,6 +262,9 @@ static struct sdw_intel_ctx
goto err; goto err;
} }
link->pdev = pdev; link->pdev = pdev;
link->cdns = platform_get_drvdata(pdev);
list_add_tail(&link->list, &ctx->link_list);
} }
return ctx; return ctx;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment