Loading drivers/tty/serial/msm_geni_serial.c +74 −65 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ struct msm_geni_serial_port { void *ipc_log_pwr; void *ipc_log_misc; unsigned int cur_baud; int ioctl_count; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -161,6 +162,8 @@ static int handle_rx_hs(struct uart_port *uport, static unsigned int msm_geni_serial_tx_empty(struct uart_port *port); static int msm_geni_serial_power_on(struct uart_port *uport); static void msm_geni_serial_power_off(struct uart_port *uport); static int msm_geni_serial_poll_bit(struct uart_port *uport, int offset, int bit_field, bool set); static atomic_t uart_line_id = ATOMIC_INIT(0); Loading Loading @@ -218,22 +221,22 @@ static void dump_ipc(void *ipc_ctx, char *prefix, char *string, (unsigned int)addr, size, buf); } static void check_tx_active(struct uart_port *uport) static bool check_tx_active(struct uart_port *uport) { u32 geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); while ((geni_status & M_GENI_CMD_ACTIVE)) { cpu_relax(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); } /* * Poll if the GENI STATUS bit for TX is cleared. If the bit is * clear (poll condition met), return false, meaning tx isn't active * else return true. So return not of the poll return. */ return !msm_geni_serial_poll_bit(uport, SE_GENI_STATUS, M_GENI_CMD_ACTIVE, false); } static int vote_clock_on(struct uart_port *uport) { int ret = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); Loading @@ -245,8 +248,10 @@ static int vote_clock_on(struct uart_port *uport) dev_err(uport->dev, "Failed to vote clock on\n"); return ret; } port->ioctl_count++; __pm_relax(&port->geni_wake); IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__); IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n", __func__, usage_count, port->ioctl_count); return 0; } Loading @@ -254,16 +259,29 @@ static int vote_clock_off(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int ret = 0; int usage_count = atomic_read(&uport->dev->power.usage_count); if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); ret = -EPERM; return ret; } /* Block till any on going Tx goes out.*/ check_tx_active(uport); /* Check on going Tx. Don't block on this for now. */ if (check_tx_active(uport)) dev_warn(uport->dev, "%s: Vote off called during active Tx", __func__); if (!port->ioctl_count) { dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n", __func__, usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s:Imbalanced vote_off from userspace rpm%d", __func__, usage_count); return 0; } port->ioctl_count--; msm_geni_serial_power_off(uport); IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__); IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n", __func__, usage_count, port->ioctl_count); return 0; }; Loading Loading @@ -398,20 +416,20 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport, bool cond = false; unsigned int baud = 115200; unsigned int fifo_bits = DEF_FIFO_DEPTH_WORDS * DEF_FIFO_WIDTH_BITS; unsigned long total_iter = 0; unsigned long total_iter = 1000; if (uport->private_data) { if (uport->private_data && !uart_console(uport)) { port = GET_DEV_PORT(uport); baud = (port->cur_baud ? port->cur_baud : 115200); fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; } /* * Total polling iterations based on FIFO worth of bytes to be * sent at current baud .Add a little fluff to the wait. */ total_iter = ((fifo_bits * USEC_PER_SEC) / baud); total_iter += 50; } while (iter < total_iter) { reg = geni_read_reg_nolog(uport->membase, offset); Loading Loading @@ -449,18 +467,12 @@ static void msm_geni_serial_poll_cancel_tx(struct uart_port *uport) done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { geni_write_reg_nolog(M_GENI_CMD_CANCEL, uport->membase, SE_GENI_S_CMD_CTRL_REG); irq_clear |= M_CMD_CANCEL_EN; if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase, SE_GENI_M_CMD_CTRL_REG); irq_clear |= M_CMD_ABORT_EN; msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); } } geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR); } Loading Loading @@ -678,7 +690,6 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); /* Geni command setup/irq enables should complete before returning.*/ mb(); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__); } static void msm_geni_serial_stop_tx(struct uart_port *uport) Loading Loading @@ -1032,8 +1043,25 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) if (!uart_console(uport)) { /* For now only assume FIFO mode. */ msm_port->xfer_mode = FIFO_MODE; ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); se_get_packing_config(8, 4, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } else { /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ msm_port->xfer_mode = FIFO_MODE; msm_geni_serial_poll_cancel_tx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); if (ret) { dev_err(uport->dev, "%s: Fail\n", __func__); goto exit_portsetup; Loading @@ -1043,13 +1071,6 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) if (ret) goto exit_portsetup; se_get_packing_config(8, 4, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } msm_port->port_setup = true; /* * Ensure Port setup related IO completes before returning to Loading Loading @@ -1118,13 +1139,11 @@ static int msm_geni_serial_startup(struct uart_port *uport) if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); if (unlikely(get_se_proto(uport->membase) != UART)) { ret = -ENXIO; disable_irq(uport->irq); free_irq(uport->irq, msm_port); goto exit_startup; } } if (!msm_port->port_setup) { if (msm_geni_serial_port_setup(uport)) Loading Loading @@ -1358,7 +1377,6 @@ static int __init msm_geni_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; int ret = 0; unsigned long cfg0, cfg1; if (unlikely(co->index >= GENI_UART_NR_PORTS || co->index < 0)) return -ENXIO; Loading Loading @@ -1386,14 +1404,6 @@ static int __init msm_geni_console_setup(struct console *co, char *options) if (!dev_port->port_setup) msm_geni_serial_port_setup(uport); /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); Loading Loading @@ -1438,9 +1448,6 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, goto exit_geni_serial_earlyconsetup; } geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), (DEF_FIFO_DEPTH_WORDS - 2)); geni_se_select_mode(uport->membase, FIFO_MODE); /* * Ignore Flow control. * Disable Tx Parity. Loading Loading @@ -1471,7 +1478,11 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); msm_geni_serial_abort_rx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), (DEF_FIFO_DEPTH_WORDS - 2)); geni_se_select_mode(uport->membase, FIFO_MODE); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); geni_write_reg_nolog(tx_trans_cfg, uport->membase, Loading Loading @@ -1802,8 +1813,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) } if (port->wakeup_irq > 0) enable_irq(port->wakeup_irq); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__, atomic_read(&dev->power.usage_count)); IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); exit_runtime_suspend: return ret; } Loading @@ -1821,8 +1831,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev) dev_err(dev, "%s: Error ret %d\n", __func__, ret); goto exit_runtime_resume; } IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__, atomic_read(&dev->power.usage_count)); IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); exit_runtime_resume: return ret; } Loading Loading
drivers/tty/serial/msm_geni_serial.c +74 −65 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ struct msm_geni_serial_port { void *ipc_log_pwr; void *ipc_log_misc; unsigned int cur_baud; int ioctl_count; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -161,6 +162,8 @@ static int handle_rx_hs(struct uart_port *uport, static unsigned int msm_geni_serial_tx_empty(struct uart_port *port); static int msm_geni_serial_power_on(struct uart_port *uport); static void msm_geni_serial_power_off(struct uart_port *uport); static int msm_geni_serial_poll_bit(struct uart_port *uport, int offset, int bit_field, bool set); static atomic_t uart_line_id = ATOMIC_INIT(0); Loading Loading @@ -218,22 +221,22 @@ static void dump_ipc(void *ipc_ctx, char *prefix, char *string, (unsigned int)addr, size, buf); } static void check_tx_active(struct uart_port *uport) static bool check_tx_active(struct uart_port *uport) { u32 geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); while ((geni_status & M_GENI_CMD_ACTIVE)) { cpu_relax(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); } /* * Poll if the GENI STATUS bit for TX is cleared. If the bit is * clear (poll condition met), return false, meaning tx isn't active * else return true. So return not of the poll return. */ return !msm_geni_serial_poll_bit(uport, SE_GENI_STATUS, M_GENI_CMD_ACTIVE, false); } static int vote_clock_on(struct uart_port *uport) { int ret = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); Loading @@ -245,8 +248,10 @@ static int vote_clock_on(struct uart_port *uport) dev_err(uport->dev, "Failed to vote clock on\n"); return ret; } port->ioctl_count++; __pm_relax(&port->geni_wake); IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__); IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n", __func__, usage_count, port->ioctl_count); return 0; } Loading @@ -254,16 +259,29 @@ static int vote_clock_off(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int ret = 0; int usage_count = atomic_read(&uport->dev->power.usage_count); if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); ret = -EPERM; return ret; } /* Block till any on going Tx goes out.*/ check_tx_active(uport); /* Check on going Tx. Don't block on this for now. */ if (check_tx_active(uport)) dev_warn(uport->dev, "%s: Vote off called during active Tx", __func__); if (!port->ioctl_count) { dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n", __func__, usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s:Imbalanced vote_off from userspace rpm%d", __func__, usage_count); return 0; } port->ioctl_count--; msm_geni_serial_power_off(uport); IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__); IPC_LOG_MSG(port->ipc_log_pwr, "%s rpm %d ioctl %d\n", __func__, usage_count, port->ioctl_count); return 0; }; Loading Loading @@ -398,20 +416,20 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport, bool cond = false; unsigned int baud = 115200; unsigned int fifo_bits = DEF_FIFO_DEPTH_WORDS * DEF_FIFO_WIDTH_BITS; unsigned long total_iter = 0; unsigned long total_iter = 1000; if (uport->private_data) { if (uport->private_data && !uart_console(uport)) { port = GET_DEV_PORT(uport); baud = (port->cur_baud ? port->cur_baud : 115200); fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; } /* * Total polling iterations based on FIFO worth of bytes to be * sent at current baud .Add a little fluff to the wait. */ total_iter = ((fifo_bits * USEC_PER_SEC) / baud); total_iter += 50; } while (iter < total_iter) { reg = geni_read_reg_nolog(uport->membase, offset); Loading Loading @@ -449,18 +467,12 @@ static void msm_geni_serial_poll_cancel_tx(struct uart_port *uport) done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { geni_write_reg_nolog(M_GENI_CMD_CANCEL, uport->membase, SE_GENI_S_CMD_CTRL_REG); irq_clear |= M_CMD_CANCEL_EN; if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase, SE_GENI_M_CMD_CTRL_REG); irq_clear |= M_CMD_ABORT_EN; msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); } } geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR); } Loading Loading @@ -678,7 +690,6 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); /* Geni command setup/irq enables should complete before returning.*/ mb(); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s\n", __func__); } static void msm_geni_serial_stop_tx(struct uart_port *uport) Loading Loading @@ -1032,8 +1043,25 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) if (!uart_console(uport)) { /* For now only assume FIFO mode. */ msm_port->xfer_mode = FIFO_MODE; ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); se_get_packing_config(8, 4, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } else { /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ msm_port->xfer_mode = FIFO_MODE; msm_geni_serial_poll_cancel_tx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); if (ret) { dev_err(uport->dev, "%s: Fail\n", __func__); goto exit_portsetup; Loading @@ -1043,13 +1071,6 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) if (ret) goto exit_portsetup; se_get_packing_config(8, 4, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); } msm_port->port_setup = true; /* * Ensure Port setup related IO completes before returning to Loading Loading @@ -1118,13 +1139,11 @@ static int msm_geni_serial_startup(struct uart_port *uport) if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); if (unlikely(get_se_proto(uport->membase) != UART)) { ret = -ENXIO; disable_irq(uport->irq); free_irq(uport->irq, msm_port); goto exit_startup; } } if (!msm_port->port_setup) { if (msm_geni_serial_port_setup(uport)) Loading Loading @@ -1358,7 +1377,6 @@ static int __init msm_geni_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; int ret = 0; unsigned long cfg0, cfg1; if (unlikely(co->index >= GENI_UART_NR_PORTS || co->index < 0)) return -ENXIO; Loading Loading @@ -1386,14 +1404,6 @@ static int __init msm_geni_console_setup(struct console *co, char *options) if (!dev_port->port_setup) msm_geni_serial_port_setup(uport); /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); Loading Loading @@ -1438,9 +1448,6 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, goto exit_geni_serial_earlyconsetup; } geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), (DEF_FIFO_DEPTH_WORDS - 2)); geni_se_select_mode(uport->membase, FIFO_MODE); /* * Ignore Flow control. * Disable Tx Parity. Loading Loading @@ -1471,7 +1478,11 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); msm_geni_serial_abort_rx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), (DEF_FIFO_DEPTH_WORDS - 2)); geni_se_select_mode(uport->membase, FIFO_MODE); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1); geni_write_reg_nolog(tx_trans_cfg, uport->membase, Loading Loading @@ -1802,8 +1813,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) } if (port->wakeup_irq > 0) enable_irq(port->wakeup_irq); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__, atomic_read(&dev->power.usage_count)); IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); exit_runtime_suspend: return ret; } Loading @@ -1821,8 +1831,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev) dev_err(dev, "%s: Error ret %d\n", __func__, ret); goto exit_runtime_resume; } IPC_LOG_MSG(port->ipc_log_pwr, "%s: Current usage count %d\n", __func__, atomic_read(&dev->power.usage_count)); IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); exit_runtime_resume: return ret; } Loading