From 75e0beaff360b19816b4c3a15f7d67479f634388 Mon Sep 17 00:00:00 2001 From: ats Date: Sat, 3 Sep 1994 18:10:44 +0000 Subject: Reviewed by: Submitted by: Update the if_ep driver for the 3C579 and bring over some of the changes from the netbsd driver. This is not complete: the detection of the irq in the eisa does not work and sometimes the reset for the 3C509 in ISA in an EISA bus system don't work ( Need a hard reset to be found again == reset knob). --- sys/dev/ep/if_ep.c | 303 ++++++++++++++++++++++++++++++++++++++------------ sys/dev/ep/if_epreg.h | 21 +++- 2 files changed, 247 insertions(+), 77 deletions(-) (limited to 'sys/dev/ep') diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c index 57e17691..7544de8 100644 --- a/sys/dev/ep/if_ep.c +++ b/sys/dev/ep/if_ep.c @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $ - * $Id: if_ep.c,v 1.10 1994/05/25 08:59:10 rgrimes Exp $ + * $Id: if_ep.c,v 1.11 1994/08/08 13:33:14 davidg Exp $ */ #include "ep.h" @@ -72,6 +72,13 @@ #include #include #include +#include + +/* For backwards compatibility */ +#ifndef IFF_ALTPHYS +#define IFF_ALTPHYS IFF_LINK0 +#endif + #define ETHER_MIN_LEN 64 #define ETHER_MAX_LEN 1518 @@ -82,13 +89,14 @@ */ struct ep_softc { struct arpcom arpcom; /* Ethernet common part */ - short ep_io_addr; /* i/o bus address */ + ushort ep_iobase; /* i/o bus address */ char ep_connectors; /* Connectors on this card. */ #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. */ int tx_start_thresh; /* Current TX_start_thresh. */ + int tx_succ_ok; /* # packets sent in sequence w/o underrun */ caddr_t bpf; /* BPF "magic cookie" */ char bus32bit; /* 32bit access possible */ } ep_softc[NEP]; @@ -99,8 +107,8 @@ static int epioctl __P((struct ifnet * ifp, int, caddr_t)); void epinit __P((int)); void epintr __P((int)); -void epmbuffill __P((caddr_t)); -void epmbufempty __P((struct ep_softc *)); +void epmbuffill __P((void *)); +static void epmbufempty __P((struct ep_softc *)); void epread __P((struct ep_softc *)); void epreset __P((int)); void epstart __P((struct ifnet *)); @@ -114,53 +122,194 @@ struct isa_driver epdriver = { }; static int send_ID_sequence __P((u_short)); -static u_short get_eeprom_data __P((int, int)); -static int is_eeprom_busy __P((struct isa_device *)); +static u_short epreadeeprom __P((int, int)); +static int epbusyeeprom __P((int, ushort)); + + +#define MAXEPCARDS 20 /* if you have 21 cards in your machine... you lose */ + +static struct epcard { + int iobase; + u_short irq; + char available; + char bus32bit; +} epcards[MAXEPCARDS]; + +static int nepcards; + +static void +epaddcard(p, i, mode) + short p; + u_short i; + char mode; +{ + if (nepcards >= sizeof(epcards)/sizeof(epcards[0])) + return; + epcards[nepcards].iobase = p; + epcards[nepcards].irq = 1 << ((i == 2) ? 9 : i); + epcards[nepcards].available = 1; + epcards[nepcards].bus32bit = mode; + nepcards++; +} + /* - * Rudimentary support for multiple cards is here but is not - * currently handled. In the future we will have to add code - * for tagging the cards for later activation. We wanna do something - * about the id_port. We're limited due to current config procedure. - * Magnum config holds promise of a fix but we'll have to wait a bit. + * 3c579 cards on the EISA bus are probed by their slot number. 3c509 + * cards on the ISA bus are probed in ethernet address order. The probe + * sequence requires careful orchestration, and we'd like like to allow + * the irq and base address to be wildcarded. So, we probe all the cards + * the first time epprobe() is called. On subsequent calls we look for + * matching cards. */ int epprobe(is) struct isa_device *is; { struct ep_softc *sc = &ep_softc[is->id_unit]; - u_short k; - int id_port = 0x100; /* XXX */ + static int probed; + int slot, iobase, i; + u_short k, k2; + u_short prodid; + + if (probed==0) { + probed = 1; + + /* find all EISA cards */ + for (slot = 1; slot < 16; slot++) { + iobase = 0x1000 * slot; + outw(iobase + EP_COMMAND, GLOBAL_RESET); + DELAY(1000); + if (inw(iobase + EISA_VENDOR) != MFG_ID) + continue; + k = inw(iobase + EISA_MODEL); +#ifdef EP_DEBUG +printf("prod id = %x ", k); +prodid = k; +#endif + if ((k & 0xf0ff) != PROD_ID) + continue; + + k = inw(iobase + EP_W0_CONFIG_CTRL); + /* enable adapter */ + outw(iobase + EP_W0_CONFIG_CTRL, k | 1); +#ifdef EP_DEBUG +printf("config = %x ", k); +#endif - outw(BASE + EP_COMMAND, GLOBAL_RESET); - DELAY(1000); - outb(id_port, 0xc0); /* Global reset to id_port. */ - DELAY(1000); - send_ID_sequence(id_port); - DELAY(1000); + /* read in eeprom address configuration */ + if (epbusyeeprom(slot - 1, iobase)) + continue; + outw(iobase + EP_W0_EEPROM_COMMAND, READ_EEPROM | EEPROM_ADDR_CFG); + if (epbusyeeprom(slot - 1, iobase)) + continue; + k = inw(iobase + EP_W0_EEPROM_DATA); +#ifdef EP_DEBUG +printf("addr_cfg = %x ", k); +#endif + outw(iobase + EP_W0_ADDRESS_CFG, k); + /* read in eeprom resource configuration */ + if (epbusyeeprom(slot - 1, iobase)) + continue; + outw(iobase + EP_W0_EEPROM_COMMAND, READ_EEPROM | EEPROM_RESOURCE_CFG); + if (epbusyeeprom(slot - 1, iobase)) + continue; + k2 = inw(iobase + EP_W0_EEPROM_DATA); + +#ifdef EP_DEBUG +/** XXXXXXXXXXXXXXXXXXXXX*/ +/* This doesn't give back the actual IRQ number as it should be , ATS */ +/* In the moment simply hardcoded the IRQ's for testing purposes */ +printf("resource config = %x\n", k2); +if (prodid == 0x9150) /* the 3c509 card */ + k2 = 7 << 12; +else + k2 = 3 << 12; /* the eisa 3c579 card set to irq 3 */ +#endif - /* - * MFG_ID should have 0x6d50. - * PROD_ID should be 0x9[0-f]50 - */ - k = get_eeprom_data(id_port, EEPROM_MFG_ID); - if (k != MFG_ID) - return (0); - k = get_eeprom_data(id_port, EEPROM_PROD_ID); - if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) - return (0); + outw(iobase + EP_W0_RESOURCE_CFG, k2); + epaddcard(iobase, k2 >> 12, 1); + } - k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */ - k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */ - if (k != (u_short)is->id_iobase) - return (0); + /* find all isa cards */ +#ifdef 0 + outw(BASE + EP_COMMAND, GLOBAL_RESET); +#endif + DELAY(1000); + elink_reset(); /* global reset to ELINK_ID_PORT */ + DELAY(1000); - k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); - k >>= 12; - if (is->id_irq != (1 << ((k == 2) ? 9 : k))) - return (0); + for (slot = 0; slot < 10; slot++) { + outb(ELINK_ID_PORT, 0x00); + elink_idseq(ELINK_509_POLY); + DELAY(1000); + + k = epreadeeprom(ELINK_ID_PORT, EEPROM_MFG_ID); + if (k != MFG_ID) + continue; + k = epreadeeprom(ELINK_ID_PORT, EEPROM_PROD_ID); + if ((k & 0xf0ff) != PROD_ID) + continue; + + k = epreadeeprom(ELINK_ID_PORT, EEPROM_ADDR_CFG); + k = (k & 0x1f) * 0x10 + 0x200; + + k2 = epreadeeprom(ELINK_ID_PORT, EEPROM_RESOURCE_CFG); + k2 >>= 12; + epaddcard(k, k2, 0); + + /* so card will not respond to contention again */ + outb(ELINK_ID_PORT, TAG_ADAPTER_0 + 1); + + /* + * XXX: this should probably not be done here + * because it enables the drq/irq lines from + * the board. Perhaps it should be done after + * we have checked for irq/drq collisions? + */ + outb(ELINK_ID_PORT, ACTIVATE_ADAPTER_TO_CONFIG); + } + /* XXX should we sort by ethernet address? */ + } - outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); + /* + * a very specific search order: + * exact iobase & irq + * exact iobase, wildcard irq + * wildcard iobase, exact irq + * wildcard iobase & irq + * else fail.. + */ + if (is->id_iobase != 0 && is->id_irq != (u_short)0) { + for (i = 0; iid_iobase == epcards[i].iobase && + is->id_irq == epcards[i].irq) + goto good; + } + } + if (is->id_iobase != 0 && is->id_irq == (u_short)0) { + for (i = 0; iid_iobase == epcards[i].iobase) + goto good; + } + } + if (is->id_iobase == 0 && is->id_irq != (u_short)0) { + for (i = 0; iid_irq == epcards[i].irq) + goto good; + } + } + return 0; + +good: + epcards[i].available = 0; + sc->bus32bit = epcards[i].bus32bit; + is->id_iobase = epcards[i].iobase; return (0x10); /* 16 bytes of I/O space used. */ } @@ -175,7 +324,7 @@ epattach(is) struct ifaddr *ifa; struct sockaddr_dl *sdl; - sc->ep_io_addr = is->id_iobase; + sc->ep_iobase = is->id_iobase; printf("ep%d: ", is->id_unit); @@ -206,10 +355,10 @@ epattach(is) for (i = 0; i < 3; i++) { u_short *p; GO_WINDOW(0); - if (is_eeprom_busy(is)) + if (epbusyeeprom(is->id_unit, sc->ep_iobase)) return(0); outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i); - if (is_eeprom_busy(is)) + if (epbusyeeprom(is->id_unit, sc->ep_iobase)) return(0); p =(u_short *)&sc->arpcom.ac_enaddr[i*2]; *p = htons(inw(BASE + EP_W0_EEPROM_DATA)); @@ -221,7 +370,8 @@ epattach(is) ifp->if_unit = is->id_unit; ifp->if_name = "ep"; ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | + IFF_MULTICAST ; ifp->if_init = epinit; ifp->if_output = ether_output; ifp->if_start = epstart; @@ -250,6 +400,9 @@ epattach(is) #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif + + sc->tx_start_thresh = 20; /* probably a good starting point. */ + return 1; } @@ -304,7 +457,7 @@ epinit(unit) S_TX_COMPLETE | S_TX_AVAIL); outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | - FIL_GROUP | FIL_BRDCST); + FIL_MULTICAST | FIL_BRDCST); /* * you can `ifconfig (link0|-link0) ep0' to get the following @@ -338,7 +491,6 @@ epinit(unit) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ - sc->tx_start_thresh = 20; /* probably a good starting point. */ /* * Store up a bunch of mbuf's for use later. (MAX_MBS). First we * free up any that we had in case we're being called from intr or @@ -346,7 +498,7 @@ epinit(unit) */ sc->last_mb = 0; sc->next_mb = 0; - epmbuffill((caddr_t)sc, 0); + epmbuffill((void *)sc); epstart(ifp); @@ -404,7 +556,10 @@ startagain: sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; splx(s); return; + } else { + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 2044); } + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); if (m == 0) { /* not really needed */ splx(s); @@ -418,17 +573,20 @@ startagain: for (top = m; m != 0; m = m->m_next) { if (sc->bus32bit) { - outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), - m->m_len/4); - if (m->m_len & 3) + if(m->m_len > 3) + outsl(BASE + EP_W1_TX_PIO_WR_1, + mtod(m, caddr_t), m->m_len/4); + if(m->m_len & 3) outsb(BASE + EP_W1_TX_PIO_WR_1, - mtod(m, caddr_t) + m->m_len/4, - m->m_len & 3); + mtod(m, caddr_t) + (m->m_len & ~3), m->m_len & 3); } else { - outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2); + if (m->m_len > 1) + outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), + m->m_len/2); if (m->m_len & 1) outb(BASE + EP_W1_TX_PIO_WR_1, - *(mtod(m, caddr_t) + m->m_len - 1)); + *(mtod(m, caddr_t) + m->m_len - 1)); + } } while (pad--) @@ -673,21 +831,23 @@ epread(sc) lenthisone = min(totlen, M_TRAILINGSPACE(m)); } if (sc->bus32bit) { - insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, - lenthisone / 4); - m->m_len += (lenthisone & ~3); - if (lenthisone & 3) + if(totlen > 3) { + lenthisone &= ~3; + insl(BASE + EP_W1_RX_PIO_RD_1, + mtod(m, caddr_t) + m->m_len, lenthisone / 4); + } else insb(BASE + EP_W1_RX_PIO_RD_1, - mtod(m, caddr_t) + m->m_len, - lenthisone & 3); - m->m_len += (lenthisone & 3); + mtod(m, caddr_t) + m->m_len, lenthisone); } else { - insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, - lenthisone / 2); - m->m_len += lenthisone; - if (lenthisone & 1) - *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); + if (totlen > 1) { + lenthisone &= ~1; + insw(BASE + EP_W1_RX_PIO_RD_1, + mtod(m, caddr_t) + m->m_len, lenthisone / 2); + } else + *(mtod(m, caddr_t) + m->m_len) = + inb(BASE + EP_W1_RX_PIO_RD_1); } + m->m_len += lenthisone; totlen -= lenthisone; } if (off) { @@ -927,7 +1087,7 @@ loop1: cx--; * bit of data with each read. */ static u_short -get_eeprom_data(id_port, offset) +epreadeeprom(id_port, offset) int id_port; int offset; { @@ -940,25 +1100,24 @@ get_eeprom_data(id_port, offset) } static int -is_eeprom_busy(is) - struct isa_device *is; +epbusyeeprom(unit, base) + int unit; ushort base; { int i = 0, j; - register struct ep_softc *sc = &ep_softc[is->id_unit]; while (i++ < 100) { - j = inw(BASE + EP_W0_EEPROM_COMMAND); + j = inw(base + EP_W0_EEPROM_COMMAND); if (j & EEPROM_BUSY) DELAY(100); else break; } if (i >= 100) { - printf("\nep%d: eeprom failed to come ready.\n", is->id_unit); + printf("\nep%d: eeprom failed to come ready.\n", unit); return (1); } if (j & EEPROM_TST_MODE) { - printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit); + printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", unit); return (1); } return (0); @@ -966,7 +1125,7 @@ is_eeprom_busy(is) void epmbuffill(sp) - caddr_t sp; + void *sp; { struct ep_softc *sc = (struct ep_softc *)sp; int s, i; diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h index f0b4cd9..2b2bcb9 100644 --- a/sys/dev/ep/if_epreg.h +++ b/sys/dev/ep/if_epreg.h @@ -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_epreg.h,v 1.1 1993/12/14 04:26:47 hpeyerl Exp $ + * $Id: if_epreg.h,v 1.2 1994/01/10 19:13:50 ats Exp $ */ /************************************************************************** * * @@ -181,9 +181,9 @@ #define SET_RD_0_MASK (u_short) (0xf<<11) #define SET_RX_FILTER (u_short) (0x10<<11) # define FIL_INDIVIDUAL (u_short) (0x1) -# define FIL_GROUP (u_short) (0x2) +# define FIL_MULTICAST (u_short) (0x2) # define FIL_BRDCST (u_short) (0x4) -# define FIL_ALL (u_short) (0x8) +# define FIL_PROMISC (u_short) (0x8) #define SET_RX_EARLY_THRESH (u_short) (0x11<<11) #define SET_TX_AVAIL_THRESH (u_short) (0x12<<11) #define SET_TX_START_THRESH (u_short) (0x13<<11) @@ -276,8 +276,8 @@ #define ACTIVATE_ADAPTER_TO_CONFIG 0xff #define ENABLE_DRQ_IRQ 0x0001 #define MFG_ID 0x6d50 -#define PROD_ID 0x9150 -#define BASE sc->ep_io_addr +#define PROD_ID 0x9050 +#define BASE sc->ep_iobase #define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|x) #define AUI 0x1 #define BNC 0x2 @@ -293,3 +293,14 @@ #define ENABLE_UTP 0xc0 #define DISABLE_UTP 0x0 #define RX_BYTES_MASK (u_short) (0x07ff) + + +/* + * EISA registers (offset from slot base) + */ +#define EISA_VENDOR 0x0c80 /* vendor ID (2 ports) */ +#define EISA_MODEL 0x0c82 /* model number (2 ports) */ +#define EISA_CONTROL 0x0c84 +#define EISA_RESET 0x04 +#define EISA_ERROR 0x02 +#define EISA_ENABLE 0x01 -- cgit v1.1