add/re-enable at_wini debug output
[minix3.git] / drivers / rtl8139 / rtl8139.c
blobf2571de8037dadbdc82a6ecc04deddaf15b0c64a
1 /*
2 * rtl8139.c
4 * This file contains a ethernet device driver for Realtek rtl8139 based
5 * ethernet cards.
7 * The valid messages and their parameters are:
9 * m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR DL_GRANT
10 * |------------+----------+---------+----------+---------+---------+---------|
11 * | HARDINT | | | | | | |
12 * |------------|----------|---------|----------|---------|---------|---------|
13 * | DL_WRITE | port nr | proc nr | count | mode | address | |
14 * |------------|----------|---------|----------|---------|---------|---------|
15 * | DL_WRITEV | port nr | proc nr | count | mode | address | |
16 * |------------|----------|---------|----------|---------|---------|---------|
17 * | DL_WRITEV_S| port nr | proc nr | count | mode | | grant |
18 * |------------|----------|---------|----------|---------|---------|---------|
19 * | DL_READ | port nr | proc nr | count | | address | |
20 * |------------|----------|---------|----------|---------|---------|---------|
21 * | DL_READV | port nr | proc nr | count | | address | |
22 * |------------|----------|---------|----------|---------|---------|---------|
23 * | DL_READV_S | port nr | proc nr | count | | | grant |
24 * |------------|----------|---------|----------|---------|---------|---------|
25 * | DL_CONF | port nr | proc nr | | mode | address | |
26 * |------------|----------|---------|----------|---------|---------|---------|
27 * | DL_GETSTAT | port nr | proc nr | | | address | |
28 * |------------|----------|---------|----------|---------|---------|---------|
29 * |DL_GETSTAT_S| port nr | proc nr | | | | grant |
30 * |------------|----------|---------|----------|---------|---------|---------|
31 * | DL_STOP | port_nr | | | | | |
32 * |------------|----------|---------|----------|---------|---------|---------|
34 * The messages sent are:
36 * m-type DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
37 * |------------|----------|---------|----------|---------|---------|
38 * |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
39 * |------------|----------|---------|----------|---------|---------|
41 * m_type m3_i1 m3_i2 m3_ca1
42 * |------------+---------+-----------+---------------|
43 * |DL_CONF_REPL| port nr | last port | ethernet addr |
44 * |------------|---------|-----------|---------------|
46 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
47 * Changes:
48 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
49 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
53 #include "../drivers.h"
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <stddef.h>
59 #include <minix/com.h>
60 #include <minix/keymap.h>
61 #include <minix/syslib.h>
62 #include <minix/type.h>
63 #include <minix/sysutil.h>
64 #include <timers.h>
65 #include <net/hton.h>
66 #include <net/gen/ether.h>
67 #include <net/gen/eth_io.h>
68 #include <ibm/pci.h>
70 #include <sys/types.h>
71 #include <fcntl.h>
72 #include <assert.h>
73 #include <unistd.h>
74 #include <sys/ioc_memory.h>
75 #include "../../kernel/const.h"
76 #include "../../kernel/config.h"
77 #include "../../kernel/type.h"
79 #define tmra_ut timer_t
80 #define tmra_inittimer(tp) tmr_inittimer(tp)
81 #define Proc_number(p) proc_number(p)
82 #define debug 0
83 #define printW() ((void)0)
84 #define vm_1phys2bus(p) (p)
86 #define VERBOSE 1 /* display message during init */
88 #include "rtl8139.h"
90 #define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE
91 #define RX_BUFBITS RL_RCR_RBLEN_64K
92 #define N_TX_BUF RL_N_TX
94 #define RE_PORT_NR 1 /* Minix */
96 /* I/O vectors are handled IOVEC_NR entries at a time. */
97 #define IOVEC_NR 16
99 /* Configuration */
100 #define RL_ENVVAR "RTLETH"
102 PRIVATE struct pcitab
104 u16_t vid;
105 u16_t did;
106 int checkclass;
107 } pcitab[]=
109 { 0x10ec, 0x8139, 0 }, /* Realtek RTL8139 */
111 /* Alternative IDs */
112 { 0x02ac, 0x1012, 0 }, /* SpeedStream 1012 PCMCIA 10/100 */
113 { 0x1065, 0x8139, 0 }, /* Texas Microsystems 8139C Network Card */
114 { 0x1113, 0x1211, 0 }, /* Accton MPX5030 or SMC1211TX EZCard 10/100 */
115 { 0x1186, 0x1300, 0 }, /* D-Link DFE530TX+/DFE538TX */
116 { 0x1186, 0x1340, 0 }, /* D-Link DFE690TXD */
117 { 0x11db, 0x1234, 0 }, /* Sega Dreamcast HIT-400 */
118 { 0x1259, 0xa117, 0 }, /* Allied Telesyn 8139 */
119 { 0x1259, 0xa11e, 0 }, /* Allied Telesyn 8139 */
120 { 0x126c, 0x1211, 0 }, /* Northern Telecom 10/100BaseTX*/
121 { 0x13d1, 0xab06, 0 }, /* AboCom FE2000VX */
122 { 0x1432, 0x9130, 0 }, /* Edimax Computer Co. RTL81xx */
123 { 0x14ea, 0xab06, 0 }, /* Planex FNW-3603-TX */
124 { 0x14ea, 0xab07, 0 }, /* Planex FNW-3800-TX */
125 { 0x1500, 0x1360, 0 }, /* Delta Electronics RealTek Ethernet */
126 { 0x1743, 0x8139, 0 }, /* Peppercon AG 8139 ROL/F-100 */
127 { 0x4033, 0x1360, 0 }, /* Addtron Technology 8139 */
129 { 0x0000, 0x0000, 0 }
132 typedef struct re
134 port_t re_base_port;
135 int re_irq;
136 int re_mode;
137 int re_flags;
138 int re_client;
139 int re_link_up;
140 int re_got_int;
141 int re_send_int;
142 int re_report_link;
143 int re_clear_rx;
144 int re_need_reset;
145 int re_tx_alive;
146 char *re_model;
148 /* Rx */
149 phys_bytes re_rx_buf;
150 char *v_re_rx_buf;
151 vir_bytes re_read_s;
153 /* Tx */
154 int re_tx_head;
155 int re_tx_tail;
156 struct
158 int ret_busy;
159 phys_bytes ret_buf;
160 char * v_ret_buf;
161 } re_tx[N_TX_BUF];
162 u32_t re_ertxth; /* Early Tx Threshold */
164 /* PCI related */
165 int re_seen; /* TRUE iff device available */
166 u8_t re_pcibus;
167 u8_t re_pcidev;
168 u8_t re_pcifunc;
170 /* 'large' items */
171 int re_hook_id; /* IRQ hook id at kernel */
172 eth_stat_t re_stat;
173 ether_addr_t re_address;
174 message re_rx_mess;
175 message re_tx_mess;
176 char re_name[sizeof("rtl8139#n")];
177 iovec_t re_iovec[IOVEC_NR];
178 iovec_s_t re_iovec_s[IOVEC_NR];
180 re_t;
182 #define REM_DISABLED 0x0
183 #define REM_ENABLED 0x1
185 #define REF_PACK_SENT 0x001
186 #define REF_PACK_RECV 0x002
187 #define REF_SEND_AVAIL 0x004
188 #define REF_READING 0x010
189 #define REF_EMPTY 0x000
190 #define REF_PROMISC 0x040
191 #define REF_MULTI 0x080
192 #define REF_BROAD 0x100
193 #define REF_ENABLED 0x200
195 static re_t re_table[RE_PORT_NR];
197 static u16_t eth_ign_proto;
198 static tmra_ut rl_watchdog;
200 FORWARD _PROTOTYPE( unsigned my_inb, (U16_t port) );
201 FORWARD _PROTOTYPE( unsigned my_inw, (U16_t port) );
202 FORWARD _PROTOTYPE( unsigned my_inl, (U16_t port) );
203 static unsigned my_inb(U16_t port) {
204 u32_t value;
205 int s;
206 if ((s=sys_inb(port, &value)) !=OK)
207 printf("RTL8139: warning, sys_inb failed: %d\n", s);
208 return value;
210 static unsigned my_inw(U16_t port) {
211 u32_t value;
212 int s;
213 if ((s=sys_inw(port, &value)) !=OK)
214 printf("RTL8139: warning, sys_inw failed: %d\n", s);
215 return value;
217 static unsigned my_inl(U16_t port) {
218 U32_t value;
219 int s;
220 if ((s=sys_inl(port, &value)) !=OK)
221 printf("RTL8139: warning, sys_inl failed: %d\n", s);
222 return value;
224 #define rl_inb(port, offset) (my_inb((port) + (offset)))
225 #define rl_inw(port, offset) (my_inw((port) + (offset)))
226 #define rl_inl(port, offset) (my_inl((port) + (offset)))
228 FORWARD _PROTOTYPE( void my_outb, (U16_t port, U8_t value) );
229 FORWARD _PROTOTYPE( void my_outw, (U16_t port, U16_t value) );
230 FORWARD _PROTOTYPE( void my_outl, (U16_t port, U32_t value) );
231 static void my_outb(U16_t port, U8_t value) {
232 int s;
233 if ((s=sys_outb(port, value)) !=OK)
234 printf("RTL8139: warning, sys_outb failed: %d\n", s);
236 static void my_outw(U16_t port, U16_t value) {
237 int s;
238 if ((s=sys_outw(port, value)) !=OK)
239 printf("RTL8139: warning, sys_outw failed: %d\n", s);
241 static void my_outl(U16_t port, U32_t value) {
242 int s;
243 if ((s=sys_outl(port, value)) !=OK)
244 printf("RTL8139: warning, sys_outl failed: %d\n", s);
246 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
247 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
248 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
250 _PROTOTYPE( static void sig_handler, (void) );
251 _PROTOTYPE( static void rl_init, (message *mp) );
252 _PROTOTYPE( static void rl_pci_conf, (void) );
253 _PROTOTYPE( static int rl_probe, (re_t *rep) );
254 _PROTOTYPE( static void rl_conf_hw, (re_t *rep) );
255 _PROTOTYPE( static void rl_init_buf, (re_t *rep) );
256 _PROTOTYPE( static void rl_init_hw, (re_t *rep) );
257 _PROTOTYPE( static void rl_reset_hw, (re_t *rep) );
258 _PROTOTYPE( static void rl_confaddr, (re_t *rep) );
259 _PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
260 _PROTOTYPE( static void rl_readv, (message *mp, int from_int,
261 int vectored) );
262 _PROTOTYPE( static void rl_readv_s, (message *mp, int from_int) );
263 _PROTOTYPE( static void rl_writev, (message *mp, int from_int,
264 int vectored) );
265 _PROTOTYPE( static void rl_writev_s, (message *mp, int from_int) );
266 _PROTOTYPE( static void rl_check_ints, (re_t *rep) );
267 _PROTOTYPE( static void rl_report_link, (re_t *rep) );
268 _PROTOTYPE( static void mii_print_techab, (U16_t techab) );
269 _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
270 U16_t extstat) );
271 _PROTOTYPE( static void rl_clear_rx, (re_t *rep) );
272 _PROTOTYPE( static void rl_do_reset, (re_t *rep) );
273 _PROTOTYPE( static void rl_getstat, (message *mp) );
274 _PROTOTYPE( static void rl_getstat_s, (message *mp) );
275 _PROTOTYPE( static void rl_getname, (message *mp) );
276 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
277 _PROTOTYPE( static void mess_reply, (message *req, message *reply) );
278 _PROTOTYPE( static void rtl8139_stop, (void) );
279 _PROTOTYPE( static void check_int_events, (void) );
280 _PROTOTYPE( static int do_hard_int, (void) );
281 _PROTOTYPE( static void rtl8139_dump, (message *m) );
282 #if 0
283 _PROTOTYPE( static void dump_phy, (re_t *rep) );
284 #endif
285 _PROTOTYPE( static int rl_handler, (re_t *rep) );
286 _PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) );
288 /* The message used in the main loop is made global, so that rl_watchdog_f()
289 * can change its message type to fake a HARD_INT message.
291 PRIVATE message m;
292 PRIVATE int int_event_check; /* set to TRUE if events arrived */
294 static char *progname;
295 extern int errno;
297 /*===========================================================================*
298 * main *
299 *===========================================================================*/
300 int main(int argc, char *argv[])
302 int fkeys, sfkeys;
303 int inet_proc_nr;
304 int i, r;
305 re_t *rep;
306 long v;
308 env_setargs(argc, argv);
310 v= 0;
311 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
312 eth_ign_proto= htons((u16_t) v);
314 /* Observe some function key for debug dumps. */
315 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
316 if ((r=fkey_map(&fkeys, &sfkeys)) != OK)
317 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
319 /* Claim buffer memory now under Minix, before MM takes it all. */
320 for (rep= &re_table[0]; rep < re_table+RE_PORT_NR; rep++)
321 rl_init_buf(rep);
323 /* Try to notify INET that we are present (again). If INET cannot
324 * be found, assume this is the first time we started and INET is
325 * not yet alive.
327 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
328 r = _pm_findproc("inet", &inet_proc_nr);
329 if (r == OK) notify(inet_proc_nr);
332 while (TRUE)
334 if ((r= receive(ANY, &m)) != OK)
335 panic("rtl8139","receive failed", r);
337 switch (m.m_type)
339 case DEV_PING: notify(m.m_source); break;
340 case DL_WRITE: rl_writev(&m, FALSE, FALSE); break;
341 case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
342 case DL_WRITEV_S: rl_writev_s(&m, FALSE); break;
343 case DL_READ: rl_readv(&m, FALSE, FALSE); break;
344 case DL_READV: rl_readv(&m, FALSE, TRUE); break;
345 case DL_READV_S: rl_readv_s(&m, FALSE); break;
346 case DL_CONF: rl_init(&m); break;
347 case DL_GETSTAT: rl_getstat(&m); break;
348 case DL_GETSTAT_S: rl_getstat_s(&m); break;
349 case DL_GETNAME: rl_getname(&m); break;
350 #if 0
351 case DL_STOP: do_stop(&m); break;
352 #endif
353 case SYN_ALARM:
354 /* Under MINIX, synchronous alarms are used instead of
355 * watchdog functions. The approach is very different:
356 * MINIX VMD timeouts are handled within the kernel
357 * (the watchdog is executed by CLOCK), and notify()
358 * the driver in some cases.
359 * MINIX timeouts result in a SYN_ALARM message to the
360 * driver and thus are handled where they should be
361 * handled. Locally, watchdog functions are used again.
363 rl_watchdog_f(NULL);
364 break;
365 case HARD_INT:
366 do_hard_int();
367 if (int_event_check)
368 check_int_events();
369 break ;
370 case FKEY_PRESSED: rtl8139_dump(&m); break;
371 case PROC_EVENT:
372 sig_handler();
373 break;
374 default:
375 panic("rtl8139","illegal message", m.m_type);
380 /*===========================================================================*
381 * sig_handler *
382 *===========================================================================*/
383 PRIVATE void sig_handler()
385 sigset_t sigset;
386 int sig;
388 /* Try to obtain signal set from PM. */
389 if (getsigset(&sigset) != 0) return;
391 /* Check for known signals. */
392 if (sigismember(&sigset, SIGTERM)) {
393 rtl8139_stop();
397 /*===========================================================================*
398 * check_int_events *
399 *===========================================================================*/
400 static void check_int_events(void)
402 int i;
403 re_t *rep;
404 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
406 if (rep->re_mode != REM_ENABLED)
407 continue;
408 if (!rep->re_got_int)
409 continue;
410 rep->re_got_int= 0;
411 assert(rep->re_flags & REF_ENABLED);
412 rl_check_ints(rep);
416 /*===========================================================================*
417 * rtl8139_stop *
418 *===========================================================================*/
419 static void rtl8139_stop()
421 int i;
422 re_t *rep;
424 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
426 if (rep->re_mode != REM_ENABLED)
427 continue;
428 rl_outb(rep->re_base_port, RL_CR, 0);
430 sys_exit(0);
433 /*===========================================================================*
434 * rtl8139_dump *
435 *===========================================================================*/
436 static void rtl8139_dump(m)
437 message *m; /* pointer to request message */
439 re_t *rep;
440 int i;
442 printf("\n");
443 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
445 if (rep->re_mode == REM_DISABLED)
446 printf("Realtek RTL 8139 port %d is disabled\n", i);
448 if (rep->re_mode != REM_ENABLED)
449 continue;
451 printf("Realtek RTL 8139 statistics of port %d:\n", i);
453 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
454 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
455 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
457 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
458 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
459 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
461 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
462 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
463 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
465 printf("collision :%8ld\t", rep->re_stat.ets_collision);
466 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
467 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
469 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
470 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
471 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
473 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
475 printf("re_flags = 0x%x\n", rep->re_flags);
477 printf(
478 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
479 rl_inw(rep->re_base_port, RL_TSAD),
480 rl_inl(rep->re_base_port, RL_TSD0+0*4),
481 rl_inl(rep->re_base_port, RL_TSD0+1*4),
482 rl_inl(rep->re_base_port, RL_TSD0+2*4),
483 rl_inl(rep->re_base_port, RL_TSD0+3*4));
484 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
485 rep->re_tx_head, rep->re_tx_tail,
486 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
487 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
491 /*===========================================================================*
492 * do_init *
493 *===========================================================================*/
494 static void rl_init(mp)
495 message *mp;
497 static int first_time= 1;
499 int port;
500 re_t *rep;
501 message reply_mess;
503 if (first_time)
505 first_time= 0;
506 rl_pci_conf(); /* Configure PCI devices. */
508 tmra_inittimer(&rl_watchdog);
509 /* Use a synchronous alarm instead of a watchdog timer. */
510 sys_setalarm(HZ, 0);
513 port = mp->DL_PORT;
514 if (port < 0 || port >= RE_PORT_NR)
516 reply_mess.m_type= DL_CONF_REPLY;
517 reply_mess.m3_i1= ENXIO;
518 mess_reply(mp, &reply_mess);
519 return;
521 rep= &re_table[port];
522 if (rep->re_mode == REM_DISABLED)
524 /* This is the default, try to (re)locate the device. */
525 rl_conf_hw(rep);
526 if (rep->re_mode == REM_DISABLED)
528 /* Probe failed, or the device is configured off. */
529 reply_mess.m_type= DL_CONF_REPLY;
530 reply_mess.m3_i1= ENXIO;
531 mess_reply(mp, &reply_mess);
532 return;
534 if (rep->re_mode == REM_ENABLED)
535 rl_init_hw(rep);
536 #if VERBOSE /* load silently ... can always check status later */
537 rl_report_link(rep);
538 #endif
541 assert(rep->re_mode == REM_ENABLED);
542 assert(rep->re_flags & REF_ENABLED);
544 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
546 if (mp->DL_MODE & DL_PROMISC_REQ)
547 rep->re_flags |= REF_PROMISC;
548 if (mp->DL_MODE & DL_MULTI_REQ)
549 rep->re_flags |= REF_MULTI;
550 if (mp->DL_MODE & DL_BROAD_REQ)
551 rep->re_flags |= REF_BROAD;
553 rep->re_client = mp->m_source;
554 rl_rec_mode(rep);
556 reply_mess.m_type = DL_CONF_REPLY;
557 reply_mess.m3_i1 = mp->DL_PORT;
558 reply_mess.m3_i2 = RE_PORT_NR;
559 *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
561 mess_reply(mp, &reply_mess);
564 /*===========================================================================*
565 * rl_pci_conf *
566 *===========================================================================*/
567 static void rl_pci_conf()
569 int i, h;
570 re_t *rep;
571 static char envvar[] = RL_ENVVAR "#";
572 static char envfmt[] = "*:d.d.d";
573 static char val[128];
574 long v;
576 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
578 strcpy(rep->re_name, "rtl8139#0");
579 rep->re_name[8] += i;
580 rep->re_seen= FALSE;
581 envvar[sizeof(RL_ENVVAR)-1]= '0'+i;
582 if (0 == env_get_param(envvar, val, sizeof(val)) &&
583 ! env_prefix(envvar, "pci")) {
584 env_panic(envvar);
586 v= 0;
587 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
588 rep->re_pcibus= v;
589 v= 0;
590 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
591 rep->re_pcidev= v;
592 v= 0;
593 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
594 rep->re_pcifunc= v;
597 pci_init();
599 for (h= 1; h >= 0; h--) {
600 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
602 if (((rep->re_pcibus | rep->re_pcidev |
603 rep->re_pcifunc) != 0) != h)
605 continue;
607 if (rl_probe(rep))
608 rep->re_seen= TRUE;
613 /*===========================================================================*
614 * rl_probe *
615 *===========================================================================*/
616 static int rl_probe(rep)
617 re_t *rep;
619 int i, r, devind, just_one;
620 u16_t vid, did;
621 u32_t bar;
622 u8_t ilr;
623 char *dname;
625 if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0)
627 /* Look for specific PCI device */
628 r= pci_find_dev(rep->re_pcibus, rep->re_pcidev,
629 rep->re_pcifunc, &devind);
630 if (r == 0)
632 printf("%s: no PCI found at %d.%d.%d\n",
633 rep->re_name, rep->re_pcibus,
634 rep->re_pcidev, rep->re_pcifunc);
635 return 0;
637 pci_ids(devind, &vid, &did);
638 just_one= TRUE;
640 else
642 r= pci_first_dev(&devind, &vid, &did);
643 if (r == 0)
644 return 0;
645 just_one= FALSE;
648 for(;;)
650 for (i= 0; pcitab[i].vid != 0; i++)
652 if (pcitab[i].vid != vid)
653 continue;
654 if (pcitab[i].did != did)
655 continue;
656 if (pcitab[i].checkclass)
658 panic("rtl_probe",
659 "class check not implemented", NO_NUM);
661 break;
663 if (pcitab[i].vid != 0)
664 break;
666 if (just_one)
668 printf(
669 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
670 rep->re_name, vid, did,
671 rep->re_pcibus,
672 rep->re_pcidev, rep->re_pcifunc);
673 return 0;
676 r= pci_next_dev(&devind, &vid, &did);
677 if (!r)
678 return 0;
681 #if VERBOSE /* stay silent at startup, can always get status later */
682 dname= pci_dev_name(vid, did);
683 if (!dname)
684 dname= "unknown device";
685 printf("%s: ", rep->re_name);
686 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
687 #endif
688 pci_reserve(devind);
689 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
690 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
691 if (bar < 0x400)
693 panic("rtl_probe",
694 "base address is not properly configured", NO_NUM);
696 rep->re_base_port= bar;
698 ilr= pci_attr_r8(devind, PCI_ILR);
699 rep->re_irq= ilr;
700 if (debug)
702 printf("%s: using I/O address 0x%lx, IRQ %d\n",
703 rep->re_name, (unsigned long)bar, ilr);
706 return TRUE;
709 /*===========================================================================*
710 * rl_conf_hw *
711 *===========================================================================*/
712 static void rl_conf_hw(rep)
713 re_t *rep;
715 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
717 rep->re_mode= REM_DISABLED; /* Superfluous */
719 if (rep->re_seen)
721 /* PCI device is present */
722 rep->re_mode= REM_ENABLED;
724 if (rep->re_mode != REM_ENABLED)
725 return;
727 rep->re_flags= REF_EMPTY;
728 rep->re_link_up= -1; /* Unknown */
729 rep->re_got_int= 0;
730 rep->re_send_int= 0;
731 rep->re_report_link= 0;
732 rep->re_clear_rx= 0;
733 rep->re_need_reset= 0;
734 rep->re_tx_alive= 0;
735 rep->re_read_s= 0;
736 rep->re_tx_head= 0;
737 rep->re_tx_tail= 0;
738 rep->re_ertxth= RL_TSD_ERTXTH_8;
739 rep->re_stat= empty_stat;
742 /*===========================================================================*
743 * rl_init_buf *
744 *===========================================================================*/
745 static void rl_init_buf(rep)
746 re_t *rep;
748 size_t rx_bufsize, tx_bufsize, tot_bufsize;
749 phys_bytes buf;
750 char *mallocbuf;
751 static struct memory chunk;
752 int fd, s, i, off;
754 /* Allocate receive and transmit buffers */
755 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
756 if (tx_bufsize % 4)
757 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
758 rx_bufsize= RX_BUFSIZE;
759 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
761 /* Now try to allocate a kernel memory buffer. */
762 chunk.size = tot_bufsize;
764 #define BUF_ALIGNMENT (64*1024)
766 if(!(mallocbuf = malloc(BUF_ALIGNMENT + tot_bufsize))) {
767 panic("RTL8139","Couldn't allocate kernel buffer",i);
770 if(OK != (i = sys_umap(SELF, D, (vir_bytes) mallocbuf, tot_bufsize, &buf))) {
771 panic("RTL8139","Couldn't re-map malloced buffer",i);
774 /* click-align mallocced buffer. this is what we used to get
775 * from kmalloc() too.
777 if((off = buf % BUF_ALIGNMENT)) {
778 mallocbuf += BUF_ALIGNMENT - off;
779 buf += BUF_ALIGNMENT - off;
782 for (i= 0; i<N_TX_BUF; i++)
784 rep->re_tx[i].ret_buf= buf;
785 rep->re_tx[i].v_ret_buf= mallocbuf;
786 buf += tx_bufsize;
787 mallocbuf += tx_bufsize;
789 rep->re_rx_buf= buf;
790 rep->v_re_rx_buf= mallocbuf;
793 /*===========================================================================*
794 * rl_init_hw *
795 *===========================================================================*/
796 static void rl_init_hw(rep)
797 re_t *rep;
799 int s, i;
801 rep->re_flags = REF_EMPTY;
802 rep->re_flags |= REF_ENABLED;
804 /* Set the interrupt handler. The policy is to only send HARD_INT
805 * notifications. Don't reenable interrupts automatically. The id
806 * that is passed back is the interrupt line number.
808 rep->re_hook_id = rep->re_irq;
809 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
810 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
812 rl_reset_hw(rep);
814 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
815 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
817 #if VERBOSE /* stay silent during startup, can always get status later */
818 if (rep->re_model) {
819 printf("%s: model %s\n", rep->re_name, rep->re_model);
820 } else
822 printf("%s: unknown model 0x%08x\n",
823 rep->re_name,
824 rl_inl(rep->re_base_port, RL_TCR) &
825 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
827 #endif
829 rl_confaddr(rep);
830 if (debug)
832 printf("%s: Ethernet address ", rep->re_name);
833 for (i= 0; i < 6; i++)
835 printf("%x%c", rep->re_address.ea_addr[i],
836 i < 5 ? ':' : '\n');
841 /*===========================================================================*
842 * rl_reset_hw *
843 *===========================================================================*/
844 static void rl_reset_hw(rep)
845 re_t *rep;
847 port_t port;
848 u32_t t;
849 phys_bytes bus_buf;
850 int i;
851 clock_t t0,t1;
853 port= rep->re_base_port;
855 #if 0
856 /* Reset the PHY */
857 rl_outb(port, RL_BMCR, MII_CTRL_RST);
858 getuptime(&t0);
859 do {
860 if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
861 break;
862 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
863 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
864 panic("rtl8139","reset PHY failed to complete", NO_NUM);
865 #endif
867 /* Reset the device */
868 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
869 port, rl_inb(port, RL_CR));
870 rl_outb(port, RL_CR, RL_CR_RST);
871 getuptime(&t0);
872 do {
873 if (!(rl_inb(port, RL_CR) & RL_CR_RST))
874 break;
875 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
876 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
877 port, rl_inb(port, RL_CR));
878 if (rl_inb(port, RL_CR) & RL_CR_RST)
879 printf("rtl8139: reset failed to complete");
881 t= rl_inl(port, RL_TCR);
882 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
884 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
885 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
886 case RL_TCR_HWVER_RTL8139AG:
887 rep->re_model= "RTL8139A-G / RTL8139C";
888 break;
889 case RL_TCR_HWVER_RTL8139B:
890 rep->re_model= "RTL8139B / RTL8130";
891 break;
892 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
893 case RL_TCR_HWVER_RTL8100B:
894 rep->re_model= "RTL8100B/RTL8139D";
895 break;
896 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
897 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
898 default:
899 rep->re_model= NULL;
900 break;
903 #if 0
904 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
905 #endif
907 /* Intialize Rx */
909 /* Should init multicast mask */
910 #if 0
911 08-0f R/W MAR[0-7] multicast
912 #endif
913 bus_buf= vm_1phys2bus(rep->re_rx_buf);
914 rl_outl(port, RL_RBSTART, bus_buf);
916 /* Initialize Tx */
917 for (i= 0; i<N_TX_BUF; i++)
919 rep->re_tx[i].ret_busy= FALSE;
920 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
921 rl_outl(port, RL_TSAD0+i*4, bus_buf);
922 t= rl_inl(port, RL_TSD0+i*4);
923 assert(t & RL_TSD_OWN);
926 #if 0
927 dump_phy(rep);
928 #endif
930 t= rl_inw(port, RL_IMR);
931 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
932 RL_IMR_LENCHG));
934 t= rl_inw(port, RL_IMR);
935 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
936 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
938 t= rl_inw(port, RL_IMR);
939 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
941 t= rl_inb(port, RL_CR);
942 rl_outb(port, RL_CR, t | RL_CR_RE);
944 t= rl_inb(port, RL_CR);
945 rl_outb(port, RL_CR, t | RL_CR_TE);
947 rl_outl(port, RL_RCR, RX_BUFBITS);
949 t= rl_inl(port, RL_TCR);
950 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
953 /*===========================================================================*
954 * rl_confaddr *
955 *===========================================================================*/
956 static void rl_confaddr(rep)
957 re_t *rep;
959 static char eakey[]= RL_ENVVAR "#_EA";
960 static char eafmt[]= "x:x:x:x:x:x";
962 int i;
963 port_t port;
964 u32_t w;
965 long v;
967 /* User defined ethernet address? */
968 eakey[sizeof(RL_ENVVAR)-1]= '0' + (rep-re_table);
970 port= rep->re_base_port;
972 for (i= 0; i < 6; i++)
974 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
975 break;
976 rep->re_address.ea_addr[i]= v;
979 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
981 /* Should update ethernet address in hardware */
982 if (i == 6)
984 port= rep->re_base_port;
985 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
986 w= 0;
987 for (i= 0; i<4; i++)
988 w |= (rep->re_address.ea_addr[i] << (i*8));
989 rl_outl(port, RL_IDR, w);
990 w= 0;
991 for (i= 4; i<6; i++)
992 w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
993 rl_outl(port, RL_IDR+4, w);
994 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
997 /* Get ethernet address */
998 for (i= 0; i<6; i++)
999 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
1002 /*===========================================================================*
1003 * rl_rec_mode *
1004 *===========================================================================*/
1005 static void rl_rec_mode(rep)
1006 re_t *rep;
1008 port_t port;
1009 u32_t rcr;
1011 port= rep->re_base_port;
1012 rcr= rl_inl(port, RL_RCR);
1013 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
1014 if (rep->re_flags & REF_PROMISC)
1015 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
1016 if (rep->re_flags & REF_BROAD)
1017 rcr |= RL_RCR_AB;
1018 if (rep->re_flags & REF_MULTI)
1019 rcr |= RL_RCR_AM;
1020 rcr |= RL_RCR_APM;
1022 rl_outl(port, RL_RCR, rcr);
1025 /*===========================================================================*
1026 * rl_readv *
1027 *===========================================================================*/
1028 static void rl_readv(mp, from_int, vectored)
1029 message *mp;
1030 int from_int;
1031 int vectored;
1033 int i, j, n, o, s, s1, dl_port, re_client, count, size;
1034 port_t port;
1035 unsigned amount, totlen, packlen;
1036 phys_bytes src_phys, dst_phys, iov_src;
1037 u16_t d_start, d_end;
1038 u32_t l, rxstat = 0x12345678;
1039 re_t *rep;
1040 iovec_t *iovp;
1041 int cps;
1043 dl_port = mp->DL_PORT;
1044 count = mp->DL_COUNT;
1045 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1046 panic("rtl8139"," illegal port", dl_port);
1047 rep= &re_table[dl_port];
1048 re_client= mp->DL_PROC;
1049 rep->re_client= re_client;
1051 if (rep->re_clear_rx)
1052 goto suspend; /* Buffer overflow */
1054 assert(rep->re_mode == REM_ENABLED);
1055 assert(rep->re_flags & REF_ENABLED);
1057 port= rep->re_base_port;
1059 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1061 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1063 /* Receive buffer is empty, suspend */
1064 goto suspend;
1067 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1068 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1070 if (d_start >= RX_BUFSIZE)
1072 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1073 rl_inw(port, RL_CAPR));
1074 d_start %= RX_BUFSIZE;
1077 if (d_end > d_start)
1078 amount= d_end-d_start;
1079 else
1080 amount= d_end+RX_BUFSIZE - d_start;
1082 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1084 if (rep->re_clear_rx)
1086 #if 0
1087 printf("rl_readv: late buffer overflow\n");
1088 #endif
1089 goto suspend; /* Buffer overflow */
1092 /* Should convert from little endian to host byte order */
1094 if (!(rxstat & RL_RXS_ROK))
1096 printf("rxstat = 0x%08lx\n", rxstat);
1097 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1098 d_start, d_end, rxstat);
1099 panic("rtl8139","received packet not OK", NO_NUM);
1101 totlen= (rxstat >> RL_RXS_LEN_S);
1102 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1104 /* Someting went wrong */
1105 printf(
1106 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1107 totlen, rxstat, d_start);
1108 printf(
1109 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1110 d_start, d_end, totlen, rxstat);
1111 panic(NULL, NULL, NO_NUM);
1114 #if 0
1115 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1116 d_start, d_end, totlen, rxstat);
1117 #endif
1119 if (totlen+4 > amount)
1121 printf("rl_readv: packet not yet ready\n");
1122 goto suspend;
1125 /* Should subtract the CRC */
1126 packlen= totlen - ETH_CRC_SIZE;
1128 if (vectored)
1130 int iov_offset = 0;
1132 size= 0;
1133 o= d_start+4;
1134 src_phys= rep->re_rx_buf;
1135 for (i= 0; i<count; i += IOVEC_NR,
1136 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1137 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1139 n= IOVEC_NR;
1140 if (i+n > count)
1141 n= count-i;
1143 cps = sys_vircopy(re_client, D,
1144 (vir_bytes) mp->DL_ADDR + iov_offset,
1145 SELF, D, (vir_bytes) rep->re_iovec,
1146 n * sizeof(rep->re_iovec[0]));
1147 if (cps != OK)
1148 printf(
1149 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1150 cps, __LINE__);
1152 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1154 s= iovp->iov_size;
1155 if (size + s > packlen)
1157 assert(packlen > size);
1158 s= packlen-size;
1161 if (o >= RX_BUFSIZE)
1163 o -= RX_BUFSIZE;
1164 assert(o < RX_BUFSIZE);
1167 if (o+s > RX_BUFSIZE)
1169 assert(o<RX_BUFSIZE);
1170 s1= RX_BUFSIZE-o;
1172 cps = sys_vircopy(SELF, D,
1173 (vir_bytes) rep->v_re_rx_buf+o,
1174 re_client, D, iovp->iov_addr,
1175 s1);
1176 if (cps != OK)
1177 printf(
1178 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1179 cps, __LINE__);
1180 cps = sys_vircopy(SELF, D,
1181 (vir_bytes) rep->v_re_rx_buf,
1182 re_client, D,
1183 iovp->iov_addr+s1, s-s1);
1184 if (cps != OK)
1185 printf(
1186 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1187 cps, __LINE__);
1189 else
1191 cps = sys_vircopy(SELF, D,
1192 (vir_bytes) rep->v_re_rx_buf+o,
1193 re_client, D, iovp->iov_addr,
1195 if (cps != OK)
1196 printf(
1197 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1198 cps, __LINE__);
1201 size += s;
1202 if (size == packlen)
1203 break;
1204 o += s;
1206 if (size == packlen)
1207 break;
1209 if (size < packlen)
1211 assert(0);
1214 else
1216 assert(0);
1217 #if 0
1218 size= mp->DL_COUNT;
1219 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1220 panic("rtl8139","invalid packet size", size);
1221 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1222 panic("rtl8139","umap_local failed", NO_NUM);
1224 p= rep->re_tx[tx_head].ret_buf;
1225 cps = sys_abscopy(phys_user, p, size);
1226 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1227 #endif
1230 if (rep->re_clear_rx)
1232 /* For some reason the receiver FIFO is not stopped when
1233 * the buffer is full.
1235 #if 0
1236 printf("rl_readv: later buffer overflow\n");
1237 #endif
1238 goto suspend; /* Buffer overflow */
1241 rep->re_stat.ets_packetR++;
1242 rep->re_read_s= packlen;
1243 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1245 /* Avoid overflow in 16-bit computations */
1246 l= d_start;
1247 l += totlen+4;
1248 l= (l+3) & ~3; /* align */
1249 if (l >= RX_BUFSIZE)
1251 l -= RX_BUFSIZE;
1252 assert(l < RX_BUFSIZE);
1254 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1256 if (!from_int)
1257 reply(rep, OK, FALSE);
1259 return;
1261 suspend:
1262 if (from_int)
1264 assert(rep->re_flags & REF_READING);
1266 /* No need to store any state */
1267 return;
1270 rep->re_rx_mess= *mp;
1271 assert(!(rep->re_flags & REF_READING));
1272 rep->re_flags |= REF_READING;
1274 reply(rep, OK, FALSE);
1277 /*===========================================================================*
1278 * rl_readv_s *
1279 *===========================================================================*/
1280 static void rl_readv_s(mp, from_int)
1281 message *mp;
1282 int from_int;
1284 int i, j, n, o, s, s1, dl_port, re_client, count, size;
1285 port_t port;
1286 unsigned amount, totlen, packlen;
1287 phys_bytes src_phys, dst_phys, iov_src;
1288 u16_t d_start, d_end;
1289 u32_t l, rxstat = 0x12345678;
1290 re_t *rep;
1291 iovec_s_t *iovp;
1292 int cps;
1293 int iov_offset = 0;
1295 dl_port = mp->DL_PORT;
1296 count = mp->DL_COUNT;
1297 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1298 panic("rtl8139"," illegal port", dl_port);
1299 rep= &re_table[dl_port];
1300 re_client= mp->DL_PROC;
1301 rep->re_client= re_client;
1303 if (rep->re_clear_rx)
1304 goto suspend; /* Buffer overflow */
1306 assert(rep->re_mode == REM_ENABLED);
1307 assert(rep->re_flags & REF_ENABLED);
1309 port= rep->re_base_port;
1311 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1313 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1315 /* Receive buffer is empty, suspend */
1316 goto suspend;
1319 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1320 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1322 if (d_start >= RX_BUFSIZE)
1324 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1325 rl_inw(port, RL_CAPR));
1326 d_start %= RX_BUFSIZE;
1329 if (d_end > d_start)
1330 amount= d_end-d_start;
1331 else
1332 amount= d_end+RX_BUFSIZE - d_start;
1334 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1336 if (rep->re_clear_rx)
1338 #if 0
1339 printf("rl_readv: late buffer overflow\n");
1340 #endif
1341 goto suspend; /* Buffer overflow */
1344 /* Should convert from little endian to host byte order */
1346 if (!(rxstat & RL_RXS_ROK))
1348 printf("rxstat = 0x%08lx\n", rxstat);
1349 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1350 d_start, d_end, rxstat);
1351 panic("rtl8139","received packet not OK", NO_NUM);
1353 totlen= (rxstat >> RL_RXS_LEN_S);
1354 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1356 /* Someting went wrong */
1357 printf(
1358 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1359 totlen, rxstat, d_start);
1360 printf(
1361 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1362 d_start, d_end, totlen, rxstat);
1363 panic(NULL, NULL, NO_NUM);
1366 #if 0
1367 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1368 d_start, d_end, totlen, rxstat);
1369 #endif
1371 if (totlen+4 > amount)
1373 printf("rl_readv: packet not yet ready\n");
1374 goto suspend;
1377 /* Should subtract the CRC */
1378 packlen= totlen - ETH_CRC_SIZE;
1380 size= 0;
1381 o= d_start+4;
1382 src_phys= rep->re_rx_buf;
1383 for (i= 0; i<count; i += IOVEC_NR,
1384 iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
1385 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1387 n= IOVEC_NR;
1388 if (i+n > count)
1389 n= count-i;
1391 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1392 (vir_bytes) rep->re_iovec_s,
1393 n * sizeof(rep->re_iovec_s[0]), D);
1394 if (cps != OK)
1396 panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed",
1397 cps);
1400 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
1402 s= iovp->iov_size;
1403 if (size + s > packlen)
1405 assert(packlen > size);
1406 s= packlen-size;
1409 #if 0
1410 if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
1411 panic("rtl8139","umap_local failed\n", NO_NUM);
1412 #endif
1414 if (o >= RX_BUFSIZE)
1416 o -= RX_BUFSIZE;
1417 assert(o < RX_BUFSIZE);
1420 if (o+s > RX_BUFSIZE)
1422 assert(o<RX_BUFSIZE);
1423 s1= RX_BUFSIZE-o;
1425 cps = sys_safecopyto(re_client,
1426 iovp->iov_grant, 0,
1427 (vir_bytes) rep->v_re_rx_buf+o, s1, D);
1428 if (cps != OK)
1430 panic(__FILE__,
1431 "rl_readv_s: sys_safecopyto failed",
1432 cps);
1434 cps = sys_safecopyto(re_client,
1435 iovp->iov_grant, s1,
1436 (vir_bytes) rep->v_re_rx_buf, s-s1, S);
1437 if (cps != OK)
1439 panic(__FILE__,
1440 "rl_readv_s: sys_safecopyto failed",
1441 cps);
1444 else
1446 cps = sys_safecopyto(re_client,
1447 iovp->iov_grant, 0,
1448 (vir_bytes) rep->v_re_rx_buf+o, s, D);
1449 if (cps != OK)
1450 panic(__FILE__,
1451 "rl_readv_s: sys_vircopy failed",
1452 cps);
1455 size += s;
1456 if (size == packlen)
1457 break;
1458 o += s;
1460 if (size == packlen)
1461 break;
1463 if (size < packlen)
1465 assert(0);
1468 if (rep->re_clear_rx)
1470 /* For some reason the receiver FIFO is not stopped when
1471 * the buffer is full.
1473 #if 0
1474 printf("rl_readv: later buffer overflow\n");
1475 #endif
1476 goto suspend; /* Buffer overflow */
1479 rep->re_stat.ets_packetR++;
1480 rep->re_read_s= packlen;
1481 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1483 /* Avoid overflow in 16-bit computations */
1484 l= d_start;
1485 l += totlen+4;
1486 l= (l+3) & ~3; /* align */
1487 if (l >= RX_BUFSIZE)
1489 l -= RX_BUFSIZE;
1490 assert(l < RX_BUFSIZE);
1492 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1494 if (!from_int)
1495 reply(rep, OK, FALSE);
1497 return;
1499 suspend:
1500 if (from_int)
1502 assert(rep->re_flags & REF_READING);
1504 /* No need to store any state */
1505 return;
1508 rep->re_rx_mess= *mp;
1509 assert(!(rep->re_flags & REF_READING));
1510 rep->re_flags |= REF_READING;
1512 reply(rep, OK, FALSE);
1515 /*===========================================================================*
1516 * rl_writev *
1517 *===========================================================================*/
1518 static void rl_writev(mp, from_int, vectored)
1519 message *mp;
1520 int from_int;
1521 int vectored;
1523 phys_bytes iov_src, phys_user;
1524 int i, j, n, s, port, count, size;
1525 int tx_head, re_client;
1526 re_t *rep;
1527 iovec_t *iovp;
1528 char *ret;
1529 int cps;
1531 port = mp->DL_PORT;
1532 count = mp->DL_COUNT;
1533 if (port < 0 || port >= RE_PORT_NR)
1534 panic("rtl8139","illegal port", port);
1535 rep= &re_table[port];
1536 re_client= mp->DL_PROC;
1537 rep->re_client= re_client;
1539 assert(rep->re_mode == REM_ENABLED);
1540 assert(rep->re_flags & REF_ENABLED);
1542 if (from_int)
1544 assert(rep->re_flags & REF_SEND_AVAIL);
1545 rep->re_flags &= ~REF_SEND_AVAIL;
1546 rep->re_send_int= FALSE;
1547 rep->re_tx_alive= TRUE;
1550 tx_head= rep->re_tx_head;
1551 if (rep->re_tx[tx_head].ret_busy)
1553 assert(!(rep->re_flags & REF_SEND_AVAIL));
1554 rep->re_flags |= REF_SEND_AVAIL;
1555 if (rep->re_tx[tx_head].ret_busy)
1556 goto suspend;
1558 /* Race condition, the interrupt handler may clear re_busy
1559 * before we got a chance to set REF_SEND_AVAIL. Checking
1560 * ret_busy twice should be sufficient.
1562 #if 0
1563 printf("rl_writev: race detected\n");
1564 #endif
1565 rep->re_flags &= ~REF_SEND_AVAIL;
1566 rep->re_send_int= FALSE;
1569 assert(!(rep->re_flags & REF_SEND_AVAIL));
1570 assert(!(rep->re_flags & REF_PACK_SENT));
1572 if (vectored)
1574 int iov_offset = 0;
1576 size= 0;
1577 ret = rep->re_tx[tx_head].v_ret_buf;
1578 for (i= 0; i<count; i += IOVEC_NR,
1579 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1580 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1582 n= IOVEC_NR;
1583 if (i+n > count)
1584 n= count-i;
1585 cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
1586 SELF, D, (vir_bytes) rep->re_iovec,
1587 n * sizeof(rep->re_iovec[0]));
1588 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1590 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1592 s= iovp->iov_size;
1593 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1595 panic("rtl8139","invalid packet size",
1596 NO_NUM);
1599 if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
1600 panic("rtl8139","umap_local failed\n", NO_NUM);
1602 cps = sys_vircopy(re_client, D, iovp->iov_addr,
1603 SELF, D, (vir_bytes) ret, s);
1604 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1605 size += s;
1606 ret += s;
1609 if (size < ETH_MIN_PACK_SIZE)
1610 panic("rtl8139","invalid packet size", size);
1612 else
1614 size= mp->DL_COUNT;
1615 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1616 panic("rtl8139","invalid packet size", size);
1617 ret = rep->re_tx[tx_head].v_ret_buf;
1618 cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR,
1619 SELF, D, (vir_bytes) ret, size);
1620 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1623 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1624 rep->re_ertxth | size);
1625 rep->re_tx[tx_head].ret_busy= TRUE;
1627 if (++tx_head == N_TX_BUF)
1628 tx_head= 0;
1629 assert(tx_head < RL_N_TX);
1630 rep->re_tx_head= tx_head;
1632 rep->re_flags |= REF_PACK_SENT;
1634 /* If the interrupt handler called, don't send a reply. The reply
1635 * will be sent after all interrupts are handled.
1637 if (from_int)
1638 return;
1639 reply(rep, OK, FALSE);
1640 return;
1642 suspend:
1643 #if 0
1644 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1645 tx_head, rep->re_tx_tail,
1646 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1647 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1648 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1649 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1650 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1651 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1652 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1653 #endif
1655 if (from_int)
1656 panic("rtl8139","should not be sending\n", NO_NUM);
1658 rep->re_tx_mess= *mp;
1659 reply(rep, OK, FALSE);
1662 /*===========================================================================*
1663 * rl_writev_s *
1664 *===========================================================================*/
1665 static void rl_writev_s(mp, from_int)
1666 message *mp;
1667 int from_int;
1669 phys_bytes iov_src;
1670 int i, j, n, s, port, count, size;
1671 int tx_head, re_client;
1672 re_t *rep;
1673 iovec_s_t *iovp;
1674 char *ret;
1675 int cps;
1676 int iov_offset = 0;
1678 port = mp->DL_PORT;
1679 count = mp->DL_COUNT;
1680 if (port < 0 || port >= RE_PORT_NR)
1681 panic("rtl8139","illegal port", port);
1682 rep= &re_table[port];
1683 re_client= mp->DL_PROC;
1684 rep->re_client= re_client;
1686 assert(rep->re_mode == REM_ENABLED);
1687 assert(rep->re_flags & REF_ENABLED);
1689 if (from_int)
1691 assert(rep->re_flags & REF_SEND_AVAIL);
1692 rep->re_flags &= ~REF_SEND_AVAIL;
1693 rep->re_send_int= FALSE;
1694 rep->re_tx_alive= TRUE;
1697 tx_head= rep->re_tx_head;
1698 if (rep->re_tx[tx_head].ret_busy)
1700 assert(!(rep->re_flags & REF_SEND_AVAIL));
1701 rep->re_flags |= REF_SEND_AVAIL;
1702 if (rep->re_tx[tx_head].ret_busy)
1703 goto suspend;
1705 /* Race condition, the interrupt handler may clear re_busy
1706 * before we got a chance to set REF_SEND_AVAIL. Checking
1707 * ret_busy twice should be sufficient.
1709 #if 0
1710 printf("rl_writev: race detected\n");
1711 #endif
1712 rep->re_flags &= ~REF_SEND_AVAIL;
1713 rep->re_send_int= FALSE;
1716 assert(!(rep->re_flags & REF_SEND_AVAIL));
1717 assert(!(rep->re_flags & REF_PACK_SENT));
1719 size= 0;
1720 ret = rep->re_tx[tx_head].v_ret_buf;
1721 for (i= 0; i<count; i += IOVEC_NR,
1722 iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
1723 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1725 n= IOVEC_NR;
1726 if (i+n > count)
1727 n= count-i;
1728 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1729 (vir_bytes) rep->re_iovec_s,
1730 n * sizeof(rep->re_iovec_s[0]), D);
1731 if (cps != OK)
1733 panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed",
1734 cps);
1737 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
1739 s= iovp->iov_size;
1740 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1742 panic("rtl8139","invalid packet size",
1743 NO_NUM);
1745 cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0,
1746 (vir_bytes) ret, s, D);
1747 if (cps != OK)
1749 panic(__FILE__,
1750 "rl_writev_s: sys_safecopyfrom failed",
1751 cps);
1753 size += s;
1754 ret += s;
1757 if (size < ETH_MIN_PACK_SIZE)
1758 panic("rtl8139","invalid packet size", size);
1760 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1761 rep->re_ertxth | size);
1762 rep->re_tx[tx_head].ret_busy= TRUE;
1764 if (++tx_head == N_TX_BUF)
1765 tx_head= 0;
1766 assert(tx_head < RL_N_TX);
1767 rep->re_tx_head= tx_head;
1769 rep->re_flags |= REF_PACK_SENT;
1771 /* If the interrupt handler called, don't send a reply. The reply
1772 * will be sent after all interrupts are handled.
1774 if (from_int)
1775 return;
1776 reply(rep, OK, FALSE);
1777 return;
1779 suspend:
1780 #if 0
1781 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1782 tx_head, rep->re_tx_tail,
1783 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1784 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1785 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1786 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1787 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1788 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1789 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1790 #endif
1792 if (from_int)
1793 panic("rtl8139","should not be sending\n", NO_NUM);
1795 rep->re_tx_mess= *mp;
1796 reply(rep, OK, FALSE);
1799 /*===========================================================================*
1800 * rl_check_ints *
1801 *===========================================================================*/
1802 static void rl_check_ints(rep)
1803 re_t *rep;
1805 #if 0
1806 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
1807 31 R CRS Carrier Sense Lost
1808 30 R TABT Transmit Abort
1809 29 R OWC Out of Window Collision
1810 27-24 R NCC[3-0] Number of Collision Count
1811 23-22 reserved
1812 21-16 R/W ERTXH[5-0] Early Tx Threshold
1813 15 R TOK Transmit OK
1814 14 R TUN Transmit FIFO Underrun
1815 13 R/W OWN OWN
1816 12-0 R/W SIZE Descriptor Size
1817 3e-3f R/W ISR Interrupt Status Register
1818 6 R/W FOVW Fx FIFO Overflow Interrupt
1819 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
1820 3 R/W TER Transmit Error Interrupt
1821 2 R/W TOK Transmit OK Interrupt
1822 3e-3f R/W ISR Interrupt Status Register
1823 15 R/W SERR System Error Interrupt
1824 14 R/W TimeOut Time Out Interrupt
1825 13 R/W LenChg Cable Length Change Interrupt
1826 3e-3f R/W ISR Interrupt Status Register
1827 4 R/W RXOVW Rx Buffer Overflow Interrupt
1828 1 R/W RER Receive Error Interrupt
1829 0 R/W ROK Receive OK Interrupt
1830 4c-4f R/W MPC Missed Packet Counter
1831 60-61 R TSAD Transmit Status of All Descriptors
1832 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
1833 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
1834 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
1835 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
1836 6c-6d R DIS Disconnect Counter
1837 15-0 R DCNT Disconnect Counter
1838 6e-6f R FCSC False Carrier Sense Counter
1839 15-0 R FCSCNT False Carrier event counter
1840 72-73 R REC RX_ER Counter
1841 15-0 R RXERCNT Received packet counter
1842 #endif
1844 int re_flags;
1846 re_flags= rep->re_flags;
1848 if ((re_flags & REF_READING) &&
1849 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1851 if (rep->re_rx_mess.m_type == DL_READV)
1853 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1854 TRUE /* vectored */);
1856 else if (rep->re_rx_mess.m_type == DL_READV_S)
1858 rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
1860 else
1862 assert(rep->re_rx_mess.m_type == DL_READ);
1863 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1864 FALSE /* !vectored */);
1867 if (rep->re_clear_rx)
1868 rl_clear_rx(rep);
1870 if (rep->re_need_reset)
1871 rl_do_reset(rep);
1873 if (rep->re_send_int)
1875 if (rep->re_tx_mess.m_type == DL_WRITEV)
1877 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1878 TRUE /* vectored */);
1880 else
1882 assert(rep->re_tx_mess.m_type == DL_WRITE);
1883 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1884 FALSE /* !vectored */);
1888 if (rep->re_report_link)
1889 rl_report_link(rep);
1891 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1892 reply(rep, OK, TRUE);
1895 /*===========================================================================*
1896 * rl_report_link *
1897 *===========================================================================*/
1898 static void rl_report_link(rep)
1899 re_t *rep;
1901 port_t port;
1902 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
1903 u8_t msr;
1904 int f, link_up;
1906 rep->re_report_link= FALSE;
1907 port= rep->re_base_port;
1908 msr= rl_inb(port, RL_MSR);
1909 link_up= !(msr & RL_MSR_LINKB);
1910 rep->re_link_up= link_up;
1911 if (!link_up)
1913 printf("%s: link down\n", rep->re_name);
1914 return;
1917 mii_ctrl= rl_inw(port, RL_BMCR);
1918 mii_status= rl_inw(port, RL_BMSR);
1919 mii_ana= rl_inw(port, RL_ANAR);
1920 mii_anlpa= rl_inw(port, RL_ANLPAR);
1921 mii_ane= rl_inw(port, RL_ANER);
1922 mii_extstat= 0;
1924 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1926 printf("%s: PHY: ", rep->re_name);
1927 f= 1;
1928 if (mii_ctrl & MII_CTRL_LB)
1930 printf("loopback mode");
1931 f= 0;
1933 if (mii_ctrl & MII_CTRL_PD)
1935 if (!f) printf(", ");
1936 f= 0;
1937 printf("powered down");
1939 if (mii_ctrl & MII_CTRL_ISO)
1941 if (!f) printf(", ");
1942 f= 0;
1943 printf("isolated");
1945 printf("\n");
1946 return;
1948 if (!(mii_ctrl & MII_CTRL_ANE))
1950 printf("%s: manual config: ", rep->re_name);
1951 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1953 case MII_CTRL_SP_10: printf("10 Mbps"); break;
1954 case MII_CTRL_SP_100: printf("100 Mbps"); break;
1955 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
1956 case MII_CTRL_SP_RES: printf("reserved speed"); break;
1958 if (mii_ctrl & MII_CTRL_DM)
1959 printf(", full duplex");
1960 else
1961 printf(", half duplex");
1962 printf("\n");
1963 return;
1966 if (!debug) goto resspeed;
1968 printf("%s: ", rep->re_name);
1969 mii_print_stat_speed(mii_status, mii_extstat);
1970 printf("\n");
1972 if (!(mii_status & MII_STATUS_ANC))
1973 printf("%s: auto-negotiation not complete\n", rep->re_name);
1974 if (mii_status & MII_STATUS_RF)
1975 printf("%s: remote fault detected\n", rep->re_name);
1976 if (!(mii_status & MII_STATUS_ANA))
1978 printf("%s: local PHY has no auto-negotiation ability\n",
1979 rep->re_name);
1981 if (!(mii_status & MII_STATUS_LS))
1982 printf("%s: link down\n", rep->re_name);
1983 if (mii_status & MII_STATUS_JD)
1984 printf("%s: jabber condition detected\n", rep->re_name);
1985 if (!(mii_status & MII_STATUS_EC))
1987 printf("%s: no extended register set\n", rep->re_name);
1988 goto resspeed;
1990 if (!(mii_status & MII_STATUS_ANC))
1991 goto resspeed;
1993 printf("%s: local cap.: ", rep->re_name);
1994 mii_print_techab(mii_ana);
1995 printf("\n");
1997 if (mii_ane & MII_ANE_PDF)
1998 printf("%s: parallel detection fault\n", rep->re_name);
1999 if (!(mii_ane & MII_ANE_LPANA))
2001 printf("%s: link-partner does not support auto-negotiation\n",
2002 rep->re_name);
2003 goto resspeed;
2006 printf("%s: remote cap.: ", rep->re_name);
2007 mii_print_techab(mii_anlpa);
2008 printf("\n");
2010 resspeed:
2011 printf("%s: ", rep->re_name);
2012 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
2013 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
2017 static void mii_print_techab(techab)
2018 u16_t techab;
2020 int fs, ft;
2021 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
2023 printf("strange selector 0x%x, value 0x%x",
2024 techab & MII_ANA_SEL_M,
2025 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
2026 return;
2028 fs= 1;
2029 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
2031 printf("100 Mbps: ");
2032 fs= 0;
2033 ft= 1;
2034 if (techab & MII_ANA_100T4)
2036 printf("T4");
2037 ft= 0;
2039 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
2041 if (!ft)
2042 printf(", ");
2043 ft= 0;
2044 printf("TX-");
2045 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
2047 case MII_ANA_100TXFD: printf("FD"); break;
2048 case MII_ANA_100TXHD: printf("HD"); break;
2049 default: printf("FD/HD"); break;
2053 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
2055 if (!fs)
2056 printf(", ");
2057 printf("10 Mbps: ");
2058 fs= 0;
2059 printf("T-");
2060 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
2062 case MII_ANA_10TFD: printf("FD"); break;
2063 case MII_ANA_10THD: printf("HD"); break;
2064 default: printf("FD/HD"); break;
2067 if (techab & MII_ANA_PAUSE_SYM)
2069 if (!fs)
2070 printf(", ");
2071 fs= 0;
2072 printf("pause(SYM)");
2074 if (techab & MII_ANA_PAUSE_ASYM)
2076 if (!fs)
2077 printf(", ");
2078 fs= 0;
2079 printf("pause(ASYM)");
2081 if (techab & MII_ANA_TAF_RES)
2083 if (!fs)
2084 printf(", ");
2085 fs= 0;
2086 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
2090 static void mii_print_stat_speed(stat, extstat)
2091 u16_t stat;
2092 u16_t extstat;
2094 int fs, ft;
2095 fs= 1;
2096 if (stat & MII_STATUS_EXT_STAT)
2098 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
2099 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
2101 printf("1000 Mbps: ");
2102 fs= 0;
2103 ft= 1;
2104 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
2106 ft= 0;
2107 printf("X-");
2108 switch(extstat &
2109 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
2111 case MII_ESTAT_1000XFD: printf("FD"); break;
2112 case MII_ESTAT_1000XHD: printf("HD"); break;
2113 default: printf("FD/HD"); break;
2116 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
2118 if (!ft)
2119 printf(", ");
2120 ft= 0;
2121 printf("T-");
2122 switch(extstat &
2123 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
2125 case MII_ESTAT_1000TFD: printf("FD"); break;
2126 case MII_ESTAT_1000THD: printf("HD"); break;
2127 default: printf("FD/HD"); break;
2132 if (stat & (MII_STATUS_100T4 |
2133 MII_STATUS_100XFD | MII_STATUS_100XHD |
2134 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
2136 if (!fs)
2137 printf(", ");
2138 fs= 0;
2139 printf("100 Mbps: ");
2140 ft= 1;
2141 if (stat & MII_STATUS_100T4)
2143 printf("T4");
2144 ft= 0;
2146 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
2148 if (!ft)
2149 printf(", ");
2150 ft= 0;
2151 printf("TX-");
2152 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
2154 case MII_STATUS_100XFD: printf("FD"); break;
2155 case MII_STATUS_100XHD: printf("HD"); break;
2156 default: printf("FD/HD"); break;
2159 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
2161 if (!ft)
2162 printf(", ");
2163 ft= 0;
2164 printf("T2-");
2165 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
2167 case MII_STATUS_100T2FD: printf("FD"); break;
2168 case MII_STATUS_100T2HD: printf("HD"); break;
2169 default: printf("FD/HD"); break;
2173 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
2175 if (!fs)
2176 printf(", ");
2177 printf("10 Mbps: ");
2178 fs= 0;
2179 printf("T-");
2180 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
2182 case MII_STATUS_10FD: printf("FD"); break;
2183 case MII_STATUS_10HD: printf("HD"); break;
2184 default: printf("FD/HD"); break;
2189 /*===========================================================================*
2190 * rl_clear_rx *
2191 *===========================================================================*/
2192 static void rl_clear_rx(rep)
2193 re_t *rep;
2195 port_t port;
2196 u8_t cr;
2197 int i;
2198 clock_t t0,t1;
2200 rep->re_clear_rx= FALSE;
2201 port= rep->re_base_port;
2203 /* Reset the receiver */
2204 cr= rl_inb(port, RL_CR);
2205 cr &= ~RL_CR_RE;
2206 rl_outb(port, RL_CR, cr);
2207 getuptime(&t0);
2208 do {
2209 if (!(rl_inb(port, RL_CR) & RL_CR_RE))
2210 break;
2211 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
2212 if (rl_inb(port, RL_CR) & RL_CR_RE)
2213 panic("rtl8139","cannot disable receiver", NO_NUM);
2215 #if 0
2216 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
2217 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
2218 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
2219 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
2220 #endif
2222 rl_outb(port, RL_CR, cr | RL_CR_RE);
2224 rl_outl(port, RL_RCR, RX_BUFBITS);
2226 rl_rec_mode(rep);
2228 rep->re_stat.ets_missedP++;
2231 /*===========================================================================*
2232 * rl_do_reset *
2233 *===========================================================================*/
2234 static void rl_do_reset(rep)
2235 re_t *rep;
2237 rep->re_need_reset= FALSE;
2238 rl_reset_hw(rep);
2239 rl_rec_mode(rep);
2241 rep->re_tx_head= 0;
2242 if (rep->re_flags & REF_SEND_AVAIL)
2244 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
2245 rep->re_send_int= TRUE;
2249 /*===========================================================================*
2250 * rl_getstat *
2251 *===========================================================================*/
2252 static void rl_getstat(mp)
2253 message *mp;
2255 int r, port;
2256 eth_stat_t stats;
2257 re_t *rep;
2259 port = mp->DL_PORT;
2260 if (port < 0 || port >= RE_PORT_NR)
2261 panic("rtl8139","illegal port", port);
2262 rep= &re_table[port];
2263 rep->re_client= mp->DL_PROC;
2265 assert(rep->re_mode == REM_ENABLED);
2266 assert(rep->re_flags & REF_ENABLED);
2268 stats= rep->re_stat;
2270 r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC,
2271 (vir_bytes) mp->DL_ADDR, sizeof(stats));
2272 if (r != OK)
2273 panic(__FILE__, "rl_getstat: sys_datacopy failed", r);
2274 reply(rep, OK, FALSE);
2277 /*===========================================================================*
2278 * rl_getstat_s *
2279 *===========================================================================*/
2280 static void rl_getstat_s(mp)
2281 message *mp;
2283 int r, port;
2284 eth_stat_t stats;
2285 re_t *rep;
2287 port = mp->DL_PORT;
2288 if (port < 0 || port >= RE_PORT_NR)
2289 panic("rtl8139","illegal port", port);
2290 rep= &re_table[port];
2291 rep->re_client= mp->DL_PROC;
2293 assert(rep->re_mode == REM_ENABLED);
2294 assert(rep->re_flags & REF_ENABLED);
2296 stats= rep->re_stat;
2298 r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
2299 (vir_bytes) &stats, sizeof(stats), D);
2300 if (r != OK)
2301 panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r);
2302 reply(rep, OK, FALSE);
2306 /*===========================================================================*
2307 * rl_getname *
2308 *===========================================================================*/
2309 static void rl_getname(mp)
2310 message *mp;
2312 int r;
2314 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
2315 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
2316 mp->m_type= DL_NAME_REPLY;
2317 r= send(mp->m_source, mp);
2318 if (r != OK)
2319 panic("RTL8139", "rl_getname: send failed: %d\n", r);
2323 /*===========================================================================*
2324 * reply *
2325 *===========================================================================*/
2326 static void reply(rep, err, may_block)
2327 re_t *rep;
2328 int err;
2329 int may_block;
2331 message reply;
2332 int status;
2333 int r;
2334 clock_t now;
2336 status = 0;
2337 if (rep->re_flags & REF_PACK_SENT)
2338 status |= DL_PACK_SEND;
2339 if (rep->re_flags & REF_PACK_RECV)
2340 status |= DL_PACK_RECV;
2342 reply.m_type = DL_TASK_REPLY;
2343 reply.DL_PORT = rep - re_table;
2344 reply.DL_PROC = rep->re_client;
2345 reply.DL_STAT = status | ((u32_t) err << 16);
2346 reply.DL_COUNT = rep->re_read_s;
2347 if (OK != (r = getuptime(&now)))
2348 panic("rtl8139","getuptime() failed:", r);
2349 reply.DL_CLCK = now;
2351 r= send(rep->re_client, &reply);
2353 if (r == ELOCKED && may_block)
2355 #if 0
2356 printW(); printf("send locked\n");
2357 #endif
2358 return;
2361 if (r < 0) {
2362 printf("RTL8139 tried sending to %d, type %d\n", rep->re_client, reply.m_type);
2363 panic("rtl8139","send failed:", r);
2366 rep->re_read_s = 0;
2367 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
2370 /*===========================================================================*
2371 * mess_reply *
2372 *===========================================================================*/
2373 static void mess_reply(req, reply_mess)
2374 message *req;
2375 message *reply_mess;
2377 if (send(req->m_source, reply_mess) != OK)
2378 panic("rtl8139","unable to mess_reply", NO_NUM);
2381 #if 0
2382 static void dump_phy(rep)
2383 re_t *rep;
2385 port_t port;
2386 u32_t t;
2388 port= rep->re_base_port;
2390 t= rl_inb(port, RL_MSR);
2391 printf("MSR: 0x%02lx\n", t);
2392 if (t & RL_MSR_SPEED_10)
2393 printf("\t10 Mbps\n");
2394 if (t & RL_MSR_LINKB)
2395 printf("\tLink failed\n");
2397 t= rl_inb(port, RL_CONFIG1);
2398 printf("CONFIG1: 0x%02lx\n", t);
2400 t= rl_inb(port, RL_CONFIG3);
2401 printf("CONFIG3: 0x%02lx\n", t);
2403 t= rl_inb(port, RL_CONFIG4);
2404 printf("CONFIG4: 0x%02lx\n", t);
2406 t= rl_inw(port, RL_BMCR);
2407 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
2409 t= rl_inw(port, RL_BMSR);
2410 printf("BMSR:");
2411 if (t & MII_STATUS_100T4)
2412 printf(" 100Base-T4");
2413 if (t & MII_STATUS_100XFD)
2414 printf(" 100Base-X-FD");
2415 if (t & MII_STATUS_100XHD)
2416 printf(" 100Base-X-HD");
2417 if (t & MII_STATUS_10FD)
2418 printf(" 10Mbps-FD");
2419 if (t & MII_STATUS_10HD)
2420 printf(" 10Mbps-HD");
2421 if (t & MII_STATUS_100T2FD)
2422 printf(" 100Base-T2-FD");
2423 if (t & MII_STATUS_100T2HD)
2424 printf(" 100Base-T2-HD");
2425 if (t & MII_STATUS_EXT_STAT)
2426 printf(" Ext-stat");
2427 if (t & MII_STATUS_RES)
2428 printf(" res-0x%lx", t & MII_STATUS_RES);
2429 if (t & MII_STATUS_MFPS)
2430 printf(" MFPS");
2431 if (t & MII_STATUS_ANC)
2432 printf(" ANC");
2433 if (t & MII_STATUS_RF)
2434 printf(" remote-fault");
2435 if (t & MII_STATUS_ANA)
2436 printf(" ANA");
2437 if (t & MII_STATUS_LS)
2438 printf(" Link");
2439 if (t & MII_STATUS_JD)
2440 printf(" Jabber");
2441 if (t & MII_STATUS_EC)
2442 printf(" Extended-capability");
2443 printf("\n");
2445 t= rl_inw(port, RL_ANAR);
2446 printf("ANAR (MII_ANA): 0x%04lx\n", t);
2448 t= rl_inw(port, RL_ANLPAR);
2449 printf("ANLPAR: 0x%04lx\n", t);
2451 t= rl_inw(port, RL_ANER);
2452 printf("ANER (MII_ANE): ");
2453 if (t & MII_ANE_RES)
2454 printf(" res-0x%lx", t & MII_ANE_RES);
2455 if (t & MII_ANE_PDF)
2456 printf(" Par-Detect-Fault");
2457 if (t & MII_ANE_LPNPA)
2458 printf(" LP-Next-Page-Able");
2459 if (t & MII_ANE_NPA)
2460 printf(" Loc-Next-Page-Able");
2461 if (t & MII_ANE_PR)
2462 printf(" Page-Received");
2463 if (t & MII_ANE_LPANA)
2464 printf(" LP-Auto-Neg-Able");
2465 printf("\n");
2467 t= rl_inw(port, RL_NWAYTR);
2468 printf("NWAYTR: 0x%04lx\n", t);
2469 t= rl_inw(port, RL_CSCR);
2470 printf("CSCR: 0x%04lx\n", t);
2472 t= rl_inb(port, RL_CONFIG5);
2473 printf("CONFIG5: 0x%02lx\n", t);
2475 #endif
2477 static int do_hard_int(void)
2479 int i,s;
2481 for (i=0; i < RE_PORT_NR; i ++) {
2483 /* Run interrupt handler at driver level. */
2484 rl_handler( &re_table[i]);
2486 /* Reenable interrupts for this hook. */
2487 if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK)
2488 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
2492 /*===========================================================================*
2493 * rl_handler *
2494 *===========================================================================*/
2495 static int rl_handler(rep)
2496 re_t *rep;
2498 int i, port, tx_head, tx_tail, link_up;
2499 u16_t isr, tsad;
2500 u32_t tsd, tcr, ertxth;
2501 #if 0
2502 u8_t cr;
2503 #endif
2504 clock_t t0,t1;
2505 int_event_check = FALSE; /* disable check by default */
2507 port= rep->re_base_port;
2509 /* Ack interrupt */
2510 isr= rl_inw(port, RL_ISR);
2511 rl_outw(port, RL_ISR, isr);
2513 if (isr & RL_IMR_FOVW)
2515 isr &= ~RL_IMR_FOVW;
2516 /* Should do anything? */
2518 rep->re_stat.ets_fifoOver++;
2520 if (isr & RL_IMR_PUN)
2522 isr &= ~RL_IMR_PUN;
2524 /* Either the link status changed or there was a TX fifo
2525 * underrun.
2527 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
2528 if (link_up != rep->re_link_up)
2530 rep->re_report_link= TRUE;
2531 rep->re_got_int= TRUE;
2532 int_event_check = TRUE;
2535 if (isr & RL_IMR_RXOVW)
2537 isr &= ~RL_IMR_RXOVW;
2539 /* Clear the receive buffer */
2540 rep->re_clear_rx= TRUE;
2541 rep->re_got_int= TRUE;
2542 int_event_check = TRUE;
2545 if (isr & (RL_ISR_RER | RL_ISR_ROK))
2547 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
2549 if (!rep->re_got_int && (rep->re_flags & REF_READING))
2551 rep->re_got_int= TRUE;
2552 int_event_check = TRUE;
2555 #if 0
2556 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
2557 (rep->re_flags & REF_SEND_AVAIL) &&
2558 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
2559 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
2562 printf(
2563 "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2564 rep->re_tx_head, rep->re_tx_tail,
2565 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2566 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2567 printf(
2568 "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2569 rl_inw(port, RL_TSAD),
2570 rl_inl(port, RL_TSD0+0*4),
2571 rl_inl(port, RL_TSD0+1*4),
2572 rl_inl(port, RL_TSD0+2*4),
2573 rl_inl(port, RL_TSD0+3*4));
2575 #endif
2576 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
2578 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
2580 tsad= rl_inw(port, RL_TSAD);
2581 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
2582 RL_TSAD_TABT2|RL_TSAD_TABT3))
2584 #if 0
2585 /* Do we need a watch dog? */
2586 /* Just reset the whole chip */
2587 rep->re_need_reset= TRUE;
2588 rep->re_got_int= TRUE;
2589 int_event_check = TRUE;
2590 #elif 0
2591 /* Reset transmitter */
2592 rep->re_stat.ets_transAb++;
2594 cr= rl_inb(port, RL_CR);
2595 cr &= ~RL_CR_TE;
2596 rl_outb(port, RL_CR, cr);
2597 getuptime(&t0);
2598 do {
2599 if (!(rl_inb(port, RL_CR) & RL_CR_TE))
2600 break;
2601 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
2602 if (rl_inb(port, RL_CR) & RL_CR_TE)
2604 panic("rtl8139","cannot disable transmitter",
2605 NO_NUM);
2607 rl_outb(port, RL_CR, cr | RL_CR_TE);
2609 tcr= rl_inl(port, RL_TCR);
2610 rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
2612 printf("rl_handler: reset after abort\n");
2614 if (rep->re_flags & REF_SEND_AVAIL)
2616 printf("rl_handler: REF_SEND_AVAIL\n");
2617 rep->re_send_int= TRUE;
2618 rep->re_got_int= TRUE;
2619 int_event_check = TRUE;
2621 for (i= 0; i< N_TX_BUF; i++)
2622 rep->re_tx[i].ret_busy= FALSE;
2623 rep->re_tx_head= 0;
2624 #else
2625 printf("rl_handler, TABT, tasd = 0x%04x\n",
2626 tsad);
2628 /* Find the aborted transmit request */
2629 for (i= 0; i< N_TX_BUF; i++)
2631 tsd= rl_inl(port, RL_TSD0+i*4);
2632 if (tsd & RL_TSD_TABT)
2633 break;
2635 if (i >= N_TX_BUF)
2637 printf(
2638 "rl_handler: can't find aborted TX req.\n");
2640 else
2642 printf("TSD%d = 0x%04lx\n", i, tsd);
2644 /* Set head and tail to this buffer */
2645 rep->re_tx_head= rep->re_tx_tail= i;
2648 /* Aborted transmission, just kick the device
2649 * and be done with it.
2651 rep->re_stat.ets_transAb++;
2652 tcr= rl_inl(port, RL_TCR);
2653 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2654 #endif
2657 /* Transmit completed */
2658 tx_head= rep->re_tx_head;
2659 tx_tail= rep->re_tx_tail;
2660 for (i= 0; i< 2*N_TX_BUF; i++)
2662 if (!rep->re_tx[tx_tail].ret_busy)
2664 /* Strange, this buffer is not in-use.
2665 * Increment tx_tail until tx_head is
2666 * reached (or until we find a buffer that
2667 * is in-use.
2669 if (tx_tail == tx_head)
2670 break;
2671 if (++tx_tail >= N_TX_BUF)
2672 tx_tail= 0;
2673 assert(tx_tail < RL_N_TX);
2674 rep->re_tx_tail= tx_tail;
2675 continue;
2677 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
2678 if (!(tsd & RL_TSD_OWN))
2680 /* Buffer is not yet ready */
2681 break;
2684 /* Should collect statistics */
2685 if (tsd & RL_TSD_CRS)
2686 rep->re_stat.ets_carrSense++;
2687 if (tsd & RL_TSD_TABT)
2689 printf("rl_handler, TABT, TSD%d = 0x%04lx\n",
2690 tx_tail, tsd);
2691 assert(0); /* CLRABT is not all that
2692 * effective, why not?
2694 rep->re_stat.ets_transAb++;
2695 tcr= rl_inl(port, RL_TCR);
2696 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2698 if (tsd & RL_TSD_OWC)
2699 rep->re_stat.ets_OWC++;
2700 if (tsd & RL_TSD_CDH)
2701 rep->re_stat.ets_CDheartbeat++;
2703 /* What about collisions? */
2704 if (tsd & RL_TSD_TOK)
2705 rep->re_stat.ets_packetT++;
2706 else
2707 rep->re_stat.ets_sendErr++;
2708 if (tsd & RL_TSD_TUN)
2710 rep->re_stat.ets_fifoUnder++;
2712 /* Increase ERTXTH */
2713 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
2714 ertxth &= RL_TSD_ERTXTH_M;
2715 if (debug && ertxth > rep->re_ertxth)
2717 printf("%s: new ertxth: %ld bytes\n",
2718 rep->re_name,
2719 (ertxth >> RL_TSD_ERTXTH_S) *
2720 32);
2721 rep->re_ertxth= ertxth;
2724 rep->re_tx[tx_tail].ret_busy= FALSE;
2726 #if 0
2727 if (rep->re_flags & REF_SEND_AVAIL)
2729 printf("TSD%d: %08lx\n", tx_tail, tsd);
2730 printf(
2731 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
2732 tx_head, tx_tail,
2733 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2734 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2736 #endif
2738 if (++tx_tail >= N_TX_BUF)
2739 tx_tail= 0;
2740 assert(tx_tail < RL_N_TX);
2741 rep->re_tx_tail= tx_tail;
2743 if (rep->re_flags & REF_SEND_AVAIL)
2745 #if 0
2746 printf("rl_handler: REF_SEND_AVAIL\n");
2747 #endif
2748 rep->re_send_int= TRUE;
2749 if (!rep->re_got_int)
2751 rep->re_got_int= TRUE;
2752 int_event_check = TRUE;
2756 assert(i < 2*N_TX_BUF);
2758 if (isr)
2760 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
2761 isr);
2764 return 1;
2767 /*===========================================================================*
2768 * rl_watchdog_f *
2769 *===========================================================================*/
2770 static void rl_watchdog_f(tp)
2771 timer_t *tp;
2773 int i;
2774 re_t *rep;
2775 /* Use a synchronous alarm instead of a watchdog timer. */
2776 sys_setalarm(HZ, 0);
2778 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
2780 if (rep->re_mode != REM_ENABLED)
2781 continue;
2782 if (!(rep->re_flags & REF_SEND_AVAIL))
2784 /* Assume that an idle system is alive */
2785 rep->re_tx_alive= TRUE;
2786 continue;
2788 if (rep->re_tx_alive)
2790 rep->re_tx_alive= FALSE;
2791 continue;
2793 printf("rl_watchdog_f: resetting port %d\n", i);
2794 printf(
2795 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2796 rl_inw(rep->re_base_port, RL_TSAD),
2797 rl_inl(rep->re_base_port, RL_TSD0+0*4),
2798 rl_inl(rep->re_base_port, RL_TSD0+1*4),
2799 rl_inl(rep->re_base_port, RL_TSD0+2*4),
2800 rl_inl(rep->re_base_port, RL_TSD0+3*4));
2801 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2802 rep->re_tx_head, rep->re_tx_tail,
2803 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2804 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2805 rep->re_need_reset= TRUE;
2806 rep->re_got_int= TRUE;
2808 check_int_events();
2812 #if 0
2814 _PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
2815 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
2816 _PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
2817 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );
2818 _PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
2820 static void rtl_init(dep)
2821 dpeth_t *dep;
2823 u8_t reg_a, reg_b, cr, config0, config2, config3;
2824 int i;
2825 char val[128];
2827 printf("rtl_init called\n");
2828 ne_init(dep);
2830 /* ID */
2831 outb_reg0(dep, DP_CR, CR_PS_P0);
2832 reg_a = inb_reg0(dep, DP_DUM1);
2833 reg_b = inb_reg0(dep, DP_DUM2);
2835 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
2837 outb_reg0(dep, DP_CR, CR_PS_P3);
2838 config0 = inb_reg3(dep, 3);
2839 config2 = inb_reg3(dep, 5);
2840 config3 = inb_reg3(dep, 6);
2841 outb_reg0(dep, DP_CR, CR_PS_P0);
2843 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
2844 config0, config2, config3);
2846 if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
2848 printf("rtl_init: setting full-duplex mode\n");
2849 outb_reg0(dep, DP_CR, CR_PS_P3);
2851 cr= inb_reg3(dep, 1);
2852 outb_reg3(dep, 1, cr | 0xc0);
2854 outb_reg3(dep, 6, config3 | 0x40);
2855 config3 = inb_reg3(dep, 6);
2857 config2= inb_reg3(dep, 5);
2858 outb_reg3(dep, 5, config2 | 0x20);
2859 config2= inb_reg3(dep, 5);
2861 outb_reg3(dep, 1, cr);
2863 outb_reg0(dep, DP_CR, CR_PS_P0);
2865 printf("rtl_init: config 2 = %x\n", config2);
2866 printf("rtl_init: config 3 = %x\n", config3);
2869 for (i= 0; i<64; i++)
2870 printf("%x ", get_ee_word(dep, i));
2871 printf("\n");
2873 if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
2875 ee_wen(dep);
2877 set_ee_word(dep, 0x78/2, 0x10ec);
2878 set_ee_word(dep, 0x7A/2, 0x8029);
2879 set_ee_word(dep, 0x7C/2, 0x10ec);
2880 set_ee_word(dep, 0x7E/2, 0x8029);
2882 ee_wds(dep);
2884 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
2885 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
2886 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
2887 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
2890 if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
2892 ee_wen(dep);
2894 set_ee_word(dep, 0x76/2, 0x8029);
2896 ee_wds(dep);
2898 assert(get_ee_word(dep, 0x76/2) == 0x8029);
2902 static u16_t get_ee_word(dep, a)
2903 dpeth_t *dep;
2904 int a;
2906 int b, i, cmd;
2907 u16_t w;
2909 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2911 /* Switch to 9346 mode and enable CS */
2912 outb_reg3(dep, 1, 0x80 | 0x8);
2914 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
2915 for (i= 8; i >= 0; i--)
2917 b= (cmd & (1 << i));
2918 b= (b ? 2 : 0);
2920 /* Cmd goes out on the rising edge of the clock */
2921 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2922 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2924 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2926 w= 0;
2927 for (i= 0; i<16; i++)
2929 w <<= 1;
2931 /* Data is shifted out on the rising edge. Read at the
2932 * falling edge.
2934 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
2935 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2936 b= inb_reg3(dep, 1);
2937 w |= (b & 1);
2940 outb_reg3(dep, 1, 0x80); /* drop CS */
2941 outb_reg3(dep, 1, 0x00); /* back to normal */
2942 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2944 return w;
2947 static void ee_wen(dep)
2948 dpeth_t *dep;
2950 int b, i, cmd;
2951 u16_t w;
2953 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2955 /* Switch to 9346 mode and enable CS */
2956 outb_reg3(dep, 1, 0x80 | 0x8);
2958 cmd= 0x130; /* 1 0 0 1 1 x x x x */
2959 for (i= 8; i >= 0; i--)
2961 b= (cmd & (1 << i));
2962 b= (b ? 2 : 0);
2964 /* Cmd goes out on the rising edge of the clock */
2965 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2966 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2968 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2969 outb_reg3(dep, 1, 0x80); /* Drop CS */
2970 /* micro_delay(1); */ /* Is this required? */
2973 static void set_ee_word(dep, a, w)
2974 dpeth_t *dep;
2975 int a;
2976 u16_t w;
2978 int b, i, cmd;
2979 clock_t t0, t1;
2981 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2983 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
2984 for (i= 8; i >= 0; i--)
2986 b= (cmd & (1 << i));
2987 b= (b ? 2 : 0);
2989 /* Cmd goes out on the rising edge of the clock */
2990 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2991 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2993 for (i= 15; i >= 0; i--)
2995 b= (w & (1 << i));
2996 b= (b ? 2 : 0);
2998 /* Cmd goes out on the rising edge of the clock */
2999 outb_reg3(dep, 1, 0x80 | 0x8 | b);
3000 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
3002 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
3003 outb_reg3(dep, 1, 0x80); /* Drop CS */
3004 /* micro_delay(1); */ /* Is this required? */
3005 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
3006 getuptime(&t0);
3007 do {
3008 if (inb_reg3(dep, 1) & 1)
3009 break;
3010 } while (getuptime(&t1) == OK && (t1 == t0));
3011 if (!(inb_reg3(dep, 1) & 1))
3012 panic("set_ee_word","device remains busy", NO_NUM);
3015 static void ee_wds(dep)
3016 dpeth_t *dep;
3018 int b, i, cmd;
3019 u16_t w;
3021 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
3023 /* Switch to 9346 mode and enable CS */
3024 outb_reg3(dep, 1, 0x80 | 0x8);
3026 cmd= 0x100; /* 1 0 0 0 0 x x x x */
3027 for (i= 8; i >= 0; i--)
3029 b= (cmd & (1 << i));
3030 b= (b ? 2 : 0);
3032 /* Cmd goes out on the rising edge of the clock */
3033 outb_reg3(dep, 1, 0x80 | 0x8 | b);
3034 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
3036 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
3037 outb_reg3(dep, 1, 0x80); /* Drop CS */
3038 outb_reg3(dep, 1, 0x00); /* back to normal */
3039 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
3041 #endif
3044 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $