From owner-freebsd-sparc64@FreeBSD.ORG Fri Aug 1 10:03:54 2003 Return-Path: Delivered-To: freebsd-sparc64@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2ED7F37B401 for ; Fri, 1 Aug 2003 10:03:54 -0700 (PDT) Received: from mail.gmx.net (pop.gmx.net [213.165.64.20]) by mx1.FreeBSD.org (Postfix) with SMTP id 6C15043FA3 for ; Fri, 1 Aug 2003 10:03:52 -0700 (PDT) (envelope-from tmoestl@gmx.net) Received: (qmail 6243 invoked by uid 65534); 1 Aug 2003 17:03:50 -0000 Received: from p508E758A.dip.t-dialin.net (EHLO galatea.local) (80.142.117.138) by mail.gmx.net (mp027) with SMTP; 01 Aug 2003 19:03:50 +0200 Received: from tmm by galatea.local with local (Exim 4.20 #1) id 19idKD-00075H-Ii; Fri, 01 Aug 2003 19:04:17 +0200 Date: Fri, 1 Aug 2003 19:04:17 +0200 From: Thomas Moestl To: Maxim Mazurok Message-ID: <20030801170417.GC834@crow.dom2ip.de> References: <20030801132240.GA77415@km.ua> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="4jXrM3lyYWu4nBt5" Content-Disposition: inline In-Reply-To: <20030801132240.GA77415@km.ua> User-Agent: Mutt/1.4.1i Sender: Thomas Moestl cc: freebsd-sparc@freebsd.org Subject: Re: sio(4) driver X-BeenThere: freebsd-sparc64@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Porting FreeBSD to the Sparc List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Aug 2003 17:03:54 -0000 --4jXrM3lyYWu4nBt5 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, 2003/08/01 at 16:22:40 +0300, Maxim Mazurok wrote: > I need to add 2 async serial port to my sparc. > > 5.1-RELEASE > > I add to kernel > > device puc > options PUC_FASTINTR > > but i forgot add > > device sio > > after reboot i have in dmesg: > > puc0: port 0x1030-0x103f,0x1020-0x1027,0x1018-0x101f,0x1010-0x1017,0x1008-0x100f,0x1000-0x1007 irq 4 at device 3.0 on pci1 > > card detected, but no have ports (no sio driver in kernel). > I rebuild kernel width sio driver and after reboot have kernel trap. > sio(4) diver are ported to sparc? It works only for ISA sio(4)s currently, due to some ISA specific code that happens to work with PCI on other platforms. I have attached a quick hack to fix this which I use on one of my machines, which should get you around the problems (it also cointains things like console support). The rework which marcel@ is doing in the perforce repository will fix this the right way. - Thomas -- Thomas Moestl http://www.tu-bs.de/~y0015675/ http://people.FreeBSD.org/~tmm/ PGP fingerprint: 1C97 A604 2BD0 E492 51D0 9C0F 1FE6 4F1D 419C 776C --4jXrM3lyYWu4nBt5 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="sio-s64-20030612.diff" Index: sio.c =================================================================== RCS file: /vol/ncvs/src/sys/dev/sio/sio.c,v retrieving revision 1.400 diff -u -r1.400 sio.c --- sio.c 9 Jun 2003 21:25:14 -0000 1.400 +++ sio.c 12 Jun 2003 14:00:19 -0000 @@ -126,7 +126,7 @@ #define sio_getreg(com, off) \ (bus_space_read_1((com)->bst, (com)->bsh, (off))) #define sio_setreg(com, off, value) \ - (bus_space_write_1((com)->bst, (com)->bsh, (off), (value))) + bus_space_write_1((com)->bst, (com)->bsh, (off), (value)) /* * com state bits. @@ -229,15 +229,9 @@ bus_space_tag_t bst; bus_space_handle_t bsh; - Port_t data_port; /* i/o ports */ #ifdef COM_ESP Port_t esp_port; #endif - Port_t int_id_port; - Port_t modem_ctl_port; - Port_t line_status_port; - Port_t modem_status_port; - Port_t intr_ctl_port; /* Ports of IIR register */ struct tty *tp; /* cross reference */ @@ -337,9 +331,20 @@ &gdbdefaultrate, GDBSPEED, ""); static u_int com_events; /* input chars + weighted output completions */ static Port_t siocniobase; -static int siocnunit = -1; +#ifdef __sparc64__ +#define SIOP_CONS 0 +#define SIOP_LLCONS 1 +static struct bus_space_tag siocntag[2]; +static bus_space_handle_t siocnhandle[2]; +static bus_addr_t siocnports[2]; +#endif +#if defined(__i386__) || defined(__ia64__) || defined(__sparc64__) +static int siocnunit; +#endif static Port_t siogdbiobase; +#ifndef __sparc64__ static int siogdbunit = -1; +#endif static void *sio_slow_ih; static void *sio_fast_ih; static int sio_timeout; @@ -348,6 +353,18 @@ = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle); static int sio_numunits; +#ifdef __sparc64__ +#define SIOCNIOBASE(b) siocnports[(b)] +#define SIOCNOUTB(p, o, v) \ + bus_space_write_1(&siocntag[p], siocnhandle[p], o, v) +#define SIOCNINB(p, o) \ + bus_space_read_1(&siocntag[p], siocnhandle[p], o) +#else +#define SIOCNIOBASE(b) (b) +#define SIOCNOUTB(p, o, v) outb(p + o, v) +#define SIOCNINB(p, o) inb(p + o) +#endif + #ifdef COM_ESP /* XXX configure this properly. */ /* XXX quite broken for new-bus. */ @@ -640,7 +657,7 @@ * XXX what about the UART bug avoided by waiting in comparam()? * We don't want to to wait long enough to drain at 2 bps. */ - if (iobase == siocniobase) + if (iobase == SIOCNIOBASE(siocniobase)) DELAY((16 + 1) * 1000000 / (comdefaultrate / 10)); else { sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS); @@ -660,7 +677,8 @@ sio_setreg(com, com_mcr, mcr_image); sio_setreg(com, com_ier, 0); DELAY(1000); /* XXX */ - irqmap[0] = isa_irq_pending(); + if (!noprobe) + irqmap[0] = isa_irq_pending(); /* * Attempt to set loopback mode so that we can send a null byte @@ -736,7 +754,7 @@ sio_setreg(com, com_cfcr, CFCR_8BITS); mtx_unlock_spin(&sio_lock); bus_release_resource(dev, SYS_RES_IOPORT, rid, port); - if (iobase == siocniobase) + if (iobase == SIOCNIOBASE(siocniobase)) result = 0; if (result != 0) { device_set_softc(dev, NULL); @@ -813,7 +831,7 @@ break; } bus_release_resource(dev, SYS_RES_IOPORT, rid, port); - if (iobase == siocniobase) + if (iobase == SIOCNIOBASE(siocniobase)) result = 0; if (result != 0) { device_set_softc(dev, NULL); @@ -944,13 +962,7 @@ com->obufs[0].l_head = com->obuf1; com->obufs[1].l_head = com->obuf2; - com->data_port = iobase + com_data; - com->int_id_port = iobase + com_iir; - com->modem_ctl_port = iobase + com_mcr; - com->mcr_image = inb(com->modem_ctl_port); - com->line_status_port = iobase + com_lsr; - com->modem_status_port = iobase + com_msr; - com->intr_ctl_port = iobase + com_ier; + com->mcr_image = sio_getreg(com, com_mcr); if (rclk == 0) rclk = DEFAULT_RCLK; @@ -983,7 +995,7 @@ * Leave i/o resources allocated if this is a `cn'-level * console, so that other devices can't snarf them. */ - if (iobase != siocniobase) + if (iobase != SIOCNIOBASE(siocniobase)) bus_release_resource(dev, SYS_RES_IOPORT, rid, port); return (ENOMEM); } @@ -1015,7 +1027,7 @@ sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH); DELAY(100); com->st16650a = 0; - switch (inb(com->int_id_port) & IIR_FIFO_MASK) { + switch (sio_getreg(com, com_iir) & IIR_FIFO_MASK) { case FIFO_RX_LOW: printf(" 16450"); break; @@ -1164,7 +1176,7 @@ * on the console. */ if (ret == 0 && unit == comconsole) - outb(siocniobase + com_ier, IER_ERXRDY | IER_ERLS | + SIOCNOUTB(siocniobase, com_ier, IER_ERXRDY | IER_ERLS | IER_EMSC); #endif } @@ -1292,11 +1304,11 @@ * for about 85 usec instead of 100. */ DELAY(50); - if (!(inb(com->line_status_port) & LSR_RXRDY)) + if (!(sio_getreg(com, com_lsr) & LSR_RXRDY)) break; sio_setreg(com, com_fifo, 0); DELAY(50); - (void) inb(com->data_port); + (void) sio_getreg(com, com_data); } if (i == 500) { error = EIO; @@ -1305,15 +1317,15 @@ } mtx_lock_spin(&sio_lock); - (void) inb(com->line_status_port); - (void) inb(com->data_port); + (void) sio_getreg(com, com_lsr); + (void) sio_getreg(com, com_data); com->prev_modem_status = com->last_modem_status - = inb(com->modem_status_port); + = sio_getreg(com, com_msr); if (COM_IIR_TXRDYBUG(com->flags)) { - outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS + sio_setreg(com, com_ier, IER_ERXRDY | IER_ERLS | IER_EMSC); } else { - outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY + sio_setreg(com, com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); } mtx_unlock_spin(&sio_lock); @@ -1524,7 +1536,7 @@ s = spltty(); if (com->state & CS_BUSY) com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */ - else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + else if ((sio_getreg(com, com_lsr) & (LSR_TSRE | LSR_TXRDY)) == (LSR_TSRE | LSR_TXRDY)) { com->tp->t_state &= ~TS_BUSY; ttwwakeup(com->tp); @@ -1668,7 +1680,7 @@ */ if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) && !(tp->t_state & TS_TBLOCK)) - outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS); } static void @@ -1705,7 +1717,7 @@ */ if (com != NULL && !com->gone - && (inb(com->int_id_port) & IIR_IMASK) + && (sio_getreg(com, com_iir) & IIR_IMASK) != IIR_NOPEND) { siointr1(com); possibly_more_intrs = TRUE; @@ -1761,12 +1773,12 @@ u_char int_ctl; u_char int_ctl_new; - int_ctl = inb(com->intr_ctl_port); + int_ctl = sio_getreg(com, com_ier); int_ctl_new = int_ctl; while (!com->gone) { if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) { - modem_status = inb(com->modem_status_port); + modem_status = sio_getreg(com, com_msr); if ((modem_status ^ com->last_modem_status) & com->pps_bit) { pps_capture(&com->pps); @@ -1775,7 +1787,7 @@ PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); } } - line_status = inb(com->line_status_port); + line_status = sio_getreg(com, com_lsr); /* input event? (check first to help avoid overruns) */ while (line_status & LSR_RCV_MASK) { @@ -1783,7 +1795,7 @@ if (!(line_status & LSR_RXRDY)) recv_data = 0; else - recv_data = inb(com->data_port); + recv_data = sio_getreg(com, com_data); #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) /* * Solaris implements a new BREAK which is initiated @@ -1870,7 +1882,7 @@ com->iptr = ++ioptr; if (ioptr == com->ihighwater && com->state & CS_RTS_IFLOW) - outb(com->modem_ctl_port, + sio_setreg(com, com_mcr, com->mcr_image &= ~MCR_RTS); if (line_status & LSR_OE) CE_RECORD(com, CE_OVERRUN); @@ -1880,11 +1892,11 @@ * "& 0x7F" is to avoid the gcc-1.40 generating a slow * jump from the top of the loop to here */ - line_status = inb(com->line_status_port) & 0x7F; + line_status = sio_getreg(com, com_lsr) & 0x7F; } /* modem status change? (always check before doing output) */ - modem_status = inb(com->modem_status_port); + modem_status = sio_getreg(com, com_msr); if (modem_status != com->last_modem_status) { if (com->do_dcd_timestamp && !(com->last_modem_status & MSR_DCD) @@ -1925,10 +1937,10 @@ ocount = com->tx_fifo_size; com->bytes_out += ocount; do - outb(com->data_port, *ioptr++); + sio_setreg(com, com_data, *ioptr++); while (--ocount != 0); } else { - outb(com->data_port, *ioptr++); + sio_setreg(com, com_data, *ioptr++); ++com->bytes_out; if (com->unit == siotsunit) { nanouptime(&siots[siotso]); @@ -1965,13 +1977,13 @@ } } if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) { - outb(com->intr_ctl_port, int_ctl_new); + sio_setreg(com, com_ier, int_ctl_new); } } /* finished? */ #ifndef COM_MULTIPORT - if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) + if ((sio_getreg(com, com_iir) & IIR_IMASK) == IIR_NOPEND) #endif /* COM_MULTIPORT */ return; } @@ -2345,7 +2357,7 @@ * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS * on here, since comstart() won't do it later. */ - outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS); if (com->st16650a) { sio_setreg(com, com_cfcr, 0xbf); sio_setreg(com, com_fifo, @@ -2494,11 +2506,11 @@ com->state |= CS_TTGO; if (tp->t_state & TS_TBLOCK) { if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) - outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); + sio_setreg(com, com_mcr, com->mcr_image &= ~MCR_RTS); } else { if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater && com->state & CS_RTS_IFLOW) - outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS); } mtx_unlock_spin(&sio_lock); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { @@ -2643,14 +2655,14 @@ mtx_lock_spin(&sio_lock); switch (how) { case DMSET: - outb(com->modem_ctl_port, + sio_setreg(com, com_mcr, com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE)); break; case DMBIS: - outb(com->modem_ctl_port, com->mcr_image |= mcr); + sio_setreg(com, com_mcr, com->mcr_image |= mcr); break; case DMBIC: - outb(com->modem_ctl_port, com->mcr_image &= ~mcr); + sio_setreg(com, com_mcr, com->mcr_image &= ~mcr); break; } mtx_unlock_spin(&sio_lock); @@ -2785,6 +2797,7 @@ static speed_t siocngetspeed(Port_t, u_long rclk); #endif static void siocnclose(struct siocnstate *sp, Port_t iobase); +static void siocninitdl(Port_t iobase, speed_t rate); static void siocnopen(struct siocnstate *sp, Port_t iobase, int speed); static void siocntxwait(Port_t iobase); @@ -2810,7 +2823,9 @@ /* To get the GDB related variables */ #if DDB > 0 #include +#ifndef __sparc64__ static struct consdev gdbconsdev; +#endif #endif @@ -2826,7 +2841,7 @@ * transmits. */ timo = 100000; - while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY)) + while ((SIOCNINB(iobase, com_lsr) & (LSR_TSRE | LSR_TXRDY)) != (LSR_TSRE | LSR_TXRDY) && --timo != 0) ; } @@ -2852,13 +2867,13 @@ u_char dlbl; u_char cfcr; - cfcr = inb(iobase + com_cfcr); - outb(iobase + com_cfcr, CFCR_DLAB | cfcr); + cfcr = SIOCNINB(iobase, com_cfcr); + SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | cfcr); - dlbl = inb(iobase + com_dlbl); - dlbh = inb(iobase + com_dlbh); + dlbl = SIOCNINB(iobase, com_dlbl); + dlbh = SIOCNINB(iobase, com_dlbh); - outb(iobase + com_cfcr, cfcr); + SIOCNOUTB(iobase, com_cfcr, cfcr); divisor = dlbh << 8 | dlbl; @@ -2885,13 +2900,13 @@ * and set our default ones (cs8 -parenb speed=comdefaultrate). * We can't save the fifo register since it is read-only. */ - sp->ier = inb(iobase + com_ier); - outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */ + sp->ier = SIOCNINB(iobase, com_ier); + SIOCNOUTB(iobase, com_ier, 0); /* spltty() doesn't stop siointr() */ siocntxwait(iobase); - sp->cfcr = inb(iobase + com_cfcr); - outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); - sp->dlbl = inb(iobase + com_dlbl); - sp->dlbh = inb(iobase + com_dlbh); + sp->cfcr = SIOCNINB(iobase, com_cfcr); + SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | CFCR_8BITS); + sp->dlbl = SIOCNINB(iobase, com_dlbl); + sp->dlbh = SIOCNINB(iobase, com_dlbh); /* * Only set the divisor registers if they would change, since on * some 16550 incompatibles (Startech), setting them clears the @@ -2901,18 +2916,18 @@ divisor = siodivisor(comdefaultrclk, speed); dlbl = divisor & 0xFF; if (sp->dlbl != dlbl) - outb(iobase + com_dlbl, dlbl); + SIOCNOUTB(iobase, com_dlbl, dlbl); dlbh = divisor >> 8; if (sp->dlbh != dlbh) - outb(iobase + com_dlbh, dlbh); - outb(iobase + com_cfcr, CFCR_8BITS); - sp->mcr = inb(iobase + com_mcr); + SIOCNOUTB(iobase, com_dlbh, dlbh); + SIOCNOUTB(iobase, com_cfcr, CFCR_8BITS); + sp->mcr = SIOCNINB(iobase, com_mcr); /* * We don't want interrupts, but must be careful not to "disable" * them by clearing the MCR_IENABLE bit, since that might cause * an interrupt by floating the IRQ line. */ - outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); + SIOCNOUTB(iobase, com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); } static void @@ -2924,20 +2939,45 @@ * Restore the device control registers. */ siocntxwait(iobase); - outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); - if (sp->dlbl != inb(iobase + com_dlbl)) - outb(iobase + com_dlbl, sp->dlbl); - if (sp->dlbh != inb(iobase + com_dlbh)) - outb(iobase + com_dlbh, sp->dlbh); - outb(iobase + com_cfcr, sp->cfcr); + SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | CFCR_8BITS); + if (sp->dlbl != SIOCNINB(iobase, com_dlbl)) + SIOCNOUTB(iobase, com_dlbl, sp->dlbl); + if (sp->dlbh != SIOCNINB(iobase, com_dlbh)) + SIOCNOUTB(iobase, com_dlbh, sp->dlbh); + SIOCNOUTB(iobase, com_cfcr, sp->cfcr); /* * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them. */ - outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS); - outb(iobase + com_ier, sp->ier); + SIOCNOUTB(iobase, com_mcr, sp->mcr | MCR_DTR | MCR_RTS); + SIOCNOUTB(iobase, com_ier, sp->ier); } -#ifndef __alpha__ +static void +siocninitdl(iobase, rate) + Port_t iobase; + speed_t rate; +{ + u_int divisor; + u_char cfcr; + + /* + * Initialize the divisor latch. We can't rely on + * siocnopen() to do this the first time, since it + * avoids writing to the latch if the latch appears + * to have the correct value. Also, if we didn't + * just read the speed from the hardware, then we + * need to set the speed in hardware so that + * switching it later is null. + */ + cfcr = SIOCNINB(iobase, com_cfcr); + SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | cfcr); + divisor = siodivisor(comdefaultrclk, rate); + SIOCNOUTB(iobase, com_dlbl, divisor & 0xff); + SIOCNOUTB(iobase, com_dlbh, divisor >> 8); + SIOCNOUTB(iobase, com_cfcr, cfcr); +} + +#if defined(__i386__) || defined(__ia64__) static void siocnprobe(cp) @@ -2945,7 +2985,6 @@ { speed_t boot_speed; u_char cfcr; - u_int divisor; int s, unit; struct siocnstate sp; @@ -2989,22 +3028,7 @@ comdefaultrate = boot_speed; } - /* - * Initialize the divisor latch. We can't rely on - * siocnopen() to do this the first time, since it - * avoids writing to the latch if the latch appears - * to have the correct value. Also, if we didn't - * just read the speed from the hardware, then we - * need to set the speed in hardware so that - * switching it later is null. - */ - cfcr = inb(iobase + com_cfcr); - outb(iobase + com_cfcr, CFCR_DLAB | cfcr); - divisor = siodivisor(comdefaultrclk, comdefaultrate); - outb(iobase + com_dlbl, divisor & 0xff); - outb(iobase + com_dlbh, divisor >> 8); - outb(iobase + com_cfcr, cfcr); - + siocninitdl(iobase, comdefaultrate); siocnopen(&sp, iobase, comdefaultrate); splx(s); @@ -3052,6 +3076,10 @@ #endif } +#endif + +#ifndef __alpha__ + static void siocninit(cp) struct consdev *cp; @@ -3079,34 +3107,16 @@ { int s; u_char cfcr; - u_int divisor; struct siocnstate sp; - int unit = 0; /* XXX random value! */ siocniobase = port; - siocnunit = unit; comdefaultrate = speed; sio_consdev.cn_pri = CN_NORMAL; - sio_consdev.cn_dev = makedev(CDEV_MAJOR, unit); + sio_consdev.cn_dev = makedev(CDEV_MAJOR, 0); s = spltty(); - /* - * Initialize the divisor latch. We can't rely on - * siocnopen() to do this the first time, since it - * avoids writing to the latch if the latch appears - * to have the correct value. Also, if we didn't - * just read the speed from the hardware, then we - * need to set the speed in hardware so that - * switching it later is null. - */ - cfcr = inb(siocniobase + com_cfcr); - outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr); - divisor = siodivisor(comdefaultrclk, comdefaultrate); - outb(siocniobase + com_dlbl, divisor & 0xff); - outb(siocniobase + com_dlbh, divisor >> 8); - outb(siocniobase + com_cfcr, cfcr); - + siocninitdl(siocniobase, comdefaultrate); siocnopen(&sp, siocniobase, comdefaultrate); splx(s); @@ -3121,9 +3131,8 @@ { int s; u_char cfcr; - u_int divisor; struct siocnstate sp; - int unit = 1; /* XXX random value! */ + int unit = 1; /* XXX !!! */ siogdbiobase = port; gdbdefaultrate = speed; @@ -3139,22 +3148,7 @@ s = spltty(); - /* - * Initialize the divisor latch. We can't rely on - * siocnopen() to do this the first time, since it - * avoids writing to the latch if the latch appears - * to have the correct value. Also, if we didn't - * just read the speed from the hardware, then we - * need to set the speed in hardware so that - * switching it later is null. - */ - cfcr = inb(siogdbiobase + com_cfcr); - outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr); - divisor = siodivisor(comdefaultrclk, gdbdefaultrate); - outb(siogdbiobase + com_dlbl, divisor & 0xff); - outb(siogdbiobase + com_dlbh, divisor >> 8); - outb(siogdbiobase + com_cfcr, cfcr); - + siocninitdl(siogdbiobase, gdbdefaultrate); siocnopen(&sp, siogdbiobase, gdbdefaultrate); splx(s); @@ -3183,8 +3177,8 @@ } s = spltty(); siocnopen(&sp, iobase, speed); - if (inb(iobase + com_lsr) & LSR_RXRDY) - c = inb(iobase + com_data); + if (SIOCNINB(iobase, com_lsr) & LSR_RXRDY) + c = SIOCNINB(iobase, com_data); else c = -1; siocnclose(&sp, iobase); @@ -3213,9 +3207,9 @@ } s = spltty(); siocnopen(&sp, iobase, speed); - while (!(inb(iobase + com_lsr) & LSR_RXRDY)) + while (!(SIOCNINB(iobase, com_lsr) & LSR_RXRDY)) ; - c = inb(iobase + com_data); + c = SIOCNINB(iobase, com_data); siocnclose(&sp, iobase); splx(s); return (c); @@ -3247,7 +3241,7 @@ } siocnopen(&sp, iobase, speed); siocntxwait(iobase); - outb(iobase + com_data, c); + SIOCNOUTB(iobase, com_data, c); siocnclose(&sp, iobase); if (need_unlock) mtx_unlock_spin(&sio_lock); @@ -3304,6 +3298,208 @@ siocntxwait(siogdbiobase); outb(siogdbiobase + com_data, c); siocnclose(&sp, siogdbiobase); + splx(s); +} +#endif + +#ifdef __sparc64__ + +#include +#include +#include +#include +#include +#include + +/* This requires EBus support for now. */ +extern char *sio_ofw_names[]; +extern char *sio_ofw_compat[]; +int sio_ofw_inlist(char *name, char *list[]); + +static phandle_t siocnfind(struct consdev *cp, phandle_t root, + int *unit, int *flags); + +static char sio_ofw_name[32]; + +/* + * Sparc64 console support is a bit complicated; the console needs to + * initialize before any bus drivers are registered. Therefore the attach + * routine needs to walk the ofw device tree, extract nodes that look like + * sio's, look at the parent bus nodes, map the registers, and map the + * resulting PCI adresses to physical addresses using the PCI host bridge node. + */ + +/* Find the first sio eligible for console use and return. */ +static phandle_t +siocnfind(cp, root, unit, flags) + struct consdev *cp; + phandle_t root; + int *unit; + int *flags; +{ + int disabled; + int found; + phandle_t node; + phandle_t rv; + + node = OF_child(root); + while (node != 0) { + found = 0; + if (OF_getprop(node, "name", sio_ofw_name, + sizeof(sio_ofw_name)) != -1) { + sio_ofw_name[sizeof(sio_ofw_name) - 1] = '\0'; + if (sio_ofw_inlist(sio_ofw_name, sio_ofw_names)) + found = 1; + } + if (OF_getprop(node, "compat", sio_ofw_name, + sizeof(sio_ofw_name)) != -1) { + sio_ofw_name[sizeof(sio_ofw_name) - 1] = '\0'; + if (sio_ofw_inlist(sio_ofw_name, sio_ofw_compat)) + found = 1; + } + if (found) { + if (resource_int_value("sio", *unit, "disabled", + &disabled) != 0) + disabled = 0; + if (resource_int_value("sio", *unit, "flags", + flags) == 0) { + if (!disabled && COM_CONSOLE(*flags)) + return (node); + } + (*unit)++; + } + /* + * This recursion should be at most only about 5 levels deep, + * so this should not take up too much stack space. + * It is also done very early, before interrupts can kick in + * or the like. + */ + if ((rv = siocnfind(cp, node, unit, flags)) != 0) + return (rv); + node = OF_peer(node); + } + return (0); +} + +static int siocnmap(phandle_t node, phandle_t parent); + +/* + * ISA and EBus ranges and regs are identical, so we can use a single function + * here. + */ +static int +siocnmap(node, parent) + phandle_t node; + phandle_t parent; +{ + int bs; + phandle_t bus; + u_long child; + int cs; + u_long dummy; + int error; + int i; + struct isa_ranges ir[4]; + char name[32]; + phandle_t pbus; + u_long phys; + struct isa_regs reg; + int rsz; + int type; + struct upa_ranges ur[4]; + + if (OF_getprop(node, "reg", ®, sizeof(reg)) == -1 || + (rsz = OF_getprop(parent, "ranges", ir, sizeof(ir))) == -1) + return (ENXIO); + phys = ISA_REG_PHYS(®); + dummy = phys + 8; + type = ofw_isa_map_iorange(ir, rsz / sizeof(*ir), &phys, &dummy); + if (type == SYS_RES_MEMORY) { + cs = PCI_CS_MEM32; + bs = PCI_MEMORY_BUS_SPACE; + } else { + cs = PCI_CS_IO; + bs = PCI_IO_BUS_SPACE; + } + bus = OF_parent(parent); + if (OF_getprop(bus, "name", name, sizeof(name)) == -1) + return (ENXIO); + name[sizeof(name) - 1] = '\0'; + if (strcmp(name, "pci") != 0) + return (ENXIO); + /* Find the topmost PCI node (the host bridge) */ + while ((pbus = OF_parent(bus)) != 0) { + if (OF_getprop(pbus, "name", name, sizeof(name)) != -1) { + name[sizeof(name) - 1] = '\0'; + if (strcmp(name, "pci") != 0) + break; + } + bus = pbus; + } + if (pbus == 0) + return (ENXIO); + if ((rsz = OF_getprop(bus, "ranges", ur, sizeof(ur))) == -1) + return (ENXIO); + error = ENXIO; + siocniobase = SIOP_CONS; + for (i = 0; i < (rsz / sizeof(ur[0])); i++) { + child = UPA_RANGE_CHILD(&ur[i]); + if (UPA_RANGE_CS(&ur[i]) == cs && phys >= child && + phys - child < UPA_RANGE_SIZE(&ur[i])) { + siocnports[SIOP_CONS] = phys; + siocnhandle[SIOP_CONS] = sparc64_fake_bustag(bs, + UPA_RANGE_PHYS(&ur[i]) + phys, + &siocntag[SIOP_CONS]); + error = 0; + break; + } + } + return (error); +} + +static void +siocnprobe(cp) + struct consdev *cp; +{ + char bname[32]; + speed_t boot_speed; + int error; + int flags; + phandle_t node; + phandle_t parent; + int s; + struct siocnstate sp; + int unit; + + cp->cn_pri = CN_DEAD; + node = OF_peer(0); + if (node <= 0) + return; + unit = 0; + if ((node = siocnfind(cp, node, &unit, &flags)) == 0) + return; + if ((parent = OF_parent(node)) == 0) + return; + if ((OF_getprop(parent, "name", bname, sizeof(bname))) <= 0) + return; + bname[sizeof(bname) - 1] = '\0'; + error = ENXIO; + if (strcmp(bname, "isa") == 0 || + strcmp(bname, "ebus") == 0) + error = siocnmap(node, parent); + if (error != 0) + return; + s = spltty(); + if (boothowto & RB_SERIAL) { + boot_speed = siocngetspeed(SIOP_CONS, comdefaultrclk); + if (boot_speed) + comdefaultrate = boot_speed; + } + cp->cn_dev = makedev(CDEV_MAJOR, unit); + cp->cn_pri = COM_FORCECONSOLE(flags) || boothowto & RB_SERIAL ? + CN_REMOTE : CN_NORMAL; + siocninitdl(SIOP_CONS, comdefaultrate); + siocnopen(&sp, SIOP_CONS, comdefaultrate); splx(s); } #endif --4jXrM3lyYWu4nBt5--