kernel - Add support for MosChip PCIe serial com, and console support
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 29 May 2018 02:58:03 +0000 (19:58 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 29 May 2018 03:08:13 +0000 (20:08 -0700)
* Add support for the MosChip PCIe serial com (brand is typically
  'StarTech' 'Natikve PCI Express RS232 serial adapter card with
  16550 UART'.

* Add late console support.  Console operation works the same
  way, set it up in /boot/loader.conf.  Typically:

  sio0.flags=0x00
  sio4.flags=0x30
  sio4.baud=115200
  #set boot_serial="YES" <-- commented out, do not set this

  Note that at the point a late-configured serial port
  wants to become the console, syscons is probably already
  the console, so you have to use flags 0x30 instead of
  0x10 to force it to change the console.

* Note, you do not have to set boot_serial="YES", because it
  won't really help since the adapter isn't accessible to the
  boot loader or to the kernel until the PCIe device probes
  in the middle of the boot sequence.

* The kernel now retests for consoles at the end of its normal
  configuration sequence, which allows the now-available
  sioN devices from PCIe card(s) to become the console.

* Remove syscons sccnterm() code that tried to undo the syscons
  console designation.  This code was never called in the past
  because the system console couldn't actually change once
  selected.  But now it can, and the code completely blows up
  syscons for numerous reasons.  Just leave the console
  designation intact from syscons's point of view (the main
  system will be vectored elsewhere so syscons will simply
  not receive new kernel console reads and writes).

* Add a siocntxwait() call before changing com parameters,
  since we are potentially changing the baud rate here.

* Change how the SIO driver assigns baud rates for the console
  to handle late-console configurations.  Also, allow sio*.baud
  variables in loader.conf to override the default com rate.

* Add entries for com5 and com6 to /etc/remote, and default to
  a more reasonable baud rate of 115200.

etc/remote
sys/dev/misc/syscons/syscons.c
sys/dev/serial/sio/sio.c
sys/kern/tty_cons.c
sys/platform/pc64/x86_64/autoconf.c
sys/platform/vkernel64/x86_64/autoconf.c

index 1f1eb9b..b4e9c5d 100644 (file)
@@ -57,7 +57,11 @@ com1:dv=/dev/cuaa0:br#9600:pa=none:
 com2:dv=/dev/cuaa1:br#9600:pa=none:
 com3:dv=/dev/cuaa2:br#9600:pa=none:
 com4:dv=/dev/cuaa3:br#9600:pa=none:
+com5:dv=/dev/cuaa4:br#115200:pa=none:
+com6:dv=/dev/cuaa5:br#115200:pa=none:
 ucom1:dv=/dev/cuaU0:br#9600:pa=none:
 ucom2:dv=/dev/cuaU1:br#9600:pa=none:
 ucom3:dv=/dev/cuaU2:br#9600:pa=none:
 ucom4:dv=/dev/cuaU3:br#9600:pa=none:
+ucom5:dv=/dev/cuaU4:br#115200:pa=none:
+ucom6:dv=/dev/cuaU5:br#115200:pa=none:
index 101026f..e988a57 100644 (file)
@@ -172,7 +172,9 @@ static kbd_callback_func_t sckbdevent;
 static int scparam(struct tty *tp, struct termios *t);
 static void scstart(struct tty *tp);
 static void scinit(int unit, int flags);
+#if 0
 static void scterm(int unit, int flags);
+#endif
 static void scshutdown(void *arg, int howto);
 static void sc_puts(scr_stat *scp, u_char *buf, int len);
 static u_int scgetc(sc_softc_t *sc, u_int flags);
@@ -1811,9 +1813,21 @@ sccninit_fini(struct consdev *cp)
        cp->cn_dev = cctl_dev;
 }
 
+/*
+ * This is called when the console is switched away from syscons to
+ * a late-configuring device (such as a PCIe serial port).  Since
+ * late-configuring devices basically didn't exist until now, this
+ * routine was never called, and SURPRISE!  It doesn't work... causes
+ * syscons to implode due to all the funny console-not-console structure
+ * selection syscons does.
+ *
+ * Make it a NOP.  Just leave the console designation intact, even
+ * though it is no longer a console.
+ */
 static void
 sccnterm(struct consdev *cp)
 {
+#if 0
     /* we are not the kernel console any more, release everything */
 
     if (sc_console_unit < 0)
@@ -1828,6 +1842,7 @@ sccnterm(struct consdev *cp)
     scterm(sc_console_unit, SC_KERNEL_CONSOLE);
     sc_console_unit = -1;
     sc_console = NULL;
+#endif
 }
 
 /*
@@ -3405,6 +3420,7 @@ scinit(int unit, int flags)
     sc->flags |= SC_INIT_DONE;
 }
 
+#if 0
 static void
 scterm(int unit, int flags)
 {
@@ -3468,6 +3484,7 @@ scterm(int unit, int flags)
     sc->adapter = -1;
     lwkt_reltoken(&tty_token);
 }
+#endif
 
 static void
 scshutdown(void *arg, int howto)
index 0a4c47f..4b423b1 100644 (file)
@@ -170,6 +170,7 @@ static      void    comstop         (struct tty *tp, int rw);
 static timeout_t comwakeup;
 static void    disc_optim      (struct tty     *tp, struct termios *t,
                                     struct com_s *com);
+static void siocntxwait        (Port_t iobase);
 
 #if NPCI > 0
 static int     sio_pci_attach (device_t dev);
@@ -358,6 +359,7 @@ static struct pci_ids pci_ids[] = {
        { 0x7101135e, "SeaLevel Ultra 530.PCI Single Port Serial", 0x18 },
        { 0x0000151f, "SmartLink 5634PCV SurfRider", 0x10 },
        { 0x98459710, "Netmos Nm9845 PCI Bridge with Dual UART", 0x10 },
+       { 0x99229710, "MCS9922 PCIe Multi-I/O Controller", 0x10 },
        { 0x8c3d8086, "Intel Lynx Point KT Controller", 0x10 },
        { 0x9c3d8086, "Intel Lynx Point-LP HECI KT", 0x10 },
        { 0x8cbd8086, "Intel Wildcat Point KT Controller", 0x10 },
@@ -724,10 +726,21 @@ sioprobe(device_t dev, int xrid, u_long rclk)
                (void)sio_getreg(com, com_data);
        }
        if (fn == 256) {
+               /*
+                * Serial port might be probed but not exist, disable
+                * if so.  Clear console flags if the serial port does
+                * not exist.  This is very common for sio0 and sio1
+                * now and avoids unnecessary user confusion (user does
+                * not have to clear the sio0 console flag if sio0 does
+                * not exist and the user wants the console on another
+                * sio).
+                */
                com_unlock();
                lwkt_reltoken(&tty_token);
                kprintf("sio%d: can't drain, serial port might "
                        "not exist, disabling\n", device_get_unit(dev));
+               com->flags &= ~0x30;
+
                return (ENXIO);
        }
 
@@ -2266,12 +2279,13 @@ comparam(struct tty *tp, struct termios *t)
                t->c_ispeed = t->c_ospeed;
 
        /* check requested parameters */
-       if (t->c_ospeed == 0)
+       if (t->c_ospeed == 0) {
                divisor = 0;
-       else {
+       else {
                if (t->c_ispeed != t->c_ospeed)
                        return (EINVAL);
                divisor = siodivisor(com->rclk, t->c_ispeed);
+                       com->rclk, t->c_ispeed);
                if (divisor == 0)
                        return (EINVAL);
        }
@@ -2340,6 +2354,7 @@ comparam(struct tty *tp, struct termios *t)
         * the speed change atomically.  Keeping interrupts disabled is
         * especially important while com_data is hidden.
         */
+       siocntxwait(com->bsh);
        (void) siosetwater(com, t->c_ispeed);
 
        if (divisor != 0) {
@@ -2357,7 +2372,6 @@ comparam(struct tty *tp, struct termios *t)
                if (sio_getreg(com, com_dlbh) != dlbh)
                        sio_setreg(com, com_dlbh, dlbh);
        }
-
        sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
 
        if (!(tp->t_state & TS_TTSTOP))
@@ -2390,7 +2404,6 @@ comparam(struct tty *tp, struct termios *t)
                }
        }
 
-
        /*
         * Set up state to handle output flow control.
         * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
@@ -2834,7 +2847,6 @@ static speed_t siocngetspeed (Port_t, u_long rclk);
 static void siocnclose (struct siocnstate *sp, Port_t iobase);
 #endif
 static void siocnopen  (struct siocnstate *sp, Port_t iobase, int speed);
-static void siocntxwait        (Port_t iobase);
 
 static cn_probe_t siocnprobe;
 static cn_init_t siocninit;
@@ -2995,7 +3007,8 @@ siocnprobe(struct consdev *cp)
        for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
                int flags;
                int disabled;
-               if (resource_int_value("sio", unit, "disabled", &disabled) == 0) {
+
+               if (!resource_int_value("sio", unit, "disabled", &disabled)) {
                        if (disabled)
                                continue;
                }
@@ -3006,9 +3019,24 @@ siocnprobe(struct consdev *cp)
                        int baud;
                        Port_t iobase;
                        speed_t boot_speed;
+                       struct com_s *com;
 
-                       if (resource_int_value("sio", unit, "port", &port))
-                               continue;
+                       /*
+                        * We need the port.  For built-in serial ports
+                        * (e.g. sio0/sio1) the resources exist.  For
+                        * add-on serial ports they resources might not
+                        * but the port may have been configured late
+                        * and we can find it when we re-probe.
+                        *
+                        * If the port is not specified check to see if
+                        * the device configured after the fact.
+                        */
+                       com = com_addr(unit);
+                       if (resource_int_value("sio", unit, "port", &port)) {
+                               if (com == NULL || com->ioportres == NULL)
+                                       continue;
+                               port = rman_get_bushandle(com->ioportres);
+                       }
                        if (resource_int_value("sio", unit, "baud", &baud) == 0)
                                boot_speed = baud;
                        else
@@ -3023,6 +3051,8 @@ siocnprobe(struct consdev *cp)
                                if (boot_speed)
                                        comdefaultrate = boot_speed;
                        }
+                       if (boot_speed == 0)
+                               boot_speed = comdefaultrate;
 
                        /*
                         * Initialize the divisor latch.  We can't rely on
@@ -3036,21 +3066,36 @@ siocnprobe(struct consdev *cp)
                        com_lock();
                        cfcr = inb(iobase + com_cfcr);
                        outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
-                       divisor = siodivisor(comdefaultrclk, comdefaultrate);
+                       divisor = siodivisor(comdefaultrclk, boot_speed);
                        outb(iobase + com_dlbl, divisor & 0xff);
                        outb(iobase + com_dlbh, divisor >> 8);
                        outb(iobase + com_cfcr, cfcr);
 
-                       siocnopen(&sp, iobase, comdefaultrate);
+                       /*
+                        * We want ttyopen
+                        */
+                       if (com) {
+                               com->it_in.c_iflag = TTYDEF_IFLAG;
+                               com->it_in.c_oflag = TTYDEF_OFLAG;
+                               com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
+                               com->it_in.c_lflag = TTYDEF_LFLAG;
+                               com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
+                               com->lt_out.c_ispeed = com->lt_out.c_ospeed =
+                               com->lt_in.c_ispeed = com->lt_in.c_ospeed =
+                               com->it_in.c_ispeed = com->it_in.c_ospeed =
+                                       boot_speed;
+                       }
+
+                       siocnopen(&sp, iobase, boot_speed);
                        com_unlock();
 
                        crit_exit();
                        if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) {
                                cp->cn_probegood = 1;
                                cp->cn_private = (void *)(intptr_t)unit;
-                               cp->cn_pri = COM_FORCECONSOLE(flags)
-                                            || boothowto & RB_SERIAL
-                                            ? CN_REMOTE : CN_NORMAL;
+                               cp->cn_pri = (COM_FORCECONSOLE(flags)
+                                            || ((boothowto & RB_SERIAL)) ?
+                                                CN_REMOTE : CN_NORMAL);
                                siocniobase = iobase;
                                siocnunit = unit;
                        }
@@ -3101,12 +3146,14 @@ siocninit_fini(struct consdev *cp)
 
        if (cp->cn_probegood) {
                unit = (int)(intptr_t)cp->cn_private;
+
                /*
-                * Call devfs_find_device_by_name on ttydX to find the correct device,
-                * as it should have been created already at this point by the
-                * attach routine.
-                * If it isn't found, the serial port was not attached at all and we
-                * shouldn't be here, so assert this case.
+                * Call devfs_find_device_by_name on ttydX to find the correct
+                * device, as it should have been created already at this
+                * point by the attach routine.
+                *
+                * If it isn't found, the serial port was not attached at all
+                * and we shouldn't be here, so assert this case.
                 */
                dev = devfs_find_device_by_name("ttyd%s",
                                                makedev_unit_b32(tbuf, unit));
index 00f4b2c..745bb21 100644 (file)
@@ -94,7 +94,7 @@ SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
 static int cn_mute;
 
 #ifdef BREAK_TO_DEBUGGER
-int    break_to_debugger = 1;
+int    break_to_debugger = 1;          /* CTL-ALT-ESC on system keyboard */
 #else
 int    break_to_debugger = 0;
 #endif
@@ -103,7 +103,7 @@ SYSCTL_INT(_kern, OID_AUTO, break_to_debugger, CTLFLAG_RW,
        &break_to_debugger, 0, "");
 
 #ifdef ALT_BREAK_TO_DEBUGGER
-int    alt_break_to_debugger = 1;
+int    alt_break_to_debugger = 1;      /* CR ~ ^B on serial port */
 #else
 int    alt_break_to_debugger = 0;
 #endif
@@ -174,7 +174,6 @@ cninit(void)
                    (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
                        best_cp = cp;
        }
-
        
        /*
         * If no console, give up.
index 2cf76ee..407be5c 100644 (file)
@@ -172,47 +172,15 @@ configure(void *dummy)
        safepri = TDPRI_KERN_USER;
 }
 
+/*
+ * Finalize configure.  Reprobe for the console, in case it was one
+ * of the devices which attached, then finish console initialization.
+ */
 static void
 configure_final(void *dummy)
 {
+       cninit();
        cninit_finish();
-
-       if (bootverbose) {
-#if 0 /* JG */
-               /*
-                * Print out the BIOS's idea of the disk geometries.
-                */
-               int i;
-               kprintf("BIOS Geometries:\n");
-               for (i = 0; i < N_BIOS_GEOM; i++) {
-                       unsigned long bios_geom;
-                       int max_cylinder, max_head, max_sector;
-
-                       bios_geom = bootinfo.bi_bios_geom[i];
-
-                       /*
-                        * XXX the bootstrap punts a 1200K floppy geometry
-                        * when the get-disk-geometry interrupt fails.  Skip
-                        * drives that have this geometry.
-                        */
-                       if (bios_geom == 0x4f010f)
-                               continue;
-
-                       kprintf(" %x:%08lx ", i, bios_geom);
-                       max_cylinder = bios_geom >> 16;
-                       max_head = (bios_geom >> 8) & 0xff;
-                       max_sector = bios_geom & 0xff;
-                       kprintf(
-               "0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
-                              max_cylinder, max_cylinder + 1,
-                              max_head, max_head + 1,
-                              max_sector, max_sector);
-               }
-               kprintf(" %d accounted for\n", bootinfo.bi_n_bios_used);
-
-               kprintf("Device configuration finished.\n");
-#endif
-       }
 }
 
 #ifdef BOOTP
index a73b54e..3148b66 100644 (file)
@@ -235,9 +235,14 @@ configure(void *dummy)
        safepri = TDPRI_KERN_USER;
 }
 
+/*
+ * Finalize configure.  Reprobe for the console, in case it was one
+ * of the devices which attached, then finish console initialization.
+ */
 static void
 configure_final(void *dummy)
 {
+       cninit();
        cninit_finish();
 
        if (bootverbose)