]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge tag 'tty-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Oct 2014 10:52:11 +0000 (06:52 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Oct 2014 10:52:11 +0000 (06:52 -0400)
Pull tty/serial driver updates from Greg KH:
 "Here's the big tty/serial driver patchset for 3.18-rc1.

  Lots of little things in here, some good work from Peter Hurley on the
  tty core, and in lots of drivers.  There are also lots of other driver
  updates in here as well, full details in the changelogs.

  All have been in the linux-next tree for a while"

* tag 'tty-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (99 commits)
  Revert "serial/core: Initialize the console pm state"
  tty: serial: 8250: use 32bit variable for rpm_tx_active
  tty: serial: msm: Add earlycon support
  serial/core: Initialize the console pm state
  serial: asc: Conditionally use readl_relaxed (COMPILE_TEST)
  serial: of-serial: add PM suspend/resume support
  m68k: AMIGA_BUILTIN_SERIAL should depend on TTY
  asm/uapi: Add definition of TIOC[SG]RS485
  tty/metag_da: Add console_poll module parameter
  serial: 8250_pci: remove rts_n override from Baytrail quirk
  serial: cadence: Add generic earlycon support
  serial: imx: change the wait even to interruptiable
  serial: imx: terminate the RX DMA when the UART is suspending
  serial: imx: fix throttle/unthrottle callbacks for hardware assisted flow control
  serial: 8250: Add Quark X1000 to 8250_pci.c
  tty: omap-serial: pull out calculation from baud_is_mode16
  tty: omap-serial: fix division by zero
  xen_hvc: no reason to write the type key on xenstore
  tty: serial: 8250_core: remove UART_IER_RDI in serial8250_stop_rx()
  tty: serial: 8250_core: use the ->line argument as a hint in serial8250_find_match_or_unused()
  ...

1  2 
Documentation/kernel-parameters.txt
drivers/staging/dgnc/dgnc_driver.c
drivers/tty/serial/8250/8250_core.c

index 1edd5fdc629d29d4b9ddbf650a86f285a457f71b,67e93f139b574590e3fd9330cd6047ab2b066269..d9a452e8fb9b3bb1f34d89ddaa87cb8dd90b04bd
@@@ -921,6 -921,12 +921,12 @@@ bytes respectively. Such letter suffixe
  
        earlycon=       [KNL] Output early console device and options.
  
+               cdns,<addr>
+                       Start an early, polled-mode console on a cadence serial
+                       port at the specified address. The cadence serial port
+                       must already be setup and configured. Options are not
+                       yet supported.
                uart[8250],io,<addr>[,options]
                uart[8250],mmio,<addr>[,options]
                uart[8250],mmio32,<addr>[,options]
                        must already be setup and configured. Options are not
                        yet supported.
  
+               msm_serial,<addr>
+                       Start an early, polled-mode console on an msm serial
+                       port at the specified address. The serial port
+                       must already be setup and configured. Options are not
+                       yet supported.
+               msm_serial_dm,<addr>
+                       Start an early, polled-mode console on an msm serial
+                       dm port at the specified address. The serial port
+                       must already be setup and configured. Options are not
+                       yet supported.
                smh     Use ARM semihosting calls for early console.
  
        earlyprintk=    [X86,SH,BLACKFIN,ARM,M68k]
                                        READ_DISC_INFO command);
                                e = NO_READ_CAPACITY_16 (don't use
                                        READ_CAPACITY_16 command);
 +                              f = NO_REPORT_OPCODES (don't use report opcodes
 +                                      command, uas only);
                                h = CAPACITY_HEURISTICS (decrease the
                                        reported device capacity by one
                                        sector if the number is odd);
                                        bogus residue values);
                                s = SINGLE_LUN (the device has only one
                                        Logical Unit);
 +                              t = NO_ATA_1X (don't allow ATA(12) and ATA(16)
 +                                      commands, uas only);
                                u = IGNORE_UAS (don't bind to the uas driver);
                                w = NO_WP_DETECT (don't test whether the
                                        medium is write-protected).
index 29cc2e4ba93513bdfc8869e568cc52dccb90f0d8,ad07cc6981472f2434b11a224f876591a165ead5..21546659ff07549034e248597364386a33df32be
@@@ -57,7 -57,7 +57,7 @@@ MODULE_SUPPORTED_DEVICE("dgnc")
   */
  PARM_INT(debug,               0x00,           0644,   "Driver debugging level");
  PARM_INT(rawreadok,   1,              0644,   "Bypass flip buffers on input");
 -PARM_INT(trcbuf_size, 0x100000,       0644,   "Debugging trace buffer size.");
 +PARM_INT(trcbuf_size, 0x100000,       0644,   "Debugging trace buffer size.");
  
  /**************************************************************************
   *
@@@ -70,15 -70,26 +70,15 @@@ static void                dgnc_init_globals(void)
  static int            dgnc_found_board(struct pci_dev *pdev, int id);
  static void           dgnc_cleanup_board(struct dgnc_board *brd);
  static void           dgnc_poll_handler(ulong dummy);
 -static int            dgnc_init_pci(void);
  static int            dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 -static void           dgnc_remove_one(struct pci_dev *dev);
 -static int            dgnc_probe1(struct pci_dev *pdev, int card_type);
  static void           dgnc_do_remap(struct dgnc_board *brd);
  
 -/* Driver load/unload functions */
 -int           dgnc_init_module(void);
 -void          dgnc_cleanup_module(void);
 -
 -module_init(dgnc_init_module);
 -module_exit(dgnc_cleanup_module);
 -
 -
  /*
   * File operations permitted on Control/Management major.
   */
  static const struct file_operations dgnc_BoardFops = {
        .owner          =       THIS_MODULE,
 -      .unlocked_ioctl =       dgnc_mgmt_ioctl,
 +      .unlocked_ioctl =       dgnc_mgmt_ioctl,
        .open           =       dgnc_mgmt_open,
        .release        =       dgnc_mgmt_close
  };
  uint                  dgnc_NumBoards;
  struct dgnc_board             *dgnc_Board[MAXBOARDS];
  DEFINE_SPINLOCK(dgnc_global_lock);
 -int                   dgnc_driver_state = DRIVER_INITIALIZED;
 -ulong                 dgnc_poll_counter;
  uint                  dgnc_Major;
  int                   dgnc_poll_tick = 20;    /* Poll interval - 20 ms */
  
  /*
   * Static vars.
   */
 -static uint           dgnc_Major_Control_Registered = FALSE;
 -static uint           dgnc_driver_start = FALSE;
 -
  static struct class *dgnc_class;
  
  /*
   * Poller stuff
   */
 -static                        DEFINE_SPINLOCK(dgnc_poll_lock);        /* Poll scheduling lock */
 +static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
  static ulong          dgnc_poll_time;                         /* Time of next poll */
  static uint           dgnc_poll_stop;                         /* Used to tell poller to stop */
  static struct timer_list dgnc_poll_timer;
@@@ -112,25 -128,12 +112,12 @@@ static struct pci_device_id dgnc_pci_tb
        {       DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,   1 },
        {       DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,       2 },
        {       DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,   3 },
-       {       DIGI_VID, PCI_DEVICE_NEO_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,           4 },
-       {       DIGI_VID, PCI_DEVICE_NEO_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,           5 },
-       {       DIGI_VID, PCI_DEVICE_NEO_2DB9_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,        6 },
-       {       DIGI_VID, PCI_DEVICE_NEO_2DB9PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,     7 },
-       {       DIGI_VID, PCI_DEVICE_NEO_2RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,       8 },
-       {       DIGI_VID, PCI_DEVICE_NEO_2RJ45PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,    9 },
-       {       DIGI_VID, PCI_DEVICE_NEO_1_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,       10 },
-       {       DIGI_VID, PCI_DEVICE_NEO_1_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,   11 },
-       {       DIGI_VID, PCI_DEVICE_NEO_2_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,   12 },
-       {       DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,    13 },
-       {       DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,   14 },
-       {       DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,       15 },
-       {       DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,       16 },
        {0,}                                            /* 0 terminated list. */
  };
  MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
  
  struct board_id {
 -      uchar *name;
 +      unsigned char *name;
        uint maxports;
        unsigned int is_pci_express;
  };
@@@ -160,6 -163,7 +147,6 @@@ static struct pci_driver dgnc_driver = 
        .name           = "dgnc",
        .probe          = dgnc_init_one,
        .id_table       = dgnc_pci_tbl,
 -      .remove         = dgnc_remove_one,
  };
  
  
@@@ -169,6 -173,12 +156,6 @@@ char *dgnc_state_text[] = 
        "Board READY",
  };
  
 -char *dgnc_driver_state_text[] = {
 -      "Driver Initialized",
 -      "Driver Ready."
 -};
 -
 -
  
  /************************************************************************
   *
   *
   ************************************************************************/
  
 +/*
 + * dgnc_cleanup_module()
 + *
 + * Module unload.  This is where it all ends.
 + */
 +static void dgnc_cleanup_module(void)
 +{
 +      int i;
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&dgnc_poll_lock, flags);
 +      dgnc_poll_stop = 1;
 +      spin_unlock_irqrestore(&dgnc_poll_lock, flags);
 +
 +      /* Turn off poller right away. */
 +      del_timer_sync(&dgnc_poll_timer);
 +
 +      dgnc_remove_driver_sysfiles(&dgnc_driver);
 +
 +      device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
 +      class_destroy(dgnc_class);
 +      unregister_chrdev(dgnc_Major, "dgnc");
 +
 +      for (i = 0; i < dgnc_NumBoards; ++i) {
 +              dgnc_remove_ports_sysfiles(dgnc_Board[i]);
 +              dgnc_tty_uninit(dgnc_Board[i]);
 +              dgnc_cleanup_board(dgnc_Board[i]);
 +      }
 +
 +      dgnc_tty_post_uninit();
 +
 +      if (dgnc_NumBoards)
 +              pci_unregister_driver(&dgnc_driver);
 +}
  
  /*
   * init_module()
   *
   * Module load.  This is where it all starts.
   */
 -int dgnc_init_module(void)
 +static int __init dgnc_init_module(void)
  {
        int rc = 0;
  
        /*
         * Find and configure all the cards
         */
 -      rc = dgnc_init_pci();
 +      rc = pci_register_driver(&dgnc_driver);
  
        /*
         * If something went wrong in the scan, bail out of driver.
                dgnc_create_driver_sysfiles(&dgnc_driver);
        }
  
 -      DPR_INIT(("Finished init_module. Returning %d\n", rc));
        return rc;
  }
  
 +module_init(dgnc_init_module);
 +module_exit(dgnc_cleanup_module);
  
  /*
   * Start of driver.
@@@ -264,54 -239,77 +251,54 @@@ static int dgnc_start(void
        int rc = 0;
        unsigned long flags;
  
 -      if (dgnc_driver_start == FALSE) {
 -
 -              dgnc_driver_start = TRUE;
 -
 -              /* make sure that the globals are init'd before we do anything else */
 -              dgnc_init_globals();
 +      /* make sure that the globals are init'd before we do anything else */
 +      dgnc_init_globals();
  
 -              dgnc_NumBoards = 0;
 +      APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
  
 -              APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
 -
 -              /*
 -               * Register our base character device into the kernel.
 -               * This allows the download daemon to connect to the downld device
 -               * before any of the boards are init'ed.
 -               */
 -              if (!dgnc_Major_Control_Registered) {
 -                      /*
 -                       * Register management/dpa devices
 -                       */
 -                      rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
 -                      if (rc <= 0) {
 -                              APR(("Can't register dgnc driver device (%d)\n", rc));
 -                              rc = -ENXIO;
 -                              return rc;
 -                      }
 -                      dgnc_Major = rc;
 -
 -                      dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
 -                      device_create(dgnc_class, NULL,
 -                              MKDEV(dgnc_Major, 0),
 -                              NULL, "dgnc_mgmt");
 -                      dgnc_Major_Control_Registered = TRUE;
 -              }
 +      /*
 +       * Register our base character device into the kernel.
 +       * This allows the download daemon to connect to the downld device
 +       * before any of the boards are init'ed.
 +       *
 +       * Register management/dpa devices
 +       */
 +      rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
 +      if (rc <= 0) {
 +              APR(("Can't register dgnc driver device (%d)\n", rc));
 +              return -ENXIO;
 +      }
 +      dgnc_Major = rc;
  
 -              /*
 -               * Init any global tty stuff.
 -               */
 -              rc = dgnc_tty_preinit();
 +      dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
 +      device_create(dgnc_class, NULL,
 +              MKDEV(dgnc_Major, 0),
 +              NULL, "dgnc_mgmt");
  
 -              if (rc < 0) {
 -                      APR(("tty preinit - not enough memory (%d)\n", rc));
 -                      return rc;
 -              }
 +      /*
 +       * Init any global tty stuff.
 +       */
 +      rc = dgnc_tty_preinit();
  
 -              /* Start the poller */
 -              DGNC_LOCK(dgnc_poll_lock, flags);
 -              init_timer(&dgnc_poll_timer);
 -              dgnc_poll_timer.function = dgnc_poll_handler;
 -              dgnc_poll_timer.data = 0;
 -              dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
 -              dgnc_poll_timer.expires = dgnc_poll_time;
 -              DGNC_UNLOCK(dgnc_poll_lock, flags);
 +      if (rc < 0) {
 +              APR(("tty preinit - not enough memory (%d)\n", rc));
 +              return rc;
 +      }
  
 -              add_timer(&dgnc_poll_timer);
 +      /* Start the poller */
 +      spin_lock_irqsave(&dgnc_poll_lock, flags);
 +      init_timer(&dgnc_poll_timer);
 +      dgnc_poll_timer.function = dgnc_poll_handler;
 +      dgnc_poll_timer.data = 0;
 +      dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
 +      dgnc_poll_timer.expires = dgnc_poll_time;
 +      spin_unlock_irqrestore(&dgnc_poll_lock, flags);
  
 -              dgnc_driver_state = DRIVER_READY;
 -      }
 +      add_timer(&dgnc_poll_timer);
  
        return rc;
  }
  
 -/*
 - * Register pci driver, and return how many boards we have.
 - */
 -static int dgnc_init_pci(void)
 -{
 -      return pci_register_driver(&dgnc_driver);
 -}
 -
 -
  /* returns count (>= 0), or negative on error */
  static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
        if (rc < 0) {
                rc = -EIO;
        } else {
 -              rc = dgnc_probe1(pdev, ent->driver_data);
 -              if (rc == 0) {
 +              rc = dgnc_found_board(pdev, ent->driver_data);
 +              if (rc == 0)
                        dgnc_NumBoards++;
 -                      DPR_INIT(("Incrementing numboards to %d\n", dgnc_NumBoards));
 -              }
        }
        return rc;
  }
  
 -static int dgnc_probe1(struct pci_dev *pdev, int card_type)
 -{
 -      return dgnc_found_board(pdev, card_type);
 -}
 -
 -
 -static void dgnc_remove_one(struct pci_dev *dev)
 -{
 -      /* Do Nothing */
 -}
 -
 -/*
 - * dgnc_cleanup_module()
 - *
 - * Module unload.  This is where it all ends.
 - */
 -void dgnc_cleanup_module(void)
 -{
 -      int i;
 -      ulong lock_flags;
 -
 -      DGNC_LOCK(dgnc_poll_lock, lock_flags);
 -      dgnc_poll_stop = 1;
 -      DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
 -
 -      /* Turn off poller right away. */
 -      del_timer_sync(&dgnc_poll_timer);
 -
 -      dgnc_remove_driver_sysfiles(&dgnc_driver);
 -
 -      if (dgnc_Major_Control_Registered) {
 -              device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
 -              class_destroy(dgnc_class);
 -              unregister_chrdev(dgnc_Major, "dgnc");
 -      }
 -
 -      for (i = 0; i < dgnc_NumBoards; ++i) {
 -              dgnc_remove_ports_sysfiles(dgnc_Board[i]);
 -              dgnc_tty_uninit(dgnc_Board[i]);
 -              dgnc_cleanup_board(dgnc_Board[i]);
 -      }
 -
 -      dgnc_tty_post_uninit();
 -
 -      if (dgnc_NumBoards)
 -              pci_unregister_driver(&dgnc_driver);
 -}
 -
 -
  /*
   * dgnc_cleanup_board()
   *
@@@ -369,12 -418,12 +356,12 @@@ static void dgnc_cleanup_board(struct d
        if (brd->msgbuf_head) {
                unsigned long flags;
  
 -              DGNC_LOCK(dgnc_global_lock, flags);
 +              spin_lock_irqsave(&dgnc_global_lock, flags);
                brd->msgbuf = NULL;
                printk("%s", brd->msgbuf_head);
                kfree(brd->msgbuf_head);
                brd->msgbuf_head = NULL;
 -              DGNC_UNLOCK(dgnc_global_lock, flags);
 +              spin_unlock_irqrestore(&dgnc_global_lock, flags);
        }
  
        /* Free all allocated channels structs */
@@@ -410,16 -459,14 +397,16 @@@ static int dgnc_found_board(struct pci_
        unsigned long flags;
  
        /* get the board structure and prep it */
 -      brd = dgnc_Board[dgnc_NumBoards] =
 -              kzalloc(sizeof(*brd), GFP_KERNEL);
 +      dgnc_Board[dgnc_NumBoards] = kzalloc(sizeof(*brd), GFP_KERNEL);
 +      brd = dgnc_Board[dgnc_NumBoards];
 +
        if (!brd)
                return -ENOMEM;
  
        /* make a temporary message buffer for the boot messages */
 -      brd->msgbuf = brd->msgbuf_head =
 -              kzalloc(sizeof(u8) * 8192, GFP_KERNEL);
 +      brd->msgbuf_head = kzalloc(sizeof(u8) * 8192, GFP_KERNEL);
 +      brd->msgbuf = brd->msgbuf_head;
 +
        if (!brd->msgbuf) {
                kfree(brd);
                return -ENOMEM;
        brd->dpastatus = BD_NOFEP;
        init_waitqueue_head(&brd->state_wait);
  
 -      DGNC_SPINLOCK_INIT(brd->bd_lock);
 -      DGNC_SPINLOCK_INIT(brd->bd_intr_lock);
 +      spin_lock_init(&brd->bd_lock);
 +      spin_lock_init(&brd->bd_intr_lock);
  
        brd->state              = BOARD_FOUND;
  
  
                brd->dpatype = T_CLASSIC | T_PCIBUS;
  
 -              DPR_INIT(("dgnc_found_board - Classic.\n"));
 -
                /*
                 * For PCI ClassicBoards
                 * PCI Local Address (i.e. "resource" number) space
                else
                        brd->dpatype = T_NEO | T_PCIBUS;
  
 -              DPR_INIT(("dgnc_found_board - NEO.\n"));
 -
                /* get the PCI Base Address Registers */
                brd->membase     = pci_resource_start(pdev, 0);
                brd->membase_end = pci_resource_end(pdev, 0);
        /* init our poll helper tasklet */
        tasklet_init(&brd->helper_tasklet, brd->bd_ops->tasklet, (unsigned long) brd);
  
 -      DPR_INIT(("dgnc_scan(%d) - printing out the msgbuf\n", i));
 -      DGNC_LOCK(dgnc_global_lock, flags);
 +      spin_lock_irqsave(&dgnc_global_lock, flags);
        brd->msgbuf = NULL;
        printk("%s", brd->msgbuf_head);
        kfree(brd->msgbuf_head);
        brd->msgbuf_head = NULL;
 -      DGNC_UNLOCK(dgnc_global_lock, flags);
 +      spin_unlock_irqrestore(&dgnc_global_lock, flags);
  
        /*
         * allocate flip buffer for board.
@@@ -643,9 -695,13 +630,9 @@@ static int dgnc_finalize_board_init(str
  {
        int rc = 0;
  
 -      DPR_INIT(("dgnc_finalize_board_init() - start\n"));
 -
        if (!brd || brd->magic != DGNC_BOARD_MAGIC)
                return -ENODEV;
  
 -      DPR_INIT(("dgnc_finalize_board_init() - start #2\n"));
 -
        if (brd->irq) {
                rc = request_irq(brd->irq, brd->bd_ops->intr,
                                 IRQF_SHARED, "DGNC", brd);
                        brd->state = BOARD_FAILED;
                        brd->dpastatus = BD_NOFEP;
                        rc = -ENODEV;
 -              } else {
 -                      DPR_INIT(("Requested and received usage of IRQ %d\n",
 -                                brd->irq));
                }
        }
        return rc;
@@@ -671,6 -730,8 +658,6 @@@ static void dgnc_do_remap(struct dgnc_b
                return;
  
        brd->re_map_membase = ioremap(brd->membase, 0x1000);
 -
 -      DPR_INIT(("remapped mem: 0x%p\n", brd->re_map_membase));
  }
  
  
  static void dgnc_poll_handler(ulong dummy)
  {
        struct dgnc_board *brd;
 -      unsigned long lock_flags;
 +      unsigned long flags;
        int i;
        unsigned long new_time;
  
 -      dgnc_poll_counter++;
 -
 -      /*
 -       * Do not start the board state machine until
 -       * driver tells us its up and running, and has
 -       * everything it needs.
 -       */
 -      if (dgnc_driver_state != DRIVER_READY)
 -              goto schedule_poller;
 -
        /* Go thru each board, kicking off a tasklet for each if needed */
        for (i = 0; i < dgnc_NumBoards; i++) {
                brd = dgnc_Board[i];
  
 -              DGNC_LOCK(brd->bd_lock, lock_flags);
 +              spin_lock_irqsave(&brd->bd_lock, flags);
  
                /* If board is in a failed state, don't bother scheduling a tasklet */
                if (brd->state == BOARD_FAILED) {
 -                      DGNC_UNLOCK(brd->bd_lock, lock_flags);
 +                      spin_unlock_irqrestore(&brd->bd_lock, flags);
                        continue;
                }
  
                /* Schedule a poll helper task */
                tasklet_schedule(&brd->helper_tasklet);
  
 -              DGNC_UNLOCK(brd->bd_lock, lock_flags);
 +              spin_unlock_irqrestore(&brd->bd_lock, flags);
        }
  
 -schedule_poller:
 -
        /*
         * Schedule ourself back at the nominal wakeup interval.
         */
 -      DGNC_LOCK(dgnc_poll_lock, lock_flags);
 +      spin_lock_irqsave(&dgnc_poll_lock, flags);
        dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
  
        new_time = dgnc_poll_time - jiffies;
        dgnc_poll_timer.function = dgnc_poll_handler;
        dgnc_poll_timer.data = 0;
        dgnc_poll_timer.expires = dgnc_poll_time;
 -      DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
 +      spin_unlock_irqrestore(&dgnc_poll_lock, flags);
  
        if (!dgnc_poll_stop)
                add_timer(&dgnc_poll_timer);
@@@ -760,7 -833,6 +747,7 @@@ static void dgnc_init_globals(void
        dgnc_rawreadok          = rawreadok;
        dgnc_trcbuf_size        = trcbuf_size;
        dgnc_debug              = debug;
 +      dgnc_NumBoards          = 0;
  
        for (i = 0; i < MAXBOARDS; i++)
                dgnc_Board[i] = NULL;
        init_timer(&dgnc_poll_timer);
  }
  
 -
 -/************************************************************************
 - *
 - * Utility functions
 - *
 - ************************************************************************/
 -
 -/*
 - * dgnc_ms_sleep()
 - *
 - * Put the driver to sleep for x ms's
 - *
 - * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
 - */
 -int dgnc_ms_sleep(ulong ms)
 -{
 -      current->state = TASK_INTERRUPTIBLE;
 -      schedule_timeout((ms * HZ) / 1000);
 -      return signal_pending(current);
 -}
 -
 -
 -
 -/*
 - *      dgnc_ioctl_name() : Returns a text version of each ioctl value.
 - */
 -char *dgnc_ioctl_name(int cmd)
 -{
 -      switch (cmd) {
 -
 -      case TCGETA:            return "TCGETA";
 -      case TCGETS:            return "TCGETS";
 -      case TCSETA:            return "TCSETA";
 -      case TCSETS:            return "TCSETS";
 -      case TCSETAW:           return "TCSETAW";
 -      case TCSETSW:           return "TCSETSW";
 -      case TCSETAF:           return "TCSETAF";
 -      case TCSETSF:           return "TCSETSF";
 -      case TCSBRK:            return "TCSBRK";
 -      case TCXONC:            return "TCXONC";
 -      case TCFLSH:            return "TCFLSH";
 -      case TIOCGSID:          return "TIOCGSID";
 -
 -      case TIOCGETD:          return "TIOCGETD";
 -      case TIOCSETD:          return "TIOCSETD";
 -      case TIOCGWINSZ:        return "TIOCGWINSZ";
 -      case TIOCSWINSZ:        return "TIOCSWINSZ";
 -
 -      case TIOCMGET:          return "TIOCMGET";
 -      case TIOCMSET:          return "TIOCMSET";
 -      case TIOCMBIS:          return "TIOCMBIS";
 -      case TIOCMBIC:          return "TIOCMBIC";
 -
 -      /* from digi.h */
 -      case DIGI_SETA:         return "DIGI_SETA";
 -      case DIGI_SETAW:        return "DIGI_SETAW";
 -      case DIGI_SETAF:        return "DIGI_SETAF";
 -      case DIGI_SETFLOW:      return "DIGI_SETFLOW";
 -      case DIGI_SETAFLOW:     return "DIGI_SETAFLOW";
 -      case DIGI_GETFLOW:      return "DIGI_GETFLOW";
 -      case DIGI_GETAFLOW:     return "DIGI_GETAFLOW";
 -      case DIGI_GETA:         return "DIGI_GETA";
 -      case DIGI_GEDELAY:      return "DIGI_GEDELAY";
 -      case DIGI_SEDELAY:      return "DIGI_SEDELAY";
 -      case DIGI_GETCUSTOMBAUD: return "DIGI_GETCUSTOMBAUD";
 -      case DIGI_SETCUSTOMBAUD: return "DIGI_SETCUSTOMBAUD";
 -      case TIOCMODG:          return "TIOCMODG";
 -      case TIOCMODS:          return "TIOCMODS";
 -      case TIOCSDTR:          return "TIOCSDTR";
 -      case TIOCCDTR:          return "TIOCCDTR";
 -
 -      default:                return "unknown";
 -      }
 -}
index bd672948f2f15fb6e18ce86540ba7fffa12141d4,139f3d2b8aa991f3af5ac675e8f757962c960cb6..ca5cfdc1459a61ca407f9888cbe20d50e33b71b3
@@@ -37,6 -37,8 +37,8 @@@
  #include <linux/nmi.h>
  #include <linux/mutex.h>
  #include <linux/slab.h>
+ #include <linux/uaccess.h>
+ #include <linux/pm_runtime.h>
  #ifdef CONFIG_SPARC
  #include <linux/sunserialcore.h>
  #endif
@@@ -539,6 -541,53 +541,53 @@@ void serial8250_clear_and_reinit_fifos(
  }
  EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
  
+ static void serial8250_rpm_get(struct uart_8250_port *p)
+ {
+       if (!(p->capabilities & UART_CAP_RPM))
+               return;
+       pm_runtime_get_sync(p->port.dev);
+ }
+ static void serial8250_rpm_put(struct uart_8250_port *p)
+ {
+       if (!(p->capabilities & UART_CAP_RPM))
+               return;
+       pm_runtime_mark_last_busy(p->port.dev);
+       pm_runtime_put_autosuspend(p->port.dev);
+ }
+ /*
+  * This two wrapper ensure, that enable_runtime_pm_tx() can be called more than
+  * once and disable_runtime_pm_tx() will still disable RPM because the fifo is
+  * empty and the HW can idle again.
+  */
+ static void serial8250_rpm_get_tx(struct uart_8250_port *p)
+ {
+       unsigned char rpm_active;
+       if (!(p->capabilities & UART_CAP_RPM))
+               return;
+       rpm_active = xchg(&p->rpm_tx_active, 1);
+       if (rpm_active)
+               return;
+       pm_runtime_get_sync(p->port.dev);
+ }
+ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
+ {
+       unsigned char rpm_active;
+       if (!(p->capabilities & UART_CAP_RPM))
+               return;
+       rpm_active = xchg(&p->rpm_tx_active, 0);
+       if (!rpm_active)
+               return;
+       pm_runtime_mark_last_busy(p->port.dev);
+       pm_runtime_put_autosuspend(p->port.dev);
+ }
  /*
   * IER sleep support.  UARTs which have EFRs need the "extended
   * capability" bit enabled.  Note that on XR16C850s, we need to
@@@ -553,10 -602,11 +602,11 @@@ static void serial8250_set_sleep(struc
         * offset but the UART channel may only write to the corresponding
         * bit.
         */
+       serial8250_rpm_get(p);
        if ((p->port.type == PORT_XR17V35X) ||
           (p->port.type == PORT_XR17D15X)) {
                serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
-               return;
+               goto out;
        }
  
        if (p->capabilities & UART_CAP_SLEEP) {
                        serial_out(p, UART_LCR, 0);
                }
        }
+ out:
+       serial8250_rpm_put(p);
  }
  
  #ifdef CONFIG_SERIAL_8250_RSA
@@@ -1272,6 -1324,7 +1324,7 @@@ static inline void __stop_tx(struct uar
        if (p->ier & UART_IER_THRI) {
                p->ier &= ~UART_IER_THRI;
                serial_out(p, UART_IER, p->ier);
+               serial8250_rpm_put_tx(p);
        }
  }
  
@@@ -1279,6 -1332,7 +1332,7 @@@ static void serial8250_stop_tx(struct u
  {
        struct uart_8250_port *up = up_to_u8250p(port);
  
+       serial8250_rpm_get(up);
        __stop_tx(up);
  
        /*
                up->acr |= UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
        }
+       serial8250_rpm_put(up);
  }
  
  static void serial8250_start_tx(struct uart_port *port)
  {
        struct uart_8250_port *up = up_to_u8250p(port);
  
+       serial8250_rpm_get_tx(up);
        if (up->dma && !serial8250_tx_dma(up)) {
                return;
        } else if (!(up->ier & UART_IER_THRI)) {
        }
  }
  
+ static void serial8250_throttle(struct uart_port *port)
+ {
+       port->throttle(port);
+ }
+ static void serial8250_unthrottle(struct uart_port *port)
+ {
+       port->unthrottle(port);
+ }
  static void serial8250_stop_rx(struct uart_port *port)
  {
        struct uart_8250_port *up = up_to_u8250p(port);
  
-       up->ier &= ~UART_IER_RLSI;
+       serial8250_rpm_get(up);
+       up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
        up->port.read_status_mask &= ~UART_LSR_DR;
        serial_port_out(port, UART_IER, up->ier);
+       serial8250_rpm_put(up);
  }
  
  static void serial8250_enable_ms(struct uart_port *port)
                return;
  
        up->ier |= UART_IER_MSI;
+       serial8250_rpm_get(up);
        serial_port_out(port, UART_IER, up->ier);
+       serial8250_rpm_put(up);
  }
  
  /*
@@@ -1458,11 -1531,17 +1531,17 @@@ void serial8250_tx_chars(struct uart_82
  
        DEBUG_INTR("THRE...");
  
-       if (uart_circ_empty(xmit))
+       /*
+        * With RPM enabled, we have to wait once the FIFO is empty before the
+        * HW can go idle. So we get here once again with empty FIFO and disable
+        * the interrupt and RPM in __stop_tx()
+        */
+       if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
                __stop_tx(up);
  }
  EXPORT_SYMBOL_GPL(serial8250_tx_chars);
  
+ /* Caller holds uart port lock */
  unsigned int serial8250_modem_status(struct uart_8250_port *up)
  {
        struct uart_port *port = &up->port;
@@@ -1525,9 -1604,17 +1604,17 @@@ EXPORT_SYMBOL_GPL(serial8250_handle_irq
  
  static int serial8250_default_handle_irq(struct uart_port *port)
  {
-       unsigned int iir = serial_port_in(port, UART_IIR);
+       struct uart_8250_port *up = up_to_u8250p(port);
+       unsigned int iir;
+       int ret;
+       serial8250_rpm_get(up);
  
-       return serial8250_handle_irq(port, iir);
+       iir = serial_port_in(port, UART_IIR);
+       ret = serial8250_handle_irq(port, iir);
+       serial8250_rpm_put(up);
+       return ret;
  }
  
  /*
@@@ -1784,11 -1871,15 +1871,15 @@@ static unsigned int serial8250_tx_empty
        unsigned long flags;
        unsigned int lsr;
  
+       serial8250_rpm_get(up);
        spin_lock_irqsave(&port->lock, flags);
        lsr = serial_port_in(port, UART_LSR);
        up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
        spin_unlock_irqrestore(&port->lock, flags);
  
+       serial8250_rpm_put(up);
        return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
  }
  
@@@ -1798,7 -1889,9 +1889,9 @@@ static unsigned int serial8250_get_mctr
        unsigned int status;
        unsigned int ret;
  
+       serial8250_rpm_get(up);
        status = serial8250_modem_status(up);
+       serial8250_rpm_put(up);
  
        ret = 0;
        if (status & UART_MSR_DCD)
@@@ -1838,6 -1931,7 +1931,7 @@@ static void serial8250_break_ctl(struc
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned long flags;
  
+       serial8250_rpm_get(up);
        spin_lock_irqsave(&port->lock, flags);
        if (break_state == -1)
                up->lcr |= UART_LCR_SBC;
                up->lcr &= ~UART_LCR_SBC;
        serial_port_out(port, UART_LCR, up->lcr);
        spin_unlock_irqrestore(&port->lock, flags);
+       serial8250_rpm_put(up);
  }
  
  /*
@@@ -1889,12 -1984,23 +1984,23 @@@ static void wait_for_xmitr(struct uart_
  
  static int serial8250_get_poll_char(struct uart_port *port)
  {
-       unsigned char lsr = serial_port_in(port, UART_LSR);
+       struct uart_8250_port *up = up_to_u8250p(port);
+       unsigned char lsr;
+       int status;
+       serial8250_rpm_get(up);
+       lsr = serial_port_in(port, UART_LSR);
  
-       if (!(lsr & UART_LSR_DR))
-               return NO_POLL_CHAR;
+       if (!(lsr & UART_LSR_DR)) {
+               status = NO_POLL_CHAR;
+               goto out;
+       }
  
-       return serial_port_in(port, UART_RX);
+       status = serial_port_in(port, UART_RX);
+ out:
+       serial8250_rpm_put(up);
+       return status;
  }
  
  
@@@ -1904,6 -2010,7 +2010,7 @@@ static void serial8250_put_poll_char(st
        unsigned int ier;
        struct uart_8250_port *up = up_to_u8250p(port);
  
+       serial8250_rpm_get(up);
        /*
         *      First save the IER then disable the interrupts
         */
         */
        wait_for_xmitr(up, BOTH_EMPTY);
        serial_port_out(port, UART_IER, ier);
+       serial8250_rpm_put(up);
  }
  
  #endif /* CONFIG_CONSOLE_POLL */
  
static int serial8250_startup(struct uart_port *port)
int serial8250_do_startup(struct uart_port *port)
  {
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned long flags;
        if (port->iotype != up->cur_iotype)
                set_io_from_upio(port);
  
+       serial8250_rpm_get(up);
        if (port->type == PORT_16C950) {
                /* Wake up and initialize UART */
                up->acr = 0;
         */
        enable_rsa(up);
  #endif
        /*
         * Clear the FIFO buffers and disable them.
         * (they will be reenabled in set_termios())
        /*
         * Clear the interrupt registers.
         */
-       serial_port_in(port, UART_LSR);
-       serial_port_in(port, UART_RX);
+       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+               serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
  
            (serial_port_in(port, UART_LSR) == 0xff)) {
                printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
                                   serial_index(port));
-               return -ENODEV;
+               retval = -ENODEV;
+               goto out;
        }
  
        /*
        } else {
                retval = serial_link_irq_chain(up);
                if (retval)
-                       return retval;
+                       goto out;
        }
  
        /*
@@@ -2141,8 -2250,8 +2250,8 @@@ dont_test_tx_en
         * saved flags to avoid getting false values from polling
         * routines or the previous session.
         */
-       serial_port_in(port, UART_LSR);
-       serial_port_in(port, UART_RX);
+       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+               serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
        up->lsr_saved_flags = 0;
                outb_p(0x80, icp);
                inb_p(icp);
        }
+       retval = 0;
+ out:
+       serial8250_rpm_put(up);
+       return retval;
+ }
+ EXPORT_SYMBOL_GPL(serial8250_do_startup);
  
-       return 0;
+ static int serial8250_startup(struct uart_port *port)
+ {
+       if (port->startup)
+               return port->startup(port);
+       return serial8250_do_startup(port);
  }
  
static void serial8250_shutdown(struct uart_port *port)
void serial8250_do_shutdown(struct uart_port *port)
  {
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned long flags;
  
+       serial8250_rpm_get(up);
        /*
         * Disable interrupts from this port
         */
         * Read data port to reset things, and then unlink from
         * the IRQ chain.
         */
-       serial_port_in(port, UART_RX);
+       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+               serial_port_in(port, UART_RX);
+       serial8250_rpm_put(up);
  
        del_timer_sync(&up->timer);
        up->timer.function = serial8250_timeout;
        if (port->irq)
                serial_unlink_irq_chain(up);
  }
+ EXPORT_SYMBOL_GPL(serial8250_do_shutdown);
+ static void serial8250_shutdown(struct uart_port *port)
+ {
+       if (port->shutdown)
+               port->shutdown(port);
+       else
+               serial8250_do_shutdown(port);
+ }
  
  static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
  {
@@@ -2319,11 -2450,9 +2450,9 @@@ serial8250_do_set_termios(struct uart_p
         * the trigger, or the MCR RTS bit is cleared.  In the case where
         * the remote UART is not using CTS auto flow control, we must
         * have sufficient FIFO entries for the latency of the remote
-        * UART to respond.  IOW, at least 32 bytes of FIFO. Also enable
-        * AFE if hw flow control is supported
+        * UART to respond.  IOW, at least 32 bytes of FIFO.
         */
-       if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
-           (port->flags & UPF_HARD_FLOW)) {
+       if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
                up->mcr &= ~UART_MCR_AFE;
                if (termios->c_cflag & CRTSCTS)
                        up->mcr |= UART_MCR_AFE;
         * Ok, we're now changing the port state.  Do it with
         * interrupts disabled.
         */
+       serial8250_rpm_get(up);
        spin_lock_irqsave(&port->lock, flags);
  
        /*
        }
        serial8250_set_mctrl(port, port->mctrl);
        spin_unlock_irqrestore(&port->lock, flags);
+       serial8250_rpm_put(up);
        /* Don't rewrite B0 */
        if (tty_termios_baud_rate(termios))
                tty_termios_encode_baud_rate(termios, baud, baud);
@@@ -2843,6 -2975,42 +2975,42 @@@ serial8250_verify_port(struct uart_por
        return 0;
  }
  
+ static int serial8250_ioctl(struct uart_port *port, unsigned int cmd,
+                          unsigned long arg)
+ {
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       int ret;
+       struct serial_rs485 rs485_config;
+       if (!up->rs485_config)
+               return -ENOIOCTLCMD;
+       switch (cmd) {
+       case TIOCSRS485:
+               if (copy_from_user(&rs485_config, (void __user *)arg,
+                                  sizeof(rs485_config)))
+                       return -EFAULT;
+               ret = up->rs485_config(up, &rs485_config);
+               if (ret)
+                       return ret;
+               memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
+               return 0;
+       case TIOCGRS485:
+               if (copy_to_user((void __user *)arg, &up->rs485,
+                                sizeof(up->rs485)))
+                       return -EFAULT;
+               return 0;
+       default:
+               break;
+       }
+       return -ENOIOCTLCMD;
+ }
  static const char *
  serial8250_type(struct uart_port *port)
  {
@@@ -2859,6 -3027,8 +3027,8 @@@ static struct uart_ops serial8250_pops 
        .get_mctrl      = serial8250_get_mctrl,
        .stop_tx        = serial8250_stop_tx,
        .start_tx       = serial8250_start_tx,
+       .throttle       = serial8250_throttle,
+       .unthrottle     = serial8250_unthrottle,
        .stop_rx        = serial8250_stop_rx,
        .enable_ms      = serial8250_enable_ms,
        .break_ctl      = serial8250_break_ctl,
        .request_port   = serial8250_request_port,
        .config_port    = serial8250_config_port,
        .verify_port    = serial8250_verify_port,
+       .ioctl          = serial8250_ioctl,
  #ifdef CONFIG_CONSOLE_POLL
        .poll_get_char = serial8250_get_poll_char,
        .poll_put_char = serial8250_put_poll_char,
  
  static struct uart_8250_port serial8250_ports[UART_NR];
  
+ /**
+  * serial8250_get_port - retrieve struct uart_8250_port
+  * @line: serial line number
+  *
+  * This function retrieves struct uart_8250_port for the specific line.
+  * This struct *must* *not* be used to perform a 8250 or serial core operation
+  * which is not accessible otherwise. Its only purpose is to make the struct
+  * accessible to the runtime-pm callbacks for context suspend/restore.
+  * The lock assumption made here is none because runtime-pm suspend/resume
+  * callbacks should not be invoked if there is any operation performed on the
+  * port.
+  */
+ struct uart_8250_port *serial8250_get_port(int line)
+ {
+       return &serial8250_ports[line];
+ }
+ EXPORT_SYMBOL_GPL(serial8250_get_port);
  static void (*serial8250_isa_config)(int port, struct uart_port *up,
        unsigned short *capabilities);
  
@@@ -3007,6 -3196,8 +3196,8 @@@ serial8250_console_write(struct consol
  
        touch_nmi_watchdog();
  
+       serial8250_rpm_get(up);
        if (port->sysrq || oops_in_progress)
                locked = spin_trylock_irqsave(&port->lock, flags);
        else
  
        if (locked)
                spin_unlock_irqrestore(&port->lock, flags);
+       serial8250_rpm_put(up);
  }
  
  static int __init serial8250_console_setup(struct console *co, char *options)
@@@ -3324,6 -3516,11 +3516,11 @@@ static struct uart_8250_port *serial825
                if (uart_match_port(&serial8250_ports[i].port, port))
                        return &serial8250_ports[i];
  
+       /* try line number first if still available */
+       i = port->line;
+       if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN &&
+                       serial8250_ports[i].port.iobase == 0)
+               return &serial8250_ports[i];
        /*
         * We didn't find a matching entry, so look for the first
         * free entry.  We look for one which hasn't been previously
@@@ -3388,6 -3585,10 +3585,10 @@@ int serial8250_register_8250_port(struc
                uart->port.fifosize     = up->port.fifosize;
                uart->tx_loadsz         = up->tx_loadsz;
                uart->capabilities      = up->capabilities;
+               uart->rs485_config      = up->rs485_config;
+               uart->rs485             = up->rs485;
+               uart->port.throttle     = up->port.throttle;
+               uart->port.unthrottle   = up->port.unthrottle;
  
                /* Take tx_loadsz from fifosize if it wasn't set separately */
                if (uart->port.fifosize && !uart->tx_loadsz)
                /*  Possibly override set_termios call */
                if (up->port.set_termios)
                        uart->port.set_termios = up->port.set_termios;
+               if (up->port.startup)
+                       uart->port.startup = up->port.startup;
+               if (up->port.shutdown)
+                       uart->port.shutdown = up->port.shutdown;
                if (up->port.pm)
                        uart->port.pm = up->port.pm;
                if (up->port.handle_break)
@@@ -3587,7 -3792,7 +3792,7 @@@ static void __used s8250_options(void
  #ifdef CONFIG_SERIAL_8250_RSA
        __module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
                &param_array_ops, .arr = &__param_arr_probe_rsa,
 -              0444, -1);
 +              0444, -1, 0);
  #endif
  }
  #else