From b4f604b50bd59e3dd10fcce40523c0f26aaadf8b Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 25 Apr 2014 13:56:20 +0800 Subject: ENGR00310498 usb: chipidea: otg: fix otg role switch from host to device failure This patch fix the failure when OTG port switch from host to device mode after removes ID cable with usb device(e.g usb hub) connected. How to reproduce: - Enable console wakeup: echo enabled > /sys/class/tty/ttymxc0/power/wakeup - Connect a usb hub with ID cable to OTG port. - Suspend the system: ehco mem > /sys/power/state - Wakeup the system by console. - Remove ID cable together with usb hub. - OTG port cannot switch to device role. Root cause: In this case, ID change interrupt generates before port change interrupt, so with irq disabled, ci_handle_id_switch() will find there is usb device still connected and wait it to disconnect by sleep, but disconnect will not happen since usb irq still disabled so port change irq has no chance to be handled. How this patch is fixing this issue: This patch enables irq before sleep and disables irq after, thus port change irq can be handled and usb device disconnection can timely happen, then ci_handle_id_switch() can stop host and switch to device role correctly. meanwhile change the delay time to 10~15 ms to avoid too frequent connection check and irq enable/disable. Signed-off-by: Li Jun --- drivers/usb/chipidea/otg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index fb8a1fe6ead3..70ac5c4028af 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -100,8 +100,11 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) if ((ci->role == CI_ROLE_HOST) && ci->hcd) { roothub = ci->hcd->self.root_hub; for (i = 0; i < roothub->maxchild; ++i) { - while (usb_hub_find_child(roothub, (i + 1))) - usleep_range(500, 1000); + while (usb_hub_find_child(roothub, (i + 1))) { + enable_irq(ci->irq); + usleep_range(10000, 15000); + disable_irq_nosync(ci->irq); + } } } -- cgit v1.2.3 From 30ae10651c7dc6b2aa50e13cc4be83b9d7983c04 Mon Sep 17 00:00:00 2001 From: Xianzhong Date: Mon, 28 Apr 2014 21:36:36 +0800 Subject: ENGR00310742 [#1087] fixed gpu database query failure this patch fix gpu database query failure with gmem_info Date: Apr 28, 2014 Signed-off-by: Xianzhong Acked-by: Jason Liu (cherry picked from commit e04a8681a977153c7adf34c36d7ee33218cfcab3) --- drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c index 97b64850e4e1..733e45060673 100644 --- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c +++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c @@ -1591,12 +1591,19 @@ gckKERNEL_QueryProcessDB( } /* Release the database mutex. */ - gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: + if(acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + /* Return the status. */ gcmkFOOTER(); return status; -- cgit v1.2.3 From c868f352379d739076256e75ce81fe9d7f934f35 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 23 Apr 2014 09:58:25 -0500 Subject: tty_ldisc: add more limits to the @write_wakeup In the uart_handle_cts_change(), uart_write_wakeup() is called after we call @uart_port->ops->start_tx(). The Documentation/serial/driver tells us: ----------------------------------------------- start_tx(port) Start transmitting characters. Locking: port->lock taken. Interrupts: locally disabled. ----------------------------------------------- So when the uart_write_wakeup() is called, the port->lock is taken by the upper. See the following callstack: |_ uart_write_wakeup |_ tty_wakeup |_ ld->ops->write_wakeup With the port->lock held, we call the @write_wakeup. Some implemetation of the @write_wakeup does not notice that the port->lock is held, and it still tries to send data with uart_write() which will try to grab the prot->lock. A dead lock occurs, see the following log caught in the Bluetooth by uart: -------------------------------------------------------------------- BUG: spinlock lockup suspected on CPU#0, swapper/0/0 lock: 0xdc3f4410, .magic: dead4ead, .owner: swapper/0/0, .owner_cpu: 0 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.10.17-16839-ge4a1bef #1320 [<80014cbc>] (unwind_backtrace+0x0/0x138) from [<8001251c>] (show_stack+0x10/0x14) [<8001251c>] (show_stack+0x10/0x14) from [<802816ac>] (do_raw_spin_lock+0x108/0x184) [<802816ac>] (do_raw_spin_lock+0x108/0x184) from [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) from [<802f5754>] (uart_write+0x38/0xe0) [<802f5754>] (uart_write+0x38/0xe0) from [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) from [<802dab18>] (tty_wakeup+0x50/0x5c) [<802dab18>] (tty_wakeup+0x50/0x5c) from [<802f81a4>] (imx_rtsint+0x50/0x80) [<802f81a4>] (imx_rtsint+0x50/0x80) from [<802f88f4>] (imx_int+0x158/0x17c) [<802f88f4>] (imx_int+0x158/0x17c) from [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) from [<8007ad60>] (handle_irq_event+0x3c/0x5c) -------------------------------------------------------------------- This patch adds more limits to the @write_wakeup, the one who wants to implemet the @write_wakeup should follow the limits which avoid the deadlock. Signed-off-by: Huang Shijie Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- include/linux/tty_ldisc.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 58390c73df8b..84c9d8a96f48 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -91,7 +91,10 @@ * This function is called by the low-level tty driver to signal * that line discpline should try to send more characters to the * low-level driver for transmission. If the line discpline does - * not have any more data to send, it can just return. + * not have any more data to send, it can just return. If the line + * discipline does have some data to send, please arise a tasklet + * or workqueue to do the real data transfer. Do not send data in + * this hook, it may leads to a deadlock. * * int (*hangup)(struct tty_struct *) * -- cgit v1.2.3 From 2b2ab2029243b98bd8cd23f44ce757e39df6fb2e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 23 Apr 2014 09:58:26 -0500 Subject: bluetooth: hci_ldisc: fix deadlock condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LDISCs shouldn't call tty->ops->write() from within ->write_wakeup(). ->write_wakeup() is called with port lock taken and IRQs disabled, tty->ops->write() will try to acquire the same port lock and we will deadlock. Acked-by: Marcel Holtmann Reviewed-by: Peter Hurley Reported-by: Huang Shijie Signed-off-by: Felipe Balbi Tested-by: Andreas Bießmann Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Huang Shijie --- drivers/bluetooth/hci_ldisc.c | 24 +++++++++++++++++++----- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index bc68a440d432..c4d2f0e48685 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = hu->hdev; - struct sk_buff *skb; - if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); + schedule_work(&hu->write_work); + + return 0; +} + +static void hci_uart_write_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, write_work); + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + + /* REVISIT: should we cope with bad skbs or ->write() returning + * and error value ? + */ + restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -153,7 +165,6 @@ restart: goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return 0; } static void hci_uart_init_work(struct work_struct *work) @@ -289,6 +300,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; INIT_WORK(&hu->init_ready, hci_uart_init_work); + INIT_WORK(&hu->write_work, hci_uart_write_work); spin_lock_init(&hu->rx_lock); @@ -326,6 +338,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); + cancel_work_sync(&hu->write_work); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fffa61ff5cb1..12df101ca942 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -68,6 +68,7 @@ struct hci_uart { unsigned long hdev_flags; struct work_struct init_ready; + struct work_struct write_work; struct hci_uart_proto *proto; void *priv; -- cgit v1.2.3 From 182841f5a558c8d66db013a85d43678d33d1741c Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:33 +0400 Subject: serial: imx: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler and it gives proper codes on errors. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Huang Shijie --- drivers/tty/serial/imx.c | 44 ++++---------------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dff0f0a472ea..d1859724bf2a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1468,36 +1468,6 @@ static const char *imx_type(struct uart_port *port) return sport->port.type == PORT_IMX ? "IMX" : NULL; } -/* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - - return ret ? 0 : -EBUSY; -} - /* * Configure/autoconfigure the port. */ @@ -1505,8 +1475,7 @@ static void imx_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) + if (flags & UART_CONFIG_TYPE) sport->port.type = PORT_IMX; } @@ -1616,8 +1585,6 @@ static struct uart_ops imx_pops = { .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, .config_port = imx_config_port, .verify_port = imx_verify_port, #if defined(CONFIG_CONSOLE_POLL) @@ -1950,12 +1917,9 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; -- cgit v1.2.3 From 01769d97e98ca1be48d64eee31311fefe9812c6c Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:34 +0400 Subject: serial: imx: Use dev_name() for request_irq() to distinguish UARTs Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Huang Shijie --- drivers/tty/serial/imx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d1859724bf2a..37c39390efb7 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1116,25 +1116,25 @@ static int imx_startup(struct uart_port *port) */ if (sport->txirq > 0) { retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out1; retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out2; /* do not use RTS IRQ on IrDA */ if (!USE_IRDA(sport)) { retval = request_irq(sport->rtsirq, imx_rtsint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out3; } } else { retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) { free_irq(sport->port.irq, sport); goto error_out1; -- cgit v1.2.3 From 8614fc820d62cc2c84eea8d2fdd3157805fdb1c5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 16:01:35 +0400 Subject: serial: imx: Remove init() and exit() platform callbacks Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Huang Shijie --- arch/arm/mach-imx/mach-mx31moboard.c | 21 +++++---------------- drivers/tty/serial/imx.c | 27 ++------------------------- include/linux/platform_data/serial-imx.h | 2 -- 3 files changed, 7 insertions(+), 43 deletions(-) diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index dae4cd7be040..fb0211617e32 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = { .num_resources = 1, }; -static int moboard_uart0_init(struct platform_device *pdev) +static void __init moboard_uart0_init(void) { - int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack"); - if (ret) - return ret; - - ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); - if (ret) + if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) { + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); - - return ret; -} - -static void moboard_uart0_exit(struct platform_device *pdev) -{ - gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); + } } static const struct imxuart_platform_data uart0_pdata __initconst = { - .init = moboard_uart0_init, - .exit = moboard_uart0_exit, }; static const struct imxuart_platform_data uart4_pdata __initconst = { @@ -542,6 +530,7 @@ static void __init mx31moboard_init(void) imx31_add_imx2_wdt(); + moboard_uart0_init(); imx31_add_imx_uart0(&uart0_pdata); imx31_add_imx_uart4(&uart4_pdata); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 37c39390efb7..3b6c1a2e25de 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1901,7 +1901,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; - struct imxuart_platform_data *pdata; void __iomem *base; int ret = 0; struct resource *res; @@ -1955,38 +1954,16 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[sport->port.line] = sport; - pdata = dev_get_platdata(&pdev->dev); - if (pdata && pdata->init) { - ret = pdata->init(pdev); - if (ret) - return ret; - } - - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; platform_set_drvdata(pdev, sport); - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); - return ret; + return uart_add_one_port(&imx_reg, &sport->port); } static int serial_imx_remove(struct platform_device *pdev) { - struct imxuart_platform_data *pdata; struct imx_port *sport = platform_get_drvdata(pdev); - pdata = dev_get_platdata(&pdev->dev); - - uart_remove_one_port(&imx_reg, &sport->port); - - if (pdata && pdata->exit) - pdata->exit(pdev); - - return 0; + return uart_remove_one_port(&imx_reg, &sport->port); } static struct platform_driver serial_imx_driver = { diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h index 4adec9b154dd..3cc2e3c40914 100644 --- a/include/linux/platform_data/serial-imx.h +++ b/include/linux/platform_data/serial-imx.h @@ -23,8 +23,6 @@ #define IMXUART_IRDA (1<<1) struct imxuart_platform_data { - int (*init)(struct platform_device *pdev); - void (*exit)(struct platform_device *pdev); unsigned int flags; void (*irda_enable)(int enable); unsigned int irda_inv_rx:1; -- cgit v1.2.3