From fb3cf125d14f9ce5c7fbbb8774eb3d5f88f6344c Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 28 May 2018 19:58:03 -0700 Subject: [PATCH] kernel - Add support for MosChip PCIe serial com, and console support * 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 | 4 ++ sys/dev/misc/syscons/syscons.c | 17 +++++ sys/dev/serial/sio/sio.c | 83 +++++++++++++++++++----- sys/kern/tty_cons.c | 5 +- sys/platform/pc64/x86_64/autoconf.c | 42 ++---------- sys/platform/vkernel64/x86_64/autoconf.c | 5 ++ 6 files changed, 98 insertions(+), 58 deletions(-) diff --git a/etc/remote b/etc/remote index 1f1eb9b90c..b4e9c5d44d 100644 --- a/etc/remote +++ b/etc/remote @@ -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: diff --git a/sys/dev/misc/syscons/syscons.c b/sys/dev/misc/syscons/syscons.c index 101026f2d9..e988a579ab 100644 --- a/sys/dev/misc/syscons/syscons.c +++ b/sys/dev/misc/syscons/syscons.c @@ -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) diff --git a/sys/dev/serial/sio/sio.c b/sys/dev/serial/sio/sio.c index 0a4c47f4a8..4b423b108d 100644 --- a/sys/dev/serial/sio/sio.c +++ b/sys/dev/serial/sio/sio.c @@ -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)); diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c index 00f4b2c846..745bb21c1f 100644 --- a/sys/kern/tty_cons.c +++ b/sys/kern/tty_cons.c @@ -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. diff --git a/sys/platform/pc64/x86_64/autoconf.c b/sys/platform/pc64/x86_64/autoconf.c index 2cf76eed4c..407be5c4fc 100644 --- a/sys/platform/pc64/x86_64/autoconf.c +++ b/sys/platform/pc64/x86_64/autoconf.c @@ -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 diff --git a/sys/platform/vkernel64/x86_64/autoconf.c b/sys/platform/vkernel64/x86_64/autoconf.c index a73b54edec..3148b668ae 100644 --- a/sys/platform/vkernel64/x86_64/autoconf.c +++ b/sys/platform/vkernel64/x86_64/autoconf.c @@ -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) -- 2.41.0