Now enableclock is not used
[unix-history] / usr / src / sys / news3400 / if / if_en.c
CommitLineData
af5295ff
KM
1/*
2 * Copyright (c) 1992 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7 *
8 * %sccs.include.redist.c%
9 *
10 * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY
11 *
5b7c2955 12 * @(#)if_en.c 7.6 (Berkeley) %G%
af5295ff
KM
13 */
14
15#include "en.h"
16#include "rawether.h"
17#include "bpfilter.h"
18
19#if NEN > 0
20
21/*
22 * Interlan Ethernet Communications Controller interface
23 */
5b7c2955
KU
24#include <sys/types.h>
25#include <machine/fix_machine_type.h>
26#include <machine/pte.h>
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/mbuf.h>
31#include <sys/buf.h>
32#include <sys/protosw.h>
33#include <sys/socket.h>
34#include <sys/ioctl.h>
35#include <sys/errno.h>
36#include <sys/time.h>
37#include <sys/cdefs.h>
38
39#include <net/if.h>
40#include <net/netisr.h>
41#include <net/route.h>
af5295ff
KM
42
43#ifdef INET
5b7c2955
KU
44#include <netinet/in.h>
45#include <netinet/in_systm.h>
46#include <netinet/in_var.h>
47#include <netinet/ip.h>
48#include <netinet/if_ether.h>
af5295ff
KM
49#endif
50
5b7c2955
KU
51#include <news3400/if/if_news.h>
52#include <news3400/if/if_en.h>
af5295ff
KM
53
54#ifdef CPU_SINGLE
5b7c2955 55#include <news3400/hbdev/hbvar.h>
af5295ff
KM
56#define iop_device hb_device
57#define iop_driver hb_driver
58#define ii_unit hi_unit
59#define ii_intr hi_intr
60#define ii_alive hi_alive
61#else
5b7c2955 62#include <news3400/iop/iopvar.h>
af5295ff
KM
63#endif
64
65int enprobe(), enattach(), enrint(), enxint();
66struct mbuf *m_devget();
67
68#ifdef CPU_SINGLE
69struct hb_device *eninfo[NEN];
70struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo };
71#else
72struct iop_device *eninfo[NEN];
73struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo };
74#endif
75
76#define ENUNIT(x) minor(x)
77
4fd05659 78int eninit(),enioctl(),enreset(),enwatch(),enstart();
af5295ff
KM
79int endebug = 0;
80
81struct ether_addr {
82 u_char addr[6];
83};
84
85extern struct ifnet loif;
86
87struct en_softc en_softc[NEN];
af5295ff
KM
88
89#if NBPFILTER > 0
5b7c2955 90#include <net/bpf.h>
af5295ff
KM
91#endif
92
93enprobe(ii)
94 struct iop_device *ii;
95{
96
97 return (en_probe(ii));
98}
99
100/*
101 * Interface exists: make available by filling in network interface
102 * record. System will initialize the interface when it is ready
103 * to accept packets. A STATUS command is done to get the ethernet
104 * address and other interesting data.
105 */
106enattach(ii)
107 register struct iop_device *ii;
108{
109 register struct en_softc *es = &en_softc[ii->ii_unit];
110 register struct ifnet *ifp = &es->es_if;
111 extern char *ether_sprintf();
112
113 en_attach(ii->ii_unit);
af5295ff
KM
114 printf("en%d: hardware address %s\n",
115 ii->ii_unit, ether_sprintf((u_char *)es->es_addr));
116 ifp->if_unit = ii->ii_unit;
117 ifp->if_name = "en";
118 ifp->if_mtu = ETHERMTU;
119 ifp->if_init = eninit;
120 ifp->if_ioctl = enioctl;
121 ifp->if_output = ether_output;
122#ifdef NOTDEF /* KU:XXX if_reset is obsolete */
123 ifp->if_reset = enreset;
124#endif
125 ifp->if_start = enstart;
82cd4001 126 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
af5295ff 127#if NBPFILTER > 0
82cd4001 128 bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
af5295ff
KM
129#endif
130 if_attach(ifp);
131}
132
133/*
134 * Reset of interface after IOP reset.
135 */
136enreset(unit)
137 int unit;
138{
139 register struct iop_device *ii;
140
141 if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0)
142 return;
143 printf(" en%d", unit);
144 en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
145 en_softc[unit].es_flags &= ~ENF_RUNNING;
146 eninit(unit);
147}
148
149/*
150 * Initialization of interface; clear recorded pending
151 * operations, and reinitialize IOP usage.
152 */
153eninit(unit)
154 int unit;
155{
156 register struct en_softc *es = &en_softc[unit];
157 register struct ifnet *ifp = &es->es_if;
158 int s;
159
160 /* not yet, if address still unknown */
161 if (ifp->if_addrlist == (struct ifaddr *)0)
162 return;
163 if (es->es_flags & ENF_RUNNING)
164 return;
165 if ((ifp->if_flags & IFF_RUNNING) == 0) {
166 if (if_newsinit(&es->es_ifnews,
167 sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) {
168 printf("en%d: can't initialize\n", unit);
169 es->es_if.if_flags &= ~IFF_UP;
170 return;
171 }
172 ifp->if_watchdog = enwatch;
173 es->es_interval = ENWATCHINTERVAL;
174 ifp->if_timer = es->es_interval;
175 s = splimp();
176 en_init(unit);
177 splx(s);
178 }
179 es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS;
180 es->es_flags |= ENF_RUNNING;
181}
182
183/*
184 * Start output on interface.
185 * Get another datagram to send off of the interface queue,
186 * and map it to the interface before starting the output.
187 */
188enstart(ifp)
189 register struct ifnet *ifp;
190{
191 int unit = ifp->if_unit, len;
192 register struct en_softc *es = &en_softc[unit];
193 register struct mbuf *m;
c1738274 194 int s;
af5295ff
KM
195
196 IF_DEQUEUE(&es->es_if.if_snd, m);
197 if (m == 0)
198 return(0);
199#ifdef CPU_SINGLE
200 es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit);
201#endif
202 len = if_wnewsput(&es->es_ifnews, m);
203 /*
204 * Ensure minimum packet length.
205 * This makes the safe assumtion that there are no virtual holes
206 * after the data.
207 * For security, it might be wise to zero out the added bytes,
208 * but we're mainly interested in speed at the moment.
209 */
210 if (len - sizeof(struct ether_header) < ETHERMIN)
211 len = ETHERMIN + sizeof(struct ether_header);
c1738274 212 s = splclock(); /* KU:XXX should be gone */
af5295ff 213 en_start(unit, len);
c1738274
KU
214 es->es_if.if_flags |= IFF_OACTIVE;
215 (void) splx(s); /* KU:XXX */
af5295ff
KM
216#if NBPFILTER > 0
217 /*
218 * If bpf is listening on this interface, let it
219 * see the packet before we commit it to the wire.
220 */
82cd4001 221 if (es->es_bpf) {
af5295ff 222#ifdef CPU_SINGLE
82cd4001 223 bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len);
af5295ff 224#else
82cd4001 225 bpf_mtap(es->es_bpf, m);
af5295ff
KM
226#endif
227 }
228#endif /* NBPFILTER > 0 */
af5295ff
KM
229 return(0);
230}
231
232/*
233 * Transmit done interrupt.
234 */
235_enxint(unit, error, collision)
236 int unit;
237 int error, collision;
238{
239 register struct en_softc *es = &en_softc[unit];
240
241#ifdef notyet /* KU:XXX */
242 intrcnt[INTR_ETHER0 + unit]++;
243#endif
244 if ((es->es_if.if_flags & IFF_OACTIVE) == 0) {
245 printf("en%d: stray xmit interrupt\n", unit);
af5295ff 246 return;
af5295ff
KM
247 } else {
248 es->es_if.if_flags &= ~IFF_OACTIVE;
249 es->es_if.if_opackets++;
250 }
82cd4001
KU
251 if (error) {
252#ifdef DEBUG
253 printf("_enxint: error (unit=%d)\n", unit);
254#endif
af5295ff 255 es->es_if.if_oerrors++;
82cd4001
KU
256 }
257 if (collision) {
258#ifdef DEBUG
259 printf("_enxint: collision (unit=%d)\n", unit);
260#endif
af5295ff 261 es->es_if.if_collisions++;
82cd4001 262 }
af5295ff
KM
263 enstart(&es->es_if);
264}
265
266/*
267 * Ethernet interface receiver interrupt.
268 * If input error just drop packet.
269 * Otherwise purge input buffered data path and examine
270 * packet to determine type. If can't determine length
271 * from type, then have to drop packet. Othewise decapsulate
272 * packet based on type and pass to type specific higher-level
273 * input routine.
274 */
275_enrint(unit, len)
276 int unit;
277 register int len;
278{
279 register struct en_softc *es = &en_softc[unit];
280 register struct en_rheader *en;
281 struct mbuf *m;
282 int off, resid, s;
cd6e7c50 283 int type;
af5295ff
KM
284 register struct ensw *esp;
285 extern struct mbuf *if_rnewsget();
cd6e7c50
KU
286#if defined(mips) && defined(CPU_SINGLE)
287 int bxcopy();
288#endif
af5295ff
KM
289
290#ifdef notyet /* KU:XXX */
291 intrcnt[INTR_ETHER0 + unit]++;
292#endif
293 es->es_if.if_ipackets++;
294 if ((es->es_flags & ENF_RUNNING) == 0)
295 return;
296 en = (struct en_rheader *)(es->es_ifnews.ifn_raddr);
297 if (len < ETHERMIN || len > ETHERMTU) {
298 es->es_if.if_ierrors++;
299 return;
300 }
301#if NBPFILTER > 0
af5295ff
KM
302 /*
303 * Check if there's a bpf filter listening on this interface.
304 * If so, hand off the raw packet to enet.
305 */
82cd4001
KU
306 if (es->es_bpf) {
307 bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr,
af5295ff
KM
308 len + sizeof(struct en_rheader));
309 /*
310 * Note that the interface cannot be in promiscuous mode if
311 * there are no bpf listeners. And if we are in promiscuous
312 * mode, we have to check if this packet is really ours.
313 *
314 * XXX This test does not support multicasts.
315 */
316 if ((es->es_if.if_flags & IFF_PROMISC)
317 && bcmp(en->enr_dhost, es->es_addr,
318 sizeof(en->enr_dhost)) != 0
319 && bcmp(en->enr_dhost, etherbroadcastaddr,
320 sizeof(en->enr_dhost)) != 0)
321 return;
322 }
af5295ff
KM
323#endif /* NBPFILTER > 0 */
324 /*
325 * Deal with trailer protocol: if type is trailer type
326 * get true type from first 16-bit word past data.
327 * Remember that type was trailer by setting off.
328 */
329 en->enr_type = ntohs((u_short)en->enr_type);
330#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
331 if (en->enr_type >= ETHERTYPE_TRAIL &&
332 en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
333 off = (en->enr_type - ETHERTYPE_TRAIL) * 512;
334 if (off >= ETHERMTU)
335 return;
336 en->enr_type = ntohs(*endataaddr(en, off, u_short *));
337 resid = ntohs(*(endataaddr(en, off+2, u_short *)));
338 if (off + resid > len)
339 return;
340 len = off + resid;
341 } else
342 off = 0;
343 /*
344 * Pull packet off interface. Off is nonzero if packet
345 * has trailing header; m_devget will then force this header
346 * information to be at the front, but we still have to drop
347 * the type and length which are at the front of any trailer data.
348 * KU:XXX really?
349 */
350 type = en->enr_type;
cd6e7c50
KU
351#if defined(mips) && defined(CPU_SINGLE)
352 m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy);
353#else
af5295ff 354 m = m_devget((char *)(en + 1), len, off, &es->es_if, 0);
cd6e7c50 355#endif
af5295ff
KM
356 if (m == 0)
357 return;
358 ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m);
359}
360
361/*
362 * Watchdog routine, request statistics from board.
363 */
364enwatch(unit)
365 int unit;
366{
367 register struct en_softc *es = &en_softc[unit];
368 register struct ifnet *ifp = &es->es_if;
369
370 ifp->if_timer = es->es_interval;
371}
372
373/*
374 * Process an ioctl request.
375 */
376enioctl(ifp, cmd, data)
377 register struct ifnet *ifp;
378 int cmd;
379 caddr_t data;
380{
381 register struct ifaddr *ifa = (struct ifaddr *)data;
382 register struct en_softc *es = &en_softc[ifp->if_unit];
383 register struct ensw *esp;
384 register int family;
385 int s = splimp(), error = 0;
386
387 switch (cmd) {
388
389 case SIOCSIFADDR:
390 ifp->if_flags |= IFF_UP;
391 eninit(ifp->if_unit);
392 switch (ifa->ifa_addr->sa_family) {
393#ifdef INET
394 case AF_INET:
395 ((struct arpcom *)ifp)->ac_ipaddr =
396 IA_SIN(ifa)->sin_addr;
397 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
398 break;
399#endif
400 }
401 break;
402
403 case SIOCSIFFLAGS:
404 if ((ifp->if_flags & IFF_UP) == 0 &&
405 es->es_flags & ENF_RUNNING) {
406 es->es_flags &= ~ENF_RUNNING;
407 } else if (ifp->if_flags & IFF_UP &&
408 (es->es_flags & ENF_RUNNING) == 0)
409 eninit(ifp->if_unit);
410#if NBPFILTER > 0
411 else if (ifp->if_flags & IFF_UP &&
412 (ifp->if_flags & IFF_RUNNING) == 0) {
413 en_prom_mode(ifp->if_unit,
414 ifp->if_flags & IFF_PROMISC);
415 ifp->if_flags |= IFF_RUNNING;
416 }
417#endif
418 break;
419
420 default:
421 error = EINVAL;
422 }
423 splx(s);
424 return (error);
425}
426
427/*
428 * set ethernet address for unit
429 */
430ensetaddr(physaddr, unit)
431 u_char *physaddr;
432 int unit;
433{
434 register struct en_softc *es = &en_softc[unit];
435
436 if (!(es->es_flags & ENF_RUNNING))
437 return;
438
439 bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr);
440 es->es_flags &= ~ENF_RUNNING;
441 es->es_flags |= ENF_SETADDR;
442 eninit(unit);
443}
444
445/*
446 * Machine dependent functions
447 *
448 * en_probe();
449 * en_attach();
450 * en_init();
451 * enxint();
452 * enrint();
453 * en_prom_mode()
454 */
455#ifdef CPU_SINGLE
5b7c2955 456#include <machine/cpu.h>
af5295ff
KM
457
458en_probe(hi)
459 struct hb_device *hi;
460{
461
462 return (lance_probe(hi->hi_unit));
463}
464
465en_attach(unit)
466 int unit;
467{
468 register struct en_softc *es = &en_softc[unit];
469 register u_char *p;
470 register int i;
471 extern lance_intr();
472
473#if !defined(news700) && !defined(mips)
474 register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr);
475#endif
476 if (lance_open(unit) < 0)
477 printf("lance initialize error\n");
478 lance_get_addr(unit, (caddr_t)es->es_addr);
479}
480
481en_init(unit)
482 int unit;
483{
484
485}
486
487en_start(unit, len)
488 int unit;
489 int len;
490{
491
492 lance_transmit(unit, len);
493}
494
495enxint(unit)
496 register int unit;
497{
498
499 _enxint(unit, lance_xmit_error(unit), lance_collision(unit));
500}
501
502enrint(unit)
503 register int unit;
504{
505 register struct en_softc *es = &en_softc[unit];
506 caddr_t get_recv_buffer();
507
508 while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) {
509 _enrint(unit,
510 get_recv_length(unit) - sizeof(struct en_rheader));
511 free_recv_buffer(unit);
512 }
513}
514
515en_prom_mode(unit, mode)
516 int unit, mode;
517{
518
519 lance_prom_mode(unit, mode);
520}
521#endif /* CPU_SINGLE */
522
523#ifdef IPC_MRX
524#include "../ipc/newsipc.h"
525#include "../mrx/h/lancereg.h"
526#include "../mrx/h/lance.h"
527
528int port_enxmit[NEN];
529int port_enrecv[NEN];
530int port_enctrl[NEN];
531int port_enxmit_iop[NEN];
532int port_enrecv_iop[NEN];
533int port_enctrl_iop[NEN];
534
535en_probe(ii)
536 register struct iop_device *ii;
537{
538 int unit = ii->ii_unit;
539 int lance_func, *reply;
540 char name[32];
541 extern char *make_name();
542
543 if (port_enrecv[unit] == 0) {
544
545#define PT_CREATE(buf, name, unit, func) \
546 port_create(make_name(buf, name, unit), func, unit)
547#define OB_QUERY(buf, name, unit) \
548 object_query(make_name(buf, name, unit))
549
550 make_name(name, "@enrecvX", unit);
551 port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint);
552 port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint);
553 port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL);
554 /* use NULL action port */
555 port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit);
556 port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit);
557 port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit);
558 }
559 if (port_enctrl_iop[unit] < 0)
560 goto bad;
561 lance_func = EN_START;
562 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
563 sizeof(lance_func), 0);
564 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
565 if (*reply < 0)
566 goto bad;
567 lance_func = EN_STOP;
568 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
569 sizeof(lance_func), 0);
570 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
571 return (1);
572bad:
573 return (0);
574}
575
576en_attach(unit)
577 int unit;
578{
579 register struct en_softc *es = &en_softc[unit];
580 int lance_func;
581 struct ether_addr *ether_addr;
582
583 lance_func = EN_GETADDR;
584 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
585 sizeof(lance_func), 0);
586 msg_recv(port_enctrl[unit], NULL, &ether_addr, NULL, 0);
587 bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr));
588 msg_free(port_enctrl[unit]);
589}
590
591en_init(unit)
592 int unit;
593{
594 register struct en_softc *es = &en_softc[unit];
595 register int port;
596 struct lance_ctrl_req req;
597 int *reply;
598
599 req.lance_func = EN_SETXMITBUF;
600 mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr,
601 ETHERMTU + sizeof(struct en_rheader));
602 msg_send(port_enctrl_iop[unit], port_enctrl[unit],
603 &req, sizeof(req), 0);
604 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
605
606 req.lance_func = EN_START;
607 msg_send(port_enctrl_iop[unit], port_enctrl[unit],
608 &req, sizeof(req), 0);
609 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
610 msg_free(port_enctrl[unit]);
611
612 msg_send(port_enrecv_iop[unit], port_enrecv[unit],
613 es->es_ifnews.ifn_raddr,
614 ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
615}
616
617en_start(unit, len)
618 int unit;
619 int len;
620{
621
622 msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0);
623}
624
625enxint(unit)
626 register int unit;
627{
628 int *len;
629 struct en_softc *es = &en_softc[unit];
630
631 if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) {
632 printf("stray enxint\n");
633 return;
634 }
635 if (es->es_ifnews.ifn_mbuf)
636 m_freem(es->es_ifnews.ifn_mbuf);
637 _enxint(unit, *len < 0, *len & 0x10000);
638}
639
640enrint(unit)
641 int unit;
642{
643 int len;
644 int *reply;
645
646 if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) {
647 printf("stray enrint\n");
648 return;
649 }
650 len = *reply - sizeof(struct en_rheader);
651 msg_free(port_enrecv[unit]);
652#ifdef mips
653 /*
654 * cache flush address must aligned long word boundary.
655 * so, add 3 for sanity.
656 */
657 clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03,
658 len + sizeof (struct en_rheader) + 3);
659#endif
660 _enrint(unit, len);
661 msg_send(port_enrecv_iop[unit], port_enrecv[unit],
662 en_softc[unit].es_ifnews.ifn_raddr,
663 ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
664}
665
666en_prom_mode(unit, mode)
667 int unit, mode;
668{
669 static int port;
670 struct lance_ctrl_req req;
671 extern int port_enctrl_iop[];
672
673 req.lance_func = EN_PROMMODE;
674 req.lance_mode = mode;
675 msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0);
676}
677#endif /* IPC_MRX */
678#endif /* NEN > 0 */