dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / rtl8139 / rtl8139.c
blobd1dc60e135c4128d941f0e1567083ce2994e9986
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_PORT 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 * m_type DL_PORT DL_STAT
47 * |------------|---------|-----------|
48 * |DL_STAT_REPL| port nr | err |
49 * |------------|---------|-----------|
51 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
52 * Changes:
53 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
54 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
58 #define RTL8139_FKEY 0 /* Use function key to dump RTL8139 status */
60 #include "rtl8139.h"
62 PRIVATE struct pcitab
64 u16_t vid;
65 u16_t did;
66 int checkclass;
67 } pcitab[]=
69 { 0x10ec, 0x8139, 0 }, /* Realtek RTL8139 */
71 /* Alternative IDs */
72 { 0x02ac, 0x1012, 0 }, /* SpeedStream 1012 PCMCIA 10/100 */
73 { 0x1065, 0x8139, 0 }, /* Texas Microsystems 8139C Network Card */
74 { 0x1113, 0x1211, 0 }, /* Accton MPX5030 or SMC1211TX EZCard 10/100 */
75 { 0x1186, 0x1300, 0 }, /* D-Link DFE530TX+/DFE538TX */
76 { 0x1186, 0x1340, 0 }, /* D-Link DFE690TXD */
77 { 0x11db, 0x1234, 0 }, /* Sega Dreamcast HIT-400 */
78 { 0x1259, 0xa117, 0 }, /* Allied Telesyn 8139 */
79 { 0x1259, 0xa11e, 0 }, /* Allied Telesyn 8139 */
80 { 0x126c, 0x1211, 0 }, /* Northern Telecom 10/100BaseTX*/
81 { 0x13d1, 0xab06, 0 }, /* AboCom FE2000VX */
82 { 0x1432, 0x9130, 0 }, /* Edimax Computer Co. RTL81xx */
83 { 0x14ea, 0xab06, 0 }, /* Planex FNW-3603-TX */
84 { 0x14ea, 0xab07, 0 }, /* Planex FNW-3800-TX */
85 { 0x1500, 0x1360, 0 }, /* Delta Electronics RealTek Ethernet */
86 { 0x1743, 0x8139, 0 }, /* Peppercon AG 8139 ROL/F-100 */
87 { 0x4033, 0x1360, 0 }, /* Addtron Technology 8139 */
89 { 0x0000, 0x0000, 0 }
92 PUBLIC re_t re_table[RE_PORT_NR];
94 static u16_t eth_ign_proto;
95 static tmra_ut rl_watchdog;
97 FORWARD _PROTOTYPE( unsigned my_inb, (U16_t port) );
98 FORWARD _PROTOTYPE( unsigned my_inw, (U16_t port) );
99 FORWARD _PROTOTYPE( unsigned my_inl, (U16_t port) );
100 static unsigned my_inb(U16_t port) {
101 u32_t value;
102 int s;
103 if ((s=sys_inb(port, &value)) !=OK)
104 printf("RTL8139: warning, sys_inb failed: %d\n", s);
105 return value;
107 static unsigned my_inw(U16_t port) {
108 u32_t value;
109 int s;
110 if ((s=sys_inw(port, &value)) !=OK)
111 printf("RTL8139: warning, sys_inw failed: %d\n", s);
112 return value;
114 static unsigned my_inl(U16_t port) {
115 U32_t value;
116 int s;
117 if ((s=sys_inl(port, &value)) !=OK)
118 printf("RTL8139: warning, sys_inl failed: %d\n", s);
119 return value;
121 #define rl_inb(port, offset) (my_inb((port) + (offset)))
122 #define rl_inw(port, offset) (my_inw((port) + (offset)))
123 #define rl_inl(port, offset) (my_inl((port) + (offset)))
125 FORWARD _PROTOTYPE( void my_outb, (U16_t port, U8_t value) );
126 FORWARD _PROTOTYPE( void my_outw, (U16_t port, U16_t value) );
127 FORWARD _PROTOTYPE( void my_outl, (U16_t port, U32_t value) );
128 static void my_outb(U16_t port, U8_t value) {
129 int s;
130 if ((s=sys_outb(port, value)) !=OK)
131 printf("RTL8139: warning, sys_outb failed: %d\n", s);
133 static void my_outw(U16_t port, U16_t value) {
134 int s;
135 if ((s=sys_outw(port, value)) !=OK)
136 printf("RTL8139: warning, sys_outw failed: %d\n", s);
138 static void my_outl(U16_t port, U32_t value) {
139 int s;
140 if ((s=sys_outl(port, value)) !=OK)
141 printf("RTL8139: warning, sys_outl failed: %d\n", s);
143 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
144 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
145 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
147 _PROTOTYPE( static void rl_init, (message *mp) );
148 _PROTOTYPE( static void rl_pci_conf, (void) );
149 _PROTOTYPE( static int rl_probe, (re_t *rep) );
150 _PROTOTYPE( static void rl_conf_hw, (re_t *rep) );
151 _PROTOTYPE( static void rl_init_buf, (re_t *rep) );
152 _PROTOTYPE( static void rl_init_hw, (re_t *rep) );
153 _PROTOTYPE( static void rl_reset_hw, (re_t *rep) );
154 _PROTOTYPE( static void rl_confaddr, (re_t *rep) );
155 _PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
156 _PROTOTYPE( static void rl_readv, (message *mp, int from_int,
157 int vectored) );
158 _PROTOTYPE( static void rl_readv_s, (message *mp, int from_int) );
159 _PROTOTYPE( static void rl_writev, (message *mp, int from_int,
160 int vectored) );
161 _PROTOTYPE( static void rl_writev_s, (message *mp, int from_int) );
162 _PROTOTYPE( static void rl_check_ints, (re_t *rep) );
163 _PROTOTYPE( static void rl_report_link, (re_t *rep) );
164 _PROTOTYPE( static void mii_print_techab, (U16_t techab) );
165 _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
166 U16_t extstat) );
167 _PROTOTYPE( static void rl_clear_rx, (re_t *rep) );
168 _PROTOTYPE( static void rl_do_reset, (re_t *rep) );
169 _PROTOTYPE( static void rl_getstat, (message *mp) );
170 _PROTOTYPE( static void rl_getstat_s, (message *mp) );
171 _PROTOTYPE( static void rl_getname, (message *mp) );
172 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
173 _PROTOTYPE( static void mess_reply, (message *req, message *reply) );
174 _PROTOTYPE( static void rtl8139_stop, (void) );
175 _PROTOTYPE( static void check_int_events, (void) );
176 _PROTOTYPE( static int do_hard_int, (void) );
177 _PROTOTYPE( static void rtl8139_dump, (message *m) );
178 #if 0
179 _PROTOTYPE( static void dump_phy, (re_t *rep) );
180 #endif
181 _PROTOTYPE( static int rl_handler, (re_t *rep) );
182 _PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) );
183 _PROTOTYPE( static void tell_dev, (vir_bytes start, size_t size,
184 int pci_bus, int pci_dev, int pci_func) );
186 /* The message used in the main loop is made global, so that rl_watchdog_f()
187 * can change its message type to fake an interrupt message.
189 PRIVATE message m;
190 PRIVATE int int_event_check; /* set to TRUE if events arrived */
192 static char *progname;
193 extern int errno;
194 u32_t system_hz;
196 /* SEF functions and variables. */
197 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
198 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
199 EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
200 EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
201 EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
202 EXTERN int env_argc;
203 EXTERN char **env_argv;
205 /*===========================================================================*
206 * main *
207 *===========================================================================*/
208 int main(int argc, char *argv[])
210 int r;
212 /* SEF local startup. */
213 env_setargs(argc, argv);
214 sef_local_startup();
216 while (TRUE)
218 if ((r= sef_receive(ANY, &m)) != OK)
219 panic("rtl8139","sef_receive failed", r);
221 if (is_notify(m.m_type)) {
222 switch (_ENDPOINT_P(m.m_source)) {
223 case CLOCK:
225 * Under MINIX, synchronous alarms are
226 * used instead of watchdog functions.
227 * The approach is very different: MINIX
228 * VMD timeouts are handled within the
229 * kernel (the watchdog is executed by
230 * CLOCK), and notify() the driver in
231 * some cases. MINIX timeouts result in
232 * a SYN_ALARM message to the driver and
233 * thus are handled where they should be
234 * handled. Locally, watchdog functions
235 * are used again.
237 rl_watchdog_f(NULL);
238 break;
239 case HARDWARE:
240 do_hard_int();
241 if (int_event_check)
242 check_int_events();
243 break ;
244 case TTY_PROC_NR:
245 rtl8139_dump(&m);
246 break;
247 case PM_PROC_NR:
249 sigset_t set;
251 if (getsigset(&set) != 0) break;
253 if (sigismember(&set, SIGTERM))
254 rtl8139_stop();
256 break;
258 default:
259 panic("rtl8139","illegal notify from",
260 m.m_source);
263 /* done, get nwe message */
264 continue;
267 switch (m.m_type)
269 case DL_WRITE: rl_writev(&m, FALSE, FALSE); break;
270 case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
271 case DL_WRITEV_S: rl_writev_s(&m, FALSE); break;
272 case DL_READ: rl_readv(&m, FALSE, FALSE); break;
273 case DL_READV: rl_readv(&m, FALSE, TRUE); break;
274 case DL_READV_S: rl_readv_s(&m, FALSE); break;
275 case DL_CONF: rl_init(&m); break;
276 case DL_GETSTAT: rl_getstat(&m); break;
277 case DL_GETSTAT_S: rl_getstat_s(&m); break;
278 case DL_GETNAME: rl_getname(&m); break;
279 #if 0
280 case DL_STOP: do_stop(&m); break;
281 #endif
282 default:
283 panic("rtl8139","illegal message", m.m_type);
288 /*===========================================================================*
289 * sef_local_startup *
290 *===========================================================================*/
291 PRIVATE void sef_local_startup()
293 /* Register init callbacks. */
294 sef_setcb_init_fresh(sef_cb_init_fresh);
295 sef_setcb_init_lu(sef_cb_init_fresh);
296 sef_setcb_init_restart(sef_cb_init_fresh);
298 /* Register live update callbacks. */
299 sef_setcb_lu_prepare(sef_cb_lu_prepare);
300 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
301 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
303 /* Let SEF perform startup. */
304 sef_startup();
307 /*===========================================================================*
308 * sef_cb_init_fresh *
309 *===========================================================================*/
310 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
312 /* Initialize the rtl8139 driver. */
313 #if RTL8139_FKEY
314 int fkeys, sfkeys;
315 #endif
316 u32_t inet_proc_nr;
317 int r;
318 re_t *rep;
319 long v;
321 system_hz = sys_hz();
323 (progname=strrchr(env_argv[0],'/')) ? progname++
324 : (progname=env_argv[0]);
326 v= 0;
327 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
328 eth_ign_proto= htons((u16_t) v);
330 #if RTL8139_FKEY
331 /* Observe some function key for debug dumps. */
332 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
333 if ((r=fkey_map(&fkeys, &sfkeys)) != OK)
334 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
335 #endif
337 /* Claim buffer memory now under Minix, before MM takes it all. */
338 for (rep= &re_table[0]; rep < re_table+RE_PORT_NR; rep++)
339 rl_init_buf(rep);
341 /* Try to notify INET that we are present (again). If INET cannot
342 * be found, assume this is the first time we started and INET is
343 * not yet alive.
345 r= ds_retrieve_label_num("inet", &inet_proc_nr);
346 if (r == OK)
347 notify(inet_proc_nr);
348 else if (r != ESRCH)
349 printf("rtl8139: ds_retrieve_label_num failed for 'inet': %d\n",
352 return(OK);
355 /*===========================================================================*
356 * check_int_events *
357 *===========================================================================*/
358 static void check_int_events(void)
360 int i;
361 re_t *rep;
362 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
364 if (rep->re_mode != REM_ENABLED)
365 continue;
366 if (!rep->re_got_int)
367 continue;
368 rep->re_got_int= 0;
369 assert(rep->re_flags & REF_ENABLED);
370 rl_check_ints(rep);
374 /*===========================================================================*
375 * rtl8139_stop *
376 *===========================================================================*/
377 static void rtl8139_stop()
379 int i;
380 re_t *rep;
382 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
384 if (rep->re_mode != REM_ENABLED)
385 continue;
386 rl_outb(rep->re_base_port, RL_CR, 0);
388 exit(0);
391 /*===========================================================================*
392 * rtl8139_dump *
393 *===========================================================================*/
394 static void rtl8139_dump(m)
395 message *m; /* pointer to request message */
397 re_t *rep;
398 int i;
400 printf("\n");
401 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
403 if (rep->re_mode == REM_DISABLED)
404 printf("Realtek RTL 8139 port %d is disabled\n", i);
406 if (rep->re_mode != REM_ENABLED)
407 continue;
409 printf("Realtek RTL 8139 statistics of port %d:\n", i);
411 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
412 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
413 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
415 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
416 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
417 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
419 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
420 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
421 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
423 printf("collision :%8ld\t", rep->re_stat.ets_collision);
424 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
425 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
427 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
428 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
429 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
431 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
433 printf("re_flags = 0x%x\n", rep->re_flags);
435 printf(
436 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
437 rl_inw(rep->re_base_port, RL_TSAD),
438 rl_inl(rep->re_base_port, RL_TSD0+0*4),
439 rl_inl(rep->re_base_port, RL_TSD0+1*4),
440 rl_inl(rep->re_base_port, RL_TSD0+2*4),
441 rl_inl(rep->re_base_port, RL_TSD0+3*4));
442 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
443 rep->re_tx_head, rep->re_tx_tail,
444 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
445 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
449 /*===========================================================================*
450 * do_init *
451 *===========================================================================*/
452 static void rl_init(mp)
453 message *mp;
455 static int first_time= 1;
457 int port;
458 re_t *rep;
459 message reply_mess;
461 if (first_time)
463 first_time= 0;
464 rl_pci_conf(); /* Configure PCI devices. */
466 tmra_inittimer(&rl_watchdog);
467 /* Use a synchronous alarm instead of a watchdog timer. */
468 sys_setalarm(system_hz, 0);
471 port = mp->DL_PORT;
472 if (port < 0 || port >= RE_PORT_NR)
474 reply_mess.m_type= DL_CONF_REPLY;
475 reply_mess.m3_i1= ENXIO;
476 mess_reply(mp, &reply_mess);
477 return;
479 rep= &re_table[port];
480 if (rep->re_mode == REM_DISABLED)
482 /* This is the default, try to (re)locate the device. */
483 rl_conf_hw(rep);
484 if (rep->re_mode == REM_DISABLED)
486 /* Probe failed, or the device is configured off. */
487 reply_mess.m_type= DL_CONF_REPLY;
488 reply_mess.m3_i1= ENXIO;
489 mess_reply(mp, &reply_mess);
490 return;
492 if (rep->re_mode == REM_ENABLED)
493 rl_init_hw(rep);
494 #if VERBOSE /* load silently ... can always check status later */
495 rl_report_link(rep);
496 #endif
499 assert(rep->re_mode == REM_ENABLED);
500 assert(rep->re_flags & REF_ENABLED);
502 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
504 if (mp->DL_MODE & DL_PROMISC_REQ)
505 rep->re_flags |= REF_PROMISC;
506 if (mp->DL_MODE & DL_MULTI_REQ)
507 rep->re_flags |= REF_MULTI;
508 if (mp->DL_MODE & DL_BROAD_REQ)
509 rep->re_flags |= REF_BROAD;
511 rep->re_client = mp->m_source;
512 rl_rec_mode(rep);
514 reply_mess.m_type = DL_CONF_REPLY;
515 reply_mess.m3_i1 = mp->DL_PORT;
516 reply_mess.m3_i2 = RE_PORT_NR;
517 *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
519 mess_reply(mp, &reply_mess);
522 /*===========================================================================*
523 * rl_pci_conf *
524 *===========================================================================*/
525 static void rl_pci_conf()
527 int i, h;
528 re_t *rep;
529 static char envvar[] = RL_ENVVAR "#";
530 static char envfmt[] = "*:d.d.d";
531 static char val[128];
532 long v;
534 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
536 strcpy(rep->re_name, "rtl8139#0");
537 rep->re_name[8] += i;
538 rep->re_seen= FALSE;
539 envvar[sizeof(RL_ENVVAR)-1]= '0'+i;
540 if (0 == env_get_param(envvar, val, sizeof(val)) &&
541 ! env_prefix(envvar, "pci")) {
542 env_panic(envvar);
544 v= 0;
545 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
546 rep->re_pcibus= v;
547 v= 0;
548 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
549 rep->re_pcidev= v;
550 v= 0;
551 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
552 rep->re_pcifunc= v;
555 pci_init();
557 for (h= 1; h >= 0; h--) {
558 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
560 if (((rep->re_pcibus | rep->re_pcidev |
561 rep->re_pcifunc) != 0) != h)
563 continue;
565 if (rl_probe(rep))
566 rep->re_seen= TRUE;
571 /*===========================================================================*
572 * rl_probe *
573 *===========================================================================*/
574 static int rl_probe(rep)
575 re_t *rep;
577 int i, r, devind, just_one;
578 u16_t vid, did;
579 u32_t bar;
580 u8_t ilr;
581 char *dname;
583 if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0)
585 /* Look for specific PCI device */
586 r= pci_find_dev(rep->re_pcibus, rep->re_pcidev,
587 rep->re_pcifunc, &devind);
588 if (r == 0)
590 printf("%s: no PCI found at %d.%d.%d\n",
591 rep->re_name, rep->re_pcibus,
592 rep->re_pcidev, rep->re_pcifunc);
593 return 0;
595 pci_ids(devind, &vid, &did);
596 just_one= TRUE;
598 else
600 r= pci_first_dev(&devind, &vid, &did);
601 if (r == 0)
602 return 0;
603 just_one= FALSE;
606 for(;;)
608 for (i= 0; pcitab[i].vid != 0; i++)
610 if (pcitab[i].vid != vid)
611 continue;
612 if (pcitab[i].did != did)
613 continue;
614 if (pcitab[i].checkclass)
616 panic("rtl_probe",
617 "class check not implemented", NO_NUM);
619 break;
621 if (pcitab[i].vid != 0)
622 break;
624 if (just_one)
626 printf(
627 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
628 rep->re_name, vid, did,
629 rep->re_pcibus,
630 rep->re_pcidev, rep->re_pcifunc);
631 return 0;
634 r= pci_next_dev(&devind, &vid, &did);
635 if (!r)
636 return 0;
639 #if VERBOSE /* stay silent at startup, can always get status later */
640 dname= pci_dev_name(vid, did);
641 if (!dname)
642 dname= "unknown device";
643 printf("%s: ", rep->re_name);
644 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
645 #endif
646 pci_reserve(devind);
647 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
648 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
649 if (bar < 0x400)
651 panic("rtl_probe",
652 "base address is not properly configured", NO_NUM);
654 rep->re_base_port= bar;
656 ilr= pci_attr_r8(devind, PCI_ILR);
657 rep->re_irq= ilr;
658 if (debug)
660 printf("%s: using I/O address 0x%lx, IRQ %d\n",
661 rep->re_name, (unsigned long)bar, ilr);
664 return TRUE;
667 /*===========================================================================*
668 * rl_conf_hw *
669 *===========================================================================*/
670 static void rl_conf_hw(rep)
671 re_t *rep;
673 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
675 rep->re_mode= REM_DISABLED; /* Superfluous */
677 if (rep->re_seen)
679 /* PCI device is present */
680 rep->re_mode= REM_ENABLED;
682 if (rep->re_mode != REM_ENABLED)
683 return;
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;
700 /*===========================================================================*
701 * rl_init_buf *
702 *===========================================================================*/
703 static void rl_init_buf(rep)
704 re_t *rep;
706 size_t rx_bufsize, tx_bufsize, tot_bufsize;
707 phys_bytes buf;
708 char *mallocbuf;
709 int fd, s, i, off;
711 /* Allocate receive and transmit buffers */
712 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
713 if (tx_bufsize % 4)
714 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
715 rx_bufsize= RX_BUFSIZE;
716 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
718 if (tot_bufsize % 4096)
719 tot_bufsize += 4096-(tot_bufsize % 4096);
721 #define BUF_ALIGNMENT (64*1024)
723 if(!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) {
724 panic("RTL8139","Couldn't allocate kernel buffer",i);
727 /* click-align mallocced buffer. this is what we used to get
728 * from kmalloc() too.
730 if((off = buf % BUF_ALIGNMENT)) {
731 mallocbuf += BUF_ALIGNMENT - off;
732 buf += BUF_ALIGNMENT - off;
735 tell_dev((vir_bytes)mallocbuf, tot_bufsize, rep->re_pcibus,
736 rep->re_pcidev, rep->re_pcifunc);
738 for (i= 0; i<N_TX_BUF; i++)
740 rep->re_tx[i].ret_buf= buf;
741 rep->re_tx[i].v_ret_buf= mallocbuf;
742 buf += tx_bufsize;
743 mallocbuf += tx_bufsize;
745 rep->re_rx_buf= buf;
746 rep->v_re_rx_buf= mallocbuf;
749 /*===========================================================================*
750 * rl_init_hw *
751 *===========================================================================*/
752 static void rl_init_hw(rep)
753 re_t *rep;
755 int s, i;
757 rep->re_flags = REF_EMPTY;
758 rep->re_flags |= REF_ENABLED;
760 /* Set the interrupt handler. The policy is to only send HARD_INT
761 * notifications. Don't reenable interrupts automatically. The id
762 * that is passed back is the interrupt line number.
764 rep->re_hook_id = rep->re_irq;
765 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
766 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
768 rl_reset_hw(rep);
770 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
771 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
773 #if VERBOSE /* stay silent during startup, can always get status later */
774 if (rep->re_model) {
775 printf("%s: model %s\n", rep->re_name, rep->re_model);
776 } else
778 printf("%s: unknown model 0x%08x\n",
779 rep->re_name,
780 rl_inl(rep->re_base_port, RL_TCR) &
781 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
783 #endif
785 rl_confaddr(rep);
786 if (debug)
788 printf("%s: Ethernet address ", rep->re_name);
789 for (i= 0; i < 6; i++)
791 printf("%x%c", rep->re_address.ea_addr[i],
792 i < 5 ? ':' : '\n');
797 /*===========================================================================*
798 * rl_reset_hw *
799 *===========================================================================*/
800 static void rl_reset_hw(rep)
801 re_t *rep;
803 port_t port;
804 u32_t t;
805 phys_bytes bus_buf;
806 int i;
807 clock_t t0,t1;
809 port= rep->re_base_port;
811 #if 0
812 /* Reset the PHY */
813 rl_outb(port, RL_BMCR, MII_CTRL_RST);
814 getuptime(&t0);
815 do {
816 if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
817 break;
818 } while (getuptime(&t1)==OK && (t1-t0) < system_hz);
819 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
820 panic("rtl8139","reset PHY failed to complete", NO_NUM);
821 #endif
823 /* Reset the device */
824 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
825 port, rl_inb(port, RL_CR));
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) < system_hz);
832 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
833 port, rl_inb(port, RL_CR));
834 if (rl_inb(port, RL_CR) & RL_CR_RST)
835 printf("rtl8139: reset failed to complete");
837 t= rl_inl(port, RL_TCR);
838 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
840 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
841 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
842 case RL_TCR_HWVER_RTL8139AG:
843 rep->re_model= "RTL8139A-G / RTL8139C";
844 break;
845 case RL_TCR_HWVER_RTL8139B:
846 rep->re_model= "RTL8139B / RTL8130";
847 break;
848 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
849 case RL_TCR_HWVER_RTL8100B:
850 rep->re_model= "RTL8100B/RTL8139D";
851 break;
852 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
853 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
854 default:
855 rep->re_model= NULL;
856 break;
859 #if 0
860 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
861 #endif
863 /* Intialize Rx */
865 /* Should init multicast mask */
866 #if 0
867 08-0f R/W MAR[0-7] multicast
868 #endif
869 bus_buf= vm_1phys2bus(rep->re_rx_buf);
870 rl_outl(port, RL_RBSTART, bus_buf);
872 /* Initialize Tx */
873 for (i= 0; i<N_TX_BUF; i++)
875 rep->re_tx[i].ret_busy= FALSE;
876 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
877 rl_outl(port, RL_TSAD0+i*4, bus_buf);
878 t= rl_inl(port, RL_TSD0+i*4);
879 assert(t & RL_TSD_OWN);
882 #if 0
883 dump_phy(rep);
884 #endif
886 t= rl_inw(port, RL_IMR);
887 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
888 RL_IMR_LENCHG));
890 t= rl_inw(port, RL_IMR);
891 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
892 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
894 t= rl_inw(port, RL_IMR);
895 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
897 t= rl_inb(port, RL_CR);
898 rl_outb(port, RL_CR, t | RL_CR_RE);
900 t= rl_inb(port, RL_CR);
901 rl_outb(port, RL_CR, t | RL_CR_TE);
903 rl_outl(port, RL_RCR, RX_BUFBITS);
905 t= rl_inl(port, RL_TCR);
906 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
909 /*===========================================================================*
910 * rl_confaddr *
911 *===========================================================================*/
912 static void rl_confaddr(rep)
913 re_t *rep;
915 static char eakey[]= RL_ENVVAR "#_EA";
916 static char eafmt[]= "x:x:x:x:x:x";
918 int i;
919 port_t port;
920 u32_t w;
921 long v;
923 /* User defined ethernet address? */
924 eakey[sizeof(RL_ENVVAR)-1]= '0' + (rep-re_table);
926 port= rep->re_base_port;
928 for (i= 0; i < 6; i++)
930 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
931 break;
932 rep->re_address.ea_addr[i]= v;
935 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
937 /* Should update ethernet address in hardware */
938 if (i == 6)
940 port= rep->re_base_port;
941 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
942 w= 0;
943 for (i= 0; i<4; i++)
944 w |= (rep->re_address.ea_addr[i] << (i*8));
945 rl_outl(port, RL_IDR, w);
946 w= 0;
947 for (i= 4; i<6; i++)
948 w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
949 rl_outl(port, RL_IDR+4, w);
950 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
953 /* Get ethernet address */
954 for (i= 0; i<6; i++)
955 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
958 /*===========================================================================*
959 * rl_rec_mode *
960 *===========================================================================*/
961 static void rl_rec_mode(rep)
962 re_t *rep;
964 port_t port;
965 u32_t rcr;
967 port= rep->re_base_port;
968 rcr= rl_inl(port, RL_RCR);
969 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
970 if (rep->re_flags & REF_PROMISC)
971 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
972 if (rep->re_flags & REF_BROAD)
973 rcr |= RL_RCR_AB;
974 if (rep->re_flags & REF_MULTI)
975 rcr |= RL_RCR_AM;
976 rcr |= RL_RCR_APM;
978 rl_outl(port, RL_RCR, rcr);
981 /*===========================================================================*
982 * rl_readv *
983 *===========================================================================*/
984 static void rl_readv(message *mp, int from_int, int vectored)
986 int i, j, n, o, s, s1, dl_port, re_client, count, size;
987 port_t port;
988 unsigned amount, totlen, packlen;
989 phys_bytes src_phys, dst_phys;
990 u16_t d_start, d_end;
991 u32_t l, rxstat = 0x12345678;
992 re_t *rep;
993 iovec_t *iovp;
994 int cps;
996 dl_port = mp->DL_PORT;
997 count = mp->DL_COUNT;
998 if (dl_port < 0 || dl_port >= RE_PORT_NR)
999 panic("rtl8139"," illegal port", dl_port);
1000 rep= &re_table[dl_port];
1001 re_client= mp->DL_PROC;
1002 rep->re_client= re_client;
1004 if (rep->re_clear_rx)
1005 goto suspend; /* Buffer overflow */
1007 assert(rep->re_mode == REM_ENABLED);
1008 assert(rep->re_flags & REF_ENABLED);
1010 port= rep->re_base_port;
1012 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1014 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1016 /* Receive buffer is empty, suspend */
1017 goto suspend;
1020 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1021 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1023 if (d_start >= RX_BUFSIZE)
1025 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1026 rl_inw(port, RL_CAPR));
1027 d_start %= RX_BUFSIZE;
1030 if (d_end > d_start)
1031 amount= d_end-d_start;
1032 else
1033 amount= d_end+RX_BUFSIZE - d_start;
1035 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1037 if (rep->re_clear_rx)
1039 #if 0
1040 printf("rl_readv: late buffer overflow\n");
1041 #endif
1042 goto suspend; /* Buffer overflow */
1045 /* Should convert from little endian to host byte order */
1047 if (!(rxstat & RL_RXS_ROK))
1049 printf("rxstat = 0x%08lx\n", rxstat);
1050 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1051 d_start, d_end, rxstat);
1052 panic("rtl8139","received packet not OK", NO_NUM);
1054 totlen= (rxstat >> RL_RXS_LEN_S);
1055 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1057 /* Someting went wrong */
1058 printf(
1059 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1060 totlen, rxstat, d_start);
1061 printf(
1062 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1063 d_start, d_end, totlen, rxstat);
1064 panic(NULL, NULL, NO_NUM);
1067 #if 0
1068 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1069 d_start, d_end, totlen, rxstat);
1070 #endif
1072 if (totlen+4 > amount)
1074 printf("rl_readv: packet not yet ready\n");
1075 goto suspend;
1078 /* Should subtract the CRC */
1079 packlen= totlen - ETH_CRC_SIZE;
1081 if (vectored)
1083 int iov_offset = 0;
1085 size= 0;
1086 o= d_start+4;
1087 src_phys= rep->re_rx_buf;
1088 for (i= 0; i<count; i += IOVEC_NR,
1089 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1091 n= IOVEC_NR;
1092 if (i+n > count)
1093 n= count-i;
1095 cps = sys_vircopy(re_client, D,
1096 (vir_bytes) mp->DL_ADDR + iov_offset,
1097 SELF, D, (vir_bytes) rep->re_iovec,
1098 n * sizeof(rep->re_iovec[0]));
1099 if (cps != OK)
1100 printf(
1101 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1102 cps, __LINE__);
1104 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1106 s= iovp->iov_size;
1107 if (size + s > packlen)
1109 assert(packlen > size);
1110 s= packlen-size;
1113 if (o >= RX_BUFSIZE)
1115 o -= RX_BUFSIZE;
1116 assert(o < RX_BUFSIZE);
1119 if (o+s > RX_BUFSIZE)
1121 assert(o<RX_BUFSIZE);
1122 s1= RX_BUFSIZE-o;
1124 cps = sys_vircopy(SELF, D,
1125 (vir_bytes) rep->v_re_rx_buf+o,
1126 re_client, D, iovp->iov_addr,
1127 s1);
1128 if (cps != OK)
1129 printf(
1130 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1131 cps, __LINE__);
1132 cps = sys_vircopy(SELF, D,
1133 (vir_bytes) rep->v_re_rx_buf,
1134 re_client, D,
1135 iovp->iov_addr+s1, s-s1);
1136 if (cps != OK)
1137 printf(
1138 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1139 cps, __LINE__);
1141 else
1143 cps = sys_vircopy(SELF, D,
1144 (vir_bytes) rep->v_re_rx_buf+o,
1145 re_client, D, iovp->iov_addr,
1147 if (cps != OK)
1148 printf(
1149 "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
1150 cps, __LINE__);
1153 size += s;
1154 if (size == packlen)
1155 break;
1156 o += s;
1158 if (size == packlen)
1159 break;
1161 if (size < packlen)
1163 assert(0);
1166 else
1168 assert(0);
1169 #if 0
1170 size= mp->DL_COUNT;
1171 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1172 panic("rtl8139","invalid packet size", size);
1173 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1174 panic("rtl8139","umap_local failed", NO_NUM);
1176 p= rep->re_tx[tx_head].ret_buf;
1177 cps = sys_abscopy(phys_user, p, size);
1178 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1179 #endif
1182 if (rep->re_clear_rx)
1184 /* For some reason the receiver FIFO is not stopped when
1185 * the buffer is full.
1187 #if 0
1188 printf("rl_readv: later buffer overflow\n");
1189 #endif
1190 goto suspend; /* Buffer overflow */
1193 rep->re_stat.ets_packetR++;
1194 rep->re_read_s= packlen;
1195 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1197 /* Avoid overflow in 16-bit computations */
1198 l= d_start;
1199 l += totlen+4;
1200 l= (l+3) & ~3; /* align */
1201 if (l >= RX_BUFSIZE)
1203 l -= RX_BUFSIZE;
1204 assert(l < RX_BUFSIZE);
1206 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1208 if (!from_int)
1209 reply(rep, OK, FALSE);
1211 return;
1213 suspend:
1214 if (from_int)
1216 assert(rep->re_flags & REF_READING);
1218 /* No need to store any state */
1219 return;
1222 rep->re_rx_mess= *mp;
1223 assert(!(rep->re_flags & REF_READING));
1224 rep->re_flags |= REF_READING;
1226 reply(rep, OK, FALSE);
1229 /*===========================================================================*
1230 * rl_readv_s *
1231 *===========================================================================*/
1232 static void rl_readv_s(message *mp, int from_int)
1234 int i, j, n, o, s, s1, dl_port, re_client, count, size;
1235 port_t port;
1236 unsigned amount, totlen, packlen;
1237 phys_bytes src_phys, dst_phys;
1238 u16_t d_start, d_end;
1239 u32_t l, rxstat = 0x12345678;
1240 re_t *rep;
1241 iovec_s_t *iovp;
1242 int cps;
1243 int iov_offset = 0;
1245 dl_port = mp->DL_PORT;
1246 count = mp->DL_COUNT;
1247 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1248 panic("rtl8139"," illegal port", dl_port);
1249 rep= &re_table[dl_port];
1250 re_client= mp->DL_PROC;
1251 rep->re_client= re_client;
1253 if (rep->re_clear_rx)
1254 goto suspend; /* Buffer overflow */
1256 assert(rep->re_mode == REM_ENABLED);
1257 assert(rep->re_flags & REF_ENABLED);
1259 port= rep->re_base_port;
1261 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1263 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1265 /* Receive buffer is empty, suspend */
1266 goto suspend;
1269 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1270 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1272 if (d_start >= RX_BUFSIZE)
1274 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1275 rl_inw(port, RL_CAPR));
1276 d_start %= RX_BUFSIZE;
1279 if (d_end > d_start)
1280 amount= d_end-d_start;
1281 else
1282 amount= d_end+RX_BUFSIZE - d_start;
1284 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1286 if (rep->re_clear_rx)
1288 #if 0
1289 printf("rl_readv: late buffer overflow\n");
1290 #endif
1291 goto suspend; /* Buffer overflow */
1294 /* Should convert from little endian to host byte order */
1296 if (!(rxstat & RL_RXS_ROK))
1298 printf("rxstat = 0x%08lx\n", rxstat);
1299 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1300 d_start, d_end, rxstat);
1301 panic("rtl8139","received packet not OK", NO_NUM);
1303 totlen= (rxstat >> RL_RXS_LEN_S);
1304 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1306 /* Someting went wrong */
1307 printf(
1308 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1309 totlen, rxstat, d_start);
1310 printf(
1311 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1312 d_start, d_end, totlen, rxstat);
1313 panic(NULL, NULL, NO_NUM);
1316 #if 0
1317 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1318 d_start, d_end, totlen, rxstat);
1319 #endif
1321 if (totlen+4 > amount)
1323 printf("rl_readv: packet not yet ready\n");
1324 goto suspend;
1327 /* Should subtract the CRC */
1328 packlen= totlen - ETH_CRC_SIZE;
1330 size= 0;
1331 o= d_start+4;
1332 src_phys= rep->re_rx_buf;
1333 for (i= 0; i<count; i += IOVEC_NR,
1334 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1336 n= IOVEC_NR;
1337 if (i+n > count)
1338 n= count-i;
1340 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1341 (vir_bytes) rep->re_iovec_s,
1342 n * sizeof(rep->re_iovec_s[0]), D);
1343 if (cps != OK)
1345 panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed",
1346 cps);
1349 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
1351 s= iovp->iov_size;
1352 if (size + s > packlen)
1354 assert(packlen > size);
1355 s= packlen-size;
1358 #if 0
1359 if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
1360 panic("rtl8139","umap_local failed\n", NO_NUM);
1361 #endif
1363 if (o >= RX_BUFSIZE)
1365 o -= RX_BUFSIZE;
1366 assert(o < RX_BUFSIZE);
1369 if (o+s > RX_BUFSIZE)
1371 assert(o<RX_BUFSIZE);
1372 s1= RX_BUFSIZE-o;
1374 cps = sys_safecopyto(re_client,
1375 iovp->iov_grant, 0,
1376 (vir_bytes) rep->v_re_rx_buf+o, s1, D);
1377 if (cps != OK)
1379 panic(__FILE__,
1380 "rl_readv_s: sys_safecopyto failed",
1381 cps);
1383 cps = sys_safecopyto(re_client,
1384 iovp->iov_grant, s1,
1385 (vir_bytes) rep->v_re_rx_buf, s-s1, S);
1386 if (cps != OK)
1388 panic(__FILE__,
1389 "rl_readv_s: sys_safecopyto failed",
1390 cps);
1393 else
1395 cps = sys_safecopyto(re_client,
1396 iovp->iov_grant, 0,
1397 (vir_bytes) rep->v_re_rx_buf+o, s, D);
1398 if (cps != OK)
1399 panic(__FILE__,
1400 "rl_readv_s: sys_safecopyto failed",
1401 cps);
1404 size += s;
1405 if (size == packlen)
1406 break;
1407 o += s;
1409 if (size == packlen)
1410 break;
1412 if (size < packlen)
1414 assert(0);
1417 if (rep->re_clear_rx)
1419 /* For some reason the receiver FIFO is not stopped when
1420 * the buffer is full.
1422 #if 0
1423 printf("rl_readv: later buffer overflow\n");
1424 #endif
1425 goto suspend; /* Buffer overflow */
1428 rep->re_stat.ets_packetR++;
1429 rep->re_read_s= packlen;
1430 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1432 /* Avoid overflow in 16-bit computations */
1433 l= d_start;
1434 l += totlen+4;
1435 l= (l+3) & ~3; /* align */
1436 if (l >= RX_BUFSIZE)
1438 l -= RX_BUFSIZE;
1439 assert(l < RX_BUFSIZE);
1441 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1443 if (!from_int)
1444 reply(rep, OK, FALSE);
1446 return;
1448 suspend:
1449 if (from_int)
1451 assert(rep->re_flags & REF_READING);
1453 /* No need to store any state */
1454 return;
1457 rep->re_rx_mess= *mp;
1458 assert(!(rep->re_flags & REF_READING));
1459 rep->re_flags |= REF_READING;
1461 reply(rep, OK, FALSE);
1464 /*===========================================================================*
1465 * rl_writev *
1466 *===========================================================================*/
1467 static void rl_writev(message *mp, int from_int, int vectored)
1469 phys_bytes phys_user;
1470 int i, j, n, s, port, count, size;
1471 int tx_head, re_client;
1472 re_t *rep;
1473 iovec_t *iovp;
1474 char *ret;
1475 int cps;
1477 port = mp->DL_PORT;
1478 count = mp->DL_COUNT;
1479 if (port < 0 || port >= RE_PORT_NR)
1480 panic("rtl8139","illegal port", port);
1481 rep= &re_table[port];
1482 re_client= mp->DL_PROC;
1483 rep->re_client= re_client;
1485 assert(rep->re_mode == REM_ENABLED);
1486 assert(rep->re_flags & REF_ENABLED);
1488 if (from_int)
1490 assert(rep->re_flags & REF_SEND_AVAIL);
1491 rep->re_flags &= ~REF_SEND_AVAIL;
1492 rep->re_send_int= FALSE;
1493 rep->re_tx_alive= TRUE;
1496 tx_head= rep->re_tx_head;
1497 if (rep->re_tx[tx_head].ret_busy)
1499 assert(!(rep->re_flags & REF_SEND_AVAIL));
1500 rep->re_flags |= REF_SEND_AVAIL;
1501 if (rep->re_tx[tx_head].ret_busy)
1502 goto suspend;
1504 /* Race condition, the interrupt handler may clear re_busy
1505 * before we got a chance to set REF_SEND_AVAIL. Checking
1506 * ret_busy twice should be sufficient.
1508 #if 0
1509 printf("rl_writev: race detected\n");
1510 #endif
1511 rep->re_flags &= ~REF_SEND_AVAIL;
1512 rep->re_send_int= FALSE;
1515 assert(!(rep->re_flags & REF_SEND_AVAIL));
1516 assert(!(rep->re_flags & REF_PACK_SENT));
1518 if (vectored)
1520 int iov_offset = 0;
1522 size= 0;
1523 ret = rep->re_tx[tx_head].v_ret_buf;
1524 for (i= 0; i<count; i += IOVEC_NR,
1525 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1527 n= IOVEC_NR;
1528 if (i+n > count)
1529 n= count-i;
1530 cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
1531 SELF, D, (vir_bytes) rep->re_iovec,
1532 n * sizeof(rep->re_iovec[0]));
1533 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1535 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1537 s= iovp->iov_size;
1538 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1540 panic("rtl8139","invalid packet size",
1541 NO_NUM);
1544 if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
1545 panic("rtl8139","umap_local failed\n", NO_NUM);
1547 cps = sys_vircopy(re_client, D, iovp->iov_addr,
1548 SELF, D, (vir_bytes) ret, s);
1549 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1550 size += s;
1551 ret += s;
1554 if (size < ETH_MIN_PACK_SIZE)
1555 panic("rtl8139","invalid packet size", size);
1557 else
1559 size= mp->DL_COUNT;
1560 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1561 panic("rtl8139","invalid packet size", size);
1562 ret = rep->re_tx[tx_head].v_ret_buf;
1563 cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR,
1564 SELF, D, (vir_bytes) ret, size);
1565 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1568 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1569 rep->re_ertxth | size);
1570 rep->re_tx[tx_head].ret_busy= TRUE;
1572 if (++tx_head == N_TX_BUF)
1573 tx_head= 0;
1574 assert(tx_head < RL_N_TX);
1575 rep->re_tx_head= tx_head;
1577 rep->re_flags |= REF_PACK_SENT;
1579 /* If the interrupt handler called, don't send a reply. The reply
1580 * will be sent after all interrupts are handled.
1582 if (from_int)
1583 return;
1584 reply(rep, OK, FALSE);
1585 return;
1587 suspend:
1588 #if 0
1589 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1590 tx_head, rep->re_tx_tail,
1591 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1592 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1593 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1594 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1595 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1596 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1597 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1598 #endif
1600 if (from_int)
1601 panic("rtl8139","should not be sending\n", NO_NUM);
1603 rep->re_tx_mess= *mp;
1604 reply(rep, OK, FALSE);
1607 /*===========================================================================*
1608 * rl_writev_s *
1609 *===========================================================================*/
1610 static void rl_writev_s(message *mp, int from_int)
1612 int i, j, n, s, port, count, size;
1613 int tx_head, re_client;
1614 re_t *rep;
1615 iovec_s_t *iovp;
1616 char *ret;
1617 int cps;
1618 int iov_offset = 0;
1620 port = mp->DL_PORT;
1621 count = mp->DL_COUNT;
1622 if (port < 0 || port >= RE_PORT_NR)
1623 panic("rtl8139","illegal port", port);
1624 rep= &re_table[port];
1625 re_client= mp->DL_PROC;
1626 rep->re_client= re_client;
1628 assert(rep->re_mode == REM_ENABLED);
1629 assert(rep->re_flags & REF_ENABLED);
1631 if (from_int)
1633 assert(rep->re_flags & REF_SEND_AVAIL);
1634 rep->re_flags &= ~REF_SEND_AVAIL;
1635 rep->re_send_int= FALSE;
1636 rep->re_tx_alive= TRUE;
1639 tx_head= rep->re_tx_head;
1640 if (rep->re_tx[tx_head].ret_busy)
1642 assert(!(rep->re_flags & REF_SEND_AVAIL));
1643 rep->re_flags |= REF_SEND_AVAIL;
1644 if (rep->re_tx[tx_head].ret_busy)
1645 goto suspend;
1647 /* Race condition, the interrupt handler may clear re_busy
1648 * before we got a chance to set REF_SEND_AVAIL. Checking
1649 * ret_busy twice should be sufficient.
1651 #if 0
1652 printf("rl_writev: race detected\n");
1653 #endif
1654 rep->re_flags &= ~REF_SEND_AVAIL;
1655 rep->re_send_int= FALSE;
1658 assert(!(rep->re_flags & REF_SEND_AVAIL));
1659 assert(!(rep->re_flags & REF_PACK_SENT));
1661 size= 0;
1662 ret = rep->re_tx[tx_head].v_ret_buf;
1663 for (i= 0; i<count; i += IOVEC_NR,
1664 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1666 n= IOVEC_NR;
1667 if (i+n > count)
1668 n= count-i;
1669 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1670 (vir_bytes) rep->re_iovec_s,
1671 n * sizeof(rep->re_iovec_s[0]), D);
1672 if (cps != OK)
1674 panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed",
1675 cps);
1678 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
1680 s= iovp->iov_size;
1681 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1683 panic("rtl8139","invalid packet size",
1684 NO_NUM);
1686 cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0,
1687 (vir_bytes) ret, s, D);
1688 if (cps != OK)
1690 panic(__FILE__,
1691 "rl_writev_s: sys_safecopyfrom failed",
1692 cps);
1694 size += s;
1695 ret += s;
1698 if (size < ETH_MIN_PACK_SIZE)
1699 panic("rtl8139","invalid packet size", size);
1701 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1702 rep->re_ertxth | size);
1703 rep->re_tx[tx_head].ret_busy= TRUE;
1705 if (++tx_head == N_TX_BUF)
1706 tx_head= 0;
1707 assert(tx_head < RL_N_TX);
1708 rep->re_tx_head= tx_head;
1710 rep->re_flags |= REF_PACK_SENT;
1712 /* If the interrupt handler called, don't send a reply. The reply
1713 * will be sent after all interrupts are handled.
1715 if (from_int)
1716 return;
1717 reply(rep, OK, FALSE);
1718 return;
1720 suspend:
1721 #if 0
1722 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1723 tx_head, rep->re_tx_tail,
1724 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1725 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1726 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1727 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1728 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1729 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1730 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1731 #endif
1733 if (from_int)
1734 panic("rtl8139","should not be sending\n", NO_NUM);
1736 rep->re_tx_mess= *mp;
1737 reply(rep, OK, FALSE);
1740 /*===========================================================================*
1741 * rl_check_ints *
1742 *===========================================================================*/
1743 static void rl_check_ints(rep)
1744 re_t *rep;
1746 #if 0
1747 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
1748 31 R CRS Carrier Sense Lost
1749 30 R TABT Transmit Abort
1750 29 R OWC Out of Window Collision
1751 27-24 R NCC[3-0] Number of Collision Count
1752 23-22 reserved
1753 21-16 R/W ERTXH[5-0] Early Tx Threshold
1754 15 R TOK Transmit OK
1755 14 R TUN Transmit FIFO Underrun
1756 13 R/W OWN OWN
1757 12-0 R/W SIZE Descriptor Size
1758 3e-3f R/W ISR Interrupt Status Register
1759 6 R/W FOVW Fx FIFO Overflow Interrupt
1760 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
1761 3 R/W TER Transmit Error Interrupt
1762 2 R/W TOK Transmit OK Interrupt
1763 3e-3f R/W ISR Interrupt Status Register
1764 15 R/W SERR System Error Interrupt
1765 14 R/W TimeOut Time Out Interrupt
1766 13 R/W LenChg Cable Length Change Interrupt
1767 3e-3f R/W ISR Interrupt Status Register
1768 4 R/W RXOVW Rx Buffer Overflow Interrupt
1769 1 R/W RER Receive Error Interrupt
1770 0 R/W ROK Receive OK Interrupt
1771 4c-4f R/W MPC Missed Packet Counter
1772 60-61 R TSAD Transmit Status of All Descriptors
1773 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
1774 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
1775 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
1776 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
1777 6c-6d R DIS Disconnect Counter
1778 15-0 R DCNT Disconnect Counter
1779 6e-6f R FCSC False Carrier Sense Counter
1780 15-0 R FCSCNT False Carrier event counter
1781 72-73 R REC RX_ER Counter
1782 15-0 R RXERCNT Received packet counter
1783 #endif
1785 int re_flags;
1787 re_flags= rep->re_flags;
1789 if ((re_flags & REF_READING) &&
1790 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1792 if (rep->re_rx_mess.m_type == DL_READV)
1794 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1795 TRUE /* vectored */);
1797 else if (rep->re_rx_mess.m_type == DL_READV_S)
1799 rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
1801 else
1803 assert(rep->re_rx_mess.m_type == DL_READ);
1804 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1805 FALSE /* !vectored */);
1808 if (rep->re_clear_rx)
1809 rl_clear_rx(rep);
1811 if (rep->re_need_reset)
1812 rl_do_reset(rep);
1814 if (rep->re_send_int)
1816 if (rep->re_tx_mess.m_type == DL_WRITEV)
1818 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1819 TRUE /* vectored */);
1821 else if (rep->re_tx_mess.m_type == DL_WRITEV_S)
1823 rl_writev_s(&rep->re_tx_mess, TRUE /* from int */);
1825 else
1827 assert(rep->re_tx_mess.m_type == DL_WRITE);
1828 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1829 FALSE /* !vectored */);
1833 if (rep->re_report_link)
1834 rl_report_link(rep);
1836 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1837 reply(rep, OK, TRUE);
1840 /*===========================================================================*
1841 * rl_report_link *
1842 *===========================================================================*/
1843 static void rl_report_link(rep)
1844 re_t *rep;
1846 port_t port;
1847 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
1848 u8_t msr;
1849 int f, link_up;
1851 rep->re_report_link= FALSE;
1852 port= rep->re_base_port;
1853 msr= rl_inb(port, RL_MSR);
1854 link_up= !(msr & RL_MSR_LINKB);
1855 rep->re_link_up= link_up;
1856 if (!link_up)
1858 printf("%s: link down\n", rep->re_name);
1859 return;
1862 mii_ctrl= rl_inw(port, RL_BMCR);
1863 mii_status= rl_inw(port, RL_BMSR);
1864 mii_ana= rl_inw(port, RL_ANAR);
1865 mii_anlpa= rl_inw(port, RL_ANLPAR);
1866 mii_ane= rl_inw(port, RL_ANER);
1867 mii_extstat= 0;
1869 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1871 printf("%s: PHY: ", rep->re_name);
1872 f= 1;
1873 if (mii_ctrl & MII_CTRL_LB)
1875 printf("loopback mode");
1876 f= 0;
1878 if (mii_ctrl & MII_CTRL_PD)
1880 if (!f) printf(", ");
1881 f= 0;
1882 printf("powered down");
1884 if (mii_ctrl & MII_CTRL_ISO)
1886 if (!f) printf(", ");
1887 f= 0;
1888 printf("isolated");
1890 printf("\n");
1891 return;
1893 if (!(mii_ctrl & MII_CTRL_ANE))
1895 printf("%s: manual config: ", rep->re_name);
1896 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1898 case MII_CTRL_SP_10: printf("10 Mbps"); break;
1899 case MII_CTRL_SP_100: printf("100 Mbps"); break;
1900 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
1901 case MII_CTRL_SP_RES: printf("reserved speed"); break;
1903 if (mii_ctrl & MII_CTRL_DM)
1904 printf(", full duplex");
1905 else
1906 printf(", half duplex");
1907 printf("\n");
1908 return;
1911 if (!debug) goto resspeed;
1913 printf("%s: ", rep->re_name);
1914 mii_print_stat_speed(mii_status, mii_extstat);
1915 printf("\n");
1917 if (!(mii_status & MII_STATUS_ANC))
1918 printf("%s: auto-negotiation not complete\n", rep->re_name);
1919 if (mii_status & MII_STATUS_RF)
1920 printf("%s: remote fault detected\n", rep->re_name);
1921 if (!(mii_status & MII_STATUS_ANA))
1923 printf("%s: local PHY has no auto-negotiation ability\n",
1924 rep->re_name);
1926 if (!(mii_status & MII_STATUS_LS))
1927 printf("%s: link down\n", rep->re_name);
1928 if (mii_status & MII_STATUS_JD)
1929 printf("%s: jabber condition detected\n", rep->re_name);
1930 if (!(mii_status & MII_STATUS_EC))
1932 printf("%s: no extended register set\n", rep->re_name);
1933 goto resspeed;
1935 if (!(mii_status & MII_STATUS_ANC))
1936 goto resspeed;
1938 printf("%s: local cap.: ", rep->re_name);
1939 mii_print_techab(mii_ana);
1940 printf("\n");
1942 if (mii_ane & MII_ANE_PDF)
1943 printf("%s: parallel detection fault\n", rep->re_name);
1944 if (!(mii_ane & MII_ANE_LPANA))
1946 printf("%s: link-partner does not support auto-negotiation\n",
1947 rep->re_name);
1948 goto resspeed;
1951 printf("%s: remote cap.: ", rep->re_name);
1952 mii_print_techab(mii_anlpa);
1953 printf("\n");
1955 resspeed:
1956 printf("%s: ", rep->re_name);
1957 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
1958 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
1962 static void mii_print_techab(techab)
1963 u16_t techab;
1965 int fs, ft;
1966 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
1968 printf("strange selector 0x%x, value 0x%x",
1969 techab & MII_ANA_SEL_M,
1970 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
1971 return;
1973 fs= 1;
1974 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
1976 printf("100 Mbps: ");
1977 fs= 0;
1978 ft= 1;
1979 if (techab & MII_ANA_100T4)
1981 printf("T4");
1982 ft= 0;
1984 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
1986 if (!ft)
1987 printf(", ");
1988 ft= 0;
1989 printf("TX-");
1990 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
1992 case MII_ANA_100TXFD: printf("FD"); break;
1993 case MII_ANA_100TXHD: printf("HD"); break;
1994 default: printf("FD/HD"); break;
1998 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
2000 if (!fs)
2001 printf(", ");
2002 printf("10 Mbps: ");
2003 fs= 0;
2004 printf("T-");
2005 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
2007 case MII_ANA_10TFD: printf("FD"); break;
2008 case MII_ANA_10THD: printf("HD"); break;
2009 default: printf("FD/HD"); break;
2012 if (techab & MII_ANA_PAUSE_SYM)
2014 if (!fs)
2015 printf(", ");
2016 fs= 0;
2017 printf("pause(SYM)");
2019 if (techab & MII_ANA_PAUSE_ASYM)
2021 if (!fs)
2022 printf(", ");
2023 fs= 0;
2024 printf("pause(ASYM)");
2026 if (techab & MII_ANA_TAF_RES)
2028 if (!fs)
2029 printf(", ");
2030 fs= 0;
2031 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
2035 static void mii_print_stat_speed(stat, extstat)
2036 u16_t stat;
2037 u16_t extstat;
2039 int fs, ft;
2040 fs= 1;
2041 if (stat & MII_STATUS_EXT_STAT)
2043 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
2044 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
2046 printf("1000 Mbps: ");
2047 fs= 0;
2048 ft= 1;
2049 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
2051 ft= 0;
2052 printf("X-");
2053 switch(extstat &
2054 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
2056 case MII_ESTAT_1000XFD: printf("FD"); break;
2057 case MII_ESTAT_1000XHD: printf("HD"); break;
2058 default: printf("FD/HD"); break;
2061 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
2063 if (!ft)
2064 printf(", ");
2065 ft= 0;
2066 printf("T-");
2067 switch(extstat &
2068 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
2070 case MII_ESTAT_1000TFD: printf("FD"); break;
2071 case MII_ESTAT_1000THD: printf("HD"); break;
2072 default: printf("FD/HD"); break;
2077 if (stat & (MII_STATUS_100T4 |
2078 MII_STATUS_100XFD | MII_STATUS_100XHD |
2079 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
2081 if (!fs)
2082 printf(", ");
2083 fs= 0;
2084 printf("100 Mbps: ");
2085 ft= 1;
2086 if (stat & MII_STATUS_100T4)
2088 printf("T4");
2089 ft= 0;
2091 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
2093 if (!ft)
2094 printf(", ");
2095 ft= 0;
2096 printf("TX-");
2097 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
2099 case MII_STATUS_100XFD: printf("FD"); break;
2100 case MII_STATUS_100XHD: printf("HD"); break;
2101 default: printf("FD/HD"); break;
2104 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
2106 if (!ft)
2107 printf(", ");
2108 ft= 0;
2109 printf("T2-");
2110 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
2112 case MII_STATUS_100T2FD: printf("FD"); break;
2113 case MII_STATUS_100T2HD: printf("HD"); break;
2114 default: printf("FD/HD"); break;
2118 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
2120 if (!fs)
2121 printf(", ");
2122 printf("10 Mbps: ");
2123 fs= 0;
2124 printf("T-");
2125 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
2127 case MII_STATUS_10FD: printf("FD"); break;
2128 case MII_STATUS_10HD: printf("HD"); break;
2129 default: printf("FD/HD"); break;
2134 /*===========================================================================*
2135 * rl_clear_rx *
2136 *===========================================================================*/
2137 static void rl_clear_rx(rep)
2138 re_t *rep;
2140 port_t port;
2141 u8_t cr;
2142 int i;
2143 clock_t t0,t1;
2145 rep->re_clear_rx= FALSE;
2146 port= rep->re_base_port;
2148 /* Reset the receiver */
2149 cr= rl_inb(port, RL_CR);
2150 cr &= ~RL_CR_RE;
2151 rl_outb(port, RL_CR, cr);
2152 getuptime(&t0);
2153 do {
2154 if (!(rl_inb(port, RL_CR) & RL_CR_RE))
2155 break;
2156 } while (getuptime(&t1)==OK && (t1-t0) < system_hz);
2157 if (rl_inb(port, RL_CR) & RL_CR_RE)
2158 panic("rtl8139","cannot disable receiver", NO_NUM);
2160 #if 0
2161 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
2162 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
2163 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
2164 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
2165 #endif
2167 rl_outb(port, RL_CR, cr | RL_CR_RE);
2169 rl_outl(port, RL_RCR, RX_BUFBITS);
2171 rl_rec_mode(rep);
2173 rep->re_stat.ets_missedP++;
2176 /*===========================================================================*
2177 * rl_do_reset *
2178 *===========================================================================*/
2179 static void rl_do_reset(rep)
2180 re_t *rep;
2182 rep->re_need_reset= FALSE;
2183 rl_reset_hw(rep);
2184 rl_rec_mode(rep);
2186 rep->re_tx_head= 0;
2187 if (rep->re_flags & REF_SEND_AVAIL)
2189 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
2190 rep->re_send_int= TRUE;
2194 /*===========================================================================*
2195 * rl_getstat *
2196 *===========================================================================*/
2197 static void rl_getstat(mp)
2198 message *mp;
2200 int r, port;
2201 eth_stat_t stats;
2202 re_t *rep;
2204 port = mp->DL_PORT;
2205 if (port < 0 || port >= RE_PORT_NR)
2206 panic("rtl8139","illegal port", port);
2207 rep= &re_table[port];
2208 rep->re_client= mp->DL_PROC;
2210 assert(rep->re_mode == REM_ENABLED);
2211 assert(rep->re_flags & REF_ENABLED);
2213 stats= rep->re_stat;
2215 r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC,
2216 (vir_bytes) mp->DL_ADDR, sizeof(stats));
2217 if (r != OK)
2218 panic(__FILE__, "rl_getstat: sys_datacopy failed", r);
2220 mp->m_type= DL_STAT_REPLY;
2221 mp->DL_PORT= port;
2222 mp->DL_STAT= OK;
2223 r= send(mp->m_source, mp);
2224 if (r != OK)
2225 panic("RTL8139", "rl_getstat: send failed: %d\n", r);
2228 /*===========================================================================*
2229 * rl_getstat_s *
2230 *===========================================================================*/
2231 static void rl_getstat_s(mp)
2232 message *mp;
2234 int r, port;
2235 eth_stat_t stats;
2236 re_t *rep;
2238 port = mp->DL_PORT;
2239 if (port < 0 || port >= RE_PORT_NR)
2240 panic("rtl8139","illegal port", port);
2241 rep= &re_table[port];
2242 rep->re_client= mp->DL_PROC;
2244 assert(rep->re_mode == REM_ENABLED);
2245 assert(rep->re_flags & REF_ENABLED);
2247 stats= rep->re_stat;
2249 r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
2250 (vir_bytes) &stats, sizeof(stats), D);
2251 if (r != OK)
2252 panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r);
2254 mp->m_type= DL_STAT_REPLY;
2255 mp->DL_PORT= port;
2256 mp->DL_STAT= OK;
2257 r= send(mp->m_source, mp);
2258 if (r != OK)
2259 panic("RTL8139", "rl_getstat_s: send failed: %d\n", r);
2263 /*===========================================================================*
2264 * rl_getname *
2265 *===========================================================================*/
2266 static void rl_getname(mp)
2267 message *mp;
2269 int r;
2271 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
2272 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
2273 mp->m_type= DL_NAME_REPLY;
2274 r= send(mp->m_source, mp);
2275 if (r != OK)
2276 panic("RTL8139", "rl_getname: send failed: %d\n", r);
2280 /*===========================================================================*
2281 * reply *
2282 *===========================================================================*/
2283 static void reply(rep, err, may_block)
2284 re_t *rep;
2285 int err;
2286 int may_block;
2288 message reply;
2289 int status;
2290 int r;
2291 clock_t now;
2293 status = 0;
2294 if (rep->re_flags & REF_PACK_SENT)
2295 status |= DL_PACK_SEND;
2296 if (rep->re_flags & REF_PACK_RECV)
2297 status |= DL_PACK_RECV;
2299 reply.m_type = DL_TASK_REPLY;
2300 reply.DL_PORT = rep - re_table;
2301 reply.DL_PROC = rep->re_client;
2302 reply.DL_STAT = status | ((u32_t) err << 16);
2303 reply.DL_COUNT = rep->re_read_s;
2304 if (OK != (r = getuptime(&now)))
2305 panic("rtl8139","getuptime() failed:", r);
2306 reply.DL_CLCK = now;
2308 r= send(rep->re_client, &reply);
2310 if (r == ELOCKED && may_block)
2312 #if 0
2313 printW(); printf("send locked\n");
2314 #endif
2315 return;
2318 if (r < 0) {
2319 printf("RTL8139 tried sending to %d, type %d\n", rep->re_client, reply.m_type);
2320 panic("rtl8139","send failed:", r);
2323 rep->re_read_s = 0;
2324 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
2327 /*===========================================================================*
2328 * mess_reply *
2329 *===========================================================================*/
2330 static void mess_reply(req, reply_mess)
2331 message *req;
2332 message *reply_mess;
2334 if (send(req->m_source, reply_mess) != OK)
2335 panic("rtl8139","unable to mess_reply", NO_NUM);
2338 #if 0
2339 static void dump_phy(rep)
2340 re_t *rep;
2342 port_t port;
2343 u32_t t;
2345 port= rep->re_base_port;
2347 t= rl_inb(port, RL_MSR);
2348 printf("MSR: 0x%02lx\n", t);
2349 if (t & RL_MSR_SPEED_10)
2350 printf("\t10 Mbps\n");
2351 if (t & RL_MSR_LINKB)
2352 printf("\tLink failed\n");
2354 t= rl_inb(port, RL_CONFIG1);
2355 printf("CONFIG1: 0x%02lx\n", t);
2357 t= rl_inb(port, RL_CONFIG3);
2358 printf("CONFIG3: 0x%02lx\n", t);
2360 t= rl_inb(port, RL_CONFIG4);
2361 printf("CONFIG4: 0x%02lx\n", t);
2363 t= rl_inw(port, RL_BMCR);
2364 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
2366 t= rl_inw(port, RL_BMSR);
2367 printf("BMSR:");
2368 if (t & MII_STATUS_100T4)
2369 printf(" 100Base-T4");
2370 if (t & MII_STATUS_100XFD)
2371 printf(" 100Base-X-FD");
2372 if (t & MII_STATUS_100XHD)
2373 printf(" 100Base-X-HD");
2374 if (t & MII_STATUS_10FD)
2375 printf(" 10Mbps-FD");
2376 if (t & MII_STATUS_10HD)
2377 printf(" 10Mbps-HD");
2378 if (t & MII_STATUS_100T2FD)
2379 printf(" 100Base-T2-FD");
2380 if (t & MII_STATUS_100T2HD)
2381 printf(" 100Base-T2-HD");
2382 if (t & MII_STATUS_EXT_STAT)
2383 printf(" Ext-stat");
2384 if (t & MII_STATUS_RES)
2385 printf(" res-0x%lx", t & MII_STATUS_RES);
2386 if (t & MII_STATUS_MFPS)
2387 printf(" MFPS");
2388 if (t & MII_STATUS_ANC)
2389 printf(" ANC");
2390 if (t & MII_STATUS_RF)
2391 printf(" remote-fault");
2392 if (t & MII_STATUS_ANA)
2393 printf(" ANA");
2394 if (t & MII_STATUS_LS)
2395 printf(" Link");
2396 if (t & MII_STATUS_JD)
2397 printf(" Jabber");
2398 if (t & MII_STATUS_EC)
2399 printf(" Extended-capability");
2400 printf("\n");
2402 t= rl_inw(port, RL_ANAR);
2403 printf("ANAR (MII_ANA): 0x%04lx\n", t);
2405 t= rl_inw(port, RL_ANLPAR);
2406 printf("ANLPAR: 0x%04lx\n", t);
2408 t= rl_inw(port, RL_ANER);
2409 printf("ANER (MII_ANE): ");
2410 if (t & MII_ANE_RES)
2411 printf(" res-0x%lx", t & MII_ANE_RES);
2412 if (t & MII_ANE_PDF)
2413 printf(" Par-Detect-Fault");
2414 if (t & MII_ANE_LPNPA)
2415 printf(" LP-Next-Page-Able");
2416 if (t & MII_ANE_NPA)
2417 printf(" Loc-Next-Page-Able");
2418 if (t & MII_ANE_PR)
2419 printf(" Page-Received");
2420 if (t & MII_ANE_LPANA)
2421 printf(" LP-Auto-Neg-Able");
2422 printf("\n");
2424 t= rl_inw(port, RL_NWAYTR);
2425 printf("NWAYTR: 0x%04lx\n", t);
2426 t= rl_inw(port, RL_CSCR);
2427 printf("CSCR: 0x%04lx\n", t);
2429 t= rl_inb(port, RL_CONFIG5);
2430 printf("CONFIG5: 0x%02lx\n", t);
2432 #endif
2434 static int do_hard_int(void)
2436 int i,s;
2438 for (i=0; i < RE_PORT_NR; i ++) {
2440 /* Run interrupt handler at driver level. */
2441 rl_handler( &re_table[i]);
2443 /* Reenable interrupts for this hook. */
2444 if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK)
2445 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
2449 /*===========================================================================*
2450 * rl_handler *
2451 *===========================================================================*/
2452 static int rl_handler(rep)
2453 re_t *rep;
2455 int i, port, tx_head, tx_tail, link_up;
2456 u16_t isr, tsad;
2457 u32_t tsd, tcr, ertxth;
2458 #if 0
2459 u8_t cr;
2460 #endif
2461 clock_t t0,t1;
2462 int_event_check = FALSE; /* disable check by default */
2464 port= rep->re_base_port;
2466 /* Ack interrupt */
2467 isr= rl_inw(port, RL_ISR);
2468 rl_outw(port, RL_ISR, isr);
2470 if (isr & RL_IMR_FOVW)
2472 isr &= ~RL_IMR_FOVW;
2473 /* Should do anything? */
2475 rep->re_stat.ets_fifoOver++;
2477 if (isr & RL_IMR_PUN)
2479 isr &= ~RL_IMR_PUN;
2481 /* Either the link status changed or there was a TX fifo
2482 * underrun.
2484 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
2485 if (link_up != rep->re_link_up)
2487 rep->re_report_link= TRUE;
2488 rep->re_got_int= TRUE;
2489 int_event_check = TRUE;
2492 if (isr & RL_IMR_RXOVW)
2494 isr &= ~RL_IMR_RXOVW;
2496 /* Clear the receive buffer */
2497 rep->re_clear_rx= TRUE;
2498 rep->re_got_int= TRUE;
2499 int_event_check = TRUE;
2502 if (isr & (RL_ISR_RER | RL_ISR_ROK))
2504 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
2506 if (!rep->re_got_int && (rep->re_flags & REF_READING))
2508 rep->re_got_int= TRUE;
2509 int_event_check = TRUE;
2512 #if 0
2513 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
2514 (rep->re_flags & REF_SEND_AVAIL) &&
2515 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
2516 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
2519 printf(
2520 "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2521 rep->re_tx_head, rep->re_tx_tail,
2522 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2523 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2524 printf(
2525 "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2526 rl_inw(port, RL_TSAD),
2527 rl_inl(port, RL_TSD0+0*4),
2528 rl_inl(port, RL_TSD0+1*4),
2529 rl_inl(port, RL_TSD0+2*4),
2530 rl_inl(port, RL_TSD0+3*4));
2532 #endif
2533 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
2535 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
2537 tsad= rl_inw(port, RL_TSAD);
2538 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
2539 RL_TSAD_TABT2|RL_TSAD_TABT3))
2541 #if 0
2542 /* Do we need a watch dog? */
2543 /* Just reset the whole chip */
2544 rep->re_need_reset= TRUE;
2545 rep->re_got_int= TRUE;
2546 int_event_check = TRUE;
2547 #elif 0
2548 /* Reset transmitter */
2549 rep->re_stat.ets_transAb++;
2551 cr= rl_inb(port, RL_CR);
2552 cr &= ~RL_CR_TE;
2553 rl_outb(port, RL_CR, cr);
2554 getuptime(&t0);
2555 do {
2556 if (!(rl_inb(port, RL_CR) & RL_CR_TE))
2557 break;
2558 } while (getuptime(&t1)==OK && (t1-t0) < system_hz);
2559 if (rl_inb(port, RL_CR) & RL_CR_TE)
2561 panic("rtl8139","cannot disable transmitter",
2562 NO_NUM);
2564 rl_outb(port, RL_CR, cr | RL_CR_TE);
2566 tcr= rl_inl(port, RL_TCR);
2567 rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
2569 printf("rl_handler: reset after abort\n");
2571 if (rep->re_flags & REF_SEND_AVAIL)
2573 printf("rl_handler: REF_SEND_AVAIL\n");
2574 rep->re_send_int= TRUE;
2575 rep->re_got_int= TRUE;
2576 int_event_check = TRUE;
2578 for (i= 0; i< N_TX_BUF; i++)
2579 rep->re_tx[i].ret_busy= FALSE;
2580 rep->re_tx_head= 0;
2581 #else
2582 printf("rl_handler, TABT, tasd = 0x%04x\n",
2583 tsad);
2585 /* Find the aborted transmit request */
2586 for (i= 0; i< N_TX_BUF; i++)
2588 tsd= rl_inl(port, RL_TSD0+i*4);
2589 if (tsd & RL_TSD_TABT)
2590 break;
2592 if (i >= N_TX_BUF)
2594 printf(
2595 "rl_handler: can't find aborted TX req.\n");
2597 else
2599 printf("TSD%d = 0x%04lx\n", i, tsd);
2601 /* Set head and tail to this buffer */
2602 rep->re_tx_head= rep->re_tx_tail= i;
2605 /* Aborted transmission, just kick the device
2606 * and be done with it.
2608 rep->re_stat.ets_transAb++;
2609 tcr= rl_inl(port, RL_TCR);
2610 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2611 #endif
2614 /* Transmit completed */
2615 tx_head= rep->re_tx_head;
2616 tx_tail= rep->re_tx_tail;
2617 for (i= 0; i< 2*N_TX_BUF; i++)
2619 if (!rep->re_tx[tx_tail].ret_busy)
2621 /* Strange, this buffer is not in-use.
2622 * Increment tx_tail until tx_head is
2623 * reached (or until we find a buffer that
2624 * is in-use.
2626 if (tx_tail == tx_head)
2627 break;
2628 if (++tx_tail >= N_TX_BUF)
2629 tx_tail= 0;
2630 assert(tx_tail < RL_N_TX);
2631 rep->re_tx_tail= tx_tail;
2632 continue;
2634 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
2635 if (!(tsd & RL_TSD_OWN))
2637 /* Buffer is not yet ready */
2638 break;
2641 /* Should collect statistics */
2642 if (tsd & RL_TSD_CRS)
2643 rep->re_stat.ets_carrSense++;
2644 if (tsd & RL_TSD_TABT)
2646 printf("rl_handler, TABT, TSD%d = 0x%04lx\n",
2647 tx_tail, tsd);
2648 assert(0); /* CLRABT is not all that
2649 * effective, why not?
2651 rep->re_stat.ets_transAb++;
2652 tcr= rl_inl(port, RL_TCR);
2653 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2655 if (tsd & RL_TSD_OWC)
2656 rep->re_stat.ets_OWC++;
2657 if (tsd & RL_TSD_CDH)
2658 rep->re_stat.ets_CDheartbeat++;
2660 /* What about collisions? */
2661 if (tsd & RL_TSD_TOK)
2662 rep->re_stat.ets_packetT++;
2663 else
2664 rep->re_stat.ets_sendErr++;
2665 if (tsd & RL_TSD_TUN)
2667 rep->re_stat.ets_fifoUnder++;
2669 /* Increase ERTXTH */
2670 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
2671 ertxth &= RL_TSD_ERTXTH_M;
2672 if (debug && ertxth > rep->re_ertxth)
2674 printf("%s: new ertxth: %ld bytes\n",
2675 rep->re_name,
2676 (ertxth >> RL_TSD_ERTXTH_S) *
2677 32);
2678 rep->re_ertxth= ertxth;
2681 rep->re_tx[tx_tail].ret_busy= FALSE;
2683 #if 0
2684 if (rep->re_flags & REF_SEND_AVAIL)
2686 printf("TSD%d: %08lx\n", tx_tail, tsd);
2687 printf(
2688 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
2689 tx_head, tx_tail,
2690 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2691 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2693 #endif
2695 if (++tx_tail >= N_TX_BUF)
2696 tx_tail= 0;
2697 assert(tx_tail < RL_N_TX);
2698 rep->re_tx_tail= tx_tail;
2700 if (rep->re_flags & REF_SEND_AVAIL)
2702 #if 0
2703 printf("rl_handler: REF_SEND_AVAIL\n");
2704 #endif
2705 rep->re_send_int= TRUE;
2706 if (!rep->re_got_int)
2708 rep->re_got_int= TRUE;
2709 int_event_check = TRUE;
2713 assert(i < 2*N_TX_BUF);
2715 if (isr)
2717 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
2718 isr);
2721 return 1;
2724 /*===========================================================================*
2725 * rl_watchdog_f *
2726 *===========================================================================*/
2727 static void rl_watchdog_f(tp)
2728 timer_t *tp;
2730 int i;
2731 re_t *rep;
2732 /* Use a synchronous alarm instead of a watchdog timer. */
2733 sys_setalarm(system_hz, 0);
2735 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
2737 if (rep->re_mode != REM_ENABLED)
2738 continue;
2739 if (!(rep->re_flags & REF_SEND_AVAIL))
2741 /* Assume that an idle system is alive */
2742 rep->re_tx_alive= TRUE;
2743 continue;
2745 if (rep->re_tx_alive)
2747 rep->re_tx_alive= FALSE;
2748 continue;
2750 printf("rl_watchdog_f: resetting port %d\n", i);
2751 printf(
2752 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2753 rl_inw(rep->re_base_port, RL_TSAD),
2754 rl_inl(rep->re_base_port, RL_TSD0+0*4),
2755 rl_inl(rep->re_base_port, RL_TSD0+1*4),
2756 rl_inl(rep->re_base_port, RL_TSD0+2*4),
2757 rl_inl(rep->re_base_port, RL_TSD0+3*4));
2758 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2759 rep->re_tx_head, rep->re_tx_tail,
2760 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2761 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2762 rep->re_need_reset= TRUE;
2763 rep->re_got_int= TRUE;
2765 check_int_events();
2769 #if 0
2771 _PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
2772 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
2773 _PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
2774 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );
2775 _PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
2777 static void rtl_init(dep)
2778 dpeth_t *dep;
2780 u8_t reg_a, reg_b, cr, config0, config2, config3;
2781 int i;
2782 char val[128];
2784 printf("rtl_init called\n");
2785 ne_init(dep);
2787 /* ID */
2788 outb_reg0(dep, DP_CR, CR_PS_P0);
2789 reg_a = inb_reg0(dep, DP_DUM1);
2790 reg_b = inb_reg0(dep, DP_DUM2);
2792 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
2794 outb_reg0(dep, DP_CR, CR_PS_P3);
2795 config0 = inb_reg3(dep, 3);
2796 config2 = inb_reg3(dep, 5);
2797 config3 = inb_reg3(dep, 6);
2798 outb_reg0(dep, DP_CR, CR_PS_P0);
2800 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
2801 config0, config2, config3);
2803 if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
2805 printf("rtl_init: setting full-duplex mode\n");
2806 outb_reg0(dep, DP_CR, CR_PS_P3);
2808 cr= inb_reg3(dep, 1);
2809 outb_reg3(dep, 1, cr | 0xc0);
2811 outb_reg3(dep, 6, config3 | 0x40);
2812 config3 = inb_reg3(dep, 6);
2814 config2= inb_reg3(dep, 5);
2815 outb_reg3(dep, 5, config2 | 0x20);
2816 config2= inb_reg3(dep, 5);
2818 outb_reg3(dep, 1, cr);
2820 outb_reg0(dep, DP_CR, CR_PS_P0);
2822 printf("rtl_init: config 2 = %x\n", config2);
2823 printf("rtl_init: config 3 = %x\n", config3);
2826 for (i= 0; i<64; i++)
2827 printf("%x ", get_ee_word(dep, i));
2828 printf("\n");
2830 if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
2832 ee_wen(dep);
2834 set_ee_word(dep, 0x78/2, 0x10ec);
2835 set_ee_word(dep, 0x7A/2, 0x8029);
2836 set_ee_word(dep, 0x7C/2, 0x10ec);
2837 set_ee_word(dep, 0x7E/2, 0x8029);
2839 ee_wds(dep);
2841 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
2842 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
2843 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
2844 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
2847 if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
2849 ee_wen(dep);
2851 set_ee_word(dep, 0x76/2, 0x8029);
2853 ee_wds(dep);
2855 assert(get_ee_word(dep, 0x76/2) == 0x8029);
2859 static u16_t get_ee_word(dep, a)
2860 dpeth_t *dep;
2861 int a;
2863 int b, i, cmd;
2864 u16_t w;
2866 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2868 /* Switch to 9346 mode and enable CS */
2869 outb_reg3(dep, 1, 0x80 | 0x8);
2871 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
2872 for (i= 8; i >= 0; i--)
2874 b= (cmd & (1 << i));
2875 b= (b ? 2 : 0);
2877 /* Cmd goes out on the rising edge of the clock */
2878 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2879 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2881 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2883 w= 0;
2884 for (i= 0; i<16; i++)
2886 w <<= 1;
2888 /* Data is shifted out on the rising edge. Read at the
2889 * falling edge.
2891 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
2892 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2893 b= inb_reg3(dep, 1);
2894 w |= (b & 1);
2897 outb_reg3(dep, 1, 0x80); /* drop CS */
2898 outb_reg3(dep, 1, 0x00); /* back to normal */
2899 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2901 return w;
2904 static void ee_wen(dep)
2905 dpeth_t *dep;
2907 int b, i, cmd;
2908 u16_t w;
2910 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2912 /* Switch to 9346 mode and enable CS */
2913 outb_reg3(dep, 1, 0x80 | 0x8);
2915 cmd= 0x130; /* 1 0 0 1 1 x x x x */
2916 for (i= 8; i >= 0; i--)
2918 b= (cmd & (1 << i));
2919 b= (b ? 2 : 0);
2921 /* Cmd goes out on the rising edge of the clock */
2922 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2923 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2925 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2926 outb_reg3(dep, 1, 0x80); /* Drop CS */
2927 /* micro_delay(1); */ /* Is this required? */
2930 static void set_ee_word(dep, a, w)
2931 dpeth_t *dep;
2932 int a;
2933 u16_t w;
2935 int b, i, cmd;
2936 clock_t t0, t1;
2938 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2940 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
2941 for (i= 8; i >= 0; i--)
2943 b= (cmd & (1 << i));
2944 b= (b ? 2 : 0);
2946 /* Cmd goes out on the rising edge of the clock */
2947 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2948 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2950 for (i= 15; i >= 0; i--)
2952 b= (w & (1 << i));
2953 b= (b ? 2 : 0);
2955 /* Cmd goes out on the rising edge of the clock */
2956 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2957 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2959 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
2960 outb_reg3(dep, 1, 0x80); /* Drop CS */
2961 /* micro_delay(1); */ /* Is this required? */
2962 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2963 getuptime(&t0);
2964 do {
2965 if (inb_reg3(dep, 1) & 1)
2966 break;
2967 } while (getuptime(&t1) == OK && (t1 == t0));
2968 if (!(inb_reg3(dep, 1) & 1))
2969 panic("set_ee_word","device remains busy", NO_NUM);
2972 static void ee_wds(dep)
2973 dpeth_t *dep;
2975 int b, i, cmd;
2976 u16_t w;
2978 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2980 /* Switch to 9346 mode and enable CS */
2981 outb_reg3(dep, 1, 0x80 | 0x8);
2983 cmd= 0x100; /* 1 0 0 0 0 x x x x */
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 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2994 outb_reg3(dep, 1, 0x80); /* Drop CS */
2995 outb_reg3(dep, 1, 0x00); /* back to normal */
2996 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2998 #endif
3000 PRIVATE void tell_dev(buf, size, pci_bus, pci_dev, pci_func)
3001 vir_bytes buf;
3002 size_t size;
3003 int pci_bus;
3004 int pci_dev;
3005 int pci_func;
3007 int r;
3008 endpoint_t dev_e;
3009 u32_t u32;
3010 message m;
3012 r= ds_retrieve_label_num("amddev", &u32);
3013 if (r != OK)
3015 #if 0
3016 printf(
3017 "rtl8139`tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
3019 #endif
3020 return;
3023 dev_e= u32;
3025 m.m_type= IOMMU_MAP;
3026 m.m2_i1= pci_bus;
3027 m.m2_i2= pci_dev;
3028 m.m2_i3= pci_func;
3029 m.m2_l1= buf;
3030 m.m2_l2= size;
3032 r= sendrec(dev_e, &m);
3033 if (r != OK)
3035 printf("rtl8139`tell_dev: sendrec to %d failed: %d\n",
3036 dev_e, r);
3037 return;
3039 if (m.m_type != OK)
3041 printf("rtl8139`tell_dev: dma map request failed: %d\n",
3042 m.m_type);
3043 return;
3048 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $