FreeBSD/Linux Kernel Cross Reference
sys/i386at/if_pc586.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 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_pc586.c,v $
29 * Revision 2.22 93/05/10 21:19:37 rvb
30 * Lint.
31 * [93/05/08 11:21:38 af]
32 *
33 * Revision 2.21 93/01/24 13:17:39 danner
34 * Found a pc586 with octets 0:0:1c
35 * [93/01/15 rvb]
36 *
37 * Revision 2.20 93/01/14 17:30:55 danner
38 * Proper spl typing.
39 * [92/11/30 af]
40 *
41 * Revision 2.19 92/07/09 22:54:30 rvb
42 * Check for pc586 signature, rather than just for writable memory.
43 * [92/05/18 rvb]
44 *
45 * Revision 2.18 91/11/12 11:09:47 rvb
46 * Undo 2.16.1.1
47 * [91/10/25 rvb]
48 * Typo in transcribing the 2.5 changes missed ! before pc586read().
49 * Funny thing is that we did have this fixed in a branch once.
50 * [91/10/16 rvb]
51 *
52 * Revision 2.17 91/10/07 17:25:48 af
53 * Add a lot of fixes/improvements from 2.5.
54 * [91/09/04 rvb]
55 *
56 * Revision 2.16.1.1 91/09/03 17:27:39 af
57 * Be strict on matching the port and the device in the probe routine.
58 *
59 * Revision 2.16 91/08/24 11:58:12 af
60 * New MI autoconf.
61 * [91/08/02 02:54:27 af]
62 *
63 * Revision 2.15 91/05/14 16:25:37 mrt
64 * Correcting copyright
65 *
66 * Revision 2.14 91/05/13 06:02:51 af
67 * Made code under CMUCS standard.
68 * [91/05/12 15:50:10 af]
69 *
70 * Revision 2.13 91/03/16 14:46:38 rpd
71 * Updated for new kmem_alloc interface.
72 * [91/03/03 rpd]
73 * Changed net_filter to net_packet.
74 * [91/01/15 rpd]
75 *
76 * Revision 2.12 91/02/14 14:43:03 mrt
77 * You must check RBD_SW_EOF for rbd chain termination, a link of 0xffff
78 * does not work. Also we've just seen a status of 0xffff in rcv() with
79 * a bad fd_p->link_offset; we'll now reset.
80 * [91/01/17 rvb]
81 *
82 * Revision 2.11 91/02/05 17:18:19 mrt
83 * Changed to new Mach copyright
84 * [91/02/01 17:44:30 mrt]
85 *
86 * Revision 2.10 91/01/08 15:11:45 rpd
87 * Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
88 * [91/01/05 rpd]
89 *
90 * Revision 1.8.1.11 90/12/07 22:53:44 rvb
91 * Fix a few problems if your hardware goes haywire.
92 * Noted by Ali.
93 * [90/12/11 rvb]
94 *
95 * Revision 2.9 90/12/20 16:38:09 jeffreyh
96 * Changes for __STDC__
97 * [90/12/07 jeffreyh]
98 *
99 * Revision 1.8.1.12 91/01/06 22:11:54 rvb
100 * Try try again to get the ram_to_ptr problem in requeue.
101 * [90/11/29 rvb]
102 *
103 * Revision 2.8 90/11/26 14:49:59 rvb
104 * jsb bet me to XMK34, sigh ...
105 * [90/11/26 rvb]
106 * Synched 2.5 & 3.0 at I386q (r1.8.1.10) & XMK35 (r2.8)
107 * [90/11/15 rvb]
108 *
109 * Revision 2.7 90/11/05 14:28:11 rpd
110 * Convert for pure kernel
111 * [90/11/02 rvb]
112 *
113 * Init scb and reset as per spec. Use bcopy16 vs pc586copy as per spec.
114 * Accumulate counters at hwrst. Add counters everywhere.
115 * Editing and style and consistency cleanup.
116 * Flush NOP's: this required major mods to hwrst and everything it
117 * called -- testing OK is not correct if the command is not COMPLETE.
118 * Lot's of code clean up in xmt, rcv, reqfd.
119 * Flush pc_softc_t "address" and pc586ehcpy.
120 * Handle loopback of our ownbroadcast.
121 * The rcv and xmt loops have been rewriten not copy sram
122 * to the t_packet buffer. This yields a teriffic thruput
123 * improvement.
124 * Add Notes and sram map.
125 * [90/09/28 rvb]
126 *
127 * Revision 1.8.1.9 90/09/18 08:39:03 rvb
128 * Debugging printout to find shutdown reason.
129 * [90/09/14 rvb]
130 *
131 * Revision 1.8.1.8 90/08/25 15:44:14 rvb
132 * Use take_<>_irq() vs direct manipulations of ivect and friends.
133 * [90/08/20 rvb]
134 *
135 * Fix DSF_RUNNING. Some more cleanup.
136 * [90/08/14 rvb]
137 *
138 * Revision 1.8.1.7 90/07/27 11:26:06 rvb
139 * Fix Intel Copyright as per B. Davies authorization.
140 * [90/07/27 rvb]
141 *
142 * Revision 1.8.1.6 90/07/10 11:43:44 rvb
143 * New style probe/attach.
144 * [90/06/15 rvb]
145 *
146 * Revision 2.4 90/06/02 14:49:13 rpd
147 * Converted to new IPC.
148 * [90/06/01 rpd]
149 *
150 * Revision 2.3 90/05/29 18:48:51 rwd
151 * Test for next_rbd_offset NULL instead of RBD_SW_EOF in
152 * pc586reqfd. I don't know why this is needed on the pure kernel
153 * but not in the mainline - our slower device interface triggers a
154 * race?
155 * [90/05/25 dbg]
156 *
157 * Revision 2.2 90/05/03 15:44:10 dbg
158 * Check whether device exists on open.
159 * [90/05/02 dbg]
160 * MACH_KERNEL conversion.
161 * [90/04/23 dbg]
162 *
163 * Revision 1.8.1.5 90/03/16 18:15:26 rvb
164 * Clean up the i386_dev/i386_ctlr confusion.
165 * [90/03/15 rvb]
166 *
167 * Revision 1.8.1.4 90/02/28 15:49:46 rvb
168 * Fix numerous typo's in Olivetti disclaimer.
169 * Revision 1.10 90/02/07 11:29:37 [eugene]
170 * expanded NOP's and loops to allow for faster machines
171 *
172 * Revision 1.8.1.3 90/01/08 13:31:17 rvb
173 * Add Intel copyright.
174 * Add Olivetti copyright.
175 * [90/01/08 rvb]
176 *
177 * Revision 1.8.1.2 89/11/10 09:52:15 rvb
178 * Revision 1.7 89/10/31 16:05:45 eugene
179 * added changes for new include files
180 *
181 * Revision 1.7 89/10/31 16:05:45 eugene
182 * added changes for new include files
183 *
184 * Revision 1.6 89/10/02 10:32:04 eugene
185 * got the previous change correct
186 *
187 * Revision 1.8 89/09/20 17:28:33 rvb
188 * Revision 1.3 89/08/01 11:17:32 eugene
189 * Fixed ethernet driver hang on 25Mhz machines
190 *
191 * Revision 1.7 89/08/08 21:46:46 jsb
192 * Just count overruns and do not print anything.
193 * [89/08/03 rvb]
194 *
195 * Revision 1.6 89/07/17 10:40:38 rvb
196 * Olivetti Changes to X79 upto 5/12/89:
197 * & Fixed reseting when RNR is detected.
198 * [89/07/11 rvb]
199 *
200 * Revision 1.5 89/04/05 13:00:53 rvb
201 * Moved "softc" structure from .h to here and some cleanup
202 * [89/03/07 rvb]
203 *
204 * made ac_t and scb_t volatile pointers for gcc.
205 * [89/03/07 rvb]
206 *
207 * collapse pack_u_long_t for gcc.
208 * [89/03/06 rvb]
209 *
210 * Revision 1.4 89/03/09 20:06:01 rpd
211 * More cleanup.
212 *
213 * Revision 1.3 89/02/26 12:42:12 gm0w
214 * Changes for cleanup.
215 *
216 */
217
218 /*
219 * Olivetti PC586 Mach Ethernet driver v1.0
220 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
221 * All rights reserved.
222 *
223 */
224
225 /*
226 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
227 Cupertino, California.
228
229 All Rights Reserved
230
231 Permission to use, copy, modify, and distribute this software and
232 its documentation for any purpose and without fee is hereby
233 granted, provided that the above copyright notice appears in all
234 copies and that both the copyright notice and this permission notice
235 appear in supporting documentation, and that the name of Olivetti
236 not be used in advertising or publicity pertaining to distribution
237 of the software without specific, written prior permission.
238
239 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
240 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
241 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
242 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
243 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
244 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
245 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
246 */
247
248 /*
249 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
250
251 All Rights Reserved
252
253 Permission to use, copy, modify, and distribute this software and
254 its documentation for any purpose and without fee is hereby
255 granted, provided that the above copyright notice appears in all
256 copies and that both the copyright notice and this permission notice
257 appear in supporting documentation, and that the name of Intel
258 not be used in advertising or publicity pertaining to distribution
259 of the software without specific, written prior permission.
260
261 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
262 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
263 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
264 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
265 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
266 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
267 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
268 */
269
270 /*
271 * NOTE:
272 * by rvb:
273 * 1. The best book on the 82586 is:
274 * LAN Components User's Manual by Intel
275 * The copy I found was dated 1984. This really tells you
276 * what the state machines are doing
277 * 2. In the current design, we only do one write at a time,
278 * though the hardware is capable of chaining and possibly
279 * even batching. The problem is that we only make one
280 * transmit buffer available in sram space.
281 * 3.
282 * n. Board Memory Map
283 RFA/FD 0 - 227 0x228 bytes
284 226 = 0x19 * 0x16 bytes
285 RBD 228 - 3813 0x35ec bytes
286 35e8 = 0x19 * 0x228 bytes
287 == 0x0a bytes (bd) + 2 bytes + 21c bytes
288 CU 3814 - 3913 0x100 bytes
289 TBD 3914 - 39a3 0x90 bytes
290 90 = No 18 * 0x08 bytes
291 TBUF 39a4 - 3fdd 0x63a bytes (= 1594(10))
292 SCB 3fde - 3fed 0x10 bytes
293 ISCP 3fee - 3ff5 0x08 bytes
294 SCP 3ff6 - 3fff 0x0a bytes
295 *
296 */
297
298 /*
299 * NOTE:
300 *
301 * Currently this driver doesn't support trailer protocols for
302 * packets. Once that is added, please remove this comment.
303 *
304 * Also, some lacking material includes the DLI code. If you
305 * are compiling this driver with DLI set, lookout, that code
306 * has not been looked at.
307 *
308 */
309
310 #define DEBUG
311 #define IF_CNTRS MACH
312 #define NDLI 0
313
314 #include <pc586.h>
315
316 #ifdef MACH_KERNEL
317 #include <kern/time_out.h>
318 #include <device/device_types.h>
319 #include <device/errno.h>
320 #include <device/io_req.h>
321 #include <device/if_hdr.h>
322 #include <device/if_ether.h>
323 #include <device/net_status.h>
324 #include <device/net_io.h>
325 #else MACH_KERNEL
326 #include <sys/param.h>
327 #include <mach/machine/vm_param.h>
328 #include <sys/systm.h>
329 #include <sys/mbuf.h>
330 #include <sys/buf.h>
331 #include <sys/protosw.h>
332 #include <sys/socket.h>
333 #include <sys/vmmac.h>
334 #include <sys/ioctl.h>
335 #include <sys/errno.h>
336 #include <sys/syslog.h>
337
338 #include <net/if.h>
339 #include <net/netisr.h>
340 #include <net/route.h>
341
342 #ifdef INET
343 #include <netinet/in.h>
344 #include <netinet/in_systm.h>
345 #include <netinet/in_var.h>
346 #include <netinet/ip.h>
347 #include <netinet/if_ether.h>
348 #endif
349
350 #ifdef NS
351 #include <netns/ns.h>
352 #include <netns/ns_if.h>
353 #endif
354
355 #if DLI
356 #include <net/dli_var.h>
357 struct dli_var de_dlv[NDE];
358 #endif DLI
359 #endif MACH_KERNEL
360
361 #include <i386/ipl.h>
362 #include <mach/vm_param.h>
363 #include <vm/vm_kern.h>
364 #include <chips/busses.h>
365 #include <i386at/if_pc586.h>
366
367 #define SPLNET spl6
368 #if __STDC__
369 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y)
370 #else __STDC__
371 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y)
372 #endif __STDC__
373
374 #define pc586chatt(unit) CMD(CHANATT, 0x0001, unit)
375 #define pc586inton(unit) CMD(INTENAB, CMD_1, unit)
376 #define pc586intoff(unit) CMD(INTENAB, CMD_0, unit)
377
378 int pc586probe();
379 void pc586attach();
380 int pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset();
381 int pc586watch(), pc586rcv(), pc586xmt(), pc586bldcu();
382 int pc586diag(), pc586config();
383 char *pc586bldru();
384 char *ram_to_ptr();
385 u_short ptr_to_ram();
386
387 static vm_offset_t pc586_std[NPC586] = { 0 };
388 static struct bus_device *pc586_info[NPC586];
389 struct bus_driver pcdriver =
390 {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0};
391
392 char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
393 int xmt_watch = 0;
394
395 typedef struct {
396 #ifdef MACH_KERNEL
397 struct ifnet ds_if; /* generic interface header */
398 u_char ds_addr[6]; /* Ethernet hardware address */
399 #else MACH_KERNEL
400 struct arpcom pc586_ac;
401 #define ds_if pc586_ac.ac_if
402 #define ds_addr pc586_ac.ac_enaddr
403 #endif MACH_KERNEL
404 int flags;
405 int seated;
406 int timer;
407 int open;
408 fd_t *begin_fd;
409 fd_t *end_fd;
410 rbd_t *end_rbd;
411 char *prom;
412 char *sram;
413 int tbusy;
414 short mode;
415 } pc_softc_t;
416 pc_softc_t pc_softc[NPC586];
417
418 struct pc586_cntrs {
419 struct {
420 u_int xmt, xmti;
421 u_int defer;
422 u_int busy;
423 u_int sleaze, intrinsic, intrinsic_count;
424 u_int chain;
425 } xmt;
426 struct {
427 u_int rcv;
428 u_int ovw;
429 u_int crc;
430 u_int frame;
431 u_int rscerrs, ovrnerrs;
432 u_int partial, bad_chain, fill;
433 } rcv;
434 u_int watch;
435 } pc586_cntrs[NPC586];
436
437
438 #ifdef IF_CNTRS
439 int pc586_narp = 1, pc586_arp = 0;
440 int pc586_ein[32], pc586_eout[32];
441 int pc586_lin[128/8], pc586_lout[128/8];
442 static
443 log_2(no)
444 unsigned long no;
445 {
446 return ({ unsigned long _temp__;
447 asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" :
448 "=r" (_temp__) : "a" (no));
449 _temp__;});
450 }
451 #endif IF_CNTRS
452
453 /*
454 * pc586probe:
455 *
456 * This function "probes" or checks for the pc586 board on the bus to see
457 * if it is there. As far as I can tell, the best break between this
458 * routine and the attach code is to simply determine whether the board
459 * is configured in properly. Currently my approach to this is to write
460 * and read a word from the SRAM on the board being probed. If the word
461 * comes back properly then we assume the board is there. The config
462 * code expects to see a successful return from the probe routine before
463 * attach will be called.
464 *
465 * input : address device is mapped to, and unit # being checked
466 * output : a '1' is returned if the board exists, and a 0 otherwise
467 *
468 */
469 pc586probe(port, dev)
470 struct bus_device *dev;
471 {
472 caddr_t addr = (caddr_t)dev->address;
473 int unit = dev->unit;
474 int len = round_page(0x4000);
475 int sram_len = round_page(0x4000);
476 extern vm_size_t mem_size;
477 int i;
478 volatile char *b_prom;
479 volatile char *b_sram;
480 volatile u_short*t_ps;
481
482 if ((unit < 0) || (unit > NPC586)) {
483 printf("pc%d: board out of range [0..%d]\n",
484 unit, NPC586);
485 return(0);
486 }
487 if (addr < (caddr_t)mem_size && addr > (caddr_t)0x100000)
488 return 0;
489
490 if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len)
491 != KERN_SUCCESS) {
492 printf("pc%d: can not allocate memory for prom.\n", unit);
493 return 0;
494 }
495 if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len)
496 != KERN_SUCCESS) {
497 printf("pc%d: can not allocate memory for sram.\n", unit);
498 return 0;
499 }
500 (void)pmap_map(b_prom, (vm_offset_t)addr,
501 (vm_offset_t)addr+len,
502 VM_PROT_READ | VM_PROT_WRITE);
503 if ((int)addr > 0x100000) /* stupid hardware */
504 addr += EXTENDED_ADDR;
505 addr += 0x4000; /* sram space */
506 (void)pmap_map(b_sram, (vm_offset_t)addr,
507 (vm_offset_t)addr+sram_len,
508 VM_PROT_READ | VM_PROT_WRITE);
509
510 *(b_prom + OFFSET_RESET) = 1;
511 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
512 *(b_prom + OFFSET_RESET) = 0;
513 t_ps = (u_short *)(b_sram + OFFSET_SCB);
514 *(t_ps) = (u_short)0x5a5a;
515 if (*(t_ps) != (u_short)0x5a5a) {
516 kmem_free(kernel_map, b_prom, len);
517 kmem_free(kernel_map, b_sram, sram_len);
518 return(0);
519 }
520 t_ps = (u_short *)(b_prom + + OFFSET_PROM);
521 #define ETHER0 0x00
522 #define ETHER1 0xaa
523 #define ETHER2 0x00
524 if ((t_ps[0]&0xff) == ETHER0 &&
525 (t_ps[1]&0xff) == ETHER1 &&
526 (t_ps[2]&0xff) == ETHER2)
527 pc_softc[unit].seated = TRUE;
528 #undef ETHER0
529 #undef ETHER1
530 #undef ETHER2
531 #define ETHER0 0x00
532 #define ETHER1 0x00
533 #define ETHER2 0x1c
534 if ((t_ps[0]&0xff) == ETHER0 ||
535 (t_ps[1]&0xff) == ETHER1 ||
536 (t_ps[2]&0xff) == ETHER2)
537 pc_softc[unit].seated = TRUE;
538 #undef ETHER0
539 #undef ETHER1
540 #undef ETHER2
541 if (pc_softc[unit].seated != TRUE) {
542 kmem_free(kernel_map, b_prom, len);
543 kmem_free(kernel_map, b_sram, sram_len);
544 return(0);
545 }
546 (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom;
547 (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram;
548 return(1);
549 }
550
551 /*
552 * pc586attach:
553 *
554 * This function attaches a PC586 board to the "system". The rest of
555 * runtime structures are initialized here (this routine is called after
556 * a successful probe of the board). Once the ethernet address is read
557 * and stored, the board's ifnet structure is attached and readied.
558 *
559 * input : bus_device structure setup in autoconfig
560 * output : board structs and ifnet is setup
561 *
562 */
563 void pc586attach(dev)
564 struct bus_device *dev;
565 {
566 struct ifnet *ifp;
567 u_char *addr_p;
568 u_short *b_addr;
569 u_char unit = (u_char)dev->unit;
570 pc_softc_t *sp = &pc_softc[unit];
571 volatile scb_t *scb_p;
572
573 take_dev_irq(dev);
574 printf(", port = %x, spl = %d, pic = %d. ",
575 dev->address, dev->sysdep, dev->sysdep1);
576
577 sp->timer = -1;
578 sp->flags = 0;
579 sp->mode = 0;
580 sp->open = 0;
581 CMD(RESET, CMD_1, unit);
582 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
583 CMD(RESET, CMD_0, unit);
584 b_addr = (u_short *)(sp->prom + OFFSET_PROM);
585 addr_p = (u_char *)sp->ds_addr;
586 addr_p[0] = b_addr[0];
587 addr_p[1] = b_addr[1];
588 addr_p[2] = b_addr[2];
589 addr_p[3] = b_addr[3];
590 addr_p[4] = b_addr[4];
591 addr_p[5] = b_addr[5];
592 printf("ethernet id [%x:%x:%x:%x:%x:%x]",
593 addr_p[0], addr_p[1], addr_p[2],
594 addr_p[3], addr_p[4], addr_p[5]);
595
596 scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB);
597 scb_p->scb_crcerrs = 0; /* initialize counters */
598 scb_p->scb_alnerrs = 0;
599 scb_p->scb_rscerrs = 0;
600 scb_p->scb_ovrnerrs = 0;
601
602 ifp = &(sp->ds_if);
603 ifp->if_unit = unit;
604 ifp->if_mtu = ETHERMTU;
605 ifp->if_flags = IFF_BROADCAST;
606 #ifdef MACH_KERNEL
607 ifp->if_header_size = sizeof(struct ether_header);
608 ifp->if_header_format = HDR_ETHERNET;
609 ifp->if_address_size = 6;
610 ifp->if_address = (char *)&sp->ds_addr[0];
611 if_init_queues(ifp);
612 #else MACH_KERNEL
613 ifp->if_name = "pc";
614 ifp->if_init = pc586init;
615 ifp->if_output = pc586output;
616 ifp->if_ioctl = pc586ioctl;
617 ifp->if_reset = pc586reset;
618 ifp->if_next = NULL;
619 if_attach(ifp);
620 #endif MACH_KERNEL
621 }
622
623 /*
624 * pc586reset:
625 *
626 * This routine is in part an entry point for the "if" code. Since most
627 * of the actual initialization has already (we hope already) been done
628 * by calling pc586attach().
629 *
630 * input : unit number or board number to reset
631 * output : board is reset
632 *
633 */
634 pc586reset(unit)
635 int unit;
636 {
637 pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
638 pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING);
639 return(pc586init(unit));
640
641 }
642
643 /*
644 * pc586init:
645 *
646 * Another routine that interfaces the "if" layer to this driver.
647 * Simply resets the structures that are used by "upper layers".
648 * As well as calling pc586hwrst that does reset the pc586 board.
649 *
650 * input : board number
651 * output : structures (if structs) and board are reset
652 *
653 */
654 pc586init(unit)
655 int unit;
656 {
657 struct ifnet *ifp;
658 int stat;
659 spl_t oldpri;
660
661 ifp = &(pc_softc[unit].ds_if);
662 #ifdef MACH_KERNEL
663 #else MACH_KERNEL
664 if (ifp->if_addrlist == (struct ifaddr *)0) {
665 return;
666 }
667 #endif MACH_KERNEL
668 oldpri = SPLNET();
669 if ((stat = pc586hwrst(unit)) == TRUE) {
670 #ifdef MACH_KERNEL
671 #undef HZ
672 #define HZ hz
673 #endif MACH_KERNEL
674 timeout(pc586watch, &(ifp->if_unit), 5*HZ);
675 pc_softc[unit].timer = 5;
676
677 pc_softc[unit].ds_if.if_flags |= IFF_RUNNING;
678 pc_softc[unit].flags |= DSF_RUNNING;
679 pc_softc[unit].tbusy = 0;
680 pc586start(unit);
681 #if DLI
682 dli_init();
683 #endif DLI
684 } else
685 printf("pc%d init(): trouble resetting board.\n", unit);
686 splx(oldpri);
687 return(stat);
688 }
689
690 #ifdef MACH_KERNEL
691 /*ARGSUSED*/
692 pc586open(dev, flag)
693 dev_t dev;
694 int flag;
695 {
696 register int unit;
697 pc_softc_t *sp;
698
699 unit = minor(dev); /* XXX */
700 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
701 return (ENXIO);
702
703 pc_softc[unit].ds_if.if_flags |= IFF_UP;
704 pc586init(unit);
705 return (0);
706 }
707 #endif MACH_KERNEL
708
709 /*
710 * pc586start:
711 *
712 * This is yet another interface routine that simply tries to output a
713 * in an mbuf after a reset.
714 *
715 * input : board number
716 * output : stuff sent to board if any there
717 *
718 */
719 pc586start(unit)
720 int unit;
721 {
722 #ifdef MACH_KERNEL
723 io_req_t m;
724 #else MACH_KERNEL
725 struct mbuf *m;
726 #endif MACH_KERNEL
727 struct ifnet *ifp;
728 register pc_softc_t *is = &pc_softc[unit];
729 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
730
731 if (is->tbusy) {
732 if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */
733 is->tbusy = 0;
734 pc586_cntrs[unit].xmt.busy++;
735 /*
736 * This is probably just a race. The xmt'r is just
737 * became idle but WE have masked interrupts so ...
738 */
739 if (xmt_watch) printf("!!");
740 } else
741 return;
742 }
743
744 ifp = &(pc_softc[unit].ds_if);
745 IF_DEQUEUE(&ifp->if_snd, m);
746 #ifdef MACH_KERNEL
747 if (m != 0)
748 #else MACH_KERNEL
749 if (m != (struct mbuf *)0)
750 #endif MACH_KERNEL
751 {
752 is->tbusy++;
753 pc586_cntrs[unit].xmt.xmt++;
754 pc586xmt(unit, m);
755 }
756 return;
757 }
758
759 /*
760 * pc586read:
761 *
762 * This routine does the actual copy of data (including ethernet header
763 * structure) from the pc586 to an mbuf chain that will be passed up
764 * to the "if" (network interface) layer. NOTE: we currently
765 * don't handle trailer protocols, so if that is needed, it will
766 * (at least in part) be added here. For simplicities sake, this
767 * routine copies the receive buffers from the board into a local (stack)
768 * buffer until the frame has been copied from the board. Once in
769 * the local buffer, the contents are copied to an mbuf chain that
770 * is then enqueued onto the appropriate "if" queue.
771 *
772 * input : board number, and an frame descriptor pointer
773 * output : the packet is put into an mbuf chain, and passed up
774 * assumes : if any errors occur, packet is "dropped on the floor"
775 *
776 */
777 pc586read(unit, fd_p)
778 int unit;
779 fd_t *fd_p;
780 {
781 register pc_softc_t *is = &pc_softc[unit];
782 register struct ifnet *ifp = &is->ds_if;
783 struct ether_header eh;
784 #ifdef MACH_KERNEL
785 ipc_kmsg_t new_kmsg;
786 struct ether_header *ehp;
787 struct packet_header *pkt;
788 char *dp;
789 #else MACH_KERNEL
790 struct mbuf *m, *tm;
791 #endif MACH_KERNEL
792 rbd_t *rbd_p;
793 u_char *buffer_p;
794 u_char *mb_p;
795 u_short mlen, len, clen;
796 u_short bytes_in_msg, bytes_in_mbuf, bytes;
797
798
799 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
800 printf("pc%d read(): board is not running.\n", ifp->if_unit);
801 pc586intoff(ifp->if_unit);
802 }
803 pc586_cntrs[unit].rcv.rcv++;
804 #ifdef MACH_KERNEL
805 new_kmsg = net_kmsg_get();
806 if (new_kmsg == IKM_NULL) {
807 /*
808 * Drop the received packet.
809 */
810 is->ds_if.if_rcvdrops++;
811
812 /*
813 * not only do we want to return, we need to drop the packet on
814 * the floor to clear the interrupt.
815 */
816 return 1;
817 }
818 ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
819 pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]);
820
821 /*
822 * Get ether header.
823 */
824 ehp->ether_type = fd_p->length;
825 len = sizeof(struct ether_header);
826 bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE);
827 bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE);
828
829 /*
830 * Get packet body.
831 */
832 dp = (char *)(pkt + 1);
833
834 rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
835 if (rbd_p == 0) {
836 printf("pc%d read(): Invalid buffer\n", unit);
837 if (pc586hwrst(unit) != TRUE) {
838 printf("pc%d read(): hwrst trouble.\n", unit);
839 }
840 net_kmsg_put(new_kmsg);
841 return 0;
842 }
843
844 do {
845 buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
846 bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
847 bcopy16((u_short *)buffer_p,
848 (u_short *)dp,
849 (bytes_in_msg + 1) & ~1); /* but we know it's even */
850 len += bytes_in_msg;
851 dp += bytes_in_msg;
852 if (rbd_p->status & RBD_SW_EOF)
853 break;
854 rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit);
855 } while ((int) rbd_p);
856
857 pkt->type = ehp->ether_type;
858 pkt->length =
859 len - sizeof(struct ether_header)
860 + sizeof(struct packet_header);
861
862 /*
863 * Send the packet to the network module.
864 */
865 net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg));
866 return 1;
867 #else MACH_KERNEL
868 eh.ether_type = ntohs(fd_p->length);
869 bcopy16(fd_p->source, eh.ether_shost, ETHER_ADD_SIZE);
870 bcopy16(fd_p->destination, eh.ether_dhost, ETHER_ADD_SIZE);
871
872 if ((rbd_p =(rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit))== (rbd_t *)NULL) {
873 printf("pc%d read(): Invalid buffer\n", unit);
874 if (pc586hwrst(unit) != TRUE) {
875 printf("pc%d read(): hwrst trouble.\n", unit);
876 }
877 return 0;
878 }
879
880 bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
881 buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
882 MGET(m, M_DONTWAIT, MT_DATA);
883 tm = m;
884 if (m == (struct mbuf *)0) {
885 /*
886 * not only do we want to return, we need to drop the packet on
887 * the floor to clear the interrupt.
888 *
889 */
890 printf("pc%d read(): No mbuf 1st\n", unit);
891 if (pc586hwrst(unit) != TRUE) {
892 pc586intoff(unit);
893 printf("pc%d read(): hwrst trouble.\n", unit);
894 pc_softc[unit].timer = 0;
895 }
896 return 0;
897 }
898 m->m_next = (struct mbuf *) 0;
899 m->m_len = MLEN;
900 if (bytes_in_msg > 2 * MLEN - sizeof (struct ifnet **)) {
901 MCLGET(m);
902 }
903 /*
904 * first mbuf in the packet must contain a pointer to the
905 * ifnet structure. other mbufs that follow and make up
906 * the packet do not need this pointer in the mbuf.
907 *
908 */
909 *(mtod(tm, struct ifnet **)) = ifp;
910 mlen = sizeof (struct ifnet **);
911 clen = mlen;
912 bytes_in_mbuf = m->m_len - sizeof(struct ifnet **);
913 mb_p = mtod(tm, u_char *) + sizeof (struct ifnet **);
914 bytes = min(bytes_in_mbuf, bytes_in_msg);
915 do {
916 if (bytes & 1)
917 len = bytes + 1;
918 else
919 len = bytes;
920 bcopy16(buffer_p, mb_p, len);
921 clen += bytes;
922 mlen += bytes;
923
924 if (!(bytes_in_mbuf -= bytes)) {
925 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
926 tm = tm->m_next;
927 if (tm == (struct mbuf *)0) {
928 m_freem(m);
929 printf("pc%d read(): No mbuf nth\n", unit);
930 if (pc586hwrst(unit) != TRUE) {
931 pc586intoff(unit);
932 printf("pc%d read(): hwrst trouble.\n", unit);
933 pc_softc[unit].timer = 0;
934 }
935 return 0;
936 }
937 mlen = 0;
938 tm->m_len = MLEN;
939 bytes_in_mbuf = MLEN;
940 mb_p = mtod(tm, u_char *);
941 } else
942 mb_p += bytes;
943
944 if (!(bytes_in_msg -= bytes)) {
945 if (rbd_p->status & RBD_SW_EOF ||
946 (rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit)) ==
947 NULL) {
948 tm->m_len = mlen;
949 break;
950 } else {
951 bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
952 buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
953 }
954 } else
955 buffer_p += bytes;
956
957 bytes = min(bytes_in_mbuf, bytes_in_msg);
958 } while(1);
959 #ifdef IF_CNTRS
960 /* clen -= (sizeof (struct ifnet **)
961 clen += 4 /* crc */;
962 clen += sizeof (struct ether_header);
963 pc586_ein[log_2(clen)]++;
964 if (clen < 128) pc586_lin[clen>>3]++;
965
966 if (eh.ether_type == ETHERTYPE_ARP) {
967 pc586_arp++;
968 if (pc586_narp) {
969 pc586_ein[log_2(clen)]--;
970 if (clen < 128) pc586_lin[clen>>3]--;
971 }
972 }
973 #endif IF_CNTRS
974 /*
975 * received packet is now in a chain of mbuf's. next step is
976 * to pass the packet upwards.
977 *
978 */
979 pc586send_packet_up(m, &eh, is);
980 return 1;
981 #endif MACH_KERNEL
982 }
983
984 /*
985 * Send a packet composed of an mbuf chain to the higher levels
986 *
987 */
988 #ifndef MACH_KERNEL
989 pc586send_packet_up(m, eh, is)
990 struct mbuf *m;
991 struct ether_header *eh;
992 pc_softc_t *is;
993 {
994 register struct ifqueue *inq;
995 spl_t opri;
996
997 switch (eh->ether_type) {
998 #ifdef INET
999 case ETHERTYPE_IP:
1000 schednetisr(NETISR_IP);
1001 inq = &ipintrq;
1002 break;
1003 case ETHERTYPE_ARP:
1004 arpinput(&is->pc586_ac, m);
1005 return;
1006 #endif
1007 #ifdef NS
1008 case ETHERTYPE_NS:
1009 schednetisr(NETISR_NS);
1010 inq = &nsintrq;
1011 break;
1012 #endif
1013 default:
1014 #if DLI
1015 {
1016 eh.ether_type = htons(eh.ether_type);
1017 dli_input(m,eh.ether_type,&eh.ether_shost[0],
1018 &de_dlv[ds->ds_if.if_unit], &eh);
1019 }
1020 #else DLI
1021 m_freem(m);
1022 #endif DLI
1023 return;
1024 }
1025 opri = SPLNET();
1026 if (IF_QFULL(inq)) {
1027 IF_DROP(inq);
1028 splx(opri);
1029 m_freem(m);
1030 return;
1031 }
1032 IF_ENQUEUE(inq, m);
1033 splx(opri);
1034 return;
1035 }
1036 #endif MACH_KERNEL
1037
1038 #ifdef MACH_KERNEL
1039 pc586output(dev, ior)
1040 dev_t dev;
1041 io_req_t ior;
1042 {
1043 register int unit;
1044
1045 unit = minor(dev); /* XXX */
1046 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1047 return (ENXIO);
1048
1049 return (net_write(&pc_softc[unit].ds_if, pc586start, ior));
1050 }
1051
1052 pc586setinput(dev, receive_port, priority, filter, filter_count)
1053 dev_t dev;
1054 mach_port_t receive_port;
1055 int priority;
1056 filter_t filter[];
1057 unsigned int filter_count;
1058 {
1059 register int unit = minor(dev);
1060 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1061 return (ENXIO);
1062
1063 return (net_set_filter(&pc_softc[unit].ds_if,
1064 receive_port, priority,
1065 filter, filter_count));
1066 }
1067 #else MACH_KERNEL
1068 /*
1069 * pc586output:
1070 *
1071 * This routine is called by the "if" layer to output a packet to
1072 * the network. This code resolves the local ethernet address, and
1073 * puts it into the mbuf if there is room. If not, then a new mbuf
1074 * is allocated with the header information and precedes the data
1075 * to be transmitted. The routines that actually transmit the
1076 * data (pc586xmt()) expect the ethernet structure to precede
1077 * the data in the mbuf. This information is required by the
1078 * 82586's transfer command segment, and thus mbuf's cannot
1079 * be simply "slammed" out onto the network.
1080 *
1081 * input: ifnet structure pointer, an mbuf with data, and address
1082 * to be resolved
1083 * output: mbuf is updated to hold enet address, or a new mbuf
1084 * with the address is added
1085 *
1086 */
1087 pc586output(ifp, m0, dst)
1088 struct ifnet *ifp;
1089 struct mbuf *m0;
1090 struct sockaddr *dst;
1091 {
1092 register pc_softc_t *is = &pc_softc[ifp->if_unit];
1093 register struct mbuf *m = m0;
1094 int type, error;
1095 spl_t opri;
1096 u_char edst[6];
1097 struct in_addr idst;
1098 register struct ether_header *eh;
1099 register int off;
1100 int usetrailers;
1101
1102 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
1103 printf("pc%d output(): board is not running.\n", ifp->if_unit);
1104 pc586intoff(ifp->if_unit);
1105 error = ENETDOWN;
1106 goto bad;
1107 }
1108 switch (dst->sa_family) {
1109
1110 #ifdef INET
1111 case AF_INET:
1112 idst = ((struct sockaddr_in *)dst)->sin_addr;
1113 if (!arpresolve(&is->pc586_ac, m, &idst, edst, &usetrailers)){
1114 return (0); /* if not yet resolved */
1115 }
1116 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
1117
1118 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
1119 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
1120 type = ETHERTYPE_TRAIL + (off>>9);
1121 m->m_off -= 2 * sizeof (u_short);
1122 m->m_len += 2 * sizeof (u_short);
1123 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
1124 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
1125 goto gottrailertype;
1126 }
1127 type = ETHERTYPE_IP;
1128 off = 0;
1129 goto gottype;
1130 #endif
1131 #ifdef NS
1132 case AF_NS:
1133 type = ETHERTYPE_NS;
1134 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
1135 (caddr_t)edst, sizeof (edst));
1136 off = 0;
1137 goto gottype;
1138 #endif
1139
1140 #if DLI
1141 case AF_DLI:
1142 if (m->m_len < sizeof(struct ether_header))
1143 {
1144 error = EMSGSIZE;
1145 goto bad;
1146 }
1147 eh = mtod(m, struct ether_header *);
1148 bcopy(dst->sa_data, (caddr_t)eh->ether_dhost,
1149 sizeof (eh->ether_dhost));
1150 goto gotheader;
1151 #endif DLI
1152
1153 case AF_UNSPEC:
1154 eh = (struct ether_header *)dst->sa_data;
1155 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
1156 type = eh->ether_type;
1157 goto gottype;
1158
1159 default:
1160 printf("pc%d output(): can't handle af%d\n",
1161 ifp->if_unit, dst->sa_family);
1162 error = EAFNOSUPPORT;
1163 goto bad;
1164 }
1165
1166 gottrailertype:
1167 /*
1168 * Packet to be sent as trailer: move first packet
1169 * (control information) to end of chain.
1170 */
1171 while (m->m_next)
1172 m = m->m_next;
1173 m->m_next = m0;
1174 m = m0->m_next;
1175 m0->m_next = 0;
1176 m0 = m;
1177
1178 gottype:
1179 /*
1180 * Add local net header. If no space in first mbuf,
1181 * allocate another.
1182 */
1183 if (m->m_off > MMAXOFF ||
1184 MMINOFF + sizeof (struct ether_header) > m->m_off) {
1185 m = m_get(M_DONTWAIT, MT_HEADER);
1186 if (m == 0) {
1187 error = ENOBUFS;
1188 goto bad;
1189 }
1190 m->m_next = m0;
1191 m->m_off = MMINOFF;
1192 m->m_len = sizeof (struct ether_header);
1193 } else {
1194 m->m_off -= sizeof (struct ether_header);
1195 m->m_len += sizeof (struct ether_header);
1196 }
1197 eh = mtod(m, struct ether_header *);
1198 eh->ether_type = htons((u_short)type);
1199 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
1200 bcopy((caddr_t)is->ds_addr,(caddr_t)eh->ether_shost, sizeof(edst));
1201 #if DLI
1202 gotheader:
1203 #endif DLI
1204
1205 /*
1206 * Queue message on interface, and start output if interface
1207 * not yet active.
1208 */
1209 opri = SPLNET();
1210 if (IF_QFULL(&ifp->if_snd)) {
1211 IF_DROP(&ifp->if_snd);
1212 splx(opri);
1213 m_freem(m);
1214 return (ENOBUFS);
1215 }
1216 IF_ENQUEUE(&ifp->if_snd, m);
1217 /*
1218 * Some action needs to be added here for checking whether the
1219 * board is already transmitting. If it is, we don't want to
1220 * start it up (ie call pc586start()). We will attempt to send
1221 * packets that are queued up after an interrupt occurs. Some
1222 * flag checking action has to happen here and/or in the start
1223 * routine. This note is here to remind me that some thought
1224 * is needed and there is a potential problem here.
1225 *
1226 */
1227 pc586start(ifp->if_unit);
1228 splx(opri);
1229 return (0);
1230 bad:
1231 m_freem(m0);
1232 return (error);
1233 }
1234 #endif MACH_KERNEL
1235
1236 #ifdef MACH_KERNEL
1237 pc586getstat(dev, flavor, status, count)
1238 dev_t dev;
1239 int flavor;
1240 dev_status_t status; /* pointer to OUT array */
1241 unsigned int *count; /* out */
1242 {
1243 register int unit = minor(dev);
1244 register pc_softc_t *sp;
1245
1246 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1247 return (ENXIO);
1248
1249 sp = &pc_softc[unit];
1250 return (net_getstat(&sp->ds_if, flavor, status, count));
1251 }
1252
1253 pc586setstat(dev, flavor, status, count)
1254 dev_t dev;
1255 int flavor;
1256 dev_status_t status;
1257 unsigned int count;
1258 {
1259 register int unit = minor(dev);
1260 register pc_softc_t *sp;
1261
1262 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1263 return (ENXIO);
1264
1265 sp = &pc_softc[unit];
1266
1267 switch (flavor) {
1268 case NET_STATUS:
1269 {
1270 /*
1271 * All we can change are flags, and not many of those.
1272 */
1273 register struct net_status *ns = (struct net_status *)status;
1274 int mode = 0;
1275
1276 if (count < NET_STATUS_COUNT)
1277 return (D_INVALID_OPERATION);
1278
1279 if (ns->flags & IFF_ALLMULTI)
1280 mode |= MOD_ENAL;
1281 if (ns->flags & IFF_PROMISC)
1282 mode |= MOD_PROM;
1283
1284 /*
1285 * Force a complete reset if the receive mode changes
1286 * so that these take effect immediately.
1287 */
1288 if (sp->mode != mode) {
1289 sp->mode = mode;
1290 if (sp->flags & DSF_RUNNING) {
1291 sp->flags &= ~(DSF_LOCK|DSF_RUNNING);
1292 pc586init(unit);
1293 }
1294 }
1295 break;
1296 }
1297
1298 default:
1299 return (D_INVALID_OPERATION);
1300 }
1301 return (D_SUCCESS);
1302
1303 }
1304 #else MACH_KERNEL
1305 /*
1306 * pc586ioctl:
1307 *
1308 * This routine processes an ioctl request from the "if" layer
1309 * above.
1310 *
1311 * input : pointer the appropriate "if" struct, command, and data
1312 * output : based on command appropriate action is taken on the
1313 * pc586 board(s) or related structures
1314 * return : error is returned containing exit conditions
1315 *
1316 */
1317 pc586ioctl(ifp, cmd, data)
1318 struct ifnet *ifp;
1319 int cmd;
1320 caddr_t data;
1321 {
1322 register struct ifaddr *ifa = (struct ifaddr *)data;
1323 int unit = ifp->if_unit;
1324 register pc_softc_t *is = &pc_softc[unit];
1325 short mode = 0;
1326 int error = 0;
1327 spl_t opri;
1328
1329 opri = SPLNET();
1330 switch (cmd) {
1331 case SIOCSIFADDR:
1332 ifp->if_flags |= IFF_UP;
1333 pc586init(unit);
1334 switch (ifa->ifa_addr.sa_family) {
1335 #ifdef INET
1336 case AF_INET:
1337 ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
1338 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1339 break;
1340 #endif
1341 #ifdef NS
1342 case AF_NS:
1343 {
1344 register struct ns_addr *ina =
1345 &(IA_SNS(ifa)->sns_addr);
1346 if (ns_nullhost(*ina))
1347 ina->x_host = *(union ns_host *)(ds->ds_addr);
1348 else
1349 pc586setaddr(ina->x_host.c_host, unit);
1350 break;
1351 }
1352 #endif
1353 }
1354 break;
1355 case SIOCSIFFLAGS:
1356 if (ifp->if_flags & IFF_ALLMULTI)
1357 mode |= MOD_ENAL;
1358 if (ifp->if_flags & IFF_PROMISC)
1359 mode |= MOD_PROM;
1360 /*
1361 * force a complete reset if the receive multicast/
1362 * promiscuous mode changes so that these take
1363 * effect immediately.
1364 *
1365 */
1366 if (is->mode != mode) {
1367 is->mode = mode;
1368 if (is->flags & DSF_RUNNING) {
1369 is->flags &= ~(DSF_LOCK|DSF_RUNNING);
1370 pc586init(unit);
1371 }
1372 }
1373 if ((ifp->if_flags & IFF_UP) == 0 && is->flags & DSF_RUNNING) {
1374 printf("pc%d ioctl(): board is not running\n", unit);
1375 is->flags &= ~(DSF_LOCK | DSF_RUNNING);
1376 is->timer = -1;
1377 pc586intoff(unit);
1378 } else if (ifp->if_flags & IFF_UP && (is->flags & DSF_RUNNING) == 0) {
1379 pc586init(unit);
1380 }
1381 break;
1382 #ifdef IF_CNTRS
1383 case SIOCCIFCNTRS:
1384 if (!suser()) {
1385 error = EPERM;
1386 break;
1387 }
1388 bzero((caddr_t)pc586_ein, sizeof (pc586_ein));
1389 bzero((caddr_t)pc586_eout, sizeof (pc586_eout));
1390 bzero((caddr_t)pc586_lin, sizeof (pc586_lin));
1391 bzero((caddr_t)pc586_lout, sizeof (pc586_lout));
1392 bzero((caddr_t)&pc586_arp, sizeof (int));
1393 bzero((caddr_t)&pc586_cntrs, sizeof (pc586_cntrs));
1394 break;
1395 #endif IF_CNTRS
1396 default:
1397 error = EINVAL;
1398 }
1399 splx(opri);
1400 return (error);
1401 }
1402 #endif MACH_KERNEL
1403
1404 /*
1405 * pc586hwrst:
1406 *
1407 * This routine resets the pc586 board that corresponds to the
1408 * board number passed in.
1409 *
1410 * input : board number to do a hardware reset
1411 * output : board is reset
1412 *
1413 */
1414 pc586hwrst(unit)
1415 int unit;
1416 {
1417 CMD(CHANATT, CMD_0, unit);
1418 CMD(RESET, CMD_1, unit);
1419 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
1420 CMD(RESET,CMD_0, unit);
1421
1422 /*
1423 * for (i = 0; i < 1000000; i++);
1424 * with this loop above and with the reset toggle also looping to
1425 * 1000000. We don't see the reset behaving as advertised. DOES
1426 * IT HAPPEN AT ALL. In particular, NORMODE, ENABLE, and XFER
1427 * should all be zero and they have not changed at all.
1428 */
1429 CMD(INTENAB, CMD_0, unit);
1430 CMD(NORMMODE, CMD_0, unit);
1431 CMD(XFERMODE, CMD_1, unit);
1432
1433 pc586bldcu(unit);
1434
1435 if (pc586diag(unit) == FALSE)
1436 return(FALSE);
1437
1438 if (pc586config(unit) == FALSE)
1439 return(FALSE);
1440 /*
1441 * insert code for loopback test here
1442 *
1443 */
1444 pc586rustrt(unit);
1445
1446 pc586inton(unit);
1447 CMD(NORMMODE, CMD_1, unit);
1448 return(TRUE);
1449 }
1450
1451 /*
1452 * pc586watch():
1453 *
1454 * This routine is the watchdog timer routine for the pc586 chip. If
1455 * chip wedges, this routine will fire and cause a board reset and
1456 * begin again.
1457 *
1458 * input : which board is timing out
1459 * output : potential board reset if wedged
1460 *
1461 */
1462 int watch_dead = 0;
1463 pc586watch(b_ptr)
1464 caddr_t b_ptr;
1465 {
1466 spl_t opri;
1467 int unit = *b_ptr;
1468
1469 if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0) {
1470 return;
1471 }
1472 if (pc_softc[unit].timer == -1) {
1473 timeout(pc586watch, b_ptr, 5*HZ);
1474 return;
1475 }
1476 if (--pc_softc[unit].timer != -1) {
1477 timeout(pc586watch, b_ptr, 1*HZ);
1478 return;
1479 }
1480
1481 opri = SPLNET();
1482 #ifdef notdef
1483 printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead);
1484 #endif notdef
1485 pc586_cntrs[unit].watch++;
1486 if (pc586hwrst(unit) != TRUE) {
1487 printf("pc%d watch(): hwrst trouble.\n", unit);
1488 pc_softc[unit].timer = 0;
1489 } else {
1490 timeout(pc586watch, b_ptr, 1*HZ);
1491 pc_softc[unit].timer = 5;
1492 }
1493 splx(opri);
1494 }
1495
1496 /*
1497 * pc586intr:
1498 *
1499 * This function is the interrupt handler for the pc586 ethernet
1500 * board. This routine will be called whenever either a packet
1501 * is received, or a packet has successfully been transfered and
1502 * the unit is ready to transmit another packet.
1503 *
1504 * input : board number that interrupted
1505 * output : either a packet is received, or a packet is transfered
1506 *
1507 */
1508 pc586intr(unit)
1509 int unit;
1510 {
1511 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1512 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1513 int next, x;
1514 int i;
1515 u_short int_type;
1516
1517 if (pc_softc[unit].seated == FALSE) {
1518 printf("pc%d intr(): board not seated\n", unit);
1519 return(-1);
1520 }
1521
1522 while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) {
1523 pc586ack(unit);
1524 if (int_type & SCB_SW_FR) {
1525 pc586rcv(unit);
1526 watch_dead=0;
1527 }
1528 if (int_type & SCB_SW_RNR) {
1529 pc586_cntrs[unit].rcv.ovw++;
1530 #ifdef notdef
1531 printf("pc%d intr(): receiver overrun! begin_fd = %x\n",
1532 unit, pc_softc[unit].begin_fd);
1533 #endif notdef
1534 pc586rustrt(unit);
1535 }
1536 if (int_type & SCB_SW_CNA) {
1537 /*
1538 * At present, we don't care about CNA's. We
1539 * believe they are a side effect of XMT.
1540 */
1541 }
1542 if (int_type & SCB_SW_CX) {
1543 /*
1544 * At present, we only request Interrupt for
1545 * XMT.
1546 */
1547 if ((!(cb_p->ac_status & AC_SW_OK)) ||
1548 (cb_p->ac_status & (0xfff^TC_SQE))) {
1549 if (cb_p->ac_status & TC_DEFER) {
1550 if (xmt_watch) printf("DF");
1551 pc586_cntrs[unit].xmt.defer++;
1552 } else if (cb_p->ac_status & (TC_COLLISION|0xf)) {
1553 if (xmt_watch) printf("%x",cb_p->ac_status & 0xf);
1554 } else if (xmt_watch)
1555 printf("pc%d XMT: %x %x\n",
1556 unit, cb_p->ac_status, cb_p->ac_command);
1557 }
1558 pc586_cntrs[unit].xmt.xmti++;
1559 pc_softc[unit].tbusy = 0;
1560 pc586start(unit);
1561 }
1562 pc_softc[unit].timer = 5;
1563 }
1564 return(0);
1565 }
1566
1567 /*
1568 * pc586rcv:
1569 *
1570 * This routine is called by the interrupt handler to initiate a
1571 * packet transfer from the board to the "if" layer above this
1572 * driver. This routine checks if a buffer has been successfully
1573 * received by the pc586. If so, the routine pc586read is called
1574 * to do the actual transfer of the board data (including the
1575 * ethernet header) into a packet (consisting of an mbuf chain).
1576 *
1577 * input : number of the board to check
1578 * output : if a packet is available, it is "sent up"
1579 *
1580 */
1581 pc586rcv(unit)
1582 int unit;
1583 {
1584 fd_t *fd_p;
1585
1586 for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL;
1587 fd_p = pc_softc[unit].begin_fd) {
1588 if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) {
1589 if (pc586hwrst(unit) != TRUE)
1590 printf("pc%d rcv(): hwrst ffff trouble.\n",
1591 unit);
1592 return;
1593 } else if (fd_p->status & AC_SW_C) {
1594 fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit);
1595
1596 if (fd_p->status == (RFD_DONE|RFD_RSC)) {
1597 /* lost one */;
1598 #ifdef notdef
1599 printf("pc%d RCV: RSC %x\n",
1600 unit, fd_p->status);
1601 #endif notdef
1602 pc586_cntrs[unit].rcv.partial++;
1603 } else if (!(fd_p->status & RFD_OK))
1604 printf("pc%d RCV: !OK %x\n",
1605 unit, fd_p->status);
1606 else if (fd_p->status & 0xfff)
1607 printf("pc%d RCV: ERRs %x\n",
1608 unit, fd_p->status);
1609 else
1610 if (!pc586read(unit, fd_p))
1611 return;
1612 if (!pc586requeue(unit, fd_p)) { /* abort on chain error */
1613 if (pc586hwrst(unit) != TRUE)
1614 printf("pc%d rcv(): hwrst trouble.\n", unit);
1615 return;
1616 }
1617 pc_softc[unit].begin_fd = bfd;
1618 } else
1619 break;
1620 }
1621 return;
1622 }
1623
1624 /*
1625 * pc586requeue:
1626 *
1627 * This routine puts rbd's used in the last receive back onto the
1628 * free list for the next receive.
1629 *
1630 */
1631 pc586requeue(unit, fd_p)
1632 int unit;
1633 fd_t *fd_p;
1634 {
1635 rbd_t *l_rbdp;
1636 rbd_t *f_rbdp;
1637
1638 #ifndef REQUEUE_DBG
1639 if (bad_rbd_chain(fd_p->rbd_offset, unit))
1640 return 0;
1641 #endif REQUEUE_DBG
1642 f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
1643 if (f_rbdp != NULL) {
1644 l_rbdp = f_rbdp;
1645 while ( (!(l_rbdp->status & RBD_SW_EOF)) &&
1646 (l_rbdp->next_rbd_offset != 0xffff))
1647 {
1648 l_rbdp->status = 0;
1649 l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset,
1650 unit);
1651 }
1652 l_rbdp->next_rbd_offset = PC586NULL;
1653 l_rbdp->status = 0;
1654 l_rbdp->size |= AC_CW_EL;
1655 pc_softc[unit].end_rbd->next_rbd_offset =
1656 ptr_to_ram((char *)f_rbdp, unit);
1657 pc_softc[unit].end_rbd->size &= ~AC_CW_EL;
1658 pc_softc[unit].end_rbd= l_rbdp;
1659 }
1660
1661 fd_p->status = 0;
1662 fd_p->command = AC_CW_EL;
1663 fd_p->link_offset = PC586NULL;
1664 fd_p->rbd_offset = PC586NULL;
1665
1666 pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit);
1667 pc_softc[unit].end_fd->command = 0;
1668 pc_softc[unit].end_fd = fd_p;
1669
1670 return 1;
1671 }
1672
1673 /*
1674 * pc586xmt:
1675 *
1676 * This routine fills in the appropriate registers and memory
1677 * locations on the PC586 board and starts the board off on
1678 * the transmit.
1679 *
1680 * input : board number of interest, and a pointer to the mbuf
1681 * output : board memory and registers are set for xfer and attention
1682 *
1683 */
1684 #ifdef DEBUG
1685 int xmt_debug = 0;
1686 #endif DEBUG
1687 pc586xmt(unit, m)
1688 int unit;
1689 #ifdef MACH_KERNEL
1690 io_req_t m;
1691 #else MACH_KERNEL
1692 struct mbuf *m;
1693 #endif MACH_KERNEL
1694 {
1695 pc_softc_t *is = &pc_softc[unit];
1696 register u_char *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF);
1697 register u_short *xmtshort_p;
1698 #ifdef MACH_KERNEL
1699 register struct ether_header *eh_p = (struct ether_header *)m->io_data;
1700 #else MACH_KERNEL
1701 struct mbuf *tm_p = m;
1702 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1703 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1704 u_short count = m->m_len - sizeof(struct ether_header);
1705 #endif MACH_KERNEL
1706 volatile scb_t *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB);
1707 volatile ac_t *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU);
1708 tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
1709 u_short tbd = OFFSET_TBD;
1710 u_short len, clen = 0;
1711
1712 cb_p->ac_status = 0;
1713 cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1714 cb_p->ac_link_offset = PC586NULL;
1715 cb_p->cmd.transmit.tbd_offset = OFFSET_TBD;
1716
1717 bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE);
1718 cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type);
1719
1720 #ifndef MACH_KERNEL
1721 #ifdef DEBUG
1722 if (xmt_debug)
1723 printf("XMT mbuf: L%d @%x ", count, mb_p);
1724 #endif DEBUG
1725 #endif MACH_KERNEL
1726 tbd_p->act_count = 0;
1727 tbd_p->buffer_base = 0;
1728 tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
1729 #ifdef MACH_KERNEL
1730 { int Rlen, Llen;
1731 clen = m->io_count - sizeof(struct ether_header);
1732 Llen = clen & 1;
1733 Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1;
1734
1735 bcopy16(m->io_data + sizeof(struct ether_header) - Rlen,
1736 xmtdata_p,
1737 clen + (Rlen + Llen) );
1738 xmtdata_p += clen + Llen;
1739 tbd_p->act_count = clen;
1740 tbd_p->buffer_addr += Rlen;
1741 }
1742 #else MACH_KERNEL
1743 do {
1744 if (count) {
1745 if (clen + count > ETHERMTU)
1746 break;
1747 if (count & 1)
1748 len = count + 1;
1749 else
1750 len = count;
1751 bcopy16(mb_p, xmtdata_p, len);
1752 clen += count;
1753 tbd_p->act_count += count;
1754 xmtdata_p += len;
1755 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1756 break;
1757 if (count & 1) {
1758 /* go to the next descriptor */
1759 tbd_p++->next_tbd_offset = (tbd += sizeof (tbd_t));
1760 tbd_p->act_count = 0;
1761 tbd_p->buffer_base = 0;
1762 tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
1763 /* at the end -> coallesce remaining mbufs */
1764 if (tbd == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1765 pc586sftwsleaze(&count, &mb_p, &tm_p, unit);
1766 continue;
1767 }
1768 /* next mbuf short -> coallesce as needed */
1769 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1770 #define HDW_THRESHOLD 55
1771 tm_p->m_len > HDW_THRESHOLD)
1772 /* ok */;
1773 else {
1774 pc586hdwsleaze(&count, &mb_p, &tm_p, unit);
1775 continue;
1776 }
1777 }
1778 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1779 break;
1780 count = tm_p->m_len;
1781 mb_p = mtod(tm_p, u_char *);
1782 #ifdef DEBUG
1783 if (xmt_debug)
1784 printf("mbuf+ L%d @%x ", count, mb_p);
1785 #endif DEBUG
1786 } while (1);
1787 #endif MACH_KERNEL
1788 #ifdef DEBUG
1789 if (xmt_debug)
1790 printf("CLEN = %d\n", clen);
1791 #endif DEBUG
1792 if (clen < ETHERMIN) {
1793 tbd_p->act_count += ETHERMIN - clen;
1794 for (xmtshort_p = (u_short *)xmtdata_p;
1795 clen < ETHERMIN;
1796 clen += 2) *xmtshort_p++ = 0;
1797 }
1798 tbd_p->act_count |= TBD_SW_EOF;
1799 tbd_p->next_tbd_offset = PC586NULL;
1800 #ifdef IF_CNTRS
1801 clen += sizeof (struct ether_header) + 4 /* crc */;
1802 pc586_eout[log_2(clen)]++;
1803 if (clen < 128) pc586_lout[clen>>3]++;
1804 #endif IF_CNTRS
1805 #ifdef DEBUG
1806 if (xmt_debug) {
1807 pc586tbd(unit);
1808 printf("\n");
1809 }
1810 #endif DEBUG
1811
1812 while (scb_p->scb_command) ;
1813 scb_p->scb_command = SCB_CU_STRT;
1814 pc586chatt(unit);
1815
1816 #ifdef MACH_KERNEL
1817 iodone(m);
1818 #else MACH_KERNEL
1819 for (count=0; ((count < 6) && (eh_p->ether_dhost[count] == 0xff)); count++) ;
1820 if (count == 6) {
1821 pc586send_packet_up(m, eh_p, is);
1822 } else
1823 m_freem(m);
1824 #endif MACH_KERNEL
1825 return;
1826 }
1827
1828 /*
1829 * pc586bldcu:
1830 *
1831 * This function builds up the command unit structures. It inits
1832 * the scp, iscp, scb, cb, tbd, and tbuf.
1833 *
1834 */
1835 pc586bldcu(unit)
1836 {
1837 char *sram = pc_softc[unit].sram;
1838 scp_t *scp_p = (scp_t *)(sram + OFFSET_SCP);
1839 iscp_t *iscp_p = (iscp_t *)(sram + OFFSET_ISCP);
1840 volatile scb_t *scb_p = (volatile scb_t *)(sram + OFFSET_SCB);
1841 volatile ac_t *cb_p = (volatile ac_t *)(sram + OFFSET_CU);
1842 tbd_t *tbd_p = (tbd_t *)(sram + OFFSET_TBD);
1843 int i;
1844
1845 scp_p->scp_sysbus = 0;
1846 scp_p->scp_iscp = OFFSET_ISCP;
1847 scp_p->scp_iscp_base = 0;
1848
1849 iscp_p->iscp_busy = 1;
1850 iscp_p->iscp_scb_offset = OFFSET_SCB;
1851 iscp_p->iscp_scb = 0;
1852 iscp_p->iscp_scb_base = 0;
1853
1854 pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs;
1855 pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs;
1856 pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs;
1857 pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs;
1858 scb_p->scb_status = 0;
1859 scb_p->scb_command = 0;
1860 scb_p->scb_cbl_offset = OFFSET_CU;
1861 scb_p->scb_rfa_offset = OFFSET_RU;
1862 scb_p->scb_crcerrs = 0;
1863 scb_p->scb_alnerrs = 0;
1864 scb_p->scb_rscerrs = 0;
1865 scb_p->scb_ovrnerrs = 0;
1866
1867 scb_p->scb_command = SCB_RESET;
1868 pc586chatt(unit);
1869 for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); );
1870 if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit);
1871 for (i = STATUS_TRIES; i-- > 0; ) {
1872 if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA))
1873 break;
1874 }
1875 if (!i)
1876 printf("pc%d bldcu(): not ready after reset.\n", unit);
1877 pc586ack(unit);
1878
1879 cb_p->ac_status = 0;
1880 cb_p->ac_command = AC_CW_EL;
1881 cb_p->ac_link_offset = OFFSET_CU;
1882
1883 tbd_p->act_count = 0;
1884 tbd_p->next_tbd_offset = PC586NULL;
1885 tbd_p->buffer_addr = 0;
1886 tbd_p->buffer_base = 0;
1887 return;
1888 }
1889
1890 /*
1891 * pc586bldru:
1892 *
1893 * This function builds the linear linked lists of fd's and
1894 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1895 *
1896 */
1897 char *
1898 pc586bldru(unit)
1899 int unit;
1900 {
1901 fd_t *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1902 ru_t *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD);
1903 int i;
1904
1905 pc_softc[unit].begin_fd = fd_p;
1906 for(i = 0; i < N_FD; i++, fd_p++) {
1907 fd_p->status = 0;
1908 fd_p->command = 0;
1909 fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit);
1910 fd_p->rbd_offset = PC586NULL;
1911 }
1912 pc_softc[unit].end_fd = --fd_p;
1913 fd_p->link_offset = PC586NULL;
1914 fd_p->command = AC_CW_EL;
1915 fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1916
1917 fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit);
1918 for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) {
1919 rbd_p->r.status = 0;
1920 rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer),
1921 unit);
1922 rbd_p->r.buffer_base = 0;
1923 rbd_p->r.size = RCVBUFSIZE;
1924 if (i != N_RBD-1) {
1925 rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]),
1926 unit);
1927 } else {
1928 rbd_p->r.next_rbd_offset = PC586NULL;
1929 rbd_p->r.size |= AC_CW_EL;
1930 pc_softc[unit].end_rbd = (rbd_t *)rbd_p;
1931 }
1932 }
1933 return (char *)pc_softc[unit].begin_fd;
1934 }
1935
1936 /*
1937 * pc586rustrt:
1938 *
1939 * This routine starts the receive unit running. First checks if the
1940 * board is actually ready, then the board is instructed to receive
1941 * packets again.
1942 *
1943 */
1944 pc586rustrt(unit)
1945 int unit;
1946 {
1947 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1948 char *strt;
1949
1950 if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY)
1951 return;
1952
1953 strt = pc586bldru(unit);
1954 scb_p->scb_command = SCB_RU_STRT;
1955 scb_p->scb_rfa_offset = ptr_to_ram(strt, unit);
1956 pc586chatt(unit);
1957 return;
1958 }
1959
1960 /*
1961 * pc586diag:
1962 *
1963 * This routine does a 586 op-code number 7, and obtains the
1964 * diagnose status for the pc586.
1965 *
1966 */
1967 pc586diag(unit)
1968 int unit;
1969 {
1970 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1971 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1972 int i;
1973
1974 if (scb_p->scb_status & SCB_SW_INT) {
1975 printf("pc%d diag(): bad initial state %\n",
1976 unit, scb_p->scb_status);
1977 pc586ack(unit);
1978 }
1979 cb_p->ac_status = 0;
1980 cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL);
1981 scb_p->scb_command = SCB_CU_STRT;
1982 pc586chatt(unit);
1983
1984 for(i = 0; i < 0xffff; i++)
1985 if ((cb_p->ac_status & AC_SW_C))
1986 break;
1987 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1988 printf("pc%d: diag failed; status = %x\n",
1989 unit, cb_p->ac_status);
1990 return(FALSE);
1991 }
1992
1993 if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) ) {
1994 printf("pc%d diag(): bad final state %x\n",
1995 unit, scb_p->scb_status);
1996 pc586ack(unit);
1997 }
1998 return(TRUE);
1999 }
2000
2001 /*
2002 * pc586config:
2003 *
2004 * This routine does a standard config of the pc586 board.
2005 *
2006 */
2007 pc586config(unit)
2008 int unit;
2009 {
2010 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
2011 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
2012 int i;
2013
2014
2015 /*
2016 if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) {
2017 printf("pc%d config(): unexpected initial state %x\n",
2018 unit, scb_p->scb_status);
2019 }
2020 */
2021 pc586ack(unit);
2022
2023 cb_p->ac_status = 0;
2024 cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL);
2025
2026 /*
2027 * below is the default board configuration from p2-28 from 586 book
2028 */
2029 cb_p->cmd.configure.fifolim_bytecnt = 0x080c;
2030 cb_p->cmd.configure.addrlen_mode = 0x2600;
2031 cb_p->cmd.configure.linprio_interframe = 0x6000;
2032 cb_p->cmd.configure.slot_time = 0xf200;
2033 cb_p->cmd.configure.hardware = 0x0000;
2034 cb_p->cmd.configure.min_frame_len = 0x0040;
2035
2036 scb_p->scb_command = SCB_CU_STRT;
2037 pc586chatt(unit);
2038
2039 for(i = 0; i < 0xffff; i++)
2040 if ((cb_p->ac_status & AC_SW_C))
2041 break;
2042 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
2043 printf("pc%d: config-configure failed; status = %x\n",
2044 unit, cb_p->ac_status);
2045 return(FALSE);
2046 }
2047 /*
2048 if (scb_p->scb_status & SCB_SW_INT) {
2049 printf("pc%d configure(): bad configure state %x\n",
2050 unit, scb_p->scb_status);
2051 pc586ack(unit);
2052 }
2053 */
2054 cb_p->ac_status = 0;
2055 cb_p->ac_command = (AC_IASETUP|AC_CW_EL);
2056
2057 bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE);
2058
2059 scb_p->scb_command = SCB_CU_STRT;
2060 pc586chatt(unit);
2061
2062 for (i = 0; i < 0xffff; i++)
2063 if ((cb_p->ac_status & AC_SW_C))
2064 break;
2065 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
2066 printf("pc%d: config-address failed; status = %x\n",
2067 unit, cb_p->ac_status);
2068 return(FALSE);
2069 }
2070 /*
2071 if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) {
2072 printf("pc%d configure(): unexpected final state %x\n",
2073 unit, scb_p->scb_status);
2074 }
2075 */
2076 pc586ack(unit);
2077
2078 return(TRUE);
2079 }
2080
2081 /*
2082 * pc586ack:
2083 */
2084 pc586ack(unit)
2085 {
2086 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
2087 int i;
2088
2089 if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT))
2090 return;
2091 CMD(CHANATT, 0x0001, unit);
2092 for (i = 1000000; scb_p->scb_command && (i-- > 0); );
2093 if (!i)
2094 printf("pc%d pc586ack(): board not accepting command.\n", unit);
2095 }
2096
2097 char *
2098 ram_to_ptr(offset, unit)
2099 int unit;
2100 u_short offset;
2101 {
2102 if (offset == PC586NULL)
2103 return(NULL);
2104 if (offset > 0x3fff) {
2105 printf("ram_to_ptr(%x, %d)\n", offset, unit);
2106 panic("range");
2107 return(NULL);
2108 }
2109 return(pc_softc[unit].sram + offset);
2110 }
2111
2112 #ifndef REQUEUE_DBG
2113 bad_rbd_chain(offset, unit)
2114 {
2115 rbd_t *rbdp;
2116 char *sram = pc_softc[unit].sram;
2117
2118 for (;;) {
2119 if (offset == PC586NULL)
2120 return 0;
2121 if (offset > 0x3fff) {
2122 printf("pc%d: bad_rbd_chain offset = %x\n",
2123 unit, offset);
2124 pc586_cntrs[unit].rcv.bad_chain++;
2125 return 1;
2126 }
2127
2128 rbdp = (rbd_t *)(sram + offset);
2129 offset = rbdp->next_rbd_offset;
2130 }
2131 }
2132 #endif REQUEUE_DBG
2133
2134 u_short
2135 ptr_to_ram(k_va, unit)
2136 char *k_va;
2137 int unit;
2138 {
2139 return((u_short)(k_va - pc_softc[unit].sram));
2140 }
2141
2142 pc586scb(unit)
2143 {
2144 volatile scb_t *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
2145 volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE);
2146 u_short i;
2147
2148 i = scb->scb_status;
2149 printf("stat: stat %x, cus %x, rus %x //",
2150 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
2151 i = scb->scb_command;
2152 printf(" cmd: ack %x, cuc %x, ruc %x\n",
2153 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
2154
2155 printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n",
2156 scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc,
2157 scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame,
2158 scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs,
2159 scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs);
2160
2161 printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset);
2162 printf(" norm %x, ena %x, xfer %x //",
2163 cmd[0] & 1, cmd[3] & 1, cmd[4] & 1);
2164 printf(" atn %x, reset %x, type %x, stat %x\n",
2165 cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1);
2166 }
2167
2168 pc586tbd(unit)
2169 {
2170 pc_softc_t *is = &pc_softc[unit];
2171 tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
2172 int i = 0;
2173 int sum = 0;
2174
2175 do {
2176 sum += (tbd_p->act_count & ~TBD_SW_EOF);
2177 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2178 i++, tbd_p->buffer_addr,
2179 (tbd_p->act_count & ~TBD_SW_EOF), sum,
2180 tbd_p->next_tbd_offset,
2181 tbd_p->buffer_base);
2182 if (tbd_p->act_count & TBD_SW_EOF)
2183 break;
2184 tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset);
2185 } while (1);
2186 }
2187
2188 #ifndef MACH_KERNEL
2189 pc586hdwsleaze(countp, mb_pp, tm_pp, unit)
2190 struct mbuf **tm_pp;
2191 u_char **mb_pp;
2192 u_short *countp;
2193 {
2194 struct mbuf *tm_p = *tm_pp;
2195 u_char *mb_p = *mb_pp;
2196 u_short count = 0;
2197 u_char *cp;
2198 int len;
2199
2200 pc586_cntrs[unit].xmt.sleaze++;
2201 /*
2202 * can we get a run that will be coallesced or
2203 * that terminates before breaking
2204 */
2205 do {
2206 count += tm_p->m_len;
2207 if (tm_p->m_len & 1)
2208 break;
2209 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2210 if ( (tm_p == (struct mbuf *)0) ||
2211 count > HDW_THRESHOLD) {
2212 *countp = (*tm_pp)->m_len;
2213 *mb_pp = mtod((*tm_pp), u_char *);
2214 printf("\n");
2215 return;
2216 }
2217
2218 /* we need to copy */
2219 pc586_cntrs[unit].xmt.intrinsic++;
2220 tm_p = *tm_pp;
2221 mb_p = *mb_pp;
2222 count = 0;
2223 cp = (u_char *) t_packet;
2224 do {
2225 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2226 count += len;
2227 if (count > HDW_THRESHOLD)
2228 break;
2229 cp += len;
2230 if (tm_p->m_next == (struct mbuf *)0)
2231 break;
2232 tm_p = tm_p->m_next;
2233 } while (1);
2234 pc586_cntrs[unit].xmt.intrinsic_count += count;
2235 *countp = count;
2236 *mb_pp = (u_char *) t_packet;
2237 *tm_pp = tm_p;
2238 return;
2239 }
2240
2241 pc586sftwsleaze(countp, mb_pp, tm_pp, unit)
2242 struct mbuf **tm_pp;
2243 u_char **mb_pp;
2244 u_short *countp;
2245 {
2246 struct mbuf *tm_p = *tm_pp;
2247 u_char *mb_p = *mb_pp;
2248 u_short count = 0;
2249 u_char *cp = (u_char *) t_packet;
2250 int len;
2251
2252 pc586_cntrs[unit].xmt.chain++;
2253 /* we need to copy */
2254 do {
2255 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2256 count += len;
2257 cp += len;
2258 if (tm_p->m_next == (struct mbuf *)0)
2259 break;
2260 tm_p = tm_p->m_next;
2261 } while (1);
2262
2263 *countp = count;
2264 *mb_pp = (u_char *) t_packet;
2265 *tm_pp = tm_p;
2266 return;
2267 }
2268 #endif MACH_KERNEL
Cache object: 4bfe9403221443532dd3f3c40a03278b
|