From owner-p4-projects Tue Dec 24 22:23: 8 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BD19E37B405; Tue, 24 Dec 2002 22:22:58 -0800 (PST) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4BF9A37B401 for ; Tue, 24 Dec 2002 22:22:58 -0800 (PST) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 83D9643ED1 for ; Tue, 24 Dec 2002 22:22:57 -0800 (PST) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.6/8.12.6) with ESMTP id gBP6Mvfh074499 for ; Tue, 24 Dec 2002 22:22:57 -0800 (PST) (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.6/8.12.6/Submit) id gBP6MuMo074496 for perforce@freebsd.org; Tue, 24 Dec 2002 22:22:56 -0800 (PST) Date: Tue, 24 Dec 2002 22:22:56 -0800 (PST) Message-Id: <200212250622.gBP6MuMo074496@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar Subject: PERFORCE change 22732 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://perforce.freebsd.org/chv.cgi?CH=22732 Change 22732 by marcel@marcel_nfs on 2002/12/24 22:22:25 Auto-detect the FIFO size. Keep a debug printf in there to keep an eye on it for a while. Rename two LCR bits to match the names used in the datasheet. Affected files ... .. //depot/projects/ia64/sys/dev/sio/sio.c#30 edit .. //depot/projects/ia64/sys/dev/sio/sio_cons.c#9 edit .. //depot/projects/ia64/sys/dev/sio/sioreg.h#6 edit Differences ... ==== //depot/projects/ia64/sys/dev/sio/sio.c#30 (text+ko) ==== @@ -264,43 +264,158 @@ /* TUNABLE_INT("machdep.conspeed", &comdefaultrate); */ /* - * Initialize FIFOs. We cannot simple enable the FIFOs because that may cause - * garbage to appear on the wire (non-empty transmit FIFO) or garbage to be - * received (non-empty receive FIFO). The former is prevented by enabling - * loopback prior to enabling the FIFOs. The latter is prevented by ignoring - * any data in the RHR after we have reset the FIFOs. + * Set a FIFO mode. We try not to be disruptive, but leave some of the + * responsibility for the caller to avoid unconditional high overhead. + * For best results, set loopback mode and clear all interrupt sources + * before calling this function. The loopback mode prevents garbage on + * the line and clearing IER avoids possible stray interrupts. */ -static void -sioinitfifo(struct com_s *com) +static int +siosetfifo(struct com_s *com, int fcr) { + int delay, limit; + + /* 1/10th the time to transmit 1 character (estimate). */ + delay = 16000000 * com->reg_dl / com->rclk; - sio_setreg(com, com_mcr, com->reg_mcr | MCR_LOOPBACK); + com->reg_fcr = 0; + sio_setreg(com, com_fcr, 0); /* XXX barrier */ - sio_setreg(com, com_fcr, FCR_ENABLE); + + /* + * Make sure the transmitter is idle before we play with the + * FIFOs. We don't wait more than roughly three times as long + * as needed to send a single character. Given that we may need + * to wait for both the THR and the TSR to clear, this leaves + * us roughly 1 character time slack. + */ + limit = 30; + while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) { + if (delay) + DELAY(delay); + } + if (limit == 0) + return (EIO); + + com->reg_fcr = fcr; + sio_setreg(com, com_fcr, fcr | FCR_XMT_RST | FCR_RCV_RST); /* XXX barrier */ - sio_setreg(com, com_fcr, FCR_ENABLE | FCR_RCV_RST | FCR_XMT_RST); - /* XXX barrier */ - DELAY(100); - com->reg_fcr = 0; + + /* + * Set the hasfifo field when the device has FIFOs. In that case + * we also flush any possible garbage from the transmitter and + * receiver. Flush the transmitter before flushing the receiver + * to allow having the UART in loopback mode. Since we always + * enable FIFO mode after disabling it first, we won't have more + * than two characters the flush. + */ com->hasfifo = (sio_getreg(com, com_iir) & IIR_FIFO_MASK) ? 1 : 0; if (com->hasfifo) { - while (sio_getreg(com, com_lsr) & LSR_RXRDY) { + limit = 30; + while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) { + if (delay) + DELAY(delay); + } + if (limit == 0) + return (EIO); + + limit = 30; + while ((sio_getreg(com, com_lsr) & LSR_RXRDY) && --limit) { (void)sio_getreg(com, com_data); /* XXX barrier */ } - com->reg_fcr = FCR_ENABLE | FCR_RX_HIGH; - sio_setreg(com, com_mcr, com->reg_fcr); + if (limit == 0) + return (EIO); + } + + return (0); +} + +/* + * Initialize the FIFOs and determine the size of the receiver FIFO. We + * assume that the transmitter FIFO has the same size. First we set DMA + * mode (mode 1) with the highest trigger level. In combination with + * loopback this allows us to determine the size of the receiver FIFO. + * After that we re-initialize with a medium high trigger level. + */ +static int +sioinitfifo(struct com_s *com) +{ + int count, delay, error, limit; + + com->fifosize = 0; + + sio_setreg(com, com_mcr, MCR_LOOPBACK | MCR_DTR | MCR_RTS); + /* XXX barrier */ + + error = siosetfifo(com, FCR_ENABLE | FCR_DMA_MODE | FCR_RX_HIGH); + if (error || !com->hasfifo) { + sio_setreg(com, com_mcr, com->reg_mcr); + /* XXX barrier */ + return (error); + } + + /* 1/10th the time to transmit 1 character (estimate). */ + delay = 16000000 * com->reg_dl / com->rclk; + + sio_setreg(com, com_ier, IER_ERXRDY); + /* XXX barrier */ + + /* + * We should have a sufficiently clean "pipe" to determine + * the size of the FIFOs. If there was a character lurking + * in the receiver, then it really cannot do any harm. We + * send as much characters as is reasonable and wait for the + * the TX interrupt to be asserted, counting the characters + * as we send them. Based on that count we know the FIFO size. + */ + count = 0; + while ((sio_getreg(com, com_iir) & IIR_RXRDY) == 0 && count < 1030) { + sio_setreg(com, com_data, 0); /* XXX barrier */ + count++; + + limit = 30; + while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) { + if (delay) + DELAY(delay); + } + if (limit == 0) { + sio_setreg(com, com_ier, 0); + /* XXX barrier */ + sio_setreg(com, com_mcr, com->reg_mcr); + /* XXX barrier */ + return (EIO); + } + } - com->fifosize = 16; /* Minimal FIFO size. */ - /* - * XXX count the number of characters we can send before - * we have a receive interrupt. This tells us how large - * the FIFOs are. - */ + sio_setreg(com, com_ier, 0); + /* XXX barrier */ + + error = siosetfifo(com, FCR_ENABLE | FCR_RX_MEDH); + if (error) { + sio_setreg(com, com_mcr, com->reg_mcr); + /* XXX barrier */ + return (error); } + + if (count >= 14 && count < 16) + com->fifosize = 16; /* 16550 */ + else if (count >= 28 && count < 32) + com->fifosize = 32; /* 16650 */ + else if (count >= 56 && count < 64) + com->fifosize = 64; /* 16750 */ + else if (count >= 120 && count < 128) + com->fifosize = 128; /* 16950 */ + else + com->fifosize = 1; /* XXX */ + sio_setreg(com, com_mcr, com->reg_mcr); /* XXX barrier */ + + device_printf(com->dev, "count=%d, FIFO size=%d\n", count, + com->fifosize); + return (0); } static void @@ -324,23 +439,21 @@ device_set_desc(com->dev, "16550 or compatible"); break; case 32: - /* - * XXX Should we check that features like automatic - * flow control exist? - */ + /* XXX Should we check features? */ device_set_desc(com->dev, "16650 or compatible"); break; case 64: - /* - * XXX Should we check that features like automatic - * flow control exist? - */ + /* XXX Should we check features? */ device_set_desc(com->dev, "16750 or compatible"); break; + case 128: + /* XXX Should we check features? */ + device_set_desc(com->dev, "16950 or compatible"); + break; default: /* XXX Probably not right. */ device_set_desc(com->dev, - "16550 with non-standard FIFO"); + "Non-standard or broken UART with FIFO"); break; } } else { @@ -467,6 +580,7 @@ sioprobe(device_t dev) { struct com_s *com; + int error; u_int flags; while (sio_inited != 2) @@ -505,18 +619,35 @@ * are set correctly for the console. */ if (com->consdev == NULL) { - if (sioprobe1(com)) { + error = sioprobe1(com); + if (error) { bus_release_resource(dev, com->addr_type, com->addr_rid, com->addr_res); - return (ENXIO); + return (error); } if (com->rclk == 0) com->rclk = DEFAULT_RCLK; + + sio_setreg(com, com_lcr, LCR_8BITS | LCR_DLAB); + /* XXX barrier */ + com->reg_dl = siodivisor(com->rclk, comdefaultrate); + sio_setdreg(com, com_dl, com->reg_dl); + /* XXX barrier */ + sio_setreg(com, com_lcr, LCR_8BITS); + /* XXX barrier */ + com->reg_mcr = MCR_IENABLE; + sio_setreg(com, com_mcr, com->reg_mcr); + /* XXX barrier */ } /* Initialize the FIFOs. */ - sioinitfifo(com); + error = sioinitfifo(com); + if (error) { + bus_release_resource(dev, com->addr_type, com->addr_rid, + com->addr_res); + return (error); + } if (device_get_desc(dev) == NULL) siodescribe(com); @@ -532,7 +663,8 @@ return (ENXIO); } - bus_release_resource(dev, com->addr_type, com->addr_rid, com->addr_res); + bus_release_resource(dev, com->addr_type, com->addr_rid, + com->addr_res); return (0); } @@ -557,22 +689,7 @@ if (unit >= sio_numunits) sio_numunits = unit + 1; - /* - * Preset the UART to something reasonable. Only do this when the - * UART is not used as the console. We assume the console works - * and whatever the setting, it cannot be unreasonable. - */ - if (com->consdev == NULL) { - sio_setreg(com, com_lcr, LCR_8BITS | LCR_DLAB); - /* XXX barrier */ - com->reg_dl = siodivisor(com->rclk, comdefaultrate); - sio_setdreg(com, com_dl, com->reg_dl); - /* XXX barrier */ - sio_setreg(com, com_lcr, LCR_8BITS); - /* XXX barrier */ - sio_setreg(com, com_mcr, MCR_IENABLE); - /* XXX barrier */ - } else + if (com->consdev != NULL) com->consdev->cn_dev = makedev(CDEV_MAJOR, unit); com->unit = unit; @@ -1039,8 +1156,7 @@ s = spltty(); if (com->state & CS_BUSY) com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */ - else if ((sio_getreg(com, com_lsr) & (LSR_TSRE | LSR_TXRDY)) - == (LSR_TSRE | LSR_TXRDY)) { + else if (sio_getreg(com, com_lsr) & LSR_TEMT) { com->tp->t_state &= ~TS_BUSY; ttwwakeup(com->tp); com->extra_state &= ~CSE_BUSYCHECK; @@ -1364,7 +1480,7 @@ } /* output queued and everything ready? */ - if (line_status & LSR_TXRDY + if (line_status & LSR_THRE && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { ioptr = com->obufq.l_head; if (com->hasfifo && com->unit != siotsunit) { ==== //depot/projects/ia64/sys/dev/sio/sio_cons.c#9 (text+ko) ==== @@ -210,7 +210,7 @@ s = spltty(); to = 100000; - while ((sio_getreg(&sio_console, com_lsr) & LSR_TSRE) == 0 && --to) + while ((sio_getreg(&sio_console, com_lsr) & LSR_THRE) == 0 && --to) ; sio_setreg(&sio_console, com_data, c); splx(s); ==== //depot/projects/ia64/sys/dev/sio/sioreg.h#6 (text+ko) ==== @@ -79,7 +79,7 @@ #define FCR_RX_MEDH 0x80 #define FCR_RX_HIGH 0xc0 -/* character format control register */ +/* line control register */ #define LCR_DLAB 0x80 #define LCR_SBREAK 0x40 #define LCR_PZERO 0x30 @@ -102,8 +102,8 @@ /* line status register */ #define LSR_RCV_FIFO 0x80 -#define LSR_TSRE 0x40 -#define LSR_TXRDY 0x20 +#define LSR_TEMT 0x40 /* Transmitter Empty. */ +#define LSR_THRE 0x20 /* Transmitter Holding Register Empty. */ #define LSR_BI 0x10 #define LSR_FE 0x08 #define LSR_PE 0x04 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message