diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-28 14:14:55 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-28 14:14:55 -0400 |
| commit | 04b905942b482092a547798a2477f21e32a8f65d (patch) | |
| tree | 9ad2837587f5ce284f830432fec3569ecf44fbcb | |
| parent | d90ce8711ceb516de823ae878270e5a21d11dede (diff) | |
| parent | 3bc46b312b1486b1fe2db4246a34a30160d26d8d (diff) | |
Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6:
serial: bcm63xx_uart: fix irq storm after rx fifo overrun.
amba pl011: platform data for reg lockup and glitch v2
amba pl011: workaround for uart registers lockup
tty: n_gsm: improper skb_pull() use was leaking framed data
tty: n_gsm: Fixed logic to decode break signal from modem status
TTY: ntty, add one more sanity check
TTY: ldisc, do not close until there are readers
8250: Fix capabilities when changing the port type
8250_pci: Fix missing const from merges
ARM: SAMSUNG: serial: Fix on handling of one clock source for UART
serial: ioremap warning fix for jsm driver.
8250_pci: add -ENODEV code for Intel EG20T PCH
| -rw-r--r-- | arch/arm/mach-exynos4/init.c | 1 | ||||
| -rw-r--r-- | arch/arm/mach-ux500/board-mop500-pins.c | 16 | ||||
| -rw-r--r-- | arch/arm/mach-ux500/board-mop500.c | 54 | ||||
| -rw-r--r-- | arch/arm/plat-samsung/include/plat/regs-serial.h | 2 | ||||
| -rw-r--r-- | drivers/tty/n_gsm.c | 26 | ||||
| -rw-r--r-- | drivers/tty/n_tty.c | 1 | ||||
| -rw-r--r-- | drivers/tty/serial/8250.c | 1 | ||||
| -rw-r--r-- | drivers/tty/serial/8250_pci.c | 59 | ||||
| -rw-r--r-- | drivers/tty/serial/amba-pl011.c | 123 | ||||
| -rw-r--r-- | drivers/tty/serial/bcm63xx_uart.c | 18 | ||||
| -rw-r--r-- | drivers/tty/serial/jsm/jsm_driver.c | 2 | ||||
| -rw-r--r-- | drivers/tty/serial/s5pv210.c | 4 | ||||
| -rw-r--r-- | drivers/tty/tty_ldisc.c | 4 | ||||
| -rw-r--r-- | include/linux/amba/serial.h | 3 |
14 files changed, 295 insertions, 19 deletions
diff --git a/arch/arm/mach-exynos4/init.c b/arch/arm/mach-exynos4/init.c index cf91f50e43ab..a8a83e3881a4 100644 --- a/arch/arm/mach-exynos4/init.c +++ b/arch/arm/mach-exynos4/init.c | |||
| @@ -35,6 +35,7 @@ void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
| 35 | tcfg->clocks = exynos4_serial_clocks; | 35 | tcfg->clocks = exynos4_serial_clocks; |
| 36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); | 36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); |
| 37 | } | 37 | } |
| 38 | tcfg->flags |= NO_NEED_CHECK_CLKSRC; | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); | 41 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); |
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index fd4cf1ca5efd..70cdbd60596a 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c | |||
| @@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = { | |||
| 110 | GPIO168_KP_O0, | 110 | GPIO168_KP_O0, |
| 111 | 111 | ||
| 112 | /* UART */ | 112 | /* UART */ |
| 113 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | 113 | /* uart-0 pins gpio configuration should be |
| 114 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | 114 | * kept intact to prevent glitch in tx line |
| 115 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | 115 | * when tty dev is opened. Later these pins |
| 116 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | 116 | * are configured to uart mop500_pins_uart0 |
| 117 | * | ||
| 118 | * It will be replaced with uart configuration | ||
| 119 | * once the issue is solved. | ||
| 120 | */ | ||
| 121 | GPIO0_GPIO | PIN_INPUT_PULLUP, | ||
| 122 | GPIO1_GPIO | PIN_OUTPUT_HIGH, | ||
| 123 | GPIO2_GPIO | PIN_INPUT_PULLUP, | ||
| 124 | GPIO3_GPIO | PIN_OUTPUT_HIGH, | ||
| 117 | 125 | ||
| 118 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, | 126 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, |
| 119 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, | 127 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index bb26f40493e6..2a08c07dec6d 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
| @@ -27,18 +27,21 @@ | |||
| 27 | #include <linux/leds-lp5521.h> | 27 | #include <linux/leds-lp5521.h> |
| 28 | #include <linux/input.h> | 28 | #include <linux/input.h> |
| 29 | #include <linux/gpio_keys.h> | 29 | #include <linux/gpio_keys.h> |
| 30 | #include <linux/delay.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
| 32 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
| 33 | 34 | ||
| 34 | #include <plat/i2c.h> | 35 | #include <plat/i2c.h> |
| 35 | #include <plat/ste_dma40.h> | 36 | #include <plat/ste_dma40.h> |
| 37 | #include <plat/pincfg.h> | ||
| 36 | 38 | ||
| 37 | #include <mach/hardware.h> | 39 | #include <mach/hardware.h> |
| 38 | #include <mach/setup.h> | 40 | #include <mach/setup.h> |
| 39 | #include <mach/devices.h> | 41 | #include <mach/devices.h> |
| 40 | #include <mach/irqs.h> | 42 | #include <mach/irqs.h> |
| 41 | 43 | ||
| 44 | #include "pins-db8500.h" | ||
| 42 | #include "ste-dma40-db8500.h" | 45 | #include "ste-dma40-db8500.h" |
| 43 | #include "devices-db8500.h" | 46 | #include "devices-db8500.h" |
| 44 | #include "board-mop500.h" | 47 | #include "board-mop500.h" |
| @@ -393,12 +396,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = { | |||
| 393 | }; | 396 | }; |
| 394 | #endif | 397 | #endif |
| 395 | 398 | ||
| 399 | |||
| 400 | static pin_cfg_t mop500_pins_uart0[] = { | ||
| 401 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | ||
| 402 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | ||
| 403 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | ||
| 404 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | ||
| 405 | }; | ||
| 406 | |||
| 407 | #define PRCC_K_SOFTRST_SET 0x18 | ||
| 408 | #define PRCC_K_SOFTRST_CLEAR 0x1C | ||
| 409 | static void ux500_uart0_reset(void) | ||
| 410 | { | ||
| 411 | void __iomem *prcc_rst_set, *prcc_rst_clr; | ||
| 412 | |||
| 413 | prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
| 414 | PRCC_K_SOFTRST_SET); | ||
| 415 | prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
| 416 | PRCC_K_SOFTRST_CLEAR); | ||
| 417 | |||
| 418 | /* Activate soft reset PRCC_K_SOFTRST_CLEAR */ | ||
| 419 | writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr); | ||
| 420 | udelay(1); | ||
| 421 | |||
| 422 | /* Release soft reset PRCC_K_SOFTRST_SET */ | ||
| 423 | writel((readl(prcc_rst_set) | 0x1), prcc_rst_set); | ||
| 424 | udelay(1); | ||
| 425 | } | ||
| 426 | |||
| 427 | static void ux500_uart0_init(void) | ||
| 428 | { | ||
| 429 | int ret; | ||
| 430 | |||
| 431 | ret = nmk_config_pins(mop500_pins_uart0, | ||
| 432 | ARRAY_SIZE(mop500_pins_uart0)); | ||
| 433 | if (ret < 0) | ||
| 434 | pr_err("pl011: uart pins_enable failed\n"); | ||
| 435 | } | ||
| 436 | |||
| 437 | static void ux500_uart0_exit(void) | ||
| 438 | { | ||
| 439 | int ret; | ||
| 440 | |||
| 441 | ret = nmk_config_pins_sleep(mop500_pins_uart0, | ||
| 442 | ARRAY_SIZE(mop500_pins_uart0)); | ||
| 443 | if (ret < 0) | ||
| 444 | pr_err("pl011: uart pins_disable failed\n"); | ||
| 445 | } | ||
| 446 | |||
| 396 | static struct amba_pl011_data uart0_plat = { | 447 | static struct amba_pl011_data uart0_plat = { |
| 397 | #ifdef CONFIG_STE_DMA40 | 448 | #ifdef CONFIG_STE_DMA40 |
| 398 | .dma_filter = stedma40_filter, | 449 | .dma_filter = stedma40_filter, |
| 399 | .dma_rx_param = &uart0_dma_cfg_rx, | 450 | .dma_rx_param = &uart0_dma_cfg_rx, |
| 400 | .dma_tx_param = &uart0_dma_cfg_tx, | 451 | .dma_tx_param = &uart0_dma_cfg_tx, |
| 401 | #endif | 452 | #endif |
| 453 | .init = ux500_uart0_init, | ||
| 454 | .exit = ux500_uart0_exit, | ||
| 455 | .reset = ux500_uart0_reset, | ||
| 402 | }; | 456 | }; |
| 403 | 457 | ||
| 404 | static struct amba_pl011_data uart1_plat = { | 458 | static struct amba_pl011_data uart1_plat = { |
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h index c151c5f94a87..116edfe120b9 100644 --- a/arch/arm/plat-samsung/include/plat/regs-serial.h +++ b/arch/arm/plat-samsung/include/plat/regs-serial.h | |||
| @@ -224,6 +224,8 @@ | |||
| 224 | #define S5PV210_UFSTAT_RXMASK (255<<0) | 224 | #define S5PV210_UFSTAT_RXMASK (255<<0) |
| 225 | #define S5PV210_UFSTAT_RXSHIFT (0) | 225 | #define S5PV210_UFSTAT_RXSHIFT (0) |
| 226 | 226 | ||
| 227 | #define NO_NEED_CHECK_CLKSRC 1 | ||
| 228 | |||
| 227 | #ifndef __ASSEMBLY__ | 229 | #ifndef __ASSEMBLY__ |
| 228 | 230 | ||
| 229 | /* struct s3c24xx_uart_clksrc | 231 | /* struct s3c24xx_uart_clksrc |
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 09e8c7d53af3..19b4ae052af8 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
| @@ -875,7 +875,8 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, | |||
| 875 | *dp++ = last << 7 | first << 6 | 1; /* EA */ | 875 | *dp++ = last << 7 | first << 6 | 1; /* EA */ |
| 876 | len--; | 876 | len--; |
| 877 | } | 877 | } |
| 878 | memcpy(dp, skb_pull(dlci->skb, len), len); | 878 | memcpy(dp, dlci->skb->data, len); |
| 879 | skb_pull(dlci->skb, len); | ||
| 879 | __gsm_data_queue(dlci, msg); | 880 | __gsm_data_queue(dlci, msg); |
| 880 | if (last) | 881 | if (last) |
| 881 | dlci->skb = NULL; | 882 | dlci->skb = NULL; |
| @@ -984,10 +985,22 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, | |||
| 984 | */ | 985 | */ |
| 985 | 986 | ||
| 986 | static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, | 987 | static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, |
| 987 | u32 modem) | 988 | u32 modem, int clen) |
| 988 | { | 989 | { |
| 989 | int mlines = 0; | 990 | int mlines = 0; |
| 990 | u8 brk = modem >> 6; | 991 | u8 brk = 0; |
| 992 | |||
| 993 | /* The modem status command can either contain one octet (v.24 signals) | ||
| 994 | or two octets (v.24 signals + break signals). The length field will | ||
| 995 | either be 2 or 3 respectively. This is specified in section | ||
| 996 | 5.4.6.3.7 of the 27.010 mux spec. */ | ||
| 997 | |||
| 998 | if (clen == 2) | ||
| 999 | modem = modem & 0x7f; | ||
| 1000 | else { | ||
| 1001 | brk = modem & 0x7f; | ||
| 1002 | modem = (modem >> 7) & 0x7f; | ||
| 1003 | }; | ||
| 991 | 1004 | ||
| 992 | /* Flow control/ready to communicate */ | 1005 | /* Flow control/ready to communicate */ |
| 993 | if (modem & MDM_FC) { | 1006 | if (modem & MDM_FC) { |
| @@ -1061,7 +1074,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) | |||
| 1061 | return; | 1074 | return; |
| 1062 | } | 1075 | } |
| 1063 | tty = tty_port_tty_get(&dlci->port); | 1076 | tty = tty_port_tty_get(&dlci->port); |
| 1064 | gsm_process_modem(tty, dlci, modem); | 1077 | gsm_process_modem(tty, dlci, modem, clen); |
| 1065 | if (tty) { | 1078 | if (tty) { |
| 1066 | tty_wakeup(tty); | 1079 | tty_wakeup(tty); |
| 1067 | tty_kref_put(tty); | 1080 | tty_kref_put(tty); |
| @@ -1482,12 +1495,13 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci) | |||
| 1482 | * open we shovel the bits down it, if not we drop them. | 1495 | * open we shovel the bits down it, if not we drop them. |
| 1483 | */ | 1496 | */ |
| 1484 | 1497 | ||
| 1485 | static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) | 1498 | static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) |
| 1486 | { | 1499 | { |
| 1487 | /* krefs .. */ | 1500 | /* krefs .. */ |
| 1488 | struct tty_port *port = &dlci->port; | 1501 | struct tty_port *port = &dlci->port; |
| 1489 | struct tty_struct *tty = tty_port_tty_get(port); | 1502 | struct tty_struct *tty = tty_port_tty_get(port); |
| 1490 | unsigned int modem = 0; | 1503 | unsigned int modem = 0; |
| 1504 | int len = clen; | ||
| 1491 | 1505 | ||
| 1492 | if (debug & 16) | 1506 | if (debug & 16) |
| 1493 | pr_debug("%d bytes for tty %p\n", len, tty); | 1507 | pr_debug("%d bytes for tty %p\n", len, tty); |
| @@ -1507,7 +1521,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) | |||
| 1507 | if (len == 0) | 1521 | if (len == 0) |
| 1508 | return; | 1522 | return; |
| 1509 | } | 1523 | } |
| 1510 | gsm_process_modem(tty, dlci, modem); | 1524 | gsm_process_modem(tty, dlci, modem, clen); |
| 1511 | /* Line state will go via DLCI 0 controls only */ | 1525 | /* Line state will go via DLCI 0 controls only */ |
| 1512 | case 1: | 1526 | case 1: |
| 1513 | default: | 1527 | default: |
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0ad32888091c..c3954fbf6ac4 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
| @@ -1815,6 +1815,7 @@ do_it_again: | |||
| 1815 | /* FIXME: does n_tty_set_room need locking ? */ | 1815 | /* FIXME: does n_tty_set_room need locking ? */ |
| 1816 | n_tty_set_room(tty); | 1816 | n_tty_set_room(tty); |
| 1817 | timeout = schedule_timeout(timeout); | 1817 | timeout = schedule_timeout(timeout); |
| 1818 | BUG_ON(!tty->read_buf); | ||
| 1818 | continue; | 1819 | continue; |
| 1819 | } | 1820 | } |
| 1820 | __set_current_state(TASK_RUNNING); | 1821 | __set_current_state(TASK_RUNNING); |
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index b40f7b90c81d..b4129f53fb1b 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c | |||
| @@ -3318,6 +3318,7 @@ void serial8250_unregister_port(int line) | |||
| 3318 | uart->port.flags &= ~UPF_BOOT_AUTOCONF; | 3318 | uart->port.flags &= ~UPF_BOOT_AUTOCONF; |
| 3319 | uart->port.type = PORT_UNKNOWN; | 3319 | uart->port.type = PORT_UNKNOWN; |
| 3320 | uart->port.dev = &serial8250_isa_devs->dev; | 3320 | uart->port.dev = &serial8250_isa_devs->dev; |
| 3321 | uart->capabilities = uart_config[uart->port.type].flags; | ||
| 3321 | uart_add_one_port(&serial8250_reg, &uart->port); | 3322 | uart_add_one_port(&serial8250_reg, &uart->port); |
| 3322 | } else { | 3323 | } else { |
| 3323 | uart->port.dev = NULL; | 3324 | uart->port.dev = NULL; |
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index 78e98a5cef96..f41b4259ecdd 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c | |||
| @@ -994,6 +994,15 @@ static int skip_tx_en_setup(struct serial_private *priv, | |||
| 994 | return pci_default_setup(priv, board, port, idx); | 994 | return pci_default_setup(priv, board, port, idx); |
| 995 | } | 995 | } |
| 996 | 996 | ||
| 997 | static int pci_eg20t_init(struct pci_dev *dev) | ||
| 998 | { | ||
| 999 | #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) | ||
| 1000 | return -ENODEV; | ||
| 1001 | #else | ||
| 1002 | return 0; | ||
| 1003 | #endif | ||
| 1004 | } | ||
| 1005 | |||
| 997 | /* This should be in linux/pci_ids.h */ | 1006 | /* This should be in linux/pci_ids.h */ |
| 998 | #define PCI_VENDOR_ID_SBSMODULARIO 0x124B | 1007 | #define PCI_VENDOR_ID_SBSMODULARIO 0x124B |
| 999 | #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B | 1008 | #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B |
| @@ -1446,6 +1455,56 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
| 1446 | .init = pci_oxsemi_tornado_init, | 1455 | .init = pci_oxsemi_tornado_init, |
| 1447 | .setup = pci_default_setup, | 1456 | .setup = pci_default_setup, |
| 1448 | }, | 1457 | }, |
| 1458 | { | ||
| 1459 | .vendor = PCI_VENDOR_ID_INTEL, | ||
| 1460 | .device = 0x8811, | ||
| 1461 | .init = pci_eg20t_init, | ||
| 1462 | }, | ||
| 1463 | { | ||
| 1464 | .vendor = PCI_VENDOR_ID_INTEL, | ||
| 1465 | .device = 0x8812, | ||
| 1466 | .init = pci_eg20t_init, | ||
| 1467 | }, | ||
| 1468 | { | ||
| 1469 | .vendor = PCI_VENDOR_ID_INTEL, | ||
| 1470 | .device = 0x8813, | ||
| 1471 | .init = pci_eg20t_init, | ||
| 1472 | }, | ||
| 1473 | { | ||
| 1474 | .vendor = PCI_VENDOR_ID_INTEL, | ||
| 1475 | .device = 0x8814, | ||
| 1476 | .init = pci_eg20t_init, | ||
| 1477 | }, | ||
| 1478 | { | ||
| 1479 | .vendor = 0x10DB, | ||
| 1480 | .device = 0x8027, | ||
| 1481 | .init = pci_eg20t_init, | ||
| 1482 | }, | ||
| 1483 | { | ||
| 1484 | .vendor = 0x10DB, | ||
| 1485 | .device = 0x8028, | ||
| 1486 | .init = pci_eg20t_init, | ||
| 1487 | }, | ||
| 1488 | { | ||
| 1489 | .vendor = 0x10DB, | ||
| 1490 | .device = 0x8029, | ||
| 1491 | .init = pci_eg20t_init, | ||
| 1492 | }, | ||
| 1493 | { | ||
| 1494 | .vendor = 0x10DB, | ||
| 1495 | .device = 0x800C, | ||
| 1496 | .init = pci_eg20t_init, | ||
| 1497 | }, | ||
| 1498 | { | ||
| 1499 | .vendor = 0x10DB, | ||
| 1500 | .device = 0x800D, | ||
| 1501 | .init = pci_eg20t_init, | ||
| 1502 | }, | ||
| 1503 | { | ||
| 1504 | .vendor = 0x10DB, | ||
| 1505 | .device = 0x800D, | ||
| 1506 | .init = pci_eg20t_init, | ||
| 1507 | }, | ||
| 1449 | /* | 1508 | /* |
| 1450 | * Cronyx Omega PCI (PLX-chip based) | 1509 | * Cronyx Omega PCI (PLX-chip based) |
| 1451 | */ | 1510 | */ |
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8dc0541feecc..f5f6831b0a64 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <linux/dmaengine.h> | 50 | #include <linux/dmaengine.h> |
| 51 | #include <linux/dma-mapping.h> | 51 | #include <linux/dma-mapping.h> |
| 52 | #include <linux/scatterlist.h> | 52 | #include <linux/scatterlist.h> |
| 53 | #include <linux/delay.h> | ||
| 53 | 54 | ||
| 54 | #include <asm/io.h> | 55 | #include <asm/io.h> |
| 55 | #include <asm/sizes.h> | 56 | #include <asm/sizes.h> |
| @@ -65,6 +66,30 @@ | |||
| 65 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) | 66 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) |
| 66 | #define UART_DUMMY_DR_RX (1 << 16) | 67 | #define UART_DUMMY_DR_RX (1 << 16) |
| 67 | 68 | ||
| 69 | |||
| 70 | #define UART_WA_SAVE_NR 14 | ||
| 71 | |||
| 72 | static void pl011_lockup_wa(unsigned long data); | ||
| 73 | static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { | ||
| 74 | ST_UART011_DMAWM, | ||
| 75 | ST_UART011_TIMEOUT, | ||
| 76 | ST_UART011_LCRH_RX, | ||
| 77 | UART011_IBRD, | ||
| 78 | UART011_FBRD, | ||
| 79 | ST_UART011_LCRH_TX, | ||
| 80 | UART011_IFLS, | ||
| 81 | ST_UART011_XFCR, | ||
| 82 | ST_UART011_XON1, | ||
| 83 | ST_UART011_XON2, | ||
| 84 | ST_UART011_XOFF1, | ||
| 85 | ST_UART011_XOFF2, | ||
| 86 | UART011_CR, | ||
| 87 | UART011_IMSC | ||
| 88 | }; | ||
| 89 | |||
| 90 | static u32 uart_wa_regdata[UART_WA_SAVE_NR]; | ||
| 91 | static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); | ||
| 92 | |||
| 68 | /* There is by now at least one vendor with differing details, so handle it */ | 93 | /* There is by now at least one vendor with differing details, so handle it */ |
| 69 | struct vendor_data { | 94 | struct vendor_data { |
| 70 | unsigned int ifls; | 95 | unsigned int ifls; |
| @@ -72,6 +97,7 @@ struct vendor_data { | |||
| 72 | unsigned int lcrh_tx; | 97 | unsigned int lcrh_tx; |
| 73 | unsigned int lcrh_rx; | 98 | unsigned int lcrh_rx; |
| 74 | bool oversampling; | 99 | bool oversampling; |
| 100 | bool interrupt_may_hang; /* vendor-specific */ | ||
| 75 | bool dma_threshold; | 101 | bool dma_threshold; |
| 76 | }; | 102 | }; |
| 77 | 103 | ||
| @@ -90,9 +116,12 @@ static struct vendor_data vendor_st = { | |||
| 90 | .lcrh_tx = ST_UART011_LCRH_TX, | 116 | .lcrh_tx = ST_UART011_LCRH_TX, |
| 91 | .lcrh_rx = ST_UART011_LCRH_RX, | 117 | .lcrh_rx = ST_UART011_LCRH_RX, |
| 92 | .oversampling = true, | 118 | .oversampling = true, |
| 119 | .interrupt_may_hang = true, | ||
| 93 | .dma_threshold = true, | 120 | .dma_threshold = true, |
| 94 | }; | 121 | }; |
| 95 | 122 | ||
| 123 | static struct uart_amba_port *amba_ports[UART_NR]; | ||
| 124 | |||
| 96 | /* Deals with DMA transactions */ | 125 | /* Deals with DMA transactions */ |
| 97 | 126 | ||
| 98 | struct pl011_sgbuf { | 127 | struct pl011_sgbuf { |
| @@ -132,6 +161,7 @@ struct uart_amba_port { | |||
| 132 | unsigned int lcrh_rx; /* vendor-specific */ | 161 | unsigned int lcrh_rx; /* vendor-specific */ |
| 133 | bool autorts; | 162 | bool autorts; |
| 134 | char type[12]; | 163 | char type[12]; |
| 164 | bool interrupt_may_hang; /* vendor-specific */ | ||
| 135 | #ifdef CONFIG_DMA_ENGINE | 165 | #ifdef CONFIG_DMA_ENGINE |
| 136 | /* DMA stuff */ | 166 | /* DMA stuff */ |
| 137 | bool using_tx_dma; | 167 | bool using_tx_dma; |
| @@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) | |||
| 1008 | #endif | 1038 | #endif |
| 1009 | 1039 | ||
| 1010 | 1040 | ||
| 1041 | /* | ||
| 1042 | * pl011_lockup_wa | ||
| 1043 | * This workaround aims to break the deadlock situation | ||
| 1044 | * when after long transfer over uart in hardware flow | ||
| 1045 | * control, uart interrupt registers cannot be cleared. | ||
| 1046 | * Hence uart transfer gets blocked. | ||
| 1047 | * | ||
| 1048 | * It is seen that during such deadlock condition ICR | ||
| 1049 | * don't get cleared even on multiple write. This leads | ||
| 1050 | * pass_counter to decrease and finally reach zero. This | ||
| 1051 | * can be taken as trigger point to run this UART_BT_WA. | ||
| 1052 | * | ||
| 1053 | */ | ||
| 1054 | static void pl011_lockup_wa(unsigned long data) | ||
| 1055 | { | ||
| 1056 | struct uart_amba_port *uap = amba_ports[0]; | ||
| 1057 | void __iomem *base = uap->port.membase; | ||
| 1058 | struct circ_buf *xmit = &uap->port.state->xmit; | ||
| 1059 | struct tty_struct *tty = uap->port.state->port.tty; | ||
| 1060 | int buf_empty_retries = 200; | ||
| 1061 | int loop; | ||
| 1062 | |||
| 1063 | /* Stop HCI layer from submitting data for tx */ | ||
| 1064 | tty->hw_stopped = 1; | ||
| 1065 | while (!uart_circ_empty(xmit)) { | ||
| 1066 | if (buf_empty_retries-- == 0) | ||
| 1067 | break; | ||
| 1068 | udelay(100); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /* Backup registers */ | ||
| 1072 | for (loop = 0; loop < UART_WA_SAVE_NR; loop++) | ||
| 1073 | uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); | ||
| 1074 | |||
| 1075 | /* Disable UART so that FIFO data is flushed out */ | ||
| 1076 | writew(0x00, uap->port.membase + UART011_CR); | ||
| 1077 | |||
| 1078 | /* Soft reset UART module */ | ||
| 1079 | if (uap->port.dev->platform_data) { | ||
| 1080 | struct amba_pl011_data *plat; | ||
| 1081 | |||
| 1082 | plat = uap->port.dev->platform_data; | ||
| 1083 | if (plat->reset) | ||
| 1084 | plat->reset(); | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | /* Restore registers */ | ||
| 1088 | for (loop = 0; loop < UART_WA_SAVE_NR; loop++) | ||
| 1089 | writew(uart_wa_regdata[loop] , | ||
| 1090 | uap->port.membase + uart_wa_reg[loop]); | ||
| 1091 | |||
| 1092 | /* Initialise the old status of the modem signals */ | ||
| 1093 | uap->old_status = readw(uap->port.membase + UART01x_FR) & | ||
| 1094 | UART01x_FR_MODEM_ANY; | ||
| 1095 | |||
| 1096 | if (readl(base + UART011_MIS) & 0x2) | ||
| 1097 | printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); | ||
| 1098 | |||
| 1099 | /* Start Tx/Rx */ | ||
| 1100 | tty->hw_stopped = 0; | ||
| 1101 | } | ||
| 1102 | |||
| 1011 | static void pl011_stop_tx(struct uart_port *port) | 1103 | static void pl011_stop_tx(struct uart_port *port) |
| 1012 | { | 1104 | { |
| 1013 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 1105 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
| @@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id) | |||
| 1158 | if (status & UART011_TXIS) | 1250 | if (status & UART011_TXIS) |
| 1159 | pl011_tx_chars(uap); | 1251 | pl011_tx_chars(uap); |
| 1160 | 1252 | ||
| 1161 | if (pass_counter-- == 0) | 1253 | if (pass_counter-- == 0) { |
| 1254 | if (uap->interrupt_may_hang) | ||
| 1255 | tasklet_schedule(&pl011_lockup_tlet); | ||
| 1162 | break; | 1256 | break; |
| 1257 | } | ||
| 1163 | 1258 | ||
| 1164 | status = readw(uap->port.membase + UART011_MIS); | 1259 | status = readw(uap->port.membase + UART011_MIS); |
| 1165 | } while (status != 0); | 1260 | } while (status != 0); |
| @@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port) | |||
| 1339 | writew(uap->im, uap->port.membase + UART011_IMSC); | 1434 | writew(uap->im, uap->port.membase + UART011_IMSC); |
| 1340 | spin_unlock_irq(&uap->port.lock); | 1435 | spin_unlock_irq(&uap->port.lock); |
| 1341 | 1436 | ||
| 1437 | if (uap->port.dev->platform_data) { | ||
| 1438 | struct amba_pl011_data *plat; | ||
| 1439 | |||
| 1440 | plat = uap->port.dev->platform_data; | ||
| 1441 | if (plat->init) | ||
| 1442 | plat->init(); | ||
| 1443 | } | ||
| 1444 | |||
| 1342 | return 0; | 1445 | return 0; |
| 1343 | 1446 | ||
| 1344 | clk_dis: | 1447 | clk_dis: |
| @@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port) | |||
| 1394 | * Shut down the clock producer | 1497 | * Shut down the clock producer |
| 1395 | */ | 1498 | */ |
| 1396 | clk_disable(uap->clk); | 1499 | clk_disable(uap->clk); |
| 1500 | |||
| 1501 | if (uap->port.dev->platform_data) { | ||
| 1502 | struct amba_pl011_data *plat; | ||
| 1503 | |||
| 1504 | plat = uap->port.dev->platform_data; | ||
| 1505 | if (plat->exit) | ||
| 1506 | plat->exit(); | ||
| 1507 | } | ||
| 1508 | |||
| 1397 | } | 1509 | } |
| 1398 | 1510 | ||
| 1399 | static void | 1511 | static void |
| @@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options) | |||
| 1700 | if (!uap) | 1812 | if (!uap) |
| 1701 | return -ENODEV; | 1813 | return -ENODEV; |
| 1702 | 1814 | ||
| 1815 | if (uap->port.dev->platform_data) { | ||
| 1816 | struct amba_pl011_data *plat; | ||
| 1817 | |||
| 1818 | plat = uap->port.dev->platform_data; | ||
| 1819 | if (plat->init) | ||
| 1820 | plat->init(); | ||
| 1821 | } | ||
| 1822 | |||
| 1703 | uap->port.uartclk = clk_get_rate(uap->clk); | 1823 | uap->port.uartclk = clk_get_rate(uap->clk); |
| 1704 | 1824 | ||
| 1705 | if (options) | 1825 | if (options) |
| @@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) | |||
| 1774 | uap->lcrh_rx = vendor->lcrh_rx; | 1894 | uap->lcrh_rx = vendor->lcrh_rx; |
| 1775 | uap->lcrh_tx = vendor->lcrh_tx; | 1895 | uap->lcrh_tx = vendor->lcrh_tx; |
| 1776 | uap->fifosize = vendor->fifosize; | 1896 | uap->fifosize = vendor->fifosize; |
| 1897 | uap->interrupt_may_hang = vendor->interrupt_may_hang; | ||
| 1777 | uap->port.dev = &dev->dev; | 1898 | uap->port.dev = &dev->dev; |
| 1778 | uap->port.mapbase = dev->res.start; | 1899 | uap->port.mapbase = dev->res.start; |
| 1779 | uap->port.membase = base; | 1900 | uap->port.membase = base; |
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index a1a0e55d0807..c0b68b9cad91 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c | |||
| @@ -250,6 +250,20 @@ static void bcm_uart_do_rx(struct uart_port *port) | |||
| 250 | /* get overrun/fifo empty information from ier | 250 | /* get overrun/fifo empty information from ier |
| 251 | * register */ | 251 | * register */ |
| 252 | iestat = bcm_uart_readl(port, UART_IR_REG); | 252 | iestat = bcm_uart_readl(port, UART_IR_REG); |
| 253 | |||
| 254 | if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { | ||
| 255 | unsigned int val; | ||
| 256 | |||
| 257 | /* fifo reset is required to clear | ||
| 258 | * interrupt */ | ||
| 259 | val = bcm_uart_readl(port, UART_CTL_REG); | ||
| 260 | val |= UART_CTL_RSTRXFIFO_MASK; | ||
| 261 | bcm_uart_writel(port, val, UART_CTL_REG); | ||
| 262 | |||
| 263 | port->icount.overrun++; | ||
| 264 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
| 265 | } | ||
| 266 | |||
| 253 | if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) | 267 | if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) |
| 254 | break; | 268 | break; |
| 255 | 269 | ||
| @@ -284,10 +298,6 @@ static void bcm_uart_do_rx(struct uart_port *port) | |||
| 284 | if (uart_handle_sysrq_char(port, c)) | 298 | if (uart_handle_sysrq_char(port, c)) |
| 285 | continue; | 299 | continue; |
| 286 | 300 | ||
| 287 | if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { | ||
| 288 | port->icount.overrun++; | ||
| 289 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
| 290 | } | ||
| 291 | 301 | ||
| 292 | if ((cstat & port->ignore_status_mask) == 0) | 302 | if ((cstat & port->ignore_status_mask) == 0) |
| 293 | tty_insert_flip_char(tty, c, flag); | 303 | tty_insert_flip_char(tty, c, flag); |
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 18f548449c63..96da17868cf3 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c | |||
| @@ -125,7 +125,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device | |||
| 125 | brd->bd_uart_offset = 0x200; | 125 | brd->bd_uart_offset = 0x200; |
| 126 | brd->bd_dividend = 921600; | 126 | brd->bd_dividend = 921600; |
| 127 | 127 | ||
| 128 | brd->re_map_membase = ioremap(brd->membase, 0x1000); | 128 | brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0)); |
| 129 | if (!brd->re_map_membase) { | 129 | if (!brd->re_map_membase) { |
| 130 | dev_err(&pdev->dev, | 130 | dev_err(&pdev->dev, |
| 131 | "card has no PCI Memory resources, " | 131 | "card has no PCI Memory resources, " |
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c index fb2619f93d84..dd194dc80ee9 100644 --- a/drivers/tty/serial/s5pv210.c +++ b/drivers/tty/serial/s5pv210.c | |||
| @@ -30,7 +30,7 @@ static int s5pv210_serial_setsource(struct uart_port *port, | |||
| 30 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; | 30 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; |
| 31 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | 31 | unsigned long ucon = rd_regl(port, S3C2410_UCON); |
| 32 | 32 | ||
| 33 | if ((cfg->clocks_size) == 1) | 33 | if (cfg->flags & NO_NEED_CHECK_CLKSRC) |
| 34 | return 0; | 34 | return 0; |
| 35 | 35 | ||
| 36 | if (strcmp(clk->name, "pclk") == 0) | 36 | if (strcmp(clk->name, "pclk") == 0) |
| @@ -55,7 +55,7 @@ static int s5pv210_serial_getsource(struct uart_port *port, | |||
| 55 | 55 | ||
| 56 | clk->divisor = 1; | 56 | clk->divisor = 1; |
| 57 | 57 | ||
| 58 | if ((cfg->clocks_size) == 1) | 58 | if (cfg->flags & NO_NEED_CHECK_CLKSRC) |
| 59 | return 0; | 59 | return 0; |
| 60 | 60 | ||
| 61 | switch (ucon & S5PV210_UCON_CLKMASK) { | 61 | switch (ucon & S5PV210_UCON_CLKMASK) { |
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 5d01d32e2cf0..ef925d581713 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
| @@ -555,7 +555,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
| 555 | static int tty_ldisc_wait_idle(struct tty_struct *tty) | 555 | static int tty_ldisc_wait_idle(struct tty_struct *tty) |
| 556 | { | 556 | { |
| 557 | int ret; | 557 | int ret; |
| 558 | ret = wait_event_interruptible_timeout(tty_ldisc_idle, | 558 | ret = wait_event_timeout(tty_ldisc_idle, |
| 559 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); | 559 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); |
| 560 | if (ret < 0) | 560 | if (ret < 0) |
| 561 | return ret; | 561 | return ret; |
| @@ -763,6 +763,8 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | |||
| 763 | if (IS_ERR(ld)) | 763 | if (IS_ERR(ld)) |
| 764 | return -1; | 764 | return -1; |
| 765 | 765 | ||
| 766 | WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); | ||
| 767 | |||
| 766 | tty_ldisc_close(tty, tty->ldisc); | 768 | tty_ldisc_close(tty, tty->ldisc); |
| 767 | tty_ldisc_put(tty->ldisc); | 769 | tty_ldisc_put(tty->ldisc); |
| 768 | tty->ldisc = NULL; | 770 | tty->ldisc = NULL; |
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 5479fdc849e9..514ed45c462e 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h | |||
| @@ -201,6 +201,9 @@ struct amba_pl011_data { | |||
| 201 | bool (*dma_filter)(struct dma_chan *chan, void *filter_param); | 201 | bool (*dma_filter)(struct dma_chan *chan, void *filter_param); |
| 202 | void *dma_rx_param; | 202 | void *dma_rx_param; |
| 203 | void *dma_tx_param; | 203 | void *dma_tx_param; |
| 204 | void (*init) (void); | ||
| 205 | void (*exit) (void); | ||
| 206 | void (*reset) (void); | ||
| 204 | }; | 207 | }; |
| 205 | #endif | 208 | #endif |
| 206 | 209 | ||
