|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Tim L. Tucker.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.1.1.3 ! root 36: * if_ec.c,v 1.10 1993/06/14 16:45:25 mycroft Exp
1.1 root 37: */
1.1.1.3 ! root 38:
1.1 root 39: /*
40: * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor.
41: *
42: * Written by Herb Peyerl ([email protected]) on 04/25/92.
43: * (This is my first ever device driver and I couldn't have done
44: * it without the consumption of many "Brock Gummy Bears" so a
45: * big thanx to the "Brock Candy Company" of Chattanooga TN)
46: *
47: * This driver uses the Western Digital 8003 driver for a template
48: * since the two cards use the DP8390 chip by National. Everything
49: * is fairly similar except that the nic on the wd8003 appears to
50: * to see shared memory at 0x0000 and on the 3com, the nic sees it
51: * at 0x2000. Also, the 3c503 has it's own ASIC for controlling
52: * things like the IRQ level in software and whether to use the
53: * onboard xceiver or not. Since the Clarkson drivers do a very
54: * good rendition of a 3c503, I also scavenged a lot of ideas from
55: * there.
56: */
57: #include "param.h"
58: #include "mbuf.h"
59: #include "socket.h"
60: #include "ioctl.h"
61: #include "errno.h"
62: #include "syslog.h"
63: #include "net/if.h"
64: #include "net/netisr.h"
65: #ifdef INET
66: #include "netinet/in.h"
67: #include "netinet/in_systm.h"
68: #include "netinet/in_var.h"
69: #include "netinet/ip.h"
70: #include "netinet/if_ether.h"
71: #endif
72: #ifdef NS
73: #include "netns/ns.h"
74: #include "netns/ns_if.h"
75: #endif
76: #include "i386/isa/isa_device.h"
77: #include "i386/isa/if_ec.h"
78:
1.1.1.2 root 79: #include "ec.h"
80:
1.1 root 81: /*
82: * Ethernet software status per interface.
83: *
84: * Each interface is referenced by a network interface structure,
85: * qe_if, which the routing code uses to locate the interface.
86: * This structure contains the output queue for the interface, its address, ...
87: */
88: struct ec_softc {
89: struct arpcom ec_ac; /* Ethernet common part */
90: #define ec_if ec_ac.ac_if /* network-visible interface */
91: #define ec_addr ec_ac.ac_enaddr /* hardware Ethernet address */
1.1.1.2 root 92: #define ns_addrp ec_ac.ac_enaddr /* hardware Ethernet address (for ns)*/
1.1 root 93: u_char ec_flags; /* software state */
94: #define EC_RUNNING 0x01
95: #define EC_TXBUSY 0x02
96:
97: u_char ec_type; /* interface type code */
98: u_short ec_vector; /* interrupt vector */
99: short ec_io_ctl_addr; /* i/o bus address, control */
100: short ec_io_nic_addr; /* i/o bus address, DS8390 */
101:
102: caddr_t ec_vmem_addr; /* card RAM virtual memory base */
103: u_long ec_vmem_size; /* card RAM bytes */
104: caddr_t ec_vmem_ring; /* receive ring RAM vaddress */
105: caddr_t ec_vmem_end; /* receive ring RAM end */
106: } ec_softc[NEC];
107:
108: #define PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0);
109: #define PAGE1 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1);
110: static Bdry;
111:
112: int ether_output(),
113: ecprobe(),
114: ecattach(),
115: ecintr(),
116: ec_init(),
117: ec_ioctl(),
118: ec_reset(),
119: ec_watchdog(),
120: ec_start_output();
121:
122: struct isa_driver ecdriver = {
123: ecprobe,
124: ecattach,
125: "ec",
126: };
127:
128: ecprobe(is)
129: struct isa_device *is;
130: {
131: register struct ec_softc *sc = &ec_softc[is->id_unit&127];
132: int i, sum;
133: /*
134: * Set up the softc structure with card specific info.
135: * The 3Com asic is at base+0x400
136: */
137: sc->ec_io_ctl_addr = is->id_iobase + 0x400;
138: sc->ec_io_nic_addr = is->id_iobase;
139: sc->ec_vector = is->id_irq;
140: sc->ec_vmem_addr = (caddr_t)is->id_maddr;
141: sc->ec_vmem_size = is->id_msize;
142: sc->ec_vmem_ring = sc->ec_vmem_addr + (EC_PAGE_SIZE * EC_TXBUF_SIZE);
143: sc->ec_vmem_end = sc->ec_vmem_addr + is->id_msize;
144: /*
145: * Now we get the MAC address. Assume thin ethernet unless told otherwise later.
146: */
1.1.1.3 ! root 147: /* Toggle reset bit on*/
! 148: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_RESET|ECNTRL_ONBOARD);
1.1 root 149: DELAY(100);
1.1.1.3 ! root 150: /* Toggle reset bit off */
! 151: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_ONBOARD);
1.1 root 152: DELAY(100);
1.1.1.3 ! root 153: /* Map SA_PROM */
! 154: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_SAPROM|ECNTRL_ONBOARD);
1.1 root 155: for (i=0;i<ETHER_ADDR_LEN; ++i)
156: sc->ec_addr[i] = inb(sc->ec_io_nic_addr + i);
1.1.1.3 ! root 157: /* Disable SA_PROM */
! 158: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_ONBOARD);
! 159: /* tcm, rsel, mbs0, nim */
! 160: outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_IRQOFF);
1.1 root 161: /*
162: * Stop the chip just in case.
163: */
164: DELAY(1000);
165: PAGE0
166: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
167: DELAY(1000);
168:
169: /* Check cmd reg and fail if not right */
170: if ((i=inb(sc->ec_io_nic_addr + EN_CCMD)) != (ENC_NODMA|ENC_STOP))
171: return(0);
172:
173: /*
174: * Test the shared memory.
175: */
176: for(i = 0 ; i < sc->ec_vmem_size ; ++i)
177: sc->ec_vmem_addr[i] = 0x0;
178: for(sum=0, i=0; i<sc->ec_vmem_size; ++i)
179: sum += sc->ec_vmem_addr[i];
180: if(sum)
181: {
182: printf("ec%d: shared memory error (device conflict?)\n",
183: is->id_unit);
184: return(0);
185: }
186: /*
187: * All done.
188: */
1.1.1.3 ! root 189: return(16);
1.1 root 190: }
191:
192: ecattach(is)
193: struct isa_device *is;
194: {
195: register struct ec_softc *sc = &ec_softc[is->id_unit];
196: register struct ifnet *ifp = &sc->ec_if;
197:
198: /**
199: ** Initialize the ASIC in same order as Clarkson driver.
200: **/
201:
202:
203: /*
204: * Point vector pointer registers off into boonies.
205: */
206: outb(sc->ec_io_ctl_addr + E33G_VP2, 0xff);
207: outb(sc->ec_io_ctl_addr + E33G_VP1, 0xff);
208: outb(sc->ec_io_ctl_addr + E33G_VP0, 0x0);
209: /*
210: * Set up control of shared memory, buffer ring, etc.
211: */
212: outb(sc->ec_io_ctl_addr + E33G_STARTPG, EC_RXBUF_OFFSET);
213: outb(sc->ec_io_ctl_addr + E33G_STOPPG, EC_RXBUF_END);
214: /*
215: * Set up the IRQ and NBURST on the board.
216: * ( Not sure why we set up NBURST since we don't use DMA.)
217: *
218: * Normally we would is->id_irq<<2 but IRQ2 is defined as 0x200
219: * in icu.h so it's a special case.
220: */
221: if(is->id_irq == 0x200)
222: outb(sc->ec_io_ctl_addr + E33G_IDCFR, 0x10);
223: else
224: outb(sc->ec_io_ctl_addr + E33G_IDCFR, is->id_irq << 2);
225: outb(sc->ec_io_ctl_addr + E33G_NBURST, 0x08); /* Set Burst to 8 */
226: outb(sc->ec_io_ctl_addr + E33G_DMAAH, 0x20);
227: outb(sc->ec_io_ctl_addr + E33G_DMAAL, 0x0);
228: /*
229: * Fill in the ifnet structure.
230: */
231: ifp->if_unit = is->id_unit;
232: ifp->if_name = "ec" ;
233: ifp->if_mtu = ETHERMTU;
234: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
235: ifp->if_init = ec_init;
236: ifp->if_output = ether_output;
237: ifp->if_start = ec_start_output;
238: ifp->if_ioctl = ec_ioctl;
239: ifp->if_reset = ec_reset;
240: ifp->if_watchdog = ec_watchdog;
241: /*
242: * Attach the interface to something. Have to figure this out later.
243: */
244: if_attach(ifp);
245: /*
246: * Weeee.. We get to tell people we exist...
247: */
1.1.1.3 ! root 248: printf("ec%d: ethernet address %s\n",
! 249: is->id_unit, ether_sprintf(sc->ec_addr));
1.1 root 250: }
251:
252: ec_init(unit)
253: int unit;
254: {
255: register struct ec_softc *sc = &ec_softc[unit];
256: register struct ifnet *ifp = &sc->ec_if;
257: int i, s;
258: u_short ax, cx;
259:
260: Bdry=0;
261: /*
262: * Address not known.
263: */
264: if(ifp->if_addrlist == (struct ifaddr *) 0)
265: return;
266:
267: /*
268: * select thick (e.g. AUI connector) if LLC0 bit is set
269: */
1.1.1.3 ! root 270: outb(sc->ec_io_ctl_addr + E33G_CNTRL,
! 271: (ifp->if_flags & IFF_LLC0) ? 0 : ECNTRL_ONBOARD);
1.1 root 272:
273: /*
274: * Set up the 8390 chip.
275: * (Use sequence recommended by 3Com. )
276: */
277: s=splhigh();
278: PAGE0
279: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP);
280: outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8);
281: outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0);
282: outb(sc->ec_io_nic_addr + EN0_RCNTHI, 0x0);
283: outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_MON );
284: outb(sc->ec_io_nic_addr + EN0_TXCR, 0x02);
285: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, EC_RXBUF_OFFSET);
286: outb(sc->ec_io_nic_addr + EN0_TPSR, 0x20);
287: outb(sc->ec_io_nic_addr + EN0_STARTPG, EC_RXBUF_OFFSET);
288: outb(sc->ec_io_nic_addr + EN0_STOPPG, EC_RXBUF_END);
289: outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
290: outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
291: /*
292: * Copy Ethernet address from SA_PROM into 8390 chip registers.
293: */
294: PAGE1
295: for(i=0;i<6;i++)
296: outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]);
297: /*
298: * Set multicast filter mask bits in case promiscuous rcv wanted (???)
299: * (set to 0xff as in if_we.c)
300: */
301: for(i=0;i<8;i++)
302: outb(sc->ec_io_nic_addr + EN1_MULT+i, 0xff);
303: /*
304: * Set current shared page for RX to work on.
305: */
306: outb(sc->ec_io_nic_addr + EN1_CURPAG, EC_RXBUF_OFFSET);
307: /*
308: * Start the 8390. Clear Interrupt Status reg, and accept Broadcast
309: * packets.
310: */
311: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA);
312: outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
313: outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0);
314: outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST);
315: /*
316: * Take interface out of reset, program the vector,
317: * enable interrupts, and tell the world we are up.
318: */
319: ifp->if_flags |= IFF_RUNNING;
320: outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_NORM); /* tcm, rsel, mbs0 */
321: (void) splx(s);
322: sc->ec_flags &= ~EC_TXBUSY;
323: ec_start_output(ifp);
324: }
325:
326: ec_start_output(ifp)
327: struct ifnet *ifp;
328: {
329: register struct ec_softc *sc = &ec_softc[ifp->if_unit];
330: struct mbuf *m0, *m;
331: register caddr_t buffer;
332: int len, s;
333: int ec_cmd_reg;
334:
335: /*
336: * The DS8390 only has one transmit buffer, if it is busy we
337: * must wait until the transmit interrupt completes.
338: */
339: s=splhigh();
340: if(sc->ec_flags & EC_TXBUSY)
341: {
342: (void) splx(s);
343: return;
344: }
345: IF_DEQUEUE(&sc->ec_if.if_snd, m);
346: if(m == 0)
347: {
348: (void) splx(s);
349: return;
350: }
351: sc->ec_flags |= EC_TXBUSY;
352: (void) splx(s);
353:
354: /*
355: * Copy the mbuf chain into the transmit buffer
356: */
357: buffer = sc->ec_vmem_addr;
358: len = 0;
359: for(m0 = m; m!= 0; m = m->m_next)
360: {
361: bcopy(mtod(m, caddr_t), buffer, m->m_len);
362: buffer += m->m_len;
363: len += m->m_len;
364: }
365: m_freem(m0);
366:
367: /*
368: * Init transmit length registers and set transmit start flag.
369: */
370: s=splhigh();
371: len = MAX(len, ETHER_MIN_LEN);
372: PAGE0
373: outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff);
374: outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8);
375: ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
376: outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS);
377: (void) splx(s);
378: }
379:
380: int ec_cmd_reg, ec_sts_reg;
381: /*
382: * Interrupt handler.
383: */
384: ecintr(unit)
385: int unit;
386: {
387: register struct ec_softc *sc = &ec_softc[unit];
388:
389: unit = 0;
390:
391: /*
392: * Get current command register and interrupt status.
393: * Turn off interrupts while we take care of things.
394: */
395: ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
396: PAGE0
397: ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR);
398: outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
399: loop:
400: outb(sc->ec_io_nic_addr + EN0_ISR, ec_sts_reg);
401: /*
402: * have we lost ourselves somewhere?
403: */
404: if (ec_sts_reg == 0xff)
405: ec_watchdog(unit);
406: /*
407: * Transmit error
408: */
409: if(ec_sts_reg & ENISR_TX_ERR)
410: {
411: sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
412: ++sc->ec_if.if_oerrors;
413: }
414: /*
415: * Receive Error
416: */
417: if(ec_sts_reg & ENISR_RX_ERR)
418: {
419: (void) inb(sc->ec_io_nic_addr + 0xD);
420: (void) inb(sc->ec_io_nic_addr + 0xE);
421: (void) inb(sc->ec_io_nic_addr + 0xF);
422: ++sc->ec_if.if_ierrors;
423: }
424: /*
425: * Normal transmit complete.
426: */
427: if(ec_sts_reg&ENISR_TX || ec_sts_reg&ENISR_TX_ERR)
428: ectint(unit);
429: /*
430: * Normal receive notification
431: */
432: if(ec_sts_reg&(ENISR_RX|ENISR_RX_ERR))
433: ecrint(unit);
434:
435: /*
436: * Try to start transmit
437: */
438: ec_start_output(&sc->ec_if);
439: /*
440: * Reenable onboard interrupts.
441: */
442: /*PAGE0*/
443: outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg);
444: outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
445: if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR))
446: goto loop;
447: }
448:
449: /*
450: * Transmit interrupt
451: */
452: ectint(unit)
453: int unit;
454: {
455: register struct ec_softc *sc = &ec_softc[unit];
456: /*
457: * Do some statistics.
458: */
459: PAGE0
460: sc->ec_flags &= ~EC_TXBUSY;
461: sc->ec_if.if_timer = 0;
462: ++sc->ec_if.if_opackets;
463: sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
464: }
465:
466: /*
467: * Receive interrupt.
468: * (This gave me the most trouble so excuse the mess.)
469: */
470: ecrint(unit)
471: int unit;
472: {
473: register struct ec_softc *sc = &ec_softc[unit];
474: u_char bnry, curr;
475: int len;
476: struct ec_ring *ecr;
477:
478: /*
479: * Traverse the receive ring looking for packets to pass back.
480: * The search is complete when we find a descriptor not in use.
481: */
482: PAGE0
483: bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY);
484: PAGE1
485: curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
486: if(Bdry)
487: bnry =Bdry;
488:
489: while (bnry != curr)
490: {
491: /* get pointer to this buffer header structure */
492: ecr = (struct ec_ring *)(sc->ec_vmem_addr + ((bnry-EC_VMEM_OFFSET) << 8));
493:
494: /* count includes CRC */
495: len = ecr->ec_count - 4;
496: /*if (len > 30 && len <= ETHERMTU+100) */
497: ecread(sc, (caddr_t)(ecr + 1), len);
498: /*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/
499: outofbufs:
500: PAGE0
501: /* advance on chip Boundry register */
502: if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) {
503: bnry = EC_RXBUF_OFFSET;
504: outb(sc->ec_io_nic_addr + EN0_BOUNDARY,
505: (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET);
506: } else {
507: if (len > 30 && len <= ETHERMTU+100)
508: bnry = ecr->ec_next_packet;
509: else bnry = curr;
510:
511: /* watch out for NIC overflow, reset Boundry if invalid */
512: if ((bnry - 1) < EC_RXBUF_OFFSET) {
513: outb(sc->ec_io_nic_addr + EN0_BOUNDARY,
514: (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET);
515: bnry = EC_RXBUF_OFFSET;
516: } else
517: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, bnry-1);
518: }
519:
520: /* refresh our copy of CURR */
521: PAGE1
522: curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
523: }
524: Bdry = bnry;
525: PAGE0
526: }
527:
528: #define ecdataaddr(sc, eh, off, type) \
529: ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \
530: (((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \
531: + (sc)->ec_vmem_ring: \
532: ((caddr_t)((eh)+1)+(off)))
533:
534: ecread(sc, buf, len)
535: register struct ec_softc *sc;
536: char *buf;
537: int len;
538: {
539: register struct ether_header *eh;
540: struct mbuf *m, *ecget();
541: int off, resid;
542:
1.1.1.3 ! root 543: ++sc->ec_if.if_ipackets;
1.1 root 544: /*
545: * Deal with trailer protocol: if type is trailer type
546: * get true type from first 16-bit word past data.
547: * Remember that type was trailer by setting off.
548: */
549: eh = (struct ether_header *)buf;
550: eh->ether_type = ntohs((u_short)eh->ether_type);
551: if (eh->ether_type >= ETHERTYPE_TRAIL &&
552: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
553: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
554: if (off >= ETHERMTU) return; /* sanity */
555: eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *));
556: resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *)));
557: if (off + resid > len) return; /* sanity */
558: len = off + resid;
559: } else off = 0;
560:
561: len -= sizeof(struct ether_header);
562: if (len <= 0) return;
563:
564: /*
565: * Pull packet off interface. Off is nonzero if packet
566: * has trailing header; neget will then force this header
567: * information to be at the front, but we still have to drop
568: * the type and length which are at the front of any trailer data.
569: */
570: m = ecget(buf, len, off, &sc->ec_if, sc);
571: if (m == 0) return;
572: ether_input(&sc->ec_if, eh, m);
573: }
574: ec_ioctl(ifp, cmd, data)
575: register struct ifnet *ifp;
576: int cmd;
577: caddr_t data;
578: {
579: register struct ifaddr *ifa = (struct ifaddr *)data;
580: struct ec_softc *sc = &ec_softc[ifp->if_unit];
581: struct ifreq *ifr = (struct ifreq *)data;
582: int s=splimp(), error=0;
583: switch(cmd){
584: case SIOCSIFADDR:
585: ifp->if_flags |= IFF_UP;
586: switch (ifa->ifa_addr->sa_family) {
587: #ifdef INET
588: case AF_INET:
589: ec_init(ifp->if_unit); /* before arpwhohas */
590: ((struct arpcom *)ifp)->ac_ipaddr =
591: IA_SIN(ifa)->sin_addr;
592: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
593: break;
594: #endif
595: #ifdef NS
596: case AF_NS:
597: {
598: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
599:
600: if (ns_nullhost(*ina))
1.1.1.2 root 601: ina->x_host = *(union ns_host *)(sc->ns_addrp);
1.1 root 602: else {
603: /*
604: * The manual says we can't change the address
605: * while the receiver is armed,
606: * so reset everything
607: */
608: ifp->if_flags &= ~IFF_RUNNING;
609: bcopy((caddr_t)ina->x_host.c_host,
1.1.1.2 root 610: (caddr_t)sc->ns_addrp, sizeof(sc->ns_addrp));
1.1 root 611: }
612: ec_init(ifp->if_unit); /* does ne_setaddr() */
613: break;
614: }
615: #endif
616: default:
617: ec_init(ifp->if_unit);
618: break;
619: }
620: break;
621:
622: case SIOCSIFFLAGS:
623: if ((ifp->if_flags & IFF_UP) == 0 &&
624: ifp->if_flags & IFF_RUNNING) {
625: ifp->if_flags &= ~IFF_RUNNING;
626: ec_stop(ifp->if_unit);
627: } else if (ifp->if_flags & IFF_UP &&
628: (ifp->if_flags & IFF_RUNNING) == 0)
629: ec_init(ifp->if_unit);
630: break;
631:
632: #ifdef notdef
633: case SIOCGHWADDR:
634: bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
635: sizeof(sc->sc_addr));
636: break;
637: #endif
638:
639: default:
640: error = EINVAL;
641: }
642: splx(s);
643: return (error);
644: }
645:
646: ec_reset(unit)
647: int unit;
648: {
649: if(unit >= NEC)
650: return;
651: printf("ec%d: reset\n", unit);
652: ec_init(unit);
653: }
654:
655: ec_watchdog(unit)
656: int unit;
657: {
658: log(LOG_WARNING, "ec%d: soft reset\n", unit);
659: ec_stop(unit);
660: ec_init(unit);
661: }
662:
663: ec_stop(unit)
664: int unit;
665: {
666: register struct ec_softc *sc = &ec_softc[unit];
667: int s;
668:
669: s=splimp();
670: PAGE0
671: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
672: outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
673: sc->ec_flags &= ~EC_RUNNING;
674: /*
675: * Shutdown the 8390.
676: */
677: (void) splx(s);
678: }
679:
680: /*
681: * Pull read data off a interface.
682: * Len is length of data, with local net header stripped.
683: * Off is non-zero if a trailer protocol was used, and
684: * gives the offset of the trailer information.
685: * We copy the trailer information and then all the normal
686: * data into mbufs. When full cluster sized units are present
687: * we copy into clusters.
688: */
689: struct mbuf *
690: ecget(buf, totlen, off0, ifp, sc)
691: caddr_t buf;
692: int totlen, off0;
693: struct ifnet *ifp;
694: struct ec_softc *sc;
695: {
696: struct mbuf *top, **mp, *m, *p;
697: int off = off0, len;
698: register caddr_t cp = buf;
699: char *epkt;
700: int tc =totlen;
701:
702: buf += sizeof(struct ether_header);
703: cp = buf;
704: epkt = cp + totlen;
705:
706: if (off) {
707: cp += off + 2 * sizeof(u_short);
708: totlen -= 2 * sizeof(u_short);
709: }
710:
711: MGETHDR(m, M_DONTWAIT, MT_DATA);
712: if (m == 0)
713: return (0);
714: m->m_pkthdr.rcvif = ifp;
715: m->m_pkthdr.len = totlen;
716: m->m_len = MHLEN;
717:
718: top = 0;
719: mp = ⊤
720: while (totlen > 0) {
721: if (top) {
722: MGET(m, M_DONTWAIT, MT_DATA);
723: if (m == 0) {
724: m_freem(top);
725: return (0);
726: }
727: m->m_len = MLEN;
728: }
729: len = min(totlen, epkt - cp);
730: if (len >= MINCLSIZE) {
731: MCLGET(m, M_DONTWAIT);
732: if (m->m_flags & M_EXT)
733: m->m_len = len = min(len, MCLBYTES);
734: else
735: len = m->m_len;
736: } else {
737: /*
738: * Place initial small packet/header at end of mbuf.
739: */
740: if (len < m->m_len) {
741: if (top == 0 && len + max_linkhdr <= m->m_len)
742: m->m_data += max_linkhdr;
743: m->m_len = len;
744: } else
745: len = m->m_len;
746: }
747:
748: totlen -= len;
749: /* only do up to end of buffer */
750: if (cp+len > sc->ec_vmem_end) {
751: unsigned toend = sc->ec_vmem_end - cp;
752:
753: bcopy(cp, mtod(m, caddr_t), toend);
754: cp = sc->ec_vmem_ring;
755: bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
756: cp += len - toend;
757: epkt = cp + totlen;
758: } else {
759: bcopy(cp, mtod(m, caddr_t), (unsigned)len);
760: cp += len;
761: }
762: *mp = m;
763: mp = &m->m_next;
764: if (cp == epkt) {
765: cp = buf;
766: epkt = cp + tc;
767: }
768: }
769: return (top);
770: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.