diff options
author | dg <dg@FreeBSD.org> | 1995-04-09 04:46:15 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1995-04-09 04:46:15 +0000 |
commit | 57ebd3303adc277f005c3e337e6764245d1176f7 (patch) | |
tree | 5e16e944cf40b0a792aae408d23ca5ed74fa192f | |
parent | 2ef7bb4cbc802e6a933fe3421b91323ec9d26447 (diff) | |
download | FreeBSD-src-57ebd3303adc277f005c3e337e6764245d1176f7.zip FreeBSD-src-57ebd3303adc277f005c3e337e6764245d1176f7.tar.gz |
From Matt Thomas: Added support for 100Mb cards (such as the DEC DE-500-XA
and SMC 9332).
-rw-r--r-- | sys/dev/de/if_de.c | 455 | ||||
-rw-r--r-- | sys/pci/dc21040.h | 65 | ||||
-rw-r--r-- | sys/pci/if_de.c | 455 |
3 files changed, 702 insertions, 273 deletions
diff --git a/sys/dev/de/if_de.c b/sys/dev/de/if_de.c index c2d6262..c8e422e 100644 --- a/sys/dev/de/if_de.c +++ b/sys/dev/de/if_de.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994 Matt Thomas (thomas@lkg.dec.com) + * Copyright (c) 1994, 1995 Matt Thomas (matt@lkg.dec.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_de.c,v 1.18 1995/03/17 04:27:16 davidg Exp $ + * $Id: if_de.c,v 1.19 1995/03/21 22:41:18 se Exp $ * */ @@ -89,7 +89,9 @@ #include <pci/dc21040.h> /* - * This module supports the DEC DC21040 PCI Ethernet Controller. + * This module supports + * the DEC DC21040 PCI Ethernet Controller. + * the DEC DC21140 PCI Fast Ethernet Controller. */ typedef struct { @@ -116,6 +118,9 @@ typedef struct { volatile tulip_uint32_t *csr_command; /* CSR6 */ volatile tulip_uint32_t *csr_intr; /* CSR7 */ volatile tulip_uint32_t *csr_missed_frame; /* CSR8 */ + + /* DC21040 specific registers */ + volatile tulip_sint32_t *csr_enetrom; /* CSR9 */ volatile tulip_uint32_t *csr_reserved; /* CSR10 */ volatile tulip_uint32_t *csr_full_duplex; /* CSR11 */ @@ -123,6 +128,13 @@ typedef struct { volatile tulip_uint32_t *csr_sia_connectivity; /* CSR13 */ volatile tulip_uint32_t *csr_sia_tx_rx; /* CSR14 */ volatile tulip_uint32_t *csr_sia_general; /* CSR15 */ + + /* DC21140/DC21041 specific registers */ + + volatile tulip_uint32_t *csr_srom_mii; /* CSR9 */ + volatile tulip_uint32_t *csr_gp_timer; /* CSR11 */ + volatile tulip_uint32_t *csr_gp; /* CSR12 */ + volatile tulip_uint32_t *csr_watchdog; /* CSR15 */ } tulip_regfile_t; /* @@ -144,22 +156,24 @@ typedef struct { * is so that we can manipulate the page tables so that even if a * packet wraps around the end of the receive space, we can * treat it as virtually contiguous. + * + * The above used to be true (the stupid restriction is still true) + * but we gone to directly DMA'ing into MBUFs because with 100Mb + * cards the copying is just too much of a hit. */ -#define TULIP_RXBUFSIZE 512 -#define TULIP_RXDESCS 128 -#define TULIP_RXSPACE (TULIP_RXBUFSIZE * TULIP_RXDESCS) +#define TULIP_RXDESCS 16 #define TULIP_TXDESCS 128 +#define TULIP_RXQ_TARGET 8 typedef struct { struct arpcom tulip_ac; tulip_regfile_t tulip_csrs; - vm_offset_t tulip_rxspace; unsigned tulip_flags; #define TULIP_WANTSETUP 0x01 #define TULIP_WANTHASH 0x02 #define TULIP_DOINGSETUP 0x04 #define TULIP_ALTPHYS 0x08 /* use AUI */ - unsigned char tulip_rombuf[32]; + unsigned char tulip_rombuf[128]; tulip_uint32_t tulip_setupbuf[192/sizeof(tulip_uint32_t)]; tulip_uint32_t tulip_setupdata[192/sizeof(tulip_uint32_t)]; tulip_uint32_t tulip_intrmask; @@ -169,6 +183,7 @@ typedef struct { caddr_t tulip_bpf; /* BPF context */ #endif struct ifqueue tulip_txq; + struct ifqueue tulip_rxq; tulip_ringinfo_t tulip_rxinfo; tulip_ringinfo_t tulip_txinfo; } tulip_softc_t; @@ -176,10 +191,11 @@ typedef struct { #ifndef IFF_ALTPHYS #define IFF_ALTPHYS IFF_LINK0 /* In case it isn't defined */ #endif -typedef enum { TULIP_DC21040, TULIP_DC21140 } tulip_chipid_t; +typedef enum { TULIP_DC21040, TULIP_DC21140, TULIP_DC21041 } tulip_chipid_t; const char *tulip_chipdescs[] = { "DC21040 [10Mb/s]", - "DC21140 [100Mb/s]", + "DC21140 [10/100Mb/s]", + "DC21041 [10Mb/s]" }; tulip_softc_t *tulips[NDE]; @@ -204,6 +220,7 @@ tulip_chipid_t tulip_chipids[NDE]; && ((u_short *)a1)[2] == 0xFFFFU) static void tulip_start(struct ifnet *ifp); +static void tulip_rx_intr(tulip_softc_t *sc); static void tulip_addr_filter(tulip_softc_t *sc); #if __FreeBSD__ > 1 @@ -221,34 +238,59 @@ tulip_reset( tulip_softc_t *sc = tulips[unit]; tulip_ringinfo_t *ri; tulip_desc_t *di; - vm_offset_t vmoff; *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 33MHz that comes to two microseconds but wait a bit longer anyways) */ - /* - * Use the - */ - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; - if (sc->tulip_if.if_flags & IFF_ALTPHYS) { - if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) - printf("%s%d: enabling Thinwire/AUI port\n", - sc->tulip_if.if_name, sc->tulip_if.if_unit); - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; - sc->tulip_flags |= TULIP_ALTPHYS; - } else { - if (sc->tulip_flags & TULIP_ALTPHYS) - printf("%s%d: enabling 10baseT/UTP port\n", - sc->tulip_if.if_name, sc->tulip_if.if_unit); - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; - sc->tulip_flags &= ~TULIP_ALTPHYS; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + /* + * Use the + */ + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; + if (sc->tulip_if.if_flags & IFF_ALTPHYS) { + if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) + printf("%s%d: enabling Thinwire/AUI port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; + sc->tulip_flags |= TULIP_ALTPHYS; + } else { + if (sc->tulip_flags & TULIP_ALTPHYS) + printf("%s%d: enabling 10baseT/UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; + sc->tulip_flags &= ~TULIP_ALTPHYS; + } + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + *sc->tulip_csrs.csr_gp = TULIP_GP_PINS; + *sc->tulip_csrs.csr_gp = TULIP_GP_INIT; + if (sc->tulip_if.if_flags & IFF_ALTPHYS) { + if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) + printf("%s%d: enabling 100baseTX UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER; + sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; + sc->tulip_flags |= TULIP_ALTPHYS; + } else { + if (sc->tulip_flags & TULIP_ALTPHYS) + printf("%s%d: enabling 10baseT UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + sc->tulip_cmdmode &= ~(TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER); + sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; + sc->tulip_flags &= ~TULIP_ALTPHYS; + } } *sc->tulip_csrs.csr_txlist = vtophys(&sc->tulip_txinfo.ri_first[0]); *sc->tulip_csrs.csr_rxlist = vtophys(&sc->tulip_rxinfo.ri_first[0]); *sc->tulip_csrs.csr_intr = 0; - *sc->tulip_csrs.csr_busmode = 0x4800; + *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_BURSTLEN_8LW + |TULIP_BUSMODE_CACHE_ALIGN8 + |(BYTE_ORDER != LITTLE_ENDIAN + ? TULIP_BUSMODE_BIGENDIAN + : 0); sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; /* @@ -277,12 +319,18 @@ tulip_reset( ri = &sc->tulip_rxinfo; ri->ri_nextin = ri->ri_nextout = ri->ri_first; ri->ri_free = ri->ri_max; - for (vmoff = vtophys(sc->tulip_rxspace), di = ri->ri_first; - di < ri->ri_last; di++, vmoff += TULIP_RXBUFSIZE) { - di->d_status |= TULIP_DSTS_OWNER; - di->d_length1 = TULIP_RXBUFSIZE; di->d_addr1 = vmoff; + for (di = ri->ri_first; di < ri->ri_last; di++) { + di->d_status = 0; + di->d_length1 = 0; di->d_addr1 = 0; di->d_length2 = 0; di->d_addr2 = 0; } + for (;;) { + struct mbuf *m; + IF_DEQUEUE(&sc->tulip_rxq, m); + if (m == NULL) + break; + m_freem(m); + } sc->tulip_intrmask = TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED @@ -311,6 +359,7 @@ tulip_init( } sc->tulip_cmdmode |= TULIP_CMD_TXRUN; if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { + tulip_rx_intr(sc); sc->tulip_cmdmode |= TULIP_CMD_RXRUN; sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; } else { @@ -370,39 +419,34 @@ tulip_rx_intr( struct ifnet *ifp = &sc->tulip_if; for (;;) { - tulip_desc_t *eop; - int total_len, ndescs; - caddr_t bufaddr = (caddr_t) sc->tulip_rxspace; + struct ether_header eh; + tulip_desc_t *eop = ri->ri_nextin; + int total_len = 0; + struct mbuf *m = NULL; + int accept = 0; - for (ndescs = 1, eop = ri->ri_nextin;; ndescs++) { - if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) - return; - - if (eop->d_status & TULIP_DSTS_RxLASTDESC) - break; - if (++eop == ri->ri_last) - eop = ri->ri_first; - } + if (sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) + goto queue_mbuf; - bufaddr += TULIP_RXBUFSIZE * (ri->ri_nextin - ri->ri_first); - total_len = ((eop->d_status >> 16) & 0x7FF) - 4; + if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) + break; + total_len = ((eop->d_status >> 16) & 0x7FF) - 4; + IF_DEQUEUE(&sc->tulip_rxq, m); if ((eop->d_status & TULIP_DSTS_ERRSUM) == 0) { - struct ether_header eh; - struct mbuf *m; #if TULIP_CHECK_RXCRC - unsigned crc = tulip_crc32(bufaddr, total_len); + unsigned crc = tulip_crc32(mtod(m, unsigned char *), total_len); if (~crc != *((unsigned *) &bufaddr[total_len])) { printf("de0: bad rx crc: %08x [rx] != %08x\n", *((unsigned *) &bufaddr[total_len]), ~crc); goto next; } #endif - eh = *(struct ether_header *) bufaddr; + eh = *mtod(m, struct ether_header *); #if NBPFILTER > 0 if (sc->tulip_bpf != NULL) { - bpf_tap(sc->tulip_bpf, bufaddr, total_len); + bpf_tap(sc->tulip_bpf, mtod(m, caddr_t), total_len); if ((eh.ether_dhost[0] & 1) == 0 && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr)) goto next; @@ -411,34 +455,58 @@ tulip_rx_intr( goto next; } #endif - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m != NULL) { - m->m_pkthdr.rcvif = ifp; - total_len -= sizeof(eh); - if (total_len > MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - ifp->if_ierrors++; - goto next; - } - } - bcopy(bufaddr + sizeof(eh), mtod(m, caddr_t), total_len); - m->m_len = m->m_pkthdr.len = total_len; - ether_input(ifp, &eh, m); - } else { - ifp->if_ierrors++; - } + accept = 1; } else { ifp->if_ierrors++; } -next: + next: ifp->if_ipackets++; - while (ndescs-- > 0) { - ri->ri_nextin->d_status |= TULIP_DSTS_OWNER; - if (++ri->ri_nextin == ri->ri_last) - ri->ri_nextin = ri->ri_first; + if (++ri->ri_nextin == ri->ri_last) + ri->ri_nextin = ri->ri_first; + queue_mbuf: + /* + * Either we are priming the TULIP with mbufs (m == NULL) + * or we are about to accept an mbuf for the upper layers + * so we need to allocate an mbuf to replace it. If we + * can't replace, then count it as an input error and reuse + * the mbuf. + */ + if (accept || m == NULL) { + struct mbuf *m0; + MGETHDR(m0, M_DONTWAIT, MT_DATA); + if (m0 != NULL) { + MCLGET(m0, M_DONTWAIT); + if ((m0->m_flags & M_EXT) == 0) { + m_freem(m0); + m0 = NULL; + } + } + if (accept) { + if (m0 != NULL) { + m->m_pkthdr.rcvif = ifp; + m->m_data += sizeof(struct ether_header); + m->m_len = m->m_pkthdr.len = total_len; + ether_input(ifp, &eh, m); + m = m0; + } else { + ifp->if_ierrors++; + } + } else { + m = m0; + } } + if (m == NULL) + break; + /* + * Now give the buffer to the TULIP and save in our + * receive queue. + */ + ri->ri_nextout->d_length1 = MCLBYTES - 4; + ri->ri_nextout->d_addr1 = vtophys(mtod(m, caddr_t)); + ri->ri_nextout->d_status = TULIP_DSTS_OWNER; + if (++ri->ri_nextout == ri->ri_last) + ri->ri_nextout = ri->ri_first; + IF_ENQUEUE(&sc->tulip_rxq, m); } } @@ -465,6 +533,7 @@ tulip_tx_intr( */ sc->tulip_flags &= ~TULIP_DOINGSETUP; if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { + tulip_rx_intr(sc); sc->tulip_cmdmode |= TULIP_CMD_RXRUN; sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; *sc->tulip_csrs.csr_status = TULIP_STS_RXSTOPPED; @@ -693,6 +762,94 @@ tulip_intr( } /* + * + */ + +void +tulip_delay_300ns( + tulip_softc_t *sc) +{ + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; +} + +#define EMIT do { *sc->tulip_csrs.csr_srom_mii = csr; tulip_delay_300ns(sc); } while (0) + + +void +tulip_idle_srom( + tulip_softc_t *sc) +{ + unsigned bit, csr; + + csr = SROMSEL | SROMRD; EMIT; + csr ^= SROMCS; EMIT; + csr ^= SROMCLKON; EMIT; + + /* + * Write 25 cycles of 0 which will force the SROM to be idle. + */ + for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + } + csr ^= SROMCLKOFF; EMIT; + csr ^= SROMCS; EMIT; EMIT; + csr = 0; EMIT; +} + + +void +tulip_read_srom( + tulip_softc_t *sc) +{ + int idx; + const unsigned bitwidth = SROM_BITWIDTH; + const unsigned cmdmask = (SROMCMD_RD << bitwidth); + const unsigned msb = 1 << (bitwidth + 3 - 1); + unsigned lastidx = (1 << bitwidth) - 1; + int lowbit = 0; + + tulip_idle_srom(sc); + + for (idx = 0; idx <= lastidx; idx++) { + unsigned lastbit, data, bits, bit, csr; + csr = SROMSEL | SROMRD; EMIT; + csr ^= SROMCSON; EMIT; + csr ^= SROMCLKON; EMIT; + + lastbit = 0; + for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { + const unsigned thisbit = bits & msb; + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + if (thisbit != lastbit) { + csr ^= SROMDOUT; EMIT; /* clock low; invert data */ + } + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + lastbit = thisbit; + } + csr ^= SROMCLKOFF; EMIT; + + for (data = 0, bits = 0; bits < 16; bits++) { + data <<= 1; + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + data |= *sc->tulip_csrs.csr_srom_mii & SROMDIN ? 1 : 0; + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + } + sc->tulip_rombuf[idx*2] = data & 0xFF; + sc->tulip_rombuf[idx*2+1] = data >> 8; + csr = SROMSEL | SROMRD; EMIT; + csr = 0; EMIT; + } +} + +/* * This is the standard method of reading the DEC Address ROMS. */ static int @@ -704,12 +861,17 @@ tulip_read_macaddr( unsigned char tmpbuf[8]; static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; - *sc->tulip_csrs.csr_enetrom = 1; - for (idx = 0; idx < 32; idx++) { - int cnt = 0; - while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) - cnt++; - sc->tulip_rombuf[idx] = csr & 0xFF; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040 + || (tulip_chipids[sc->tulip_unit] == TULIP_DC21140 && sc->tulip_revinfo < 0x10)) { + *sc->tulip_csrs.csr_enetrom = 1; + for (idx = 0; idx < 32; idx++) { + int cnt = 0; + while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) + cnt++; + sc->tulip_rombuf[idx] = csr & 0xFF; + } + } else { + tulip_read_srom(sc); } if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { @@ -813,9 +975,9 @@ tulip_addr_filter( ETHER_NEXT_MULTI(step, enm); } sc->tulip_cmdmode |= TULIP_WANTHASH; - sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; - sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; - sp[42] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; + sp[39] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; + sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; + sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; } else { /* * Else can get perfect filtering for 16 addresses. @@ -969,17 +1131,34 @@ tulip_attach( ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; - *sc->tulip_csrs.csr_sia_connectivity = 0; - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; - for (cnt = 0; cnt < 240000; cnt++) { - if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) - break; - DELAY(10); - } - if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { - ifp->if_flags |= IFF_ALTPHYS; - } else { - sc->tulip_flags |= TULIP_ALTPHYS; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + *sc->tulip_csrs.csr_sia_connectivity = 0; + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; + for (cnt = 0; cnt < 240000; cnt++) { + if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) + break; + DELAY(10); + } + if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { + ifp->if_flags |= IFF_ALTPHYS; + } else { + sc->tulip_flags |= TULIP_ALTPHYS; + } + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + /* + * This is going to suck. + */ + *sc->tulip_csrs.csr_gp = TULIP_GP_PINS; + *sc->tulip_csrs.csr_gp = TULIP_GP_INIT; + *sc->tulip_csrs.csr_command |= TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER; + *sc->tulip_csrs.csr_command &= ~TULIP_CMD_TXTHRSHLDCTL; + DELAY(1000000); + if (*sc->tulip_csrs.csr_gp & TULIP_GP_FASTMODE) { + ifp->if_flags |= IFF_ALTPHYS; + } else { + sc->tulip_flags |= TULIP_ALTPHYS; + } } TULIP_RESET(sc); @@ -1018,13 +1197,24 @@ tulip_initcsrs( sc->tulip_csrs.csr_command = va_csrs + 6 * csr_size; sc->tulip_csrs.csr_intr = va_csrs + 7 * csr_size; sc->tulip_csrs.csr_missed_frame = va_csrs + 8 * csr_size; - sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; - sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; - sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; - sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; - sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; - sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; - sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; + sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; + sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; + sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; + sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; + sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; + sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + if (sc->tulip_revinfo < 0x10) + sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; + else + sc->tulip_csrs.csr_srom_mii = va_csrs + 9 * csr_size; + + sc->tulip_csrs.csr_gp_timer = va_csrs + 11 * csr_size; + sc->tulip_csrs.csr_gp = va_csrs + 12 * csr_size; + sc->tulip_csrs.csr_watchdog = va_csrs + 15 * csr_size; + } } static void @@ -1049,14 +1239,14 @@ tulip_initring( */ static char* tulip_pci_probe (pcici_t config_id, pcidi_t device_id); static void tulip_pci_attach(pcici_t config_id, int unit); -static u_long tulip_count; +static u_long tulip_pci_count; static int tulip_pci_shutdown(struct kern_devconf *, int); struct pci_device dedevice = { "de", tulip_pci_probe, tulip_pci_attach, - &tulip_count, + &tulip_pci_count, tulip_pci_shutdown, }; @@ -1077,19 +1267,20 @@ tulip_pci_probe( pcici_t config_id, pcidi_t device_id) { - int idx; - for (idx = 0; idx < NDE; idx++) { - if (tulips[idx] == NULL) { - if (device_id == 0x00021011ul) { - tulip_chipids[idx] = TULIP_DC21040; - return "Digital DC21040 Ethernet"; - } - if (device_id == 0x00091011ul) { - tulip_chipids[idx] = TULIP_DC21140; - return "Digital DC21140 Fast Ethernet"; - } - return NULL; - } + if (device_id == 0x00021011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21040; + return "Digital DC21040 Ethernet"; + } + if (device_id == 0x00141011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21041; + return "Digital DC21041 Ethernet"; + } + if (device_id == 0x00091011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21140; + return "Digital DC21140 Fast Ethernet"; } return NULL; } @@ -1104,6 +1295,12 @@ tulip_pci_attach( vm_offset_t va_csrs, pa_csrs; tulip_desc_t *rxdescs, *txdescs; + if (unit >= NDE) { + printf("de%d: not configured; kernel is built for only %d device%s.\n", + unit, NDE, NDE == 1 ? "" : "s"); + return; + } + sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); if (sc == NULL) return; @@ -1124,32 +1321,21 @@ tulip_pci_attach( } bzero(sc, sizeof(*sc)); /* Zero out the softc*/ - sc->tulip_rxspace = vm_page_alloc_contig(TULIP_RXSPACE + NBPG, 0, 0xffffffff, PAGE_SIZE); - /* - * We've allocated an extra page of receive space so we can double map - * the first page of the receive space into the page after the last page - * of the receive space. This means that even if a receive wraps around - * the end of the receive space, it will still virtually contiguous and - * that greatly simplifies the recevie logic. - */ - pmap_enter(pmap_kernel(), sc->tulip_rxspace + TULIP_RXSPACE, - vtophys(sc->tulip_rxspace), VM_PROT_READ|VM_PROT_WRITE, TRUE); sc->tulip_unit = unit; sc->tulip_name = "de"; retval = pci_map_mem(config_id, PCI_CBMA, &va_csrs, &pa_csrs); if (!retval) { - kmem_free(kernel_map, sc->tulip_rxspace, TULIP_RXSPACE + NBPG); free((caddr_t) txdescs, M_DEVBUF); free((caddr_t) rxdescs, M_DEVBUF); free((caddr_t) sc, M_DEVBUF); return; } tulips[unit] = sc; + sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; tulip_initcsrs(sc, (volatile tulip_uint32_t *) va_csrs, TULIP_PCI_CSRSIZE); tulip_initring(sc, &sc->tulip_rxinfo, rxdescs, TULIP_RXDESCS); tulip_initring(sc, &sc->tulip_txinfo, txdescs, TULIP_TXDESCS); - sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV); if ((retval = tulip_read_macaddr(sc)) < 0) { printf("de%d: can't read ENET ROM (why=%d) (", sc->tulip_unit, retval); for (idx = 0; idx < 32; idx++) @@ -1168,18 +1354,19 @@ tulip_pci_attach( } static int -tulip_pci_shutdown(kdc, force) - struct kern_devconf *kdc; - int force; +tulip_pci_shutdown( + struct kern_devconf *kdc, + int force) { + if (kdc->kdc_unit < NDE) { tulip_softc_t *sc = tulips[kdc->kdc_unit]; - *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 33MHz that comes to two microseconds but wait a bit longer anyways) */ - (void) dev_detach(kdc); - return 0; + } + (void) dev_detach(kdc); + return 0; } #endif /* NPCI > 0 */ diff --git a/sys/pci/dc21040.h b/sys/pci/dc21040.h index 4afa274..cda3dd7 100644 --- a/sys/pci/dc21040.h +++ b/sys/pci/dc21040.h @@ -21,9 +21,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: dc21040.h,v 1.2 1994/08/15 20:42:25 thomas Exp thomas $ + * $Id: dc21040.h,v 1.1 1994/10/01 20:16:45 wollman Exp $ * * $Log: dc21040.h,v $ + * Revision 1.1 1994/10/01 20:16:45 wollman + * Add Matt Thomas's DC21040 PCI Ethernet driver. (This is turning out + * to be quite a popular chip, so expect to see a number of products + * based on it.) + * * Revision 1.2 1994/08/15 20:42:25 thomas * misc additions * @@ -165,9 +170,10 @@ typedef struct { #define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ #define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ #define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ -#define TULIP_STS_LINKFAIL 0x00001000L /* (RW) Link Failure */ -#define TULIP_STS_FULDPLXSHRT 0x00000800L /* (RW) Full Duplex Short Fram Rcvd */ -#define TULIP_STS_AUI 0x00000400L /* (RW) AUI/TP Switch */ +#define TULIP_STS_LINKFAIL 0x00001000L /* (RW) Link Failure (DC21040) */ +#define TULIP_STS_FULDPLXSHRT 0x00000800L /* (RW) Full Duplex Short Fram Rcvd (DC21040) */ +#define TULIP_STS_GPTIMEOUT 0x00000800L /* (RW) General Purpose Timeout (DC21140) */ +#define TULIP_STS_AUI 0x00000400L /* (RW) AUI/TP Switch (DC21040) */ #define TULIP_STS_RXTIMEOUT 0x00000200L /* (RW) Receive Watchbog Timeout */ #define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */ #define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buffer Unavailable */ @@ -181,8 +187,13 @@ typedef struct { /* * CSR6 -- Command (Operation Mode) Register */ +#define TULIP_CMD_SCRAMBLER 0x00400000L /* (RW) Scrambler Mode (DC21140) */ +#define TULIP_CMD_PCSFUNCTION 0x00200000L /* (RW) PCS Function (DC21140) */ +#define TULIP_CMD_TXTHRSHLDCTL 0x00100000L /* (RW) Transmit Threshold Mode (DC21140) */ +#define TULIP_CMD_STOREFWD 0x00080000L /* (RW) Store and Foward (DC21140) */ +#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (DC21140) */ #define TULIP_CMD_CAPTREFFCT 0x00020000L /* (RW) Capture Effect (!802.3) */ -#define TULIP_CMD_BACKPRESSURE 0x00010000L /* (RW) Back Pressure (!802.3) */ +#define TULIP_CMD_BACKPRESSURE 0x00010000L /* (RW) Back Pressure (!802.3) (DC21040) */ #define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */ #define TULIP_CMD_THRSHLD72 0x00000000L /* 00 - 72 Bytes */ #define TULIP_CMD_THRSHLD96 0x00004000L /* 01 - 96 Bytes */ @@ -210,5 +221,49 @@ typedef struct { #define TULIP_SIACONN_10BASET 0x00000005L #define TULIP_BUSMODE_SWRESET 0x00000001L +#define TULIP_BUSMODE_DESCSKIPLEN_MASK 0x0000007CL +#define TULIP_BUSMODE_BIGENDIAN 0x00000080L +#define TULIP_BUSMODE_BURSTLEN_MASK 0x00003F00L +#define TULIP_BUSMODE_BURSTLEN_DEFAULT 0x00000000L +#define TULIP_BUSMODE_BURSTLEN_1LW 0x00000100L +#define TULIP_BUSMODE_BURSTLEN_2LW 0x00000200L +#define TULIP_BUSMODE_BURSTLEN_4LW 0x00000400L +#define TULIP_BUSMODE_BURSTLEN_8LW 0x00000800L +#define TULIP_BUSMODE_BURSTLEN_16LW 0x00001000L +#define TULIP_BUSMODE_BURSTLEN_32LW 0x00002000L +#define TULIP_BUSMODE_CACHE_NOALIGN 0x00000000L +#define TULIP_BUSMODE_CACHE_ALIGN8 0x00004000L +#define TULIP_BUSMODE_CACHE_ALIGN16 0x00008000L +#define TULIP_BUSMODE_CACHE_ALIGN32 0x0000C000L +#define TULIP_BUSMODE_TXPOLL_NEVER 0x00000000L +#define TULIP_BUSMODE_TXPOLL_200us 0x00020000L +#define TULIP_BUSMODE_TXPOLL_800us 0x00040000L +#define TULIP_BUSMODE_TXPOLL_1600us 0x00060000L + + +#define TULIP_GP_FASTMODE 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */ +#define TULIP_GP_PINS 0x0000013F /* General Purpose Pin directions */ +#define TULIP_GP_INIT 0x0000000B /* No loopback --- point-to-point */ + +/* + * SROM definitions for the DC21140 and DC21041. + */ +#define SROMSEL 0x0800 +#define SROMRD 0x4000 +#define SROMWR 0x2000 +#define SROMDIN 0x0008 +#define SROMDOUT 0x0004 +#define SROMDOUTON 0x0004 +#define SROMDOUTOFF 0x0004 +#define SROMCLKON 0x0002 +#define SROMCLKOFF 0x0002 +#define SROMCSON 0x0001 +#define SROMCSOFF 0x0001 +#define SROMCS 0x0001 + +#define SROMCMD_MODE 4 +#define SROMCMD_WR 5 +#define SROMCMD_RD 6 +#define SROM_BITWIDTH 6 #endif /* !defined(_DC21040_H) */ diff --git a/sys/pci/if_de.c b/sys/pci/if_de.c index c2d6262..c8e422e 100644 --- a/sys/pci/if_de.c +++ b/sys/pci/if_de.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1994 Matt Thomas (thomas@lkg.dec.com) + * Copyright (c) 1994, 1995 Matt Thomas (matt@lkg.dec.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_de.c,v 1.18 1995/03/17 04:27:16 davidg Exp $ + * $Id: if_de.c,v 1.19 1995/03/21 22:41:18 se Exp $ * */ @@ -89,7 +89,9 @@ #include <pci/dc21040.h> /* - * This module supports the DEC DC21040 PCI Ethernet Controller. + * This module supports + * the DEC DC21040 PCI Ethernet Controller. + * the DEC DC21140 PCI Fast Ethernet Controller. */ typedef struct { @@ -116,6 +118,9 @@ typedef struct { volatile tulip_uint32_t *csr_command; /* CSR6 */ volatile tulip_uint32_t *csr_intr; /* CSR7 */ volatile tulip_uint32_t *csr_missed_frame; /* CSR8 */ + + /* DC21040 specific registers */ + volatile tulip_sint32_t *csr_enetrom; /* CSR9 */ volatile tulip_uint32_t *csr_reserved; /* CSR10 */ volatile tulip_uint32_t *csr_full_duplex; /* CSR11 */ @@ -123,6 +128,13 @@ typedef struct { volatile tulip_uint32_t *csr_sia_connectivity; /* CSR13 */ volatile tulip_uint32_t *csr_sia_tx_rx; /* CSR14 */ volatile tulip_uint32_t *csr_sia_general; /* CSR15 */ + + /* DC21140/DC21041 specific registers */ + + volatile tulip_uint32_t *csr_srom_mii; /* CSR9 */ + volatile tulip_uint32_t *csr_gp_timer; /* CSR11 */ + volatile tulip_uint32_t *csr_gp; /* CSR12 */ + volatile tulip_uint32_t *csr_watchdog; /* CSR15 */ } tulip_regfile_t; /* @@ -144,22 +156,24 @@ typedef struct { * is so that we can manipulate the page tables so that even if a * packet wraps around the end of the receive space, we can * treat it as virtually contiguous. + * + * The above used to be true (the stupid restriction is still true) + * but we gone to directly DMA'ing into MBUFs because with 100Mb + * cards the copying is just too much of a hit. */ -#define TULIP_RXBUFSIZE 512 -#define TULIP_RXDESCS 128 -#define TULIP_RXSPACE (TULIP_RXBUFSIZE * TULIP_RXDESCS) +#define TULIP_RXDESCS 16 #define TULIP_TXDESCS 128 +#define TULIP_RXQ_TARGET 8 typedef struct { struct arpcom tulip_ac; tulip_regfile_t tulip_csrs; - vm_offset_t tulip_rxspace; unsigned tulip_flags; #define TULIP_WANTSETUP 0x01 #define TULIP_WANTHASH 0x02 #define TULIP_DOINGSETUP 0x04 #define TULIP_ALTPHYS 0x08 /* use AUI */ - unsigned char tulip_rombuf[32]; + unsigned char tulip_rombuf[128]; tulip_uint32_t tulip_setupbuf[192/sizeof(tulip_uint32_t)]; tulip_uint32_t tulip_setupdata[192/sizeof(tulip_uint32_t)]; tulip_uint32_t tulip_intrmask; @@ -169,6 +183,7 @@ typedef struct { caddr_t tulip_bpf; /* BPF context */ #endif struct ifqueue tulip_txq; + struct ifqueue tulip_rxq; tulip_ringinfo_t tulip_rxinfo; tulip_ringinfo_t tulip_txinfo; } tulip_softc_t; @@ -176,10 +191,11 @@ typedef struct { #ifndef IFF_ALTPHYS #define IFF_ALTPHYS IFF_LINK0 /* In case it isn't defined */ #endif -typedef enum { TULIP_DC21040, TULIP_DC21140 } tulip_chipid_t; +typedef enum { TULIP_DC21040, TULIP_DC21140, TULIP_DC21041 } tulip_chipid_t; const char *tulip_chipdescs[] = { "DC21040 [10Mb/s]", - "DC21140 [100Mb/s]", + "DC21140 [10/100Mb/s]", + "DC21041 [10Mb/s]" }; tulip_softc_t *tulips[NDE]; @@ -204,6 +220,7 @@ tulip_chipid_t tulip_chipids[NDE]; && ((u_short *)a1)[2] == 0xFFFFU) static void tulip_start(struct ifnet *ifp); +static void tulip_rx_intr(tulip_softc_t *sc); static void tulip_addr_filter(tulip_softc_t *sc); #if __FreeBSD__ > 1 @@ -221,34 +238,59 @@ tulip_reset( tulip_softc_t *sc = tulips[unit]; tulip_ringinfo_t *ri; tulip_desc_t *di; - vm_offset_t vmoff; *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 33MHz that comes to two microseconds but wait a bit longer anyways) */ - /* - * Use the - */ - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; - if (sc->tulip_if.if_flags & IFF_ALTPHYS) { - if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) - printf("%s%d: enabling Thinwire/AUI port\n", - sc->tulip_if.if_name, sc->tulip_if.if_unit); - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; - sc->tulip_flags |= TULIP_ALTPHYS; - } else { - if (sc->tulip_flags & TULIP_ALTPHYS) - printf("%s%d: enabling 10baseT/UTP port\n", - sc->tulip_if.if_name, sc->tulip_if.if_unit); - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; - sc->tulip_flags &= ~TULIP_ALTPHYS; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + /* + * Use the + */ + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; + if (sc->tulip_if.if_flags & IFF_ALTPHYS) { + if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) + printf("%s%d: enabling Thinwire/AUI port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; + sc->tulip_flags |= TULIP_ALTPHYS; + } else { + if (sc->tulip_flags & TULIP_ALTPHYS) + printf("%s%d: enabling 10baseT/UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; + sc->tulip_flags &= ~TULIP_ALTPHYS; + } + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + *sc->tulip_csrs.csr_gp = TULIP_GP_PINS; + *sc->tulip_csrs.csr_gp = TULIP_GP_INIT; + if (sc->tulip_if.if_flags & IFF_ALTPHYS) { + if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) + printf("%s%d: enabling 100baseTX UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER; + sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; + sc->tulip_flags |= TULIP_ALTPHYS; + } else { + if (sc->tulip_flags & TULIP_ALTPHYS) + printf("%s%d: enabling 10baseT UTP port\n", + sc->tulip_if.if_name, sc->tulip_if.if_unit); + sc->tulip_cmdmode &= ~(TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER); + sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; + sc->tulip_flags &= ~TULIP_ALTPHYS; + } } *sc->tulip_csrs.csr_txlist = vtophys(&sc->tulip_txinfo.ri_first[0]); *sc->tulip_csrs.csr_rxlist = vtophys(&sc->tulip_rxinfo.ri_first[0]); *sc->tulip_csrs.csr_intr = 0; - *sc->tulip_csrs.csr_busmode = 0x4800; + *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_BURSTLEN_8LW + |TULIP_BUSMODE_CACHE_ALIGN8 + |(BYTE_ORDER != LITTLE_ENDIAN + ? TULIP_BUSMODE_BIGENDIAN + : 0); sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; /* @@ -277,12 +319,18 @@ tulip_reset( ri = &sc->tulip_rxinfo; ri->ri_nextin = ri->ri_nextout = ri->ri_first; ri->ri_free = ri->ri_max; - for (vmoff = vtophys(sc->tulip_rxspace), di = ri->ri_first; - di < ri->ri_last; di++, vmoff += TULIP_RXBUFSIZE) { - di->d_status |= TULIP_DSTS_OWNER; - di->d_length1 = TULIP_RXBUFSIZE; di->d_addr1 = vmoff; + for (di = ri->ri_first; di < ri->ri_last; di++) { + di->d_status = 0; + di->d_length1 = 0; di->d_addr1 = 0; di->d_length2 = 0; di->d_addr2 = 0; } + for (;;) { + struct mbuf *m; + IF_DEQUEUE(&sc->tulip_rxq, m); + if (m == NULL) + break; + m_freem(m); + } sc->tulip_intrmask = TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED @@ -311,6 +359,7 @@ tulip_init( } sc->tulip_cmdmode |= TULIP_CMD_TXRUN; if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { + tulip_rx_intr(sc); sc->tulip_cmdmode |= TULIP_CMD_RXRUN; sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; } else { @@ -370,39 +419,34 @@ tulip_rx_intr( struct ifnet *ifp = &sc->tulip_if; for (;;) { - tulip_desc_t *eop; - int total_len, ndescs; - caddr_t bufaddr = (caddr_t) sc->tulip_rxspace; + struct ether_header eh; + tulip_desc_t *eop = ri->ri_nextin; + int total_len = 0; + struct mbuf *m = NULL; + int accept = 0; - for (ndescs = 1, eop = ri->ri_nextin;; ndescs++) { - if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) - return; - - if (eop->d_status & TULIP_DSTS_RxLASTDESC) - break; - if (++eop == ri->ri_last) - eop = ri->ri_first; - } + if (sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) + goto queue_mbuf; - bufaddr += TULIP_RXBUFSIZE * (ri->ri_nextin - ri->ri_first); - total_len = ((eop->d_status >> 16) & 0x7FF) - 4; + if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) + break; + total_len = ((eop->d_status >> 16) & 0x7FF) - 4; + IF_DEQUEUE(&sc->tulip_rxq, m); if ((eop->d_status & TULIP_DSTS_ERRSUM) == 0) { - struct ether_header eh; - struct mbuf *m; #if TULIP_CHECK_RXCRC - unsigned crc = tulip_crc32(bufaddr, total_len); + unsigned crc = tulip_crc32(mtod(m, unsigned char *), total_len); if (~crc != *((unsigned *) &bufaddr[total_len])) { printf("de0: bad rx crc: %08x [rx] != %08x\n", *((unsigned *) &bufaddr[total_len]), ~crc); goto next; } #endif - eh = *(struct ether_header *) bufaddr; + eh = *mtod(m, struct ether_header *); #if NBPFILTER > 0 if (sc->tulip_bpf != NULL) { - bpf_tap(sc->tulip_bpf, bufaddr, total_len); + bpf_tap(sc->tulip_bpf, mtod(m, caddr_t), total_len); if ((eh.ether_dhost[0] & 1) == 0 && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr)) goto next; @@ -411,34 +455,58 @@ tulip_rx_intr( goto next; } #endif - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m != NULL) { - m->m_pkthdr.rcvif = ifp; - total_len -= sizeof(eh); - if (total_len > MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - ifp->if_ierrors++; - goto next; - } - } - bcopy(bufaddr + sizeof(eh), mtod(m, caddr_t), total_len); - m->m_len = m->m_pkthdr.len = total_len; - ether_input(ifp, &eh, m); - } else { - ifp->if_ierrors++; - } + accept = 1; } else { ifp->if_ierrors++; } -next: + next: ifp->if_ipackets++; - while (ndescs-- > 0) { - ri->ri_nextin->d_status |= TULIP_DSTS_OWNER; - if (++ri->ri_nextin == ri->ri_last) - ri->ri_nextin = ri->ri_first; + if (++ri->ri_nextin == ri->ri_last) + ri->ri_nextin = ri->ri_first; + queue_mbuf: + /* + * Either we are priming the TULIP with mbufs (m == NULL) + * or we are about to accept an mbuf for the upper layers + * so we need to allocate an mbuf to replace it. If we + * can't replace, then count it as an input error and reuse + * the mbuf. + */ + if (accept || m == NULL) { + struct mbuf *m0; + MGETHDR(m0, M_DONTWAIT, MT_DATA); + if (m0 != NULL) { + MCLGET(m0, M_DONTWAIT); + if ((m0->m_flags & M_EXT) == 0) { + m_freem(m0); + m0 = NULL; + } + } + if (accept) { + if (m0 != NULL) { + m->m_pkthdr.rcvif = ifp; + m->m_data += sizeof(struct ether_header); + m->m_len = m->m_pkthdr.len = total_len; + ether_input(ifp, &eh, m); + m = m0; + } else { + ifp->if_ierrors++; + } + } else { + m = m0; + } } + if (m == NULL) + break; + /* + * Now give the buffer to the TULIP and save in our + * receive queue. + */ + ri->ri_nextout->d_length1 = MCLBYTES - 4; + ri->ri_nextout->d_addr1 = vtophys(mtod(m, caddr_t)); + ri->ri_nextout->d_status = TULIP_DSTS_OWNER; + if (++ri->ri_nextout == ri->ri_last) + ri->ri_nextout = ri->ri_first; + IF_ENQUEUE(&sc->tulip_rxq, m); } } @@ -465,6 +533,7 @@ tulip_tx_intr( */ sc->tulip_flags &= ~TULIP_DOINGSETUP; if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { + tulip_rx_intr(sc); sc->tulip_cmdmode |= TULIP_CMD_RXRUN; sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; *sc->tulip_csrs.csr_status = TULIP_STS_RXSTOPPED; @@ -693,6 +762,94 @@ tulip_intr( } /* + * + */ + +void +tulip_delay_300ns( + tulip_softc_t *sc) +{ + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; + *sc->tulip_csrs.csr_busmode; *sc->tulip_csrs.csr_busmode; +} + +#define EMIT do { *sc->tulip_csrs.csr_srom_mii = csr; tulip_delay_300ns(sc); } while (0) + + +void +tulip_idle_srom( + tulip_softc_t *sc) +{ + unsigned bit, csr; + + csr = SROMSEL | SROMRD; EMIT; + csr ^= SROMCS; EMIT; + csr ^= SROMCLKON; EMIT; + + /* + * Write 25 cycles of 0 which will force the SROM to be idle. + */ + for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + } + csr ^= SROMCLKOFF; EMIT; + csr ^= SROMCS; EMIT; EMIT; + csr = 0; EMIT; +} + + +void +tulip_read_srom( + tulip_softc_t *sc) +{ + int idx; + const unsigned bitwidth = SROM_BITWIDTH; + const unsigned cmdmask = (SROMCMD_RD << bitwidth); + const unsigned msb = 1 << (bitwidth + 3 - 1); + unsigned lastidx = (1 << bitwidth) - 1; + int lowbit = 0; + + tulip_idle_srom(sc); + + for (idx = 0; idx <= lastidx; idx++) { + unsigned lastbit, data, bits, bit, csr; + csr = SROMSEL | SROMRD; EMIT; + csr ^= SROMCSON; EMIT; + csr ^= SROMCLKON; EMIT; + + lastbit = 0; + for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { + const unsigned thisbit = bits & msb; + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + if (thisbit != lastbit) { + csr ^= SROMDOUT; EMIT; /* clock low; invert data */ + } + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + lastbit = thisbit; + } + csr ^= SROMCLKOFF; EMIT; + + for (data = 0, bits = 0; bits < 16; bits++) { + data <<= 1; + csr ^= SROMCLKON; EMIT; /* clock high; data valid */ + data |= *sc->tulip_csrs.csr_srom_mii & SROMDIN ? 1 : 0; + csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ + } + sc->tulip_rombuf[idx*2] = data & 0xFF; + sc->tulip_rombuf[idx*2+1] = data >> 8; + csr = SROMSEL | SROMRD; EMIT; + csr = 0; EMIT; + } +} + +/* * This is the standard method of reading the DEC Address ROMS. */ static int @@ -704,12 +861,17 @@ tulip_read_macaddr( unsigned char tmpbuf[8]; static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; - *sc->tulip_csrs.csr_enetrom = 1; - for (idx = 0; idx < 32; idx++) { - int cnt = 0; - while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) - cnt++; - sc->tulip_rombuf[idx] = csr & 0xFF; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040 + || (tulip_chipids[sc->tulip_unit] == TULIP_DC21140 && sc->tulip_revinfo < 0x10)) { + *sc->tulip_csrs.csr_enetrom = 1; + for (idx = 0; idx < 32; idx++) { + int cnt = 0; + while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) + cnt++; + sc->tulip_rombuf[idx] = csr & 0xFF; + } + } else { + tulip_read_srom(sc); } if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { @@ -813,9 +975,9 @@ tulip_addr_filter( ETHER_NEXT_MULTI(step, enm); } sc->tulip_cmdmode |= TULIP_WANTHASH; - sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; - sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; - sp[42] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; + sp[39] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; + sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; + sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; } else { /* * Else can get perfect filtering for 16 addresses. @@ -969,17 +1131,34 @@ tulip_attach( ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; - *sc->tulip_csrs.csr_sia_connectivity = 0; - *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; - for (cnt = 0; cnt < 240000; cnt++) { - if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) - break; - DELAY(10); - } - if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { - ifp->if_flags |= IFF_ALTPHYS; - } else { - sc->tulip_flags |= TULIP_ALTPHYS; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + *sc->tulip_csrs.csr_sia_connectivity = 0; + *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; + for (cnt = 0; cnt < 240000; cnt++) { + if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) + break; + DELAY(10); + } + if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { + ifp->if_flags |= IFF_ALTPHYS; + } else { + sc->tulip_flags |= TULIP_ALTPHYS; + } + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + /* + * This is going to suck. + */ + *sc->tulip_csrs.csr_gp = TULIP_GP_PINS; + *sc->tulip_csrs.csr_gp = TULIP_GP_INIT; + *sc->tulip_csrs.csr_command |= TULIP_CMD_PORTSELECT + |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER; + *sc->tulip_csrs.csr_command &= ~TULIP_CMD_TXTHRSHLDCTL; + DELAY(1000000); + if (*sc->tulip_csrs.csr_gp & TULIP_GP_FASTMODE) { + ifp->if_flags |= IFF_ALTPHYS; + } else { + sc->tulip_flags |= TULIP_ALTPHYS; + } } TULIP_RESET(sc); @@ -1018,13 +1197,24 @@ tulip_initcsrs( sc->tulip_csrs.csr_command = va_csrs + 6 * csr_size; sc->tulip_csrs.csr_intr = va_csrs + 7 * csr_size; sc->tulip_csrs.csr_missed_frame = va_csrs + 8 * csr_size; - sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; - sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; - sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; - sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; - sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; - sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; - sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; + if (tulip_chipids[sc->tulip_unit] == TULIP_DC21040) { + sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; + sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; + sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; + sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; + sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; + sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; + sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; + } else if (tulip_chipids[sc->tulip_unit] == TULIP_DC21140) { + if (sc->tulip_revinfo < 0x10) + sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; + else + sc->tulip_csrs.csr_srom_mii = va_csrs + 9 * csr_size; + + sc->tulip_csrs.csr_gp_timer = va_csrs + 11 * csr_size; + sc->tulip_csrs.csr_gp = va_csrs + 12 * csr_size; + sc->tulip_csrs.csr_watchdog = va_csrs + 15 * csr_size; + } } static void @@ -1049,14 +1239,14 @@ tulip_initring( */ static char* tulip_pci_probe (pcici_t config_id, pcidi_t device_id); static void tulip_pci_attach(pcici_t config_id, int unit); -static u_long tulip_count; +static u_long tulip_pci_count; static int tulip_pci_shutdown(struct kern_devconf *, int); struct pci_device dedevice = { "de", tulip_pci_probe, tulip_pci_attach, - &tulip_count, + &tulip_pci_count, tulip_pci_shutdown, }; @@ -1077,19 +1267,20 @@ tulip_pci_probe( pcici_t config_id, pcidi_t device_id) { - int idx; - for (idx = 0; idx < NDE; idx++) { - if (tulips[idx] == NULL) { - if (device_id == 0x00021011ul) { - tulip_chipids[idx] = TULIP_DC21040; - return "Digital DC21040 Ethernet"; - } - if (device_id == 0x00091011ul) { - tulip_chipids[idx] = TULIP_DC21140; - return "Digital DC21140 Fast Ethernet"; - } - return NULL; - } + if (device_id == 0x00021011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21040; + return "Digital DC21040 Ethernet"; + } + if (device_id == 0x00141011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21041; + return "Digital DC21041 Ethernet"; + } + if (device_id == 0x00091011ul) { + if (tulip_pci_count < NDE) + tulip_chipids[tulip_pci_count] = TULIP_DC21140; + return "Digital DC21140 Fast Ethernet"; } return NULL; } @@ -1104,6 +1295,12 @@ tulip_pci_attach( vm_offset_t va_csrs, pa_csrs; tulip_desc_t *rxdescs, *txdescs; + if (unit >= NDE) { + printf("de%d: not configured; kernel is built for only %d device%s.\n", + unit, NDE, NDE == 1 ? "" : "s"); + return; + } + sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); if (sc == NULL) return; @@ -1124,32 +1321,21 @@ tulip_pci_attach( } bzero(sc, sizeof(*sc)); /* Zero out the softc*/ - sc->tulip_rxspace = vm_page_alloc_contig(TULIP_RXSPACE + NBPG, 0, 0xffffffff, PAGE_SIZE); - /* - * We've allocated an extra page of receive space so we can double map - * the first page of the receive space into the page after the last page - * of the receive space. This means that even if a receive wraps around - * the end of the receive space, it will still virtually contiguous and - * that greatly simplifies the recevie logic. - */ - pmap_enter(pmap_kernel(), sc->tulip_rxspace + TULIP_RXSPACE, - vtophys(sc->tulip_rxspace), VM_PROT_READ|VM_PROT_WRITE, TRUE); sc->tulip_unit = unit; sc->tulip_name = "de"; retval = pci_map_mem(config_id, PCI_CBMA, &va_csrs, &pa_csrs); if (!retval) { - kmem_free(kernel_map, sc->tulip_rxspace, TULIP_RXSPACE + NBPG); free((caddr_t) txdescs, M_DEVBUF); free((caddr_t) rxdescs, M_DEVBUF); free((caddr_t) sc, M_DEVBUF); return; } tulips[unit] = sc; + sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; tulip_initcsrs(sc, (volatile tulip_uint32_t *) va_csrs, TULIP_PCI_CSRSIZE); tulip_initring(sc, &sc->tulip_rxinfo, rxdescs, TULIP_RXDESCS); tulip_initring(sc, &sc->tulip_txinfo, txdescs, TULIP_TXDESCS); - sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV); if ((retval = tulip_read_macaddr(sc)) < 0) { printf("de%d: can't read ENET ROM (why=%d) (", sc->tulip_unit, retval); for (idx = 0; idx < 32; idx++) @@ -1168,18 +1354,19 @@ tulip_pci_attach( } static int -tulip_pci_shutdown(kdc, force) - struct kern_devconf *kdc; - int force; +tulip_pci_shutdown( + struct kern_devconf *kdc, + int force) { + if (kdc->kdc_unit < NDE) { tulip_softc_t *sc = tulips[kdc->kdc_unit]; - *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 33MHz that comes to two microseconds but wait a bit longer anyways) */ - (void) dev_detach(kdc); - return 0; + } + (void) dev_detach(kdc); + return 0; } #endif /* NPCI > 0 */ |