Date: Tue, 17 Jan 2012 06:40:41 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r230257 - stable/9/sys/boot/i386/libi386 Message-ID: <201201170640.q0H6efP2071470@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Jan 17 06:40:41 2012 New Revision: 230257 URL: http://svn.freebsd.org/changeset/base/230257 Log: MFC r229435: Add special loader environment variables 'comconsole_port' and 'comconsole_pcidev'. Change allows to use ISA serial ports other than COM1 for the loader/kernel console without loader recompilation, and to configure console on the PCI-attached UARTs. Modified: stable/9/sys/boot/i386/libi386/biospci.c stable/9/sys/boot/i386/libi386/comconsole.c stable/9/sys/boot/i386/libi386/libi386.h Directory Properties: stable/9/sys/ (props changed) stable/9/sys/boot/ (props changed) Modified: stable/9/sys/boot/i386/libi386/biospci.c ============================================================================== --- stable/9/sys/boot/i386/libi386/biospci.c Tue Jan 17 06:23:25 2012 (r230256) +++ stable/9/sys/boot/i386/libi386/biospci.c Tue Jan 17 06:40:41 2012 (r230257) @@ -342,3 +342,9 @@ biospci_read_config(uint32_t locator, in return (0); } +uint32_t +biospci_locator(int8_t bus, uint8_t device, uint8_t function) +{ + + return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7)); +} Modified: stable/9/sys/boot/i386/libi386/comconsole.c ============================================================================== --- stable/9/sys/boot/i386/libi386/comconsole.c Tue Jan 17 06:23:25 2012 (r230256) +++ stable/9/sys/boot/i386/libi386/comconsole.c Tue Jan 17 06:40:41 2012 (r230257) @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <bootstrap.h> #include <machine/cpufunc.h> #include <dev/ic/ns16550.h> +#include <dev/pci/pcireg.h> #include "libi386.h" #define COMC_FMT 0x3 /* 8N1 */ @@ -49,14 +50,23 @@ static int comc_init(int arg); static void comc_putchar(int c); static int comc_getchar(void); static int comc_getspeed(void); +static void set_hw_console_hint(void); static int comc_ischar(void); -static int comc_parsespeed(const char *string); -static void comc_setup(int speed); +static int comc_parseint(const char *string); +static uint32_t comc_parse_pcidev(const char *string); +static int comc_pcidev_set(struct env_var *ev, int flags, + const void *value); +static int comc_pcidev_handle(uint32_t locator); +static int comc_port_set(struct env_var *ev, int flags, + const void *value); +static void comc_setup(int speed, int port); static int comc_speed_set(struct env_var *ev, int flags, const void *value); static int comc_started; static int comc_curspeed; +static int comc_port = COMPORT; +static uint32_t comc_locator; struct console comconsole = { "comconsole", @@ -72,9 +82,10 @@ struct console comconsole = { static void comc_probe(struct console *cp) { - char speedbuf[16]; - char *cons, *speedenv; - int speed; + char intbuf[16]; + char *cons, *env; + int speed, port; + uint32_t locator; /* XXX check the BIOS equipment list? */ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); @@ -90,16 +101,40 @@ comc_probe(struct console *cp) getenv("boot_multicons") != NULL) { comc_curspeed = comc_getspeed(); } - speedenv = getenv("comconsole_speed"); - if (speedenv != NULL) { - speed = comc_parsespeed(speedenv); + + env = getenv("comconsole_speed"); + if (env != NULL) { + speed = comc_parseint(env); if (speed > 0) comc_curspeed = speed; } - sprintf(speedbuf, "%d", comc_curspeed); + sprintf(intbuf, "%d", comc_curspeed); unsetenv("comconsole_speed"); - env_setenv("comconsole_speed", EV_VOLATILE, speedbuf, comc_speed_set, + env_setenv("comconsole_speed", EV_VOLATILE, intbuf, comc_speed_set, + env_nounset); + + env = getenv("comconsole_port"); + if (env != NULL) { + port = comc_parseint(env); + if (port > 0) + comc_port = port; + } + + sprintf(intbuf, "%d", comc_port); + unsetenv("comconsole_port"); + env_setenv("comconsole_port", EV_VOLATILE, intbuf, comc_port_set, + env_nounset); + + env = getenv("comconsole_pcidev"); + if (env != NULL) { + locator = comc_parse_pcidev(env); + if (locator != 0) + comc_pcidev_handle(locator); + } + + unsetenv("comconsole_pcidev"); + env_setenv("comconsole_pcidev", EV_VOLATILE, env, comc_pcidev_set, env_nounset); } } @@ -111,7 +146,7 @@ comc_init(int arg) return 0; comc_started = 1; - comc_setup(comc_curspeed); + comc_setup(comc_curspeed, comc_port); return(0); } @@ -122,8 +157,8 @@ comc_putchar(int c) int wait; for (wait = COMC_TXWAIT; wait > 0; wait--) - if (inb(COMPORT + com_lsr) & LSR_TXRDY) { - outb(COMPORT + com_data, (u_char)c); + if (inb(comc_port + com_lsr) & LSR_TXRDY) { + outb(comc_port + com_data, (u_char)c); break; } } @@ -131,13 +166,13 @@ comc_putchar(int c) static int comc_getchar(void) { - return(comc_ischar() ? inb(COMPORT + com_data) : -1); + return(comc_ischar() ? inb(comc_port + com_data) : -1); } static int comc_ischar(void) { - return(inb(COMPORT + com_lsr) & LSR_RXRDY); + return(inb(comc_port + com_lsr) & LSR_RXRDY); } static int @@ -145,13 +180,33 @@ comc_speed_set(struct env_var *ev, int f { int speed; - if (value == NULL || (speed = comc_parsespeed(value)) <= 0) { + if (value == NULL || (speed = comc_parseint(value)) <= 0) { printf("Invalid speed\n"); return (CMD_ERROR); } if (comc_started && comc_curspeed != speed) - comc_setup(speed); + comc_setup(speed, comc_port); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static int +comc_port_set(struct env_var *ev, int flags, const void *value) +{ + int port; + + if (value == NULL || (port = comc_parseint(value)) <= 0) { + printf("Invalid port\n"); + return (CMD_ERROR); + } + + if (comc_started && comc_port != port) { + comc_setup(comc_curspeed, port); + set_hw_console_hint(); + } env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); @@ -159,24 +214,126 @@ comc_speed_set(struct env_var *ev, int f } static void -comc_setup(int speed) +set_hw_console_hint(void) +{ + char intbuf[64]; + + unsetenv("hw.uart.console"); + sprintf(intbuf, "io:%d,br:%d", comc_port, comc_curspeed); + env_setenv("hw.uart.console", EV_VOLATILE, intbuf, + env_noset, env_nounset); +} + +/* + * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10. + * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0] + */ +static uint32_t +comc_parse_pcidev(const char *string) +{ + char *p, *p1; + uint8_t bus, dev, func, bar; + uint32_t locator; + int pres; + + pres = strtol(string, &p, 0); + if (p == string || *p != ':' || pres < 0 ) + return (0); + bus = pres; + p1 = ++p; + + pres = strtol(p1, &p, 0); + if (p == string || *p != ':' || pres < 0 ) + return (0); + dev = pres; + p1 = ++p; + + pres = strtol(p1, &p, 0); + if (p == string || (*p != ':' && *p != '\0') || pres < 0 ) + return (0); + func = pres; + + if (*p == ':') { + p1 = ++p; + pres = strtol(p1, &p, 0); + if (p == string || *p != '\0' || pres <= 0 ) + return (0); + bar = pres; + } else + bar = 0x10; + + locator = (bar << 16) | biospci_locator(bus, dev, func); + return (locator); +} + +static int +comc_pcidev_handle(uint32_t locator) +{ + char intbuf[64]; + uint32_t port; + + if (biospci_read_config(locator & 0xffff, + (locator & 0xff0000) >> 16, 2, &port) == -1) { + printf("Cannot read bar at 0x%x\n", locator); + return (CMD_ERROR); + } + if (!PCI_BAR_IO(port)) { + printf("Memory bar at 0x%x\n", locator); + return (CMD_ERROR); + } + port &= PCIM_BAR_IO_BASE; + + sprintf(intbuf, "%d", port); + unsetenv("comconsole_port"); + env_setenv("comconsole_port", EV_VOLATILE, intbuf, + comc_port_set, env_nounset); + + comc_setup(comc_curspeed, port); + set_hw_console_hint(); + comc_locator = locator; + + return (CMD_OK); +} + +static int +comc_pcidev_set(struct env_var *ev, int flags, const void *value) +{ + uint32_t locator; + int error; + + if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) { + printf("Invalid pcidev\n"); + return (CMD_ERROR); + } + if (comc_started && comc_locator != locator) { + error = comc_pcidev_handle(locator); + if (error != CMD_OK) + return (error); + } + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (CMD_OK); +} + +static void +comc_setup(int speed, int port) { comc_curspeed = speed; + comc_port = port; - outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT); - outb(COMPORT + com_dlbl, COMC_BPS(speed) & 0xff); - outb(COMPORT + com_dlbh, COMC_BPS(speed) >> 8); - outb(COMPORT + com_cfcr, COMC_FMT); - outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR); + outb(comc_port + com_cfcr, CFCR_DLAB | COMC_FMT); + outb(comc_port + com_dlbl, COMC_BPS(speed) & 0xff); + outb(comc_port + com_dlbh, COMC_BPS(speed) >> 8); + outb(comc_port + com_cfcr, COMC_FMT); + outb(comc_port + com_mcr, MCR_RTS | MCR_DTR); do - inb(COMPORT + com_data); - while (inb(COMPORT + com_lsr) & LSR_RXRDY); + inb(comc_port + com_data); + while (inb(comc_port + com_lsr) & LSR_RXRDY); } static int -comc_parsespeed(const char *speedstr) +comc_parseint(const char *speedstr) { char *p; int speed; @@ -196,13 +353,13 @@ comc_getspeed(void) u_char dlbl; u_char cfcr; - cfcr = inb(COMPORT + com_cfcr); - outb(COMPORT + com_cfcr, CFCR_DLAB | cfcr); + cfcr = inb(comc_port + com_cfcr); + outb(comc_port + com_cfcr, CFCR_DLAB | cfcr); - dlbl = inb(COMPORT + com_dlbl); - dlbh = inb(COMPORT + com_dlbh); + dlbl = inb(comc_port + com_dlbl); + dlbh = inb(comc_port + com_dlbh); - outb(COMPORT + com_cfcr, cfcr); + outb(comc_port + com_cfcr, cfcr); divisor = dlbh << 8 | dlbl; Modified: stable/9/sys/boot/i386/libi386/libi386.h ============================================================================== --- stable/9/sys/boot/i386/libi386/libi386.h Tue Jan 17 06:23:25 2012 (r230256) +++ stable/9/sys/boot/i386/libi386/libi386.h Tue Jan 17 06:40:41 2012 (r230257) @@ -97,6 +97,7 @@ extern vm_offset_t high_heap_base; /* fo int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); +uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function); void biosacpi_detect(void);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201170640.q0H6efP2071470>