153897Smckusick /* 253897Smckusick * Copyright (c) 1992 The Regents of the University of California. 353897Smckusick * All rights reserved. 453897Smckusick * 553897Smckusick * This code is derived from software contributed to Berkeley by 653897Smckusick * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 753897Smckusick * 853897Smckusick * %sccs.include.redist.c% 953897Smckusick * 1053897Smckusick * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY 1153897Smckusick * 12*58612Sutashiro * @(#)if_en.c 7.7 (Berkeley) 03/09/93 1353897Smckusick */ 1453897Smckusick 1553897Smckusick #include "en.h" 1653897Smckusick #include "rawether.h" 1753897Smckusick #include "bpfilter.h" 1853897Smckusick 1953897Smckusick #if NEN > 0 2053897Smckusick 2153897Smckusick /* 2253897Smckusick * Interlan Ethernet Communications Controller interface 2353897Smckusick */ 2457180Sutashiro #include <sys/types.h> 2557180Sutashiro #include <machine/pte.h> 2653897Smckusick 2757180Sutashiro #include <sys/param.h> 2857180Sutashiro #include <sys/systm.h> 2957180Sutashiro #include <sys/mbuf.h> 3057180Sutashiro #include <sys/buf.h> 3157180Sutashiro #include <sys/protosw.h> 3257180Sutashiro #include <sys/socket.h> 3357180Sutashiro #include <sys/ioctl.h> 3457180Sutashiro #include <sys/errno.h> 3557180Sutashiro #include <sys/time.h> 3657180Sutashiro #include <sys/cdefs.h> 3753897Smckusick 3857180Sutashiro #include <net/if.h> 3957180Sutashiro #include <net/netisr.h> 4057180Sutashiro #include <net/route.h> 4153897Smckusick 4253897Smckusick #ifdef INET 4357180Sutashiro #include <netinet/in.h> 4457180Sutashiro #include <netinet/in_systm.h> 4557180Sutashiro #include <netinet/in_var.h> 4657180Sutashiro #include <netinet/ip.h> 4757180Sutashiro #include <netinet/if_ether.h> 4853897Smckusick #endif 4953897Smckusick 5057180Sutashiro #include <news3400/if/if_news.h> 5157180Sutashiro #include <news3400/if/if_en.h> 5253897Smckusick 5353897Smckusick #ifdef CPU_SINGLE 5457180Sutashiro #include <news3400/hbdev/hbvar.h> 5553897Smckusick #define iop_device hb_device 5653897Smckusick #define iop_driver hb_driver 5753897Smckusick #define ii_unit hi_unit 5853897Smckusick #define ii_intr hi_intr 5953897Smckusick #define ii_alive hi_alive 6053897Smckusick #else 6157180Sutashiro #include <news3400/iop/iopvar.h> 6253897Smckusick #endif 6353897Smckusick 6453897Smckusick int enprobe(), enattach(), enrint(), enxint(); 6553897Smckusick struct mbuf *m_devget(); 6653897Smckusick 6753897Smckusick #ifdef CPU_SINGLE 6853897Smckusick struct hb_device *eninfo[NEN]; 6953897Smckusick struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo }; 7053897Smckusick #else 7153897Smckusick struct iop_device *eninfo[NEN]; 7253897Smckusick struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo }; 7353897Smckusick #endif 7453897Smckusick 7553897Smckusick #define ENUNIT(x) minor(x) 7653897Smckusick 7754473Sutashiro int eninit(),enioctl(),enreset(),enwatch(),enstart(); 7853897Smckusick int endebug = 0; 7953897Smckusick 8053897Smckusick struct ether_addr { 8153897Smckusick u_char addr[6]; 8253897Smckusick }; 8353897Smckusick 8453897Smckusick extern struct ifnet loif; 8553897Smckusick 8653897Smckusick struct en_softc en_softc[NEN]; 8753897Smckusick 8853897Smckusick #if NBPFILTER > 0 8957180Sutashiro #include <net/bpf.h> 9053897Smckusick #endif 9153897Smckusick 9253897Smckusick enprobe(ii) 9353897Smckusick struct iop_device *ii; 9453897Smckusick { 9553897Smckusick 9653897Smckusick return (en_probe(ii)); 9753897Smckusick } 9853897Smckusick 9953897Smckusick /* 10053897Smckusick * Interface exists: make available by filling in network interface 10153897Smckusick * record. System will initialize the interface when it is ready 10253897Smckusick * to accept packets. A STATUS command is done to get the ethernet 10353897Smckusick * address and other interesting data. 10453897Smckusick */ 10553897Smckusick enattach(ii) 10653897Smckusick register struct iop_device *ii; 10753897Smckusick { 10853897Smckusick register struct en_softc *es = &en_softc[ii->ii_unit]; 10953897Smckusick register struct ifnet *ifp = &es->es_if; 11053897Smckusick extern char *ether_sprintf(); 11153897Smckusick 11253897Smckusick en_attach(ii->ii_unit); 11353897Smckusick printf("en%d: hardware address %s\n", 11453897Smckusick ii->ii_unit, ether_sprintf((u_char *)es->es_addr)); 11553897Smckusick ifp->if_unit = ii->ii_unit; 11653897Smckusick ifp->if_name = "en"; 11753897Smckusick ifp->if_mtu = ETHERMTU; 11853897Smckusick ifp->if_init = eninit; 11953897Smckusick ifp->if_ioctl = enioctl; 12053897Smckusick ifp->if_output = ether_output; 12153897Smckusick #ifdef NOTDEF /* KU:XXX if_reset is obsolete */ 12253897Smckusick ifp->if_reset = enreset; 12353897Smckusick #endif 12453897Smckusick ifp->if_start = enstart; 12554517Sutashiro ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 12653897Smckusick #if NBPFILTER > 0 12754517Sutashiro bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 12853897Smckusick #endif 12953897Smckusick if_attach(ifp); 13053897Smckusick } 13153897Smckusick 13253897Smckusick /* 13353897Smckusick * Reset of interface after IOP reset. 13453897Smckusick */ 13553897Smckusick enreset(unit) 13653897Smckusick int unit; 13753897Smckusick { 13853897Smckusick register struct iop_device *ii; 13953897Smckusick 14053897Smckusick if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0) 14153897Smckusick return; 14253897Smckusick printf(" en%d", unit); 14353897Smckusick en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 14453897Smckusick en_softc[unit].es_flags &= ~ENF_RUNNING; 14553897Smckusick eninit(unit); 14653897Smckusick } 14753897Smckusick 14853897Smckusick /* 14953897Smckusick * Initialization of interface; clear recorded pending 15053897Smckusick * operations, and reinitialize IOP usage. 15153897Smckusick */ 15253897Smckusick eninit(unit) 15353897Smckusick int unit; 15453897Smckusick { 15553897Smckusick register struct en_softc *es = &en_softc[unit]; 15653897Smckusick register struct ifnet *ifp = &es->es_if; 15753897Smckusick int s; 15853897Smckusick 15953897Smckusick /* not yet, if address still unknown */ 16053897Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 16153897Smckusick return; 16253897Smckusick if (es->es_flags & ENF_RUNNING) 16353897Smckusick return; 16453897Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 16553897Smckusick if (if_newsinit(&es->es_ifnews, 16653897Smckusick sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) { 16753897Smckusick printf("en%d: can't initialize\n", unit); 16853897Smckusick es->es_if.if_flags &= ~IFF_UP; 16953897Smckusick return; 17053897Smckusick } 17153897Smckusick ifp->if_watchdog = enwatch; 17253897Smckusick es->es_interval = ENWATCHINTERVAL; 17353897Smckusick ifp->if_timer = es->es_interval; 17453897Smckusick s = splimp(); 17553897Smckusick en_init(unit); 17653897Smckusick splx(s); 17753897Smckusick } 17853897Smckusick es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS; 17953897Smckusick es->es_flags |= ENF_RUNNING; 18053897Smckusick } 18153897Smckusick 18253897Smckusick /* 18353897Smckusick * Start output on interface. 18453897Smckusick * Get another datagram to send off of the interface queue, 18553897Smckusick * and map it to the interface before starting the output. 18653897Smckusick */ 18753897Smckusick enstart(ifp) 18853897Smckusick register struct ifnet *ifp; 18953897Smckusick { 19053897Smckusick int unit = ifp->if_unit, len; 19153897Smckusick register struct en_softc *es = &en_softc[unit]; 19253897Smckusick register struct mbuf *m; 19354584Sutashiro int s; 19453897Smckusick 19553897Smckusick IF_DEQUEUE(&es->es_if.if_snd, m); 19653897Smckusick if (m == 0) 19753897Smckusick return(0); 19853897Smckusick #ifdef CPU_SINGLE 19953897Smckusick es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit); 20053897Smckusick #endif 20153897Smckusick len = if_wnewsput(&es->es_ifnews, m); 20253897Smckusick /* 20353897Smckusick * Ensure minimum packet length. 20453897Smckusick * This makes the safe assumtion that there are no virtual holes 20553897Smckusick * after the data. 20653897Smckusick * For security, it might be wise to zero out the added bytes, 20753897Smckusick * but we're mainly interested in speed at the moment. 20853897Smckusick */ 20953897Smckusick if (len - sizeof(struct ether_header) < ETHERMIN) 21053897Smckusick len = ETHERMIN + sizeof(struct ether_header); 21154584Sutashiro s = splclock(); /* KU:XXX should be gone */ 21253897Smckusick en_start(unit, len); 21354584Sutashiro es->es_if.if_flags |= IFF_OACTIVE; 21454584Sutashiro (void) splx(s); /* KU:XXX */ 21553897Smckusick #if NBPFILTER > 0 21653897Smckusick /* 21753897Smckusick * If bpf is listening on this interface, let it 21853897Smckusick * see the packet before we commit it to the wire. 21953897Smckusick */ 22054517Sutashiro if (es->es_bpf) { 22153897Smckusick #ifdef CPU_SINGLE 22254517Sutashiro bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len); 22353897Smckusick #else 22454517Sutashiro bpf_mtap(es->es_bpf, m); 22553897Smckusick #endif 22653897Smckusick } 22753897Smckusick #endif /* NBPFILTER > 0 */ 22853897Smckusick return(0); 22953897Smckusick } 23053897Smckusick 23153897Smckusick /* 23253897Smckusick * Transmit done interrupt. 23353897Smckusick */ 23453897Smckusick _enxint(unit, error, collision) 23553897Smckusick int unit; 23653897Smckusick int error, collision; 23753897Smckusick { 23853897Smckusick register struct en_softc *es = &en_softc[unit]; 23953897Smckusick 24053897Smckusick #ifdef notyet /* KU:XXX */ 24153897Smckusick intrcnt[INTR_ETHER0 + unit]++; 24253897Smckusick #endif 24353897Smckusick if ((es->es_if.if_flags & IFF_OACTIVE) == 0) { 24453897Smckusick printf("en%d: stray xmit interrupt\n", unit); 24553897Smckusick return; 24653897Smckusick } else { 24753897Smckusick es->es_if.if_flags &= ~IFF_OACTIVE; 24853897Smckusick es->es_if.if_opackets++; 24953897Smckusick } 250*58612Sutashiro if (error) 25153897Smckusick es->es_if.if_oerrors++; 252*58612Sutashiro if (collision) 25353897Smckusick es->es_if.if_collisions++; 25453897Smckusick enstart(&es->es_if); 25553897Smckusick } 25653897Smckusick 25753897Smckusick /* 25853897Smckusick * Ethernet interface receiver interrupt. 25953897Smckusick * If input error just drop packet. 26053897Smckusick * Otherwise purge input buffered data path and examine 26153897Smckusick * packet to determine type. If can't determine length 26253897Smckusick * from type, then have to drop packet. Othewise decapsulate 26353897Smckusick * packet based on type and pass to type specific higher-level 26453897Smckusick * input routine. 26553897Smckusick */ 26653897Smckusick _enrint(unit, len) 26753897Smckusick int unit; 26853897Smckusick register int len; 26953897Smckusick { 27053897Smckusick register struct en_softc *es = &en_softc[unit]; 27153897Smckusick register struct en_rheader *en; 27253897Smckusick struct mbuf *m; 27353897Smckusick int off, resid, s; 27454522Sutashiro int type; 27553897Smckusick register struct ensw *esp; 27653897Smckusick extern struct mbuf *if_rnewsget(); 27754522Sutashiro #if defined(mips) && defined(CPU_SINGLE) 27854522Sutashiro int bxcopy(); 27954522Sutashiro #endif 28053897Smckusick 28153897Smckusick #ifdef notyet /* KU:XXX */ 28253897Smckusick intrcnt[INTR_ETHER0 + unit]++; 28353897Smckusick #endif 28453897Smckusick es->es_if.if_ipackets++; 28553897Smckusick if ((es->es_flags & ENF_RUNNING) == 0) 28653897Smckusick return; 28753897Smckusick en = (struct en_rheader *)(es->es_ifnews.ifn_raddr); 28853897Smckusick if (len < ETHERMIN || len > ETHERMTU) { 28953897Smckusick es->es_if.if_ierrors++; 29053897Smckusick return; 29153897Smckusick } 29253897Smckusick #if NBPFILTER > 0 29353897Smckusick /* 29453897Smckusick * Check if there's a bpf filter listening on this interface. 29553897Smckusick * If so, hand off the raw packet to enet. 29653897Smckusick */ 29754517Sutashiro if (es->es_bpf) { 29854517Sutashiro bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr, 29953897Smckusick len + sizeof(struct en_rheader)); 30053897Smckusick /* 30153897Smckusick * Note that the interface cannot be in promiscuous mode if 30253897Smckusick * there are no bpf listeners. And if we are in promiscuous 30353897Smckusick * mode, we have to check if this packet is really ours. 30453897Smckusick * 30553897Smckusick * XXX This test does not support multicasts. 30653897Smckusick */ 30753897Smckusick if ((es->es_if.if_flags & IFF_PROMISC) 30853897Smckusick && bcmp(en->enr_dhost, es->es_addr, 30953897Smckusick sizeof(en->enr_dhost)) != 0 31053897Smckusick && bcmp(en->enr_dhost, etherbroadcastaddr, 31153897Smckusick sizeof(en->enr_dhost)) != 0) 31253897Smckusick return; 31353897Smckusick } 31453897Smckusick #endif /* NBPFILTER > 0 */ 31553897Smckusick /* 31653897Smckusick * Deal with trailer protocol: if type is trailer type 31753897Smckusick * get true type from first 16-bit word past data. 31853897Smckusick * Remember that type was trailer by setting off. 31953897Smckusick */ 32053897Smckusick en->enr_type = ntohs((u_short)en->enr_type); 32153897Smckusick #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 32253897Smckusick if (en->enr_type >= ETHERTYPE_TRAIL && 32353897Smckusick en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 32453897Smckusick off = (en->enr_type - ETHERTYPE_TRAIL) * 512; 32553897Smckusick if (off >= ETHERMTU) 32653897Smckusick return; 32753897Smckusick en->enr_type = ntohs(*endataaddr(en, off, u_short *)); 32853897Smckusick resid = ntohs(*(endataaddr(en, off+2, u_short *))); 32953897Smckusick if (off + resid > len) 33053897Smckusick return; 33153897Smckusick len = off + resid; 33253897Smckusick } else 33353897Smckusick off = 0; 33453897Smckusick /* 33553897Smckusick * Pull packet off interface. Off is nonzero if packet 33653897Smckusick * has trailing header; m_devget will then force this header 33753897Smckusick * information to be at the front, but we still have to drop 33853897Smckusick * the type and length which are at the front of any trailer data. 33953897Smckusick * KU:XXX really? 34053897Smckusick */ 34153897Smckusick type = en->enr_type; 34254522Sutashiro #if defined(mips) && defined(CPU_SINGLE) 34354522Sutashiro m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy); 34454522Sutashiro #else 34553897Smckusick m = m_devget((char *)(en + 1), len, off, &es->es_if, 0); 34654522Sutashiro #endif 34753897Smckusick if (m == 0) 34853897Smckusick return; 34953897Smckusick ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m); 35053897Smckusick } 35153897Smckusick 35253897Smckusick /* 35353897Smckusick * Watchdog routine, request statistics from board. 35453897Smckusick */ 35553897Smckusick enwatch(unit) 35653897Smckusick int unit; 35753897Smckusick { 35853897Smckusick register struct en_softc *es = &en_softc[unit]; 35953897Smckusick register struct ifnet *ifp = &es->es_if; 36053897Smckusick 36153897Smckusick ifp->if_timer = es->es_interval; 36253897Smckusick } 36353897Smckusick 36453897Smckusick /* 36553897Smckusick * Process an ioctl request. 36653897Smckusick */ 36753897Smckusick enioctl(ifp, cmd, data) 36853897Smckusick register struct ifnet *ifp; 36953897Smckusick int cmd; 37053897Smckusick caddr_t data; 37153897Smckusick { 37253897Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 37353897Smckusick register struct en_softc *es = &en_softc[ifp->if_unit]; 37453897Smckusick register struct ensw *esp; 37553897Smckusick register int family; 37653897Smckusick int s = splimp(), error = 0; 37753897Smckusick 37853897Smckusick switch (cmd) { 37953897Smckusick 38053897Smckusick case SIOCSIFADDR: 38153897Smckusick ifp->if_flags |= IFF_UP; 38253897Smckusick eninit(ifp->if_unit); 38353897Smckusick switch (ifa->ifa_addr->sa_family) { 38453897Smckusick #ifdef INET 38553897Smckusick case AF_INET: 38653897Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 38753897Smckusick IA_SIN(ifa)->sin_addr; 38853897Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 38953897Smckusick break; 39053897Smckusick #endif 39153897Smckusick } 39253897Smckusick break; 39353897Smckusick 39453897Smckusick case SIOCSIFFLAGS: 39553897Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 39653897Smckusick es->es_flags & ENF_RUNNING) { 39753897Smckusick es->es_flags &= ~ENF_RUNNING; 39853897Smckusick } else if (ifp->if_flags & IFF_UP && 39953897Smckusick (es->es_flags & ENF_RUNNING) == 0) 40053897Smckusick eninit(ifp->if_unit); 40153897Smckusick #if NBPFILTER > 0 40253897Smckusick else if (ifp->if_flags & IFF_UP && 40353897Smckusick (ifp->if_flags & IFF_RUNNING) == 0) { 40453897Smckusick en_prom_mode(ifp->if_unit, 40553897Smckusick ifp->if_flags & IFF_PROMISC); 40653897Smckusick ifp->if_flags |= IFF_RUNNING; 40753897Smckusick } 40853897Smckusick #endif 40953897Smckusick break; 41053897Smckusick 41153897Smckusick default: 41253897Smckusick error = EINVAL; 41353897Smckusick } 41453897Smckusick splx(s); 41553897Smckusick return (error); 41653897Smckusick } 41753897Smckusick 41853897Smckusick /* 41953897Smckusick * set ethernet address for unit 42053897Smckusick */ 42153897Smckusick ensetaddr(physaddr, unit) 42253897Smckusick u_char *physaddr; 42353897Smckusick int unit; 42453897Smckusick { 42553897Smckusick register struct en_softc *es = &en_softc[unit]; 42653897Smckusick 42753897Smckusick if (!(es->es_flags & ENF_RUNNING)) 42853897Smckusick return; 42953897Smckusick 43053897Smckusick bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr); 43153897Smckusick es->es_flags &= ~ENF_RUNNING; 43253897Smckusick es->es_flags |= ENF_SETADDR; 43353897Smckusick eninit(unit); 43453897Smckusick } 43553897Smckusick 43653897Smckusick /* 43753897Smckusick * Machine dependent functions 43853897Smckusick * 43953897Smckusick * en_probe(); 44053897Smckusick * en_attach(); 44153897Smckusick * en_init(); 44253897Smckusick * enxint(); 44353897Smckusick * enrint(); 44453897Smckusick * en_prom_mode() 44553897Smckusick */ 44653897Smckusick #ifdef CPU_SINGLE 44757180Sutashiro #include <machine/cpu.h> 44853897Smckusick 44953897Smckusick en_probe(hi) 45053897Smckusick struct hb_device *hi; 45153897Smckusick { 45253897Smckusick 45353897Smckusick return (lance_probe(hi->hi_unit)); 45453897Smckusick } 45553897Smckusick 45653897Smckusick en_attach(unit) 45753897Smckusick int unit; 45853897Smckusick { 45953897Smckusick register struct en_softc *es = &en_softc[unit]; 46053897Smckusick register u_char *p; 46153897Smckusick register int i; 46253897Smckusick extern lance_intr(); 46353897Smckusick 46453897Smckusick #if !defined(news700) && !defined(mips) 46553897Smckusick register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr); 46653897Smckusick #endif 46753897Smckusick if (lance_open(unit) < 0) 46853897Smckusick printf("lance initialize error\n"); 46953897Smckusick lance_get_addr(unit, (caddr_t)es->es_addr); 47053897Smckusick } 47153897Smckusick 47253897Smckusick en_init(unit) 47353897Smckusick int unit; 47453897Smckusick { 47553897Smckusick 47653897Smckusick } 47753897Smckusick 47853897Smckusick en_start(unit, len) 47953897Smckusick int unit; 48053897Smckusick int len; 48153897Smckusick { 48253897Smckusick 48353897Smckusick lance_transmit(unit, len); 48453897Smckusick } 48553897Smckusick 48653897Smckusick enxint(unit) 48753897Smckusick register int unit; 48853897Smckusick { 48953897Smckusick 49053897Smckusick _enxint(unit, lance_xmit_error(unit), lance_collision(unit)); 49153897Smckusick } 49253897Smckusick 49353897Smckusick enrint(unit) 49453897Smckusick register int unit; 49553897Smckusick { 49653897Smckusick register struct en_softc *es = &en_softc[unit]; 49753897Smckusick caddr_t get_recv_buffer(); 49853897Smckusick 49953897Smckusick while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) { 50053897Smckusick _enrint(unit, 50153897Smckusick get_recv_length(unit) - sizeof(struct en_rheader)); 50253897Smckusick free_recv_buffer(unit); 50353897Smckusick } 50453897Smckusick } 50553897Smckusick 50653897Smckusick en_prom_mode(unit, mode) 50753897Smckusick int unit, mode; 50853897Smckusick { 50953897Smckusick 51053897Smckusick lance_prom_mode(unit, mode); 51153897Smckusick } 51253897Smckusick #endif /* CPU_SINGLE */ 51353897Smckusick 51453897Smckusick #ifdef IPC_MRX 51553897Smckusick #include "../ipc/newsipc.h" 51653897Smckusick #include "../mrx/h/lancereg.h" 51753897Smckusick #include "../mrx/h/lance.h" 51853897Smckusick 51953897Smckusick int port_enxmit[NEN]; 52053897Smckusick int port_enrecv[NEN]; 52153897Smckusick int port_enctrl[NEN]; 52253897Smckusick int port_enxmit_iop[NEN]; 52353897Smckusick int port_enrecv_iop[NEN]; 52453897Smckusick int port_enctrl_iop[NEN]; 52553897Smckusick 52653897Smckusick en_probe(ii) 52753897Smckusick register struct iop_device *ii; 52853897Smckusick { 52953897Smckusick int unit = ii->ii_unit; 53053897Smckusick int lance_func, *reply; 53153897Smckusick char name[32]; 53253897Smckusick extern char *make_name(); 53353897Smckusick 53453897Smckusick if (port_enrecv[unit] == 0) { 53553897Smckusick 53653897Smckusick #define PT_CREATE(buf, name, unit, func) \ 53753897Smckusick port_create(make_name(buf, name, unit), func, unit) 53853897Smckusick #define OB_QUERY(buf, name, unit) \ 53953897Smckusick object_query(make_name(buf, name, unit)) 54053897Smckusick 54153897Smckusick make_name(name, "@enrecvX", unit); 54253897Smckusick port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint); 54353897Smckusick port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint); 54453897Smckusick port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL); 54553897Smckusick /* use NULL action port */ 54653897Smckusick port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit); 54753897Smckusick port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit); 54853897Smckusick port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit); 54953897Smckusick } 55053897Smckusick if (port_enctrl_iop[unit] < 0) 55153897Smckusick goto bad; 55253897Smckusick lance_func = EN_START; 55353897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 55453897Smckusick sizeof(lance_func), 0); 55553897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 55653897Smckusick if (*reply < 0) 55753897Smckusick goto bad; 55853897Smckusick lance_func = EN_STOP; 55953897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 56053897Smckusick sizeof(lance_func), 0); 56153897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 56253897Smckusick return (1); 56353897Smckusick bad: 56453897Smckusick return (0); 56553897Smckusick } 56653897Smckusick 56753897Smckusick en_attach(unit) 56853897Smckusick int unit; 56953897Smckusick { 57053897Smckusick register struct en_softc *es = &en_softc[unit]; 57153897Smckusick int lance_func; 57253897Smckusick struct ether_addr *ether_addr; 57353897Smckusick 57453897Smckusick lance_func = EN_GETADDR; 57553897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 57653897Smckusick sizeof(lance_func), 0); 57753897Smckusick msg_recv(port_enctrl[unit], NULL, ðer_addr, NULL, 0); 57853897Smckusick bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr)); 57953897Smckusick msg_free(port_enctrl[unit]); 58053897Smckusick } 58153897Smckusick 58253897Smckusick en_init(unit) 58353897Smckusick int unit; 58453897Smckusick { 58553897Smckusick register struct en_softc *es = &en_softc[unit]; 58653897Smckusick register int port; 58753897Smckusick struct lance_ctrl_req req; 58853897Smckusick int *reply; 58953897Smckusick 59053897Smckusick req.lance_func = EN_SETXMITBUF; 59153897Smckusick mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr, 59253897Smckusick ETHERMTU + sizeof(struct en_rheader)); 59353897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 59453897Smckusick &req, sizeof(req), 0); 59553897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 59653897Smckusick 59753897Smckusick req.lance_func = EN_START; 59853897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 59953897Smckusick &req, sizeof(req), 0); 60053897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 60153897Smckusick msg_free(port_enctrl[unit]); 60253897Smckusick 60353897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 60453897Smckusick es->es_ifnews.ifn_raddr, 60553897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 60653897Smckusick } 60753897Smckusick 60853897Smckusick en_start(unit, len) 60953897Smckusick int unit; 61053897Smckusick int len; 61153897Smckusick { 61253897Smckusick 61353897Smckusick msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0); 61453897Smckusick } 61553897Smckusick 61653897Smckusick enxint(unit) 61753897Smckusick register int unit; 61853897Smckusick { 61953897Smckusick int *len; 62053897Smckusick struct en_softc *es = &en_softc[unit]; 62153897Smckusick 62253897Smckusick if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) { 62353897Smckusick printf("stray enxint\n"); 62453897Smckusick return; 62553897Smckusick } 62653897Smckusick if (es->es_ifnews.ifn_mbuf) 62753897Smckusick m_freem(es->es_ifnews.ifn_mbuf); 62853897Smckusick _enxint(unit, *len < 0, *len & 0x10000); 62953897Smckusick } 63053897Smckusick 63153897Smckusick enrint(unit) 63253897Smckusick int unit; 63353897Smckusick { 63453897Smckusick int len; 63553897Smckusick int *reply; 63653897Smckusick 63753897Smckusick if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) { 63853897Smckusick printf("stray enrint\n"); 63953897Smckusick return; 64053897Smckusick } 64153897Smckusick len = *reply - sizeof(struct en_rheader); 64253897Smckusick msg_free(port_enrecv[unit]); 64353897Smckusick #ifdef mips 64453897Smckusick /* 64553897Smckusick * cache flush address must aligned long word boundary. 64653897Smckusick * so, add 3 for sanity. 64753897Smckusick */ 64853897Smckusick clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03, 64953897Smckusick len + sizeof (struct en_rheader) + 3); 65053897Smckusick #endif 65153897Smckusick _enrint(unit, len); 65253897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 65353897Smckusick en_softc[unit].es_ifnews.ifn_raddr, 65453897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 65553897Smckusick } 65653897Smckusick 65753897Smckusick en_prom_mode(unit, mode) 65853897Smckusick int unit, mode; 65953897Smckusick { 66053897Smckusick static int port; 66153897Smckusick struct lance_ctrl_req req; 66253897Smckusick extern int port_enctrl_iop[]; 66353897Smckusick 66453897Smckusick req.lance_func = EN_PROMMODE; 66553897Smckusick req.lance_mode = mode; 66653897Smckusick msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0); 66753897Smckusick } 66853897Smckusick #endif /* IPC_MRX */ 66953897Smckusick #endif /* NEN > 0 */ 670