Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1425770 > unrolled thread
| Started by | Sebastian Reichel <sre@kernel.org> |
|---|---|
| First post | 2016-06-18 18:30 +0200 |
| Last post | 2016-06-19 00:10 +0200 |
| Articles | 18 — 3 participants |
Back to article view | Back to linux.kernel
[RFC 00/19] Runtime PM fixes for omap-ssi Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 14/19] HSI: omap_ssi_port: avoid calling runtime_pm_*_sync inside spinlock Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 15/19] HSI: omap_ssi_port: replace pm_runtime_put_sync with non-sync variant Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 02/19] HSI: omap_ssi: do not reset module Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
Re: [RFC 02/19] HSI: omap_ssi: do not reset module Tony Lindgren <tony@atomide.com> - 2016-06-21 13:50 +0200
[RFC 12/19] HSI: omap_ssi_port: switch to threaded pio irq Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 13/19] HSI: omap_ssi_port: avoid pm_runtime_get_sync in ssi_start_dma and ssi_start_pio Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 11/19] HSI: omap_ssi_core: remove pm_runtime_get_sync call from tasklet Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 06/19] HSI: omap_ssi: convert cawake irq handler to thread Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 05/19] HSI: ssi_protocol: fix ssip_xmit invocation Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 18/19] HSI: omap_ssi_port: use rpm autosuspend API Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 08/19] HSI: core: switch port event notifier from atomic to blocking Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 07/19] HSI: omap_ssi_port: replace wkin_cken with atomic bitmap operations Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:30 +0200
[RFC 09/19] HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime calls Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:40 +0200
[RFC 01/19] HSI: omap_ssi_port: remove useless newline Sebastian Reichel <sre@kernel.org> - 2016-06-18 18:40 +0200
Re: [RFC 00/19] Runtime PM fixes for omap-ssi Pavel Machek <pavel@ucw.cz> - 2016-06-18 21:00 +0200
Re: [RFC 00/19] Runtime PM fixes for omap-ssi Sebastian Reichel <sre@kernel.org> - 2016-06-18 22:30 +0200
Re: [RFC 00/19] Runtime PM fixes for omap-ssi Pavel Machek <pavel@ucw.cz> - 2016-06-19 00:10 +0200
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 00/19] Runtime PM fixes for omap-ssi |
| Message-ID | <rLri9-6py-7@gated-at.bofh.it> |
Hi,
This series fixes runtime PM for omap-ssi, so that
the OMAP SoC can idle correctly. After applying the
series, the SSI module correctly goes into idle if
phonet0 interface is not configured or if it's
used by ofono (*). Apart from me Pavel Machek did
some testing of my devel branch [0] and reported,
that he was able to get the phone into full idle.
Note: I did my testing with kernel flashing over USB, so
idle is broken. But I found the bit in cm_idlest1_core,
that stands for SSI blocking status: 0x00800000 (documented
as "reserved" in the public TRM).
(*) "ifconfig phonet0 up" will result in blocking ssi module
until modem setup has finished (data communication via
phonet0 device), since it enables ssi wakelines.
[0] https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=runtime-pm-fixes
-- Sebastian
Sebastian Reichel (19):
HSI: omap_ssi_port: remove useless newline
HSI: omap_ssi: do not reset module
HSI: ssi_protocol: avoid ssi_waketest call with held spinlock
HSI: ssi_protocol: replace spin_lock with spin_lock_bh
HSI: ssi_protocol: fix ssip_xmit invocation
HSI: omap_ssi: convert cawake irq handler to thread
HSI: omap_ssi_port: replace wkin_cken with atomic bitmap operations
HSI: core: switch port event notifier from atomic to blocking
HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime
calls
HSI: omap_ssi_core: use pm_runtime_put instead of pm_runtime_put_sync
HSI: omap_ssi_core: remove pm_runtime_get_sync call from tasklet
HSI: omap_ssi_port: switch to threaded pio irq
HSI: omap_ssi_port: avoid pm_runtime_get_sync in ssi_start_dma and
ssi_start_pio
HSI: omap_ssi_port: avoid calling runtime_pm_*_sync inside spinlock
HSI: omap_ssi_port: replace pm_runtime_put_sync with non-sync variant
HSI: omap_ssi_port: ensure clocks are kept enabled during transfer
HSI: omap_ssi: call msg->complete() from process context
HSI: omap_ssi_port: use rpm autosuspend API
HSI: omap_ssi: drop pm_runtime_irq_safe
drivers/hsi/clients/ssi_protocol.c | 110 +++++++++-------
drivers/hsi/controllers/omap_ssi.h | 18 +--
drivers/hsi/controllers/omap_ssi_core.c | 46 +++----
drivers/hsi/controllers/omap_ssi_port.c | 226 ++++++++++++++++++--------------
drivers/hsi/hsi_core.c | 8 +-
include/linux/hsi/hsi.h | 2 +-
6 files changed, 229 insertions(+), 181 deletions(-)
--
2.8.1
[toc] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 14/19] HSI: omap_ssi_port: avoid calling runtime_pm_*_sync inside spinlock |
| Message-ID | <rLria-6py-41@gated-at.bofh.it> |
| In reply to | #1425770 |
runtime_pm_*_sync can block when irq_safe flag is removed
from omap-ssi driver, so it may not be called while a
spinlock is held.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_port.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index f7ed59ba3b2c..92064221dbab 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -767,13 +767,12 @@ static int ssi_release(struct hsi_client *cl)
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
- spin_lock_bh(&omap_port->lock);
pm_runtime_get_sync(omap_port->pdev);
+ spin_lock_bh(&omap_port->lock);
/* Stop all the pending DMA requests for that client */
ssi_cleanup_gdd(ssi, cl);
/* Now cleanup all the queues */
ssi_cleanup_queues(cl);
- pm_runtime_put_sync(omap_port->pdev);
/* If it is the last client of the port, do extra checks and cleanup */
if (port->claimed <= 1) {
/*
@@ -782,15 +781,16 @@ static int ssi_release(struct hsi_client *cl)
*/
if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags))
pm_runtime_put_sync(omap_port->pdev);
- pm_runtime_get_sync(omap_port->pdev);
+ pm_runtime_get(omap_port->pdev);
/* Stop any SSI TX/RX without a client */
ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
omap_port->sst.mode = SSI_MODE_SLEEP;
omap_port->ssr.mode = SSI_MODE_SLEEP;
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
WARN_ON(omap_port->wk_refcount != 0);
}
spin_unlock_bh(&omap_port->lock);
+ pm_runtime_put_sync(omap_port->pdev);
return 0;
}
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 15/19] HSI: omap_ssi_port: replace pm_runtime_put_sync with non-sync variant |
| Message-ID | <rLria-6py-33@gated-at.bofh.it> |
| In reply to | #1425770 |
There is no need to wait for hardware to really reach idle states,
so just release runtime PM asynchronously.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_port.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 92064221dbab..aef5a8666d48 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -375,7 +375,7 @@ static int ssi_async_break(struct hsi_msg *msg)
spin_unlock_bh(&omap_port->lock);
}
out:
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
return err;
}
@@ -515,7 +515,7 @@ static int ssi_setup(struct hsi_client *cl)
omap_port->ssr.mode = cl->rx_cfg.mode;
out:
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
return err;
}
@@ -546,7 +546,7 @@ static int ssi_flush(struct hsi_client *cl)
continue;
writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
if (msg->ttype == HSI_MSG_READ)
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
omap_ssi->gdd_trn[i].msg = NULL;
}
/* Flush all SST buffers */
@@ -570,7 +570,7 @@ static int ssi_flush(struct hsi_client *cl)
for (i = 0; i < omap_port->channels; i++) {
/* Release write clocks */
if (!list_empty(&omap_port->txqueue[i]))
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
ssi_flush_queue(&omap_port->txqueue[i], NULL);
ssi_flush_queue(&omap_port->rxqueue[i], NULL);
}
@@ -580,7 +580,7 @@ static int ssi_flush(struct hsi_client *cl)
pinctrl_pm_select_default_state(omap_port->pdev);
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
return 0;
}
@@ -687,7 +687,7 @@ static void ssi_cleanup_queues(struct hsi_client *cl)
txbufstate |= (1 << i);
status |= SSI_DATAACCEPT(i);
/* Release the clocks writes, also GDD ones */
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
}
ssi_flush_queue(&omap_port->txqueue[i], cl);
}
@@ -742,7 +742,7 @@ static void ssi_cleanup_gdd(struct hsi_controller *ssi, struct hsi_client *cl)
* ssi_cleanup_queues
*/
if (msg->ttype == HSI_MSG_READ)
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
omap_ssi->gdd_trn[i].msg = NULL;
}
tmp = readl_relaxed(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
@@ -790,7 +790,7 @@ static int ssi_release(struct hsi_client *cl)
WARN_ON(omap_port->wk_refcount != 0);
}
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
return 0;
}
@@ -937,7 +937,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
reg = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
if (msg->ttype == HSI_MSG_WRITE) {
/* Release clocks for write transfer */
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
}
reg &= ~val;
writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 02/19] HSI: omap_ssi: do not reset module |
| Message-ID | <rLrib-6py-51@gated-at.bofh.it> |
| In reply to | #1425770 |
module reset and power management rule setup
is already done by hwmod. Remove this cruft,
which predates hwmod.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi.h | 2 --
drivers/hsi/controllers/omap_ssi_core.c | 19 +------------------
2 files changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
index 7b4dec2c69ff..ba2f92722c09 100644
--- a/drivers/hsi/controllers/omap_ssi.h
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -138,7 +138,6 @@ struct gdd_trn {
* @fck_rate: clock rate
* @loss_count: To follow if we need to restore context or not
* @max_speed: Maximum TX speed (Kb/s) set by the clients.
- * @sysconfig: SSI controller saved context
* @gdd_gcr: SSI GDD saved context
* @get_loss: Pointer to omap_pm_get_dev_context_loss_count, if any
* @port: Array of pointers of the ports of the controller
@@ -158,7 +157,6 @@ struct omap_ssi_controller {
u32 loss_count;
u32 max_speed;
/* OMAP SSI Controller context */
- u32 sysconfig;
u32 gdd_gcr;
int (*get_loss)(struct device *dev);
struct omap_ssi_port **port;
diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c
index a3e0febfb64a..54943e439488 100644
--- a/drivers/hsi/controllers/omap_ssi_core.c
+++ b/drivers/hsi/controllers/omap_ssi_core.c
@@ -452,8 +452,6 @@ out_err:
static int ssi_hw_init(struct hsi_controller *ssi)
{
struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
- unsigned int i;
- u32 val;
int err;
err = pm_runtime_get_sync(ssi->device.parent);
@@ -461,27 +459,12 @@ static int ssi_hw_init(struct hsi_controller *ssi)
dev_err(&ssi->device, "runtime PM failed %d\n", err);
return err;
}
- /* Reseting SSI controller */
- writel_relaxed(SSI_SOFTRESET, omap_ssi->sys + SSI_SYSCONFIG_REG);
- val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
- for (i = 0; ((i < 20) && !(val & SSI_RESETDONE)); i++) {
- msleep(20);
- val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
- }
- if (!(val & SSI_RESETDONE)) {
- dev_err(&ssi->device, "SSI HW reset failed\n");
- pm_runtime_put_sync(ssi->device.parent);
- return -EIO;
- }
/* Reseting GDD */
writel_relaxed(SSI_SWRESET, omap_ssi->gdd + SSI_GDD_GRST_REG);
/* Get FCK rate in KHz */
omap_ssi->fck_rate = DIV_ROUND_CLOSEST(ssi_get_clk_rate(ssi), 1000);
dev_dbg(&ssi->device, "SSI fck rate %lu KHz\n", omap_ssi->fck_rate);
- /* Set default PM settings */
- val = SSI_AUTOIDLE | SSI_SIDLEMODE_SMART | SSI_MIDLEMODE_SMART;
- writel_relaxed(val, omap_ssi->sys + SSI_SYSCONFIG_REG);
- omap_ssi->sysconfig = val;
+
writel_relaxed(SSI_CLK_AUTOGATING_ON, omap_ssi->sys + SSI_GDD_GCR_REG);
omap_ssi->gdd_gcr = SSI_CLK_AUTOGATING_ON;
pm_runtime_put_sync(ssi->device.parent);
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Tony Lindgren <tony@atomide.com> |
|---|---|
| Date | 2016-06-21 13:50 +0200 |
| Subject | Re: [RFC 02/19] HSI: omap_ssi: do not reset module |
| Message-ID | <rMslQ-5hj-21@gated-at.bofh.it> |
| In reply to | #1425775 |
* Sebastian Reichel <sre@kernel.org> [160618 09:30]: > module reset and power management rule setup > is already done by hwmod. Remove this cruft, > which predates hwmod. Sounds good to me: Acked-by: Tony Lindgren <tony@atomide.com>
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 12/19] HSI: omap_ssi_port: switch to threaded pio irq |
| Message-ID | <rLria-6py-37@gated-at.bofh.it> |
| In reply to | #1425770 |
Move pio interrupt handler from tasklet into thread to
allow runtime_pm_get_sync calls without irq_safe being
set.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi.h | 2 --
drivers/hsi/controllers/omap_ssi_port.c | 60 +++++++++++++--------------------
2 files changed, 24 insertions(+), 38 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
index 5467f61e5086..99143f4f8837 100644
--- a/drivers/hsi/controllers/omap_ssi.h
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -76,7 +76,6 @@ struct omap_ssm_ctx {
* @irq: IRQ number
* @wake_irq: IRQ 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
* @wk_refcount: Reference count for output wake line
* @work: worker for starting TX
@@ -100,7 +99,6 @@ struct omap_ssi_port {
unsigned int irq;
int wake_irq;
struct gpio_desc *wake_gpio;
- struct tasklet_struct pio_tasklet;
bool wktest:1; /* FIXME: HACK to be removed */
unsigned long flags;
unsigned int wk_refcount;
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index cc56d0ee82a2..f62f0c482cea 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -877,7 +877,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
u32 reg;
u32 val;
- spin_lock(&omap_port->lock);
+ spin_lock_bh(&omap_port->lock);
msg = list_first_entry(queue, struct hsi_msg, link);
if ((!msg->sgt.nents) || (!msg->sgt.sgl->length)) {
msg->actual_len = 0;
@@ -909,7 +909,7 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
(msg->ttype == HSI_MSG_WRITE))) {
writel(val, omap_ssi->sys +
SSI_MPU_STATUS_REG(port->num, 0));
- spin_unlock(&omap_port->lock);
+ spin_unlock_bh(&omap_port->lock);
return;
}
@@ -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(val, omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
list_del(&msg->link);
- spin_unlock(&omap_port->lock);
+ spin_unlock_bh(&omap_port->lock);
msg->complete(msg);
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_controller *ssi = to_hsi_controller(port->device.parent);
@@ -941,37 +941,29 @@ static void ssi_pio_tasklet(unsigned long ssi_port)
u32 status_reg;
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++) {
- if (status_reg & SSI_DATAACCEPT(ch))
- 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);
+ do {
+ status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
+ status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
- status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
- status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
- pm_runtime_put_sync(omap_port->pdev);
+ for (ch = 0; ch < omap_port->channels; ch++) {
+ if (status_reg & SSI_DATAACCEPT(ch))
+ 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)
- tasklet_hi_schedule(&omap_port->pio_tasklet);
- else
- enable_irq(omap_port->irq);
-}
+ status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
+ status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
-static irqreturn_t ssi_pio_isr(int irq, void *port)
-{
- struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
-
- tasklet_hi_schedule(&omap_port->pio_tasklet);
- disable_irq_nosync(irq);
+ /* TODO: sleep if we retry? */
+ } while (status_reg);
+ pm_runtime_put(omap_port->pdev);
return IRQ_HANDLED;
}
@@ -1023,10 +1015,8 @@ static int ssi_port_irq(struct hsi_port *port, struct platform_device *pd)
return err;
}
omap_port->irq = err;
- tasklet_init(&omap_port->pio_tasklet, ssi_pio_tasklet,
- (unsigned long)port);
- err = devm_request_irq(&port->device, omap_port->irq, ssi_pio_isr,
- 0, "mpu_irq0", port);
+ err = devm_request_threaded_irq(&port->device, omap_port->irq, NULL,
+ ssi_pio_thread, IRQF_ONESHOT, "SSI PORT", port);
if (err < 0)
dev_err(&port->device, "Request IRQ %d failed (%d)\n",
omap_port->irq, err);
@@ -1229,8 +1219,6 @@ static int ssi_port_remove(struct platform_device *pd)
hsi_port_unregister_clients(port);
- tasklet_kill(&omap_port->pio_tasklet);
-
port->async = hsi_dummy_msg;
port->setup = hsi_dummy_cl;
port->flush = hsi_dummy_cl;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 13/19] HSI: omap_ssi_port: avoid pm_runtime_get_sync in ssi_start_dma and ssi_start_pio |
| Message-ID | <rLria-6py-39@gated-at.bofh.it> |
| In reply to | #1425770 |
These functions may be called from atomic context,
so avoid synchronous runtime pm calls.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_port.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index f62f0c482cea..f7ed59ba3b2c 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -225,11 +225,21 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
u32 d_addr;
u32 tmp;
+ /* Hold clocks during the transfer */
+ pm_runtime_get(omap_port->pdev);
+
+ if (!pm_runtime_active(omap_port->pdev)) {
+ dev_warn(&port->device, "ssi_start_dma called without runtime PM!\n");
+ pm_runtime_put(omap_port->pdev);
+ return -EREMOTEIO;
+ }
+
if (msg->ttype == HSI_MSG_READ) {
err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,
DMA_FROM_DEVICE);
if (err < 0) {
dev_dbg(&ssi->device, "DMA map SG failed !\n");
+ pm_runtime_put(omap_port->pdev);
return err;
}
csdp = SSI_DST_BURST_4x32_BIT | SSI_DST_MEMORY_PORT |
@@ -246,6 +256,7 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
DMA_TO_DEVICE);
if (err < 0) {
dev_dbg(&ssi->device, "DMA map SG failed !\n");
+ pm_runtime_put(omap_port->pdev);
return err;
}
csdp = SSI_SRC_BURST_4x32_BIT | SSI_SRC_MEMORY_PORT |
@@ -261,9 +272,6 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
dev_dbg(&ssi->device, "lch %d cdsp %08x ccr %04x s_addr %08x d_addr %08x\n",
lch, csdp, ccr, s_addr, d_addr);
- /* Hold clocks during the transfer */
- pm_runtime_get_sync(omap_port->pdev);
-
writew_relaxed(csdp, gdd + SSI_GDD_CSDP_REG(lch));
writew_relaxed(SSI_BLOCK_IE | SSI_TOUT_IE, gdd + SSI_GDD_CICR_REG(lch));
writel_relaxed(d_addr, gdd + SSI_GDD_CDSA_REG(lch));
@@ -290,11 +298,18 @@ static int ssi_start_pio(struct hsi_msg *msg)
struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
u32 val;
- pm_runtime_get_sync(omap_port->pdev);
+ pm_runtime_get(omap_port->pdev);
+
+ if (!pm_runtime_active(omap_port->pdev)) {
+ dev_warn(&port->device, "ssi_start_pio called without runtime PM!\n");
+ pm_runtime_put(omap_port->pdev);
+ return -EREMOTEIO;
+ }
+
if (msg->ttype == HSI_MSG_WRITE) {
val = SSI_DATAACCEPT(msg->channel);
/* Hold clocks for pio writes */
- pm_runtime_get_sync(omap_port->pdev);
+ pm_runtime_get(omap_port->pdev);
} else {
val = SSI_DATAAVAILABLE(msg->channel) | SSI_ERROROCCURED;
}
@@ -302,7 +317,7 @@ static int ssi_start_pio(struct hsi_msg *msg)
msg->ttype ? "write" : "read");
val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
writel(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put(omap_port->pdev);
msg->actual_len = 0;
msg->status = HSI_STATUS_PROCEEDING;
@@ -388,6 +403,8 @@ static int ssi_async(struct hsi_msg *msg)
queue = &omap_port->rxqueue[msg->channel];
}
msg->status = HSI_STATUS_QUEUED;
+
+ pm_runtime_get_sync(omap_port->pdev);
spin_lock_bh(&omap_port->lock);
list_add_tail(&msg->link, queue);
err = ssi_start_transfer(queue);
@@ -396,6 +413,7 @@ static int ssi_async(struct hsi_msg *msg)
msg->status = HSI_STATUS_ERROR;
}
spin_unlock_bh(&omap_port->lock);
+ pm_runtime_put(omap_port->pdev);
dev_dbg(&port->device, "msg status %d ttype %d ch %d\n",
msg->status, msg->ttype, msg->channel);
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 11/19] HSI: omap_ssi_core: remove pm_runtime_get_sync call from tasklet |
| Message-ID | <rLrib-6py-47@gated-at.bofh.it> |
| In reply to | #1425770 |
We may not call pm_runtime_get_sync() from tasklet, since
it can block once pm_runtime_irq_safe is removed for omap-ssi.
Since irq can should only be created for a running device,
we assume, that the device is already running and use non-
synchronous API instead.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_core.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c
index 618db80577c3..79562ce65579 100644
--- a/drivers/hsi/controllers/omap_ssi_core.c
+++ b/drivers/hsi/controllers/omap_ssi_core.c
@@ -255,7 +255,13 @@ static void ssi_gdd_tasklet(unsigned long dev)
unsigned int lch;
u32 status_reg;
- pm_runtime_get_sync(ssi->device.parent);
+ pm_runtime_get(ssi->device.parent);
+
+ if (!pm_runtime_active(ssi->device.parent)) {
+ dev_warn(ssi->device.parent, "ssi_gdd_tasklet called without runtime PM!\n");
+ pm_runtime_put(ssi->device.parent);
+ return;
+ }
status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 06/19] HSI: omap_ssi: convert cawake irq handler to thread |
| Message-ID | <rLrib-6py-61@gated-at.bofh.it> |
| In reply to | #1425770 |
Convert cawake interrupt handler from tasklet to
threaded interrupt handler in preparation of
blocking runtime_pm calls.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi.h | 2 --
drivers/hsi/controllers/omap_ssi_core.c | 4 ++--
drivers/hsi/controllers/omap_ssi_port.c | 21 ++++++---------------
3 files changed, 8 insertions(+), 19 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
index ba2f92722c09..88a523902a8f 100644
--- a/drivers/hsi/controllers/omap_ssi.h
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -75,7 +75,6 @@ struct omap_ssm_ctx {
* @wake_irq: IRQ 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
- * @wake_tasklet: Bottom half for incoming wake events
* @wkin_cken: Keep track of clock references due to the incoming wake line
* @wk_refcount: Reference count for output wake line
* @sys_mpu_enable: Context for the interrupt enable register for irq 0
@@ -99,7 +98,6 @@ struct omap_ssi_port {
int wake_irq;
struct gpio_desc *wake_gpio;
struct tasklet_struct pio_tasklet;
- struct tasklet_struct wake_tasklet;
bool wktest:1; /* FIXME: HACK to be removed */
bool wkin_cken:1; /* Workaround */
unsigned int wk_refcount;
diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c
index 54943e439488..a463420a0810 100644
--- a/drivers/hsi/controllers/omap_ssi_core.c
+++ b/drivers/hsi/controllers/omap_ssi_core.c
@@ -312,7 +312,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
continue;
/* Workaround for SWBREAK + CAwake down race in CMT */
- tasklet_disable(&omap_port->wake_tasklet);
+ disable_irq(omap_port->wake_irq);
/* stop all ssi communication */
pinctrl_pm_select_idle_state(omap_port->pdev);
@@ -338,7 +338,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
/* resume ssi communication */
pinctrl_pm_select_default_state(omap_port->pdev);
- tasklet_enable(&omap_port->wake_tasklet);
+ enable_irq(omap_port->wake_irq);
}
break;
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 38388442e310..9001b06312c3 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -966,7 +966,7 @@ static irqreturn_t ssi_pio_isr(int irq, void *port)
return IRQ_HANDLED;
}
-static void ssi_wake_tasklet(unsigned long ssi_port)
+static irqreturn_t ssi_wake_thread(int irq __maybe_unused, void *ssi_port)
{
struct hsi_port *port = (struct hsi_port *)ssi_port;
struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
@@ -1007,13 +1007,6 @@ static void ssi_wake_tasklet(unsigned long ssi_port)
}
spin_unlock(&omap_port->lock);
}
-}
-
-static irqreturn_t ssi_wake_isr(int irq __maybe_unused, void *ssi_port)
-{
- struct omap_ssi_port *omap_port = hsi_port_drvdata(ssi_port);
-
- tasklet_hi_schedule(&omap_port->wake_tasklet);
return IRQ_HANDLED;
}
@@ -1051,13 +1044,12 @@ static int ssi_wake_irq(struct hsi_port *port, struct platform_device *pd)
}
cawake_irq = gpiod_to_irq(omap_port->wake_gpio);
-
omap_port->wake_irq = cawake_irq;
- tasklet_init(&omap_port->wake_tasklet, ssi_wake_tasklet,
- (unsigned long)port);
- err = devm_request_irq(&port->device, cawake_irq, ssi_wake_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "cawake", port);
+
+ err = devm_request_threaded_irq(&port->device, cawake_irq, NULL,
+ ssi_wake_thread,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "SSI cawake", port);
if (err < 0)
dev_err(&port->device, "Request Wake in IRQ %d failed %d\n",
cawake_irq, err);
@@ -1234,7 +1226,6 @@ static int ssi_port_remove(struct platform_device *pd)
hsi_port_unregister_clients(port);
- tasklet_kill(&omap_port->wake_tasklet);
tasklet_kill(&omap_port->pio_tasklet);
port->async = hsi_dummy_msg;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 05/19] HSI: ssi_protocol: fix ssip_xmit invocation |
| Message-ID | <rLrib-6py-69@gated-at.bofh.it> |
| In reply to | #1425770 |
ssip_xmit should be called from process context,
since it calls hsi_async_write.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/clients/ssi_protocol.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c
index 2388857db14b..6031cd146556 100644
--- a/drivers/hsi/clients/ssi_protocol.c
+++ b/drivers/hsi/clients/ssi_protocol.c
@@ -150,6 +150,7 @@ struct ssi_protocol {
struct net_device *netdev;
struct list_head txqueue;
struct list_head cmdqueue;
+ struct work_struct work;
struct hsi_client *cl;
struct list_head link;
atomic_t tx_usecnt;
@@ -968,6 +969,15 @@ static int ssip_pn_set_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static void ssip_xmit_work(struct work_struct *work)
+{
+ struct ssi_protocol *ssi =
+ container_of(work, struct ssi_protocol, work);
+ struct hsi_client *cl = ssi->cl;
+
+ ssip_xmit(cl);
+}
+
static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct hsi_client *cl = to_hsi_client(dev->dev.parent);
@@ -1020,7 +1030,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n",
ssi->txqueue_len);
spin_unlock_bh(&ssi->lock);
- ssip_xmit(cl);
+ schedule_work(&ssi->work);
} else {
spin_unlock_bh(&ssi->lock);
}
@@ -1097,6 +1107,7 @@ static int ssi_protocol_probe(struct device *dev)
atomic_set(&ssi->tx_usecnt, 0);
hsi_client_set_drvdata(cl, ssi);
ssi->cl = cl;
+ INIT_WORK(&ssi->work, ssip_xmit_work);
ssi->channel_id_cmd = hsi_get_channel_id_by_name(cl, "mcsaab-control");
if (ssi->channel_id_cmd < 0) {
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 18/19] HSI: omap_ssi_port: use rpm autosuspend API |
| Message-ID | <rLric-6py-95@gated-at.bofh.it> |
| In reply to | #1425770 |
Instead of immediately sending the SSI module to
sleep, wait some time in case of new incoming or
outgoing traffic.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_port.c | 68 +++++++++++++++++++++------------
1 file changed, 44 insertions(+), 24 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 7717c769c4dd..f95efabc27b0 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -126,7 +126,7 @@ static int ssi_debug_port_show(struct seq_file *m, void *p __maybe_unused)
seq_printf(m, "BUFFER_CH%d\t: 0x%08x\n", ch,
readl(base + SSI_SSR_BUFFER_CH_REG(ch)));
}
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return 0;
}
@@ -150,7 +150,7 @@ static int ssi_div_get(void *data, u64 *val)
pm_runtime_get_sync(omap_port->pdev);
*val = readl(omap_port->sst_base + SSI_SST_DIVISOR_REG);
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return 0;
}
@@ -166,7 +166,7 @@ static int ssi_div_set(void *data, u64 val)
pm_runtime_get_sync(omap_port->pdev);
writel(val, omap_port->sst_base + SSI_SST_DIVISOR_REG);
omap_port->sst.divisor = val;
- pm_runtime_put_sync(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return 0;
}
@@ -245,7 +245,7 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
if (!pm_runtime_active(omap_port->pdev)) {
dev_warn(&port->device, "ssi_start_dma called without runtime PM!\n");
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return -EREMOTEIO;
}
@@ -254,7 +254,7 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
DMA_FROM_DEVICE);
if (err < 0) {
dev_dbg(&ssi->device, "DMA map SG failed !\n");
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return err;
}
csdp = SSI_DST_BURST_4x32_BIT | SSI_DST_MEMORY_PORT |
@@ -271,7 +271,7 @@ static int ssi_start_dma(struct hsi_msg *msg, int lch)
DMA_TO_DEVICE);
if (err < 0) {
dev_dbg(&ssi->device, "DMA map SG failed !\n");
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return err;
}
csdp = SSI_SRC_BURST_4x32_BIT | SSI_SRC_MEMORY_PORT |
@@ -317,7 +317,7 @@ static int ssi_start_pio(struct hsi_msg *msg)
if (!pm_runtime_active(omap_port->pdev)) {
dev_warn(&port->device, "ssi_start_pio called without runtime PM!\n");
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return -EREMOTEIO;
}
@@ -332,7 +332,7 @@ static int ssi_start_pio(struct hsi_msg *msg)
msg->ttype ? "write" : "read");
val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
writel(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
msg->actual_len = 0;
msg->status = HSI_STATUS_PROCEEDING;
@@ -390,7 +390,8 @@ static int ssi_async_break(struct hsi_msg *msg)
spin_unlock_bh(&omap_port->lock);
}
out:
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return err;
}
@@ -428,7 +429,8 @@ static int ssi_async(struct hsi_msg *msg)
msg->status = HSI_STATUS_ERROR;
}
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
dev_dbg(&port->device, "msg status %d ttype %d ch %d\n",
msg->status, msg->ttype, msg->channel);
@@ -530,7 +532,8 @@ static int ssi_setup(struct hsi_client *cl)
omap_port->ssr.mode = cl->rx_cfg.mode;
out:
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return err;
}
@@ -561,7 +564,7 @@ static int ssi_flush(struct hsi_client *cl)
continue;
writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
if (msg->ttype == HSI_MSG_READ)
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
omap_ssi->gdd_trn[i].msg = NULL;
}
/* Flush all SST buffers */
@@ -585,7 +588,7 @@ static int ssi_flush(struct hsi_client *cl)
for (i = 0; i < omap_port->channels; i++) {
/* Release write clocks */
if (!list_empty(&omap_port->txqueue[i]))
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
ssi_flush_queue(&omap_port->txqueue[i], NULL);
ssi_flush_queue(&omap_port->rxqueue[i], NULL);
}
@@ -595,7 +598,8 @@ static int ssi_flush(struct hsi_client *cl)
pinctrl_pm_select_default_state(omap_port->pdev);
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
return 0;
}
@@ -649,7 +653,9 @@ static int ssi_stop_tx(struct hsi_client *cl)
writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
spin_unlock_bh(&omap_port->wk_lock);
- pm_runtime_put(omap_port->pdev); /* Release clocks */
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev); /* Release clocks */
+
return 0;
}
@@ -675,7 +681,8 @@ static void ssi_transfer(struct omap_ssi_port *omap_port,
}
}
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
}
static void ssi_cleanup_queues(struct hsi_client *cl)
@@ -704,7 +711,8 @@ static void ssi_cleanup_queues(struct hsi_client *cl)
txbufstate |= (1 << i);
status |= SSI_DATAACCEPT(i);
/* Release the clocks writes, also GDD ones */
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
}
ssi_flush_queue(&omap_port->txqueue[i], cl);
}
@@ -758,8 +766,10 @@ static void ssi_cleanup_gdd(struct hsi_controller *ssi, struct hsi_client *cl)
* Clock references for write will be handled in
* ssi_cleanup_queues
*/
- if (msg->ttype == HSI_MSG_READ)
- pm_runtime_put(omap_port->pdev);
+ if (msg->ttype == HSI_MSG_READ) {
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
+ }
omap_ssi->gdd_trn[i].msg = NULL;
}
tmp = readl_relaxed(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
@@ -807,7 +817,7 @@ static int ssi_release(struct hsi_client *cl)
WARN_ON(omap_port->wk_refcount != 0);
}
spin_unlock_bh(&omap_port->lock);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_put_sync(omap_port->pdev);
return 0;
}
@@ -954,7 +964,8 @@ static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
reg = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
if (msg->ttype == HSI_MSG_WRITE) {
/* Release clocks for write transfer */
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
}
reg &= ~val;
writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
@@ -998,7 +1009,9 @@ static irqreturn_t ssi_pio_thread(int irq, void *ssi_port)
/* TODO: sleep if we retry? */
} while (status_reg);
- pm_runtime_put(omap_port->pdev);
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
+
return IRQ_HANDLED;
}
@@ -1032,8 +1045,10 @@ static irqreturn_t ssi_wake_thread(int irq __maybe_unused, void *ssi_port)
omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
}
hsi_event(port, HSI_EVENT_STOP_RX);
- if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags))
- pm_runtime_put_sync(omap_port->pdev);
+ if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags)) {
+ pm_runtime_mark_last_busy(omap_port->pdev);
+ pm_runtime_put_autosuspend(omap_port->pdev);
+ }
}
return IRQ_HANDLED;
@@ -1222,6 +1237,9 @@ static int ssi_port_probe(struct platform_device *pd)
omap_port->dev = &port->device;
pm_runtime_irq_safe(omap_port->pdev);
+
+ pm_runtime_use_autosuspend(omap_port->pdev);
+ pm_runtime_set_autosuspend_delay(omap_port->pdev, 250);
pm_runtime_enable(omap_port->pdev);
#ifdef CONFIG_DEBUG_FS
@@ -1266,6 +1284,8 @@ static int ssi_port_remove(struct platform_device *pd)
omap_ssi->port[omap_port->port_id] = NULL;
platform_set_drvdata(pd, NULL);
+
+ pm_runtime_dont_use_autosuspend(&pd->dev);
pm_runtime_disable(&pd->dev);
return 0;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 08/19] HSI: core: switch port event notifier from atomic to blocking |
| Message-ID | <rLric-6py-93@gated-at.bofh.it> |
| In reply to | #1425770 |
port events should be sent from process context after
irq_safe runtime pm flag is removed in omap-ssi.
---
drivers/hsi/hsi_core.c | 8 ++++----
include/linux/hsi/hsi.h | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/hsi/hsi_core.c b/drivers/hsi/hsi_core.c
index d7ce07ad67f3..c2a2a9795b0b 100644
--- a/drivers/hsi/hsi_core.c
+++ b/drivers/hsi/hsi_core.c
@@ -507,7 +507,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
port[i]->stop_tx = hsi_dummy_cl;
port[i]->release = hsi_dummy_cl;
mutex_init(&port[i]->lock);
- ATOMIC_INIT_NOTIFIER_HEAD(&port[i]->n_head);
+ BLOCKING_INIT_NOTIFIER_HEAD(&port[i]->n_head);
dev_set_name(&port[i]->device, "port%d", i);
hsi->port[i]->device.release = hsi_port_release;
device_initialize(&hsi->port[i]->device);
@@ -689,7 +689,7 @@ int hsi_register_port_event(struct hsi_client *cl,
cl->ehandler = handler;
cl->nb.notifier_call = hsi_event_notifier_call;
- return atomic_notifier_chain_register(&port->n_head, &cl->nb);
+ return blocking_notifier_chain_register(&port->n_head, &cl->nb);
}
EXPORT_SYMBOL_GPL(hsi_register_port_event);
@@ -709,7 +709,7 @@ int hsi_unregister_port_event(struct hsi_client *cl)
WARN_ON(!hsi_port_claimed(cl));
- err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb);
+ err = blocking_notifier_chain_unregister(&port->n_head, &cl->nb);
if (!err)
cl->ehandler = NULL;
@@ -734,7 +734,7 @@ EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
*/
int hsi_event(struct hsi_port *port, unsigned long event)
{
- return atomic_notifier_call_chain(&port->n_head, event, NULL);
+ return blocking_notifier_call_chain(&port->n_head, event, NULL);
}
EXPORT_SYMBOL_GPL(hsi_event);
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 2790591c77cf..57402544b53f 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -246,7 +246,7 @@ struct hsi_port {
int (*stop_tx)(struct hsi_client *cl);
int (*release)(struct hsi_client *cl);
/* private */
- struct atomic_notifier_head n_head;
+ struct blocking_notifier_head n_head;
};
#define to_hsi_port(dev) container_of(dev, struct hsi_port, device)
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:30 +0200 |
| Subject | [RFC 07/19] HSI: omap_ssi_port: replace wkin_cken with atomic bitmap operations |
| Message-ID | <rLric-6py-101@gated-at.bofh.it> |
| In reply to | #1425770 |
This simplifies the code and avoids holding a spin_lock when
runtime pm calls are made. Once the irq_safe flag is removed
for omap_ssi's runtime pm, pm_runtime_get/put_sync can sleep,
which is a no-go while holding a spin_lock.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi.h | 6 ++++--
drivers/hsi/controllers/omap_ssi_port.c | 16 +++-------------
2 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
index 88a523902a8f..6cdaad8805f7 100644
--- a/drivers/hsi/controllers/omap_ssi.h
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -35,6 +35,8 @@
#define SSI_MAX_GDD_LCH 8
#define SSI_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1)
+#define SSI_WAKE_EN 0
+
/**
* struct omap_ssm_ctx - OMAP synchronous serial module (TX/RX) context
* @mode: Bit transmission mode
@@ -75,7 +77,7 @@ struct omap_ssm_ctx {
* @wake_irq: IRQ 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
- * @wkin_cken: Keep track of clock references due to the incoming wake line
+ * @flags: flags to keep track of states
* @wk_refcount: Reference count for output wake line
* @sys_mpu_enable: Context for the interrupt enable register for irq 0
* @sst: Context for the synchronous serial transmitter
@@ -99,7 +101,7 @@ struct omap_ssi_port {
struct gpio_desc *wake_gpio;
struct tasklet_struct pio_tasklet;
bool wktest:1; /* FIXME: HACK to be removed */
- bool wkin_cken:1; /* Workaround */
+ unsigned long flags;
unsigned int wk_refcount;
/* OMAP SSI port context */
u32 sys_mpu_enable; /* We use only one irq */
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 9001b06312c3..0d3452393670 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -751,10 +751,8 @@ static int ssi_release(struct hsi_client *cl)
* Drop the clock reference for the incoming wake line
* if it is still kept high by the other side.
*/
- if (omap_port->wkin_cken) {
+ if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags))
pm_runtime_put_sync(omap_port->pdev);
- omap_port->wkin_cken = 0;
- }
pm_runtime_get_sync(omap_port->pdev);
/* Stop any SSI TX/RX without a client */
ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
@@ -981,12 +979,8 @@ static irqreturn_t ssi_wake_thread(int irq __maybe_unused, void *ssi_port)
* This workaround will avoid breaking the clock reference
* count when such a situation ocurrs.
*/
- spin_lock(&omap_port->lock);
- if (!omap_port->wkin_cken) {
- omap_port->wkin_cken = 1;
+ if (!test_and_set_bit(SSI_WAKE_EN, &omap_port->flags))
pm_runtime_get_sync(omap_port->pdev);
- }
- spin_unlock(&omap_port->lock);
dev_dbg(&ssi->device, "Wake in high\n");
if (omap_port->wktest) { /* FIXME: HACK ! To be removed */
writel(SSI_WAKE(0),
@@ -1000,12 +994,8 @@ static irqreturn_t ssi_wake_thread(int irq __maybe_unused, void *ssi_port)
omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
}
hsi_event(port, HSI_EVENT_STOP_RX);
- spin_lock(&omap_port->lock);
- if (omap_port->wkin_cken) {
+ if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags))
pm_runtime_put_sync(omap_port->pdev);
- omap_port->wkin_cken = 0;
- }
- spin_unlock(&omap_port->lock);
}
return IRQ_HANDLED;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:40 +0200 |
| Subject | [RFC 09/19] HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime calls |
| Message-ID | <rLrrQ-6sW-7@gated-at.bofh.it> |
| In reply to | #1425770 |
ssi_start_tx and ssi_stop_tx may be called from atomic context. Once
pm_runtime_irq_safe() is removed for omap-ssi, this will fail, due
to blocking pm_runtime_*_sync() calls.
This fixes ssi_stop_tx by using non-sync API and ssi_start_tx by
using a worker thread.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi.h | 2 ++
drivers/hsi/controllers/omap_ssi_port.c | 23 ++++++++++++++++++-----
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
index 6cdaad8805f7..5467f61e5086 100644
--- a/drivers/hsi/controllers/omap_ssi.h
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -79,6 +79,7 @@ struct omap_ssm_ctx {
* @pio_tasklet: Bottom half for PIO transfers and events
* @flags: flags to keep track of states
* @wk_refcount: Reference count for output wake line
+ * @work: worker for starting TX
* @sys_mpu_enable: Context for the interrupt enable register for irq 0
* @sst: Context for the synchronous serial transmitter
* @ssr: Context for the synchronous serial receiver
@@ -103,6 +104,7 @@ struct omap_ssi_port {
bool wktest:1; /* FIXME: HACK to be removed */
unsigned long flags;
unsigned int wk_refcount;
+ struct work_struct work;
/* OMAP SSI port context */
u32 sys_mpu_enable; /* We use only one irq */
struct omap_ssm_ctx sst;
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 0d3452393670..cc56d0ee82a2 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -567,12 +567,22 @@ static int ssi_flush(struct hsi_client *cl)
return 0;
}
+static void start_tx_work(struct work_struct *work)
+{
+ struct omap_ssi_port *omap_port =
+ container_of(work, struct omap_ssi_port, work);
+ struct hsi_port *port = to_hsi_port(omap_port->dev);
+ struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+ struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+ pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */
+ writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
+}
+
static int ssi_start_tx(struct hsi_client *cl)
{
struct hsi_port *port = hsi_get_port(cl);
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
- struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
- struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount);
@@ -581,10 +591,10 @@ static int ssi_start_tx(struct hsi_client *cl)
spin_unlock_bh(&omap_port->wk_lock);
return 0;
}
- pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */
- writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
spin_unlock_bh(&omap_port->wk_lock);
+ schedule_work(&omap_port->work);
+
return 0;
}
@@ -604,9 +614,10 @@ static int ssi_stop_tx(struct hsi_client *cl)
return 0;
}
writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
- pm_runtime_put_sync(omap_port->pdev); /* Release clocks */
spin_unlock_bh(&omap_port->wk_lock);
+ pm_runtime_put(omap_port->pdev); /* Release clocks */
+
return 0;
}
@@ -1149,6 +1160,8 @@ static int ssi_port_probe(struct platform_device *pd)
omap_port->pdev = &pd->dev;
omap_port->port_id = port_id;
+ INIT_WORK(&omap_port->work, start_tx_work);
+
/* initialize HSI port */
port->async = ssi_async;
port->setup = ssi_setup;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 18:40 +0200 |
| Subject | [RFC 01/19] HSI: omap_ssi_port: remove useless newline |
| Message-ID | <rLrrQ-6sW-21@gated-at.bofh.it> |
| In reply to | #1425770 |
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/controllers/omap_ssi_port.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 6b8f7739768a..38388442e310 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -1018,8 +1018,7 @@ static irqreturn_t ssi_wake_isr(int irq __maybe_unused, void *ssi_port)
return IRQ_HANDLED;
}
-static int ssi_port_irq(struct hsi_port *port,
- struct platform_device *pd)
+static int ssi_port_irq(struct hsi_port *port, struct platform_device *pd)
{
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
int err;
@@ -1040,8 +1039,7 @@ static int ssi_port_irq(struct hsi_port *port,
return err;
}
-static int ssi_wake_irq(struct hsi_port *port,
- struct platform_device *pd)
+static int ssi_wake_irq(struct hsi_port *port, struct platform_device *pd)
{
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
int cawake_irq;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Pavel Machek <pavel@ucw.cz> |
|---|---|
| Date | 2016-06-18 21:00 +0200 |
| Message-ID | <rLtDj-7O6-1@gated-at.bofh.it> |
| In reply to | #1425770 |
Hi! > This series fixes runtime PM for omap-ssi, so that > the OMAP SoC can idle correctly. After applying the > series, the SSI module correctly goes into idle if > phonet0 interface is not configured or if it's > used by ofono (*). Apart from me Pavel Machek did > some testing of my devel branch [0] and reported, > that he was able to get the phone into full idle. > > Note: I did my testing with kernel flashing over USB, so > idle is broken. But I found the bit in cm_idlest1_core, > that stands for SSI blocking status: 0x00800000 (documented > as "reserved" in the public TRM). > > (*) "ifconfig phonet0 up" will result in blocking ssi module > until modem setup has finished (data communication via > phonet0 device), since it enables ssi wakelines. > > [0] https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=runtime-pm-fixes I tried applying it over v4.7-rc, but: Applying: HSI: core: switch port event notifier from atomic to blocking error: drivers/hsi/hsi_core.c: does not exist in index Patch failed at 0008 HSI: core: switch port event notifier from atomic to blocking The copy of the patch that failed is found in: I tried against v4.6, but could not, either: git checkout 2dcd0af568b0cf583645c8a317dd12e344b1c72a Checking out files: 100% (9566/9566), done. Note: checking out '2dcd0af568b0cf583645c8a317dd12e344b1c72a'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b new_branch_name HEAD is now at 2dcd0af... Linux 4.6 pavel@amd /data/l/linux-n900 (2dcd0af...) $ git am /tmp/delme.patch Applying: HSI: omap_ssi_port: remove useless newline error: patch failed: drivers/hsi/controllers/omap_ssi_port.c:1018 error: drivers/hsi/controllers/omap_ssi_port.c: patch does not apply Patch failed at 0001 HSI: omap_ssi_port: remove useless newline The copy of the patch that failed is found in: /data/l/linux-n900/.git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". pavel@amd /data/l/linux-n900 (2dcd0af...)|AM 1/19 $ What tree should I try it against? Thanks, Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Reichel <sre@kernel.org> |
|---|---|
| Date | 2016-06-18 22:30 +0200 |
| Message-ID | <rLv2q-uj-13@gated-at.bofh.it> |
| In reply to | #1425819 |
[Multipart message — attachments visible in raw view] — view raw
Hi, On Sat, Jun 18, 2016 at 08:54:38PM +0200, Pavel Machek wrote: > > This series fixes runtime PM for omap-ssi, so that > > the OMAP SoC can idle correctly. After applying the > > series, the SSI module correctly goes into idle if > > phonet0 interface is not configured or if it's > > used by ofono (*). Apart from me Pavel Machek did > > some testing of my devel branch [0] and reported, > > that he was able to get the phone into full idle. > > > > Note: I did my testing with kernel flashing over USB, so > > idle is broken. But I found the bit in cm_idlest1_core, > > that stands for SSI blocking status: 0x00800000 (documented > > as "reserved" in the public TRM). > > > > (*) "ifconfig phonet0 up" will result in blocking ssi module > > until modem setup has finished (data communication via > > phonet0 device), since it enables ssi wakelines. > > > > [0] https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=runtime-pm-fixes > > I tried applying it over v4.7-rc, but [...] > What tree should I try it against? The patchset is based on hsi's for-next branch available here: https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=for-next You can try to apply it directly on 4.7 by changing "hsi_core.c" to "hsi.c" or by applying this additional patch: https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/commit/?h=for-next&id=e01957abd4cb3816a1eaaf191b16de182ebb333e -- Sebastian
[toc] | [prev] | [next] | [standalone]
| From | Pavel Machek <pavel@ucw.cz> |
|---|---|
| Date | 2016-06-19 00:10 +0200 |
| Message-ID | <rLwBb-1y4-1@gated-at.bofh.it> |
| In reply to | #1425838 |
Hi! > > > (*) "ifconfig phonet0 up" will result in blocking ssi module > > > until modem setup has finished (data communication via > > > phonet0 device), since it enables ssi wakelines. > > > > > > [0] https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=runtime-pm-fixes > > > > I tried applying it over v4.7-rc, but [...] > > What tree should I try it against? > > The patchset is based on hsi's for-next branch available here: > > > > https://git.kernel.org/cgit/linux/kernel/git/sre/linux-hsi.git/log/?h=for-next Aha, ok, thanks. I have some fun with wlan, but machine now goes to sleep. Thanks! Tested-by: Pavel Machek <pavel@ucw.cz> Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web