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