1 /*
2 * rtl8139.c
3 *
4 * This file contains a ethernet device driver for Realtek rtl8139 based
5 * ethernet cards.
6 *
7 * The valid messages and their parameters are:
8 *
9 * m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
10 * |------------+----------+---------+----------+---------+---------|
11 * | HARD_INT | | | | | |
12 * |------------|----------|---------|----------|---------|---------|
13 * | SYS_SIG | | | | | |
14 * |------------|----------|---------|----------|---------|---------|
15 * | DL_WRITE | port nr | proc nr | count | mode | address |
16 * |------------|----------|---------|----------|---------|---------|
17 * | DL_WRITEV | port nr | proc nr | count | mode | address |
18 * |------------|----------|---------|----------|---------|---------|
19 * | DL_READ | port nr | proc nr | count | | address |
20 * |------------|----------|---------|----------|---------|---------|
21 * | DL_READV | port nr | proc nr | count | | address |
22 * |------------|----------|---------|----------|---------|---------|
23 * | DL_INIT | port nr | proc nr | mode | | address |
24 * |------------|----------|---------|----------|---------|---------|
25 * | DL_GETSTAT | port nr | proc nr | | | address |
26 * |------------|----------|---------|----------|---------|---------|
27 * | DL_GETNAME | | | | | |
28 * |------------|----------|---------|----------|---------|---------|
29 * | DL_STOP | port_nr | | | | |
30 * |------------|----------|---------|----------|---------|---------|
31 *
32 * The messages sent are:
33 *
34 * m-type DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
35 * |------------|----------|---------|----------|---------|---------|
36 * |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
37 * |------------|----------|---------|----------|---------|---------|
38 *
39 * m_type m3_i1 m3_i2 m3_ca1
40 * |------------+---------+-----------+---------------|
41 * |DL_INIT_REPL| port nr | last port | ethernet addr |
42 * |------------|---------|-----------|---------------|
43 *
44 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
45 * Changes:
46 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
47 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
48 *
49 */
50
51 #include "../drivers.h"
52
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <stddef.h>
57 #include <minix/com.h>
58 #include <minix/keymap.h>
59 #include <minix/syslib.h>
60 #include <minix/type.h>
61 #include <minix/sysutil.h>
62 #include <timers.h>
63 #include <ibm/portio.h>
64 #include <net/hton.h>
65 #include <net/gen/ether.h>
66 #include <net/gen/eth_io.h>
67
68 #include <sys/types.h>
69 #include <fcntl.h>
70 #include <assert.h>
71 #include <unistd.h>
72 #include <sys/ioc_memory.h>
73 #include "../../kernel/const.h"
74 #include "../../kernel/config.h"
75 #include "../../kernel/type.h"
76
77 #define tmra_ut timer_t
78 #define tmra_inittimer(tp) tmr_inittimer(tp)
79 #define Proc_number(p) proc_number(p)
80 #define debug 0
81 #define printW() ((void)0)
82 #define vm_1phys2bus(p) (p)
83
84 #define VERBOSE 0 /* display message during init */
85
86 #include "../libpci/pci.h"
87 #include "rtl8139.h"
88
89 #define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE
90 #define RX_BUFBITS RL_RCR_RBLEN_64K
91 #define N_TX_BUF RL_N_TX
92
93 #define RE_PORT_NR 1 /* Minix */
94
95 /* I/O vectors are handled IOVEC_NR entries at a time. */
96 #define IOVEC_NR 16
97
98 /* Configuration */
99 #define RL_ENVVAR "RTLETH"
100
101 PRIVATE struct pcitab
102 {
103 u16_t vid;
104 u16_t did;
105 int checkclass;
106 } pcitab[]=
107 {
108 { 0x10ec, 0x8139, 0 }, /* Realtek RTL8139 */
109 { 0x1186, 0x1300, 0 }, /* D-Link RTL8139 */
110
111 { 0x0000, 0x0000, 0 }
112 };
113
114 typedef struct re
115 {
116 port_t re_base_port;
117 int re_irq;
118 int re_mode;
119 int re_flags;
120 int re_client;
121 int re_link_up;
122 int re_got_int;
123 int re_send_int;
124 int re_report_link;
125 int re_clear_rx;
126 int re_need_reset;
127 int re_tx_alive;
128 char *re_model;
129
130 /* Rx */
131 phys_bytes re_rx_buf;
132 char *v_re_rx_buf;
133 vir_bytes re_read_s;
134
135 /* Tx */
136 int re_tx_head;
137 int re_tx_tail;
138 struct
139 {
140 int ret_busy;
141 phys_bytes ret_buf;
142 char * v_ret_buf;
143 } re_tx[N_TX_BUF];
144 u32_t re_ertxth; /* Early Tx Threshold */
145
146 /* PCI related */
147 int re_seen; /* TRUE iff device available */
148 u8_t re_pcibus;
149 u8_t re_pcidev;
150 u8_t re_pcifunc;
151
152 /* 'large' items */
153 int re_hook_id; /* IRQ hook id at kernel */
154 eth_stat_t re_stat;
155 ether_addr_t re_address;
156 message re_rx_mess;
157 message re_tx_mess;
158 char re_name[sizeof("rtl8139#n")];
159 iovec_t re_iovec[IOVEC_NR];
160 }
161 re_t;
162
163 #define REM_DISABLED 0x0
164 #define REM_ENABLED 0x1
165
166 #define REF_PACK_SENT 0x001
167 #define REF_PACK_RECV 0x002
168 #define REF_SEND_AVAIL 0x004
169 #define REF_READING 0x010
170 #define REF_EMPTY 0x000
171 #define REF_PROMISC 0x040
172 #define REF_MULTI 0x080
173 #define REF_BROAD 0x100
174 #define REF_ENABLED 0x200
175
176 static re_t re_table[RE_PORT_NR];
177
178 static u16_t eth_ign_proto;
179 static tmra_ut rl_watchdog;
180
181 FORWARD _PROTOTYPE( unsigned my_inb, (U16_t port) );
182 FORWARD _PROTOTYPE( unsigned my_inw, (U16_t port) );
183 FORWARD _PROTOTYPE( unsigned my_inl, (U16_t port) );
184 static unsigned my_inb(U16_t port) {
185 U8_t value;
186 int s;
187 if ((s=sys_inb(port, &value)) !=OK)
188 printf("RTL8139: warning, sys_inb failed: %d\n", s);
189 return value;
190 }
191 static unsigned my_inw(U16_t port) {
192 U16_t value;
193 int s;
194 if ((s=sys_inw(port, &value)) !=OK)
195 printf("RTL8139: warning, sys_inw failed: %d\n", s);
196 return value;
197 }
198 static unsigned my_inl(U16_t port) {
199 U32_t value;
200 int s;
201 if ((s=sys_inl(port, &value)) !=OK)
202 printf("RTL8139: warning, sys_inl failed: %d\n", s);
203 return value;
204 }
205 #define rl_inb(port, offset) (my_inb((port) + (offset)))
206 #define rl_inw(port, offset) (my_inw((port) + (offset)))
207 #define rl_inl(port, offset) (my_inl((port) + (offset)))
208
209 FORWARD _PROTOTYPE( void my_outb, (U16_t port, U8_t value) );
210 FORWARD _PROTOTYPE( void my_outw, (U16_t port, U16_t value) );
211 FORWARD _PROTOTYPE( void my_outl, (U16_t port, U32_t value) );
212 static void my_outb(U16_t port, U8_t value) {
213 int s;
214 if ((s=sys_outb(port, value)) !=OK)
215 printf("RTL8139: warning, sys_outb failed: %d\n", s);
216 }
217 static void my_outw(U16_t port, U16_t value) {
218 int s;
219 if ((s=sys_outw(port, value)) !=OK)
220 printf("RTL8139: warning, sys_outw failed: %d\n", s);
221 }
222 static void my_outl(U16_t port, U32_t value) {
223 int s;
224 if ((s=sys_outl(port, value)) !=OK)
225 printf("RTL8139: warning, sys_outl failed: %d\n", s);
226 }
227 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
228 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
229 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
230
231 _PROTOTYPE( static void rl_init, (message *mp) );
232 _PROTOTYPE( static void rl_pci_conf, (void) );
233 _PROTOTYPE( static int rl_probe, (re_t *rep) );
234 _PROTOTYPE( static void rl_conf_hw, (re_t *rep) );
235 _PROTOTYPE( static void rl_init_buf, (re_t *rep) );
236 _PROTOTYPE( static void rl_init_hw, (re_t *rep) );
237 _PROTOTYPE( static void rl_reset_hw, (re_t *rep) );
238 _PROTOTYPE( static void rl_confaddr, (re_t *rep) );
239 _PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
240 _PROTOTYPE( static void rl_readv, (message *mp, int from_int,
241 int vectored) );
242 _PROTOTYPE( static void rl_writev, (message *mp, int from_int,
243 int vectored) );
244 _PROTOTYPE( static void rl_check_ints, (re_t *rep) );
245 _PROTOTYPE( static void rl_report_link, (re_t *rep) );
246 _PROTOTYPE( static void mii_print_techab, (U16_t techab) );
247 _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
248 U16_t extstat) );
249 _PROTOTYPE( static void rl_clear_rx, (re_t *rep) );
250 _PROTOTYPE( static void rl_do_reset, (re_t *rep) );
251 _PROTOTYPE( static void rl_getstat, (message *mp) );
252 _PROTOTYPE( static void rl_getname, (message *mp) );
253 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
254 _PROTOTYPE( static void mess_reply, (message *req, message *reply) );
255 _PROTOTYPE( static void put_userdata, (int user_proc,
256 vir_bytes user_addr, vir_bytes count, void *loc_addr) );
257 _PROTOTYPE( static void rtl8139_stop, (void) );
258 _PROTOTYPE( static void check_int_events, (void) );
259 _PROTOTYPE( static int do_hard_int, (void) );
260 _PROTOTYPE( static void rtl8139_dump, (message *m) );
261 #if 0
262 _PROTOTYPE( static void dump_phy, (re_t *rep) );
263 #endif
264 _PROTOTYPE( static int rl_handler, (re_t *rep) );
265 _PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) );
266
267 /* The message used in the main loop is made global, so that rl_watchdog_f()
268 * can change its message type to fake a HARD_INT message.
269 */
270 PRIVATE message m;
271 PRIVATE int int_event_check; /* set to TRUE if events arrived */
272
273 static char *progname;
274 extern int errno;
275
276 /*===========================================================================*
277 * main *
278 *===========================================================================*/
279 int main(int argc, char *argv[])
280 {
281 int fkeys, sfkeys;
282 int inet_proc_nr;
283 int i, r;
284 re_t *rep;
285 long v;
286
287 env_setargs(argc, argv);
288
289 v= 0;
290 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
291 eth_ign_proto= htons((u16_t) v);
292
293 /* Observe some function key for debug dumps. */
294 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
295 if ((r=fkey_map(&fkeys, &sfkeys)) != OK)
296 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
297
298 /* Claim buffer memory now under Minix, before MM takes it all. */
299 for (rep= &re_table[0]; rep < re_table+RE_PORT_NR; rep++)
300 rl_init_buf(rep);
301
302 /* Try to notify INET that we are present (again). If INET cannot
303 * be found, assume this is the first time we started and INET is
304 * not yet alive.
305 */
306 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
307 r = findproc("inet", &inet_proc_nr);
308 if (r == OK) notify(inet_proc_nr);
309
310
311 while (TRUE)
312 {
313 if ((r= receive(ANY, &m)) != OK)
314 panic("rtl8139","receive failed", r);
315
316 switch (m.m_type)
317 {
318 case DEV_PING: notify(m.m_source); continue;
319 case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
320 case DL_WRITE: rl_writev(&m, FALSE, FALSE); break;
321 #if 0
322 case DL_READ: do_vread(&m, FALSE); break;
323 #endif
324 case DL_READV: rl_readv(&m, FALSE, TRUE); break;
325 case DL_INIT: rl_init(&m); break;
326 case DL_GETSTAT: rl_getstat(&m); break;
327 case DL_GETNAME: rl_getname(&m); break;
328 #if 0
329 case DL_STOP: do_stop(&m); break;
330 #endif
331 case SYN_ALARM:
332 /* Under MINIX, synchronous alarms are used instead of
333 * watchdog functions. The approach is very different:
334 * MINIX VMD timeouts are handled within the kernel
335 * (the watchdog is executed by CLOCK), and notify()
336 * the driver in some cases.
337 * MINIX timeouts result in a SYN_ALARM message to the
338 * driver and thus are handled where they should be
339 * handled. Locally, watchdog functions are used again.
340 */
341 rl_watchdog_f(NULL);
342 break;
343 case HARD_INT:
344 do_hard_int();
345 if (int_event_check)
346 check_int_events();
347 break ;
348 case FKEY_PRESSED: rtl8139_dump(&m); break;
349 case SYS_SIG: {
350 sigset_t sigset = m.NOTIFY_ARG;
351 if (sigismember(&sigset, SIGKSTOP)) rtl8139_stop();
352 break;
353 }
354 default:
355 panic("rtl8139","illegal message", m.m_type);
356 }
357 }
358 }
359
360 static void check_int_events(void)
361 {
362 int i;
363 re_t *rep;
364 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
365 {
366 if (rep->re_mode != REM_ENABLED)
367 continue;
368 if (!rep->re_got_int)
369 continue;
370 rep->re_got_int= 0;
371 assert(rep->re_flags & REF_ENABLED);
372 rl_check_ints(rep);
373 }
374 }
375
376 /*===========================================================================*
377 * rtl8139_stop *
378 *===========================================================================*/
379 static void rtl8139_stop()
380 {
381 int i;
382 re_t *rep;
383
384 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
385 {
386 if (rep->re_mode != REM_ENABLED)
387 continue;
388 rl_outb(rep->re_base_port, RL_CR, 0);
389 }
390 sys_exit(0);
391 }
392
393 /*===========================================================================*
394 * rtl8139_dump *
395 *===========================================================================*/
396 static void rtl8139_dump(m)
397 message *m; /* pointer to request message */
398 {
399 re_t *rep;
400 int i;
401
402 printf("\n");
403 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
404 {
405 if (rep->re_mode == REM_DISABLED)
406 printf("Realtek RTL 8139 port %d is disabled\n", i);
407
408 if (rep->re_mode != REM_ENABLED)
409 continue;
410
411 printf("Realtek RTL 8139 statistics of port %d:\n", i);
412
413 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
414 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
415 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
416
417 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
418 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
419 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
420
421 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
422 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
423 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
424
425 printf("collision :%8ld\t", rep->re_stat.ets_collision);
426 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
427 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
428
429 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
430 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
431 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
432
433 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
434
435 printf("re_flags = 0x%x\n", rep->re_flags);
436
437 printf(
438 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
439 rl_inw(rep->re_base_port, RL_TSAD),
440 rl_inl(rep->re_base_port, RL_TSD0+0*4),
441 rl_inl(rep->re_base_port, RL_TSD0+1*4),
442 rl_inl(rep->re_base_port, RL_TSD0+2*4),
443 rl_inl(rep->re_base_port, RL_TSD0+3*4));
444 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
445 rep->re_tx_head, rep->re_tx_tail,
446 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
447 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
448 }
449 }
450
451 /*===========================================================================*
452 * do_init *
453 *===========================================================================*/
454 static void rl_init(mp)
455 message *mp;
456 {
457 static int first_time= 1;
458
459 int port;
460 re_t *rep;
461 message reply_mess;
462
463 if (first_time)
464 {
465 first_time= 0;
466 rl_pci_conf(); /* Configure PCI devices. */
467
468 tmra_inittimer(&rl_watchdog);
469 /* Use a synchronous alarm instead of a watchdog timer. */
470 sys_setalarm(HZ, 0);
471 }
472
473 port = mp->DL_PORT;
474 if (port < 0 || port >= RE_PORT_NR)
475 {
476 reply_mess.m_type= DL_INIT_REPLY;
477 reply_mess.m3_i1= ENXIO;
478 mess_reply(mp, &reply_mess);
479 return;
480 }
481 rep= &re_table[port];
482 if (rep->re_mode == REM_DISABLED)
483 {
484 /* This is the default, try to (re)locate the device. */
485 rl_conf_hw(rep);
486 if (rep->re_mode == REM_DISABLED)
487 {
488 /* Probe failed, or the device is configured off. */
489 reply_mess.m_type= DL_INIT_REPLY;
490 reply_mess.m3_i1= ENXIO;
491 mess_reply(mp, &reply_mess);
492 return;
493 }
494 if (rep->re_mode == REM_ENABLED)
495 rl_init_hw(rep);
496 #if VERBOSE /* load silently ... can always check status later */
497 rl_report_link(rep);
498 #endif
499 }
500
501 assert(rep->re_mode == REM_ENABLED);
502 assert(rep->re_flags & REF_ENABLED);
503
504 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
505
506 if (mp->DL_MODE & DL_PROMISC_REQ)
507 rep->re_flags |= REF_PROMISC;
508 if (mp->DL_MODE & DL_MULTI_REQ)
509 rep->re_flags |= REF_MULTI;
510 if (mp->DL_MODE & DL_BROAD_REQ)
511 rep->re_flags |= REF_BROAD;
512
513 rep->re_client = mp->m_source;
514 rl_rec_mode(rep);
515
516 reply_mess.m_type = DL_INIT_REPLY;
517 reply_mess.m3_i1 = mp->DL_PORT;
518 reply_mess.m3_i2 = RE_PORT_NR;
519 *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
520
521 mess_reply(mp, &reply_mess);
522 }
523
524 /*===========================================================================*
525 * rl_pci_conf *
526 *===========================================================================*/
527 static void rl_pci_conf()
528 {
529 int i, h;
530 re_t *rep;
531 static char envvar[] = RL_ENVVAR "#";
532 static char envfmt[] = "*:d.d.d";
533 static char val[128];
534 long v;
535
536 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
537 {
538 strcpy(rep->re_name, "rtl8139#0");
539 rep->re_name[8] += i;
540 rep->re_seen= FALSE;
541 envvar[sizeof(RL_ENVVAR)-1]= ''+i;
542 if (0 == env_get_param(envvar, val, sizeof(val)) &&
543 ! env_prefix(envvar, "pci")) {
544 env_panic(envvar);
545 }
546 v= 0;
547 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
548 rep->re_pcibus= v;
549 v= 0;
550 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
551 rep->re_pcidev= v;
552 v= 0;
553 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
554 rep->re_pcifunc= v;
555 }
556
557 pci_init();
558
559 for (h= 1; h >= 0; h--) {
560 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
561 {
562 if (((rep->re_pcibus | rep->re_pcidev |
563 rep->re_pcifunc) != 0) != h)
564 {
565 continue;
566 }
567 if (rl_probe(rep))
568 rep->re_seen= TRUE;
569 }
570 }
571 }
572
573 /*===========================================================================*
574 * rl_probe *
575 *===========================================================================*/
576 static int rl_probe(rep)
577 re_t *rep;
578 {
579 int i, r, devind, just_one;
580 u16_t vid, did;
581 u32_t bar;
582 u8_t ilr;
583 char *dname;
584
585 if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0)
586 {
587 /* Look for specific PCI device */
588 r= pci_find_dev(rep->re_pcibus, rep->re_pcidev,
589 rep->re_pcifunc, &devind);
590 if (r == 0)
591 {
592 printf("%s: no PCI found at %d.%d.%d\n",
593 rep->re_name, rep->re_pcibus,
594 rep->re_pcidev, rep->re_pcifunc);
595 return 0;
596 }
597 pci_ids(devind, &vid, &did);
598 just_one= TRUE;
599 }
600 else
601 {
602 r= pci_first_dev(&devind, &vid, &did);
603 if (r == 0)
604 return 0;
605 just_one= FALSE;
606 }
607
608 for(;;)
609 {
610 for (i= 0; pcitab[i].vid != 0; i++)
611 {
612 if (pcitab[i].vid != vid)
613 continue;
614 if (pcitab[i].did != did)
615 continue;
616 if (pcitab[i].checkclass)
617 {
618 panic("rtl_probe",
619 "class check not implemented", NO_NUM);
620 }
621 break;
622 }
623 if (pcitab[i].vid != 0)
624 break;
625
626 if (just_one)
627 {
628 printf(
629 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
630 rep->re_name, vid, did,
631 rep->re_pcibus,
632 rep->re_pcidev, rep->re_pcifunc);
633 return 0;
634 }
635
636 r= pci_next_dev(&devind, &vid, &did);
637 if (!r)
638 return 0;
639 }
640
641 #if VERBOSE /* stay silent at startup, can always get status later */
642 dname= pci_dev_name(vid, did);
643 if (!dname)
644 dname= "unknown device";
645 printf("%s: ", rep->re_name);
646 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
647 #endif
648 pci_reserve(devind);
649 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
650 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
651 if ((bar & 0x3ff) >= 0x100-32 || bar < 0x400)
652 panic("rtl_probe",
653 "base address is not properly configured", NO_NUM);
654 rep->re_base_port= bar;
655
656 ilr= pci_attr_r8(devind, PCI_ILR);
657 rep->re_irq= ilr;
658 if (debug)
659 {
660 printf("%s: using I/O address 0x%lx, IRQ %d\n",
661 rep->re_name, (unsigned long)bar, ilr);
662 }
663
664 return TRUE;
665 }
666
667 /*===========================================================================*
668 * rl_conf_hw *
669 *===========================================================================*/
670 static void rl_conf_hw(rep)
671 re_t *rep;
672 {
673 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
674
675 rep->re_mode= REM_DISABLED; /* Superfluous */
676
677 if (rep->re_seen)
678 {
679 /* PCI device is present */
680 rep->re_mode= REM_ENABLED;
681 }
682 if (rep->re_mode != REM_ENABLED)
683 return;
684
685 rep->re_flags= REF_EMPTY;
686 rep->re_link_up= -1; /* Unknown */
687 rep->re_got_int= 0;
688 rep->re_send_int= 0;
689 rep->re_report_link= 0;
690 rep->re_clear_rx= 0;
691 rep->re_need_reset= 0;
692 rep->re_tx_alive= 0;
693 rep->re_read_s= 0;
694 rep->re_tx_head= 0;
695 rep->re_tx_tail= 0;
696 rep->re_ertxth= RL_TSD_ERTXTH_8;
697 rep->re_stat= empty_stat;
698 }
699
700 /*===========================================================================*
701 * rl_init_buf *
702 *===========================================================================*/
703 static void rl_init_buf(rep)
704 re_t *rep;
705 {
706 size_t rx_bufsize, tx_bufsize, tot_bufsize;
707 phys_bytes buf;
708 char *mallocbuf;
709 static struct memory chunk;
710 int fd, s, i, off;
711
712 /* Allocate receive and transmit buffers */
713 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
714 if (tx_bufsize % 4)
715 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
716 rx_bufsize= RX_BUFSIZE;
717 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
718
719 /* Now try to allocate a kernel memory buffer. */
720 chunk.size = tot_bufsize;
721
722 #define BUF_ALIGNMENT (64*1024)
723
724 if(!(mallocbuf = malloc(BUF_ALIGNMENT + tot_bufsize))) {
725 panic("RTL8139","Couldn't allocate kernel buffer",i);
726 }
727
728 if(OK != (i = sys_umap(SELF, D, (vir_bytes) mallocbuf, tot_bufsize, &buf))) {
729 panic("RTL8139","Couldn't re-map malloced buffer",i);
730 }
731
732 /* click-align mallocced buffer. this is what we used to get
733 * from kmalloc() too.
734 */
735 if((off = buf % BUF_ALIGNMENT)) {
736 mallocbuf += BUF_ALIGNMENT - off;
737 buf += BUF_ALIGNMENT - off;
738 }
739
740 for (i= 0; i<N_TX_BUF; i++)
741 {
742 rep->re_tx[i].ret_buf= buf;
743 rep->re_tx[i].v_ret_buf= mallocbuf;
744 buf += tx_bufsize;
745 mallocbuf += tx_bufsize;
746 }
747 rep->re_rx_buf= buf;
748 rep->v_re_rx_buf= mallocbuf;
749 }
750
751 /*===========================================================================*
752 * rl_init_hw *
753 *===========================================================================*/
754 static void rl_init_hw(rep)
755 re_t *rep;
756 {
757 int s, i;
758
759 rep->re_flags = REF_EMPTY;
760 rep->re_flags |= REF_ENABLED;
761
762 /* Set the interrupt handler. The policy is to only send HARD_INT
763 * notifications. Don't reenable interrupts automatically. The id
764 * that is passed back is the interrupt line number.
765 */
766 rep->re_hook_id = rep->re_irq;
767 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
768 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
769
770 rl_reset_hw(rep);
771
772 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
773 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
774
775 #if VERBOSE /* stay silent during startup, can always get status later */
776 if (rep->re_mode) {
777 printf("%s: model %s\n", rep->re_name, rep->re_model);
778 } else
779 {
780 printf("%s: unknown model 0x%08x\n",
781 rep->re_name,
782 rl_inl(rep->re_base_port, RL_TCR) &
783 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
784 }
785 #endif
786
787 rl_confaddr(rep);
788 if (debug)
789 {
790 printf("%s: Ethernet address ", rep->re_name);
791 for (i= 0; i < 6; i++)
792 {
793 printf("%x%c", rep->re_address.ea_addr[i],
794 i < 5 ? ':' : '\n');
795 }
796 }
797 }
798
799 /*===========================================================================*
800 * rl_reset_hw *
801 *===========================================================================*/
802 static void rl_reset_hw(rep)
803 re_t *rep;
804 {
805 port_t port;
806 u32_t t;
807 phys_bytes bus_buf;
808 int i;
809 clock_t t0,t1;
810
811 port= rep->re_base_port;
812
813 #if 0
814 /* Reset the PHY */
815 rl_outb(port, RL_BMCR, MII_CTRL_RST);
816 getuptime(&t0);
817 do {
818 if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
819 break;
820 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
821 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
822 panic("rtl8139","reset PHY failed to complete", NO_NUM);
823 #endif
824
825 /* Reset the device */
826 rl_outb(port, RL_CR, RL_CR_RST);
827 getuptime(&t0);
828 do {
829 if (!(rl_inb(port, RL_CR) & RL_CR_RST))
830 break;
831 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
832 if (rl_inb(port, RL_CR) & RL_CR_RST)
833 panic("rtl8139","reset failed to complete", NO_NUM);
834
835 t= rl_inl(port, RL_TCR);
836 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
837 {
838 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
839 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
840 case RL_TCR_HWVER_RTL8139AG:
841 rep->re_model= "RTL8139A-G / RTL8139C";
842 break;
843 case RL_TCR_HWVER_RTL8139B:
844 rep->re_model= "RTL8139B / RTL8130";
845 break;
846 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
847 case RL_TCR_HWVER_RTL8100B:
848 rep->re_model= "RTL8100B/RTL8139D";
849 break;
850 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
851 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
852 default:
853 rep->re_model= NULL;
854 break;
855 }
856
857 #if 0
858 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
859 #endif
860
861 /* Intialize Rx */
862
863 /* Should init multicast mask */
864 #if 0
865 08-0f R/W MAR[0-7] multicast
866 #endif
867 bus_buf= vm_1phys2bus(rep->re_rx_buf);
868 rl_outl(port, RL_RBSTART, bus_buf);
869
870 /* Initialize Tx */
871 for (i= 0; i<N_TX_BUF; i++)
872 {
873 rep->re_tx[i].ret_busy= FALSE;
874 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
875 rl_outl(port, RL_TSAD0+i*4, bus_buf);
876 t= rl_inl(port, RL_TSD0+i*4);
877 assert(t & RL_TSD_OWN);
878 }
879
880 #if 0
881 dump_phy(rep);
882 #endif
883
884 t= rl_inw(port, RL_IMR);
885 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
886 RL_IMR_LENCHG));
887
888 t= rl_inw(port, RL_IMR);
889 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
890 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
891
892 t= rl_inw(port, RL_IMR);
893 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
894
895 t= rl_inb(port, RL_CR);
896 rl_outb(port, RL_CR, t | RL_CR_RE);
897
898 t= rl_inb(port, RL_CR);
899 rl_outb(port, RL_CR, t | RL_CR_TE);
900
901 rl_outl(port, RL_RCR, RX_BUFBITS);
902
903 t= rl_inl(port, RL_TCR);
904 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
905 }
906
907 /*===========================================================================*
908 * rl_confaddr *
909 *===========================================================================*/
910 static void rl_confaddr(rep)
911 re_t *rep;
912 {
913 static char eakey[]= RL_ENVVAR "#_EA";
914 static char eafmt[]= "x:x:x:x:x:x";
915
916 int i;
917 port_t port;
918 u32_t w;
919 long v;
920
921 /* User defined ethernet address? */
922 eakey[sizeof(RL_ENVVAR)-1]= '' + (rep-re_table);
923
924 port= rep->re_base_port;
925
926 for (i= 0; i < 6; i++)
927 {
928 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
929 break;
930 rep->re_address.ea_addr[i]= v;
931 }
932
933 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
934
935 /* Should update ethernet address in hardware */
936 if (i == 6)
937 {
938 port= rep->re_base_port;
939 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
940 w= 0;
941 for (i= 0; i<4; i++)
942 w |= (rep->re_address.ea_addr[i] << (i*8));
943 rl_outl(port, RL_IDR, w);
944 w= 0;
945 for (i= 4; i<6; i++)
946 w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
947 rl_outl(port, RL_IDR+4, w);
948 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
949 }
950
951 /* Get ethernet address */
952 for (i= 0; i<6; i++)
953 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
954 }
955
956 /*===========================================================================*
957 * rl_rec_mode *
958 *===========================================================================*/
959 static void rl_rec_mode(rep)
960 re_t *rep;
961 {
962 port_t port;
963 u32_t rcr;
964
965 port= rep->re_base_port;
966 rcr= rl_inl(port, RL_RCR);
967 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
968 if (rep->re_flags & REF_PROMISC)
969 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
970 if (rep->re_flags & REF_BROAD)
971 rcr |= RL_RCR_AB;
972 if (rep->re_flags & REF_MULTI)
973 rcr |= RL_RCR_AM;
974 rcr |= RL_RCR_APM;
975
976 rl_outl(port, RL_RCR, rcr);
977 }
978
979 /*===========================================================================*
980 * rl_readv *
981 *===========================================================================*/
982 static void rl_readv(mp, from_int, vectored)
983 message *mp;
984 int from_int;
985 int vectored;
986 {
987 int i, j, n, o, s, s1, dl_port, re_client, count, size;
988 port_t port;
989 unsigned amount, totlen, packlen;
990 phys_bytes src_phys, dst_phys, iov_src;
991 u16_t d_start, d_end;
992 u32_t l, rxstat = 0x12345678;
993 re_t *rep;
994 iovec_t *iovp;
995 int cps;
996
997 dl_port = mp->DL_PORT;
998 count = mp->DL_COUNT;
999 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1000 panic("rtl8139"," illegal port", dl_port);
1001 rep= &re_table[dl_port];
1002 re_client= mp->DL_PROC;
1003 rep->re_client= re_client;
1004
1005 if (rep->re_clear_rx)
1006 goto suspend; /* Buffer overflow */
1007
1008 assert(rep->re_mode == REM_ENABLED);
1009 assert(rep->re_flags & REF_ENABLED);
1010
1011 port= rep->re_base_port;
1012
1013 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1014 */
1015 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1016 {
1017 /* Receive buffer is empty, suspend */
1018 goto suspend;
1019 }
1020
1021 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1022 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1023
1024 if (d_start >= RX_BUFSIZE)
1025 {
1026 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1027 rl_inw(port, RL_CAPR));
1028 d_start %= RX_BUFSIZE;
1029 }
1030
1031 if (d_end > d_start)
1032 amount= d_end-d_start;
1033 else
1034 amount= d_end+RX_BUFSIZE - d_start;
1035
1036 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1037
1038 #if DEAD_CODE
1039 src_phys= rep->re_rx_buf + d_start;
1040 cps = sys_physcopy(
1041 NONE, PHYS_SEG, src_phys,
1042 SELF, D, (vir_bytes) &rxstat, sizeof(rxstat));
1043 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1044 #endif
1045
1046 if (rep->re_clear_rx)
1047 {
1048 #if 0
1049 printf("rl_readv: late buffer overflow\n");
1050 #endif
1051 goto suspend; /* Buffer overflow */
1052 }
1053
1054 /* Should convert from little endian to host byte order */
1055
1056 if (!(rxstat & RL_RXS_ROK))
1057 {
1058 printf("rxstat = 0x%08lx\n", rxstat);
1059 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1060 d_start, d_end, rxstat);
1061 panic("rtl8139","received packet not OK", NO_NUM);
1062 }
1063 totlen= (rxstat >> RL_RXS_LEN_S);
1064 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1065 {
1066 /* Someting went wrong */
1067 printf(
1068 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1069 totlen, rxstat, d_start);
1070 printf(
1071 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1072 d_start, d_end, totlen, rxstat);
1073 panic(NULL, NULL, NO_NUM);
1074 }
1075
1076 #if 0
1077 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1078 d_start, d_end, totlen, rxstat);
1079 #endif
1080
1081 if (totlen+4 > amount)
1082 {
1083 printf("rl_readv: packet not yet ready\n");
1084 goto suspend;
1085 }
1086
1087 /* Should subtract the CRC */
1088 packlen= totlen - ETH_CRC_SIZE;
1089
1090 if (vectored)
1091 {
1092 int iov_offset = 0;
1093 #if 0
1094 if ((cps = sys_umap(re_client, D, (vir_bytes) mp->DL_ADDR,
1095 count * sizeof(rep->re_iovec[0]), &iov_src)) != OK)
1096 printf("sys_umap failed: %d\n", cps);
1097 #endif
1098
1099 size= 0;
1100 o= d_start+4;
1101 src_phys= rep->re_rx_buf;
1102 for (i= 0; i<count; i += IOVEC_NR,
1103 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1104 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1105 {
1106 n= IOVEC_NR;
1107 if (i+n > count)
1108 n= count-i;
1109 #if 0
1110 cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
1111 n * sizeof(rep->re_iovec[0]));
1112 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1113 #else
1114 cps = sys_vircopy(re_client, D, (vir_bytes) mp->DL_ADDR + iov_offset,
1115 SELF, D, (vir_bytes) rep->re_iovec, n * sizeof(rep->re_iovec[0]));
1116 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1117 #endif
1118
1119 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1120 {
1121 s= iovp->iov_size;
1122 if (size + s > packlen)
1123 {
1124 assert(packlen > size);
1125 s= packlen-size;
1126 }
1127
1128 #if 0
1129 if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
1130 panic("rtl8139","umap_local failed\n", NO_NUM);
1131 #endif
1132
1133 if (o >= RX_BUFSIZE)
1134 {
1135 o -= RX_BUFSIZE;
1136 assert(o < RX_BUFSIZE);
1137 }
1138
1139 if (o+s > RX_BUFSIZE)
1140 {
1141 assert(o<RX_BUFSIZE);
1142 s1= RX_BUFSIZE-o;
1143
1144 #if 0
1145 cps = sys_abscopy(src_phys+o, dst_phys, s1);
1146 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1147 cps = sys_abscopy(src_phys, dst_phys+s1, s-s1);
1148 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1149 #else
1150 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
1151 re_client, D, iovp->iov_addr, s1);
1152 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1153 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf,
1154 re_client, D, iovp->iov_addr+s1, s-s1);
1155 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1156 #endif
1157 }
1158 else
1159 {
1160 #if 0
1161 cps = sys_abscopy(src_phys+o, dst_phys, s);
1162 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1163 #else
1164 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
1165 re_client, D, iovp->iov_addr, s);
1166 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1167 #endif
1168 }
1169
1170 size += s;
1171 if (size == packlen)
1172 break;
1173 o += s;
1174 }
1175 if (size == packlen)
1176 break;
1177 }
1178 if (size < packlen)
1179 {
1180 assert(0);
1181 }
1182 }
1183 else
1184 {
1185 assert(0);
1186 #if 0
1187 size= mp->DL_COUNT;
1188 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1189 panic("rtl8139","invalid packet size", size);
1190 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1191 panic("rtl8139","umap_local failed", NO_NUM);
1192
1193 p= rep->re_tx[tx_head].ret_buf;
1194 cps = sys_abscopy(phys_user, p, size);
1195 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1196 #endif
1197 }
1198
1199 if (rep->re_clear_rx)
1200 {
1201 /* For some reason the receiver FIFO is not stopped when
1202 * the buffer is full.
1203 */
1204 #if 0
1205 printf("rl_readv: later buffer overflow\n");
1206 #endif
1207 goto suspend; /* Buffer overflow */
1208 }
1209
1210 rep->re_stat.ets_packetR++;
1211 rep->re_read_s= packlen;
1212 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1213
1214 /* Avoid overflow in 16-bit computations */
1215 l= d_start;
1216 l += totlen+4;
1217 l= (l+3) & ~3; /* align */
1218 if (l >= RX_BUFSIZE)
1219 {
1220 l -= RX_BUFSIZE;
1221 assert(l < RX_BUFSIZE);
1222 }
1223 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1224
1225 if (!from_int)
1226 reply(rep, OK, FALSE);
1227
1228 return;
1229
1230 suspend:
1231 if (from_int)
1232 {
1233 assert(rep->re_flags & REF_READING);
1234
1235 /* No need to store any state */
1236 return;
1237 }
1238
1239 rep->re_rx_mess= *mp;
1240 assert(!(rep->re_flags & REF_READING));
1241 rep->re_flags |= REF_READING;
1242
1243 reply(rep, OK, FALSE);
1244 }
1245
1246 /*===========================================================================*
1247 * rl_writev *
1248 *===========================================================================*/
1249 static void rl_writev(mp, from_int, vectored)
1250 message *mp;
1251 int from_int;
1252 int vectored;
1253 {
1254 phys_bytes p, iov_src, phys_user;
1255 int i, j, n, s, port, count, size;
1256 int tx_head, re_client;
1257 re_t *rep;
1258 iovec_t *iovp;
1259 char *ret;
1260 int cps;
1261
1262 port = mp->DL_PORT;
1263 count = mp->DL_COUNT;
1264 if (port < 0 || port >= RE_PORT_NR)
1265 panic("rtl8139","illegal port", port);
1266 rep= &re_table[port];
1267 re_client= mp->DL_PROC;
1268 rep->re_client= re_client;
1269
1270 assert(rep->re_mode == REM_ENABLED);
1271 assert(rep->re_flags & REF_ENABLED);
1272
1273 if (from_int)
1274 {
1275 assert(rep->re_flags & REF_SEND_AVAIL);
1276 rep->re_flags &= ~REF_SEND_AVAIL;
1277 rep->re_send_int= FALSE;
1278 rep->re_tx_alive= TRUE;
1279 }
1280
1281 tx_head= rep->re_tx_head;
1282 if (rep->re_tx[tx_head].ret_busy)
1283 {
1284 assert(!(rep->re_flags & REF_SEND_AVAIL));
1285 rep->re_flags |= REF_SEND_AVAIL;
1286 if (rep->re_tx[tx_head].ret_busy)
1287 goto suspend;
1288
1289 /* Race condition, the interrupt handler may clear re_busy
1290 * before we got a chance to set REF_SEND_AVAIL. Checking
1291 * ret_busy twice should be sufficient.
1292 */
1293 #if 0
1294 printf("rl_writev: race detected\n");
1295 #endif
1296 rep->re_flags &= ~REF_SEND_AVAIL;
1297 rep->re_send_int= FALSE;
1298 }
1299
1300 assert(!(rep->re_flags & REF_SEND_AVAIL));
1301 assert(!(rep->re_flags & REF_PACK_SENT));
1302
1303 if (vectored)
1304 {
1305 int iov_offset = 0;
1306
1307 #if 0
1308 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR,
1309 count * sizeof(rep->re_iovec[0]), &iov_src))
1310 panic("rtl8139","umap_local failed", NO_NUM);
1311 #endif
1312
1313 size= 0;
1314 #if 0
1315 p= rep->re_tx[tx_head].ret_buf;
1316 #else
1317 ret = rep->re_tx[tx_head].v_ret_buf;
1318 #endif
1319 for (i= 0; i<count; i += IOVEC_NR,
1320 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1321 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1322 {
1323 n= IOVEC_NR;
1324 if (i+n > count)
1325 n= count-i;
1326 #if 0
1327 cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
1328 n * sizeof(rep->re_iovec[0]));
1329 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1330 #else
1331 cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
1332 SELF, D, (vir_bytes) rep->re_iovec,
1333 n * sizeof(rep->re_iovec[0]));
1334 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1335 #endif
1336
1337 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1338 {
1339 s= iovp->iov_size;
1340 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1341 {
1342 panic("rtl8139","invalid packet size",
1343 NO_NUM);
1344 }
1345
1346 if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
1347 panic("rtl8139","umap_local failed\n", NO_NUM);
1348
1349 #if 0
1350 cps = sys_abscopy(phys_user, p, s);
1351 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1352 #else
1353 cps = sys_vircopy(re_client, D, iovp->iov_addr,
1354 SELF, D, (vir_bytes) ret, s);
1355 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1356 #endif
1357 size += s;
1358 #if 0
1359 p += s;
1360 #endif
1361 ret += s;
1362 }
1363 }
1364 if (size < ETH_MIN_PACK_SIZE)
1365 panic("rtl8139","invalid packet size", size);
1366 }
1367 else
1368 {
1369 size= mp->DL_COUNT;
1370 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1371 panic("rtl8139","invalid packet size", size);
1372 #if 0
1373 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1374 panic("rtl8139","umap_local failed\n", NO_NUM);
1375
1376 p= rep->re_tx[tx_head].ret_buf;
1377 cps = sys_abscopy(phys_user, p, size);
1378 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1379 #else
1380 ret = rep->re_tx[tx_head].v_ret_buf;
1381 cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR,
1382 SELF, D, (vir_bytes) ret, size);
1383 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1384 #endif
1385 }
1386
1387 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1388 rep->re_ertxth | size);
1389 rep->re_tx[tx_head].ret_busy= TRUE;
1390
1391 if (++tx_head == N_TX_BUF)
1392 tx_head= 0;
1393 assert(tx_head < RL_N_TX);
1394 rep->re_tx_head= tx_head;
1395
1396 rep->re_flags |= REF_PACK_SENT;
1397
1398 /* If the interrupt handler called, don't send a reply. The reply
1399 * will be sent after all interrupts are handled.
1400 */
1401 if (from_int)
1402 return;
1403 reply(rep, OK, FALSE);
1404 return;
1405
1406 suspend:
1407 #if 0
1408 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1409 tx_head, rep->re_tx_tail,
1410 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1411 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1412 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1413 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1414 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1415 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1416 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1417 #endif
1418
1419 if (from_int)
1420 panic("rtl8139","should not be sending\n", NO_NUM);
1421
1422 rep->re_tx_mess= *mp;
1423 reply(rep, OK, FALSE);
1424 }
1425
1426 /*===========================================================================*
1427 * rl_check_ints *
1428 *===========================================================================*/
1429 static void rl_check_ints(rep)
1430 re_t *rep;
1431 {
1432 #if 0
1433 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
1434 31 R CRS Carrier Sense Lost
1435 30 R TABT Transmit Abort
1436 29 R OWC Out of Window Collision
1437 27-24 R NCC[3-0] Number of Collision Count
1438 23-22 reserved
1439 21-16 R/W ERTXH[5-0] Early Tx Threshold
1440 15 R TOK Transmit OK
1441 14 R TUN Transmit FIFO Underrun
1442 13 R/W OWN OWN
1443 12-0 R/W SIZE Descriptor Size
1444 3e-3f R/W ISR Interrupt Status Register
1445 6 R/W FOVW Fx FIFO Overflow Interrupt
1446 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
1447 3 R/W TER Transmit Error Interrupt
1448 2 R/W TOK Transmit OK Interrupt
1449 3e-3f R/W ISR Interrupt Status Register
1450 15 R/W SERR System Error Interrupt
1451 14 R/W TimeOut Time Out Interrupt
1452 13 R/W LenChg Cable Length Change Interrupt
1453 3e-3f R/W ISR Interrupt Status Register
1454 4 R/W RXOVW Rx Buffer Overflow Interrupt
1455 1 R/W RER Receive Error Interrupt
1456 0 R/W ROK Receive OK Interrupt
1457 4c-4f R/W MPC Missed Packet Counter
1458 60-61 R TSAD Transmit Status of All Descriptors
1459 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
1460 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
1461 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
1462 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
1463 6c-6d R DIS Disconnect Counter
1464 15-0 R DCNT Disconnect Counter
1465 6e-6f R FCSC False Carrier Sense Counter
1466 15-0 R FCSCNT False Carrier event counter
1467 72-73 R REC RX_ER Counter
1468 15-0 R RXERCNT Received packet counter
1469 #endif
1470
1471 int re_flags;
1472
1473 re_flags= rep->re_flags;
1474
1475 if ((re_flags & REF_READING) &&
1476 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1477 {
1478 if (rep->re_rx_mess.m_type == DL_READV)
1479 {
1480 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1481 TRUE /* vectored */);
1482 }
1483 else
1484 {
1485 assert(rep->re_rx_mess.m_type == DL_READ);
1486 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1487 FALSE /* !vectored */);
1488 }
1489 }
1490 if (rep->re_clear_rx)
1491 rl_clear_rx(rep);
1492
1493 if (rep->re_need_reset)
1494 rl_do_reset(rep);
1495
1496 if (rep->re_send_int)
1497 {
1498 if (rep->re_tx_mess.m_type == DL_WRITEV)
1499 {
1500 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1501 TRUE /* vectored */);
1502 }
1503 else
1504 {
1505 assert(rep->re_tx_mess.m_type == DL_WRITE);
1506 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1507 FALSE /* !vectored */);
1508 }
1509 }
1510
1511 if (rep->re_report_link)
1512 rl_report_link(rep);
1513
1514 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1515 reply(rep, OK, TRUE);
1516 }
1517
1518 /*===========================================================================*
1519 * rl_report_link *
1520 *===========================================================================*/
1521 static void rl_report_link(rep)
1522 re_t *rep;
1523 {
1524 port_t port;
1525 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
1526 u8_t msr;
1527 int f, link_up;
1528
1529 rep->re_report_link= FALSE;
1530 port= rep->re_base_port;
1531 msr= rl_inb(port, RL_MSR);
1532 link_up= !(msr & RL_MSR_LINKB);
1533 rep->re_link_up= link_up;
1534 if (!link_up)
1535 {
1536 printf("%s: link down\n", rep->re_name);
1537 return;
1538 }
1539
1540 mii_ctrl= rl_inw(port, RL_BMCR);
1541 mii_status= rl_inw(port, RL_BMSR);
1542 mii_ana= rl_inw(port, RL_ANAR);
1543 mii_anlpa= rl_inw(port, RL_ANLPAR);
1544 mii_ane= rl_inw(port, RL_ANER);
1545 mii_extstat= 0;
1546
1547 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1548 {
1549 printf("%s: PHY: ", rep->re_name);
1550 f= 1;
1551 if (mii_ctrl & MII_CTRL_LB)
1552 {
1553 printf("loopback mode");
1554 f= 0;
1555 }
1556 if (mii_ctrl & MII_CTRL_PD)
1557 {
1558 if (!f) printf(", ");
1559 f= 0;
1560 printf("powered down");
1561 }
1562 if (mii_ctrl & MII_CTRL_ISO)
1563 {
1564 if (!f) printf(", ");
1565 f= 0;
1566 printf("isolated");
1567 }
1568 printf("\n");
1569 return;
1570 }
1571 if (!(mii_ctrl & MII_CTRL_ANE))
1572 {
1573 printf("%s: manual config: ", rep->re_name);
1574 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1575 {
1576 case MII_CTRL_SP_10: printf("10 Mbps"); break;
1577 case MII_CTRL_SP_100: printf("100 Mbps"); break;
1578 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
1579 case MII_CTRL_SP_RES: printf("reserved speed"); break;
1580 }
1581 if (mii_ctrl & MII_CTRL_DM)
1582 printf(", full duplex");
1583 else
1584 printf(", half duplex");
1585 printf("\n");
1586 return;
1587 }
1588
1589 if (!debug) goto resspeed;
1590
1591 printf("%s: ", rep->re_name);
1592 mii_print_stat_speed(mii_status, mii_extstat);
1593 printf("\n");
1594
1595 if (!(mii_status & MII_STATUS_ANC))
1596 printf("%s: auto-negotiation not complete\n", rep->re_name);
1597 if (mii_status & MII_STATUS_RF)
1598 printf("%s: remote fault detected\n", rep->re_name);
1599 if (!(mii_status & MII_STATUS_ANA))
1600 {
1601 printf("%s: local PHY has no auto-negotiation ability\n",
1602 rep->re_name);
1603 }
1604 if (!(mii_status & MII_STATUS_LS))
1605 printf("%s: link down\n", rep->re_name);
1606 if (mii_status & MII_STATUS_JD)
1607 printf("%s: jabber condition detected\n", rep->re_name);
1608 if (!(mii_status & MII_STATUS_EC))
1609 {
1610 printf("%s: no extended register set\n", rep->re_name);
1611 goto resspeed;
1612 }
1613 if (!(mii_status & MII_STATUS_ANC))
1614 goto resspeed;
1615
1616 printf("%s: local cap.: ", rep->re_name);
1617 mii_print_techab(mii_ana);
1618 printf("\n");
1619
1620 if (mii_ane & MII_ANE_PDF)
1621 printf("%s: parallel detection fault\n", rep->re_name);
1622 if (!(mii_ane & MII_ANE_LPANA))
1623 {
1624 printf("%s: link-partner does not support auto-negotiation\n",
1625 rep->re_name);
1626 goto resspeed;
1627 }
1628
1629 printf("%s: remote cap.: ", rep->re_name);
1630 mii_print_techab(mii_anlpa);
1631 printf("\n");
1632
1633 resspeed:
1634 printf("%s: ", rep->re_name);
1635 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
1636 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
1637
1638 }
1639
1640 static void mii_print_techab(techab)
1641 u16_t techab;
1642 {
1643 int fs, ft;
1644 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
1645 {
1646 printf("strange selector 0x%x, value 0x%x",
1647 techab & MII_ANA_SEL_M,
1648 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
1649 return;
1650 }
1651 fs= 1;
1652 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
1653 {
1654 printf("100 Mbps: ");
1655 fs= 0;
1656 ft= 1;
1657 if (techab & MII_ANA_100T4)
1658 {
1659 printf("T4");
1660 ft= 0;
1661 }
1662 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
1663 {
1664 if (!ft)
1665 printf(", ");
1666 ft= 0;
1667 printf("TX-");
1668 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
1669 {
1670 case MII_ANA_100TXFD: printf("FD"); break;
1671 case MII_ANA_100TXHD: printf("HD"); break;
1672 default: printf("FD/HD"); break;
1673 }
1674 }
1675 }
1676 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
1677 {
1678 if (!fs)
1679 printf(", ");
1680 printf("10 Mbps: ");
1681 fs= 0;
1682 printf("T-");
1683 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
1684 {
1685 case MII_ANA_10TFD: printf("FD"); break;
1686 case MII_ANA_10THD: printf("HD"); break;
1687 default: printf("FD/HD"); break;
1688 }
1689 }
1690 if (techab & MII_ANA_PAUSE_SYM)
1691 {
1692 if (!fs)
1693 printf(", ");
1694 fs= 0;
1695 printf("pause(SYM)");
1696 }
1697 if (techab & MII_ANA_PAUSE_ASYM)
1698 {
1699 if (!fs)
1700 printf(", ");
1701 fs= 0;
1702 printf("pause(ASYM)");
1703 }
1704 if (techab & MII_ANA_TAF_RES)
1705 {
1706 if (!fs)
1707 printf(", ");
1708 fs= 0;
1709 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
1710 }
1711 }
1712
1713 static void mii_print_stat_speed(stat, extstat)
1714 u16_t stat;
1715 u16_t extstat;
1716 {
1717 int fs, ft;
1718 fs= 1;
1719 if (stat & MII_STATUS_EXT_STAT)
1720 {
1721 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1722 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1723 {
1724 printf("1000 Mbps: ");
1725 fs= 0;
1726 ft= 1;
1727 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1728 {
1729 ft= 0;
1730 printf("X-");
1731 switch(extstat &
1732 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1733 {
1734 case MII_ESTAT_1000XFD: printf("FD"); break;
1735 case MII_ESTAT_1000XHD: printf("HD"); break;
1736 default: printf("FD/HD"); break;
1737 }
1738 }
1739 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1740 {
1741 if (!ft)
1742 printf(", ");
1743 ft= 0;
1744 printf("T-");
1745 switch(extstat &
1746 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1747 {
1748 case MII_ESTAT_1000TFD: printf("FD"); break;
1749 case MII_ESTAT_1000THD: printf("HD"); break;
1750 default: printf("FD/HD"); break;
1751 }
1752 }
1753 }
1754 }
1755 if (stat & (MII_STATUS_100T4 |
1756 MII_STATUS_100XFD | MII_STATUS_100XHD |
1757 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1758 {
1759 if (!fs)
1760 printf(", ");
1761 fs= 0;
1762 printf("100 Mbps: ");
1763 ft= 1;
1764 if (stat & MII_STATUS_100T4)
1765 {
1766 printf("T4");
1767 ft= 0;
1768 }
1769 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1770 {
1771 if (!ft)
1772 printf(", ");
1773 ft= 0;
1774 printf("TX-");
1775 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1776 {
1777 case MII_STATUS_100XFD: printf("FD"); break;
1778 case MII_STATUS_100XHD: printf("HD"); break;
1779 default: printf("FD/HD"); break;
1780 }
1781 }
1782 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1783 {
1784 if (!ft)
1785 printf(", ");
1786 ft= 0;
1787 printf("T2-");
1788 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1789 {
1790 case MII_STATUS_100T2FD: printf("FD"); break;
1791 case MII_STATUS_100T2HD: printf("HD"); break;
1792 default: printf("FD/HD"); break;
1793 }
1794 }
1795 }
1796 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1797 {
1798 if (!fs)
1799 printf(", ");
1800 printf("10 Mbps: ");
1801 fs= 0;
1802 printf("T-");
1803 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1804 {
1805 case MII_STATUS_10FD: printf("FD"); break;
1806 case MII_STATUS_10HD: printf("HD"); break;
1807 default: printf("FD/HD"); break;
1808 }
1809 }
1810 }
1811
1812 /*===========================================================================*
1813 * rl_clear_rx *
1814 *===========================================================================*/
1815 static void rl_clear_rx(rep)
1816 re_t *rep;
1817 {
1818 port_t port;
1819 u8_t cr;
1820 int i;
1821 clock_t t0,t1;
1822
1823 rep->re_clear_rx= FALSE;
1824 port= rep->re_base_port;
1825
1826 /* Reset the receiver */
1827 cr= rl_inb(port, RL_CR);
1828 cr &= ~RL_CR_RE;
1829 rl_outb(port, RL_CR, cr);
1830 getuptime(&t0);
1831 do {
1832 if (!(rl_inb(port, RL_CR) & RL_CR_RE))
1833 break;
1834 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
1835 if (rl_inb(port, RL_CR) & RL_CR_RE)
1836 panic("rtl8139","cannot disable receiver", NO_NUM);
1837
1838 #if 0
1839 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1840 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1841 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1842 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1843 #endif
1844
1845 rl_outb(port, RL_CR, cr | RL_CR_RE);
1846
1847 rl_outl(port, RL_RCR, RX_BUFBITS);
1848
1849 rl_rec_mode(rep);
1850
1851 rep->re_stat.ets_missedP++;
1852 }
1853
1854 /*===========================================================================*
1855 * rl_do_reset *
1856 *===========================================================================*/
1857 static void rl_do_reset(rep)
1858 re_t *rep;
1859 {
1860 rep->re_need_reset= FALSE;
1861 rl_reset_hw(rep);
1862 rl_rec_mode(rep);
1863
1864 rep->re_tx_head= 0;
1865 if (rep->re_flags & REF_SEND_AVAIL)
1866 {
1867 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1868 rep->re_send_int= TRUE;
1869 }
1870 }
1871
1872 /*===========================================================================*
1873 * rl_getstat *
1874 *===========================================================================*/
1875 static void rl_getstat(mp)
1876 message *mp;
1877 {
1878 int port;
1879 eth_stat_t stats;
1880 re_t *rep;
1881
1882 port = mp->DL_PORT;
1883 if (port < 0 || port >= RE_PORT_NR)
1884 panic("rtl8139","illegal port", port);
1885 rep= &re_table[port];
1886 rep->re_client= mp->DL_PROC;
1887
1888 assert(rep->re_mode == REM_ENABLED);
1889 assert(rep->re_flags & REF_ENABLED);
1890
1891 stats= rep->re_stat;
1892
1893 put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
1894 (vir_bytes) sizeof(stats), &stats);
1895 reply(rep, OK, FALSE);
1896 }
1897
1898
1899 /*===========================================================================*
1900 * rl_getname *
1901 *===========================================================================*/
1902 static void rl_getname(mp)
1903 message *mp;
1904 {
1905 int r;
1906
1907 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
1908 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
1909 mp->m_type= DL_NAME_REPLY;
1910 r= send(mp->m_source, mp);
1911 if (r != OK)
1912 panic("RTL8139", "rl_getname: send failed: %d\n", r);
1913 }
1914
1915
1916 /*===========================================================================*
1917 * reply *
1918 *===========================================================================*/
1919 static void reply(rep, err, may_block)
1920 re_t *rep;
1921 int err;
1922 int may_block;
1923 {
1924 message reply;
1925 int status;
1926 int r;
1927 clock_t now;
1928
1929 status = 0;
1930 if (rep->re_flags & REF_PACK_SENT)
1931 status |= DL_PACK_SEND;
1932 if (rep->re_flags & REF_PACK_RECV)
1933 status |= DL_PACK_RECV;
1934
1935 reply.m_type = DL_TASK_REPLY;
1936 reply.DL_PORT = rep - re_table;
1937 reply.DL_PROC = rep->re_client;
1938 reply.DL_STAT = status | ((u32_t) err << 16);
1939 reply.DL_COUNT = rep->re_read_s;
1940 if (OK != (r = getuptime(&now)))
1941 panic("rtl8139","getuptime() failed:", r);
1942 reply.DL_CLCK = now;
1943
1944 r= send(rep->re_client, &reply);
1945
1946 if (r == ELOCKED && may_block)
1947 {
1948 #if 0
1949 printW(); printf("send locked\n");
1950 #endif
1951 return;
1952 }
1953
1954 if (r < 0) {
1955 printf("RTL8139 tried sending to %d, type %d\n", rep->re_client, reply.m_type);
1956 panic("rtl8139","send failed:", r);
1957 }
1958
1959 rep->re_read_s = 0;
1960 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
1961 }
1962
1963 /*===========================================================================*
1964 * mess_reply *
1965 *===========================================================================*/
1966 static void mess_reply(req, reply_mess)
1967 message *req;
1968 message *reply_mess;
1969 {
1970 if (send(req->m_source, reply_mess) != OK)
1971 panic("rtl8139","unable to mess_reply", NO_NUM);
1972 }
1973
1974 /*===========================================================================*
1975 * put_userdata *
1976 *===========================================================================*/
1977 static void put_userdata(user_proc, user_addr, count, loc_addr)
1978 int user_proc;
1979 vir_bytes user_addr;
1980 vir_bytes count;
1981 void *loc_addr;
1982 {
1983 int cps;
1984 cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
1985 if (cps != OK) printf("RTL8139: warning, scopy failed: %d\n", cps);
1986 }
1987
1988 #if 0
1989 static void dump_phy(rep)
1990 re_t *rep;
1991 {
1992 port_t port;
1993 u32_t t;
1994
1995 port= rep->re_base_port;
1996
1997 t= rl_inb(port, RL_MSR);
1998 printf("MSR: 0x%02lx\n", t);
1999 if (t & RL_MSR_SPEED_10)
2000 printf("\t10 Mbps\n");
2001 if (t & RL_MSR_LINKB)
2002 printf("\tLink failed\n");
2003
2004 t= rl_inb(port, RL_CONFIG1);
2005 printf("CONFIG1: 0x%02lx\n", t);
2006
2007 t= rl_inb(port, RL_CONFIG3);
2008 printf("CONFIG3: 0x%02lx\n", t);
2009
2010 t= rl_inb(port, RL_CONFIG4);
2011 printf("CONFIG4: 0x%02lx\n", t);
2012
2013 t= rl_inw(port, RL_BMCR);
2014 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
2015
2016 t= rl_inw(port, RL_BMSR);
2017 printf("BMSR:");
2018 if (t & MII_STATUS_100T4)
2019 printf(" 100Base-T4");
2020 if (t & MII_STATUS_100XFD)
2021 printf(" 100Base-X-FD");
2022 if (t & MII_STATUS_100XHD)
2023 printf(" 100Base-X-HD");
2024 if (t & MII_STATUS_10FD)
2025 printf(" 10Mbps-FD");
2026 if (t & MII_STATUS_10HD)
2027 printf(" 10Mbps-HD");
2028 if (t & MII_STATUS_100T2FD)
2029 printf(" 100Base-T2-FD");
2030 if (t & MII_STATUS_100T2HD)
2031 printf(" 100Base-T2-HD");
2032 if (t & MII_STATUS_EXT_STAT)
2033 printf(" Ext-stat");
2034 if (t & MII_STATUS_RES)
2035 printf(" res-0x%lx", t & MII_STATUS_RES);
2036 if (t & MII_STATUS_MFPS)
2037 printf(" MFPS");
2038 if (t & MII_STATUS_ANC)
2039 printf(" ANC");
2040 if (t & MII_STATUS_RF)
2041 printf(" remote-fault");
2042 if (t & MII_STATUS_ANA)
2043 printf(" ANA");
2044 if (t & MII_STATUS_LS)
2045 printf(" Link");
2046 if (t & MII_STATUS_JD)
2047 printf(" Jabber");
2048 if (t & MII_STATUS_EC)
2049 printf(" Extended-capability");
2050 printf("\n");
2051
2052 t= rl_inw(port, RL_ANAR);
2053 printf("ANAR (MII_ANA): 0x%04lx\n", t);
2054
2055 t= rl_inw(port, RL_ANLPAR);
2056 printf("ANLPAR: 0x%04lx\n", t);
2057
2058 t= rl_inw(port, RL_ANER);
2059 printf("ANER (MII_ANE): ");
2060 if (t & MII_ANE_RES)
2061 printf(" res-0x%lx", t & MII_ANE_RES);
2062 if (t & MII_ANE_PDF)
2063 printf(" Par-Detect-Fault");
2064 if (t & MII_ANE_LPNPA)
2065 printf(" LP-Next-Page-Able");
2066 if (t & MII_ANE_NPA)
2067 printf(" Loc-Next-Page-Able");
2068 if (t & MII_ANE_PR)
2069 printf(" Page-Received");
2070 if (t & MII_ANE_LPANA)
2071 printf(" LP-Auto-Neg-Able");
2072 printf("\n");
2073
2074 t= rl_inw(port, RL_NWAYTR);
2075 printf("NWAYTR: 0x%04lx\n", t);
2076 t= rl_inw(port, RL_CSCR);
2077 printf("CSCR: 0x%04lx\n", t);
2078
2079 t= rl_inb(port, RL_CONFIG5);
2080 printf("CONFIG5: 0x%02lx\n", t);
2081 }
2082 #endif
2083
2084 static int do_hard_int(void)
2085 {
2086 int i,s;
2087
2088 for (i=0; i < RE_PORT_NR; i ++) {
2089
2090 /* Run interrupt handler at driver level. */
2091 rl_handler( &re_table[i]);
2092
2093 /* Reenable interrupts for this hook. */
2094 if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK)
2095 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
2096 }
2097 }
2098
2099 /*===========================================================================*
2100 * rl_handler *
2101 *===========================================================================*/
2102 static int rl_handler(rep)
2103 re_t *rep;
2104 {
2105 int i, port, tx_head, tx_tail, link_up;
2106 u16_t isr, tsad;
2107 u32_t tsd, tcr, ertxth;
2108 #if 0
2109 u8_t cr;
2110 #endif
2111 clock_t t0,t1;
2112 int_event_check = FALSE; /* disable check by default */
2113
2114 port= rep->re_base_port;
2115
2116 /* Ack interrupt */
2117 isr= rl_inw(port, RL_ISR);
2118 rl_outw(port, RL_ISR, isr);
2119
2120 if (isr & RL_IMR_FOVW)
2121 {
2122 isr &= ~RL_IMR_FOVW;
2123 /* Should do anything? */
2124
2125 rep->re_stat.ets_fifoOver++;
2126 }
2127 if (isr & RL_IMR_PUN)
2128 {
2129 isr &= ~RL_IMR_PUN;
2130
2131 /* Either the link status changed or there was a TX fifo
2132 * underrun.
2133 */
2134 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
2135 if (link_up != rep->re_link_up)
2136 {
2137 rep->re_report_link= TRUE;
2138 rep->re_got_int= TRUE;
2139 int_event_check = TRUE;
2140 }
2141 }
2142 if (isr & RL_IMR_RXOVW)
2143 {
2144 isr &= ~RL_IMR_RXOVW;
2145
2146 /* Clear the receive buffer */
2147 rep->re_clear_rx= TRUE;
2148 rep->re_got_int= TRUE;
2149 int_event_check = TRUE;
2150 }
2151
2152 if (isr & (RL_ISR_RER | RL_ISR_ROK))
2153 {
2154 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
2155
2156 if (!rep->re_got_int && (rep->re_flags & REF_READING))
2157 {
2158 rep->re_got_int= TRUE;
2159 int_event_check = TRUE;
2160 }
2161 }
2162 #if 0
2163 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
2164 (rep->re_flags & REF_SEND_AVAIL) &&
2165 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
2166 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
2167
2168 {
2169 printf(
2170 "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2171 rep->re_tx_head, rep->re_tx_tail,
2172 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2173 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2174 printf(
2175 "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2176 rl_inw(port, RL_TSAD),
2177 rl_inl(port, RL_TSD0+0*4),
2178 rl_inl(port, RL_TSD0+1*4),
2179 rl_inl(port, RL_TSD0+2*4),
2180 rl_inl(port, RL_TSD0+3*4));
2181 }
2182 #endif
2183 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
2184 {
2185 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
2186
2187 tsad= rl_inw(port, RL_TSAD);
2188 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
2189 RL_TSAD_TABT2|RL_TSAD_TABT3))
2190 {
2191 #if 0
2192 /* Do we need a watch dog? */
2193 /* Just reset the whole chip */
2194 rep->re_need_reset= TRUE;
2195 rep->re_got_int= TRUE;
2196 int_event_check = TRUE;
2197 #elif 0
2198 /* Reset transmitter */
2199 rep->re_stat.ets_transAb++;
2200
2201 cr= rl_inb(port, RL_CR);
2202 cr &= ~RL_CR_TE;
2203 rl_outb(port, RL_CR, cr);
2204 getuptime(&t0);
2205 do {
2206 if (!(rl_inb(port, RL_CR) & RL_CR_TE))
2207 break;
2208 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
2209 if (rl_inb(port, RL_CR) & RL_CR_TE)
2210 {
2211 panic("rtl8139","cannot disable transmitter",
2212 NO_NUM);
2213 }
2214 rl_outb(port, RL_CR, cr | RL_CR_TE);
2215
2216 tcr= rl_inl(port, RL_TCR);
2217 rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
2218
2219 printf("rl_handler: reset after abort\n");
2220
2221 if (rep->re_flags & REF_SEND_AVAIL)
2222 {
2223 printf("rl_handler: REF_SEND_AVAIL\n");
2224 rep->re_send_int= TRUE;
2225 rep->re_got_int= TRUE;
2226 int_event_check = TRUE;
2227 }
2228 for (i= 0; i< N_TX_BUF; i++)
2229 rep->re_tx[i].ret_busy= FALSE;
2230 rep->re_tx_head= 0;
2231 #else
2232 printf("rl_handler, TABT, tasd = 0x%04x\n",
2233 tsad);
2234
2235 /* Find the aborted transmit request */
2236 for (i= 0; i< N_TX_BUF; i++)
2237 {
2238 tsd= rl_inl(port, RL_TSD0+i*4);
2239 if (tsd & RL_TSD_TABT)
2240 break;
2241 }
2242 if (i >= N_TX_BUF)
2243 {
2244 printf(
2245 "rl_handler: can't find aborted TX req.\n");
2246 }
2247 else
2248 {
2249 printf("TSD%d = 0x%04lx\n", i, tsd);
2250
2251 /* Set head and tail to this buffer */
2252 rep->re_tx_head= rep->re_tx_tail= i;
2253 }
2254
2255 /* Aborted transmission, just kick the device
2256 * and be done with it.
2257 */
2258 rep->re_stat.ets_transAb++;
2259 tcr= rl_inl(port, RL_TCR);
2260 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2261 #endif
2262 }
2263
2264 /* Transmit completed */
2265 tx_head= rep->re_tx_head;
2266 tx_tail= rep->re_tx_tail;
2267 for (i= 0; i< 2*N_TX_BUF; i++)
2268 {
2269 if (!rep->re_tx[tx_tail].ret_busy)
2270 {
2271 /* Strange, this buffer is not in-use.
2272 * Increment tx_tail until tx_head is
2273 * reached (or until we find a buffer that
2274 * is in-use.
2275 */
2276 if (tx_tail == tx_head)
2277 break;
2278 if (++tx_tail >= N_TX_BUF)
2279 tx_tail= 0;
2280 assert(tx_tail < RL_N_TX);
2281 rep->re_tx_tail= tx_tail;
2282 continue;
2283 }
2284 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
2285 if (!(tsd & RL_TSD_OWN))
2286 {
2287 /* Buffer is not yet ready */
2288 break;
2289 }
2290
2291 /* Should collect statistics */
2292 if (tsd & RL_TSD_CRS)
2293 rep->re_stat.ets_carrSense++;
2294 if (tsd & RL_TSD_TABT)
2295 {
2296 printf("rl_handler, TABT, TSD%d = 0x%04lx\n",
2297 tx_tail, tsd);
2298 assert(0); /* CLRABT is not all that
2299 * effective, why not?
2300 */
2301 rep->re_stat.ets_transAb++;
2302 tcr= rl_inl(port, RL_TCR);
2303 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2304 }
2305 if (tsd & RL_TSD_OWC)
2306 rep->re_stat.ets_OWC++;
2307 if (tsd & RL_TSD_CDH)
2308 rep->re_stat.ets_CDheartbeat++;
2309
2310 /* What about collisions? */
2311 if (tsd & RL_TSD_TOK)
2312 rep->re_stat.ets_packetT++;
2313 else
2314 rep->re_stat.ets_sendErr++;
2315 if (tsd & RL_TSD_TUN)
2316 {
2317 rep->re_stat.ets_fifoUnder++;
2318
2319 /* Increase ERTXTH */
2320 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
2321 ertxth &= RL_TSD_ERTXTH_M;
2322 if (debug && ertxth > rep->re_ertxth)
2323 {
2324 printf("%s: new ertxth: %ld bytes\n",
2325 rep->re_name,
2326 (ertxth >> RL_TSD_ERTXTH_S) *
2327 32);
2328 rep->re_ertxth= ertxth;
2329 }
2330 }
2331 rep->re_tx[tx_tail].ret_busy= FALSE;
2332
2333 #if 0
2334 if (rep->re_flags & REF_SEND_AVAIL)
2335 {
2336 printf("TSD%d: %08lx\n", tx_tail, tsd);
2337 printf(
2338 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
2339 tx_head, tx_tail,
2340 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2341 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2342 }
2343 #endif
2344
2345 if (++tx_tail >= N_TX_BUF)
2346 tx_tail= 0;
2347 assert(tx_tail < RL_N_TX);
2348 rep->re_tx_tail= tx_tail;
2349
2350 if (rep->re_flags & REF_SEND_AVAIL)
2351 {
2352 #if 0
2353 printf("rl_handler: REF_SEND_AVAIL\n");
2354 #endif
2355 rep->re_send_int= TRUE;
2356 if (!rep->re_got_int)
2357 {
2358 rep->re_got_int= TRUE;
2359 int_event_check = TRUE;
2360 }
2361 }
2362 }
2363 assert(i < 2*N_TX_BUF);
2364 }
2365 if (isr)
2366 {
2367 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
2368 isr);
2369 }
2370
2371 return 1;
2372 }
2373
2374 /*===========================================================================*
2375 * rl_watchdog_f *
2376 *===========================================================================*/
2377 static void rl_watchdog_f(tp)
2378 timer_t *tp;
2379 {
2380 int i;
2381 re_t *rep;
2382 /* Use a synchronous alarm instead of a watchdog timer. */
2383 sys_setalarm(HZ, 0);
2384
2385 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
2386 {
2387 if (rep->re_mode != REM_ENABLED)
2388 continue;
2389 if (!(rep->re_flags & REF_SEND_AVAIL))
2390 {
2391 /* Assume that an idle system is alive */
2392 rep->re_tx_alive= TRUE;
2393 continue;
2394 }
2395 if (rep->re_tx_alive)
2396 {
2397 rep->re_tx_alive= FALSE;
2398 continue;
2399 }
2400 printf("rl_watchdog_f: resetting port %d\n", i);
2401 printf(
2402 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2403 rl_inw(rep->re_base_port, RL_TSAD),
2404 rl_inl(rep->re_base_port, RL_TSD0+0*4),
2405 rl_inl(rep->re_base_port, RL_TSD0+1*4),
2406 rl_inl(rep->re_base_port, RL_TSD0+2*4),
2407 rl_inl(rep->re_base_port, RL_TSD0+3*4));
2408 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2409 rep->re_tx_head, rep->re_tx_tail,
2410 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2411 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2412 rep->re_need_reset= TRUE;
2413 rep->re_got_int= TRUE;
2414
2415 check_int_events();
2416 }
2417 }
2418
2419 #if 0
2420
2421 _PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
2422 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
2423 _PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
2424 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );
2425 _PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
2426
2427 static void rtl_init(dep)
2428 dpeth_t *dep;
2429 {
2430 u8_t reg_a, reg_b, cr, config0, config2, config3;
2431 int i;
2432 char val[128];
2433
2434 printf("rtl_init called\n");
2435 ne_init(dep);
2436
2437 /* ID */
2438 outb_reg0(dep, DP_CR, CR_PS_P0);
2439 reg_a = inb_reg0(dep, DP_DUM1);
2440 reg_b = inb_reg0(dep, DP_DUM2);
2441
2442 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
2443
2444 outb_reg0(dep, DP_CR, CR_PS_P3);
2445 config0 = inb_reg3(dep, 3);
2446 config2 = inb_reg3(dep, 5);
2447 config3 = inb_reg3(dep, 6);
2448 outb_reg0(dep, DP_CR, CR_PS_P0);
2449
2450 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
2451 config0, config2, config3);
2452
2453 if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
2454 {
2455 printf("rtl_init: setting full-duplex mode\n");
2456 outb_reg0(dep, DP_CR, CR_PS_P3);
2457
2458 cr= inb_reg3(dep, 1);
2459 outb_reg3(dep, 1, cr | 0xc0);
2460
2461 outb_reg3(dep, 6, config3 | 0x40);
2462 config3 = inb_reg3(dep, 6);
2463
2464 config2= inb_reg3(dep, 5);
2465 outb_reg3(dep, 5, config2 | 0x20);
2466 config2= inb_reg3(dep, 5);
2467
2468 outb_reg3(dep, 1, cr);
2469
2470 outb_reg0(dep, DP_CR, CR_PS_P0);
2471
2472 printf("rtl_init: config 2 = %x\n", config2);
2473 printf("rtl_init: config 3 = %x\n", config3);
2474 }
2475
2476 for (i= 0; i<64; i++)
2477 printf("%x ", get_ee_word(dep, i));
2478 printf("\n");
2479
2480 if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
2481 {
2482 ee_wen(dep);
2483
2484 set_ee_word(dep, 0x78/2, 0x10ec);
2485 set_ee_word(dep, 0x7A/2, 0x8029);
2486 set_ee_word(dep, 0x7C/2, 0x10ec);
2487 set_ee_word(dep, 0x7E/2, 0x8029);
2488
2489 ee_wds(dep);
2490
2491 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
2492 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
2493 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
2494 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
2495 }
2496
2497 if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
2498 {
2499 ee_wen(dep);
2500
2501 set_ee_word(dep, 0x76/2, 0x8029);
2502
2503 ee_wds(dep);
2504
2505 assert(get_ee_word(dep, 0x76/2) == 0x8029);
2506 }
2507 }
2508
2509 static u16_t get_ee_word(dep, a)
2510 dpeth_t *dep;
2511 int a;
2512 {
2513 int b, i, cmd;
2514 u16_t w;
2515
2516 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2517
2518 /* Switch to 9346 mode and enable CS */
2519 outb_reg3(dep, 1, 0x80 | 0x8);
2520
2521 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
2522 for (i= 8; i >= 0; i--)
2523 {
2524 b= (cmd & (1 << i));
2525 b= (b ? 2 : 0);
2526
2527 /* Cmd goes out on the rising edge of the clock */
2528 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2529 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2530 }
2531 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2532
2533 w= 0;
2534 for (i= 0; i<16; i++)
2535 {
2536 w <<= 1;
2537
2538 /* Data is shifted out on the rising edge. Read at the
2539 * falling edge.
2540 */
2541 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
2542 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2543 b= inb_reg3(dep, 1);
2544 w |= (b & 1);
2545 }
2546
2547 outb_reg3(dep, 1, 0x80); /* drop CS */
2548 outb_reg3(dep, 1, 0x00); /* back to normal */
2549 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2550
2551 return w;
2552 }
2553
2554 static void ee_wen(dep)
2555 dpeth_t *dep;
2556 {
2557 int b, i, cmd;
2558 u16_t w;
2559
2560 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2561
2562 /* Switch to 9346 mode and enable CS */
2563 outb_reg3(dep, 1, 0x80 | 0x8);
2564
2565 cmd= 0x130; /* 1 0 0 1 1 x x x x */
2566 for (i= 8; i >= 0; i--)
2567 {
2568 b= (cmd & (1 << i));
2569 b= (b ? 2 : 0);
2570
2571 /* Cmd goes out on the rising edge of the clock */
2572 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2573 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2574 }
2575 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2576 outb_reg3(dep, 1, 0x80); /* Drop CS */
2577 /* micro_delay(1); */ /* Is this required? */
2578 }
2579
2580 static void set_ee_word(dep, a, w)
2581 dpeth_t *dep;
2582 int a;
2583 u16_t w;
2584 {
2585 int b, i, cmd;
2586 clock_t t0, t1;
2587
2588 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2589
2590 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
2591 for (i= 8; i >= 0; i--)
2592 {
2593 b= (cmd & (1 << i));
2594 b= (b ? 2 : 0);
2595
2596 /* Cmd goes out on the rising edge of the clock */
2597 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2598 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2599 }
2600 for (i= 15; i >= 0; i--)
2601 {
2602 b= (w & (1 << i));
2603 b= (b ? 2 : 0);
2604
2605 /* Cmd goes out on the rising edge of the clock */
2606 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2607 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2608 }
2609 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
2610 outb_reg3(dep, 1, 0x80); /* Drop CS */
2611 /* micro_delay(1); */ /* Is this required? */
2612 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2613 getuptime(&t0);
2614 do {
2615 if (inb_reg3(dep, 1) & 1)
2616 break;
2617 } while (getuptime(&t1) == OK && (t1 == t0));
2618 if (!(inb_reg3(dep, 1) & 1))
2619 panic("set_ee_word","device remains busy", NO_NUM);
2620 }
2621
2622 static void ee_wds(dep)
2623 dpeth_t *dep;
2624 {
2625 int b, i, cmd;
2626 u16_t w;
2627
2628 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2629
2630 /* Switch to 9346 mode and enable CS */
2631 outb_reg3(dep, 1, 0x80 | 0x8);
2632
2633 cmd= 0x100; /* 1 0 0 0 0 x x x x */
2634 for (i= 8; i >= 0; i--)
2635 {
2636 b= (cmd & (1 << i));
2637 b= (b ? 2 : 0);
2638
2639 /* Cmd goes out on the rising edge of the clock */
2640 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2641 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2642 }
2643 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2644 outb_reg3(dep, 1, 0x80); /* Drop CS */
2645 outb_reg3(dep, 1, 0x00); /* back to normal */
2646 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2647 }
2648 #endif
2649
2650 /*
2651 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $
2652 */
Cache object: 510f338e63b3b6a52bb1a475969803e0
|