/* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* NOTE: * There are three outstanding bug/features in this implementation. * They may even be hardware misfeatures. The conditions are registered * by counters maintained by the software. * 1: over_write is a condition that means that the board wants to store * packets, but there is no room. So new packets are lost. What seems to * be happening is that we get an over_write condition, but there are no * or just a few packets in the board's ram. Also it seems that we get * several over_writes in a row. * 2: Since there is only one transmit buffer, we need a lock to indicate * whether it is in use. We clear this lock when we get a transmit interrupt. * Sometimes we go to transmit and although there is no transmit in progress, * the lock is set. (In this case, we just ignore the lock.) It would look * like we can miss transmit interrupts? * 3: We tried to clean up the unnecessary switches to bank 0. * Unfortunately, when you do an ifconfig "down", the system tend to lock up * a few seconds later (this was when DSF_RUNNING) was not being set before. * But even with DSF_RUNNING, on an EISA bus machine we ALWAYS lock up after * a few seconds. */ /* * Western Digital 8003E Mach Ethernet driver (for intel 80386) * Copyright (c) 1990 by Open Software Foundation (OSF). */ /* Copyright 1990 by Open Software Foundation, Cambridge, MA. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both the copyright notice and this permission notice appear in supporting documentation, and that the name of OSF or Open Software Foundation not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE #if NNS8390 > 0 #include #include #include #include #include #include #include #include #include #include "vm_param.h" #include #include #include #include #include #if MACH_TTD #include #endif /* MACH_TTD */ #define SPLNET spl6 int wd_debug = 0; int ns8390probe(); void ns8390attach(); int ns8390intr(); int ns8390init(); int ns8390output(); int ns8390ioctl(); int ns8390reset(); int ns8390rcv(); int ns8390watch(); int ns8390get_CURR(); int ns8390over_write(); struct bus_device *ns8390info[NNS8390]; /* ???? */ static vm_offset_t ns8390_std[NNS8390] = { 0 }; static struct bus_device *ns8390_info[NNS8390]; struct bus_driver ns8390driver = {ns8390probe, 0, ns8390attach, 0, ns8390_std, "ns8390", ns8390_info, 0, 0, 0}; int watchdog_id; char *wd8003_card = "wd"; char *elii_card = "el"; /* 2e0, 2a0, 280, 250, 350, 330, 310, 300*/ int elii_irq[8] = {5, 2, 2, 5, 5, 0x711, 0x711, 5}; int elii_bnc[8] = {1, 0, 1, 1, 0, 0x711, 0x711, 0}; /*int elii_bnc[8] = {0, 1, 1, 1, 1, 1, 0, 1}; */ typedef struct { #ifdef MACH_KERNEL struct ifnet ds_if; /* generic interface header */ u_char ds_addr[6]; /* Ethernet hardware address */ #else MACH_KERNEL struct arpcom ns8390_ac; #define ds_if ns8390_ac.ac_if #define ds_addr ns8390_ac.ac_enaddr #endif MACH_KERNEL int flags; int timer; int interrupt; char *nic; u_char address[ETHER_ADDR_SIZE]; short mode; int tbusy; char *sram; /* beginning of the shared memory RAM buffer */ int read_nxtpkt_ptr;/* pointer to next packet available */ int pstart; /* page start hold */ int pstop; /* page stop hold */ int tpsr; /* transmit page start hold */ int fifo_depth; /* NIC fifo threshold */ char *card; int board_id; } ns8390_softc_t; ns8390_softc_t ns8390_softc[NNS8390]; struct ns8390_cntrs { u_int ovw, jabber, crc, frame, miss, fifo, rcv; u_int xmt, xmti, busy, heart; } ns8390_cntrs[NNS8390]; #if MACH_TTD boolean_t ttd_poll_loop; int ns8390poll_receive(); int ns8390transmit_ttd(); #endif /* MACH_TTD */ #ifdef IF_CNTRS int ns_narp = 1, ns_arp = 0; int ns_ein[32], ns_eout[32]; int ns_lin[128/8], ns_lout[128/8]; static log_2(no) unsigned long no; { return ({ unsigned long _temp__; asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" : "=r" (_temp__) : "a" (no)); _temp__;}); } #endif IF_CNTRS /* Interrupts mask bits */ int imr_hold = DSIM_PRXE|DSIM_PTXE|DSIM_RXEE|DSIM_TXEE|DSIM_OVWE|DSIM_CNTE; /* * ns8390probe: * * This function "probes" or checks for the wd8003 board on the bus to see * if it is there. As far as I can tell, the best break between this * routine and the attach code is to simply determine whether the board * is configured in properly. Currently my approach to this is to test the * base I/O special offset for the Western Digital unique byte sequence * identifier. If the bytes match we assume board is there. * The config code expects to see a successful return from the probe * routine before attach will be called. * * input : address device is mapped to, and unit # being checked * output : a '1' is returned if the board exists, and a 0 otherwise * */ ns8390probe(port, dev) struct bus_device *dev; { caddr_t hdwbase = (caddr_t)dev->address; int unit = dev->unit; ns8390_softc_t *sp = &ns8390_softc[unit]; int tmp; int vendor_id; if ((unit < 0) || (unit > NNS8390)) { printf("ns8390 ethernet unit %d out of range\n", unit); return(0); } if (((u_char) inb(hdwbase+IFWD_LAR_0) == (u_char) WD_NODE_ADDR_0) && ((u_char) inb(hdwbase+IFWD_LAR_1) == (u_char) WD_NODE_ADDR_1) && ((u_char) inb(hdwbase+IFWD_LAR_2) == (u_char) WD_NODE_ADDR_2)) { ns8390info[unit] = dev; sp->card = wd8003_card; dev->name = wd8003_card; sp->nic = hdwbase + OFF_8390; /* enable mem access to board */ sp->board_id = wd80xxget_board_id(dev); *(sp->address) = inb(hdwbase+IFWD_LAR_0); *(sp->address + 1) = inb(hdwbase+IFWD_LAR_1); *(sp->address + 2) = inb(hdwbase+IFWD_LAR_2); *(sp->address + 3) = inb(hdwbase+IFWD_LAR_3); *(sp->address + 4) = inb(hdwbase+IFWD_LAR_4); *(sp->address + 5) = inb(hdwbase+IFWD_LAR_5); return (1); } /* checks the address of the board to verify that it is a WD */ /* try to avoid any NE2000 pretending to be an el II */ if (inb(hdwbase + 0x408) == 0xff) return 0; /* check vendor id */ tmp = inb(hdwbase + CTLR); outb(hdwbase + CTLR, CTLR_RST|CTLR_THIN); /* Reset it... */ outb(hdwbase + CTLR, CTLR_THIN); /* * Map the station addr PROM into the lower I/O ports. We now * check for both the old and new 3Com prefix */ outb(hdwbase + CTLR, CTLR_STA_ADDR|CTLR_THIN); vendor_id = inb(hdwbase)*0x10000 + inb(hdwbase + 1)*0x100 + inb(hdwbase + 2); /* Restore the register we frobbed. */ outb(hdwbase + CTLR, tmp); if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) return 0; if ((tmp = inb(hdwbase+BCFR))) { switch(tmp) { case (1<<7): sp->board_id = 7; break; /*irq5 xvcr*/ #ifdef not_currently_possible case (1<<6): sp->board_id = 6; break; case (1<<5): sp->board_id = 5; break; #endif not_currently_possible case (1<<4): sp->board_id = 4; break; case (1<<3): sp->board_id = 3; break; case (1<<2): sp->board_id = 2; break; /*irq2 bnc*/ case (1<<1): sp->board_id = 1; break; /*irq2 xvcr*/ case (1<<0): sp->board_id = 0; break; /*irq5 bnc*/ default: return 0; } switch (inb(hdwbase+PCFR)) { case (1<<7): dev->phys_address = 0xDC000; break; case (1<<6): dev->phys_address = 0xD8000; break; #ifdef not_currently_possible case (1<<5): dev->phys_address = 0xCC000; break; case (1<<4): dev->phys_address = 0xC8000; break; #endif not_currently_possible default: printf("EtherLink II with NO memory configured\n"); return 0; } ns8390info[unit] = dev; dev->sysdep1 = elii_irq[sp->board_id]; if (dev->sysdep1 == 2) dev->sysdep1 = 9; sp->card = elii_card; dev->name = elii_card; sp->nic = hdwbase; return 1; } return(0); } /* * ns8390attach: * * This function attaches a ns8390 board to the "system". The rest of * runtime structures are initialized here (this routine is called after * a successful probe of the board). Once the ethernet address is read * and stored, the board's ifnet structure is attached and readied. * * input : bus_device structure setup in autoconfig * output : board structs and ifnet is setup * */ void ns8390attach(dev) struct bus_device *dev; { ns8390_softc_t *sp; struct ifnet *ifp; u_char unit; int temp; take_dev_irq(dev); unit = (u_char)dev->unit; sp = &ns8390_softc[unit]; printf(", port = %x, spl = %d, pic = %d. ", dev->address, dev->sysdep, dev->sysdep1); if (sp->card == elii_card) { if (elii_bnc[sp->board_id]) printf("cheapernet "); else printf("ethernet "); } else printf("ethernet "); (volatile char *)sp->sram = (volatile char *) phystokv(dev->phys_address); dev->address = (vm_offset_t) phystokv(dev->address); sp->timer = -1; sp->flags = 0; sp->mode = 0; if (!ns8390hwrst(unit)) { printf("%s%d: attach(): reset failed.\n", sp->card, unit); return; } /* N.B. sp->address is not determined till * hwrst time. */ *(sp->ds_addr) = *(sp->address); *(sp->ds_addr + 1) = *(sp->address + 1); *(sp->ds_addr + 2) = *(sp->address + 2); *(sp->ds_addr + 3) = *(sp->address + 3); *(sp->ds_addr + 4) = *(sp->address + 4); *(sp->ds_addr + 5) = *(sp->address + 5); printf("id [%x:%x:%x:%x:%x:%x]", sp->address[0],sp->address[1],sp->address[2], sp->address[3],sp->address[4],sp->address[5]); ifp = &(sp->ds_if); ifp->if_unit = unit; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST; #ifdef MACH_KERNEL ifp->if_header_size = sizeof(struct ether_header); ifp->if_header_format = HDR_ETHERNET; ifp->if_address_size = 6; ifp->if_address = (char *)&sp->address[0]; if_init_queues(ifp); #else MACH_KERNEL ifp->if_name = sp->card; ifp->if_init = ns8390init; ifp->if_output = ns8390output; ifp->if_ioctl = ns8390ioctl; ifp->if_reset = ns8390reset; ifp->if_next = NULL; if_attach(ifp); #ifdef notdef watchdog_id = timeout(ns8390watch, &(ifp->if_unit), 20*HZ); #endif #endif MACH_KERNEL #ifdef MACH_KERNEL #if MACH_TTD if (!ttd_get_packet) { ttd_device_unit = unit; ttd_get_packet = ns8390poll_receive; ttd_send_packet = ns8390transmit_ttd; ttd_host_ether_id.array[0] = *(sp->address); ttd_host_ether_id.array[1] = *(sp->address + 1); ttd_host_ether_id.array[2] = *(sp->address + 2); ttd_host_ether_id.array[3] = *(sp->address + 3); ttd_host_ether_id.array[4] = *(sp->address + 4); ttd_host_ether_id.array[5] = *(sp->address + 5); } #endif /* MACH_TTD */ #endif /* MACH_KERNEL */ } /* * ns8390watch(): * */ int ns8390watch(b_ptr) caddr_t b_ptr; { int x, y, opri, unit; int temp_cr; caddr_t nic; unit = *b_ptr; #ifdef MACH_KERNEL timeout(ns8390watch,b_ptr,20*HZ); #else MACH_KERNEL watchdog_id = timeout(ns8390watch,b_ptr,20*HZ); #endif MACH_KERNEL nic = ns8390_softc[unit].nic; temp_cr = inb(nic+ds_cmd); outb(nic + ds_cmd, (temp_cr & 0x3f) | DSCM_PG0); printf("<<< ISR=%x CURR=%x rdnxt=%x BNDY=%x>>> ", inb(nic + ds0_isr), ns8390get_CURR(unit), ns8390_softc[unit].read_nxtpkt_ptr, inb(nic+ds0_bndy)); outb(nic+ds_cmd,temp_cr); } #ifdef MACH_KERNEL int ns8390start(); /* forward */ /*ARGSUSED*/ wd8003open(dev, flag) dev_t dev; int flag; { register int unit = minor(dev); if (ns8390_softc[unit].card != wd8003_card) return (ENXIO); if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); ns8390_softc[unit].ds_if.if_flags |= IFF_UP; ns8390init(unit); return(0); } eliiopen(dev, flag) dev_t dev; int flag; { register int unit = minor(dev); if (ns8390_softc[unit].card != elii_card) return (ENXIO); if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); ns8390_softc[unit].ds_if.if_flags |= IFF_UP; ns8390init(unit); return(0); } ns8390output(dev, ior) dev_t dev; io_req_t ior; { register int unit = minor(dev); if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); return (net_write(&ns8390_softc[unit].ds_if, ns8390start, ior)); } ns8390setinput(dev, receive_port, priority, filter, filter_count) dev_t dev; mach_port_t receive_port; int priority; filter_t filter[]; unsigned int filter_count; { register int unit = minor(dev); if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); return (net_set_filter(&ns8390_softc[unit].ds_if, receive_port, priority, filter, filter_count)); } #else MACH_KERNEL /* * ns8390output: * * This routine is called by the "if" layer to output a packet to * the network. This code resolves the local ethernet address, and * puts it into the mbuf if there is room. If not, then a new mbuf * is allocated with the header information and precedes the data * to be transmitted. The routine ns8390xmt() which actually * transmits the data expects the ethernet header to precede the * data in the mbuf. * * input: ifnet structure pointer, an mbuf with data, and address * to be resolved * output: mbuf is updated to hold enet address, or a new mbuf * with the address is added * */ ns8390output(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; { register ns8390_softc_t *is = &ns8390_softc[ifp->if_unit]; u_char edst[6]; struct in_addr idst; register struct mbuf *m = m0; register struct ether_header *eh; register int off; int usetrailers; int type, error; spl_t opri; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { printf("%s%d output(): Turning off board %d\n", is->card, ifp->if_unit); ns8390intoff(ifp->if_unit); error = ENETDOWN; goto bad; } switch (dst->sa_family) { #ifdef INET case AF_INET: idst = ((struct sockaddr_in *)dst)->sin_addr; if (!arpresolve(&is->ns8390_ac, m, &idst, edst, &usetrailers)){ return (0); /* if not yet resolved */ } off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; if (usetrailers && off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2 * sizeof (u_short)) { type = ETHERTYPE_TRAIL + (off>>9); m->m_off -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); goto gottrailertype; } type = ETHERTYPE_IP; off = 0; goto gottype; #endif #ifdef NS case AF_NS: type = ETHERTYPE_NS; bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), (caddr_t)edst, sizeof (edst)); off = 0; goto gottype; #endif case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); type = eh->ether_type; goto gottype; default: printf("%s%d output(): can't handle af%d\n", is->card, ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; } gottrailertype: /* * Packet to be sent as trailer: move first packet * (control information) to end of chain. */ while (m->m_next) m = m->m_next; m->m_next = m0; m = m0->m_next; m0->m_next = 0; m0 = m; gottype: /* * Add local net header. If no space in first mbuf, * allocate another. */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct ether_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_HEADER); if (m == 0) { error = ENOBUFS; goto bad; } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct ether_header); } else { m->m_off -= sizeof (struct ether_header); m->m_len += sizeof (struct ether_header); } eh = mtod(m, struct ether_header *); eh->ether_type = htons((u_short)type); bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); bcopy((caddr_t)is->address, (caddr_t)eh->ether_shost, sizeof(edst)); /* * Queue message on interface, and start output if interface * not yet active. */ opri = SPLNET(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(opri); m_freem(m); return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); /* * Some action needs to be added here for checking whether the * board is already transmitting. If it is, we don't want to * start it up (ie call ns8390start()). We will attempt to send * packets that are queued up after an interrupt occurs. Some * flag checking action has to happen here and/or in the start * routine. This note is here to remind me that some thought * is needed and there is a potential problem here. * */ ns8390start(ifp->if_unit); splx(opri); return (0); bad: m_freem(m0); return (error); } #endif MACH_KERNEL /* * ns8390reset: * * This routine is in part an entry point for the "if" code. Since most * of the actual initialization has already (we hope already) been done * by calling ns8390attach(). * * input : unit number or board number to reset * output : board is reset * */ int ns8390reset(unit) int unit; { ns8390_softc[unit].ds_if.if_flags &= ~IFF_RUNNING; return(ns8390init(unit)); } /* * ns8390init: * * Another routine that interfaces the "if" layer to this driver. * Simply resets the structures that are used by "upper layers". * As well as calling ns8390hwrst that does reset the ns8390 board. * * input : board number * output : structures (if structs) and board are reset * */ int ns8390init(unit) int unit; { struct ifnet *ifp; int stat; spl_t oldpri; ifp = &(ns8390_softc[unit].ds_if); #ifdef MACH_KERNEL #else MACH_KERNEL if (ifp->if_addrlist == (struct ifaddr *)0) { return; } #endif MACH_KERNEL oldpri = SPLNET(); if ((stat = ns8390hwrst(unit)) == TRUE) { ns8390_softc[unit].ds_if.if_flags |= IFF_RUNNING; ns8390_softc[unit].flags |= DSF_RUNNING; ns8390_softc[unit].tbusy = 0; ns8390start(unit); } else printf("%s%d init(): trouble resetting board %d\n", ns8390_softc[unit].card, unit); ns8390_softc[unit].timer = 5; splx(oldpri); return(stat); } /* * ns8390start: * * This is yet another interface routine that simply tries to output a * in an mbuf after a reset. * * input : board number * output : stuff sent to board if any there * */ ns8390start(unit) int unit; { register ns8390_softc_t *is = &ns8390_softc[unit]; struct ifnet *ifp; #ifdef MACH_KERNEL io_req_t m; #else MACH_KERNEL struct mbuf *m; #endif MACH_KERNEL if (is->tbusy) { caddr_t nic = ns8390_softc[unit].nic; if (!(inb(nic+ds_cmd) & DSCM_TRANS)) { is->tbusy = 0; ns8390_cntrs[unit].busy++; } else return; } ifp = &(ns8390_softc[unit].ds_if); IF_DEQUEUE(&ifp->if_snd, m); #ifdef MACH_KERNEL if (m != 0) #else MACH_KERNEL if (m != (struct mbuf *)0) #endif MACH_KERNEL { is->tbusy++; ns8390_cntrs[unit].xmt++; ns8390xmt(unit, m); } } #ifdef MACH_KERNEL /*ARGSUSED*/ ns8390getstat(dev, flavor, status, count) dev_t dev; int flavor; dev_status_t status; /* pointer to OUT array */ unsigned int *count; /* out */ { register int unit = minor(dev); if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); return (net_getstat(&ns8390_softc[unit].ds_if, flavor, status, count)); } ns8390setstat(dev, flavor, status, count) dev_t dev; int flavor; dev_status_t status; unsigned int count; { register int unit = minor(dev); register ns8390_softc_t *sp; if (unit < 0 || unit >= NNS8390 || ns8390_softc[unit].nic == 0) return (ENXIO); sp = &ns8390_softc[unit]; switch (flavor) { case NET_STATUS: { /* * All we can change are flags, and not many of those. */ register struct net_status *ns = (struct net_status *)status; int mode = 0; if (count < NET_STATUS_COUNT) return (D_INVALID_SIZE); if (ns->flags & IFF_ALLMULTI) mode |= MOD_ENAL; if (ns->flags & IFF_PROMISC) mode |= MOD_PROM; /* * Force a complete reset if the receive mode changes * so that these take effect immediately. */ if (sp->mode != mode) { sp->mode = mode; if (sp->flags & DSF_RUNNING) { sp->flags &= ~(DSF_LOCK | DSF_RUNNING); ns8390init(unit); } } break; } default: return (D_INVALID_OPERATION); } return (D_SUCCESS); } #else MACH_KERNEL /* * ns8390ioctl: * * This routine processes an ioctl request from the "if" layer * above. * * input : pointer the appropriate "if" struct, command, and data * output : based on command appropriate action is taken on the * ns8390 board(s) or related structures * return : error is returned containing exit conditions * */ int ns8390ioctl(ifp, cmd, data) struct ifnet *ifp; int cmd; caddr_t data; { register struct ifaddr *ifa = (struct ifaddr *)data; register ns8390_softc_t *is; int error; spl_t opri; short mode = 0; is = &ns8390_softc[ifp->if_unit]; opri = SPLNET(); error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ns8390init(ifp->if_unit); switch (ifa->ifa_addr.sa_family) { #ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break; #endif #ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(ds->ds_addr); else ???? ns8390seteh(ina->x_host.c_host, ns8390_softc[ifp->if_unit].base); break; } #endif } break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_ALLMULTI) mode |= MOD_ENAL; if (ifp->if_flags & IFF_PROMISC) mode |= MOD_PROM; /* * force a complete reset if the receive multicast/ * promiscuous mode changes so that these take * effect immediately. * */ if (is->mode != mode) { is->mode = mode; if (is->flags & DSF_RUNNING) { is->flags &= ~(DSF_LOCK|DSF_RUNNING); ns8390init(ifp->if_unit); } } if ((ifp->if_flags & IFF_UP) == 0 && is->flags & DSF_RUNNING) { printf("%s%d ioctl(): turning off board %d\n", is->card, ifp->if_unit); is->flags &= ~(DSF_LOCK | DSF_RUNNING); is->timer = -1; ns8390intoff(ifp->if_unit); ns8390over_write(ifp->if_unit); } else if (ifp->if_flags & IFF_UP && (is->flags & DSF_RUNNING) == 0) ns8390init(ifp->if_unit); break; #ifdef IF_CNTRS case SIOCCIFCNTRS: if (!suser()) { error = EPERM; break; } bzero((caddr_t)ns_ein, sizeof (ns_ein)); bzero((caddr_t)ns_eout, sizeof (ns_eout)); bzero((caddr_t)ns_lin, sizeof (ns_lin)); bzero((caddr_t)ns_lout, sizeof (ns_lout)); bzero((caddr_t)&ns_arp, sizeof (int)); bzero((caddr_t)&ns8390_cntrs, sizeof (ns8390_cntrs)); break; #endif IF_CNTRS default: error = EINVAL; } splx(opri); return (error); } #endif MACH_KERNEL /* * ns8390hwrst: * * This routine resets the ns8390 board that corresponds to the * board number passed in. * * input : board number to do a hardware reset * output : board is reset * */ int ns8390hwrst(unit) int unit; { caddr_t nic = ns8390_softc[unit].nic; int count; u_char stat; spl_t spl = SPLNET(); if (ns8390_softc[unit].card == wd8003_card && config_wd8003(unit) == FALSE) { printf("%s%d hwrst(): config_wd8003 failed.\n", ns8390_softc[unit].card, unit); splx(spl); return(FALSE); } if (ns8390_softc[unit].card == elii_card && config_3c503(unit) == FALSE) { printf("%s%d hwrst(): config_3c503 failed.\n", ns8390_softc[unit].card, unit); splx(spl); return(FALSE); } if (config_nic(unit) == FALSE) { printf("%s%d hwrst(): config_nic failed.\n", ns8390_softc[unit].card, unit); splx(spl); return(FALSE); } splx(spl); return(TRUE); } /* * ns8390intr: * * This function is the interrupt handler for the ns8390 ethernet * board. This routine will be called whenever either a packet * is received, or a packet has successfully been transfered and * the unit is ready to transmit another packet. * * input : board number that interrupted * output : either a packet is received, or a packet is transfered * */ int ns8390intr(unit) { int opri, i; int isr_status; int temp_cr; caddr_t nic = ns8390_softc[unit].nic; temp_cr = inb(nic+ds_cmd); outb(nic+ds_cmd, (temp_cr & 0x3f) | DSCM_PG0); outb(nic+ds0_imr, 0); /* stop board interrupts */ outb(nic+ds_cmd, temp_cr); while (isr_status = inb(nic+ds0_isr)) { outb(nic+ds0_isr, isr_status); /* clear interrupt status */ if ((isr_status & (DSIS_ROVRN|DSIS_RXE)) == DSIS_RXE) { int rsr = inb(nic+ds0_rsr); if (rsr & DSRS_DFR) ns8390_cntrs[unit].jabber++; if (rsr & ~(DSRS_DFR|DSRS_PHY|DSRS_FAE|DSRS_CRC|DSIS_RX)) printf("%s%d intr(): isr = %x, RSR = %x\n", ns8390_softc[unit].card, unit, isr_status, rsr); } else if (isr_status & DSIS_ROVRN) { ns8390_cntrs[unit].ovw++; ns8390over_write(unit); } if (isr_status & DSIS_RX) { /* DFR & PRX is possible */ ns8390rcv(unit); #if MACH_TTD if (kttd_active) ttd_poll_loop = FALSE; #endif /* MACH_TTD */ } if (isr_status & DSIS_TXE) { int tsr = inb(nic+ds0_tsr); tsr &= ~0x2; /* unadvertised special */ #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { if (tsr == (DSTS_CDH|DSTS_ABT)) ns8390_cntrs[unit].heart++; else printf("%s%d intr(): isr = %x, TSR = %x\n", ns8390_softc[unit].card, unit, isr_status, tsr); ns8390_softc[unit].tbusy = 0; ns8390start(unit); } } else if (isr_status & DSIS_TX) { #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { ns8390_cntrs[unit].xmti++; ns8390_softc[unit].tbusy = 0; ns8390start(unit); } } if (isr_status & DSIS_CTRS) { int c0 = inb(nic+ds0_cntr0); int c1 = inb(nic+ds0_cntr1); int c2 = inb(nic+ds0_cntr2); ns8390_cntrs[unit].frame += c0; ns8390_cntrs[unit].crc += c1; ns8390_cntrs[unit].miss += c2; #ifdef COUNTERS printf("%s%d intr(): isr = %x, FRAME %x, CRC %x, MISS %x\n", ns8390_softc[unit].card, unit, isr_status, c0, c1, c2); printf("%s%d intr(): TOTAL , FRAME %x, CRC %x, MISS %x\n", ns8390_softc[unit].card, unit, ns8390_cntrs[unit].frame, ns8390_cntrs[unit].crc, ns8390_cntrs[unit].miss); #endif COUNTERS outb(nic+ds0_isr, isr_status); /* clear interrupt status again */ } } temp_cr=inb(nic+ds_cmd); outb(nic+ds_cmd, (temp_cr & 0x3f) | DSCM_PG0); outb(nic+ds0_imr, imr_hold); outb(nic+ds_cmd, temp_cr); return(0); } /* * Called if on board buffer has been completely filled by ns8390intr. It stops * the board, reads in all the buffers that are currently in the buffer, and * then restart board. */ ns8390over_write(unit) int unit; { caddr_t nic = ns8390_softc[unit].nic; int no; int count = 0; outb(nic+ds_cmd, DSCM_NODMA|DSCM_STOP|DSCM_PG0); /* clear the receive buffer */ outb(nic+ds0_rbcr0, 0); outb(nic+ds0_rbcr1, 0); while ((!(inb (nic + ds0_isr) & DSIS_RESET)) && (count < 10000)) count++; if (count == 10000) { printf("%s%d: over_write(): would not reset.\n", ns8390_softc[unit].card, unit); } no = ns8390rcv(unit); #ifdef OVWBUG printf("%s%d over_write(): ns8390 OVW ... %d.\n", ns8390_softc[unit].card, unit, no); #endif OVWBUG outb(nic+ds0_tcr, DSTC_LB0); /* External loopback mode */ outb(nic+ds_cmd, DSCM_NODMA|DSCM_START|DSCM_PG0); outb(nic+ds0_tcr, 0); return; } /* * ns8390rcv: * * This routine is called by the interrupt handler to initiate a * packet transfer from the board to the "if" layer above this * driver. This routine checks if a buffer has been successfully * received by the ns8390. If so, it does the actual transfer of the * board data (including the ethernet header) into a packet (consisting * of an mbuf chain) and enqueues it to a higher level. * Then check again whether there are any packets in the receive ring, * if so, read the next packet, until there are no more. * * input : number of the board to check * output : if a packet is available, it is "sent up" */ ns8390rcv(unit) int unit; { register ns8390_softc_t *is = &ns8390_softc[unit]; register struct ifnet *ifp = &is->ds_if; caddr_t nic = is->nic; int packets = 0; struct ether_header eh; u_short mlen, len, bytes_in_mbuf, bytes; u_short remaining; int temp_cr; u_char *mb_p; int board_id = is->board_id; vm_offset_t hdwbase = ns8390info[unit]->address; spl_t s; /* calculation of pkt size */ int nic_overcount; /* NIC says 1 or 2 more than we need */ int pkt_size; /* calculated size of received data */ int wrap_size; /* size of data before wrapping it */ int header_nxtpkt_ptr; /* NIC's next pkt ptr in rcv header */ int low_byte_count; /* low byte count of read from rcv header */ int high_byte_count; /* calculated high byte count */ volatile char *sram_nxtpkt_ptr; /* mem location of next packet */ volatile char *sram_getdata_ptr; /* next location to be read */ #ifdef MACH_KERNEL ipc_kmsg_t new_kmsg; struct ether_header *ehp; struct packet_header *pkt; #else MACH_KERNEL struct mbuf *m, *tm; /* initial allocation of mem; temp */ #endif MACH_KERNEL #if MACH_TTD if (((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) && !kttd_active) { #else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { #endif /* MACH_TTD */ temp_cr = inb(nic+ds_cmd); /* get current CR value */ outb(nic+ds_cmd,((temp_cr & 0x3F)|DSCM_PG0|DSCM_STOP)); outb(nic+ds0_imr, 0); /* Interrupt Mask Register */ outb(nic+ds_cmd, temp_cr); return -1; } while(is->read_nxtpkt_ptr != ns8390get_CURR(unit)) { /* while there is a packet to read from the buffer */ if ((is->read_nxtpkt_ptr < is->pstart) || (is->read_nxtpkt_ptr >= is->pstop)) { ns8390hwrst(unit); return -1; } /* if next packet pointer is out of receive ring bounds */ #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { packets++; ns8390_cntrs[unit].rcv++; } sram_nxtpkt_ptr = (char *) (is->sram + (is->read_nxtpkt_ptr << 8)); /* get packet size and location of next packet */ header_nxtpkt_ptr = *(sram_nxtpkt_ptr + 1); header_nxtpkt_ptr &= 0xFF; low_byte_count = *(sram_nxtpkt_ptr + 2); low_byte_count &= 0xFF; if ((low_byte_count + NIC_HEADER_SIZE) > NIC_PAGE_SIZE) nic_overcount = 2; else nic_overcount = 1; if (header_nxtpkt_ptr > is->read_nxtpkt_ptr) { wrap_size = 0; high_byte_count = header_nxtpkt_ptr - is->read_nxtpkt_ptr - nic_overcount; } else { wrap_size = (int) (is->pstop - is->read_nxtpkt_ptr - nic_overcount); high_byte_count = is->pstop - is->read_nxtpkt_ptr + header_nxtpkt_ptr - is->pstart - nic_overcount; } pkt_size = (high_byte_count << 8) | (low_byte_count & 0xFF); /* does not seem to include NIC_HEADER_SIZE */ if (!pkt_size) { printf("%s%d rcv(): zero length.\n", ns8390_softc[unit].card, unit); goto next_pkt; } len = pkt_size; sram_getdata_ptr = sram_nxtpkt_ptr + NIC_HEADER_SIZE; if (board_id & IFWD_SLOT_16BIT) { #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { s = splhi(); } en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, &eh, sizeof(struct ether_header)); dis_16bit_access (hdwbase, board_id); #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { splx(s); } } else { bcopy16 (sram_getdata_ptr, &eh, sizeof(struct ether_header)); } sram_getdata_ptr += sizeof(struct ether_header); len -= (sizeof(struct ether_header) + 4); /* crc size */ #ifdef MACH_KERNEL #if MACH_TTD if (kttd_active) { new_kmsg = (ipc_kmsg_t)ttd_request_msg; }else #endif /* MACH_TTD */ { new_kmsg = net_kmsg_get(); if (new_kmsg == IKM_NULL) { /* * Drop the packet. */ is->ds_if.if_rcvdrops++; /* * not only do we want to return, we need to drop * the packet on the floor to clear the interrupt. */ ns8390lost_frame(unit); return;/* packets;*/ } } #if DEBUG_TTD dump_ether_header("ns8390wire",&eh); #endif /* DEBUG_TTD */ ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]); pkt = (struct packet_header *) (&net_kmsg(new_kmsg)->packet[0]); #if DEBUG_TTD printf("!ehp = 0x%x, pkt = 0x%x!",ehp, pkt); #endif /* DEBUG_TTD */ *ehp = eh; if (len > (wrap_size = (is->sram + (is->pstop << 8) - sram_getdata_ptr))) { /* if needs to wrap */ if (board_id & IFWD_SLOT_16BIT) { #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { s = splhi(); } en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, (char *) (pkt + 1), wrap_size); dis_16bit_access (hdwbase, board_id); #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { splx(s); } } else { bcopy (sram_getdata_ptr, (char *) (pkt + 1), wrap_size); } sram_getdata_ptr = (volatile char *) (is->sram + (is->pstart << 8)); } else { /* normal getting data from buffer */ wrap_size = 0; } if (board_id & IFWD_SLOT_16BIT) { #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { s = splhi(); } en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, (char *) (pkt + 1) + wrap_size, len - wrap_size); dis_16bit_access (hdwbase, board_id); #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { splx(s); } } else { bcopy (sram_getdata_ptr, (char *) (pkt + 1) + wrap_size, len - wrap_size); } pkt->type = ehp->ether_type; pkt->length = len + sizeof(struct packet_header); #if MACH_TTD /* * Don't want to call net_packet if we are polling * for a packet. */ if (!kttd_active) #endif /* MACH_TTD */ { /* * Hand the packet to the network module. */ net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg)); } #else MACH_KERNEL #define NEW #ifdef NEW m = (struct mbuf *) 0; eh.ether_type = ntohs(eh.ether_type); MGET(m, M_DONTWAIT, MT_DATA); if (m == (struct mbuf *) 0) { printf("%s%d rcv(): Lost frame\n", ns8390_softc[unit].card, unit); ns8390lost_frame(unit); /* update NIC pointers and registers */ return packets; } m->m_next = (struct mbuf *) 0; tm = m; m->m_len = MLEN; if (len > 2 * MLEN - sizeof (struct ifnet **)) { MCLGET(m); } *(mtod(tm, struct ifnet **)) = ifp; mlen = sizeof (struct ifnet **); bytes_in_mbuf = m->m_len - sizeof(struct ifnet **); mb_p = mtod(tm, u_char *) + sizeof (struct ifnet **); bytes = min(bytes_in_mbuf, len); remaining = (int) (is->sram + (is->pstop << 8) - sram_getdata_ptr); bytes = min(bytes, remaining); do { if (board_id & IFWD_SLOT_16BIT) { s = splhi(); en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, mb_p, bytes); dis_16bit_access (hdwbase, board_id); splx(s); } else { bcopy16 (sram_getdata_ptr, mb_p, bytes); } mlen += bytes; if (!(bytes_in_mbuf -= bytes)) { MGET(tm->m_next, M_DONTWAIT, MT_DATA); tm = tm->m_next; if (tm == (struct mbuf *)0) { printf("%s%d rcv(): No mbufs, lost frame\n", ns8390_softc[unit].card, unit); m_freem(m); /* free the mbuf chain */ ns8390lost_frame(unit); /* update NIC pointers and registers */ return; } mlen = 0; tm->m_len = MLEN; bytes_in_mbuf = MLEN; mb_p = mtod(tm, u_char *); } else mb_p += bytes; if (!(len -= bytes)) { tm->m_len = mlen; break; } else if (bytes == remaining) { sram_getdata_ptr = (volatile char *) (is->sram + (is->pstart << 8)); bytes = len; remaining = ETHERMTU; } else { sram_getdata_ptr += bytes; remaining -= bytes; } bytes = min(bytes_in_mbuf, len); bytes = min(bytes, remaining); } while(1); #else NEW m = (struct mbuf *) 0; eh.ether_type = ntohs(eh.ether_type); while ( len ) { if (m == (struct mbuf *) 0) { m = m_get(M_DONTWAIT, MT_DATA); if (m == (struct mbuf *) 0) { printf("%s%d rcv(): Lost frame\n", ns8390_softc[unit].card, unit); ns8390lost_frame(unit); /* update NIC pointers and registers */ return packets; } tm = m; tm->m_off = MMINOFF; /* * first mbuf in the packet must contain a pointer to the * ifnet structure. other mbufs that follow and make up * the packet do not need this pointer in the mbuf. * */ *(mtod(tm, struct ifnet **)) = ifp; tm->m_len = sizeof(struct ifnet **); /* end of first buffer of packet */ } else { tm->m_next = m_get(M_DONTWAIT, MT_DATA); tm = tm->m_next; if (tm == (struct mbuf *) 0) { printf("%s%d rcv(): No mbufs, lost frame\n", ns8390_softc[unit].card, unit); m_freem(m); /* free the mbuf chain */ ns8390lost_frame(unit); /* update NIC pointers and registers */ return packets; } tm->m_off = MMINOFF; tm->m_len = 0; } tlen = MIN( MLEN - tm->m_len, len); /* size of mbuf so you know how much you can copy from board */ tm->m_next = (struct mbuf *) 0; if (sram_getdata_ptr + tlen >= (volatile char *) (is->sram + (is->pstop << 8))) { /* if needs to wrap */ wrap_size = (int) (is->sram + (is->pstop << 8) - sram_getdata_ptr); if (board_id & IFWD_SLOT_16BIT) { s = splhi(); en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, mtod(tm, char*) + tm->m_len, wrap_size); dis_16bit_access (hdwbase, board_id); splx(s); } else { bcopy16 (sram_getdata_ptr, mtod(tm, char*) + tm->m_len, wrap_size); } tm->m_len += wrap_size; len -= wrap_size; sram_getdata_ptr = (volatile char *) (is->sram + (is->pstart << 8)); } else { /* normal getting data from buffer */ if (board_id & IFWD_SLOT_16BIT) { s = splhi(); en_16bit_access(hdwbase, board_id); bcopy16 (sram_getdata_ptr, mtod(tm, char*) + tm->m_len, tlen); dis_16bit_access (hdwbase, board_id); splx(s); } else { bcopy16 (sram_getdata_ptr, mtod(tm, char*) + tm->m_len, tlen); } sram_getdata_ptr += tlen; tm->m_len += tlen; len -= tlen; } } #endif NEW if (!ns8390send_packet_up(m, &eh, is)) m_freem(m); #ifdef IF_CNTRS ns_ein[log_2(pkt_size)]++; if (pkt_size < 128) ns_lin[(pkt_size)>>3]++; if (eh.ether_type == ETHERTYPE_ARP) { ns_arp++; if (ns_narp) { ns_ein[log_2(pkt_size)]--; if (pkt_size < 128) ns_lin[(pkt_size)>>3]--; } } #endif IF_CNTRS #endif MACH_KERNEL next_pkt: is->read_nxtpkt_ptr = *(sram_nxtpkt_ptr + 1); is->read_nxtpkt_ptr &= 0xFF; #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { temp_cr = inb(nic+ds_cmd); outb(nic+ds_cmd, (temp_cr & 0x3f) | DSCM_PG0); } if (is->read_nxtpkt_ptr == ns8390get_CURR(unit)) if (is->read_nxtpkt_ptr == is->pstart) outb(nic+ds0_bndy, is->pstop - 1); else outb(nic+ds0_bndy, is->read_nxtpkt_ptr - 1); else outb(nic+ds0_bndy, is->read_nxtpkt_ptr); #if MACH_TTD if (!kttd_active) #endif /* MACH_TTD */ { outb(nic+ds_cmd, temp_cr); } #if MACH_TTD /* * Hand the packet back to the TTD server, if active. */ if (kttd_active && pkt_size) return 1; #endif /* MACH_TTD */ } return packets; } #ifdef MACH_KERNEL #if MACH_TTD /* * Polling routines for the TTD debugger. */ int ns8390poll_receive(unit) int unit; { int s; int orig_cr; int orig_imr; int isr_status; int pkts; ttd_poll_loop = TRUE; /* * Should already in at splhigh. Is this necessary? XXX */ s = splhigh(); #if 0 if (kttd_debug) printf("ns8390poll_receive: beginning polling loop\n"); #endif /* DEBUG_TTD */ /* * Loop until packet arrives. */ while(ttd_poll_loop) { /* * Call intr routine */ ns8390intr(unit); } #if 0 if (kttd_debug) printf("ns8390poll_receive: got packet exiting loop\n"); #endif /* DEBUG_TTD */ splx(s); } int ns8390transmit_ttd(unit, packet, len) int unit; char * packet; int len; { ns8390_softc_t *is = &ns8390_softc[unit]; caddr_t nic = is->nic; u_short count = 0; /* amount of data already copied */ volatile char *sram_write_pkt; int board_id = is->board_id; caddr_t hdwbase = ns8390info[unit]->address; int s; int orig_cr; int orig_imr; int isr_status; boolean_t loop = TRUE; #if 0 dump_ipudpbootp("Beg of xmit",packet); #endif s = splhigh(); /* begining of physical address of transmition buffer */ sram_write_pkt = is->sram + is->tpsr * 0x100; count = len; if (board_id & IFWD_SLOT_16BIT) { en_16bit_access(hdwbase, board_id); bcopy16 (packet, sram_write_pkt, count); dis_16bit_access (hdwbase, board_id); } else { bcopy (packet, sram_write_pkt, count); } while (count < ETHERMIN+sizeof(struct ether_header)) { *(sram_write_pkt + count) = 0; count++; } outb(nic+ds_cmd, DSCM_NODMA|DSCM_START|DSCM_PG0); /* select page 0 */ outb(nic+ds0_tpsr, is->tpsr); /* xmt page start at 0 of RAM */ outb(nic+ds0_tbcr1, count >> 8); /* upper byte of count */ outb(nic+ds0_tbcr0, count & 0xFF); /* lower byte of count */ outb(nic+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START); /* start transmission */ ns8390intr(unit); splx(s); } #endif /* MACH_TTD */ #endif /* MACH_KERNEL */ #ifdef MACH_KERNEL #else MACH_KERNEL /* * Send a packet composed of an mbuf chain to the higher levels * */ ns8390send_packet_up(m, eh, is) struct mbuf *m; struct ether_header *eh; ns8390_softc_t *is; { register struct ifqueue *inq; spl_t opri; switch (eh->ether_type) { #ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: arpinput(&is->ns8390_ac, m); return(TRUE); #endif #ifdef NS case ETHERTYPE_NS: schednetisr(NETISR_NS); inq = &nsintrq; break; #endif default: return(FALSE); } opri = SPLNET(); if (IF_QFULL(inq)) { IF_DROP(inq); splx(opri); return(FALSE); } IF_ENQUEUE(inq, m); splx(opri); return(TRUE); } #endif MACH_KERNEL /* * ns8390lost_frame: * this routine called by ns8390read after memory for mbufs could not be * allocated. It sets the boundary pointers and registers to the next * packet location. */ ns8390lost_frame(unit) int unit; { ns8390_softc_t *is = &ns8390_softc[unit]; caddr_t nic = is->nic; volatile char *sram_nxtpkt_ptr; int temp_cr; sram_nxtpkt_ptr = (volatile char *) (is->sram + (is->read_nxtpkt_ptr << 8)); is->read_nxtpkt_ptr = *(sram_nxtpkt_ptr + 1); is->read_nxtpkt_ptr &= 0xFF; temp_cr = inb(nic+ds_cmd); outb(nic+ds_cmd, (temp_cr & 0x3f) | DSCM_PG0); /* update boundary register */ if (is->read_nxtpkt_ptr == ns8390get_CURR(unit)) if (is->read_nxtpkt_ptr == is->pstart) outb(nic+ds0_bndy, is->pstop - 1); else outb(nic+ds0_bndy, is->read_nxtpkt_ptr - 1); else outb(nic+ds0_bndy, is->read_nxtpkt_ptr); outb(nic+ds_cmd, temp_cr); return; } /* * ns8390get_CURR(): * * Returns the value of the register CURR, which points to the next * available space for NIC to receive from network unto receive ring. * */ int ns8390get_CURR(unit) int unit; { caddr_t nic = ns8390_softc[unit].nic; int temp_cr; int ret_val; spl_t s; s = SPLNET(); temp_cr = inb(nic+ds_cmd); /* get current CR value */ outb(nic+ds_cmd, ((temp_cr & 0x3F) | DSCM_PG1)); /* select page 1 registers */ ret_val = inb(nic+ds1_curr); /* read CURR value */ outb(nic+ds_cmd, temp_cr); splx(s); return (ret_val & 0xFF); } /* * ns8390xmt: * * This routine fills in the appropriate registers and memory * locations on the ns8390 board and starts the board off on * the transmit. * * input : board number of interest, and a pointer to the mbuf * output : board memory and registers are set for xfer and attention * */ ns8390xmt(unit, m) int unit; #ifdef MACH_KERNEL io_req_t m; #else MACH_KERNEL struct mbuf *m; #endif MACH_KERNEL { ns8390_softc_t *is = &ns8390_softc[unit]; caddr_t nic = is->nic; struct ether_header *eh; int i; int opri; u_short count = 0; /* amount of data already copied */ volatile char *sram_write_pkt; int board_id = is->board_id; vm_offset_t hdwbase = ns8390info[unit]->address; spl_t s; #ifdef MACH_KERNEL #else MACH_KERNEL register struct mbuf *tm_p; #endif MACH_KERNEL /* begining of physical address of transmition buffer */ sram_write_pkt = is->sram + is->tpsr * 0x100; #ifdef MACH_KERNEL count = m->io_count; if (board_id & IFWD_SLOT_16BIT) { s = splhi(); en_16bit_access(hdwbase, board_id); bcopy16 (m->io_data, sram_write_pkt, count); dis_16bit_access (hdwbase, board_id); splx(s); } else { bcopy (m->io_data, sram_write_pkt, count); } #else MACH_KERNEL for(tm_p = m; tm_p != (struct mbuf *)0; tm_p = tm_p->m_next) { if (count + tm_p->m_len > ETHERMTU + sizeof (struct ether_header)) break; if (tm_p->m_len == 0) continue; if (board_id & IFWD_SLOT_16BIT) { s = splhi(); en_16bit_access(hdwbase, board_id); bcopy16 (mtod(tm_p, caddr_t), sram_write_pkt + count, tm_p->m_len); dis_16bit_access (hdwbase, board_id); splx(s); } else { bcopy16 (mtod(tm_p, caddr_t), sram_write_pkt + count, tm_p->m_len); } count += tm_p->m_len; } #ifdef IF_CNTRS ns_eout[log_2(count+4/*crc*/)]++; if (count < 128) ns_lout[(count+4/*crc*/)>>3]++; #endif IF_CNTRS #endif MACH_KERNEL while (count < ETHERMIN+sizeof(struct ether_header)) { *(sram_write_pkt + count) = 0; count++; } /* select page 0 */ outb(nic+ds_cmd, DSCM_NODMA|DSCM_START|DSCM_PG0); outb(nic+ds0_tpsr, is->tpsr); /* xmt page start at 0 of RAM */ outb(nic+ds0_tbcr1, count >> 8); /* upper byte of count */ outb(nic+ds0_tbcr0, count & 0xFF); /* lower byte of count */ /* start transmission */ outb(nic+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START); #ifdef MACH_KERNEL iodone(m); m=0; #else MACH_KERNEL /* If this is a broadcast packet, loop it back to rcv. */ eh = mtod( m, struct ether_header *); for (i=0; ((i < 6) && (eh->ether_dhost[i] == 0xff)); i++) ; if (i == 6) { if (!ns8390send_packet_up(m, eh, is)) m_freem(m); } else m_freem(m); #endif MACH_KERNEL return; } config_nic(unit) int unit; { ns8390_softc_t *is = &ns8390_softc[unit]; caddr_t nic = is->nic; int i; int temp; int count = 0; spl_t s; /* soft reset and page 0 */ outb (nic+ds_cmd, DSCM_PG0|DSCM_NODMA|DSCM_STOP); while ((!(inb (nic + ds0_isr) & DSIS_RESET)) && (count < 10000)) count++; if (count == 10000) { printf("%s%d: config_nic(): would not reset.\n", ns8390_softc[unit].card, unit); } /* fifo depth | not loopback */ temp = ((is->fifo_depth & 0x0c) << 3) | DSDC_BMS; /* word xfer select (16 bit cards ) */ if (is->board_id & IFWD_SLOT_16BIT) temp |= DSDC_WTS; outb (nic+ds0_dcr, temp); outb (nic+ds0_tcr, 0); outb (nic+ds0_rcr, DSRC_MON); /* receive configuration register */ /* recieve ring starts 2k into RAM */ outb (nic+ds0_pstart, is->pstart); /* stop at last RAM buffer rcv location */ outb (nic+ds0_pstop, is->pstop); /* boundary pointer for page 0 */ outb (nic+ds0_bndy, is->pstart); s = SPLNET(); /* maintain rst | sel page 1 */ outb (nic+ds_cmd, DSCM_PG1|DSCM_NODMA|DSCM_STOP); /* internal next packet pointer */ is->read_nxtpkt_ptr = is->pstart + 1; outb (nic+ds1_curr, is->read_nxtpkt_ptr); /* Current page register */ for(i=0; iaddress[i]); for(i=0; i<8; i++) outb (nic+ds1_mar0+i, 0); outb (nic+ds_cmd, DSCM_PG0|DSCM_STOP|DSCM_NODMA); splx(s); outb (nic+ds0_isr, 0xff); /* clear all interrupt status bits */ outb (nic+ds0_imr, imr_hold); /* Enable interrupts */ outb (nic+ds0_rbcr0, 0); /* clear remote byte count */ outb (nic+ds0_rbcr1, 0); /* start NIC | select page 0 */ outb (nic+ds_cmd, DSCM_PG0|DSCM_START|DSCM_NODMA); outb (nic+ds0_rcr, DSRC_AB); /* receive configuration register */ return TRUE; } /* * config_ns8390: * * This routine does a standard config of a wd8003 family board, with * the proper modifications to different boards within this family. * */ config_wd8003(unit) int unit; { ns8390_softc_t *is = &ns8390_softc[unit]; vm_offset_t hdwbase = ns8390info[unit]->address; int i; int RAMsize; volatile char *RAMbase; int addr_temp; is->tpsr = 0; /* transmit page start hold */ is->pstart = 0x06; /* receive page start hold */ is->read_nxtpkt_ptr = is->pstart + 1; /* internal next packet pointer */ is->fifo_depth = 0x08; /* NIC fifo threshold */ switch (is->board_id & IFWD_RAM_SIZE_MASK) { case IFWD_RAM_SIZE_8K: RAMsize = 0x2000; break; case IFWD_RAM_SIZE_16K: RAMsize = 0x4000; break; case IFWD_RAM_SIZE_32K: RAMsize = 0x8000; break; case IFWD_RAM_SIZE_64K: RAMsize = 0x10000; break; default: RAMsize = 0x2000; break; } is->pstop = (((int)RAMsize >> 8) & 0x0ff); /* rcv page stop hold */ RAMbase = (volatile char *)ns8390info[unit]->phys_address; addr_temp = ((int)(RAMbase) >> 13) & 0x3f; /* convert to be written to MSR */ outb(hdwbase+IFWD_MSR, addr_temp | IFWD_MENB); /* initialize MSR */ /* enable 16 bit access from lan controller */ if (is->board_id & IFWD_SLOT_16BIT) { if (is->board_id & IFWD_INTERFACE_CHIP) { outb(hdwbase+IFWD_REG_5, (inb(hdwbase + IFWD_REG_5) & IFWD_REG5_MEM_MASK) | IFWD_LAN16ENB); } else { outb(hdwbase+IFWD_REG_5, (IFWD_LAN16ENB | IFWD_LA19)); } } /* outb(hdwbase+LAAR, LAN16ENB | LA19| MEM16ENB | SOFTINT); */ return TRUE; } /* * config_ns8390: * * This routine does a standard config of a 3 com etherlink II board. * */ int config_3c503(unit) int unit; { ns8390_softc_t *is = &ns8390_softc[unit]; struct bus_device *dev = ns8390info[unit]; vm_offset_t hdwbase = dev->address; int RAMsize = dev->am; int i; is->tpsr = 0x20; /* transmit page start hold */ is->sram = (char *)phystokv(dev->phys_address) - is->tpsr * 0x100; /* When NIC says page 20, this means go to the beginning of the sram range */ is->pstart = 0x26; /* receive page start hold */ is->read_nxtpkt_ptr = is->pstart + 1; /* internal next packet pointer */ is->fifo_depth = 0x08; /* NIC fifo threshold */ is->pstop = is->tpsr + ((RAMsize >> 8) & 0x0ff); /* rcv page stop hold */ outb(hdwbase+CTLR, CTLR_RST|CTLR_THIN); outb(hdwbase+CTLR, CTLR_THIN); outb(hdwbase+CTLR, CTLR_STA_ADDR|CTLR_THIN); for (i = 0; i < 6; i++) is->address[i] = inb(hdwbase+i); outb(hdwbase+CTLR, elii_bnc[is->board_id]?CTLR_THIN:CTLR_THICK); outb(hdwbase+PSTR, is->pstart); outb(hdwbase+PSPR, is->pstop); outb(hdwbase+IDCFR, IDCFR_IRQ2 << (elii_irq[is->board_id] - 2)); outb(hdwbase+GACFR, GACFR_TCM|GACFR_8K); /* BCFR & PCRFR ro */ /* STREG ro & dma */ outb(hdwbase+DQTR, 0); outb(hdwbase+DAMSB, 0); outb(hdwbase+DALSB, 0); outb(hdwbase+VPTR2, 0); outb(hdwbase+VPTR1, 0); outb(hdwbase+VPTR0, 0); outb(hdwbase+RFMSB, 0); outb(hdwbase+RFLSB, 0); return TRUE; } /* * ns8390intoff: * * This function turns interrupts off for the ns8390 board indicated. * */ void ns8390intoff(unit) int unit; { caddr_t nic = ns8390_softc[unit].nic; int temp_cr = inb(nic+ds_cmd); /* get current CR value */ outb(nic+ds_cmd,((temp_cr & 0x3F)|DSCM_PG0|DSCM_STOP)); outb(nic+ds0_imr, 0); /* Interrupt Mask Register */ outb(nic+ds_cmd, temp_cr|DSCM_STOP); } /* * wd80xxget_board_id: * * determine which board is being used. * Currently supports: * wd8003E (tested) * wd8003EBT * wd8003EP (tested) * wd8013EP (tested) * */ wd80xxget_board_id(dev) struct bus_device *dev; { vm_offset_t hdwbase = dev->address; long unit = dev->unit; long board_id = 0; int reg_temp; int rev_num; /* revision number */ int ram_flag; int intr_temp; int i; boolean_t register_aliasing; rev_num = (inb(hdwbase + IFWD_BOARD_ID) & IFWD_BOARD_REV_MASK) >> 1; printf("%s%d: ", ns8390_softc[unit].card, unit); if (rev_num == 0) { printf("rev 0x00\n"); /* It must be 8000 board */ return 0; } /* Check if register aliasing is true, that is reading from register offsets 0-7 will return the contents of register offsets 8-f */ register_aliasing = TRUE; for (i = 1; i < 5; i++) { if (inb(hdwbase + IFWD_REG_0 + i) != inb(hdwbase + IFWD_LAR_0 + i)) register_aliasing = FALSE; } if (inb(hdwbase + IFWD_REG_7) != inb(hdwbase + IFWD_CHKSUM)) register_aliasing = FALSE; if (register_aliasing == FALSE) { /* Check if board has interface chip */ reg_temp = inb(hdwbase + IFWD_REG_7); /* save old */ outb(hdwbase + IFWD_REG_7, 0x35); /* write value */ inb(hdwbase + IFWD_REG_0); /* dummy read */ if ((inb(hdwbase + IFWD_REG_7) & 0xff) == 0x35) { outb(hdwbase + IFWD_REG_7, 0x3a);/* Try another value*/ inb(hdwbase + IFWD_REG_0); /* dummy read */ if ((inb(hdwbase + IFWD_REG_7) & 0xff) == 0x3a) { board_id |= IFWD_INTERFACE_CHIP; outb(hdwbase + IFWD_REG_7, reg_temp); /* restore old value */ } } /* Check if board is 16 bit by testing if bit zero in register 1 is unchangeable by software. If so then card has 16 bit capability */ reg_temp = inb(hdwbase + IFWD_REG_1); outb(hdwbase + IFWD_REG_1, reg_temp ^ IFWD_16BIT); inb(hdwbase + IFWD_REG_0); /* dummy read */ if ((inb(hdwbase + IFWD_REG_1) & IFWD_16BIT) == (reg_temp & IFWD_16BIT)) { /* Is bit unchanged */ board_id |= IFWD_BOARD_16BIT; /* Yes == 16 bit */ reg_temp &= 0xfe; /* For 16 bit board always reset bit 0 */ } outb(hdwbase + IFWD_REG_1, reg_temp); /* write value back */ /* Test if 16 bit card is in 16 bit slot by reading bit zero in register 1. */ if (board_id & IFWD_BOARD_16BIT) { if (inb(hdwbase + IFWD_REG_1) & IFWD_16BIT) { board_id |= IFWD_SLOT_16BIT; } } } /* Get media type */ if (inb(hdwbase + IFWD_BOARD_ID) & IFWD_MEDIA_TYPE) { board_id |= IFWD_ETHERNET_MEDIA; } else if (rev_num == 1) { board_id |= IFWD_STARLAN_MEDIA; } else { board_id |= IFWD_TWISTED_PAIR_MEDIA; } if (rev_num == 2) { if (inb(hdwbase + IFWD_BOARD_ID) & IFWD_SOFT_CONFIG) { if ((board_id & IFWD_STATIC_ID_MASK) == WD8003EB || (board_id & IFWD_STATIC_ID_MASK) == WD8003W) { board_id |= IFWD_ALTERNATE_IRQ_BIT; } } /* Check for memory size */ ram_flag = inb(hdwbase + IFWD_BOARD_ID) & IFWD_MEMSIZE; switch (board_id & IFWD_STATIC_ID_MASK) { case WD8003E: /* same as WD8003EBT */ case WD8003S: /* same as WD8003SH */ case WD8003WT: case WD8003W: case WD8003EB: /* same as WD8003EP */ if (ram_flag) board_id |= IFWD_RAM_SIZE_32K; else board_id |= IFWD_RAM_SIZE_8K; break; case WD8003ETA: case WD8003STA: case WD8003EA: case WD8003SHA: case WD8003WA: board_id |= IFWD_RAM_SIZE_16K; break; case WD8013EBT: if (board_id & IFWD_SLOT_16BIT) { if (ram_flag) board_id |= IFWD_RAM_SIZE_64K; else board_id |= IFWD_RAM_SIZE_16K; } else { if (ram_flag) board_id |= IFWD_RAM_SIZE_32K; else board_id |= IFWD_RAM_SIZE_8K; } break; default: board_id |= IFWD_RAM_SIZE_UNKNOWN; break; } } else if (rev_num >= 3) { board_id &= (long) ~IFWD_MEDIA_MASK; /* remove media info */ board_id |= IFWD_INTERFACE_584_CHIP; board_id |= wd80xxget_eeprom_info(hdwbase, board_id); } else { /* Check for memory size */ if (board_id & IFWD_BOARD_16BIT) { if (board_id & IFWD_SLOT_16BIT) board_id |= IFWD_RAM_SIZE_16K; else board_id |= IFWD_RAM_SIZE_8K; } else if (board_id & IFWD_MICROCHANNEL) board_id |= IFWD_RAM_SIZE_16K; else if (board_id & IFWD_INTERFACE_CHIP) { if (inb(hdwbase + IFWD_REG_1) & IFWD_MEMSIZE) board_id |= IFWD_RAM_SIZE_32K; else board_id |= IFWD_RAM_SIZE_8K; } else board_id |= IFWD_RAM_SIZE_UNKNOWN; /* No support for 690 chip yet. It should be checked here */ } switch (board_id & IFWD_STATIC_ID_MASK) { case WD8003E: printf("WD8003E or WD8003EBT"); break; case WD8003S: printf("WD8003S or WD8003SH"); break; case WD8003WT: printf("WD8003WT"); break; case WD8003W: printf("WD8003W"); break; case WD8003EB: if (board_id & IFWD_INTERFACE_584_CHIP) printf("WD8003EP"); else printf("WD8003EB"); break; case WD8003EW: printf("WD8003EW"); break; case WD8003ETA: printf("WD8003ETA"); break; case WD8003STA: printf("WD8003STA"); break; case WD8003EA: printf("WD8003EA"); break; case WD8003SHA: printf("WD8003SHA"); break; case WD8003WA: printf("WD8003WA"); break; case WD8013EBT: printf("WD8013EBT"); break; case WD8013EB: if (board_id & IFWD_INTERFACE_584_CHIP) printf("WD8013EP"); else printf("WD8013EB"); break; case WD8013W: printf("WD8013W"); break; case WD8013EW: printf("WD8013EW"); break; default: printf("unknown"); break; } printf(" rev 0x%02x", rev_num); switch(board_id & IFWD_RAM_SIZE_RES_7) { case IFWD_RAM_SIZE_UNKNOWN: break; case IFWD_RAM_SIZE_8K: printf(" 8 kB ram"); break; case IFWD_RAM_SIZE_16K: printf(" 16 kB ram"); break; case IFWD_RAM_SIZE_32K: printf(" 32 kB ram"); break; case IFWD_RAM_SIZE_64K: printf(" 64 kB ram"); break; default: printf("wd: Internal error ram size value invalid %d\n", (board_id & IFWD_RAM_SIZE_RES_7)>>16); } if (board_id & IFWD_BOARD_16BIT) { if (board_id & IFWD_SLOT_16BIT) { printf(", in 16 bit slot"); } else { printf(", 16 bit board in 8 bit slot"); } } if (board_id & IFWD_INTERFACE_CHIP) { if (board_id & IFWD_INTERFACE_584_CHIP) { printf(", 584 chip"); } else { printf(", 583 chip"); } } if ((board_id & IFWD_INTERFACE_CHIP) == IFWD_INTERFACE_CHIP) { /* program the WD83C583 EEPROM registers */ int irr_temp, icr_temp; icr_temp = inb(hdwbase + IFWD_ICR); irr_temp = inb(hdwbase + IFWD_IRR); irr_temp &= ~(IFWD_IR0 | IFWD_IR1); irr_temp |= IFWD_IEN; icr_temp &= IFWD_WTS; if (!(board_id & IFWD_INTERFACE_584_CHIP)) { icr_temp |= IFWD_DMAE | IFWD_IOPE; if (ram_flag) icr_temp |= IFWD_MSZ; } if (board_id & IFWD_INTERFACE_584_CHIP) { switch(ns8390info[unit]->sysdep1) { case 10: icr_temp |= IFWD_DMAE; break; case 2: case 9: /* Same as 2 */ break; case 11: icr_temp |= IFWD_DMAE; /*FALLTHROUGH*/ case 3: irr_temp |= IFWD_IR0; break; case 15: icr_temp |= IFWD_DMAE; /*FALLTHROUGH*/ case 5: irr_temp |= IFWD_IR1; break; case 4: icr_temp |= IFWD_DMAE; /*FALLTHROUGH*/ case 7: irr_temp |= IFWD_IR0 | IFWD_IR1; break; default: printf("%s%d: wd80xx_get_board_id(): Could not set Interrupt Request Register according to pic(%d).\n", ns8390_softc[unit].card, unit, ns8390info[unit]->sysdep1); break; } } else { switch(ns8390info[unit]->sysdep1) { /* attempt to set interrupt according to assigned pic */ case 2: case 9: /* Same as 2 */ break; case 3: irr_temp |= IFWD_IR0; break; case 4: irr_temp |= IFWD_IR1; break; case 5: irr_temp |= IFWD_IR1 | IFWD_AINT; break; case 7: irr_temp |= IFWD_IR0 | IFWD_IR1; break; default: printf("%s%d: wd80xx_get_board_id(): Could not set Interrupt Request Register according to pic(%d).\n", ns8390_softc[unit].card, unit, ns8390info[unit]->sysdep1); } } outb(hdwbase + IFWD_IRR, irr_temp); outb(hdwbase + IFWD_ICR, icr_temp); } printf("\n"); return (board_id); } wd80xxget_eeprom_info(hdwbase, board_id) caddr_t hdwbase; long board_id; { unsigned long new_bits = 0; int reg_temp; outb(hdwbase + IFWD_REG_1, ((inb(hdwbase + IFWD_REG_1) & IFWD_ICR_MASK) | IFWD_OTHER_BIT)); outb(hdwbase + IFWD_REG_3, ((inb(hdwbase + IFWD_REG_3) & IFWD_EAR_MASK) | IFWD_ENGR_PAGE)); outb(hdwbase + IFWD_REG_1, ((inb(hdwbase + IFWD_REG_1) & IFWD_ICR_MASK) | (IFWD_RLA | IFWD_OTHER_BIT))); while (inb(hdwbase + IFWD_REG_1) & IFWD_RECALL_DONE_MASK) ; reg_temp = inb(hdwbase + IFWD_EEPROM_1); switch (reg_temp & IFWD_EEPROM_BUS_TYPE_MASK) { case IFWD_EEPROM_BUS_TYPE_AT: if (wd_debug & 1) printf("wd: AT bus, "); break; case IFWD_EEPROM_BUS_TYPE_MCA: if (wd_debug & 1) printf("wd: MICROCHANNEL, "); new_bits |= IFWD_MICROCHANNEL; break; default: break; } switch (reg_temp & IFWD_EEPROM_BUS_SIZE_MASK) { case IFWD_EEPROM_BUS_SIZE_8BIT: if (wd_debug & 1) printf("8 bit bus size, "); break; case IFWD_EEPROM_BUS_SIZE_16BIT: if (wd_debug & 1) printf("16 bit bus size "); new_bits |= IFWD_BOARD_16BIT; if (inb(hdwbase + IFWD_REG_1) & IFWD_16BIT) { new_bits |= IFWD_SLOT_16BIT; if (wd_debug & 1) printf("in 16 bit slot, "); } else { if (wd_debug & 1) printf("in 8 bit slot (why?), "); } break; default: if (wd_debug & 1) printf("bus size other than 8 or 16 bit, "); break; } reg_temp = inb(hdwbase + IFWD_EEPROM_0); switch (reg_temp & IFWD_EEPROM_MEDIA_MASK) { case IFWD_STARLAN_TYPE: if (wd_debug & 1) printf("Starlan media, "); new_bits |= IFWD_STARLAN_MEDIA; break; case IFWD_TP_TYPE: if (wd_debug & 1) printf("Twisted pair media, "); new_bits |= IFWD_TWISTED_PAIR_MEDIA; break; case IFWD_EW_TYPE: if (wd_debug & 1) printf("Ethernet and twisted pair media, "); new_bits |= IFWD_EW_MEDIA; break; case IFWD_ETHERNET_TYPE: /*FALLTHROUGH*/ default: if (wd_debug & 1) printf("ethernet media, "); new_bits |= IFWD_ETHERNET_MEDIA; break; } switch (reg_temp & IFWD_EEPROM_IRQ_MASK) { case IFWD_ALTERNATE_IRQ_1: if (wd_debug & 1) printf("Alternate irq 1\n"); new_bits |= IFWD_ALTERNATE_IRQ_BIT; break; default: if (wd_debug & 1) printf("\n"); break; } switch (reg_temp & IFWD_EEPROM_RAM_SIZE_MASK) { case IFWD_EEPROM_RAM_SIZE_8K: new_bits |= IFWD_RAM_SIZE_8K; break; case IFWD_EEPROM_RAM_SIZE_16K: if ((new_bits & IFWD_BOARD_16BIT) && (new_bits & IFWD_SLOT_16BIT)) new_bits |= IFWD_RAM_SIZE_16K; else new_bits |= IFWD_RAM_SIZE_8K; break; case IFWD_EEPROM_RAM_SIZE_32K: new_bits |= IFWD_RAM_SIZE_32K; break; case IFWD_EEPROM_RAM_SIZE_64K: if ((new_bits & IFWD_BOARD_16BIT) && (new_bits & IFWD_SLOT_16BIT)) new_bits |= IFWD_RAM_SIZE_64K; else new_bits |= IFWD_RAM_SIZE_32K; break; default: new_bits |= IFWD_RAM_SIZE_UNKNOWN; break; } outb(hdwbase + IFWD_REG_1, ((inb(hdwbase + IFWD_REG_1) & IFWD_ICR_MASK) | IFWD_OTHER_BIT)); outb(hdwbase + IFWD_REG_3, ((inb(hdwbase + IFWD_REG_3) & IFWD_EAR_MASK) | IFWD_EA6)); outb(hdwbase + IFWD_REG_1, ((inb(hdwbase + IFWD_REG_1) & IFWD_ICR_MASK) | IFWD_RLA)); return (new_bits); } wdpr(unit) { caddr_t nic = ns8390_softc[unit].nic; spl_t s; int temp_cr; s = SPLNET(); temp_cr = inb(nic+ds_cmd); /* get current CR value */ printf("CR %x, BNDRY %x, TSR %x, NCR %x, FIFO %x, ISR %x, RSR %x\n", inb(nic+0x0), inb(nic+0x3), inb(nic+0x4), inb(nic+0x5), inb(nic+0x6), inb(nic+0x7), inb(nic+0xc)); printf("CLD %x:%x, CRD %x:%x, FR %x, CRC %x, Miss %x\n", inb(nic+0x1), inb(nic+0x2), inb(nic+0x8), inb(nic+0x9), inb(nic+0xd), inb(nic+0xe), inb(nic+0xf)); outb(nic, (temp_cr&0x3f)|DSCM_PG1); /* page 1 CR value */ printf("PHYS %x:%x:%x:%x:%x CUR %x\n", inb(nic+0x1), inb(nic+0x2), inb(nic+0x3), inb(nic+0x4), inb(nic+0x5), inb(nic+0x6), inb(nic+0x7)); printf("MAR %x:%x:%x:%x:%x:%x:%x:%x\n", inb(nic+0x8), inb(nic+0x9), inb(nic+0xa), inb(nic+0xb), inb(nic+0xc), inb(nic+0xd), inb(nic+0xe), inb(nic+0xf)); outb(nic, temp_cr); /* restore current CR value */ splx(s); } /* This sets bit 7 (0 justified) of register offset 0x05. It will enable the host to access shared RAM 16 bits at a time. It will also maintain the LAN16BIT bit high in addition, this routine maintains address bit 19 (previous cards assumed this bit high...we must do it manually) note 1: this is a write only register note 2: this routine should be called only after interrupts are disabled and they should remain disabled until after the routine 'dis_16bit_access' is called */ en_16bit_access (hdwbase, board_id) caddr_t hdwbase; long board_id; { if (board_id & IFWD_INTERFACE_CHIP) outb(hdwbase+IFWD_REG_5, (inb(hdwbase+IFWD_REG_5) & IFWD_REG5_MEM_MASK) | IFWD_MEM16ENB | IFWD_LAN16ENB); else outb(hdwbase+IFWD_REG_5, (IFWD_MEM16ENB | IFWD_LAN16ENB | IFWD_LA19)); } /* This resets bit 7 (0 justified) of register offset 0x05. It will disable the host from accessing shared RAM 16 bits at a time. It will maintain the LAN16BIT bit high in addition, this routine maintains address bit 19 (previous cards assumed this bit high...we must do it manually) note: this is a write only register */ dis_16bit_access (hdwbase, board_id) caddr_t hdwbase; long board_id; { if (board_id & IFWD_INTERFACE_CHIP) outb(hdwbase+IFWD_REG_5, ((inb(hdwbase+IFWD_REG_5) & IFWD_REG5_MEM_MASK) | IFWD_LAN16ENB)); else outb(hdwbase+IFWD_REG_5, (IFWD_LAN16ENB | IFWD_LA19)); } #endif