From owner-freebsd-bugs Sun Oct 5 07:50:14 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id HAA23277 for bugs-outgoing; Sun, 5 Oct 1997 07:50:14 -0700 (PDT) Received: (from gnats@localhost) by hub.freebsd.org (8.8.7/8.8.7) id HAA23266; Sun, 5 Oct 1997 07:50:06 -0700 (PDT) Resent-Date: Sun, 5 Oct 1997 07:50:06 -0700 (PDT) Resent-Message-Id: <199710051450.HAA23266@hub.freebsd.org> Resent-From: gnats (GNATS Management) Resent-To: freebsd-bugs Resent-Reply-To: FreeBSD-gnats@FreeBSD.ORG, nao@tom-yam.or.jp Received: from mail0.iij.ad.jp (mail0.iij.ad.jp [202.232.2.113]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id HAA22538 for ; Sun, 5 Oct 1997 07:47:10 -0700 (PDT) Received: from uucp1.iij.ad.jp (uucp1.iij.ad.jp [202.232.2.201]) by mail0.iij.ad.jp (8.8.5+2.7Wbeta5/3.5Wpl4-MAIL) with SMTP id XAA25400 for ; Sun, 5 Oct 1997 23:47:04 +0900 (JST) Received: (from uucp@localhost) by uucp1.iij.ad.jp (8.6.12+2.4W/3.3W9-UUCP) with UUCP id XAA14059 for FreeBSD-gnats-submit@freebsd.org; Sun, 5 Oct 1997 23:47:03 +0900 Received: (from nao@localhost) by miffy.tom-yam.or.jp (8.8.5/8.8.5) id XAA00665; Sun, 5 Oct 1997 23:42:51 +0900 (JST) Message-Id: <199710051442.XAA00665@miffy.tom-yam.or.jp> Date: Sun, 5 Oct 1997 23:42:51 +0900 (JST) From: nao@tom-yam.or.jp To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: kern/4693: ep bug fix Sender: owner-freebsd-bugs@FreeBSD.ORG X-Loop: FreeBSD.org Precedence: bulk >Number: 4693 >Category: kern >Synopsis: 3COM Etherlink III does not work if IRQ = 9. >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Oct 5 07:50:02 PDT 1997 >Last-Modified: >Originator: HAMADA Naoki >Organization: just for me >Release: FreeBSD 2.2.1-RELEASE i386 and later >Environment: 3COM 3C509, 3C509B and 3C579 Etherlink III adapters. >Description: An Etherlink III adapter failes to work. >How-To-Repeat: Set your adapter's IRQ to 9 with the setup program provided by 3COM (3C5X9CFG.EXE). >Fix: In page 7-20 of "Etherlink III Parallel Tasking ISA, EISA, Micro Channel, and PCMCIA Adapter Drivers Technical Reference, Manual Part No. 09-0398-002B" by 3COM tells that if the IRQ area of the Resource Configuration Register is 9, the corresponding IRQ line driver is enabled and if it is 2, the corresponding IRQ line driver is disabled. So we must get rid of the following lines in /sys/i386/isa/if_ep.c (near line 590). GO_WINDOW(0); -> if(irq == 9) -> irq = 2; SET_IRQ(BASE, irq); The following patches are intended to provide a fix for this bug and some other improvements. These remove previously integrated kluges to achieve higher performance, which are now obsolete. Private mbuf allocation scheme, messy calculations for RX_EARLY_THRESHOLD and TX_AVAILABLE_THRESHOLD (which made the driver rather instable when you use it with elder adapters) and remainders for ancient trailer packets are all removed. And one more fix. The ep driver occasionally generated pathological mbuf chain, which consists of tens of short mbufs. Now it generates sane mbuf chain. These patch give rock-solid stability, and even performance improvement for slow machines (from 5% to 15% on a 486DX4-75MHz machine). These are quite conservative and none of novel features are proviced. Already checked in several enviroments and all worked well. These patches are generated for 2.2.1-RELEASE, but applicable to 2.2-stable and current with subtle changes. Enjoy! - nao --- /sys/i386/isa/if_ep.c- Sat Jun 14 15:13:42 1997 +++ /sys/i386/isa/if_ep.c Sun Oct 5 17:11:56 1997 @@ -122,8 +122,6 @@ static struct ep_board * ep_look_for_board_at __P((struct isa_device *is)); static int ep_isa_attach __P((struct isa_device *)); static int epioctl __P((struct ifnet * ifp, int, caddr_t)); -static void epmbuffill __P((caddr_t, int)); -static void epmbufempty __P((struct ep_softc *)); static void epinit __P((struct ep_softc *)); static void epread __P((struct ep_softc *)); @@ -591,8 +589,6 @@ } GO_WINDOW(0); - if(irq == 9) - irq = 2; SET_IRQ(BASE, irq); ep_attach(sc); @@ -679,23 +675,7 @@ sdl->sdl_slen = 0; bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); } - /* we give some initial parameters */ - sc->rx_avg_pkt = 128; - /* - * NOTE: In all this I multiply everything by 64. - * W_s = the speed the CPU is able to write to the TX FIFO. - * T_s = the speed the board sends the info to the Ether. - * W_s/T_s = 16 (represents 16/64) => W_s = 25 % of T_s. - * This will give us for a packet of 1500 bytes - * tx_start_thresh=1125 and for a pkt of 64 bytes tx_start_threshold=48. - * We prefer to start thinking the CPU is much slower than the Ethernet - * transmission. - */ - sc->tx_rate = TX_INIT_RATE; - sc->tx_counter = 0; - sc->rx_latency = RX_INIT_LATENCY; - sc->rx_early_thresh = RX_INIT_EARLY_THRESH; #ifdef EP_LOCAL_STATS sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = @@ -756,6 +736,7 @@ outw(BASE + EP_COMMAND, RX_RESET); outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); /* Window 1 is operating window */ GO_WINDOW(1); @@ -836,31 +817,17 @@ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ - sc->tx_rate = TX_INIT_RATE; - sc->tx_counter = 0; - sc->rx_latency = RX_INIT_LATENCY; - sc->rx_early_thresh = RX_INIT_EARLY_THRESH; #ifdef EP_LOCAL_STATS sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; #endif ep_fset(F_RX_FIRST); - ep_frst(F_RX_TRAILER); if (sc->top) { m_freem(sc->top); sc->top = sc->mcur = 0; } - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | sc->rx_early_thresh); - - /* - * These clever computations look very interesting - * but the fixed threshold gives near no output errors - * and if it as low as 16 bytes it gives the max. throughput. - * We think that processor is anyway quicker than Ethernet - * (and this should be true for any 386 and higher) - */ - + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); /* @@ -868,9 +835,6 @@ * any that we had in case we're being called from intr or somewhere * else. */ - sc->last_mb = 0; - sc->next_mb = 0; - epmbuffill((caddr_t) sc, 0); GO_WINDOW(1); epstart(ifp); @@ -895,6 +859,7 @@ } s = splimp(); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); if (ifp->if_flags & IFF_OACTIVE) { splx(s); return; @@ -926,28 +891,18 @@ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { /* no room in FIFO */ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); - ifp->if_flags |= IFF_OACTIVE; - splx(s); - return; + /* make sure */ + if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { + ifp->if_flags |= IFF_OACTIVE; + splx(s); + return; + } } IF_DEQUEUE(&ifp->if_snd, m); outw(BASE + EP_W1_TX_PIO_WR_1, len); outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ - /* compute the Tx start threshold for this packet */ - sc->tx_start_thresh = len = - (((len * (64 - sc->tx_rate)) >> 6) & ~3) + 16; -#if 0 - /* - * The following string does something strange with the card and - * we get a lot of output errors due to it so it's commented out - * and we use fixed threshold (see above) - */ - - outw(BASE + EP_COMMAND, SET_TX_START_THRESH | len); -#endif - for (top = m; m != 0; m = m->m_next) if(ep_ftst(F_ACCESS_32_BITS)) { outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), @@ -975,13 +930,6 @@ ifp->if_timer=2; ifp->if_opackets++; m_freem(top); - /* - * Every 1024*4 packets we increment the tx_rate if we haven't had - * errors, that in the case it has abnormaly goten too low - */ - if (!(++sc->tx_counter & (1024 * 4 - 1)) && - sc->tx_rate < TX_INIT_MAX_RATE) - sc->tx_rate++; /* * Is another packet coming in? We don't want to overflow the tiny RX @@ -994,8 +942,7 @@ * back later */ if (ifp->if_snd.ifq_head) { - outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | - sc->tx_start_thresh); + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); } splx(s); return; @@ -1031,6 +978,7 @@ ifp = &sc->arpcom.ac_if; + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ rescan: @@ -1088,11 +1036,8 @@ if (status & TXS_SUCCES_INTR_REQ); else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) { outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); if (status & TXS_UNDERRUN) { - if (sc->tx_rate > 1) { - sc->tx_rate--; /* Actually in steps of 1/64 */ - sc->tx_counter = 0; /* We reset it */ - } #ifdef EP_LOCAL_STATS sc->tx_underrun++; #endif @@ -1163,24 +1108,17 @@ else sc->rx_overrunl++; #endif - if (sc->rx_latency < ETHERMTU) - sc->rx_latency += 16; } goto out; } rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; if (ep_ftst(F_RX_FIRST)) { - if (m = sc->mb[sc->next_mb]) { - sc->mb[sc->next_mb] = 0; - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - m->m_data = m->m_pktdat; - m->m_flags = M_PKTHDR; - } else { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (!m) - goto out; - } + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (!m) + goto out; + if (rx_fifo >= MINCLSIZE) + MCLGET(m, M_DONTWAIT); sc->top = sc->mcur = top = m; #define EROUND ((sizeof(struct ether_header) + 3) & ~3) #define EOFF (EROUND - sizeof(struct ether_header)) @@ -1197,9 +1135,6 @@ top = sc->top; m = sc->mcur; sc->cur_len += rx_fifo2; - if (ep_ftst(F_RX_TRAILER)) - /* We don't read the trailer */ - rx_fifo -= sizeof(struct ether_header); } /* Reads what is left in the RX FIFO */ @@ -1207,15 +1142,9 @@ lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); if (lenthisone == 0) { /* no room in this one */ mcur = m; - if (m = sc->mb[sc->next_mb]) { - sc->mb[sc->next_mb] = 0; - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - } else { - MGET(m, M_DONTWAIT, MT_DATA); - if (!m) - goto out; - } - + MGET(m, M_DONTWAIT, MT_DATA); + if (!m) + goto out; if (rx_fifo >= MINCLSIZE) MCLGET(m, M_DONTWAIT); m->m_len = 0; @@ -1241,76 +1170,24 @@ rx_fifo -= lenthisone; } - if (ep_ftst(F_RX_TRAILER)) {/* reads the trailer */ - if (m = sc->mb[sc->next_mb]) { - sc->mb[sc->next_mb] = 0; - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - m->m_data = m->m_pktdat; - m->m_flags = M_PKTHDR; - } else { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (!m) - goto out; - } - insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t), - sizeof(struct ether_header)); - m->m_len = sizeof(struct ether_header); - m->m_next = top; - sc->top = top = m; - /* XXX Accomodate for type and len from beginning of trailer */ - sc->cur_len -= (2 * sizeof(u_short)); - ep_frst(F_RX_TRAILER); - goto all_pkt; - } - if (status & ERR_RX_INCOMPLETE) { /* we haven't received the complete * packet */ sc->mcur = m; #ifdef EP_LOCAL_STATS sc->rx_no_first++; /* to know how often we come here */ #endif - /* - * Re-compute rx_latency, the factor used is 1/4 to go up and 1/32 to - * go down - */ - delta = rx_fifo2 - sc->rx_early_thresh; /* last latency seen LLS */ - delta -= sc->rx_latency;/* LLS - estimated_latency */ - if (delta >= 0) - sc->rx_latency += (delta / 4); - else - sc->rx_latency += (delta / 32); ep_frst(F_RX_FIRST); if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) { /* we see if by now, the packet has completly arrived */ goto read_again; } - /* compute rx_early_threshold */ - delta = (sc->rx_avg_pkt - sc->cur_len - sc->rx_latency - 16) & ~3; - if (delta < MIN_RX_EARLY_THRESHL) - delta = MIN_RX_EARLY_THRESHL; - - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | - (sc->rx_early_thresh = delta)); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH); return; } all_pkt: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); - /* - * recompute average packet's length, the factor used is 1/8 to go down - * and 1/32 to go up - */ - delta = sc->cur_len - sc->rx_avg_pkt; - if (delta > 0) - sc->rx_avg_pkt += (delta / 32); - else - sc->rx_avg_pkt += (delta / 8); - delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; - if (delta < MIN_RX_EARLY_THRESHF) - delta = MIN_RX_EARLY_THRESHF; - sc->rx_early_thresh = delta; ++ifp->if_ipackets; ep_fset(F_RX_FIRST); - ep_frst(F_RX_TRAILER); top->m_pkthdr.rcvif = &sc->arpcom.ac_if; top->m_pkthdr.len = sc->cur_len; @@ -1335,12 +1212,11 @@ sc->top = 0; } ep_fset(F_RX_FIRST); - ep_frst(F_RX_TRAILER); #ifdef EP_LOCAL_STATS sc->rx_bpf_disc++; #endif while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); return; } } @@ -1349,11 +1225,9 @@ eh = mtod(top, struct ether_header *); m_adj(top, sizeof(struct ether_header)); ether_input(ifp, eh, top); - if (!sc->mb[sc->next_mb]) - epmbuffill((caddr_t) sc, 0); sc->top = 0; while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); return; out: @@ -1365,14 +1239,9 @@ sc->rx_no_mbuf++; #endif } - delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; - if (delta < MIN_RX_EARLY_THRESHF) - delta = MIN_RX_EARLY_THRESHF; ep_fset(F_RX_FIRST); - ep_frst(F_RX_TRAILER); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | - (sc->rx_early_thresh = delta)); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); } /* @@ -1459,7 +1328,6 @@ if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~IFF_RUNNING; epstop(sc); - epmbufempty(sc); break; } else { /* reinitialize card on any parameter change */ @@ -1540,6 +1408,7 @@ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); outw(BASE + EP_COMMAND, RX_RESET); outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); outw(BASE + EP_COMMAND, C_INTR_LATCH); outw(BASE + EP_COMMAND, SET_RD_0_MASK); outw(BASE + EP_COMMAND, SET_INTR_MASK); @@ -1588,45 +1457,6 @@ for (i = 0; i < 16; i++) data = (data << 1) | (inw(id_port) & 1); return (data); -} - -/* - * We suppose this is always called inside a splimp(){...}splx() region - */ -static void -epmbuffill(sp, dummy_arg) - caddr_t sp; - int dummy_arg; -{ - struct ep_softc *sc = (struct ep_softc *) sp; - int i; - - i = sc->last_mb; - do { - if (sc->mb[i] == NULL) - MGET(sc->mb[i], M_DONTWAIT, MT_DATA); - if (sc->mb[i] == NULL) - break; - i = (i + 1) % MAX_MBS; - } while (i != sc->next_mb); - sc->last_mb = i; -} - -static void -epmbufempty(sc) - struct ep_softc *sc; -{ - int s, i; - - s = splimp(); - for (i = 0; i < MAX_MBS; i++) { - if (sc->mb[i]) { - m_freem(sc->mb[i]); - sc->mb[i] = NULL; - } - } - sc->last_mb = sc->next_mb = 0; - splx(s); } #endif /* NEP > 0 */ --- /sys/i386/isa/if_epreg.h- Tue Nov 12 18:08:33 1996 +++ /sys/i386/isa/if_epreg.h Sun Oct 5 17:45:55 1997 @@ -55,25 +55,13 @@ struct ep_softc { struct arpcom arpcom; /* Ethernet common part */ int ep_io_addr; /* i/o bus address */ -#define MAX_MBS 8 /* # of mbufs we keep around */ - struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ - int next_mb; /* Which mbuf to use next. */ - int last_mb; /* Last mbuf. */ struct mbuf *top, *mcur; - short tx_start_thresh; /* Current TX_start_thresh. */ - short tx_rate; - short tx_counter; - short rx_early_thresh; /* Current RX_early_thresh. */ - short rx_latency; - short rx_avg_pkt; short cur_len; u_short ep_connectors; /* Connectors on this card. */ u_char ep_connector; /* Configured connector. */ int stat; /* some flags */ int gone; /* adapter is not present (for PCCARD) */ #define F_RX_FIRST 0x1 -#define F_WAIT_TRAIL 0x2 -#define F_RX_TRAILER 0x4 #define F_PROMISC 0x8 #define F_ACCESS_32_BITS 0x100 @@ -108,9 +96,8 @@ #define TX_INIT_RATE 16 #define TX_INIT_MAX_RATE 64 #define RX_INIT_LATENCY 64 -#define RX_INIT_EARLY_THRESH 64 -#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */ -#define MIN_RX_EARLY_THRESHL 4 +#define RX_INIT_EARLY_THRESH 208 /* not less than MINCLSIZE */ +#define RX_NEXT_EARLY_THRESH 500 #define EEPROMSIZE 0x40 #define MAX_EEPROMBUSY 1000 >Audit-Trail: >Unformatted: