ARM: OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos

Omap_uart_can_sleep function blocks system wide low power state until
uart is active remove this func and add qos requests to prevent
MPU from transitioning.

Keep qos request to default value which will allow MPU to transition
and while uart baud rate is available calculate the latency value
from the baudrate and use the same to hold constraint while uart clocks
are enabled, and if uart is auto-idled the constraint is updated with
default constraint value allowing MPU to transition.

Qos requests are blocking notifier calls so put these requests to
work queue, also the driver uses irq_safe version of runtime API's
and callbacks can be called in interrupt disabled context.
So to avoid warn on slow path warning while using qos update
API's from runtime callbacks use the qos_work_queue.

During bootup the runtime_resume call backs might not be called and runtime
callback gets called only after uart is idled by setting the autosuspend
timeout. So qos_request from runtime resume callback might not activated during
boot if uart baudrate is calculated during bootup for console uart, so schedule
the qos_work queue once we calc_latency while configuring the uart port.

Flush and complete any pending qos jobs in work queue while suspending.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de> (for drivers/tty changes)
Signed-off-by: Kevin Hilman <khilman@ti.com>
This commit is contained in:
Govindraj.R 2011-11-09 17:41:21 +05:30 committed by Kevin Hilman
parent 36fc2d15b1
commit 2fd149645e
6 changed files with 41 additions and 42 deletions

View File

@ -30,7 +30,6 @@
#include <plat/irqs.h> #include <plat/irqs.h>
#include "powerdomain.h" #include "powerdomain.h"
#include "clockdomain.h" #include "clockdomain.h"
#include <plat/serial.h>
#include "pm.h" #include "pm.h"
#include "control.h" #include "control.h"
@ -245,11 +244,6 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
struct omap3_idle_statedata *cx; struct omap3_idle_statedata *cx;
int ret; int ret;
if (!omap3_can_sleep()) {
new_state_idx = drv->safe_state_index;
goto select_state;
}
/* /*
* Prevent idle completely if CAM is active. * Prevent idle completely if CAM is active.
* CAM does not have wakeup capability in OMAP3. * CAM does not have wakeup capability in OMAP3.

View File

@ -222,8 +222,6 @@ static int omap2_can_sleep(void)
{ {
if (omap2_fclks_active()) if (omap2_fclks_active())
return 0; return 0;
if (!omap_uart_can_sleep())
return 0;
if (osc_ck->usecount > 1) if (osc_ck->usecount > 1)
return 0; return 0;
if (omap_dma_running()) if (omap_dma_running())

View File

@ -35,7 +35,6 @@
#include <plat/sram.h> #include <plat/sram.h>
#include "clockdomain.h" #include "clockdomain.h"
#include "powerdomain.h" #include "powerdomain.h"
#include <plat/serial.h>
#include <plat/sdrc.h> #include <plat/sdrc.h>
#include <plat/prcm.h> #include <plat/prcm.h>
#include <plat/gpmc.h> #include <plat/gpmc.h>
@ -456,21 +455,11 @@ void omap_sram_idle(void)
clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
} }
int omap3_can_sleep(void)
{
if (!omap_uart_can_sleep())
return 0;
return 1;
}
static void omap3_pm_idle(void) static void omap3_pm_idle(void)
{ {
local_irq_disable(); local_irq_disable();
local_fiq_disable(); local_fiq_disable();
if (!omap3_can_sleep())
goto out;
if (omap_irq_pending() || need_resched()) if (omap_irq_pending() || need_resched())
goto out; goto out;

View File

@ -82,28 +82,6 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = {
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM
int omap_uart_can_sleep(void)
{
struct omap_uart_state *uart;
int can_sleep = 1;
list_for_each_entry(uart, &uart_list, node) {
if (!uart->clocked)
continue;
if (!uart->can_sleep) {
can_sleep = 0;
continue;
}
/* This UART can now safely sleep. */
omap_uart_allow_sleep(uart);
}
return can_sleep;
}
static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable) static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
{ {
struct omap_device *od = to_omap_device(pdev); struct omap_device *od = to_omap_device(pdev);

View File

@ -19,6 +19,7 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <plat/mux.h> #include <plat/mux.h>
@ -130,6 +131,11 @@ struct uart_omap_port {
u32 context_loss_cnt; u32 context_loss_cnt;
u32 errata; u32 errata;
u8 wakeups_enabled; u8 wakeups_enabled;
struct pm_qos_request pm_qos_request;
u32 latency;
u32 calc_latency;
struct work_struct qos_work;
}; };
#endif /* __OMAP_SERIAL_H__ */ #endif /* __OMAP_SERIAL_H__ */

View File

@ -51,6 +51,8 @@ static void serial_omap_rxdma_poll(unsigned long uart_no);
static int serial_omap_start_rxdma(struct uart_omap_port *up); static int serial_omap_start_rxdma(struct uart_omap_port *up);
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
static struct workqueue_struct *serial_omap_uart_wq;
static inline unsigned int serial_in(struct uart_omap_port *up, int offset) static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{ {
offset <<= up->port.regshift; offset <<= up->port.regshift;
@ -671,6 +673,14 @@ serial_omap_configure_xonxoff
serial_out(up, UART_LCR, up->lcr); serial_out(up, UART_LCR, up->lcr);
} }
static void serial_omap_uart_qos_work(struct work_struct *work)
{
struct uart_omap_port *up = container_of(work, struct uart_omap_port,
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
}
static void static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
@ -711,6 +721,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
quot = serial_omap_get_divisor(port, baud); quot = serial_omap_get_divisor(port, baud);
/* calculate wakeup latency constraint */
up->calc_latency = (1000000 * up->port.fifosize) /
(1000 * baud / 8);
up->latency = up->calc_latency;
schedule_work(&up->qos_work);
up->dll = quot & 0xff; up->dll = quot & 0xff;
up->dlh = quot >> 8; up->dlh = quot >> 8;
up->mdr1 = UART_OMAP_MDR1_DISABLE; up->mdr1 = UART_OMAP_MDR1_DISABLE;
@ -1145,8 +1161,11 @@ static int serial_omap_suspend(struct device *dev)
{ {
struct uart_omap_port *up = dev_get_drvdata(dev); struct uart_omap_port *up = dev_get_drvdata(dev);
if (up) if (up) {
uart_suspend_port(&serial_omap_reg, &up->port); uart_suspend_port(&serial_omap_reg, &up->port);
flush_work_sync(&up->qos_work);
}
return 0; return 0;
} }
@ -1383,6 +1402,13 @@ static int serial_omap_probe(struct platform_device *pdev)
up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
} }
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
pm_qos_add_request(&up->pm_qos_request,
PM_QOS_CPU_DMA_LATENCY, up->latency);
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, pm_runtime_set_autosuspend_delay(&pdev->dev,
omap_up_info->autosuspend_timeout); omap_up_info->autosuspend_timeout);
@ -1416,6 +1442,8 @@ static int serial_omap_remove(struct platform_device *dev)
if (up) { if (up) {
pm_runtime_disable(&up->pdev->dev); pm_runtime_disable(&up->pdev->dev);
uart_remove_one_port(&serial_omap_reg, &up->port); uart_remove_one_port(&serial_omap_reg, &up->port);
pm_qos_remove_request(&up->pm_qos_request);
kfree(up); kfree(up);
} }
@ -1518,6 +1546,9 @@ static int serial_omap_runtime_suspend(struct device *dev)
(up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
pdata->set_forceidle(up->pdev); pdata->set_forceidle(up->pdev);
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&up->qos_work);
return 0; return 0;
} }
@ -1538,6 +1569,9 @@ static int serial_omap_runtime_resume(struct device *dev)
if (up->use_dma && pdata->set_noidle && if (up->use_dma && pdata->set_noidle &&
(up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
pdata->set_noidle(up->pdev); pdata->set_noidle(up->pdev);
up->latency = up->calc_latency;
schedule_work(&up->qos_work);
} }
return 0; return 0;