Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Oct 2011 13:11:09 +0000 (15:11 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Oct 2011 13:11:09 +0000 (15:11 +0200)
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits)
  TTY: serial_core: Fix crash if DCD drop during suspend
  tty/serial: atmel_serial: bootconsole removed from auto-enumerates
  Revert "TTY: call tty_driver_lookup_tty unconditionally"
  tty/serial: atmel_serial: add device tree support
  tty/serial: atmel_serial: auto-enumerate ports
  tty/serial: atmel_serial: whitespace and braces modifications
  tty/serial: atmel_serial: change platform_data variable name
  tty/serial: RS485 bindings for device tree
  TTY: call tty_driver_lookup_tty unconditionally
  TTY: pty, release tty in all ptmx_open fail paths
  TTY: make tty_add_file non-failing
  TTY: drop driver reference in tty_open fail path
  8250_pci: Fix kernel panic when pch_uart is disabled
  h8300: drivers/serial/Kconfig was moved
  parport_pc: release IO region properly if unsupported ITE887x card is found
  tty: Support compat_ioctl get/set termios_locked
  hvc_console: display printk messages on console.
  TTY: snyclinkmp: forever loop in tx_load_dma_buffer()
  tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output
  tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case)
  ...

Fix up Conflicts in:
 - drivers/tty/serial/8250_pci.c
Trivial conflict with removed duplicate device ID
 - drivers/tty/serial/atmel_serial.c
Annoying silly conflict between "specify the port num via
platform_data" and other changes to atmel_console_init

20 files changed:
1  2 
arch/arm/Kconfig
arch/h8300/Kconfig
arch/x86/platform/mrst/mrst.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/tty/Kconfig
drivers/tty/pty.c
drivers/tty/serial/8250.c
drivers/tty/serial/8250_pci.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/lantiq.c
drivers/tty/serial/max3107.c
drivers/tty/serial/mrst_max3110.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/samsung.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/ucc_uart.c
drivers/tty/tty_io.c
include/linux/tty.h

diff --combined arch/arm/Kconfig
@@@ -3,7 -3,7 +3,7 @@@ config AR
        default y
        select HAVE_AOUT
        select HAVE_DMA_API_DEBUG
 -      select HAVE_IDE
 +      select HAVE_IDE if PCI || ISA || PCMCIA
        select HAVE_MEMBLOCK
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
@@@ -195,8 -195,7 +195,8 @@@ config VECTORS_BAS
          The base address of exception vectors.
  
  config ARM_PATCH_PHYS_VIRT
 -      bool "Patch physical to virtual translations at runtime"
 +      bool "Patch physical to virtual translations at runtime" if EMBEDDED
 +      default y
        depends on !XIP_KERNEL && MMU
        depends on !ARCH_REALVIEW || !SPARSEMEM
        help
          kernel in system memory.
  
          This can only be used with non-XIP MMU kernels where the base
 -        of physical memory is at a 16MB boundary, or theoretically 64K
 -        for the MSM machine class.
 +        of physical memory is at a 16MB boundary.
 +
 +        Only disable this option if you know that you do not require
 +        this feature (eg, building a kernel for a single machine) and
 +        you need to shrink the kernel to the minimal size.
  
 -config ARM_PATCH_PHYS_VIRT_16BIT
 +
 +config GENERIC_BUG
        def_bool y
 -      depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM
 -      help
 -        This option extends the physical to virtual translation patching
 -        to allow physical memory down to a theoretical minimum of 64K
 -        boundaries.
 +      depends on BUG
  
  source "init/Kconfig"
  
@@@ -302,6 -301,7 +302,6 @@@ config ARCH_AT9
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
        select CLKDEV_LOOKUP
 -      select ARM_PATCH_PHYS_VIRT if MMU
        help
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 and AT91CAP9 processors.
@@@ -385,7 -385,6 +385,7 @@@ config ARCH_FOOTBRIDG
        select CPU_SA110
        select FOOTBRIDGE
        select GENERIC_CLOCKEVENTS
 +      select HAVE_IDE
        help
          Support for systems based on the DC21285 companion chip
          ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
@@@ -632,8 -631,6 +632,8 @@@ config ARCH_PX
        select SPARSE_IRQ
        select AUTO_ZRELADDR
        select MULTI_IRQ_HANDLER
 +      select ARM_CPU_SUSPEND if PM
 +      select HAVE_IDE
        help
          Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
  
@@@ -674,7 -671,6 +674,7 @@@ config ARCH_RP
        select NO_IOPORT
        select ARCH_SPARSEMEM_ENABLE
        select ARCH_USES_GETTIMEOFFSET
 +      select HAVE_IDE
        help
          On the Acorn Risc-PC, Linux can support the internal IDE disk and
          CD-ROM interface, serial and parallel port, and the floppy drive.
@@@ -693,7 -689,6 +693,7 @@@ config ARCH_SA110
        select HAVE_SCHED_CLOCK
        select TICK_ONESHOT
        select ARCH_REQUIRE_GPIOLIB
 +      select HAVE_IDE
        help
          Support for StrongARM 11x0 based boards.
  
@@@ -727,7 -722,6 +727,6 @@@ config ARCH_S3C64X
        select ARCH_REQUIRE_GPIOLIB
        select SAMSUNG_CLKSRC
        select SAMSUNG_IRQ_VIC_TIMER
-       select SAMSUNG_IRQ_UART
        select S3C_GPIO_TRACK
        select S3C_GPIO_PULL_UPDOWN
        select S3C_GPIO_CFG_S3C24XX
@@@ -1276,32 -1270,6 +1275,32 @@@ config ARM_ERRATA_75432
          This workaround defines cpu_relax() as smp_mb(), preventing correctly
          written polling loops from denying visibility of updates to memory.
  
 +config ARM_ERRATA_364296
 +      bool "ARM errata: Possible cache data corruption with hit-under-miss enabled"
 +      depends on CPU_V6 && !SMP
 +      help
 +        This options enables the workaround for the 364296 ARM1136
 +        r0p2 erratum (possible cache data corruption with
 +        hit-under-miss enabled). It sets the undocumented bit 31 in
 +        the auxiliary control register and the FI bit in the control
 +        register, thus disabling hit-under-miss without putting the
 +        processor into full low interrupt latency mode. ARM11MPCore
 +        is not affected.
 +
 +config ARM_ERRATA_764369
 +      bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
 +      depends on CPU_V7 && SMP
 +      help
 +        This option enables the workaround for erratum 764369
 +        affecting Cortex-A9 MPCore with two or more processors (all
 +        current revisions). Under certain timing circumstances, a data
 +        cache line maintenance operation by MVA targeting an Inner
 +        Shareable memory region may fail to proceed up to either the
 +        Point of Coherency or to the Point of Unification of the
 +        system. This workaround adds a DSB instruction before the
 +        relevant cache maintenance functions and sets a specific bit
 +        in the diagnostic control register of the SCU.
 +
  endmenu
  
  source "arch/arm/common/Kconfig"
@@@ -1380,7 -1348,6 +1379,7 @@@ config SM
                 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
                 ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
                 ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE
 +      depends on MMU
        select USE_GENERIC_SMP_HELPERS
        select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
        help
          processor machines. On a single processor machine, the kernel will
          run faster if you say N here.
  
 -        See also <file:Documentation/i386/IO-APIC.txt>,
 +        See also <file:Documentation/x86/i386/IO-APIC.txt>,
          <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
          <http://tldp.org/HOWTO/SMP-HOWTO.html>.
  
@@@ -1413,31 -1380,6 +1412,31 @@@ config SMP_ON_U
  
          If you don't know what to do here, say Y.
  
 +config ARM_CPU_TOPOLOGY
 +      bool "Support cpu topology definition"
 +      depends on SMP && CPU_V7
 +      default y
 +      help
 +        Support ARM cpu topology definition. The MPIDR register defines
 +        affinity between processors which is then used to describe the cpu
 +        topology of an ARM System.
 +
 +config SCHED_MC
 +      bool "Multi-core scheduler support"
 +      depends on ARM_CPU_TOPOLOGY
 +      help
 +        Multi-core scheduler support improves the CPU scheduler's decision
 +        making when dealing with multi-core CPU chips at a cost of slightly
 +        increased overhead in some places. If unsure say N here.
 +
 +config SCHED_SMT
 +      bool "SMT scheduler support"
 +      depends on ARM_CPU_TOPOLOGY
 +      help
 +        Improves the CPU scheduler's decision making when dealing with
 +        MultiThreading at a cost of slightly increased overhead in some
 +        places. If unsure say N here.
 +
  config HAVE_ARM_SCU
        bool
        help
@@@ -1513,7 -1455,6 +1512,7 @@@ config THUMB2_KERNE
        depends on CPU_V7 && !CPU_V6 && !CPU_V6K && EXPERIMENTAL
        select AEABI
        select ARM_ASM_UNIFIED
 +      select ARM_UNWIND
        help
          By enabling this option, the kernel will be compiled in
          Thumb-2 mode. A compiler/assembler that understand the unified
@@@ -2133,9 -2074,6 +2132,9 @@@ config ARCH_SUSPEND_POSSIBL
                CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
        def_bool y
  
 +config ARM_CPU_SUSPEND
 +      def_bool PM_SLEEP
 +
  endmenu
  
  source "net/Kconfig"
diff --combined arch/h8300/Kconfig
@@@ -160,7 -160,7 +160,7 @@@ config VT_CONSOL
  
  config HW_CONSOLE
        bool
 -      depends on VT && !S390 && !UM
 +      depends on VT
        default y
  
  comment "Unix98 PTY support"
@@@ -195,7 -195,7 +195,7 @@@ config UNIX98_PTY
  
  source "drivers/char/pcmcia/Kconfig"
  
- source "drivers/serial/Kconfig"
+ source "drivers/tty/serial/Kconfig"
  
  source "drivers/i2c/Kconfig"
  
@@@ -14,6 -14,8 +14,8 @@@
  
  #include <linux/init.h>
  #include <linux/kernel.h>
+ #include <linux/interrupt.h>
+ #include <linux/scatterlist.h>
  #include <linux/sfi.h>
  #include <linux/intel_pmic_gpio.h>
  #include <linux/spi/spi.h>
@@@ -392,6 -394,7 +394,7 @@@ static void __init *max3111_platform_da
        struct spi_board_info *spi_info = info;
        int intr = get_gpio_by_name("max3111_int");
  
+       spi_info->mode = SPI_MODE_0;
        if (intr == -1)
                return NULL;
        spi_info->irq = intr + MRST_IRQ_OFFSET;
@@@ -678,40 -681,36 +681,40 @@@ static int __init sfi_parse_devs(struc
        pentry = (struct sfi_device_table_entry *)sb->pentry;
  
        for (i = 0; i < num; i++, pentry++) {
 -              if (pentry->irq != (u8)0xff) { /* native RTE case */
 +              int irq = pentry->irq;
 +
 +              if (irq != (u8)0xff) { /* native RTE case */
                        /* these SPI2 devices are not exposed to system as PCI
                         * devices, but they have separate RTE entry in IOAPIC
                         * so we have to enable them one by one here
                         */
 -                      ioapic = mp_find_ioapic(pentry->irq);
 +                      ioapic = mp_find_ioapic(irq);
                        irq_attr.ioapic = ioapic;
 -                      irq_attr.ioapic_pin = pentry->irq;
 +                      irq_attr.ioapic_pin = irq;
                        irq_attr.trigger = 1;
                        irq_attr.polarity = 1;
 -                      io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr);
 -              }
 +                      io_apic_set_pci_routing(NULL, irq, &irq_attr);
 +              } else
 +                      irq = 0; /* No irq */
 +
                switch (pentry->type) {
                case SFI_DEV_TYPE_IPC:
                        /* ID as IRQ is a hack that will go away */
 -                      pdev = platform_device_alloc(pentry->name, pentry->irq);
 +                      pdev = platform_device_alloc(pentry->name, irq);
                        if (pdev == NULL) {
                                pr_err("out of memory for SFI platform device '%s'.\n",
                                                        pentry->name);
                                continue;
                        }
 -                      install_irq_resource(pdev, pentry->irq);
 +                      install_irq_resource(pdev, irq);
                        pr_debug("info[%2d]: IPC bus, name = %16.16s, "
 -                              "irq = 0x%2x\n", i, pentry->name, pentry->irq);
 +                              "irq = 0x%2x\n", i, pentry->name, irq);
                        sfi_handle_ipc_dev(pdev);
                        break;
                case SFI_DEV_TYPE_SPI:
                        memset(&spi_info, 0, sizeof(spi_info));
                        strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
 -                      spi_info.irq = pentry->irq;
 +                      spi_info.irq = irq;
                        spi_info.bus_num = pentry->host_num;
                        spi_info.chip_select = pentry->addr;
                        spi_info.max_speed_hz = pentry->max_freq;
                        memset(&i2c_info, 0, sizeof(i2c_info));
                        bus = pentry->host_num;
                        strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
 -                      i2c_info.irq = pentry->irq;
 +                      i2c_info.irq = irq;
                        i2c_info.addr = pentry->addr;
                        pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, "
                                "irq = 0x%2x, addr = 0x%x\n", i, bus,
diff --combined drivers/staging/Kconfig
@@@ -24,6 -24,8 +24,8 @@@ menuconfig STAGIN
  
  if STAGING
  
+ source "drivers/staging/serial/Kconfig"
  source "drivers/staging/et131x/Kconfig"
  
  source "drivers/staging/slicoss/Kconfig"
@@@ -44,7 -46,7 +46,7 @@@ source "drivers/staging/wlan-ng/Kconfig
  
  source "drivers/staging/echo/Kconfig"
  
 -source "drivers/staging/brcm80211/Kconfig"
 +
  
  source "drivers/staging/comedi/Kconfig"
  
@@@ -126,6 -128,8 +128,6 @@@ source "drivers/staging/quickstart/Kcon
  
  source "drivers/staging/sbe-2t3e3/Kconfig"
  
 -source "drivers/staging/ath6kl/Kconfig"
 -
  source "drivers/staging/keucr/Kconfig"
  
  source "drivers/staging/bcm/Kconfig"
diff --combined drivers/staging/Makefile
@@@ -3,6 -3,7 +3,7 @@@
  # fix for build system bug...
  obj-$(CONFIG_STAGING)         += staging.o
  
+ obj-y                         += serial/
  obj-$(CONFIG_ET131X)          += et131x/
  obj-$(CONFIG_SLICOSS)         += slicoss/
  obj-$(CONFIG_VIDEO_GO7007)    += go7007/
@@@ -14,8 -15,8 +15,8 @@@ obj-$(CONFIG_USBIP_CORE)      += usbip
  obj-$(CONFIG_W35UND)          += winbond/
  obj-$(CONFIG_PRISM2_USB)      += wlan-ng/
  obj-$(CONFIG_ECHO)            += echo/
 -obj-$(CONFIG_BRCMSMAC)                += brcm80211/
 -obj-$(CONFIG_BRCMFMAC)                += brcm80211/
 +
 +
  obj-$(CONFIG_COMEDI)          += comedi/
  obj-$(CONFIG_FB_OLPC_DCON)    += olpc_dcon/
  obj-$(CONFIG_ASUS_OLED)               += asus_oled/
@@@ -54,6 -55,7 +55,6 @@@ obj-$(CONFIG_SOLO6X10)                += solo6x10
  obj-$(CONFIG_TIDSPBRIDGE)     += tidspbridge/
  obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
  obj-$(CONFIG_SBE_2T3E3)               += sbe-2t3e3/
 -obj-$(CONFIG_ATH6K_LEGACY)    += ath6kl/
  obj-$(CONFIG_USB_ENESTORAGE)  += keucr/
  obj-$(CONFIG_BCM_WIMAX)               += bcm/
  obj-$(CONFIG_FT1000)          += ft1000/
diff --combined drivers/tty/Kconfig
@@@ -60,13 -60,9 +60,13 @@@ config VT_CONSOL
  
          If unsure, say Y.
  
 +config VT_CONSOLE_SLEEP
 +      def_bool y
 +      depends on VT_CONSOLE && PM_SLEEP
 +
  config HW_CONSOLE
        bool
 -      depends on VT && !S390 && !UML
 +      depends on VT && !UML
        default y
  
  config VT_HW_CONSOLE_BINDING
@@@ -354,3 -350,37 +354,37 @@@ config TRACE_SIN
  
          If you select this option, you need to select
          "Trace data router for MIPI P1149.7 cJTAG standard".
+ config PPC_EPAPR_HV_BYTECHAN
+       tristate "ePAPR hypervisor byte channel driver"
+       depends on PPC
+       help
+         This driver creates /dev entries for each ePAPR hypervisor byte
+         channel, thereby allowing applications to communicate with byte
+         channels as if they were serial ports.
+ config PPC_EARLY_DEBUG_EHV_BC
+       bool "Early console (udbg) support for ePAPR hypervisors"
+       depends on PPC_EPAPR_HV_BYTECHAN
+       help
+         Select this option to enable early console (a.k.a. "udbg") support
+         via an ePAPR byte channel.  You also need to choose the byte channel
+         handle below.
+ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
+       int "Byte channel handle for early console (udbg)"
+       depends on PPC_EARLY_DEBUG_EHV_BC
+       default 0
+       help
+         If you want early console (udbg) output through a byte channel,
+         specify the handle of the byte channel to use.
+         For this to work, the byte channel driver must be compiled
+         in-kernel, not as a module.
+         Note that only one early console driver can be enabled, so don't
+         enable any others if you enable this one.
+         If the number you specify is not a valid byte channel handle, then
+         there simply will be no early console output.  This is true also
+         if you don't boot under a hypervisor at all.
diff --combined drivers/tty/pty.c
@@@ -446,19 -446,8 +446,19 @@@ static inline void legacy_pty_init(void
  int pty_limit = NR_UNIX98_PTY_DEFAULT;
  static int pty_limit_min;
  static int pty_limit_max = NR_UNIX98_PTY_MAX;
 +static int tty_count;
  static int pty_count;
  
 +static inline void pty_inc_count(void)
 +{
 +      pty_count = (++tty_count) / 2;
 +}
 +
 +static inline void pty_dec_count(void)
 +{
 +      pty_count = (--tty_count) / 2;
 +}
 +
  static struct cdev ptmx_cdev;
  
  static struct ctl_table pty_table[] = {
@@@ -553,7 -542,6 +553,7 @@@ static struct tty_struct *pts_unix98_lo
  
  static void pty_unix98_shutdown(struct tty_struct *tty)
  {
 +      tty_driver_remove_tty(tty->driver, tty);
        /* We have our own method as we don't use the tty index */
        kfree(tty->termios);
  }
@@@ -600,8 -588,7 +600,8 @@@ static int pty_unix98_install(struct tt
         */
        tty_driver_kref_get(driver);
        tty->count++;
 -      pty_count++;
 +      pty_inc_count(); /* tty */
 +      pty_inc_count(); /* tty->link */
        return 0;
  err_free_mem:
        deinitialize_tty_struct(o_tty);
@@@ -615,7 -602,7 +615,7 @@@ err_free_tty
  
  static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
  {
 -      pty_count--;
 +      pty_dec_count();
  }
  
  static const struct tty_operations ptm_unix98_ops = {
@@@ -670,12 -657,18 +670,18 @@@ static int ptmx_open(struct inode *inod
  
        nonseekable_open(inode, filp);
  
+       retval = tty_alloc_file(filp);
+       if (retval)
+               return retval;
        /* find a device that is not in use. */
        tty_lock();
        index = devpts_new_index(inode);
        tty_unlock();
-       if (index < 0)
-               return index;
+       if (index < 0) {
+               retval = index;
+               goto err_file;
+       }
  
        mutex_lock(&tty_mutex);
        tty_lock();
  
        set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
  
-       retval = tty_add_file(tty, filp);
-       if (retval)
-               goto out;
+       tty_add_file(tty, filp);
  
        retval = devpts_pty_new(inode, tty->link);
        if (retval)
-               goto out1;
+               goto err_release;
  
        retval = ptm_driver->ops->open(tty, filp);
        if (retval)
-               goto out2;
- out1:
+               goto err_release;
        tty_unlock();
-       return retval;
out2:
+       return 0;
err_release:
        tty_unlock();
        tty_release(inode, filp);
        return retval;
  out:
        devpts_kill_index(inode, index);
        tty_unlock();
+ err_file:
+       tty_free_file(filp);
        return retval;
  }
  
@@@ -309,6 -309,13 +309,13 @@@ static const struct serial8250_config u
                                  UART_FCR_T_TRIG_01,
                .flags          = UART_CAP_FIFO | UART_CAP_RTOIE,
        },
+       [PORT_XR17D15X] = {
+               .name           = "XR17D15X",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
+       },
  };
  
  #if defined(CONFIG_MIPS_ALCHEMY)
@@@ -461,42 -468,6 +468,6 @@@ static void tsi_serial_out(struct uart_
                writeb(value, p->membase + offset);
  }
  
- /* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
- static inline void dwapb_save_out_value(struct uart_port *p, int offset,
-                                       int value)
- {
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-       if (offset == UART_LCR)
-               up->lcr = value;
- }
- /* Read the IER to ensure any interrupt is cleared before returning from ISR. */
- static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
- {
-       if (offset == UART_TX || offset == UART_IER)
-               p->serial_in(p, UART_IER);
- }
- static void dwapb_serial_out(struct uart_port *p, int offset, int value)
- {
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writeb(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
- }
- static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
- {
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writel(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
- }
  static unsigned int io_serial_in(struct uart_port *p, int offset)
  {
        offset = map_8250_in_reg(p, offset) << p->regshift;
@@@ -509,6 -480,8 +480,8 @@@ static void io_serial_out(struct uart_p
        outb(value, p->iobase + offset);
  }
  
+ static int serial8250_default_handle_irq(struct uart_port *port);
  static void set_io_from_upio(struct uart_port *p)
  {
        struct uart_8250_port *up =
                p->serial_out = tsi_serial_out;
                break;
  
-       case UPIO_DWAPB:
-               p->serial_in = mem_serial_in;
-               p->serial_out = dwapb_serial_out;
-               break;
-       case UPIO_DWAPB32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = dwapb32_serial_out;
-               break;
        default:
                p->serial_in = io_serial_in;
                p->serial_out = io_serial_out;
        }
        /* Remember loaded iotype */
        up->cur_iotype = p->iotype;
+       p->handle_irq = serial8250_default_handle_irq;
  }
  
  static void
@@@ -567,8 -531,6 +531,6 @@@ serial_out_sync(struct uart_8250_port *
        case UPIO_MEM:
        case UPIO_MEM32:
        case UPIO_AU:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                p->serial_out(p, offset, value);
                p->serial_in(p, UART_LCR);      /* safe, no side-effects */
                break;
@@@ -1119,6 -1081,14 +1081,14 @@@ static void autoconfig_16550a(struct ua
        }
        serial_outp(up, UART_IER, iersave);
  
+       /*
+        * Exar uarts have EFR in a weird location
+        */
+       if (up->port.flags & UPF_EXAR_EFR) {
+               up->port.type = PORT_XR17D15X;
+               up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
+       }
        /*
         * We distinguish between 16550A and U6 16550A by counting
         * how many bytes are in the FIFO.
@@@ -1621,6 -1591,29 +1591,29 @@@ static void serial8250_handle_port(stru
        spin_unlock_irqrestore(&up->port.lock, flags);
  }
  
+ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+ {
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       if (!(iir & UART_IIR_NO_INT)) {
+               serial8250_handle_port(up);
+               return 1;
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(serial8250_handle_irq);
+ static int serial8250_default_handle_irq(struct uart_port *port)
+ {
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned int iir = serial_in(up, UART_IIR);
+       return serial8250_handle_irq(port, iir);
+ }
  /*
   * This is the serial driver's interrupt routine.
   *
@@@ -1648,30 -1641,13 +1641,13 @@@ static irqreturn_t serial8250_interrupt
        l = i->head;
        do {
                struct uart_8250_port *up;
-               unsigned int iir;
+               struct uart_port *port;
  
                up = list_entry(l, struct uart_8250_port, list);
+               port = &up->port;
  
-               iir = serial_in(up, UART_IIR);
-               if (!(iir & UART_IIR_NO_INT)) {
-                       serial8250_handle_port(up);
+               if (port->handle_irq(port)) {
                        handled = 1;
-                       end = NULL;
-               } else if ((up->port.iotype == UPIO_DWAPB ||
-                           up->port.iotype == UPIO_DWAPB32) &&
-                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
-                       /* The DesignWare APB UART has an Busy Detect (0x07)
-                        * interrupt meaning an LCR write attempt occurred while the
-                        * UART was busy. The interrupt must be cleared by reading
-                        * the UART status register (USR) and the LCR re-written. */
-                       unsigned int status;
-                       status = *(volatile u32 *)up->port.private_data;
-                       serial_out(up, UART_LCR, up->lcr);
-                       handled = 1;
                        end = NULL;
                } else if (end == NULL)
                        end = l;
@@@ -1819,8 -1795,6 +1795,8 @@@ static void serial8250_backup_timeout(u
        unsigned int iir, ier = 0, lsr;
        unsigned long flags;
  
 +      spin_lock_irqsave(&up->port.lock, flags);
 +
        /*
         * Must disable interrupts or else we risk racing with the interrupt
         * based handler.
         * the "Diva" UART used on the management processor on many HP
         * ia64 and parisc boxes.
         */
 -      spin_lock_irqsave(&up->port.lock, flags);
        lsr = serial_in(up, UART_LSR);
        up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
 -      spin_unlock_irqrestore(&up->port.lock, flags);
        if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
            (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
            (lsr & UART_LSR_THRE)) {
        }
  
        if (!(iir & UART_IIR_NO_INT))
 -              serial8250_handle_port(up);
 +              transmit_chars(up);
  
        if (is_real_interrupt(up->port.irq))
                serial_out(up, UART_IER, ier);
  
 +      spin_unlock_irqrestore(&up->port.lock, flags);
 +
        /* Standard timer interval plus 0.2s to keep the port running */
        mod_timer(&up->timer,
                jiffies + uart_poll_timeout(&up->port) + HZ / 5);
@@@ -2081,8 -2055,8 +2057,8 @@@ static int serial8250_startup(struct ua
         */
        if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
-               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
-                      serial_index(&up->port));
+               printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                                  serial_index(&up->port));
                return -ENODEV;
        }
  
@@@ -2458,7 -2432,10 +2434,10 @@@ serial8250_do_set_termios(struct uart_p
                        efr |= UART_EFR_CTS;
  
                serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, efr);
+               if (up->port.flags & UPF_EXAR_EFR)
+                       serial_outp(up, UART_XR_EFR, efr);
+               else
+                       serial_outp(up, UART_EFR, efr);
        }
  
  #ifdef CONFIG_ARCH_OMAP
@@@ -2570,8 -2547,6 +2549,6 @@@ static int serial8250_request_std_resou
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                if (!up->port.mapbase)
                        break;
  
@@@ -2608,8 -2583,6 +2585,6 @@@ static void serial8250_release_std_reso
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                if (!up->port.mapbase)
                        break;
  
@@@ -3050,6 -3023,10 +3025,10 @@@ int __init early_serial_setup(struct ua
                p->serial_in = port->serial_in;
        if (port->serial_out)
                p->serial_out = port->serial_out;
+       if (port->handle_irq)
+               p->handle_irq = port->handle_irq;
+       else
+               p->handle_irq = serial8250_default_handle_irq;
  
        return 0;
  }
@@@ -3118,6 -3095,7 +3097,7 @@@ static int __devinit serial8250_probe(s
                port.type               = p->type;
                port.serial_in          = p->serial_in;
                port.serial_out         = p->serial_out;
+               port.handle_irq         = p->handle_irq;
                port.set_termios        = p->set_termios;
                port.pm                 = p->pm;
                port.dev                = &dev->dev;
@@@ -3283,6 -3261,8 +3263,8 @@@ int serial8250_register_port(struct uar
                        uart->port.serial_in = port->serial_in;
                if (port->serial_out)
                        uart->port.serial_out = port->serial_out;
+               if (port->handle_irq)
+                       uart->port.handle_irq = port->handle_irq;
                /*  Possibly override set_termios call */
                if (port->set_termios)
                        uart->port.set_termios = port->set_termios;
@@@ -1101,6 -1101,15 +1101,15 @@@ static int pci_eg20t_init(struct pci_de
  #endif
  }
  
+ static int
+ pci_xr17c154_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+ {
+       port->flags |= UPF_EXAR_EFR;
+       return pci_default_setup(priv, board, port, idx);
+ }
  /* This should be in linux/pci_ids.h */
  #define PCI_VENDOR_ID_SBSMODULARIO    0x124B
  #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
@@@ -1505,6 -1514,30 +1514,30 @@@ static struct pci_serial_quirk pci_seri
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_timedia_setup,
        },
+       /*
+        * Exar cards
+        */
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C152,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C154,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C158,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
        /*
         * Xircom cards
         */
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8811,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8812,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8813,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8814,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8027,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8028,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8029,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x800C,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x800D,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
 -      {
 -              .vendor         = 0x10DB,
 -              .device         = 0x800D,
 -              .init           = pci_eg20t_init,
 -              .setup          = pci_default_setup,
 -      },
        /*
         * Cronyx Omega PCI (PLX-chip based)
         */
@@@ -4016,17 -4064,13 +4058,17 @@@ static struct pci_device_id serial_pci_
                0, 0, pbn_NETMOS9900_2s_115200 },
  
        /*
 -       * Best Connectivity PCI Multi I/O cards
 +       * Best Connectivity and Rosewill PCI Multi I/O cards
         */
  
        {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
                0xA000, 0x1000,
                0, 0, pbn_b0_1_115200 },
  
 +      {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
 +              0xA000, 0x3002,
 +              0, 0, pbn_b0_bt_2_115200 },
 +
        {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
                0xA000, 0x3004,
                0, 0, pbn_b0_bt_4_115200 },
@@@ -33,6 -33,8 +33,8 @@@
  #include <linux/sysrq.h>
  #include <linux/tty_flip.h>
  #include <linux/platform_device.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
  #include <linux/dma-mapping.h>
  #include <linux/atmel_pdc.h>
  #include <linux/atmel_serial.h>
@@@ -157,11 -159,22 +159,22 @@@ struct atmel_uart_port 
  };
  
  static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+ static unsigned long atmel_ports_in_use;
  
  #ifdef SUPPORT_SYSRQ
  static struct console atmel_console;
  #endif
  
+ #if defined(CONFIG_OF)
+ static const struct of_device_id atmel_serial_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-usart" },
+       { .compatible = "atmel,at91sam9260-usart" },
+       { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
+ #endif
  static inline struct atmel_uart_port *
  to_atmel_uart_port(struct uart_port *uart)
  {
@@@ -339,7 -352,8 +352,8 @@@ static void atmel_stop_tx(struct uart_p
        /* Disable interrupts */
        UART_PUT_IDR(port, atmel_port->tx_done_mask);
  
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+       if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+           !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
                atmel_start_rx(port);
  }
  
@@@ -356,7 -370,8 +370,8 @@@ static void atmel_start_tx(struct uart_
                           really need this.*/
                        return;
  
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
                        atmel_stop_rx(port);
  
                /* re-enable PDC transmit */
@@@ -680,7 -695,8 +695,8 @@@ static void atmel_tx_dma(struct uart_po
                /* Enable interrupts */
                UART_PUT_IER(port, atmel_port->tx_done_mask);
        } else {
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
                        /* DMA done, stop TX, start RX for RS485 */
                        atmel_start_rx(port);
                }
@@@ -1407,6 -1423,48 +1423,48 @@@ static struct uart_ops atmel_pops = 
  #endif
  };
  
+ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
+                                        struct device_node *np)
+ {
+       u32 rs485_delay[2];
+       /* DMA/PDC usage specification */
+       if (of_get_property(np, "atmel,use-dma-rx", NULL))
+               atmel_port->use_dma_rx  = 1;
+       else
+               atmel_port->use_dma_rx  = 0;
+       if (of_get_property(np, "atmel,use-dma-tx", NULL))
+               atmel_port->use_dma_tx  = 1;
+       else
+               atmel_port->use_dma_tx  = 0;
+       /* rs485 properties */
+       if (of_property_read_u32_array(np, "rs485-rts-delay",
+                                           rs485_delay, 2) == 0) {
+               struct serial_rs485 *rs485conf = &atmel_port->rs485;
+               rs485conf->delay_rts_before_send = rs485_delay[0];
+               rs485conf->delay_rts_after_send = rs485_delay[1];
+               rs485conf->flags = 0;
+               if (rs485conf->delay_rts_before_send == 0 &&
+                   rs485conf->delay_rts_after_send == 0) {
+                       rs485conf->flags |= SER_RS485_RTS_ON_SEND;
+               } else {
+                       if (rs485conf->delay_rts_before_send)
+                               rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
+                       if (rs485conf->delay_rts_after_send)
+                               rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+               }
+               if (of_get_property(np, "rs485-rx-during-tx", NULL))
+                       rs485conf->flags |= SER_RS485_RX_DURING_TX;
+               if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
+                       rs485conf->flags |= SER_RS485_ENABLED;
+       }
+ }
  /*
   * Configure the port from the platform device resource info.
   */
@@@ -1414,13 -1472,20 +1472,20 @@@ static void __devinit atmel_init_port(s
                                      struct platform_device *pdev)
  {
        struct uart_port *port = &atmel_port->uart;
-       struct atmel_uart_data *data = pdev->dev.platform_data;
+       struct atmel_uart_data *pdata = pdev->dev.platform_data;
+       if (pdev->dev.of_node) {
+               atmel_of_init_port(atmel_port, pdev->dev.of_node);
+       } else {
+               atmel_port->use_dma_rx  = pdata->use_dma_rx;
+               atmel_port->use_dma_tx  = pdata->use_dma_tx;
+               atmel_port->rs485       = pdata->rs485;
+       }
  
        port->iotype            = UPIO_MEM;
        port->flags             = UPF_BOOT_AUTOCONF;
        port->ops               = &atmel_pops;
        port->fifosize          = 1;
-       port->line              = data->num;
        port->dev               = &pdev->dev;
        port->mapbase   = pdev->resource[0].start;
        port->irq       = pdev->resource[1].start;
  
        memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
  
-       if (data->regs)
+       if (pdata && pdata->regs) {
                /* Already mapped by setup code */
-               port->membase = data->regs;
-       else {
+               port->membase = pdata->regs;
+       else {
                port->flags     |= UPF_IOREMAP;
                port->membase   = NULL;
        }
                /* only enable clock when USART is in use */
        }
  
-       atmel_port->use_dma_rx = data->use_dma_rx;
-       atmel_port->use_dma_tx = data->use_dma_tx;
-       atmel_port->rs485       = data->rs485;
        /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
        if (atmel_port->rs485.flags & SER_RS485_ENABLED)
                atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
@@@ -1609,12 -1671,14 +1671,16 @@@ static struct console atmel_console = 
  static int __init atmel_console_init(void)
  {
        if (atmel_default_console_device) {
 -              int id = atmel_default_console_device->id;
 +              struct atmel_uart_data *pdata =
 +                      atmel_default_console_device->dev.platform_data;
++              int id = pdata->num;
+               struct atmel_uart_port *port = &atmel_ports[id];
+               port->backup_imr = 0;
+               port->uart.line = id;
  
-               add_preferred_console(ATMEL_DEVICENAME, pdata->num, NULL);
-               atmel_init_port(&atmel_ports[pdata->num],
-                               atmel_default_console_device);
+               add_preferred_console(ATMEL_DEVICENAME, id, NULL);
+               atmel_init_port(port, atmel_default_console_device);
                register_console(&atmel_console);
        }
  
@@@ -1711,14 -1775,39 +1777,39 @@@ static int atmel_serial_resume(struct p
  static int __devinit atmel_serial_probe(struct platform_device *pdev)
  {
        struct atmel_uart_port *port;
+       struct device_node *np = pdev->dev.of_node;
        struct atmel_uart_data *pdata = pdev->dev.platform_data;
        void *data;
-       int ret;
+       int ret = -ENODEV;
  
        BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
  
-       port = &atmel_ports[pdata->num];
+       if (np)
+               ret = of_alias_get_id(np, "serial");
+       else
+               if (pdata)
+                       ret = pdata->num;
+       if (ret < 0)
+               /* port id not found in platform data nor device-tree aliases:
+                * auto-enumerate it */
+               ret = find_first_zero_bit(&atmel_ports_in_use,
+                               sizeof(atmel_ports_in_use));
+       if (ret > ATMEL_MAX_UART) {
+               ret = -ENODEV;
+               goto err;
+       }
+       if (test_and_set_bit(ret, &atmel_ports_in_use)) {
+               /* port already in use */
+               ret = -EBUSY;
+               goto err;
+       }
+       port = &atmel_ports[ret];
        port->backup_imr = 0;
+       port->uart.line = ret;
  
        atmel_init_port(port, pdev);
  
@@@ -1764,7 -1853,7 +1855,7 @@@ err_alloc_ring
                clk_put(port->clk);
                port->clk = NULL;
        }
+ err:
        return ret;
  }
  
@@@ -1784,6 -1873,8 +1875,8 @@@ static int __devexit atmel_serial_remov
  
        /* "port" is allocated statically, so we shouldn't free it */
  
+       clear_bit(port->line, &atmel_ports_in_use);
        clk_put(atmel_port->clk);
  
        return ret;
@@@ -1797,6 -1888,7 +1890,7 @@@ static struct platform_driver atmel_ser
        .driver         = {
                .name   = "atmel_usart",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_serial_dt_ids),
        },
  };
  
@@@ -338,21 -338,21 +338,21 @@@ lqasc_startup(struct uart_port *port
                ASCCON_ROEN, port->membase + LTQ_ASC_CON);
  
        retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
-               IRQF_DISABLED, "asc_tx", port);
+               0, "asc_tx", port);
        if (retval) {
                pr_err("failed to request lqasc_tx_int\n");
                return retval;
        }
  
        retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
-               IRQF_DISABLED, "asc_rx", port);
+               0, "asc_rx", port);
        if (retval) {
                pr_err("failed to request lqasc_rx_int\n");
                goto err1;
        }
  
        retval = request_irq(ltq_port->err_irq, lqasc_err_int,
-               IRQF_DISABLED, "asc_err", port);
+               0, "asc_err", port);
        if (retval) {
                pr_err("failed to request lqasc_err_int\n");
                goto err2;
@@@ -478,10 -478,8 +478,10 @@@ lqasc_set_termios(struct uart_port *por
        spin_unlock_irqrestore(&ltq_asc_lock, flags);
  
        /* Don't rewrite B0 */
 -        if (tty_termios_baud_rate(new))
 +      if (tty_termios_baud_rate(new))
                tty_termios_encode_baud_rate(new, baud, baud);
 +
 +      uart_update_timeout(port, cflag, baud);
  }
  
  static const char*
@@@ -31,6 -31,8 +31,8 @@@
  #include <linux/device.h>
  #include <linux/serial_core.h>
  #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
  #include <linux/gpio.h>
  #include <linux/spi/spi.h>
  #include <linux/freezer.h>
@@@ -1209,5 -1211,5 +1211,5 @@@ module_exit(max3107_exit)
  
  MODULE_DESCRIPTION("MAX3107 driver");
  MODULE_AUTHOR("Aavamobile");
 -MODULE_ALIAS("max3107-spi");
 +MODULE_ALIAS("spi:max3107");
  MODULE_LICENSE("GPL v2");
   *    1 word. If SPI master controller doesn't support sclk frequency change,
   *    then the char need be sent out one by one with some delay
   *
 - * 2. Currently only RX available interrrupt is used, no need for waiting TXE
 + * 2. Currently only RX available interrupt is used, no need for waiting TXE
   *    interrupt for a low speed UART device
   */
  
+ #ifdef CONFIG_MAGIC_SYSRQ
+ #define SUPPORT_SYSRQ
+ #endif
  #include <linux/module.h>
  #include <linux/ioport.h>
  #include <linux/irq.h>
@@@ -73,9 -77,9 +77,9 @@@ struct uart_max3110 
  /* global data structure, may need be removed */
  static struct uart_max3110 *pmax;
  
- static void receive_chars(struct uart_max3110 *max,
-                               unsigned char *str, int len);
- static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
+ static int receive_chars(struct uart_max3110 *max,
+                               unsigned short *str, int len);
+ static int max3110_read_multi(struct uart_max3110 *max);
  static void max3110_con_receive(struct uart_max3110 *max);
  
  static int max3110_write_then_read(struct uart_max3110 *max,
@@@ -108,7 -112,6 +112,6 @@@ static int max3110_out(struct uart_max3
  {
        void *buf;
        u16 *obuf, *ibuf;
-       u8  ch;
        int ret;
  
        buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
                goto exit;
        }
  
-       /* If some valid data is read back */
-       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
-               ch = *ibuf & 0xff;
-               receive_chars(max, &ch, 1);
-       }
+       receive_chars(max, ibuf, 1);
  
  exit:
        kfree(buf);
   *
   * Return how many valide bytes are read back
   */
- static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
+ static int max3110_read_multi(struct uart_max3110 *max)
  {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
-       int i, j, blen;
+       int ret, blen;
  
        blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
        buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
                return 0;
        }
  
-       /* If caller doesn't provide a buffer, then handle received char */
-       pbuf = rxbuf ? rxbuf : valid_str;
-       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
-               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                       pbuf[j++] = ibuf[i] & 0xff;
-       }
-       if (j && (pbuf == valid_str))
-               receive_chars(max, valid_str, j);
+       ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
  
        kfree(buf);
-       return j;
+       return ret;
  }
  
  static void serial_m3110_con_putchar(struct uart_port *port, int ch)
@@@ -207,7 -196,7 +196,7 @@@ static void serial_m3110_con_write(stru
        uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
  
        if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-               wake_up_process(pmax->main_thread);
+               wake_up(&pmax->wq);
  }
  
  static int __init
@@@ -276,8 -265,7 +265,7 @@@ static void send_circ_buf(struct uart_m
  {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 valid_str[WORDS_PER_XFER];
-       int i, j, len, blen, dma_size, left, ret = 0;
+       int i, len, blen, dma_size, left, ret = 0;
  
  
        dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
                        }
  
                        /* Fail to send msg to console is not very critical */
                        ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
                        if (ret)
                                pr_warning(PR_FMT "%s(): get err msg %d\n",
                                                __func__, ret);
  
-                       for (i = 0, j = 0; i < len; i++) {
-                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                                       valid_str[j++] = ibuf[i] & 0xff;
-                       }
-                       if (j)
-                               receive_chars(max, valid_str, j);
+                       receive_chars(max, ibuf, len);
  
                        max->port.icount.tx += len;
                        left -= len;
@@@ -349,33 -332,54 +332,54 @@@ static void serial_m3110_start_tx(struc
                container_of(port, struct uart_max3110, port);
  
        if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
  }
  
- static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
+ static int
+ receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
  {
        struct uart_port *port = &max->port;
        struct tty_struct *tty;
-       int usable;
+       char buf[M3110_RX_FIFO_DEPTH];
+       int r, w, usable;
  
        /* If uart is not opened, just return */
        if (!port->state)
-               return;
+               return 0;
  
-       tty = port->state->port.tty;
+       tty = tty_port_tty_get(&port->state->port);
        if (!tty)
-               return;
+               return 0;
  
-       while (len) {
-               usable = tty_buffer_request_room(tty, len);
+       for (r = 0, w = 0; r < len; r++) {
+               if (str[r] & MAX3110_BREAK &&
+                   uart_handle_break(port))
+                       continue;
+               if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
+                       if (uart_handle_sysrq_char(port, str[r] & 0xff))
+                               continue;
+                       buf[w++] = str[r] & 0xff;
+               }
+       }
+       if (!w) {
+               tty_kref_put(tty);
+               return 0;
+       }
+       for (r = 0; w; r += usable, w -= usable) {
+               usable = tty_buffer_request_room(tty, w);
                if (usable) {
-                       tty_insert_flip_string(tty, str, usable);
-                       str += usable;
+                       tty_insert_flip_string(tty, buf + r, usable);
                        port->icount.rx += usable;
                }
-               len -= usable;
        }
        tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+       return r;
  }
  
  /*
   */
  static void max3110_con_receive(struct uart_max3110 *max)
  {
-       int loop = 1, num, total = 0;
-       u8 recv_buf[512], *pbuf;
+       int loop = 1, num;
  
-       pbuf = recv_buf;
        do {
-               num = max3110_read_multi(max, pbuf);
+               num = max3110_read_multi(max);
  
                if (num) {
                        loop = 5;
-                       pbuf += num;
-                       total += num;
-                       if (total >= 504) {
-                               receive_chars(max, recv_buf, total);
-                               pbuf = recv_buf;
-                               total = 0;
-                       }
                }
        } while (--loop);
-       if (total)
-               receive_chars(max, recv_buf, total);
  }
  
  static int max3110_main_thread(void *_max)
        pr_info(PR_FMT "start main thread\n");
  
        do {
-               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
+               wait_event_interruptible(*wq,
+                               max->uart_flags || kthread_should_stop());
  
                mutex_lock(&max->thread_mutex);
  
@@@ -452,8 -444,9 +444,9 @@@ static irqreturn_t serial_m3110_irq(in
  
        /* max3110's irq is a falling edge, not level triggered,
         * so no need to disable the irq */
        if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
  
        return IRQ_HANDLED;
  }
@@@ -917,4 -910,4 +910,4 @@@ module_init(serial_m3110_init)
  module_exit(serial_m3110_exit);
  
  MODULE_LICENSE("GPL v2");
 -MODULE_ALIAS("max3110-uart");
 +MODULE_ALIAS("spi:max3110-uart");
@@@ -20,6 -20,8 +20,8 @@@
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/serial_core.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/dmi.h>
@@@ -598,8 -600,7 +600,8 @@@ static void pch_request_dma(struct uart
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
  
 -      dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
 +      dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number,
 +                                     PCI_DEVFN(0xa, 0)); /* Get DMA's dev
                                                                information */
        /* Set Tx DMA */
        param = &priv->param_tx;
@@@ -83,6 -83,16 +83,16 @@@ static int s3c24xx_serial_txempty_nofif
        return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
  }
  
+ /*
+  * s3c64xx and later SoC's include the interrupt mask and status registers in
+  * the controller itself, unlike the s3c24xx SoC's which have these registers
+  * in the interrupt controller. Check if the port type is s3c64xx or higher.
+  */
+ static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+ {
+       return to_ourport(port)->info->type == PORT_S3C6400;
+ }
  static void s3c24xx_serial_rx_enable(struct uart_port *port)
  {
        unsigned long flags;
@@@ -126,7 -136,11 +136,11 @@@ static void s3c24xx_serial_stop_tx(stru
        struct s3c24xx_uart_port *ourport = to_ourport(port);
  
        if (tx_enabled(port)) {
-               disable_irq_nosync(ourport->tx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __set_bit(S3C64XX_UINTM_TXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       disable_irq_nosync(ourport->tx_irq);
                tx_enabled(port) = 0;
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_enable(port);
@@@ -141,19 -155,26 +155,26 @@@ static void s3c24xx_serial_start_tx(str
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_disable(port);
  
-               enable_irq(ourport->tx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __clear_bit(S3C64XX_UINTM_TXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       enable_irq(ourport->tx_irq);
                tx_enabled(port) = 1;
        }
  }
  
  static void s3c24xx_serial_stop_rx(struct uart_port *port)
  {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
  
        if (rx_enabled(port)) {
                dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               disable_irq_nosync(ourport->rx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __set_bit(S3C64XX_UINTM_RXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       disable_irq_nosync(ourport->rx_irq);
                rx_enabled(port) = 0;
        }
  }
@@@ -320,6 -341,28 +341,28 @@@ static irqreturn_t s3c24xx_serial_tx_ch
        return IRQ_HANDLED;
  }
  
+ /* interrupt handler for s3c64xx and later SoC's.*/
+ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
+ {
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       unsigned int pend = rd_regl(port, S3C64XX_UINTP);
+       unsigned long flags;
+       irqreturn_t ret = IRQ_HANDLED;
+       spin_lock_irqsave(&port->lock, flags);
+       if (pend & S3C64XX_UINTM_RXD_MSK) {
+               ret = s3c24xx_serial_rx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
+       }
+       if (pend & S3C64XX_UINTM_TXD_MSK) {
+               ret = s3c24xx_serial_tx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+ }
  static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
  {
        struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@@ -377,18 -420,25 +420,25 @@@ static void s3c24xx_serial_shutdown(str
        struct s3c24xx_uart_port *ourport = to_ourport(port);
  
        if (ourport->tx_claimed) {
-               free_irq(ourport->tx_irq, ourport);
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
        }
  
        if (ourport->rx_claimed) {
-               free_irq(ourport->rx_irq, ourport);
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->rx_irq, ourport);
                ourport->rx_claimed = 0;
                rx_enabled(port) = 0;
        }
- }
  
+       /* Clear pending interrupts and mask all interrupts */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+       }
+ }
  
  static int s3c24xx_serial_startup(struct uart_port *port)
  {
        return ret;
  }
  
+ static int s3c64xx_serial_startup(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+       dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
+       ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
+                         s3c24xx_serial_portname(port), ourport);
+       if (ret) {
+               printk(KERN_ERR "cannot get irq %d\n", port->irq);
+               return ret;
+       }
+       /* For compatibility with s3c24xx Soc's */
+       rx_enabled(port) = 1;
+       ourport->rx_claimed = 1;
+       tx_enabled(port) = 0;
+       ourport->tx_claimed = 1;
+       /* Enable Rx Interrupt */
+       __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
+       dbg("s3c64xx_serial_startup ok\n");
+       return ret;
+ }
  /* power power management control */
  
  static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@@ -879,7 -956,6 +956,6 @@@ static struct uart_ops s3c24xx_serial_o
        .verify_port    = s3c24xx_serial_verify_port,
  };
  
  static struct uart_driver s3c24xx_uart_drv = {
        .owner          = THIS_MODULE,
        .driver_name    = "s3c2410_serial",
@@@ -895,7 -971,6 +971,6 @@@ static struct s3c24xx_uart_port s3c24xx
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX0,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX1,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX2,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX3,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
@@@ -1077,6 -1149,10 +1149,10 @@@ static int s3c24xx_serial_init_port(str
        port->dev       = &platdev->dev;
        ourport->info   = info;
  
+       /* Startup sequence is different for s3c64xx and higher SoC's */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
        /* copy the info in from provided structure */
        ourport->port.fifosize = info->fifosize;
  
  
        ourport->clk    = clk_get(&platdev->dev, "uart");
  
+       /* Keep all interrupts masked and cleared */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTSP, 0xf);
+       }
        dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
            port->mapbase, port->membase, port->irq,
            ourport->rx_irq, ourport->tx_irq, port->uartclk);
@@@ -1225,19 -1308,15 +1308,19 @@@ static const struct dev_pm_ops s3c24xx_
        .suspend = s3c24xx_serial_suspend,
        .resume = s3c24xx_serial_resume,
  };
 +#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
 +
  #else /* !CONFIG_PM_SLEEP */
 -#define s3c24xx_serial_pm_ops NULL
 +
 +#define SERIAL_SAMSUNG_PM_OPS NULL
  #endif /* CONFIG_PM_SLEEP */
  
  int s3c24xx_serial_init(struct platform_driver *drv,
                        struct s3c24xx_uart_info *info)
  {
        dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
 -      drv->driver.pm = &s3c24xx_serial_pm_ops;
 +
 +      drv->driver.pm = SERIAL_SAMSUNG_PM_OPS;
  
        return platform_driver_register(drv);
  }
@@@ -57,7 -57,7 +57,7 @@@ static struct lock_class_key port_lock_
  
  static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
                                        struct ktermios *old_termios);
- static void __uart_wait_until_sent(struct uart_port *port, int timeout);
+ static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
  static void uart_change_pm(struct uart_state *state, int pm_state);
  
  /*
@@@ -72,7 -72,7 +72,7 @@@ void uart_write_wakeup(struct uart_por
         * closed.  No cookie for you.
         */
        BUG_ON(!state);
-       tasklet_schedule(&state->tlet);
+       tty_wakeup(state->port.tty);
  }
  
  static void uart_stop(struct tty_struct *tty)
@@@ -107,12 -107,6 +107,6 @@@ static void uart_start(struct tty_struc
        spin_unlock_irqrestore(&port->lock, flags);
  }
  
- static void uart_tasklet_action(unsigned long data)
- {
-       struct uart_state *state = (struct uart_state *)data;
-       tty_wakeup(state->port.tty);
- }
  static inline void
  uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
  {
@@@ -200,11 -194,6 +194,11 @@@ static int uart_startup(struct tty_stru
                clear_bit(TTY_IO_ERROR, &tty->flags);
        }
  
 +      /*
 +       * This is to allow setserial on this port. People may want to set
 +       * port/irq/type and then reconfigure the port properly if it failed
 +       * now.
 +       */
        if (retval && capable(CAP_SYS_ADMIN))
                retval = 0;
  
@@@ -255,9 -244,11 +249,11 @@@ static void uart_shutdown(struct tty_st
        }
  
        /*
-        * kill off our tasklet
+        * It's possible for shutdown to be called after suspend if we get
+        * a DCD drop (hangup) at just the right time.  Clear suspended bit so
+        * we don't try to resume a port that has been shutdown.
         */
-       tasklet_kill(&state->tlet);
+       clear_bit(ASYNCB_SUSPENDED, &port->flags);
  
        /*
         * Free the transmit buffer page.
@@@ -1261,8 -1252,6 +1257,6 @@@ static void uart_close(struct tty_struc
        struct uart_port *uport;
        unsigned long flags;
  
-       BUG_ON(!tty_locked());
        if (!state)
                return;
  
  
        pr_debug("uart_close(%d) called\n", uport->line);
  
-       mutex_lock(&port->mutex);
        spin_lock_irqsave(&port->lock, flags);
  
        if (tty_hung_up_p(filp)) {
                spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
+               return;
        }
  
        if ((tty->count == 1) && (port->count != 1)) {
        }
        if (port->count) {
                spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
+               return;
        }
  
        /*
         * the line discipline to only process XON/XOFF characters by
         * setting tty->closing.
         */
+       set_bit(ASYNCB_CLOSING, &port->flags);
        tty->closing = 1;
        spin_unlock_irqrestore(&port->lock, flags);
  
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               /*
-                * hack: open-coded tty_wait_until_sent to avoid
-                * recursive tty_lock
-                */
-               long timeout = msecs_to_jiffies(port->closing_wait);
-               if (wait_event_interruptible_timeout(tty->write_wait,
-                               !tty_chars_in_buffer(tty), timeout) >= 0)
-                       __uart_wait_until_sent(uport, timeout);
-       }
+       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent_from_close(tty,
+                               msecs_to_jiffies(port->closing_wait));
  
        /*
         * At this point, we stop accepting input.  To do this, we
                 * has completely drained; this is especially
                 * important if there is a transmit FIFO!
                 */
-               __uart_wait_until_sent(uport, uport->timeout);
+               uart_wait_until_sent(tty, uport->timeout);
        }
  
+       mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
        uart_flush_buffer(tty);
  
         * Wake up anyone trying to open this port.
         */
        clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+       clear_bit(ASYNCB_CLOSING, &port->flags);
        spin_unlock_irqrestore(&port->lock, flags);
        wake_up_interruptible(&port->open_wait);
+       wake_up_interruptible(&port->close_wait);
  
- done:
        mutex_unlock(&port->mutex);
  }
  
- static void __uart_wait_until_sent(struct uart_port *port, int timeout)
+ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
  {
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
        unsigned long char_time, expire;
  
        if (port->type == PORT_UNKNOWN || port->fifosize == 0)
        }
  }
  
- static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
- {
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-       tty_lock();
-       __uart_wait_until_sent(port, timeout);
-       tty_unlock();
- }
  /*
   * This is called with the BKL held in
   *  linux/drivers/char/tty_io.c:do_tty_hangup()
@@@ -1443,7 -1419,6 +1424,6 @@@ static void uart_hangup(struct tty_stru
        struct tty_port *port = &state->port;
        unsigned long flags;
  
-       BUG_ON(!tty_locked());
        pr_debug("uart_hangup(%d)\n", state->uart_port->line);
  
        mutex_lock(&port->mutex);
@@@ -1530,7 -1505,6 +1510,6 @@@ static int uart_open(struct tty_struct 
        struct tty_port *port;
        int retval, line = tty->index;
  
-       BUG_ON(!tty_locked());
        pr_debug("uart_open(%d) called\n", line);
  
        /*
@@@ -2008,6 -1982,8 +1987,8 @@@ int uart_resume_port(struct uart_drive
                if (port->tty && port->tty->termios && termios.c_cflag == 0)
                        termios = *(port->tty->termios);
  
+               if (console_suspend_enabled)
+                       uart_change_pm(state, 0);
                uport->ops->set_termios(uport, &termios, NULL);
                if (console_suspend_enabled)
                        console_start(uport->cons);
@@@ -2068,8 -2044,6 +2049,6 @@@ uart_report_port(struct uart_driver *dr
        case UPIO_MEM32:
        case UPIO_AU:
        case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                snprintf(address, sizeof(address),
                         "MMIO 0x%llx", (unsigned long long)port->mapbase);
                break;
@@@ -2298,8 -2272,6 +2277,6 @@@ int uart_register_driver(struct uart_dr
                port->ops = &uart_port_ops;
                port->close_delay     = 500;    /* .5 seconds */
                port->closing_wait    = 30000;  /* 30 seconds */
-               tasklet_init(&state->tlet, uart_tasklet_action,
-                            (unsigned long)state);
        }
  
        retval = tty_register_driver(normal);
@@@ -2460,11 -2432,6 +2437,6 @@@ int uart_remove_one_port(struct uart_dr
         */
        uport->type = PORT_UNKNOWN;
  
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       tasklet_kill(&state->tlet);
        state->uart_port = NULL;
        mutex_unlock(&port_mutex);
  
@@@ -2489,8 -2456,6 +2461,6 @@@ int uart_match_port(struct uart_port *p
        case UPIO_MEM32:
        case UPIO_AU:
        case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                return (port1->mapbase == port2->mapbase);
        }
        return 0;
@@@ -47,7 -47,6 +47,7 @@@
  #include <linux/ctype.h>
  #include <linux/err.h>
  #include <linux/dmaengine.h>
 +#include <linux/dma-mapping.h>
  #include <linux/scatterlist.h>
  #include <linux/slab.h>
  
@@@ -96,12 -95,6 +96,12 @@@ struct sci_port 
  #endif
  
        struct notifier_block           freq_transition;
 +
 +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 +      unsigned short saved_smr;
 +      unsigned short saved_fcr;
 +      unsigned char saved_brr;
 +#endif
  };
  
  /* Function prototypes */
@@@ -1083,7 -1076,7 +1083,7 @@@ static unsigned int sci_get_mctrl(struc
        /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
           and CTS/RTS */
  
 -      return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
 +      return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
  }
  
  #ifdef CONFIG_SERIAL_SH_SCI_DMA
@@@ -1640,25 -1633,11 +1640,25 @@@ static unsigned int sci_scbrr_calc(unsi
        return ((freq + 16 * bps) / (32 * bps) - 1);
  }
  
 +static void sci_reset(struct uart_port *port)
 +{
 +      unsigned int status;
 +
 +      do {
 +              status = sci_in(port, SCxSR);
 +      } while (!(status & SCxSR_TEND(port)));
 +
 +      sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
 +
 +      if (port->type != PORT_SCI)
 +              sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
 +}
 +
  static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
  {
        struct sci_port *s = to_sci_port(port);
 -      unsigned int status, baud, smr_val, max_baud;
 +      unsigned int baud, smr_val, max_baud;
        int t = -1;
        u16 scfcr = 0;
  
  
        sci_port_enable(s);
  
 -      do {
 -              status = sci_in(port, SCxSR);
 -      } while (!(status & SCxSR_TEND(port)));
 -
 -      sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
 -
 -      if (port->type != PORT_SCI)
 -              sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
 +      sci_reset(port);
  
        smr_val = sci_in(port, SCSMR) & 3;
  
@@@ -1927,7 -1913,6 +1927,7 @@@ static int __devinit sci_init_single(st
  
                port->dev = &dev->dev;
  
 +              pm_runtime_irq_safe(&dev->dev);
                pm_runtime_enable(&dev->dev);
        }
  
         * For the muxed case there's nothing more to do.
         */
        port->irq               = p->irqs[SCIx_RXI_IRQ];
-       port->irqflags          = IRQF_DISABLED;
+       port->irqflags          = 0;
  
        port->serial_in         = sci_serial_in;
        port->serial_out        = sci_serial_out;
@@@ -2051,8 -2036,7 +2051,8 @@@ static int __devinit serial_console_set
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
  
 -      /* TODO: disable clock */
 +      sci_port_disable(sci_port);
 +
        return uart_set_options(port, co, baud, parity, bits, flow);
  }
  
@@@ -2095,36 -2079,6 +2095,36 @@@ static int __devinit sci_probe_earlypri
        return 0;
  }
  
 +#define uart_console(port)    ((port)->cons->index == (port)->line)
 +
 +static int sci_runtime_suspend(struct device *dev)
 +{
 +      struct sci_port *sci_port = dev_get_drvdata(dev);
 +      struct uart_port *port = &sci_port->port;
 +
 +      if (uart_console(port)) {
 +              sci_port->saved_smr = sci_in(port, SCSMR);
 +              sci_port->saved_brr = sci_in(port, SCBRR);
 +              sci_port->saved_fcr = sci_in(port, SCFCR);
 +      }
 +      return 0;
 +}
 +
 +static int sci_runtime_resume(struct device *dev)
 +{
 +      struct sci_port *sci_port = dev_get_drvdata(dev);
 +      struct uart_port *port = &sci_port->port;
 +
 +      if (uart_console(port)) {
 +              sci_reset(port);
 +              sci_out(port, SCSMR, sci_port->saved_smr);
 +              sci_out(port, SCBRR, sci_port->saved_brr);
 +              sci_out(port, SCFCR, sci_port->saved_fcr);
 +              sci_out(port, SCSCR, sci_port->cfg->scscr);
 +      }
 +      return 0;
 +}
 +
  #define SCI_CONSOLE   (&serial_console)
  
  #else
@@@ -2134,8 -2088,6 +2134,8 @@@ static inline int __devinit sci_probe_e
  }
  
  #define SCI_CONSOLE   NULL
 +#define sci_runtime_suspend   NULL
 +#define sci_runtime_resume    NULL
  
  #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
  
@@@ -2251,8 -2203,6 +2251,8 @@@ static int sci_resume(struct device *de
  }
  
  static const struct dev_pm_ops sci_dev_pm_ops = {
 +      .runtime_suspend = sci_runtime_suspend,
 +      .runtime_resume = sci_runtime_resume,
        .suspend        = sci_suspend,
        .resume         = sci_resume,
  };
  
  #include <linux/module.h>
  #include <linux/serial.h>
- #include <linux/slab.h>
  #include <linux/serial_core.h>
+ #include <linux/slab.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
  #include <linux/io.h>
  #include <linux/of_platform.h>
  #include <linux/dma-mapping.h>
@@@ -235,7 -237,7 +237,7 @@@ static inline void *qe2cpu_addr(dma_add
                return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
  
        /* something nasty happened */
 -      printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
 +      printk(KERN_ERR "%s: addr=%llx\n", __func__, (u64)addr);
        BUG();
        return NULL;
  }
diff --combined drivers/tty/tty_io.c
@@@ -194,8 -194,7 +194,7 @@@ static inline struct tty_struct *file_t
        return ((struct tty_file_private *)file->private_data)->tty;
  }
  
- /* Associate a new file with the tty structure */
- int tty_add_file(struct tty_struct *tty, struct file *file)
+ int tty_alloc_file(struct file *file)
  {
        struct tty_file_private *priv;
  
        if (!priv)
                return -ENOMEM;
  
+       file->private_data = priv;
+       return 0;
+ }
+ /* Associate a new file with the tty structure */
+ void tty_add_file(struct tty_struct *tty, struct file *file)
+ {
+       struct tty_file_private *priv = file->private_data;
        priv->tty = tty;
        priv->file = file;
-       file->private_data = priv;
  
        spin_lock(&tty_files_lock);
        list_add(&priv->list, &tty->tty_files);
        spin_unlock(&tty_files_lock);
+ }
  
-       return 0;
+ /**
+  * tty_free_file - free file->private_data
+  *
+  * This shall be used only for fail path handling when tty_add_file was not
+  * called yet.
+  */
+ void tty_free_file(struct file *file)
+ {
+       struct tty_file_private *priv = file->private_data;
+       file->private_data = NULL;
+       kfree(priv);
  }
  
  /* Delete file from its tty */
@@@ -222,8 -242,7 +242,7 @@@ void tty_del_file(struct file *file
        spin_lock(&tty_files_lock);
        list_del(&priv->list);
        spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
+       tty_free_file(file);
  }
  
  
@@@ -1295,7 -1314,8 +1314,7 @@@ static int tty_driver_install_tty(struc
   *
   *    Locking: tty_mutex for now
   */
 -static void tty_driver_remove_tty(struct tty_driver *driver,
 -                                              struct tty_struct *tty)
 +void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
  {
        if (driver->ops->remove)
                driver->ops->remove(driver, tty);
@@@ -1811,6 -1831,10 +1830,10 @@@ static int tty_open(struct inode *inode
        nonseekable_open(inode, filp);
  
  retry_open:
+       retval = tty_alloc_file(filp);
+       if (retval)
+               return -ENOMEM;
        noctty = filp->f_flags & O_NOCTTY;
        index  = -1;
        retval = 0;
                if (!tty) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_free_file(filp);
                        return -ENXIO;
                }
                driver = tty_driver_kref_get(tty->driver);
                }
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
  
        if (!driver) {
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
  got_driver:
                if (IS_ERR(tty)) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_driver_kref_put(driver);
+                       tty_free_file(filp);
                        return PTR_ERR(tty);
                }
        }
        tty_driver_kref_put(driver);
        if (IS_ERR(tty)) {
                tty_unlock();
+               tty_free_file(filp);
                return PTR_ERR(tty);
        }
  
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               tty_release(inode, filp);
-               return retval;
-       }
+       tty_add_file(tty, filp);
  
        check_tty_count(tty, "tty_open");
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@@ -2716,6 -2741,8 +2740,8 @@@ static long tty_compat_ioctl(struct fil
        ld = tty_ldisc_ref_wait(tty);
        if (ld->ops->compat_ioctl)
                retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       else
+               retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
        tty_ldisc_deref(ld);
  
        return retval;
diff --combined include/linux/tty.h
@@@ -421,8 -421,6 +421,8 @@@ extern void tty_driver_flush_buffer(str
  extern void tty_throttle(struct tty_struct *tty);
  extern void tty_unthrottle(struct tty_struct *tty);
  extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
 +extern void tty_driver_remove_tty(struct tty_driver *driver,
 +                                struct tty_struct *tty);
  extern void tty_shutdown(struct tty_struct *tty);
  extern void tty_free_termios(struct tty_struct *tty);
  extern int is_current_pgrp_orphaned(void);
@@@ -473,7 -471,9 +473,9 @@@ extern void proc_clear_tty(struct task_
  extern struct tty_struct *get_current_tty(void);
  extern void tty_default_fops(struct file_operations *fops);
  extern struct tty_struct *alloc_tty_struct(void);
- extern int tty_add_file(struct tty_struct *tty, struct file *file);
+ extern int tty_alloc_file(struct file *file);
+ extern void tty_add_file(struct tty_struct *tty, struct file *file);
+ extern void tty_free_file(struct file *file);
  extern void free_tty_struct(struct tty_struct *tty);
  extern void initialize_tty_struct(struct tty_struct *tty,
                struct tty_driver *driver, int idx);
@@@ -581,6 -581,8 +583,8 @@@ extern int __init tty_init(void)
  /* tty_ioctl.c */
  extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg);
+ extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg);
  
  /* serial.c */
  
@@@ -602,8 -604,24 +606,24 @@@ extern long vt_compat_ioctl(struct tty_
  /* functions for preparation of BKL removal */
  extern void __lockfunc tty_lock(void) __acquires(tty_lock);
  extern void __lockfunc tty_unlock(void) __releases(tty_lock);
- extern struct task_struct *__big_tty_mutex_owner;
- #define tty_locked()          (current == __big_tty_mutex_owner)
+ /*
+  * this shall be called only from where BTM is held (like close)
+  *
+  * We need this to ensure nobody waits for us to finish while we are waiting.
+  * Without this we were encountering system stalls.
+  *
+  * This should be indeed removed with BTM removal later.
+  *
+  * Locking: BTM required. Nobody is allowed to hold port->mutex.
+  */
+ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
+               long timeout)
+ {
+       tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+       tty_wait_until_sent(tty, timeout);
+       tty_lock();
+ }
  
  /*
   * wait_event_interruptible_tty -- wait for a condition with the tty lock held