FreeBSD/Linux Kernel Cross Reference
sys/i386at/if_pc586.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993-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.23 93/11/17 16:48:26 dbg
30 * Removed non-MACH_KERNEL code. Converted HZ to hz.
31 * [93/05/21 dbg]
32 *
33 * Revision 2.22 93/05/10 21:19:37 rvb
34 * Lint.
35 * [93/05/08 11:21:38 af]
36 *
37 * Revision 2.21 93/01/24 13:17:39 danner
38 * Found a pc586 with octets 0:0:1c
39 * [93/01/15 rvb]
40 *
41 * Revision 2.20 93/01/14 17:30:55 danner
42 * Proper spl typing.
43 * [92/11/30 af]
44 *
45 * Revision 2.19 92/07/09 22:54:30 rvb
46 * Check for pc586 signature, rather than just for writable memory.
47 * [92/05/18 rvb]
48 *
49 * Revision 2.18 91/11/12 11:09:47 rvb
50 * Undo 2.16.1.1
51 * [91/10/25 rvb]
52 * Typo in transcribing the 2.5 changes missed ! before pc586read().
53 * Funny thing is that we did have this fixed in a branch once.
54 * [91/10/16 rvb]
55 *
56 * Revision 2.17 91/10/07 17:25:48 af
57 * Add a lot of fixes/improvements from 2.5.
58 * [91/09/04 rvb]
59 *
60 * Revision 2.16.1.1 91/09/03 17:27:39 af
61 * Be strict on matching the port and the device in the probe routine.
62 *
63 * Revision 2.16 91/08/24 11:58:12 af
64 * New MI autoconf.
65 * [91/08/02 02:54:27 af]
66 *
67 * Revision 2.15 91/05/14 16:25:37 mrt
68 * Correcting copyright
69 *
70 * Revision 2.14 91/05/13 06:02:51 af
71 * Made code under CMUCS standard.
72 * [91/05/12 15:50:10 af]
73 *
74 * Revision 2.13 91/03/16 14:46:38 rpd
75 * Updated for new kmem_alloc interface.
76 * [91/03/03 rpd]
77 * Changed net_filter to net_packet.
78 * [91/01/15 rpd]
79 *
80 * Revision 2.12 91/02/14 14:43:03 mrt
81 * You must check RBD_SW_EOF for rbd chain termination, a link of 0xffff
82 * does not work. Also we've just seen a status of 0xffff in rcv() with
83 * a bad fd_p->link_offset; we'll now reset.
84 * [91/01/17 rvb]
85 *
86 * Revision 2.11 91/02/05 17:18:19 mrt
87 * Changed to new Mach copyright
88 * [91/02/01 17:44:30 mrt]
89 *
90 * Revision 2.10 91/01/08 15:11:45 rpd
91 * Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
92 * [91/01/05 rpd]
93 *
94 * Revision 1.8.1.11 90/12/07 22:53:44 rvb
95 * Fix a few problems if your hardware goes haywire.
96 * Noted by Ali.
97 * [90/12/11 rvb]
98 *
99 * Revision 2.9 90/12/20 16:38:09 jeffreyh
100 * Changes for __STDC__
101 * [90/12/07 jeffreyh]
102 *
103 * Revision 1.8.1.12 91/01/06 22:11:54 rvb
104 * Try try again to get the ram_to_ptr problem in requeue.
105 * [90/11/29 rvb]
106 *
107 * Revision 2.8 90/11/26 14:49:59 rvb
108 * jsb bet me to XMK34, sigh ...
109 * [90/11/26 rvb]
110 * Synched 2.5 & 3.0 at I386q (r1.8.1.10) & XMK35 (r2.8)
111 * [90/11/15 rvb]
112 *
113 * Revision 2.7 90/11/05 14:28:11 rpd
114 * Convert for pure kernel
115 * [90/11/02 rvb]
116 *
117 * Init scb and reset as per spec. Use bcopy16 vs pc586copy as per spec.
118 * Accumulate counters at hwrst. Add counters everywhere.
119 * Editing and style and consistency cleanup.
120 * Flush NOP's: this required major mods to hwrst and everything it
121 * called -- testing OK is not correct if the command is not COMPLETE.
122 * Lot's of code clean up in xmt, rcv, reqfd.
123 * Flush pc_softc_t "address" and pc586ehcpy.
124 * Handle loopback of our ownbroadcast.
125 * The rcv and xmt loops have been rewriten not copy sram
126 * to the t_packet buffer. This yields a teriffic thruput
127 * improvement.
128 * Add Notes and sram map.
129 * [90/09/28 rvb]
130 *
131 * Revision 1.8.1.9 90/09/18 08:39:03 rvb
132 * Debugging printout to find shutdown reason.
133 * [90/09/14 rvb]
134 *
135 * Revision 1.8.1.8 90/08/25 15:44:14 rvb
136 * Use take_<>_irq() vs direct manipulations of ivect and friends.
137 * [90/08/20 rvb]
138 *
139 * Fix DSF_RUNNING. Some more cleanup.
140 * [90/08/14 rvb]
141 *
142 * Revision 1.8.1.7 90/07/27 11:26:06 rvb
143 * Fix Intel Copyright as per B. Davies authorization.
144 * [90/07/27 rvb]
145 *
146 * Revision 1.8.1.6 90/07/10 11:43:44 rvb
147 * New style probe/attach.
148 * [90/06/15 rvb]
149 *
150 * Revision 2.4 90/06/02 14:49:13 rpd
151 * Converted to new IPC.
152 * [90/06/01 rpd]
153 *
154 * Revision 2.3 90/05/29 18:48:51 rwd
155 * Test for next_rbd_offset NULL instead of RBD_SW_EOF in
156 * pc586reqfd. I don't know why this is needed on the pure kernel
157 * but not in the mainline - our slower device interface triggers a
158 * race?
159 * [90/05/25 dbg]
160 *
161 * Revision 2.2 90/05/03 15:44:10 dbg
162 * Check whether device exists on open.
163 * [90/05/02 dbg]
164 * MACH_KERNEL conversion.
165 * [90/04/23 dbg]
166 *
167 * Revision 1.8.1.5 90/03/16 18:15:26 rvb
168 * Clean up the i386_dev/i386_ctlr confusion.
169 * [90/03/15 rvb]
170 *
171 * Revision 1.8.1.4 90/02/28 15:49:46 rvb
172 * Fix numerous typo's in Olivetti disclaimer.
173 * Revision 1.10 90/02/07 11:29:37 [eugene]
174 * expanded NOP's and loops to allow for faster machines
175 *
176 * Revision 1.8.1.3 90/01/08 13:31:17 rvb
177 * Add Intel copyright.
178 * Add Olivetti copyright.
179 * [90/01/08 rvb]
180 *
181 * Revision 1.8.1.2 89/11/10 09:52:15 rvb
182 * Revision 1.7 89/10/31 16:05:45 eugene
183 * added changes for new include files
184 *
185 * Revision 1.7 89/10/31 16:05:45 eugene
186 * added changes for new include files
187 *
188 * Revision 1.6 89/10/02 10:32:04 eugene
189 * got the previous change correct
190 *
191 * Revision 1.8 89/09/20 17:28:33 rvb
192 * Revision 1.3 89/08/01 11:17:32 eugene
193 * Fixed ethernet driver hang on 25Mhz machines
194 *
195 * Revision 1.7 89/08/08 21:46:46 jsb
196 * Just count overruns and do not print anything.
197 * [89/08/03 rvb]
198 *
199 * Revision 1.6 89/07/17 10:40:38 rvb
200 * Olivetti Changes to X79 upto 5/12/89:
201 * & Fixed reseting when RNR is detected.
202 * [89/07/11 rvb]
203 *
204 * Revision 1.5 89/04/05 13:00:53 rvb
205 * Moved "softc" structure from .h to here and some cleanup
206 * [89/03/07 rvb]
207 *
208 * made ac_t and scb_t volatile pointers for gcc.
209 * [89/03/07 rvb]
210 *
211 * collapse pack_u_long_t for gcc.
212 * [89/03/06 rvb]
213 *
214 * Revision 1.4 89/03/09 20:06:01 rpd
215 * More cleanup.
216 *
217 * Revision 1.3 89/02/26 12:42:12 gm0w
218 * Changes for cleanup.
219 *
220 */
221
222 /*
223 * Olivetti PC586 Mach Ethernet driver v1.0
224 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
225 * All rights reserved.
226 *
227 */
228
229 /*
230 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
231 Cupertino, California.
232
233 All Rights Reserved
234
235 Permission to use, copy, modify, and distribute this software and
236 its documentation for any purpose and without fee is hereby
237 granted, provided that the above copyright notice appears in all
238 copies and that both the copyright notice and this permission notice
239 appear in supporting documentation, and that the name of Olivetti
240 not be used in advertising or publicity pertaining to distribution
241 of the software without specific, written prior permission.
242
243 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
244 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
245 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
246 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
247 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
248 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
249 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
250 */
251
252 /*
253 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
254
255 All Rights Reserved
256
257 Permission to use, copy, modify, and distribute this software and
258 its documentation for any purpose and without fee is hereby
259 granted, provided that the above copyright notice appears in all
260 copies and that both the copyright notice and this permission notice
261 appear in supporting documentation, and that the name of Intel
262 not be used in advertising or publicity pertaining to distribution
263 of the software without specific, written prior permission.
264
265 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
266 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
267 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
268 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
269 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
270 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
271 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
272 */
273
274 /*
275 * NOTE:
276 * by rvb:
277 * 1. The best book on the 82586 is:
278 * LAN Components User's Manual by Intel
279 * The copy I found was dated 1984. This really tells you
280 * what the state machines are doing
281 * 2. In the current design, we only do one write at a time,
282 * though the hardware is capable of chaining and possibly
283 * even batching. The problem is that we only make one
284 * transmit buffer available in sram space.
285 * 3.
286 * n. Board Memory Map
287 RFA/FD 0 - 227 0x228 bytes
288 226 = 0x19 * 0x16 bytes
289 RBD 228 - 3813 0x35ec bytes
290 35e8 = 0x19 * 0x228 bytes
291 == 0x0a bytes (bd) + 2 bytes + 21c bytes
292 CU 3814 - 3913 0x100 bytes
293 TBD 3914 - 39a3 0x90 bytes
294 90 = No 18 * 0x08 bytes
295 TBUF 39a4 - 3fdd 0x63a bytes (= 1594(10))
296 SCB 3fde - 3fed 0x10 bytes
297 ISCP 3fee - 3ff5 0x08 bytes
298 SCP 3ff6 - 3fff 0x0a bytes
299 *
300 */
301
302 /*
303 * NOTE:
304 *
305 * Currently this driver doesn't support trailer protocols for
306 * packets. Once that is added, please remove this comment.
307 *
308 * Also, some lacking material includes the DLI code. If you
309 * are compiling this driver with DLI set, lookout, that code
310 * has not been looked at.
311 *
312 */
313
314 #define DEBUG
315 #define IF_CNTRS MACH
316 #define NDLI 0
317
318 #include <pc586.h>
319
320 #include <kern/kern_io.h>
321 #include <kern/time_out.h>
322 #include <device/device_types.h>
323 #include <device/errno.h>
324 #include <device/io_req.h>
325 #include <device/if_hdr.h>
326 #include <device/if_ether.h>
327 #include <device/net_status.h>
328 #include <device/net_io.h>
329
330 #include <i386/ipl.h>
331 #include <mach/vm_param.h>
332 #include <vm/vm_kern.h>
333 #include <chips/busses.h>
334 #include <i386at/if_pc586.h>
335
336 #define SPLNET spl6
337 #if __STDC__
338 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y)
339 #else __STDC__
340 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y)
341 #endif __STDC__
342
343 #define pc586chatt(unit) CMD(CHANATT, 0x0001, unit)
344 #define pc586inton(unit) CMD(INTENAB, CMD_1, unit)
345 #define pc586intoff(unit) CMD(INTENAB, CMD_0, unit)
346
347 int pc586probe();
348 void pc586attach();
349 int pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset();
350 void pc586watch();
351 int pc586rcv(), pc586xmt(), pc586bldcu();
352 int pc586diag(), pc586config();
353 char *pc586bldru();
354 char *ram_to_ptr();
355 u_short ptr_to_ram();
356 void pc586start(
357 int unit);
358
359 static vm_offset_t pc586_std[NPC586] = { 0 };
360 static struct bus_device *pc586_info[NPC586];
361 struct bus_driver pcdriver =
362 {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0};
363
364 char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
365 int xmt_watch = 0;
366
367 typedef struct {
368 struct ifnet ds_if; /* generic interface header */
369 u_char ds_addr[6]; /* Ethernet hardware address */
370 int flags;
371 int seated;
372 int timer;
373 int open;
374 fd_t *begin_fd;
375 fd_t *end_fd;
376 rbd_t *end_rbd;
377 char *prom;
378 char *sram;
379 int tbusy;
380 short mode;
381 } pc_softc_t;
382 pc_softc_t pc_softc[NPC586];
383
384 struct pc586_cntrs {
385 struct {
386 u_int xmt, xmti;
387 u_int defer;
388 u_int busy;
389 u_int sleaze, intrinsic, intrinsic_count;
390 u_int chain;
391 } xmt;
392 struct {
393 u_int rcv;
394 u_int ovw;
395 u_int crc;
396 u_int frame;
397 u_int rscerrs, ovrnerrs;
398 u_int partial, bad_chain, fill;
399 } rcv;
400 u_int watch;
401 } pc586_cntrs[NPC586];
402
403
404 #ifdef IF_CNTRS
405 int pc586_narp = 1, pc586_arp = 0;
406 int pc586_ein[32], pc586_eout[32];
407 int pc586_lin[128/8], pc586_lout[128/8];
408 static
409 log_2(no)
410 unsigned long no;
411 {
412 return ({ unsigned long _temp__;
413 asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" :
414 "=r" (_temp__) : "a" (no));
415 _temp__;});
416 }
417 #endif IF_CNTRS
418
419 /*
420 * pc586probe:
421 *
422 * This function "probes" or checks for the pc586 board on the bus to see
423 * if it is there. As far as I can tell, the best break between this
424 * routine and the attach code is to simply determine whether the board
425 * is configured in properly. Currently my approach to this is to write
426 * and read a word from the SRAM on the board being probed. If the word
427 * comes back properly then we assume the board is there. The config
428 * code expects to see a successful return from the probe routine before
429 * attach will be called.
430 *
431 * input : address device is mapped to, and unit # being checked
432 * output : a '1' is returned if the board exists, and a 0 otherwise
433 *
434 */
435 pc586probe(port, dev)
436 struct bus_device *dev;
437 {
438 caddr_t addr = (caddr_t)dev->address;
439 int unit = dev->unit;
440 int len = round_page(0x4000);
441 int sram_len = round_page(0x4000);
442 extern vm_size_t mem_size;
443 volatile char *b_prom;
444 volatile char *b_sram;
445 volatile u_short*t_ps;
446
447 if ((unit < 0) || (unit > NPC586)) {
448 printf("pc%d: board out of range [0..%d]\n",
449 unit, NPC586);
450 return(0);
451 }
452 if (addr < (caddr_t)mem_size && addr > (caddr_t)0x100000)
453 return 0;
454
455 if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len)
456 != KERN_SUCCESS) {
457 printf("pc%d: can not allocate memory for prom.\n", unit);
458 return 0;
459 }
460 if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len)
461 != KERN_SUCCESS) {
462 printf("pc%d: can not allocate memory for sram.\n", unit);
463 return 0;
464 }
465 (void)pmap_map(b_prom, (vm_offset_t)addr,
466 (vm_offset_t)addr+len,
467 VM_PROT_READ | VM_PROT_WRITE);
468 if ((int)addr > 0x100000) /* stupid hardware */
469 addr += EXTENDED_ADDR;
470 addr += 0x4000; /* sram space */
471 (void)pmap_map(b_sram, (vm_offset_t)addr,
472 (vm_offset_t)addr+sram_len,
473 VM_PROT_READ | VM_PROT_WRITE);
474
475 *(b_prom + OFFSET_RESET) = 1;
476 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
477 *(b_prom + OFFSET_RESET) = 0;
478 t_ps = (u_short *)(b_sram + OFFSET_SCB);
479 *(t_ps) = (u_short)0x5a5a;
480 if (*(t_ps) != (u_short)0x5a5a) {
481 kmem_free(kernel_map, (vm_offset_t) b_prom, len);
482 kmem_free(kernel_map, (vm_offset_t) b_sram, sram_len);
483 return(0);
484 }
485 t_ps = (u_short *)(b_prom + + OFFSET_PROM);
486 #define ETHER0 0x00
487 #define ETHER1 0xaa
488 #define ETHER2 0x00
489 if ((t_ps[0]&0xff) == ETHER0 &&
490 (t_ps[1]&0xff) == ETHER1 &&
491 (t_ps[2]&0xff) == ETHER2)
492 pc_softc[unit].seated = TRUE;
493 #undef ETHER0
494 #undef ETHER1
495 #undef ETHER2
496 #define ETHER0 0x00
497 #define ETHER1 0x00
498 #define ETHER2 0x1c
499 if ((t_ps[0]&0xff) == ETHER0 ||
500 (t_ps[1]&0xff) == ETHER1 ||
501 (t_ps[2]&0xff) == ETHER2)
502 pc_softc[unit].seated = TRUE;
503 #undef ETHER0
504 #undef ETHER1
505 #undef ETHER2
506 if (pc_softc[unit].seated != TRUE) {
507 kmem_free(kernel_map, (vm_offset_t) b_prom, len);
508 kmem_free(kernel_map, (vm_offset_t) b_sram, sram_len);
509 return(0);
510 }
511 (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom;
512 (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram;
513 return(1);
514 }
515
516 /*
517 * pc586attach:
518 *
519 * This function attaches a PC586 board to the "system". The rest of
520 * runtime structures are initialized here (this routine is called after
521 * a successful probe of the board). Once the ethernet address is read
522 * and stored, the board's ifnet structure is attached and readied.
523 *
524 * input : bus_device structure setup in autoconfig
525 * output : board structs and ifnet is setup
526 *
527 */
528 void pc586attach(dev)
529 struct bus_device *dev;
530 {
531 struct ifnet *ifp;
532 u_char *addr_p;
533 u_short *b_addr;
534 u_char unit = (u_char)dev->unit;
535 pc_softc_t *sp = &pc_softc[unit];
536 volatile scb_t *scb_p;
537
538 take_dev_irq(dev);
539 printf(", port = %x, spl = %d, pic = %d. ",
540 dev->address, dev->sysdep, dev->sysdep1);
541
542 sp->timer = -1;
543 sp->flags = 0;
544 sp->mode = 0;
545 sp->open = 0;
546 CMD(RESET, CMD_1, unit);
547 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
548 CMD(RESET, CMD_0, unit);
549 b_addr = (u_short *)(sp->prom + OFFSET_PROM);
550 addr_p = (u_char *)sp->ds_addr;
551 addr_p[0] = b_addr[0];
552 addr_p[1] = b_addr[1];
553 addr_p[2] = b_addr[2];
554 addr_p[3] = b_addr[3];
555 addr_p[4] = b_addr[4];
556 addr_p[5] = b_addr[5];
557 printf("ethernet id [%x:%x:%x:%x:%x:%x]",
558 addr_p[0], addr_p[1], addr_p[2],
559 addr_p[3], addr_p[4], addr_p[5]);
560
561 scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB);
562 scb_p->scb_crcerrs = 0; /* initialize counters */
563 scb_p->scb_alnerrs = 0;
564 scb_p->scb_rscerrs = 0;
565 scb_p->scb_ovrnerrs = 0;
566
567 ifp = &(sp->ds_if);
568 ifp->if_unit = unit;
569 ifp->if_mtu = ETHERMTU;
570 ifp->if_flags = IFF_BROADCAST;
571 ifp->if_header_size = sizeof(struct ether_header);
572 ifp->if_header_format = HDR_ETHERNET;
573 ifp->if_address_size = 6;
574 ifp->if_address = (char *)&sp->ds_addr[0];
575 if_init_queues(ifp);
576 }
577
578 /*
579 * pc586reset:
580 *
581 * This routine is in part an entry point for the "if" code. Since most
582 * of the actual initialization has already (we hope already) been done
583 * by calling pc586attach().
584 *
585 * input : unit number or board number to reset
586 * output : board is reset
587 *
588 */
589 pc586reset(unit)
590 int unit;
591 {
592 pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
593 pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING);
594 return(pc586init(unit));
595
596 }
597
598 /*
599 * pc586init:
600 *
601 * Another routine that interfaces the "if" layer to this driver.
602 * Simply resets the structures that are used by "upper layers".
603 * As well as calling pc586hwrst that does reset the pc586 board.
604 *
605 * input : board number
606 * output : structures (if structs) and board are reset
607 *
608 */
609 pc586init(unit)
610 int unit;
611 {
612 struct ifnet *ifp;
613 int stat;
614 spl_t oldpri;
615
616 ifp = &(pc_softc[unit].ds_if);
617 oldpri = SPLNET();
618 if ((stat = pc586hwrst(unit)) == TRUE) {
619 timeout(pc586watch, &(ifp->if_unit), 5*hz);
620 pc_softc[unit].timer = 5;
621
622 pc_softc[unit].ds_if.if_flags |= IFF_RUNNING;
623 pc_softc[unit].flags |= DSF_RUNNING;
624 pc_softc[unit].tbusy = 0;
625 pc586start(unit);
626 #if DLI
627 dli_init();
628 #endif DLI
629 } else
630 printf("pc%d init(): trouble resetting board.\n", unit);
631 splx(oldpri);
632 return(stat);
633 }
634
635 /*ARGSUSED*/
636 io_return_t
637 pc586open(
638 int unit,
639 int flag)
640 {
641 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
642 return ENXIO;
643
644 pc_softc[unit].ds_if.if_flags |= IFF_UP;
645 pc586init(unit);
646 return 0;
647 }
648
649 /*
650 * pc586start:
651 *
652 * This is yet another interface routine that simply tries to output a
653 * in an mbuf after a reset.
654 *
655 * input : board number
656 * output : stuff sent to board if any there
657 *
658 */
659 void pc586start(
660 int unit)
661 {
662 io_req_t m;
663 struct ifnet *ifp;
664 register pc_softc_t *is = &pc_softc[unit];
665 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
666
667 if (is->tbusy) {
668 if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */
669 is->tbusy = 0;
670 pc586_cntrs[unit].xmt.busy++;
671 /*
672 * This is probably just a race. The xmt'r is just
673 * became idle but WE have masked interrupts so ...
674 */
675 if (xmt_watch) printf("!!");
676 } else
677 return;
678 }
679
680 ifp = &(pc_softc[unit].ds_if);
681 IF_DEQUEUE(&ifp->if_snd, m);
682 if (m != 0)
683 {
684 is->tbusy++;
685 pc586_cntrs[unit].xmt.xmt++;
686 pc586xmt(unit, m);
687 }
688 return;
689 }
690
691 /*
692 * pc586read:
693 *
694 * This routine does the actual copy of data (including ethernet header
695 * structure) from the pc586 to an mbuf chain that will be passed up
696 * to the "if" (network interface) layer. NOTE: we currently
697 * don't handle trailer protocols, so if that is needed, it will
698 * (at least in part) be added here. For simplicities sake, this
699 * routine copies the receive buffers from the board into a local (stack)
700 * buffer until the frame has been copied from the board. Once in
701 * the local buffer, the contents are copied to an mbuf chain that
702 * is then enqueued onto the appropriate "if" queue.
703 *
704 * input : board number, and an frame descriptor pointer
705 * output : the packet is put into an mbuf chain, and passed up
706 * assumes : if any errors occur, packet is "dropped on the floor"
707 *
708 */
709 pc586read(unit, fd_p)
710 int unit;
711 fd_t *fd_p;
712 {
713 register pc_softc_t *is = &pc_softc[unit];
714 register struct ifnet *ifp = &is->ds_if;
715 ipc_kmsg_t new_kmsg;
716 struct ether_header *ehp;
717 struct packet_header *pkt;
718 char *dp;
719 rbd_t *rbd_p;
720 u_char *buffer_p;
721 u_short len;
722 u_short bytes_in_msg;
723
724 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
725 printf("pc%d read(): board is not running.\n", ifp->if_unit);
726 pc586intoff(ifp->if_unit);
727 }
728 pc586_cntrs[unit].rcv.rcv++;
729 new_kmsg = net_kmsg_get();
730 if (new_kmsg == IKM_NULL) {
731 /*
732 * Drop the received packet.
733 */
734 is->ds_if.if_rcvdrops++;
735
736 /*
737 * not only do we want to return, we need to drop the packet on
738 * the floor to clear the interrupt.
739 */
740 return 1;
741 }
742 ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
743 pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]);
744
745 /*
746 * Get ether header.
747 */
748 ehp->ether_type = fd_p->length;
749 len = sizeof(struct ether_header);
750 bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE);
751 bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE);
752
753 /*
754 * Get packet body.
755 */
756 dp = (char *)(pkt + 1);
757
758 rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
759 if (rbd_p == 0) {
760 printf("pc%d read(): Invalid buffer\n", unit);
761 if (pc586hwrst(unit) != TRUE) {
762 printf("pc%d read(): hwrst trouble.\n", unit);
763 }
764 net_kmsg_put(new_kmsg);
765 return 0;
766 }
767
768 do {
769 buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
770 bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
771 bcopy16((u_short *)buffer_p,
772 (u_short *)dp,
773 (bytes_in_msg + 1) & ~1); /* but we know it's even */
774 len += bytes_in_msg;
775 dp += bytes_in_msg;
776 if (rbd_p->status & RBD_SW_EOF)
777 break;
778 rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit);
779 } while ((int) rbd_p);
780
781 pkt->type = ehp->ether_type;
782 pkt->length =
783 len - sizeof(struct ether_header)
784 + sizeof(struct packet_header);
785
786 /*
787 * Send the packet to the network module.
788 */
789 net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg));
790 return 1;
791 }
792
793 pc586output(dev, ior)
794 dev_t dev;
795 io_req_t ior;
796 {
797 register int unit;
798
799 unit = minor(dev); /* XXX */
800 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
801 return ENXIO;
802
803 return net_write(&pc_softc[unit].ds_if, pc586start, ior);
804 }
805
806 pc586setinput(dev, receive_port, priority, filter, filter_count)
807 dev_t dev;
808 mach_port_t receive_port;
809 int priority;
810 filter_t filter[];
811 unsigned int filter_count;
812 {
813 register int unit = minor(dev);
814 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
815 return (ENXIO);
816
817 return (net_set_filter(&pc_softc[unit].ds_if,
818 receive_port, priority,
819 filter, filter_count));
820 }
821
822 pc586getstat(dev, flavor, status, count)
823 dev_t dev;
824 int flavor;
825 dev_status_t status; /* pointer to OUT array */
826 unsigned int *count; /* out */
827 {
828 register int unit = minor(dev);
829 register pc_softc_t *sp;
830
831 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
832 return (ENXIO);
833
834 sp = &pc_softc[unit];
835 return (net_getstat(&sp->ds_if, flavor, status, count));
836 }
837
838 pc586setstat(dev, flavor, status, count)
839 dev_t dev;
840 int flavor;
841 dev_status_t status;
842 unsigned int count;
843 {
844 register int unit = minor(dev);
845 register pc_softc_t *sp;
846
847 if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
848 return (ENXIO);
849
850 sp = &pc_softc[unit];
851
852 switch (flavor) {
853 case NET_STATUS:
854 {
855 /*
856 * All we can change are flags, and not many of those.
857 */
858 register struct net_status *ns = (struct net_status *)status;
859 int mode = 0;
860
861 if (count < NET_STATUS_COUNT)
862 return (D_INVALID_OPERATION);
863
864 if (ns->flags & IFF_ALLMULTI)
865 mode |= MOD_ENAL;
866 if (ns->flags & IFF_PROMISC)
867 mode |= MOD_PROM;
868
869 /*
870 * Force a complete reset if the receive mode changes
871 * so that these take effect immediately.
872 */
873 if (sp->mode != mode) {
874 sp->mode = mode;
875 if (sp->flags & DSF_RUNNING) {
876 sp->flags &= ~(DSF_LOCK|DSF_RUNNING);
877 pc586init(unit);
878 }
879 }
880 break;
881 }
882
883 default:
884 return (D_INVALID_OPERATION);
885 }
886 return (D_SUCCESS);
887
888 }
889
890 /*
891 * pc586hwrst:
892 *
893 * This routine resets the pc586 board that corresponds to the
894 * board number passed in.
895 *
896 * input : board number to do a hardware reset
897 * output : board is reset
898 *
899 */
900 pc586hwrst(unit)
901 int unit;
902 {
903 CMD(CHANATT, CMD_0, unit);
904 CMD(RESET, CMD_1, unit);
905 { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
906 CMD(RESET,CMD_0, unit);
907
908 /*
909 * for (i = 0; i < 1000000; i++);
910 * with this loop above and with the reset toggle also looping to
911 * 1000000. We don't see the reset behaving as advertised. DOES
912 * IT HAPPEN AT ALL. In particular, NORMODE, ENABLE, and XFER
913 * should all be zero and they have not changed at all.
914 */
915 CMD(INTENAB, CMD_0, unit);
916 CMD(NORMMODE, CMD_0, unit);
917 CMD(XFERMODE, CMD_1, unit);
918
919 pc586bldcu(unit);
920
921 if (pc586diag(unit) == FALSE)
922 return(FALSE);
923
924 if (pc586config(unit) == FALSE)
925 return(FALSE);
926 /*
927 * insert code for loopback test here
928 *
929 */
930 pc586rustrt(unit);
931
932 pc586inton(unit);
933 CMD(NORMMODE, CMD_1, unit);
934 return(TRUE);
935 }
936
937 /*
938 * pc586watch():
939 *
940 * This routine is the watchdog timer routine for the pc586 chip. If
941 * chip wedges, this routine will fire and cause a board reset and
942 * begin again.
943 *
944 * input : which board is timing out
945 * output : potential board reset if wedged
946 *
947 */
948 int watch_dead = 0;
949 void pc586watch(b_ptr)
950 caddr_t b_ptr;
951 {
952 spl_t opri;
953 int unit = *b_ptr;
954
955 if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0) {
956 return;
957 }
958 if (pc_softc[unit].timer == -1) {
959 timeout(pc586watch, b_ptr, 5*hz);
960 return;
961 }
962 if (--pc_softc[unit].timer != -1) {
963 timeout(pc586watch, b_ptr, 1*hz);
964 return;
965 }
966
967 opri = SPLNET();
968 #ifdef notdef
969 printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead);
970 #endif notdef
971 pc586_cntrs[unit].watch++;
972 if (pc586hwrst(unit) != TRUE) {
973 printf("pc%d watch(): hwrst trouble.\n", unit);
974 pc_softc[unit].timer = 0;
975 } else {
976 timeout(pc586watch, b_ptr, 1*hz);
977 pc_softc[unit].timer = 5;
978 }
979 splx(opri);
980 }
981
982 /*
983 * pc586intr:
984 *
985 * This function is the interrupt handler for the pc586 ethernet
986 * board. This routine will be called whenever either a packet
987 * is received, or a packet has successfully been transfered and
988 * the unit is ready to transmit another packet.
989 *
990 * input : board number that interrupted
991 * output : either a packet is received, or a packet is transfered
992 *
993 */
994 pc586intr(unit)
995 int unit;
996 {
997 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
998 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
999 u_short int_type;
1000
1001 if (pc_softc[unit].seated == FALSE) {
1002 printf("pc%d intr(): board not seated\n", unit);
1003 return(-1);
1004 }
1005
1006 while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) {
1007 pc586ack(unit);
1008 if (int_type & SCB_SW_FR) {
1009 pc586rcv(unit);
1010 watch_dead=0;
1011 }
1012 if (int_type & SCB_SW_RNR) {
1013 pc586_cntrs[unit].rcv.ovw++;
1014 #ifdef notdef
1015 printf("pc%d intr(): receiver overrun! begin_fd = %x\n",
1016 unit, pc_softc[unit].begin_fd);
1017 #endif notdef
1018 pc586rustrt(unit);
1019 }
1020 if (int_type & SCB_SW_CNA) {
1021 /*
1022 * At present, we don't care about CNA's. We
1023 * believe they are a side effect of XMT.
1024 */
1025 }
1026 if (int_type & SCB_SW_CX) {
1027 /*
1028 * At present, we only request Interrupt for
1029 * XMT.
1030 */
1031 if ((!(cb_p->ac_status & AC_SW_OK)) ||
1032 (cb_p->ac_status & (0xfff^TC_SQE))) {
1033 if (cb_p->ac_status & TC_DEFER) {
1034 if (xmt_watch) printf("DF");
1035 pc586_cntrs[unit].xmt.defer++;
1036 } else if (cb_p->ac_status & (TC_COLLISION|0xf)) {
1037 if (xmt_watch) printf("%x",cb_p->ac_status & 0xf);
1038 } else if (xmt_watch)
1039 printf("pc%d XMT: %x %x\n",
1040 unit, cb_p->ac_status, cb_p->ac_command);
1041 }
1042 pc586_cntrs[unit].xmt.xmti++;
1043 pc_softc[unit].tbusy = 0;
1044 pc586start(unit);
1045 }
1046 pc_softc[unit].timer = 5;
1047 }
1048 return(0);
1049 }
1050
1051 /*
1052 * pc586rcv:
1053 *
1054 * This routine is called by the interrupt handler to initiate a
1055 * packet transfer from the board to the "if" layer above this
1056 * driver. This routine checks if a buffer has been successfully
1057 * received by the pc586. If so, the routine pc586read is called
1058 * to do the actual transfer of the board data (including the
1059 * ethernet header) into a packet (consisting of an mbuf chain).
1060 *
1061 * input : number of the board to check
1062 * output : if a packet is available, it is "sent up"
1063 *
1064 */
1065 pc586rcv(unit)
1066 int unit;
1067 {
1068 fd_t *fd_p;
1069
1070 for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL;
1071 fd_p = pc_softc[unit].begin_fd) {
1072 if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) {
1073 if (pc586hwrst(unit) != TRUE)
1074 printf("pc%d rcv(): hwrst ffff trouble.\n",
1075 unit);
1076 return;
1077 } else if (fd_p->status & AC_SW_C) {
1078 fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit);
1079
1080 if (fd_p->status == (RFD_DONE|RFD_RSC)) {
1081 /* lost one */;
1082 #ifdef notdef
1083 printf("pc%d RCV: RSC %x\n",
1084 unit, fd_p->status);
1085 #endif notdef
1086 pc586_cntrs[unit].rcv.partial++;
1087 } else if (!(fd_p->status & RFD_OK))
1088 printf("pc%d RCV: !OK %x\n",
1089 unit, fd_p->status);
1090 else if (fd_p->status & 0xfff)
1091 printf("pc%d RCV: ERRs %x\n",
1092 unit, fd_p->status);
1093 else
1094 if (!pc586read(unit, fd_p))
1095 return;
1096 if (!pc586requeue(unit, fd_p)) { /* abort on chain error */
1097 if (pc586hwrst(unit) != TRUE)
1098 printf("pc%d rcv(): hwrst trouble.\n", unit);
1099 return;
1100 }
1101 pc_softc[unit].begin_fd = bfd;
1102 } else
1103 break;
1104 }
1105 return;
1106 }
1107
1108 /*
1109 * pc586requeue:
1110 *
1111 * This routine puts rbd's used in the last receive back onto the
1112 * free list for the next receive.
1113 *
1114 */
1115 pc586requeue(unit, fd_p)
1116 int unit;
1117 fd_t *fd_p;
1118 {
1119 rbd_t *l_rbdp;
1120 rbd_t *f_rbdp;
1121
1122 #ifndef REQUEUE_DBG
1123 if (bad_rbd_chain(fd_p->rbd_offset, unit))
1124 return 0;
1125 #endif REQUEUE_DBG
1126 f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
1127 if (f_rbdp != NULL) {
1128 l_rbdp = f_rbdp;
1129 while ( (!(l_rbdp->status & RBD_SW_EOF)) &&
1130 (l_rbdp->next_rbd_offset != 0xffff))
1131 {
1132 l_rbdp->status = 0;
1133 l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset,
1134 unit);
1135 }
1136 l_rbdp->next_rbd_offset = PC586NULL;
1137 l_rbdp->status = 0;
1138 l_rbdp->size |= AC_CW_EL;
1139 pc_softc[unit].end_rbd->next_rbd_offset =
1140 ptr_to_ram((char *)f_rbdp, unit);
1141 pc_softc[unit].end_rbd->size &= ~AC_CW_EL;
1142 pc_softc[unit].end_rbd= l_rbdp;
1143 }
1144
1145 fd_p->status = 0;
1146 fd_p->command = AC_CW_EL;
1147 fd_p->link_offset = PC586NULL;
1148 fd_p->rbd_offset = PC586NULL;
1149
1150 pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit);
1151 pc_softc[unit].end_fd->command = 0;
1152 pc_softc[unit].end_fd = fd_p;
1153
1154 return 1;
1155 }
1156
1157 /*
1158 * pc586xmt:
1159 *
1160 * This routine fills in the appropriate registers and memory
1161 * locations on the PC586 board and starts the board off on
1162 * the transmit.
1163 *
1164 * input : board number of interest, and a pointer to the mbuf
1165 * output : board memory and registers are set for xfer and attention
1166 *
1167 */
1168 #ifdef DEBUG
1169 int xmt_debug = 0;
1170 #endif DEBUG
1171 pc586xmt(unit, m)
1172 int unit;
1173 io_req_t m;
1174 {
1175 pc_softc_t *is = &pc_softc[unit];
1176 register u_char *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF);
1177 register u_short *xmtshort_p;
1178 register struct ether_header *eh_p = (struct ether_header *)m->io_data;
1179 volatile scb_t *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB);
1180 volatile ac_t *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU);
1181 tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
1182 u_short clen = 0;
1183
1184 cb_p->ac_status = 0;
1185 cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1186 cb_p->ac_link_offset = PC586NULL;
1187 cb_p->cmd.transmit.tbd_offset = OFFSET_TBD;
1188
1189 bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE);
1190 cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type);
1191
1192 tbd_p->act_count = 0;
1193 tbd_p->buffer_base = 0;
1194 tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
1195 { int Rlen, Llen;
1196 clen = m->io_count - sizeof(struct ether_header);
1197 Llen = clen & 1;
1198 Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1;
1199
1200 bcopy16(m->io_data + sizeof(struct ether_header) - Rlen,
1201 xmtdata_p,
1202 clen + (Rlen + Llen) );
1203 xmtdata_p += clen + Llen;
1204 tbd_p->act_count = clen;
1205 tbd_p->buffer_addr += Rlen;
1206 }
1207 #ifdef DEBUG
1208 if (xmt_debug)
1209 printf("CLEN = %d\n", clen);
1210 #endif DEBUG
1211 if (clen < ETHERMIN) {
1212 tbd_p->act_count += ETHERMIN - clen;
1213 for (xmtshort_p = (u_short *)xmtdata_p;
1214 clen < ETHERMIN;
1215 clen += 2) *xmtshort_p++ = 0;
1216 }
1217 tbd_p->act_count |= TBD_SW_EOF;
1218 tbd_p->next_tbd_offset = PC586NULL;
1219 #ifdef IF_CNTRS
1220 clen += sizeof (struct ether_header) + 4 /* crc */;
1221 pc586_eout[log_2(clen)]++;
1222 if (clen < 128) pc586_lout[clen>>3]++;
1223 #endif IF_CNTRS
1224 #ifdef DEBUG
1225 if (xmt_debug) {
1226 pc586tbd(unit);
1227 printf("\n");
1228 }
1229 #endif DEBUG
1230
1231 while (scb_p->scb_command) ;
1232 scb_p->scb_command = SCB_CU_STRT;
1233 pc586chatt(unit);
1234
1235 iodone(m);
1236 return;
1237 }
1238
1239 /*
1240 * pc586bldcu:
1241 *
1242 * This function builds up the command unit structures. It inits
1243 * the scp, iscp, scb, cb, tbd, and tbuf.
1244 *
1245 */
1246 pc586bldcu(unit)
1247 {
1248 char *sram = pc_softc[unit].sram;
1249 scp_t *scp_p = (scp_t *)(sram + OFFSET_SCP);
1250 iscp_t *iscp_p = (iscp_t *)(sram + OFFSET_ISCP);
1251 volatile scb_t *scb_p = (volatile scb_t *)(sram + OFFSET_SCB);
1252 volatile ac_t *cb_p = (volatile ac_t *)(sram + OFFSET_CU);
1253 tbd_t *tbd_p = (tbd_t *)(sram + OFFSET_TBD);
1254 int i;
1255
1256 scp_p->scp_sysbus = 0;
1257 scp_p->scp_iscp = OFFSET_ISCP;
1258 scp_p->scp_iscp_base = 0;
1259
1260 iscp_p->iscp_busy = 1;
1261 iscp_p->iscp_scb_offset = OFFSET_SCB;
1262 iscp_p->iscp_scb = 0;
1263 iscp_p->iscp_scb_base = 0;
1264
1265 pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs;
1266 pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs;
1267 pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs;
1268 pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs;
1269 scb_p->scb_status = 0;
1270 scb_p->scb_command = 0;
1271 scb_p->scb_cbl_offset = OFFSET_CU;
1272 scb_p->scb_rfa_offset = OFFSET_RU;
1273 scb_p->scb_crcerrs = 0;
1274 scb_p->scb_alnerrs = 0;
1275 scb_p->scb_rscerrs = 0;
1276 scb_p->scb_ovrnerrs = 0;
1277
1278 scb_p->scb_command = SCB_RESET;
1279 pc586chatt(unit);
1280 for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); );
1281 if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit);
1282 for (i = STATUS_TRIES; i-- > 0; ) {
1283 if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA))
1284 break;
1285 }
1286 if (!i)
1287 printf("pc%d bldcu(): not ready after reset.\n", unit);
1288 pc586ack(unit);
1289
1290 cb_p->ac_status = 0;
1291 cb_p->ac_command = AC_CW_EL;
1292 cb_p->ac_link_offset = OFFSET_CU;
1293
1294 tbd_p->act_count = 0;
1295 tbd_p->next_tbd_offset = PC586NULL;
1296 tbd_p->buffer_addr = 0;
1297 tbd_p->buffer_base = 0;
1298 return;
1299 }
1300
1301 /*
1302 * pc586bldru:
1303 *
1304 * This function builds the linear linked lists of fd's and
1305 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1306 *
1307 */
1308 char *
1309 pc586bldru(unit)
1310 int unit;
1311 {
1312 fd_t *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1313 ru_t *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD);
1314 int i;
1315
1316 pc_softc[unit].begin_fd = fd_p;
1317 for(i = 0; i < N_FD; i++, fd_p++) {
1318 fd_p->status = 0;
1319 fd_p->command = 0;
1320 fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit);
1321 fd_p->rbd_offset = PC586NULL;
1322 }
1323 pc_softc[unit].end_fd = --fd_p;
1324 fd_p->link_offset = PC586NULL;
1325 fd_p->command = AC_CW_EL;
1326 fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1327
1328 fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit);
1329 for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) {
1330 rbd_p->r.status = 0;
1331 rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer),
1332 unit);
1333 rbd_p->r.buffer_base = 0;
1334 rbd_p->r.size = RCVBUFSIZE;
1335 if (i != N_RBD-1) {
1336 rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]),
1337 unit);
1338 } else {
1339 rbd_p->r.next_rbd_offset = PC586NULL;
1340 rbd_p->r.size |= AC_CW_EL;
1341 pc_softc[unit].end_rbd = (rbd_t *)rbd_p;
1342 }
1343 }
1344 return (char *)pc_softc[unit].begin_fd;
1345 }
1346
1347 /*
1348 * pc586rustrt:
1349 *
1350 * This routine starts the receive unit running. First checks if the
1351 * board is actually ready, then the board is instructed to receive
1352 * packets again.
1353 *
1354 */
1355 pc586rustrt(unit)
1356 int unit;
1357 {
1358 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1359 char *strt;
1360
1361 if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY)
1362 return;
1363
1364 strt = pc586bldru(unit);
1365 scb_p->scb_command = SCB_RU_STRT;
1366 scb_p->scb_rfa_offset = ptr_to_ram(strt, unit);
1367 pc586chatt(unit);
1368 return;
1369 }
1370
1371 /*
1372 * pc586diag:
1373 *
1374 * This routine does a 586 op-code number 7, and obtains the
1375 * diagnose status for the pc586.
1376 *
1377 */
1378 pc586diag(unit)
1379 int unit;
1380 {
1381 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1382 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1383 int i;
1384
1385 if (scb_p->scb_status & SCB_SW_INT) {
1386 printf("pc%d diag(): bad initial state %#x\n",
1387 unit, scb_p->scb_status);
1388 pc586ack(unit);
1389 }
1390 cb_p->ac_status = 0;
1391 cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL);
1392 scb_p->scb_command = SCB_CU_STRT;
1393 pc586chatt(unit);
1394
1395 for(i = 0; i < 0xffff; i++)
1396 if ((cb_p->ac_status & AC_SW_C))
1397 break;
1398 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1399 printf("pc%d: diag failed; status = %x\n",
1400 unit, cb_p->ac_status);
1401 return(FALSE);
1402 }
1403
1404 if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) ) {
1405 printf("pc%d diag(): bad final state %x\n",
1406 unit, scb_p->scb_status);
1407 pc586ack(unit);
1408 }
1409 return(TRUE);
1410 }
1411
1412 /*
1413 * pc586config:
1414 *
1415 * This routine does a standard config of the pc586 board.
1416 *
1417 */
1418 pc586config(unit)
1419 int unit;
1420 {
1421 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1422 volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1423 int i;
1424
1425
1426 /*
1427 if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) {
1428 printf("pc%d config(): unexpected initial state %x\n",
1429 unit, scb_p->scb_status);
1430 }
1431 */
1432 pc586ack(unit);
1433
1434 cb_p->ac_status = 0;
1435 cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL);
1436
1437 /*
1438 * below is the default board configuration from p2-28 from 586 book
1439 */
1440 cb_p->cmd.configure.fifolim_bytecnt = 0x080c;
1441 cb_p->cmd.configure.addrlen_mode = 0x2600;
1442 cb_p->cmd.configure.linprio_interframe = 0x6000;
1443 cb_p->cmd.configure.slot_time = 0xf200;
1444 cb_p->cmd.configure.hardware = 0x0000;
1445 cb_p->cmd.configure.min_frame_len = 0x0040;
1446
1447 scb_p->scb_command = SCB_CU_STRT;
1448 pc586chatt(unit);
1449
1450 for(i = 0; i < 0xffff; i++)
1451 if ((cb_p->ac_status & AC_SW_C))
1452 break;
1453 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1454 printf("pc%d: config-configure failed; status = %x\n",
1455 unit, cb_p->ac_status);
1456 return(FALSE);
1457 }
1458 /*
1459 if (scb_p->scb_status & SCB_SW_INT) {
1460 printf("pc%d configure(): bad configure state %x\n",
1461 unit, scb_p->scb_status);
1462 pc586ack(unit);
1463 }
1464 */
1465 cb_p->ac_status = 0;
1466 cb_p->ac_command = (AC_IASETUP|AC_CW_EL);
1467
1468 bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE);
1469
1470 scb_p->scb_command = SCB_CU_STRT;
1471 pc586chatt(unit);
1472
1473 for (i = 0; i < 0xffff; i++)
1474 if ((cb_p->ac_status & AC_SW_C))
1475 break;
1476 if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1477 printf("pc%d: config-address failed; status = %x\n",
1478 unit, cb_p->ac_status);
1479 return(FALSE);
1480 }
1481 /*
1482 if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) {
1483 printf("pc%d configure(): unexpected final state %x\n",
1484 unit, scb_p->scb_status);
1485 }
1486 */
1487 pc586ack(unit);
1488
1489 return(TRUE);
1490 }
1491
1492 /*
1493 * pc586ack:
1494 */
1495 pc586ack(unit)
1496 {
1497 volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1498 int i;
1499
1500 if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT))
1501 return;
1502 CMD(CHANATT, 0x0001, unit);
1503 for (i = 1000000; scb_p->scb_command && (i-- > 0); );
1504 if (!i)
1505 printf("pc%d pc586ack(): board not accepting command.\n", unit);
1506 }
1507
1508 char *
1509 ram_to_ptr(offset, unit)
1510 int unit;
1511 u_short offset;
1512 {
1513 if (offset == PC586NULL)
1514 return(NULL);
1515 if (offset > 0x3fff) {
1516 printf("ram_to_ptr(%x, %d)\n", offset, unit);
1517 panic("range");
1518 return(NULL);
1519 }
1520 return(pc_softc[unit].sram + offset);
1521 }
1522
1523 #ifndef REQUEUE_DBG
1524 bad_rbd_chain(offset, unit)
1525 {
1526 rbd_t *rbdp;
1527 char *sram = pc_softc[unit].sram;
1528
1529 for (;;) {
1530 if (offset == PC586NULL)
1531 return 0;
1532 if (offset > 0x3fff) {
1533 printf("pc%d: bad_rbd_chain offset = %x\n",
1534 unit, offset);
1535 pc586_cntrs[unit].rcv.bad_chain++;
1536 return 1;
1537 }
1538
1539 rbdp = (rbd_t *)(sram + offset);
1540 offset = rbdp->next_rbd_offset;
1541 }
1542 }
1543 #endif REQUEUE_DBG
1544
1545 u_short
1546 ptr_to_ram(k_va, unit)
1547 char *k_va;
1548 int unit;
1549 {
1550 return((u_short)(k_va - pc_softc[unit].sram));
1551 }
1552
1553 pc586scb(unit)
1554 {
1555 volatile scb_t *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1556 volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE);
1557 u_short i;
1558
1559 i = scb->scb_status;
1560 printf("stat: stat %x, cus %x, rus %x //",
1561 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
1562 i = scb->scb_command;
1563 printf(" cmd: ack %x, cuc %x, ruc %x\n",
1564 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
1565
1566 printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n",
1567 scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc,
1568 scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame,
1569 scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs,
1570 scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs);
1571
1572 printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset);
1573 printf(" norm %x, ena %x, xfer %x //",
1574 cmd[0] & 1, cmd[3] & 1, cmd[4] & 1);
1575 printf(" atn %x, reset %x, type %x, stat %x\n",
1576 cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1);
1577 }
1578
1579 pc586tbd(unit)
1580 {
1581 pc_softc_t *is = &pc_softc[unit];
1582 tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
1583 int i = 0;
1584 int sum = 0;
1585
1586 do {
1587 sum += (tbd_p->act_count & ~TBD_SW_EOF);
1588 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
1589 i++, tbd_p->buffer_addr,
1590 (tbd_p->act_count & ~TBD_SW_EOF), sum,
1591 tbd_p->next_tbd_offset,
1592 tbd_p->buffer_base);
1593 if (tbd_p->act_count & TBD_SW_EOF)
1594 break;
1595 tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset);
1596 } while (1);
1597 }
1598
Cache object: 332f95c5300bcf76846f116169735fd3
|