Commit c4a62573 authored by Sebastian Reichel's avatar Sebastian Reichel

HSI: omap_ssi_port: switch to threaded pio irq

Move pio interrupt handler from tasklet into thread to
allow runtime_pm_get_sync calls without irq_safe being
set.
Signed-off-by: default avatarSebastian Reichel <sre@kernel.org>
Tested-by: default avatarPavel Machek <pavel@ucw.cz>
parent 927d3f8f
...@@ -76,7 +76,6 @@ struct omap_ssm_ctx { ...@@ -76,7 +76,6 @@ struct omap_ssm_ctx {
* @irq: IRQ number * @irq: IRQ number
* @wake_irq: IRQ number for incoming wake line (-1 if none) * @wake_irq: IRQ number for incoming wake line (-1 if none)
* @wake_gpio: GPIO number for incoming wake line (-1 if none) * @wake_gpio: GPIO number for incoming wake line (-1 if none)
* @pio_tasklet: Bottom half for PIO transfers and events
* @flags: flags to keep track of states * @flags: flags to keep track of states
* @wk_refcount: Reference count for output wake line * @wk_refcount: Reference count for output wake line
* @work: worker for starting TX * @work: worker for starting TX
...@@ -100,7 +99,6 @@ struct omap_ssi_port { ...@@ -100,7 +99,6 @@ struct omap_ssi_port {
unsigned int irq; unsigned int irq;
int wake_irq; int wake_irq;
struct gpio_desc *wake_gpio; struct gpio_desc *wake_gpio;
struct tasklet_struct pio_tasklet;
bool wktest:1; /* FIXME: HACK to be removed */ bool wktest:1; /* FIXME: HACK to be removed */
unsigned long flags; unsigned long flags;
unsigned int wk_refcount; unsigned int wk_refcount;
......
...@@ -877,7 +877,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue) ...@@ -877,7 +877,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
u32 reg; u32 reg;
u32 val; u32 val;
spin_lock(&omap_port->lock); spin_lock_bh(&omap_port->lock);
msg = list_first_entry(queue, struct hsi_msg, link); msg = list_first_entry(queue, struct hsi_msg, link);
if ((!msg->sgt.nents) || (!msg->sgt.sgl->length)) { if ((!msg->sgt.nents) || (!msg->sgt.sgl->length)) {
msg->actual_len = 0; msg->actual_len = 0;
...@@ -909,7 +909,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue) ...@@ -909,7 +909,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
(msg->ttype == HSI_MSG_WRITE))) { (msg->ttype == HSI_MSG_WRITE))) {
writel(val, omap_ssi->sys + writel(val, omap_ssi->sys +
SSI_MPU_STATUS_REG(port->num, 0)); SSI_MPU_STATUS_REG(port->num, 0));
spin_unlock(&omap_port->lock); spin_unlock_bh(&omap_port->lock);
return; return;
} }
...@@ -925,12 +925,12 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue) ...@@ -925,12 +925,12 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0)); writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
writel_relaxed(val, omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0)); writel_relaxed(val, omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
list_del(&msg->link); list_del(&msg->link);
spin_unlock(&omap_port->lock); spin_unlock_bh(&omap_port->lock);
msg->complete(msg); msg->complete(msg);
ssi_transfer(omap_port, queue); ssi_transfer(omap_port, queue);
} }
static void ssi_pio_tasklet(unsigned long ssi_port) static irqreturn_t ssi_pio_thread(int irq, void *ssi_port)
{ {
struct hsi_port *port = (struct hsi_port *)ssi_port; struct hsi_port *port = (struct hsi_port *)ssi_port;
struct hsi_controller *ssi = to_hsi_controller(port->device.parent); struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
...@@ -941,37 +941,29 @@ static void ssi_pio_tasklet(unsigned long ssi_port) ...@@ -941,37 +941,29 @@ static void ssi_pio_tasklet(unsigned long ssi_port)
u32 status_reg; u32 status_reg;
pm_runtime_get_sync(omap_port->pdev); pm_runtime_get_sync(omap_port->pdev);
status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
for (ch = 0; ch < omap_port->channels; ch++) { do {
if (status_reg & SSI_DATAACCEPT(ch)) status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
ssi_pio_complete(port, &omap_port->txqueue[ch]); status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
if (status_reg & SSI_DATAAVAILABLE(ch))
ssi_pio_complete(port, &omap_port->rxqueue[ch]);
}
if (status_reg & SSI_BREAKDETECTED)
ssi_break_complete(port);
if (status_reg & SSI_ERROROCCURED)
ssi_error(port);
status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0)); for (ch = 0; ch < omap_port->channels; ch++) {
status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0)); if (status_reg & SSI_DATAACCEPT(ch))
pm_runtime_put_sync(omap_port->pdev); ssi_pio_complete(port, &omap_port->txqueue[ch]);
if (status_reg & SSI_DATAAVAILABLE(ch))
ssi_pio_complete(port, &omap_port->rxqueue[ch]);
}
if (status_reg & SSI_BREAKDETECTED)
ssi_break_complete(port);
if (status_reg & SSI_ERROROCCURED)
ssi_error(port);
if (status_reg) status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
tasklet_hi_schedule(&omap_port->pio_tasklet); status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
else
enable_irq(omap_port->irq);
}
static irqreturn_t ssi_pio_isr(int irq, void *port) /* TODO: sleep if we retry? */
{ } while (status_reg);
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
tasklet_hi_schedule(&omap_port->pio_tasklet);
disable_irq_nosync(irq);
pm_runtime_put(omap_port->pdev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1023,10 +1015,8 @@ static int ssi_port_irq(struct hsi_port *port, struct platform_device *pd) ...@@ -1023,10 +1015,8 @@ static int ssi_port_irq(struct hsi_port *port, struct platform_device *pd)
return err; return err;
} }
omap_port->irq = err; omap_port->irq = err;
tasklet_init(&omap_port->pio_tasklet, ssi_pio_tasklet, err = devm_request_threaded_irq(&port->device, omap_port->irq, NULL,
(unsigned long)port); ssi_pio_thread, IRQF_ONESHOT, "SSI PORT", port);
err = devm_request_irq(&port->device, omap_port->irq, ssi_pio_isr,
0, "mpu_irq0", port);
if (err < 0) if (err < 0)
dev_err(&port->device, "Request IRQ %d failed (%d)\n", dev_err(&port->device, "Request IRQ %d failed (%d)\n",
omap_port->irq, err); omap_port->irq, err);
...@@ -1229,8 +1219,6 @@ static int ssi_port_remove(struct platform_device *pd) ...@@ -1229,8 +1219,6 @@ static int ssi_port_remove(struct platform_device *pd)
hsi_port_unregister_clients(port); hsi_port_unregister_clients(port);
tasklet_kill(&omap_port->pio_tasklet);
port->async = hsi_dummy_msg; port->async = hsi_dummy_msg;
port->setup = hsi_dummy_cl; port->setup = hsi_dummy_cl;
port->flush = hsi_dummy_cl; port->flush = hsi_dummy_cl;
......
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