OMAP2+: UART: Make the RX_TIMEOUT for DMA configurable for each UART
Subsystems (5)
PATCH v7 15/21 OMAP2+: UART: Make the RX_TIMEOUT for DMA configurable for each UART
From: Jon Hunter <[email protected]>
When using DMA there are two timeouts defined. The first timeout, rx_timeout, is really a polling rate in which software polls the DMA status to see if the DMA has finished. This is necessary for the RX side because we do not know how much data we will receive. The secound timeout, RX_TIMEOUT, is a timeout after which the DMA will be stopped if no more data is received. To make this clearer, rename rx_timeout as rx_poll_rate and rename the function serial_omap_rx_timeout() to serial_omap_rxdma_poll().
The OMAP-Serial driver defines an RX_TIMEOUT of 3 seconds that is used to indicate when the DMA for UART can be stopped if no more data is received. The value is a global definition that is applied to all instances of the UART.
Each UART may be used for a different purpose and so the timeout required may differ. Make this value configurable for each UART so that this value can be optimised for power savings.
--- arch/arm/mach-omap2/serial.c | 5 ++++- arch/arm/plat-omap/include/plat/omap-serial.h | 3 ++- drivers/tty/serial/omap-serial.c | 15 ++++++++------- 3 files changed, 14 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/serial.c +4 -1
@@ -64,13 +64,15 @@ struct omap_uart_state {static LIST_HEAD (uart_list);static u8 num_uarts; -#define DEFAULT_RXDMA_TIMEOUT 1/* RX DMA polling rate (us) */ +#define DEFAULT_RXDMA_POLLRATE 1/* RX DMA polling rate (us) */ #define DEFAULT_RXDMA_BUFSIZE 4096/* RX DMA buffer size */ +#define DEFAULT_RXDMA_TIMEOUT (3 * HZ)/* RX DMA timeout (jiffies) */ static struct omap_uart_port_info omap_serial_default_info[]__initdata = { { .dma_enabled = false, .dma_rx_buf_size =DEFAULT_RXDMA_BUFSIZE , + .dma_rx_poll_rate =DEFAULT_RXDMA_POLLRATE , .dma_rx_timeout =DEFAULT_RXDMA_TIMEOUT , .autosuspend_timeout =DEFAULT_AUTOSUSPEND_DELAY , },
@@ -373,6 +375,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.enable_wakeup = omap_uart_enable_wakeup; omap_up.dma_rx_buf_size = info->dma_rx_buf_size; omap_up.dma_rx_timeout = info->dma_rx_timeout; + omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout;/* Enable the MDR1 errata for OMAP3 */
arch/arm/plat-omap/include/plat/omap-serial.h +2 -1
@@ -53,7 +53,6 @@#define OMAP_UART_DMA_CH_FREE -1 -#define RX_TIMEOUT (3 * HZ)#define OMAP_MAX_HSUART_PORTS 4#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
@@ -68,6 +67,7 @@ struct omap_uart_port_info {unsigned int dma_rx_buf_size;unsigned int dma_rx_timeout;unsigned int autosuspend_timeout; +unsigned int dma_rx_poll_rate;u32 (*get_context_loss_count)(struct device *);void (*set_forceidle)(struct platform_device *);
@@ -97,6 +97,7 @@ struct uart_omap_dma {/* timer to poll activity on rx dma */ struct timer_list rx_timer;unsigned int rx_buf_size; +unsigned int rx_poll_rate;unsigned int rx_timeout; };
drivers/tty/serial/omap-serial.c +8 -7
@@ -47,7 +47,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];/* Forward declaration of functions */ static void uart_tx_dma_callback (int lch,u16 ch_status,void *data); -static void serial_omap_rx_timeout (unsigned long uart_no); +static void serial_omap_rxdma_poll (unsigned long uart_no);static int serial_omap_start_rxdma (struct uart_omap_port *up);static void serial_omap_mdr1_errataset (struct uart_omap_port *up,u8 mdr1);
@@ -542,7 +542,7 @@ static int serial_omap_startup(struct uart_port *port) (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), 0);init_timer (&(up->uart_dma.rx_timer)); - up->uart_dma.rx_timer.function = serial_omap_rx_timeout; + up->uart_dma.rx_timer.function = serial_omap_rxdma_poll; up->uart_dma.rx_timer.data = up->pdev->id;/* Currently the buffer size is 4KB. Can increase it */ up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
@@ -1159,7 +1159,7 @@ static int serial_omap_resume(struct device *dev) }#endif -static void serial_omap_rx_timeout (unsigned long uart_no) +static void serial_omap_rxdma_poll (unsigned long uart_no) {struct uart_omap_port *up = ui[uart_no];unsigned int curr_dma_pos, curr_transmitted_size;
@@ -1169,9 +1169,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos ==0 )) {if (jiffies_to_msecs (jiffies - up->port_activity) < -RX_TIMEOUT ) { + up->uart_dma.rx_timeout) {mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); }else {serial_omap_stop_rxdma (up); up->ier |= (UART_IER_RDI |UART_IER_RLSI );
@@ -1200,7 +1200,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no) } }else {mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); } up->port_activity = jiffies; }
@@ -1239,7 +1239,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)/* FIXME: Cache maintenance needed here? */ omap_start_dma (up->uart_dma.rx_dma_channel);mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); up->uart_dma.rx_dma_used = true;return ret; }
@@ -1375,6 +1375,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->use_dma =1 ; up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout; + up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;spin_lock_init (&(up->uart_dma.tx_lock));spin_lock_init (&(up->uart_dma.rx_lock)); up->uart_dma.tx_dma_channel =OMAP_UART_DMA_CH_FREE ;
Signature · 1 line
1.7.4.1
PATCH v7 16/21 OMAP2+: UART: Remove custom activate funcs and use generic funcs.
The custom hwmod activate and deactivate funcs does hwmod_enable and idle same can be done with omap_device generic API's.
--- arch/arm/mach-omap2/serial.c | 18 ++---------------- 1 files changed, 2 insertions(+), 16 deletions(-)
arch/arm/mach-omap2/serial.c +2 -16
@@ -78,24 +78,10 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { }, }; -static int uart_idle_hwmod (struct omap_device *od) -{ -omap_hwmod_idle (od->hwmods[0 ]); - -return 0 ; -} - -static int uart_enable_hwmod (struct omap_device *od) -{ -omap_hwmod_enable (od->hwmods[0 ]); - -return 0 ; -} -static struct omap_device_pm_latency omap_uart_latency[] = { { - .deactivate_func = uart_idle_hwmod, - .activate_func = uart_enable_hwmod, + .activate_func = omap_device_enable_hwmods, + .deactivate_func = omap_device_idle_hwmods, .flags =OMAP_DEVICE_LATENCY_AUTO_ADJUST , }, };
Signature · 1 line
1.7.4.1
PATCH v7 16/21 OMAP2+: UART: Remove custom activate funcs and use generic funcs.
Quoted 4 lines · Govindraj.R
The custom hwmod activate and deactivate funcs does
hwmod_enableand idle same can be done withomap_devicegeneric API's.Signed-off-by Govindraj.R <[email protected]>
This one needs a minor update for current mainline...
Quoted 25 lines
--- arch/arm/mach-omap2/serial.c | 18 ++---------------- 1 files changed, 2 insertions(+), 16 deletions(-)arch/arm/mach-omap2/serial.c +0
-13@@ -78,24 +78,10 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { }, }; -static int uart_idle_hwmod (struct omap_device *od) -{ -omap_hwmod_idle (od->hwmods[0 ]); - -return 0 ; -} - -static int uart_enable_hwmod (struct omap_device *od) -{ -omap_hwmod_enable (od->hwmods[0 ]); - -return 0 ; -}
arch/arm/mach-omap2/serial.c static struct omap_uart_port_info omap_serial_default_info[] __initdata = { · line 87
Quoted 10 lines
arch/arm/mach-omap2/serial.c +2
-3-static struct omap_device_pm_latency omap_uart_latency[] = { { - .deactivate_func = uart_idle_hwmod, - .activate_func = uart_enable_hwmod, + .activate_func = omap_device_enable_hwmods, + .deactivate_func = omap_device_idle_hwmods, .flags =OMAP_DEVICE_LATENCY_AUTO_ADJUST , }, };
If we're just using default pm_latency struct, it can be passed to omap_device_build as NULL, and a default one will be configured.
Kevin
PATCH v7 16/21 OMAP2+: UART: Remove custom activate funcs and use generic funcs.
Quoted 39 lines · Kevin Hilman
Quoted 4 lines · Govindraj.R
The custom hwmod activate and deactivate funcs does
hwmod_enableand idle same can be done withomap_devicegeneric API's.Signed-off-by Govindraj.R <[email protected]>This one needs a minor update for current mainline...
Quoted 30 lines
---
?arch/arm/mach-omap2/serial.c | ? 18 ++---------------- ?1 files changed, 2 insertions(+), 16 deletions(-)arch/arm/mach-omap2/serial.c +0
-16@@ -78,24 +78,10 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { ? ? ? }, ?}; -static int uart_idle_hwmod (struct omap_device *od) -{ - ? ? omap_hwmod_idle(od->hwmods[0]); - - ? ? return 0; -} - -static int uart_enable_hwmod (struct omap_device *od) -{ - ? ? omap_hwmod_enable(od->hwmods[0]); - - ? ? return 0; -} - ?static struct omap_device_pm_latency omap_uart_latency[] = { ? ? ? { - ? ? ? ? ? ? .deactivate_func = uart_idle_hwmod, - ? ? ? ? ? ? .activate_func ? = uart_enable_hwmod,
Quoted 9 lines
arch/arm/mach-omap2/serial.c static struct omap_uart_port_info omap_serial_default_info[] __initdata = { · line 87
Quoted 5 lines
arch/arm/mach-omap2/serial.c +2
-0+ ? ? ? ? ? ? .activate_func ? = omap_device_enable_hwmods, + ? ? ? ? ? ? .deactivate_func = omap_device_idle_hwmods, ? ? ? ? ? ? ? .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, ? ? ? }, ?};If we're just using default
pm_latencystruct, it can be passed toomap_device_buildas NULL, and a default one will be configured.
yes, will update this.
--
Thanks,
Govindraj.R
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
In reply to Govindraj.ROmap_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 while uart is active and remove qos request if uart is auto-idled.
qos requests are blocking notifier calls so put these requests to work queue to avoid warn on slow path warning while using qos API's from runtime callbacks. Flush_sync any pending qos jobs in work queue while suspending.
--- arch/arm/mach-omap2/cpuidle34xx.c | 5 --- arch/arm/mach-omap2/pm24xx.c | 2 - arch/arm/mach-omap2/pm34xx.c | 10 ------ arch/arm/mach-omap2/serial.c | 24 +------------- arch/arm/plat-omap/include/plat/omap-serial.h | 8 +++++ drivers/tty/serial/omap-serial.c | 41 ++++++++++++++++++++++++- 6 files changed, 50 insertions(+), 40 deletions(-)
arch/arm/mach-omap2/cpuidle34xx.c +0 -5
@@ -226,11 +226,6 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,struct omap3_idle_statedata *cx;int ret; -if (!omap3_can_sleep ()) { - new_state = dev->safe_state; - goto select_state; - } -/* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3.
arch/arm/mach-omap2/pm24xx.c +0 -2
@@ -248,8 +248,6 @@ static int omap2_can_sleep(void) {if (omap2_fclks_active ())return 0 ; -if (!omap_uart_can_sleep ()) -return 0 ;if (osc_ck->usecount >1 )return 0 ;if (omap_dma_running ())
arch/arm/mach-omap2/pm34xx.c +0 -10
@@ -425,21 +425,11 @@ void omap_sram_idle(void)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 ) {local_irq_disable ();local_fiq_disable (); -if (!omap3_can_sleep ()) - goto out; -if (omap_irq_pending () ||need_resched ()) goto out;
arch/arm/mach-omap2/serial.c +2 -22
@@ -75,6 +75,7 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, .autosuspend_timeout = DEFAULT_AUTOSUSPEND_DELAY, + .use_pm_qos = true, }, };
@@ -87,28 +88,6 @@ static struct omap_device_pm_latency omap_uart_latency[] = { };#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) {struct omap_device *od =to_omap_device (pdev);
@@ -363,6 +342,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_timeout = info->dma_rx_timeout; omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout; + omap_up.use_pm_qos = info->use_pm_qos;/* Enable the MDR1 errata for OMAP3 */ if (cpu_is_omap34xx () && !cpu_is_ti816x ())
arch/arm/plat-omap/include/plat/omap-serial.h +8 -0
@@ -19,6 +19,7 @@#include <linux/serial_core.h> #include <linux/platform_device.h> +#include <linux/pm_qos_params.h> #include <plat/mux.h>
@@ -68,6 +69,7 @@ struct omap_uart_port_info {unsigned int dma_rx_timeout;unsigned int autosuspend_timeout;unsigned int dma_rx_poll_rate; +u8 use_pm_qos;u32 (*get_context_loss_count)(struct device *);void (*set_forceidle)(struct platform_device *);
@@ -129,6 +131,12 @@ struct uart_omap_port {u32 context_loss_cnt;u32 errata;u8 wakeups_enabled; + +struct pm_qos_request_list pm_qos_request; +u32 latency; +struct work_struct work; +u8 request_qos; + u8 use_pm_qos; };#endif /* __OMAP_SERIAL_H__ */
drivers/tty/serial/omap-serial.c +40 -1
90 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Quoted 2 lines · Govindraj.R
Omap_uart_can_sleepfunction blocks system wide low power state until uart is active remove this func and add qos requests to prevent
^
missing some punctuation.
Quoted 2 lines
MPU from transitioning while uart is active and remove qos request if uart is auto-idled.
It would be helpful to summarize my previous comments[1] about why this happens on some UARTs (PER) and not others (CORE.)
Quoted 3 lines
qos requests are blocking notifier calls so put these requests to work queue to avoid warn on slow path warning while using qos API's from runtime callbacks.
OK.
Rather than a vague reference to 'warn on slow path', please describe that this is needed because the driver uses the irq_safe mode of runtime PM, so callbacks may be run with interrupts disabled.
Quoted 1 line
Flush_syncany pending qos jobs in work queue while suspending.
Nice.
Quoted 70 lines
Signed-off-by Govindraj.R <[email protected]>--- arch/arm/mach-omap2/cpuidle34xx.c | 5 --- arch/arm/mach-omap2/pm24xx.c | 2 - arch/arm/mach-omap2/pm34xx.c | 10 ------ arch/arm/mach-omap2/serial.c | 24 +------------- arch/arm/plat-omap/include/plat/omap-serial.h | 8 +++++ drivers/tty/serial/omap-serial.c | 41 ++++++++++++++++++++++++- 6 files changed, 50 insertions(+), 40 deletions(-)arch/arm/mach-omap2/cpuidle34xx.c +0
-5@@ -226,11 +226,6 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,struct omap3_idle_statedata *cx;int ret; -if (!omap3_can_sleep ()) { - new_state = dev->safe_state; - goto select_state; - } -/* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. arch/arm/mach-omap2/pm24xx.c +0
-2@@ -248,8 +248,6 @@ static int omap2_can_sleep(void) {if (omap2_fclks_active ())return 0 ; -if (!omap_uart_can_sleep ()) -return 0 ;if (osc_ck->usecount >1 )return 0 ;if (omap_dma_running ())arch/arm/mach-omap2/pm34xx.c +0
-10@@ -425,21 +425,11 @@ void omap_sram_idle(void)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 ) {local_irq_disable ();local_fiq_disable (); -if (!omap3_can_sleep ()) - goto out; -if (omap_irq_pending () ||need_resched ()) goto out;arch/arm/mach-omap2/serial.c +0
-0
arch/arm/mach-omap2/serial.c static struct omap_uart_port_info omap_serial_default_info[] __initdata = { · line 78
Quoted 4 lines
arch/arm/mach-omap2/serial.c +1
-0@@ -75,6 +75,7 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, .autosuspend_timeout = DEFAULT_AUTOSUSPEND_DELAY, + .use_pm_qos = true,
You're enabling the MPU constraint for all UARTs.
However, as mentioned previously[1], due to a HW sleepdep between MPU and CORE, this constraint isn't actually needed for CORE UARTs, so it's a bit wasteful to go through all the constraint setting for no reason.
The changelog should summarize this, and the init code should only enable the constraints for PER UARTs, at least on OMAP3. I'm not sure about OMAP4.
Quoted 61 lines
arch/arm/mach-omap2/serial.c +1
-22}, };@@ -87,28 +88,6 @@ static struct omap_device_pm_latency omap_uart_latency[] = { };#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) {struct omap_device *od =to_omap_device (pdev);@@ -363,6 +342,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_timeout = info->dma_rx_timeout; omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout; + omap_up.use_pm_qos = info->use_pm_qos;/* Enable the MDR1 errata for OMAP3 */ if (cpu_is_omap34xx () && !cpu_is_ti816x ())arch/arm/plat-omap/include/plat/omap-serial.h +2
-0@@ -19,6 +19,7 @@#include <linux/serial_core.h> #include <linux/platform_device.h> +#include <linux/pm_qos_params.h> #include <plat/mux.h> @@ -68,6 +69,7 @@ struct omap_uart_port_info {unsigned int dma_rx_timeout;unsigned int autosuspend_timeout;unsigned int dma_rx_poll_rate; +u8 use_pm_qos;u32 (*get_context_loss_count)(struct device *);void (*set_forceidle)(struct platform_device *);
arch/arm/plat-omap/include/plat/omap-serial.h struct uart_omap_port { · line 137
Quoted 7 lines
arch/arm/plat-omap/include/plat/omap-serial.h +4
-0@@ -129,6 +131,12 @@ struct uart_omap_port {u32 context_loss_cnt;u32 errata;u8 wakeups_enabled; + +struct pm_qos_request_list pm_qos_request; +u32 latency; +struct work_struct work;
minor: call this qos_work.
Quoted 21 lines
arch/arm/plat-omap/include/plat/omap-serial.h +2
-0+u8 request_qos; + u8 use_pm_qos; };#endif /* __OMAP_SERIAL_H__ */ drivers/tty/serial/omap-serial.c +2
-0@@ -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 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) { offset <<= up->port.regshift;@@ -674,6 +676,21 @@ serial_omap_configure_xonxoffserial_out (up,UART_LCR , up->lcr); }
drivers/tty/serial/omap-serial.c serial_omap_configure_xonxoff · line 687
Quoted 10 lines
drivers/tty/serial/omap-serial.c +9
-0+static void serial_omap_uart_qos_work (struct work_struct *work) +{ + struct uart_omap_port *up = container_of(work, struct uart_omap_port, + work); + +if (!up->request_qos) { +pm_qos_add_request (&up->pm_qos_request, +PM_QOS_CPU_DMA_LATENCY , up->latency); + up->request_qos = true;
->request_qos is a confusing name. ->qos_requested would help readability, IMO.
Quoted 10 lines
drivers/tty/serial/omap-serial.c +6
-0+ }else { +pm_qos_remove_request (&up->pm_qos_request); + up->request_qos = false; + } +} +static void serial_omap_set_termios (struct uart_port *port,struct ktermios *termios,struct ktermios *old)
drivers/tty/serial/omap-serial.c serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, · line 893
Quoted 8 lines
drivers/tty/serial/omap-serial.c +5
-0@@ -869,6 +886,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_omap_configure_xonxoff (up, termios);spin_unlock_irqrestore (&up->port.lock, flags); + +if (up->use_pm_qos) { +/* calculate wakeup latency constraint */ + up->latency = (1000000 * up->port.fifosize) / (1000 * baud /8 ); +schedule_work (&up->work);
Is this one really needed? There's a pm_runtime_put() right after this that will immediately remove the constraint.
Actually, it seems like it would be better to calculate the latency earlier in this function (right after the baud rate) so that the subsequent pm_runtime_get() sets the constraint...
drivers/tty/serial/omap-serial.c serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, · line 896
Quoted 3 lines
drivers/tty/serial/omap-serial.c +2
-0+ } +pm_runtime_put (&up->pdev->dev);
...and this will remove the constraint.
Quoted 46 lines
drivers/tty/serial/omap-serial.c +13
-1dev_dbg (up->port.dev,"serial_omap_set_termios+%d\n" , up->pdev->id); }@@ -1144,8 +1168,11 @@ static int serial_omap_suspend(struct device *dev) {struct uart_omap_port *up =dev_get_drvdata (dev); -if (up) +if (up) {uart_suspend_port (&serial_omap_reg, &up->port); +flush_work_sync (&up->work); + } +return 0 ; }@@ -1368,6 +1395,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.uartclk = omap_up_info->uartclk; up->uart_dma.uart_base = mem->start; up->errata = omap_up_info->errata; + up->use_pm_qos = omap_up_info->use_pm_qos;if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start;@@ -1382,6 +1410,11 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.rx_dma_channel =OMAP_UART_DMA_CH_FREE ; } +if (up->use_pm_qos) { + serial_omap_uart_wq =create_workqueue (up->name); +INIT_WORK (&up->work, serial_omap_uart_qos_work); + } +pm_runtime_use_autosuspend (&pdev->dev);pm_runtime_set_autosuspend_delay (&pdev->dev, omap_up_info->autosuspend_timeout);@@ -1516,6 +1549,9 @@ static int serial_omap_runtime_suspend(struct device *dev)if (up->use_dma && pdata->set_forceidle) pdata->set_forceidle (up->pdev); +if (up->use_pm_qos && up->request_qos) +schedule_work (&up->work); +return 0 ; }
drivers/tty/serial/omap-serial.c static int serial_omap_runtime_resume(struct device *dev) · line 1579
Quoted 9 lines
drivers/tty/serial/omap-serial.c +3
-0@@ -1535,6 +1571,9 @@ static int serial_omap_runtime_resume(struct device *dev)/* Errata i291 */ if (up->use_dma && pdata->set_noidle) pdata->set_noidle (up->pdev); + +if (up->use_pm_qos && !up->request_qos) +schedule_work (&up->work); }return 0 ;
Kevin
[1] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg57577.html
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Hi Kevin,
Quoted 3 lines · Kevin Hilman
However, as mentioned previously[1], due to a HW sleepdep between MPU and CORE, this constraint isn't actually needed for CORE UARTs, so it's a bit wasteful to go through all the constraint setting for no reason.
I had a short chat with Govind on this and was trying to understand this better.
Are you referring to the 'autodeps' for omap3 here, because they would prevent any clock domain from idling as long as MPU or IVA are active, but not the other way round. Which means MPU can still idle, while CORE does not.
My guess was, its probably the CORE domain idling itself thats causing the UART sluggishness, (and not MPU idling), due to higher latency, which is prevented with an active UART module in CORE, but not in PER. So Govind did a small experiment to prevent just CORE idling and let MPU idle alone and that did not show any sluggishness.
Now, putting a pm-qos constraint for a UART in CORE still looks redundant because the latency requirement that UART has is in some way *indirectly* met (because the active UART in CORE prevents CORE transitions in idle).
But don't you think the UART driver should express its latency constraints regardless, without thinking of any indirect ways in which the same requirements would have already been met?
regards,
Rajendra
Quoted 197 lines
The changelog should summarize this, and the init code should only enable the constraints for PER UARTs, at least on OMAP3. I'm not sure about OMAP4.
Quoted 58 lines
Quoted 58 lines
}, };@@ -87,28 +88,6 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }; #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) { struct omap_device *od = to_omap_device(pdev); @@ -363,6 +342,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_timeout = info->dma_rx_timeout; omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout;+ omap_up.use_pm_qos =
info->use_pm_qos;/* Enable the MDR1 errata for OMAP3 */ if (cpu_is_omap34xx()&& !cpu_is_ti816x())diff --git
a/arch/arm/plat-omap/include/plat/omap-serial.hb/arch/arm/plat-omap/include/plat/omap-serial.hindex 9a6879c..41eda3c 100644
---a/arch/arm/plat-omap/include/plat/omap-serial.h
+++b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -19,6 +19,7 @@#include<linux/serial_core.h> #include<linux/platform_device.h>+#include<linux/pm_qos_params.h>
#include<plat/mux.h>@@ -68,6 +69,7 @@ struct omap_uart_port_info { unsigned int dma_rx_timeout; unsigned int autosuspend_timeout; unsigned int dma_rx_poll_rate;+ u8
use_pm_qos;Quoted 10 lines
Quoted 10 lines
u32 (*get_context_loss_count)(struct device *); void (*set_forceidle)(struct platform_device *); @@ -129,6 +131,12 @@ struct uart_omap_port { u32 context_loss_cnt; u32 errata; u8 wakeups_enabled;+
+ structpm_qos_request_listpm_qos_request;
+ u32 latency;
+ structwork_structwork;minor: call this
qos_work.Quoted 22 lines
Quoted 22 lines
+ u8
request_qos;+ u8 use_pm_qos; }; #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 1714bd2..956736c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -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 void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);+static struct
workqueue_struct*serial_omap_uart_wq;
+
static inline unsigned intserial_in(struct uart_omap_port *up, int offset){ offset<<= up->port.regshift; @@ -674,6 +676,21 @@ serial_omap_configure_xonxoff serial_out(up, UART_LCR, up->lcr); }Quoted 9 lines
Quoted 9 lines
+static void
serial_omap_uart_qos_work(struct work_struct *work)+{
+ structuart_omap_port*up = container_of(work, structuart_omap_port,
+ work);
+
+ if (!up->request_qos) {
+ pm_qos_add_request(&up->pm_qos_request,
+PM_QOS_CPU_DMA_LATENCY,up->latency);
+up->request_qos= true;->request_qos is a confusing name. ->qos_requested would help readability, IMO.
Quoted 12 lines
Quoted 12 lines
+ } else {
+pm_qos_remove_request(&up->pm_qos_request);
+up->request_qos= false;
+ }
+}
+
static void
serial_omap_set_termios(structuart_port*port, struct ktermios *termios,
struct ktermios *old)
@@ -869,6 +886,13 @@ serial_omap_set_termios(structuart_port*port, struct ktermios *termios,
serial_omap_configure_xonxoff(up, termios);Quoted 6 lines
Quoted 6 lines
spin_unlock_irqrestore(&up->port.lock, flags);+
+ if (up->use_pm_qos) {
+ /* calculate wakeup latency constraint */
+up->latency= (1000000 *up->port.fifosize) / (1000 * baud / 8);
+schedule_work(&up->work);Is this one really needed? There's a
pm_runtime_put()right after this that will immediately remove the constraint.Actually, it seems like it would be better to calculate the latency earlier in this function (right after the baud rate) so that the subsequent
pm_runtime_get()sets the constraint...Quoted 3 lines
Quoted 3 lines
+ }
+
pm_runtime_put(&up->pdev->dev);...and this will remove the constraint.
Quoted 54 lines
Quoted 54 lines
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id); } @@ -1144,8 +1168,11 @@ static int serial_omap_suspend(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev);- if (up)
+ if (up) { uart_suspend_port(&serial_omap_reg,&up->port); + flush_work_sync(&up->work); + } + return 0; }@@ -1368,6 +1395,7 @@ static int
serial_omap_probe(struct platform_device *pdev)up->port.uartclk = omap_up_info->uartclk; up->uart_dma.uart_base = mem->start; up->errata = omap_up_info->errata;+
up->use_pm_qos=omap_up_info->use_pm_qos;if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start; @@ -1382,6 +1410,11 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; }+ if (
up->use_pm_qos) {
+serial_omap_uart_wq=create_workqueue(up->name);
+INIT_WORK(&up->work, serial_omap_uart_qos_work);
+ }
+pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout);@@ -1516,6 +1549,9 @@ static int
serial_omap_runtime_suspend(struct device *dev)
if (up->use_dma&&pdata->set_forceidle)
pdata->set_forceidle(up->pdev);+ if (up->use_pm_qos&&
up->request_qos)
+schedule_work(&up->work);
+return 0; }@@ -1535,6 +1571,9 @@ static int
serial_omap_runtime_resume(struct device *dev)
/* Errata i291 */
if (up->use_dma&&pdata->set_noidle)
pdata->set_noidle(up->pdev);
+
+ if (up->use_pm_qos&& !up->request_qos)+ schedule_work(&up->work); }Quoted 1 line
Quoted 1 line
return 0;Kevin
[1]http://www.mail-archive.com/linux-omap at vger.kernel.org/msg57577.html
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Quoted 11 lines · Rajendra Nayak
Hi Kevin,
Quoted 3 lines · Kevin Hilman
However, as mentioned previously[1], due to a HW sleepdep between MPU and CORE, this constraint isn't actually needed for CORE UARTs, so it's a bit wasteful to go through all the constraint setting for no reason.
I had a short chat with Govind on this and was trying to understand this better.
Are you referring to the 'autodeps' for omap3 here, because they would prevent any clock domain from idling as long as MPU or IVA are active,
No, I was thinking of HW sleepdeps. However, I looked back at the OMAP3430 TRM and see that MPU does not have a HW sleepdep on CORE like I thought.
Quoted 6 lines
but not the other way round. Which means MPU can still idle, while CORE does not.
My guess was, its probably the CORE domain idling itself thats causing the UART sluggishness, (and not MPU idling), due to higher latency, which is prevented with an active UART module in CORE, but not in PER.
OK, that indeed makes sense. Thanks for correcting me.
Quoted 2 lines
So Govind did a small experiment to prevent just CORE idling and let MPU idle alone and that did not show any sluggishness.
OK, good.
Quoted 7 lines
Now, putting a pm-qos constraint for a UART in CORE still looks redundant because the latency requirement that UART has is in some way *indirectly* met (because the active UART in CORE prevents CORE transitions in idle).
But don't you think the UART driver should express its latency constraints regardless, without thinking of any indirect ways in which the same requirements would have already been met?
Yes, you're right. The driver should not need to know which powerdomain a given UART is in. It's probably best (and most portable) to have UART always express its requirements all the time.
Thanks for digging into this,
Kevin
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Hi Kevin,
Quoted 40 lines · Kevin Hilman
Quoted 11 lines · Rajendra Nayak
Hi Kevin,
Quoted 3 lines · Kevin Hilman
However, as mentioned previously[1], due to a HW sleepdep between MPU and CORE, this constraint isn't actually needed for CORE UARTs, so it's a bit wasteful to go through all the constraint setting for no reason.
I had a short chat with Govind on this and was trying to understand this better.
Are you referring to the 'autodeps' for omap3 here, because they would prevent any clock domain from idling as long as MPU or IVA are active,No, I was thinking of HW sleepdeps. ?However, I looked back at the OMAP3430 TRM and see that MPU does not have a HW sleepdep on CORE like I thought.
Quoted 6 lines
but not the other way round. Which means MPU can still idle, while CORE does not.
My guess was, its probably the CORE domain idling itself thats causing the UART sluggishness, (and not MPU idling), due to higher latency, which is prevented with an active UART module in CORE, but not in PER.
OK, that indeed makes sense. ?Thanks for correcting me.
Quoted 2 lines
So Govind did a small experiment to prevent just CORE idling and let MPU idle alone and that did not show any sluggishness.
OK, good.
Quoted 7 lines
Now, putting a pm-qos constraint for a UART in CORE still looks redundant because the latency requirement that UART has is in some way *indirectly* met (because the active UART in CORE prevents CORE transitions in idle).
But don't you think the UART driver should express its latency constraints regardless, without thinking of any indirect ways in which the same requirements would have already been met?
Quoted 6 lines
Yes, you're right. ?The driver should not need to know which powerdomain a given UART is in. ?It's probably best (and most portable) to have UART always express its requirements all the time.
Thanks for digging into this,
I have fixed this and other uart_v7 comments and have re-based the patch series on top
of 3.2-rc1 along with Tero's v9 irq chaining patches and tested the same. Available here [1].
Can this patches series be added to a test branch for upstreaming or do you think there are still some outstanding comments that needs to be discussed?
--
Thanks,
Govindraj.R
[1]:
git://gitorious.org/runtime_3-0/runtime_3-0.git
3.2-rc1_uart_runtime
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Quoted 47 lines · Govindraj
Hi Kevin,
Quoted 44 lines · Kevin Hilman
Quoted 11 lines · Rajendra Nayak
Hi Kevin,
Quoted 3 lines · Kevin Hilman
However, as mentioned previously[1], due to a HW sleepdep between MPU and CORE, this constraint isn't actually needed for CORE UARTs, so it's a bit wasteful to go through all the constraint setting for no reason.
I had a short chat with Govind on this and was trying to understand this better.
Are you referring to the 'autodeps' for omap3 here, because they would prevent any clock domain from idling as long as MPU or IVA are active,No, I was thinking of HW sleepdeps. ?However, I looked back at the OMAP3430 TRM and see that MPU does not have a HW sleepdep on CORE like I thought.
Quoted 6 lines
but not the other way round. Which means MPU can still idle, while CORE does not.
My guess was, its probably the CORE domain idling itself thats causing the UART sluggishness, (and not MPU idling), due to higher latency, which is prevented with an active UART module in CORE, but not in PER.
OK, that indeed makes sense. ?Thanks for correcting me.
Quoted 2 lines
So Govind did a small experiment to prevent just CORE idling and let MPU idle alone and that did not show any sluggishness.
OK, good.
Quoted 7 lines
Now, putting a pm-qos constraint for a UART in CORE still looks redundant because the latency requirement that UART has is in some way *indirectly* met (because the active UART in CORE prevents CORE transitions in idle).
But don't you think the UART driver should express its latency constraints regardless, without thinking of any indirect ways in which the same requirements would have already been met?Yes, you're right. ?The driver should not need to know which powerdomain a given UART is in. ?It's probably best (and most portable) to have UART always express its requirements all the time.
Quoted 7 lines
Quoted 2 lines
Thanks for digging into this,
I have fixed this and other
uart_v7comments and have re-based the patch series on top
of 3.2-rc1 along with Tero's v9 irq chaining patches and tested the same. Available here [1].
Please repost your updated series.
Quoted 2 lines
Can this patches series be added to a test branch for upstreaming or do you think there are still some outstanding comments that needs to be discussed?
The PRCM IRQ chaining series is not yet finalized.
Kevin
PATCH v7 17/21 OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos
Quoted 2 lines · Kevin Hilman
Govindraj <[email protected]> writes:
[..]
Quoted 7 lines
Quoted 5 lines
I have fixed this and other
uart_v7comments and have re-based the patch series on top
of 3.2-rc1 along with Tero's v9 irq chaining patches and tested the same. Available here [1].Please repost your updated series.
Yes done. v8 posted [1]
Quoted 5 lines
Quoted 3 lines
Can this patches series be added to a test branch for upstreaming or do you think there are still some outstanding comments that needs to be discussed?
The PRCM IRQ chaining series is not yet finalized.
okay fine.
--
Thanks,
Govindraj.R
PATCH v7 18/21 OMAP2+: UART: remove temporary variable used to count uart instance
In reply to Govindraj.RReuse the num_uarts variable itself to count number of uarts.
--- arch/arm/mach-omap2/serial.c | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/serial.c +2 -5
@@ -253,15 +253,13 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata) {}static int __init omap_serial_early_init (void ) { -int i =0 ; - do { char oh_name[MAX_UART_HWMOD_NAME_LEN]; struct omap_hwmod *oh; struct omap_uart_state *uart; snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, - "uart%d", i + 1); + "uart%d", num_uarts + 1); oh = omap_hwmod_lookup(oh_name); if (!oh) break;
@@ -271,9 +269,8 @@ static int __init omap_serial_early_init(void)return -ENODEV ; uart->oh = oh; - uart->num = i++; + uart->num = num_uarts++;list_add_tail (&uart->node, &uart_list); - num_uarts++;/* * NOTE: omap_hwmod_setup*() has not yet been called,
Signature · 1 line
1.7.4.1
PATCH v7 19/21 OMAP2+: UART: Use custom activate func for console uart.
In reply to Govindraj.ROmap-uart can be used as console uart to print early boot messages using earlyprintk so for console uart prevent hwmod reset or idling during bootup.
Identify the console_uart set the id and use the custom pm_latency ops for console uart for the first time to idle console uart left enabled from bootup and then enable them back and reset pm_latency ops to default ops.
Thanks to Kevin Hilman <[email protected]> for suggesting this approach.
--- arch/arm/mach-omap2/serial.c | 79 ++++++++++++++++++++++++++++------------- 1 files changed, 54 insertions(+), 25 deletions(-)
arch/arm/mach-omap2/serial.c +54 -25
@@ -63,6 +63,7 @@ struct omap_uart_state {static LIST_HEAD (uart_list);static u8 num_uarts; +static u8 console_uart_id =-1 ;#define DEFAULT_RXDMA_POLLRATE 1/* RX DMA polling rate (us) */ #define DEFAULT_RXDMA_BUFSIZE 4096/* RX DMA buffer size */
@@ -87,6 +88,29 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }, }; +static int console_uart_enable_hwmod (struct omap_device *od) +{ +/* For early console we prevented hwmod reset and idle +* So before we enable the uart clocks idle and then +*/ +omap_hwmod_idle (od->hwmods[0 ]); +omap_hwmod_enable (od->hwmods[0 ]); + +/* restore the default activate/deactivate funcs, +* since now we have set the hwmod state machine right +* with the idle/enable for console uart +*/ + od->pm_lats = omap_uart_latency; + +return 0 ; +} + +static struct omap_device_pm_latency console_uart_latency[] = { + { + .activate_func = console_uart_enable_hwmod, + }, +}; +#ifdef CONFIG_PM static void omap_uart_enable_wakeup (struct platform_device *pdev,bool enable) {
@@ -251,12 +275,20 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)static void omap_serial_fill_default_pads (struct omap_board_data *bdata) {}#endif +char *cmdline_find_option (char *str) +{ +extern char *saved_command_line; + +return strstr (saved_command_line, str); +} +static int __init omap_serial_early_init (void ) { do { char oh_name[MAX_UART_HWMOD_NAME_LEN]; struct omap_hwmod *oh; struct omap_uart_state *uart; + char uart_name[MAX_UART_HWMOD_NAME_LEN]; snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, "uart%d", num_uarts + 1);
@@ -271,18 +303,23 @@ static int __init omap_serial_early_init(void) uart->oh = oh; uart->num = num_uarts++;list_add_tail (&uart->node, &uart_list); +snprintf (uart_name,MAX_UART_HWMOD_NAME_LEN , +"%s%d" ,OMAP_SERIAL_NAME , uart->num); + +if (cmdline_find_option (uart_name)) { + console_uart_id = uart->num; +/* +* omap-uart can be used for earlyprintk logs +* So if omap-uart is used as console then prevent +* uart reset and idle to get logs from omap-uart +* until uart console driver is available to take +* care for console messages. +* Idling or resetting omap-uart while printing logs +* early boot logs can stall the boot-up. +*/ + oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; + } -/* -* NOTE: omap_hwmod_setup*() has not yet been called, -* so no hwmod functions will work yet. -*/ - -/* -* During UART early init, device need to be probed -* to determine SoC specific init before omap_device -* is ready. Therefore, don't allow idle here -*/ - uart->oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; }while (1 );return 0 ;
@@ -311,6 +348,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,u32 pdata_size =0 ;char *name;struct omap_uart_port_info omap_up; +struct omap_device *od;if (WARN_ON (!bdata))return ;
@@ -357,6 +395,11 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,WARN (IS_ERR (pdev),"Could not build omap_device for %s: %s.\n" , name, oh->name); +if (console_uart_id == bdata->id) { + od =to_omap_device (pdev); + od->pm_lats = console_uart_latency; + } +omap_device_disable_idle_on_suspend (pdev); oh->mux =omap_hwmod_mux_init (bdata->pads, bdata->pads_cnt);
@@ -364,20 +407,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, oh->dev_attr = uart; -console_lock ();/* in case the earlycon is on the UART */ - -/* -* Because of early UART probing, UART did not get idled -* on init. Now that omap_device is ready, ensure full idle -* before doing omap_device_enable(). -*/ -omap_hwmod_idle (uart->oh); - -omap_device_enable (uart->pdev); -omap_device_idle (uart->pdev); - -console_unlock (); -if ((cpu_is_omap34xx () ||cpu_is_omap44xx ()) && bdata->pads)device_init_wakeup (&pdev->dev, true); }
Signature · 1 line
1.7.4.1
PATCH v7 19/21 OMAP2+: UART: Use custom activate func for console uart.
Quoted 30 lines · Govindraj.R
Omap-uart can be used as console uart to print early boot messages using earlyprintk so for console uart prevent hwmod reset or idling during bootup.
Identify the
console_uartset the id and use the custompm_latencyops for console uart for the first time to idle console uart left enabled from bootup and then enable them back and resetpm_latencyops to default ops.Thanks to Kevin Hilman <[email protected]> for suggesting this approach.
Signed-off-by Govindraj.R <[email protected]>--- arch/arm/mach-omap2/serial.c | 79 ++++++++++++++++++++++++++++------------- 1 files changed, 54 insertions(+), 25 deletions(-)arch/arm/mach-omap2/serial.c +1
-0@@ -63,6 +63,7 @@ struct omap_uart_state {static LIST_HEAD (uart_list);static u8 num_uarts; +static u8 console_uart_id =-1 ;#define DEFAULT_RXDMA_POLLRATE 1/* RX DMA polling rate (us) */ #define DEFAULT_RXDMA_BUFSIZE 4096/* RX DMA buffer size */
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = { · line 95
Quoted 8 lines
arch/arm/mach-omap2/serial.c +5
-0@@ -87,6 +88,29 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }, }; +static int console_uart_enable_hwmod (struct omap_device *od) +{ +/* For early console we prevented hwmod reset and idle +* So before we enable the uart clocks idle and then +*/
minor: fix multi-line comment style (search for multi-line in Documentation/CodingStyle). Another one below.
Notice that you're moving existing code here, but also changing the
functionality without a description as to why. Based on the existing code:
You need a console_lock() here...
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = { · line 97
Quoted 2 lines
arch/arm/mach-omap2/serial.c +2
-0+omap_hwmod_idle (od->hwmods[0 ]); +omap_hwmod_enable (od->hwmods[0 ]);
...and this should be omap_device_enable().
And you need a console_unlock() here.
Yes, you're subsequent patches avoid this problem, but we still need a real fix other than checking for 'debug/loglevel', and when that happens, we'll need a console lock here.
Quoted 19 lines
arch/arm/mach-omap2/serial.c +15
-0+/* restore the default activate/deactivate funcs, +* since now we have set the hwmod state machine right +* with the idle/enable for console uart +*/ + od->pm_lats = omap_uart_latency; + +return 0 ; +} + +static struct omap_device_pm_latency console_uart_latency[] = { + { + .activate_func = console_uart_enable_hwmod, + }, +}; +#ifdef CONFIG_PM static void omap_uart_enable_wakeup (struct platform_device *pdev,bool enable) {
arch/arm/mach-omap2/serial.c static void omap_serial_fill_default_pads(struct omap_board_data *bdata) · line 278
Quoted 4 lines
arch/arm/mach-omap2/serial.c +1
-0@@ -251,12 +275,20 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)static void omap_serial_fill_default_pads (struct omap_board_data *bdata) {}#endif +char *cmdline_find_option (char *str)
static inline
Quoted 82 lines
arch/arm/mach-omap2/serial.c +29
-18+{ +extern char *saved_command_line; + +return strstr (saved_command_line, str); +} +static int __init omap_serial_early_init (void ) { do { char oh_name[MAX_UART_HWMOD_NAME_LEN]; struct omap_hwmod *oh; struct omap_uart_state *uart; + char uart_name[MAX_UART_HWMOD_NAME_LEN]; snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, "uart%d", num_uarts + 1);@@ -271,18 +303,23 @@ static int __init omap_serial_early_init(void) uart->oh = oh; uart->num = num_uarts++;list_add_tail (&uart->node, &uart_list); +snprintf (uart_name,MAX_UART_HWMOD_NAME_LEN , +"%s%d" ,OMAP_SERIAL_NAME , uart->num); + +if (cmdline_find_option (uart_name)) { + console_uart_id = uart->num; +/* +* omap-uart can be used for earlyprintk logs +* So if omap-uart is used as console then prevent +* uart reset and idle to get logs from omap-uart +* until uart console driver is available to take +* care for console messages. +* Idling or resetting omap-uart while printing logs +* early boot logs can stall the boot-up. +*/ + oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; + } -/* -* NOTE: omap_hwmod_setup*() has not yet been called, -* so no hwmod functions will work yet. -*/ - -/* -* During UART early init, device need to be probed -* to determine SoC specific init before omap_device -* is ready. Therefore, don't allow idle here -*/ - uart->oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; }while (1 );return 0 ;@@ -311,6 +348,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,u32 pdata_size =0 ;char *name;struct omap_uart_port_info omap_up; +struct omap_device *od;if (WARN_ON (!bdata))return ;@@ -357,6 +395,11 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,WARN (IS_ERR (pdev),"Could not build omap_device for %s: %s.\n" , name, oh->name); +if (console_uart_id == bdata->id) { + od =to_omap_device (pdev); + od->pm_lats = console_uart_latency; + } +omap_device_disable_idle_on_suspend (pdev); oh->mux =omap_hwmod_mux_init (bdata->pads, bdata->pads_cnt);@@ -364,20 +407,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, oh->dev_attr = uart; -console_lock ();/* in case the earlycon is on the UART */ - -/* -* Because of early UART probing, UART did not get idled -* on init. Now that omap_device is ready, ensure full idle -* before doing omap_device_enable(). -*/
arch/arm/mach-omap2/serial.c void __init omap_serial_init_port(struct omap_board_data *bdata, · line 412
Quoted 10 lines
arch/arm/mach-omap2/serial.c +0
-7-omap_hwmod_idle (uart->oh); - -omap_device_enable (uart->pdev); -omap_device_idle (uart->pdev); - -console_unlock (); -if ((cpu_is_omap34xx () ||cpu_is_omap44xx ()) && bdata->pads)device_init_wakeup (&pdev->dev, true); }
Kevin
PATCH v7 19/21 OMAP2+: UART: Use custom activate func for console uart.
Quoted 35 lines · Kevin Hilman
Quoted 33 lines · Govindraj.R
Omap-uart can be used as console uart to print early boot messages using earlyprintk so for console uart prevent hwmod reset or idling during bootup.
Identify the
console_uartset the id and use the custompm_latencyops for console uart for the first time to idle console uart left enabled from bootup and then enable them back and resetpm_latencyops to default ops.Thanks to Kevin Hilman <[email protected]> for suggesting this approach.
Signed-off-by Govindraj.R <[email protected]>---
?arch/arm/mach-omap2/serial.c | ? 79 ++++++++++++++++++++++++++++------------- ?1 files changed, 54 insertions(+), 25 deletions(-)arch/arm/mach-omap2/serial.c +1
-0@@ -63,6 +63,7 @@ struct omap_uart_state { ?static LIST_HEAD(uart_list); ?static u8 num_uarts; +static u8 console_uart_id =-1 ;?#define
DEFAULT_RXDMA_POLLRATE? ? ? ? ? ? ? 1 ? ? ? /* RX DMA polling rate (us) */ ?#defineDEFAULT_RXDMA_BUFSIZE? ? ? ? ? ? ? ?4096 ? ?/* RX DMA buffer size */arch/arm/mach-omap2/serial.c +0
-0@@ -87,6 +88,29 @@ static struct omap_device_pm_latency omap_uart_latency[] = { ? ? ? }, ?};
Quoted 9 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = { · line 95
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+static int console_uart_enable_hwmod (struct omap_device *od) +{ + ? ? /* For early console we prevented hwmod reset and idle +? ? ?* So before we enable the uart clocks idle and then +? ? ?*/ minor: fix multi-line comment style (search for multi-line in
Documentation/CodingStyle). ?Another one below.
will correct this.
Quoted 8 lines
Notice that you're moving existing code here, but also changing the functionality without a description as to why. ? ?Based on the existing code:
You need a
console_lock()here...arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = { · line 97
Quoted 2 lines
arch/arm/mach-omap2/serial.c +2
-0+ ? ? omap_hwmod_idle(od->hwmods[0]); + ? ? omap_hwmod_enable(od->hwmods[0]);
Quoted 8 lines
...and this should be
omap_device_enable().And ?you need a
console_unlock()here.Yes, you're subsequent patches avoid this problem, but we still need a real fix other than checking for 'debug/loglevel', and when that happens, we'll need a console lock here.
yes correct, we need console_lock/unlock binding here will update this.
--
Thanks,
Govindraj.R