FreeBSD/Linux Kernel Cross Reference
sys/i386at/if_3c501.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: if_3c501.c,v $
29 * Revision 2.16 93/11/17 16:46:08 dbg
30 * Removed all non-MACH_KERNEL code. Changed uses of 'HZ' to 'hz'.
31 * [93/05/21 dbg]
32 *
33 * Revision 2.15 93/05/10 21:19:13 rvb
34 * Lint.
35 * [93/05/08 11:22:57 af]
36 *
37 * Revision 2.14 93/03/11 13:58:09 danner
38 * u_long -> u_int.
39 * [93/03/09 danner]
40 *
41 * Revision 2.13 93/01/14 17:30:30 danner
42 * Proper spl typing.
43 * [92/11/30 af]
44 *
45 * Revision 2.12 91/08/24 11:57:53 af
46 * New MI autoconf.
47 * [91/08/02 02:54:56 af]
48 *
49 * Revision 2.11 91/05/14 16:24:19 mrt
50 * Correcting copyright
51 *
52 * Revision 2.10 91/05/13 06:02:32 af
53 * Made code under CMUCS standard.
54 * [91/05/12 15:50:59 af]
55 *
56 * Revision 2.9 91/03/16 14:46:08 rpd
57 * Changed net_filter to net_packet.
58 * [91/01/15 rpd]
59 *
60 * Revision 2.8 91/02/05 17:17:32 mrt
61 * Added OSF permision and disclaimer clause per instructions
62 * of Philippe Bernadat.
63 * [91/02/04 mrt]
64 * Changed to new Mach copyright
65 * [91/02/01 17:43:37 mrt]
66 *
67 * Revision 2.7 91/01/08 15:11:34 rpd
68 * Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
69 * [91/01/05 rpd]
70 *
71 * Revision 2.6 90/11/26 14:49:51 rvb
72 * jsb beat me to XMK34, sigh ...
73 * [90/11/26 rvb]
74 * Synched 2.5 & 3.0 at I386q (r2.1.1.4) & XMK35 (r2.6)
75 * [90/11/15 rvb]
76 *
77 * Revision 2.5 90/08/27 22:00:04 dbg
78 * Change ushort to unsigned short.
79 * [90/07/17 dbg]
80 *
81 * Revision 2.1.1.3 90/08/25 15:44:09 rvb
82 * Use take_<>_irq() vs direct manipulations of ivect and friends.
83 * [90/08/20 rvb]
84 *
85 * Fix DSF_RUNNING. Some more cleanup.
86 * [90/08/14 rvb]
87 *
88 * Revision 2.1.1.2 90/07/10 11:50:05 rvb
89 * Set etherheader in hwrst to fend off madness of the wtprobe().
90 * [90/07/02 rvb]
91 *
92 * New style probe/attach.
93 * [90/06/15 rvb]
94 *
95 * Fix xmt if jam to retry. Set tcp_recvspace for better
96 * "sink" behaviour.
97 * [90/03/29 rvb]
98 *
99 * Revision 2.4 90/06/02 14:49:05 rpd
100 * Converted to new IPC.
101 * [90/06/01 rpd]
102 *
103 * Revision 2.3 90/05/21 13:27:01 dbg
104 * Fix bugs.
105 * [90/05/17 dbg]
106 *
107 * Revision 2.2 90/05/03 15:43:38 dbg
108 * Convert for pure kernel.
109 * [90/04/27 dbg]
110 *
111 * Revision 2.1.1.1 90/03/16 18:15:22 rvb
112 * Clean up the i386_dev/i386_ctlr confusion.
113 * Some minor cleanups
114 * installed.
115 * [90/03/13 rvb]
116 * Created by Philippe Bernadat
117 */
118 /*
119 * File: if_3c501.c
120 * Author: Philippe Bernadat
121 * Date: 1989
122 * Copyright (c) 1989 OSF Research Institute
123 *
124 * 3COM Etherlink 3C501 Mach Ethernet drvier
125 */
126 /*
127 Copyright 1990 by Open Software Foundation,
128 Cambridge, MA.
129
130 All Rights Reserved
131
132 Permission to use, copy, modify, and distribute this software and
133 its documentation for any purpose and without fee is hereby granted,
134 provided that the above copyright notice appears in all copies and
135 that both the copyright notice and this permission notice appear in
136 supporting documentation, and that the name of OSF or Open Software
137 Foundation not be used in advertising or publicity pertaining to
138 distribution of the software without specific, written prior
139 permission.
140
141 OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
142 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
143 IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
144 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
145 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
146 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
147 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
148 */
149
150 #include <at3c501.h>
151
152 #include <kern/kern_io.h> /* printf */
153 #include <kern/strings.h> /* strncmp */
154 #include <kern/time_out.h>
155 #include <device/device_types.h>
156 #include <device/errno.h>
157 #include <device/io_req.h>
158 #include <device/if_hdr.h>
159 #include <device/if_ether.h>
160 #include <device/net_status.h>
161 #include <device/net_io.h>
162
163 #include <i386/ipl.h>
164 #include <i386/machspl.h>
165 #include <i386/pio.h>
166 #include <chips/busses.h>
167 #include <i386at/if_3c501.h>
168
169 #define SPLNET spl6
170
171 boolean_t at3c501probe(
172 vm_offset_t port,
173 struct bus_device *dev);
174 void at3c501attach(
175 struct bus_device *dev);
176 int at3c501intr();
177 void at3c501init(
178 int unit);
179 io_return_t at3c501output(
180 dev_t dev,
181 io_req_t ior);
182 void at3c501xmt(
183 int unit,
184 io_req_t m);
185 void at3c501reset(int unit);
186 void at3c501watch(void *b_ptr);
187 void at3c501geteh(
188 unsigned short base,
189 char * ep);
190 void at3c501seteh(
191 unsigned short base,
192 char * ep);
193
194 static vm_offset_t at3c501_std[NAT3C501] = { 0 };
195 static struct bus_device *at3c501_info[NAT3C501];
196 struct bus_driver at3c501driver =
197 {at3c501probe, 0, at3c501attach, 0, at3c501_std, "et", at3c501_info, };
198
199 int watchdog_id;
200
201 typedef struct {
202 struct ifnet ds_if; /* generic interface header */
203 u_char ds_addr[6]; /* Ethernet hardware address */
204 int flags;
205 int timer;
206 unsigned short base; /* base address of IO ports */
207 u_char address[ETHER_ADD_SIZE];
208 short mode;
209 int badxmt;
210 int badrcv;
211 int spurious;
212 int rcv;
213 int xmt;
214 } at3c501_softc_t;
215
216 at3c501_softc_t at3c501_softc[NAT3C501];
217
218 /*
219 * at3c501probe:
220 *
221 * This function "probes" or checks for the 3c501 board on the bus to see
222 * if it is there. As far as I can tell, the best break between this
223 * routine and the attach code is to simply determine whether the board
224 * is configured in properly. Currently my approach to this is to write
225 * and read a string from the Packet Buffer on the board being probed.
226 * If the string comes back properly then we assume the board is there.
227 * The config code expects to see a successful return from the probe
228 * routine before attach will be called.
229 *
230 * input : address device is mapped to, and unit # being checked
231 * output : a '1' is returned if the board exists, and a 0 otherwise
232 *
233 */
234 boolean_t at3c501probe(
235 vm_offset_t port,
236 struct bus_device *dev)
237 {
238 unsigned short base = (unsigned short) dev->address;
239 int unit = dev->unit;
240 char inbuf[50];
241 char *str = "3c501 ethernet board %d out of range\n";
242 int strsize = strlen(str);
243
244 if ((unit < 0) || (unit >= NAT3C501)) {
245 printf(str, unit);
246 return(0);
247 }
248
249 /* reset */
250 outb(IE_CSR(base), IE_RESET);
251
252 /* write a string to the packet buffer */
253
254 outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
255 outw(IE_GP(base), 0);
256 loutb(IE_BFR(base), str, strsize);
257
258 /* read it back */
259
260 outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
261 outw(IE_GP(base), 0);
262 linb(IE_BFR(base), inbuf, strsize);
263 /* compare them */
264
265 if (strncmp(str, inbuf, strsize))
266 {
267 return FALSE;
268 }
269 at3c501_softc[unit].base = base;
270
271 return TRUE;
272 }
273
274 /*
275 * at3c501attach:
276 *
277 * This function attaches a 3C501 board to the "system". The rest of
278 * runtime structures are initialized here (this routine is called after
279 * a successful probe of the board). Once the ethernet address is read
280 * and stored, the board's ifnet structure is attached and readied.
281 *
282 * input : bus_device structure setup in autoconfig
283 * output : board structs and ifnet is setup
284 *
285 */
286 void at3c501attach(
287 struct bus_device *dev)
288 {
289 at3c501_softc_t *sp;
290 struct ifnet *ifp;
291 u_char unit;
292 unsigned short base;
293
294 #if 0 /* can`t do this! */
295 extern int tcp_recvspace;
296 tcp_recvspace = 0x300; /* empircal measure */
297 #endif
298
299 take_dev_irq(dev);
300 unit = (u_char)dev->unit;
301 printf(", port = %x, spl = %d, pic = %d. ",
302 dev->address, dev->sysdep, dev->sysdep1);
303
304 sp = &at3c501_softc[unit];
305 base = sp->base;
306 if (base != dev->address) {
307 printf("3C501 board %d attach address error\n", unit);
308 return;
309 }
310 sp->timer = -1;
311 sp->flags = 0;
312 sp->mode = 0;
313 outb(IE_CSR(sp->base), IE_RESET);
314 at3c501geteh(base, sp->ds_addr);
315 at3c501geteh(base, sp->address);
316 at3c501seteh(base, sp->address);
317 printf("ethernet id [%x:%x:%x:%x:%x:%x]",
318 sp->address[0],sp->address[1],sp->address[2],
319 sp->address[3],sp->address[4],sp->address[5]);
320 ifp = &(sp->ds_if);
321 ifp->if_unit = unit;
322 ifp->if_mtu = ETHERMTU;
323 ifp->if_flags = IFF_BROADCAST;
324 ifp->if_header_size = sizeof(struct ether_header);
325 ifp->if_header_format = HDR_ETHERNET;
326 ifp->if_address_size = 6;
327 ifp->if_address = (char *)&sp->address[0];
328 if_init_queues(ifp);
329 }
330
331 /*
332 * at3c501watch():
333 *
334 */
335 void at3c501watch(void *b_ptr)
336 {
337 int unit;
338 at3c501_softc_t *is;
339
340 unit = *(char *)b_ptr;
341 timeout(at3c501watch,b_ptr,20*hz);
342 is = &at3c501_softc[unit];
343 printf("\nxmt/bad rcv/bad spurious\n");
344 printf("%d/%d %d/%d %d\n", is->xmt, is->badxmt, \
345 is->rcv, is->badrcv, is->spurious);
346 is->rcv=is->badrcv=is->xmt=is->badxmt=is->spurious=0;
347 }
348
349 /*
350 * at3c501geteh:
351 *
352 * This function gets the ethernet address (array of 6 unsigned
353 * bytes) from the 3c501 board prom.
354 *
355 */
356
357 void at3c501geteh(
358 unsigned short base,
359 char * ep)
360 {
361 int i;
362
363 for (i = 0; i < ETHER_ADD_SIZE; i++) {
364 outw(IE_GP(base), i);
365 *ep++ = inb(IE_SAPROM(base));
366 }
367 }
368
369 /*
370 * at3c501seteh:
371 *
372 * This function sets the ethernet address (array of 6 unsigned
373 * bytes) on the 3c501 board.
374 *
375 */
376
377 void at3c501seteh(
378 unsigned short base,
379 char * ep)
380 {
381 int i;
382
383 for (i = 0; i < ETHER_ADD_SIZE; i++) {
384 outb(EDLC_ADDR(base) + i, *ep++);
385 }
386 }
387
388 void at3c501start(int unit); /* forward */
389
390 io_return_t
391 at3c501output(
392 dev_t dev,
393 io_req_t ior)
394 {
395 register int unit = minor(dev);
396
397 if (unit < 0 || unit >= NAT3C501 ||
398 at3c501_softc[unit].base == 0)
399 return ENXIO;
400
401 return net_write(&at3c501_softc[unit].ds_if, at3c501start, ior);
402 }
403
404 io_return_t
405 at3c501setinput(
406 dev_t dev,
407 mach_port_t receive_port,
408 int priority,
409 filter_t filter[],
410 natural_t filter_count)
411 {
412 register int unit = minor(dev);
413
414 if (unit < 0 || unit >= NAT3C501 ||
415 at3c501_softc[unit].base == 0)
416 return ENXIO;
417
418 return net_set_filter(&at3c501_softc[unit].ds_if,
419 receive_port, priority,
420 filter, filter_count);
421 }
422
423
424 /*
425 * at3c501reset:
426 *
427 * This routine is in part an entry point for the "if" code. Since most
428 * of the actual initialization has already (we hope already) been done
429 * by calling at3c501attach().
430 *
431 * input : unit number or board number to reset
432 * output : board is reset
433 *
434 */
435 void at3c501reset(
436 int unit)
437 {
438 at3c501_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
439 at3c501init(unit);
440 }
441
442
443
444 /*
445 * at3c501init:
446 *
447 * Another routine that interfaces the "if" layer to this driver.
448 * Simply resets the structures that are used by "upper layers".
449 * As well as calling at3c501hwrst that does reset the at3c501 board.
450 *
451 * input : board number
452 * output : structures (if structs) and board are reset
453 *
454 */
455 void at3c501init(
456 int unit)
457 {
458 struct ifnet *ifp;
459 int stat;
460 spl_t oldpri;
461
462 ifp = &(at3c501_softc[unit].ds_if);
463 oldpri = SPLNET();
464 if ((stat = at3c501hwrst(unit)) == TRUE) {
465 at3c501_softc[unit].ds_if.if_flags |= IFF_RUNNING;
466 at3c501_softc[unit].flags |= DSF_RUNNING;
467 at3c501start(unit);
468 }
469 else
470 printf("3C501 trouble resetting board %d\n", unit);
471 at3c501_softc[unit].timer = 5;
472 splx(oldpri);
473 /* XXX no return value - callers ignore */
474 }
475
476 /*ARGSUSED*/
477 at3c501open(dev, flag)
478 dev_t dev;
479 int flag;
480 {
481 register int unit = minor(dev);
482
483 if (unit < 0 || unit >= NAT3C501 ||
484 at3c501_softc[unit].base == 0)
485 return (ENXIO);
486
487 at3c501_softc[unit].ds_if.if_flags |= IFF_UP;
488 at3c501init(unit);
489 return(0);
490 }
491
492 /*
493 * at3c501start:
494 *
495 * This is yet another interface routine that simply tries to output a
496 * in an mbuf after a reset.
497 *
498 * input : board number
499 * output : stuff sent to board if any there
500 *
501 */
502 void at3c501start(
503 int unit)
504 {
505 io_req_t m;
506 struct ifnet *ifp;
507
508 ifp = &(at3c501_softc[unit].ds_if);
509 for(;;) {
510 IF_DEQUEUE(&ifp->if_snd, m);
511 if (m != 0)
512 at3c501xmt(unit, m);
513 else
514 return;
515 }
516 }
517
518 /*ARGSUSED*/
519 io_return_t
520 at3c501getstat(
521 dev_t dev,
522 dev_flavor_t flavor,
523 dev_status_t status, /* pointer to OUT array */
524 natural_t *count) /* out */
525 {
526 register int unit = minor(dev);
527
528 if (unit < 0 || unit >= NAT3C501 ||
529 at3c501_softc[unit].base == 0)
530 return ENXIO;
531
532 return net_getstat(&at3c501_softc[unit].ds_if,
533 flavor,
534 status,
535 count);
536 }
537
538 io_return_t
539 at3c501setstat(
540 dev_t dev,
541 int flavor,
542 dev_status_t status,
543 natural_t count)
544 {
545 register int unit = minor(dev);
546 register at3c501_softc_t *sp;
547
548 if (unit < 0 || unit >= NAT3C501 ||
549 at3c501_softc[unit].base == 0)
550 return (ENXIO);
551
552 sp = &at3c501_softc[unit];
553
554 switch (flavor) {
555 case NET_STATUS:
556 {
557 /*
558 * All we can change are flags, and not many of those.
559 */
560 register struct net_status *ns = (struct net_status *)status;
561 int mode = 0;
562
563 if (count < NET_STATUS_COUNT)
564 return (D_INVALID_SIZE);
565
566 if (ns->flags & IFF_ALLMULTI)
567 mode |= MOD_ENAL;
568 if (ns->flags & IFF_PROMISC)
569 mode |= MOD_PROM;
570
571 /*
572 * Force a compilete reset if the receive mode changes
573 * so that these take effect immediately.
574 */
575 if (sp->mode != mode) {
576 sp->mode = mode;
577 if (sp->flags & DSF_RUNNING) {
578 sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
579 at3c501init(unit);
580 }
581 }
582 break;
583 }
584 case NET_ADDRESS:
585 {
586 register union ether_cvt {
587 char addr[6];
588 int lwd[2];
589 } *ec = (union ether_cvt *)status;
590
591 if (count < sizeof(*ec)/sizeof(int))
592 return (D_INVALID_SIZE);
593
594 ec->lwd[0] = ntohl(ec->lwd[0]);
595 ec->lwd[1] = ntohl(ec->lwd[1]);
596 at3c501seteh(sp->base, ec->addr);
597 break;
598 }
599
600 default:
601 return (D_INVALID_OPERATION);
602 }
603 return (D_SUCCESS);
604 }
605
606 /*
607 * at3c501hwrst:
608 *
609 * This routine resets the at3c501 board that corresponds to the
610 * board number passed in.
611 *
612 * input : board number to do a hardware reset
613 * output : board is reset
614 *
615 */
616 #define XMT_STAT (EDLC_16|EDLC_JAM|EDLC_UNDER|EDLC_IDLE)
617 #define RCV_STAT (EDLC_STALE|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_OVER|EDLC_FCS)
618 int
619 at3c501hwrst(unit)
620 int unit;
621 {
622 u_char stat;
623 unsigned short base = at3c501_softc[unit].base;
624
625 outb(IE_CSR(base), IE_RESET);
626 outb(IE_CSR(base), 0);
627 at3c501seteh(base, at3c501_softc[unit].address);
628 if ((stat = inb(IE_CSR(base))) != IE_RESET) {
629 printf("at3c501reset: can't reset CSR: %x\n", stat);
630 return(FALSE);
631 }
632 if ((stat = inb(EDLC_XMT(base))) & XMT_STAT) {
633 printf("at3c501reset: can't reset XMT: %x\n", stat);
634 return(FALSE);
635 }
636 if (((stat = inb(EDLC_RCV(base))) & RCV_STAT) != EDLC_STALE) {
637 printf("at3c501reset: can't reset RCV: %x\n", stat);
638 return(FALSE);
639 }
640 if (at3c501config(unit) == FALSE) {
641 printf("at3c501hwrst(): failed to config\n");
642 return(FALSE);
643 }
644 outb(IE_RP(base), 0);
645 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
646 return(TRUE);
647 }
648
649 /*
650 * at3c501intr:
651 *
652 * This function is the interrupt handler for the at3c501 ethernet
653 * board. This routine will be called whenever either a packet
654 * is received, or a packet has successfully been transfered and
655 * the unit is ready to transmit another packet.
656 *
657 * input : board number that interrupted
658 * output : either a packet is received, or a packet is transfered
659 *
660 */
661 at3c501intr(unit)
662 int unit;
663 {
664 at3c501rcv(unit);
665 at3c501start(unit);
666
667 return(0);
668 }
669
670
671 /*
672 * at3c501rcv:
673 *
674 * This routine is called by the interrupt handler to initiate a
675 * packet transfer from the board to the "if" layer above this
676 * driver. This routine checks if a buffer has been successfully
677 * received by the at3c501. If so, the routine at3c501read is called
678 * to do the actual transfer of the board data (including the
679 * ethernet header) into a packet (consisting of an mbuf chain).
680 *
681 * input : number of the board to check
682 * output : if a packet is available, it is "sent up"
683 *
684 */
685 at3c501rcv(unit)
686 int unit;
687 {
688 int stat;
689 unsigned short base;
690 ipc_kmsg_t new_kmsg;
691 struct ether_header *ehp;
692 struct packet_header *pkt;
693 u_short len;
694 register struct ifnet *ifp;
695 register at3c501_softc_t *is;
696 struct ether_header eh;
697
698 is = &at3c501_softc[unit];
699 ifp = &is->ds_if;
700 base = at3c501_softc[unit].base;
701 is->rcv++;
702 if (inb(IE_CSR(base)) & IE_RCVBSY)
703 is->spurious++;
704 while (!((stat=inb(EDLC_RCV(base))) & EDLC_STALE)) {
705 outb(IE_CSR(base), IE_SYSBFR);
706 if (!(stat & EDLC_ANY)) {
707 outw(IE_GP(base), 0);
708 len = inw(IE_RP(base))-sizeof(struct ether_header);
709 outb(IE_RP(base), 0);
710 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
711 is->badrcv++;
712 #ifdef DEBUG
713 printf("at3c501rcv: received %d bad bytes", len);
714 if (stat & EDLC_SHORT)
715 printf(" Short frame");
716 if (stat & EDLC_OVER)
717 printf(" Data overflow");
718 if (stat & EDLC_DRIBBLE)
719 printf(" Dribble error");
720 if (stat & EDLC_FCS)
721 printf(" CRC error");
722 printf("\n");
723 #endif DEBUG
724 } else {
725 outw(IE_GP(base), 0);
726 len = inw(IE_RP(base));
727 if (len < 60) {
728 outb(IE_RP(base), 0);
729 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
730 return;
731 }
732 linb(IE_BFR(base), &eh, sizeof(struct ether_header));
733 new_kmsg = net_kmsg_get();
734 if (new_kmsg == IKM_NULL) {
735 /*
736 * Drop the packet.
737 */
738 is->ds_if.if_rcvdrops++;
739
740 outb(IE_RP(base), 0);
741 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
742 return;
743 }
744
745 ehp = (struct ether_header *)
746 (&net_kmsg(new_kmsg)->header[0]);
747 pkt = (struct packet_header *)
748 (&net_kmsg(new_kmsg)->packet[0]);
749
750 /*
751 * Get header.
752 */
753 *ehp = eh;
754
755 /*
756 * Get body
757 */
758 linb(IE_BFR(base),
759 (char *)(pkt + 1),
760 len - sizeof(struct ether_header));
761
762 outb(IE_RP(base), 0);
763 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
764
765 pkt->type = ehp->ether_type;
766 pkt->length = len - sizeof(struct ether_header)
767 + sizeof(struct packet_header);
768
769 /*
770 * Hand the packet to the network module.
771 */
772 net_packet(ifp, new_kmsg, pkt->length,
773 ethernet_priority(new_kmsg));
774
775 }
776 }
777 }
778
779
780 /*
781 * at3c501xmt:
782 *
783 * This routine fills in the appropriate registers and memory
784 * locations on the 3C501 board and starts the board off on
785 * the transmit.
786 *
787 * input : board number of interest, and a pointer to the mbuf
788 * output : board memory and registers are set for xfer and attention
789 *
790 */
791 void at3c501xmt(
792 int unit,
793 io_req_t m)
794 {
795 int i;
796 at3c501_softc_t *is = &at3c501_softc[unit];
797 unsigned short base = is->base;
798 u_short count = 0;
799 u_short bytes_in_msg;
800
801 is->xmt++;
802 outb(IE_CSR(base), IE_SYSBFR);
803 count = m->io_count;
804 #define max(a,b) (((a) > (b)) ? (a) : (b))
805 bytes_in_msg = max(count,
806 ETHERMIN + sizeof(struct ether_header));
807 outw(IE_GP(base), BFRSIZ-bytes_in_msg);
808 loutb(IE_BFR(base), m->io_data, count);
809 while (count < bytes_in_msg) {
810 outb(IE_BFR(base), 0);
811 count++;
812 }
813 do {
814 if (!(int)m) {
815 outb(IE_CSR(base), IE_SYSBFR);
816 }
817 outw(IE_GP(base), BFRSIZ-bytes_in_msg);
818 outb(IE_CSR(base), IE_RIDE|IE_XMTEDLC);
819 if (m) {
820 iodone(m);
821 m = 0;
822 }
823 for (i=0; inb(IE_CSR(base)) & IE_XMTBSY; i++);
824 if ((i=inb(EDLC_XMT(base))) & EDLC_JAM) {
825 is->badxmt++;
826 #ifdef DEBUG
827 printf("at3c501xmt jam\n");
828 #endif DEBUG
829 }
830 } while ((i & EDLC_JAM) && !(i & EDLC_16));
831
832 if (i & EDLC_16) {
833 printf("%%");
834 }
835 return;
836
837 }
838
839 /*
840 * at3c501config:
841 *
842 * This routine does a standard config of the at3c501 board.
843 *
844 */
845 at3c501config(unit)
846 int unit;
847 {
848 unsigned short base = at3c501_softc[unit].base;
849
850 /* Enable DMA & Interrupts */
851
852 outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
853
854 /* No Transmit Interrupts */
855
856 outb(EDLC_XMT(base), 0);
857 inb(EDLC_XMT(base));
858
859 /* Setup Receive Interrupts */
860
861 outb(EDLC_RCV(base), EDLC_BROAD|EDLC_SHORT|EDLC_GOOD|EDLC_DRIBBLE|EDLC_OVER);
862 inb(EDLC_RCV(base));
863
864 outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
865 outb(IE_RP(base), 0);
866 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
867 return(TRUE);
868 }
869
870 /*
871 * at3c501intoff:
872 *
873 * This function turns interrupts off for the at3c501 board indicated.
874 *
875 */
876 at3c501intoff(unit)
877 int unit;
878 {
879 unsigned short base = at3c501_softc[unit].base;
880 outb(IE_CSR(base), 0);
881 }
882
Cache object: c6991a8bde76d86cca564dab2bd081c5
|