top manpage update
[minix.git] / drivers / rtl8169 / rtl8169.c
blob0dae314f1574f76eaff5bd619dc6a4190c8bb1c3
1 /*
2 * rtl8169.c
4 * This file contains a ethernet device driver for Realtek rtl8169 based
5 * ethernet cards.
7 */
9 #include "../drivers.h"
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <minix/com.h>
15 #include <minix/ds.h>
16 #include <minix/syslib.h>
17 #include <minix/type.h>
18 #include <minix/sysutil.h>
19 #include <minix/endpoint.h>
20 #include <timers.h>
21 #include <net/hton.h>
22 #include <net/gen/ether.h>
23 #include <net/gen/eth_io.h>
24 #include <ibm/pci.h>
26 #include <sys/types.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include "../../kernel/const.h"
30 #include "../../kernel/config.h"
31 #include "../../kernel/type.h"
33 #define debug 1
34 #define printW() ((void)0)
36 #define VERBOSE 0 /* display message during init */
38 #include "rtl8169.h"
40 #define RE_PORT_NR 1 /* Minix */
42 #define IOVEC_NR 16 /* I/O vectors are handled IOVEC_NR entries at a time. */
44 #define RE_DTCC_VALUE 600 /* DTCC Update after every 10 minutes */
46 #define RX_CONFIG_MASK 0xff7e1880 /* Clears the bits supported by chip */
48 #define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK)
50 #define RL_ENVVAR "RTLETH" /* Configuration */
52 PRIVATE struct pcitab
54 u16_t vid;
55 u16_t did;
56 int checkclass;
57 } pcitab[] =
59 { 0x10ec, 0x8129, 0 }, /* Realtek RTL8129 */
60 { 0x10ec, 0x8167, 0 }, /* Realtek RTL8169/8110 Family Gigabit NIC */
61 { 0x10ec, 0x8169, 0 }, /* Realtek RTL8169 */
63 { 0x1186, 0x4300, 0 }, /* D-Link DGE-528T Gigabit adaptor */
65 { 0x1259, 0xc107, 0 }, /* Allied Telesyn International Gigabit Ethernet Adapter */
67 { 0x1385, 0x8169, 0 }, /* Netgear Gigabit Ethernet Adapter */
69 { 0x16ec, 0x0116, 0 }, /* US Robotics Realtek 8169S chip */
71 { 0x1737, 0x1032, 0 }, /* Linksys Instant Gigabit Desktop Network Interface */
73 { 0x0000, 0x0000, 0 }
76 typedef struct re_desc
78 u32_t status; /* command/status */
79 u32_t vlan; /* VLAN */
80 u32_t addr_low; /* low 32-bits of physical buffer address */
81 u32_t addr_high; /* high 32-bits of physical buffer address */
82 } re_desc;
84 typedef struct re_dtcc
86 u32_t TxOk_low; /* low 32-bits of Tx Ok packets */
87 u32_t TxOk_high; /* high 32-bits of Tx Ok packets */
88 u32_t RxOk_low; /* low 32-bits of Rx Ok packets */
89 u32_t RxOk_high; /* high 32-bits of Rx Ok packets */
90 u32_t TxEr_low; /* low 32-bits of Tx errors */
91 u32_t TxEr_high; /* high 32-bits of Tx errors */
92 u32_t RxEr; /* Rx errors */
93 u16_t MissPkt; /* Missed packets */
94 u16_t FAE; /* Frame Aignment Error packets (MII mode only) */
95 u32_t Tx1Col; /* Tx Ok packets with only 1 collision happened before Tx Ok */
96 u32_t TxMCol; /* Tx Ok packets with > 1 and < 16 collisions happened before Tx Ok */
97 u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets with physical addr destination ID */
98 u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets with physical addr destination ID */
99 u32_t RxOkBrd_low; /* low 32-bits of Rx Ok packets with broadcast destination ID */
100 u32_t RxOkBrd_high; /* high 32-bits of Rx Ok packets with broadcast destination ID */
101 u32_t RxOkMul; /* Rx Ok Packets with multicast destination ID */
102 u16_t TxAbt; /* Tx abort packets */
103 u16_t TxUndrn; /* Tx underrun packets */
104 } re_dtcc;
106 typedef struct re {
107 port_t re_base_port;
108 int re_irq;
109 int re_mode;
110 int re_flags;
111 endpoint_t re_client;
112 int re_link_up;
113 int re_got_int;
114 int re_send_int;
115 int re_report_link;
116 int re_need_reset;
117 int re_tx_alive;
118 int setup;
119 u32_t re_mac;
120 char *re_model;
122 /* Rx */
123 int re_rx_head;
124 struct {
125 int ret_busy;
126 phys_bytes ret_buf;
127 char *v_ret_buf;
128 } re_rx[N_RX_DESC];
130 vir_bytes re_read_s;
131 re_desc *re_rx_desc; /* Rx descriptor buffer */
132 phys_bytes p_rx_desc; /* Rx descriptor buffer physical */
134 /* Tx */
135 int re_tx_head;
136 struct {
137 int ret_busy;
138 phys_bytes ret_buf;
139 char *v_ret_buf;
140 } re_tx[N_TX_DESC];
141 re_desc *re_tx_desc; /* Tx descriptor buffer */
142 phys_bytes p_tx_desc; /* Tx descriptor buffer physical */
144 /* PCI related */
145 int re_seen; /* TRUE iff device available */
146 u8_t re_pcibus;
147 u8_t re_pcidev;
148 u8_t re_pcifunc;
150 /* 'large' items */
151 int re_hook_id; /* IRQ hook id at kernel */
152 eth_stat_t re_stat;
153 phys_bytes dtcc_buf; /* Dump Tally Counter buffer physical */
154 re_dtcc *v_dtcc_buf; /* Dump Tally Counter buffer */
155 u32_t dtcc_counter; /* DTCC update counter */
156 ether_addr_t re_address;
157 message re_rx_mess;
158 message re_tx_mess;
159 char re_name[sizeof("rtl8169#n")];
160 iovec_t re_iovec[IOVEC_NR];
161 iovec_s_t re_iovec_s[IOVEC_NR];
162 u32_t interrupts;
164 re_t;
166 #define REM_DISABLED 0x0
167 #define REM_ENABLED 0x1
169 #define REF_PACK_SENT 0x001
170 #define REF_PACK_RECV 0x002
171 #define REF_SEND_AVAIL 0x004
172 #define REF_READING 0x010
173 #define REF_EMPTY 0x000
174 #define REF_PROMISC 0x040
175 #define REF_MULTI 0x080
176 #define REF_BROAD 0x100
177 #define REF_ENABLED 0x200
179 static re_t re_table[RE_PORT_NR];
181 static u16_t eth_ign_proto;
182 static timer_t rl_watchdog;
184 FORWARD _PROTOTYPE(unsigned my_inb, (U16_t port));
185 FORWARD _PROTOTYPE(unsigned my_inw, (U16_t port));
186 FORWARD _PROTOTYPE(unsigned my_inl, (U16_t port));
187 static unsigned my_inb(U16_t port)
189 u32_t value;
190 int s;
191 if ((s = sys_inb(port, &value)) != OK)
192 printf("RTL8169: warning, sys_inb failed: %d\n", s);
193 return value;
195 static unsigned my_inw(U16_t port)
197 u32_t value;
198 int s;
199 if ((s = sys_inw(port, &value)) != OK)
200 printf("RTL8169: warning, sys_inw failed: %d\n", s);
201 return value;
203 static unsigned my_inl(U16_t port)
205 U32_t value;
206 int s;
207 if ((s = sys_inl(port, &value)) != OK)
208 printf("RTL8169: warning, sys_inl failed: %d\n", s);
209 return value;
211 #define rl_inb(port, offset) (my_inb((port) + (offset)))
212 #define rl_inw(port, offset) (my_inw((port) + (offset)))
213 #define rl_inl(port, offset) (my_inl((port) + (offset)))
215 FORWARD _PROTOTYPE(void my_outb, (U16_t port, U8_t value));
216 FORWARD _PROTOTYPE(void my_outw, (U16_t port, U16_t value));
217 FORWARD _PROTOTYPE(void my_outl, (U16_t port, U32_t value));
218 static void my_outb(U16_t port, U8_t value)
220 int s;
222 if ((s = sys_outb(port, value)) != OK)
223 printf("RTL8169: warning, sys_outb failed: %d\n", s);
225 static void my_outw(U16_t port, U16_t value)
227 int s;
229 if ((s = sys_outw(port, value)) != OK)
230 printf("RTL8169: warning, sys_outw failed: %d\n", s);
232 static void my_outl(U16_t port, U32_t value)
234 int s;
236 if ((s = sys_outl(port, value)) != OK)
237 printf("RTL8169: warning, sys_outl failed: %d\n", s);
239 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
240 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
241 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
243 _PROTOTYPE( static void rl_init, (message *mp) );
244 _PROTOTYPE( static void rl_pci_conf, (void) );
245 _PROTOTYPE( static int rl_probe, (re_t *rep) );
246 _PROTOTYPE( static void rl_conf_hw, (re_t *rep) );
247 _PROTOTYPE( static void rl_init_buf, (re_t *rep) );
248 _PROTOTYPE( static void rl_init_hw, (re_t *rep) );
249 _PROTOTYPE( static void rl_reset_hw, (re_t *rep) );
250 _PROTOTYPE( static void rl_confaddr, (re_t *rep) );
251 _PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
252 _PROTOTYPE( static void rl_readv_s, (message *mp, int from_int) );
253 _PROTOTYPE( static void rl_writev_s, (message *mp, int from_int) );
254 _PROTOTYPE( static void rl_check_ints, (re_t *rep) );
255 _PROTOTYPE( static void rl_report_link, (re_t *rep) );
256 _PROTOTYPE( static void rl_do_reset, (re_t *rep) );
257 _PROTOTYPE( static void rl_getstat, (message *mp) );
258 _PROTOTYPE( static void rl_getstat_s, (message *mp) );
259 _PROTOTYPE( static void rl_getname, (message *mp) );
260 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
261 _PROTOTYPE( static void mess_reply, (message *req, message *reply) );
262 _PROTOTYPE( static void rtl8169_stop, (void) );
263 _PROTOTYPE( static void check_int_events, (void) );
264 _PROTOTYPE( static void do_hard_int, (void) );
265 _PROTOTYPE( static void rtl8169_dump, (void) );
266 _PROTOTYPE( static void dump_phy, (re_t *rep) );
267 _PROTOTYPE( static int rl_handler, (re_t *rep) );
268 _PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) );
271 * The message used in the main loop is made global, so that rl_watchdog_f()
272 * can change its message type to fake an interrupt message.
274 PRIVATE message m;
275 PRIVATE int int_event_check; /* set to TRUE if events arrived */
277 static char *progname;
278 u32_t system_hz;
280 /* SEF functions and variables. */
281 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
282 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
283 EXTERN int env_argc;
284 EXTERN char **env_argv;
286 /*===========================================================================*
287 * main *
288 *===========================================================================*/
289 int main(int argc, char *argv[])
291 int r;
293 /* SEF local startup. */
294 env_setargs(argc, argv);
295 sef_local_startup();
297 while (TRUE) {
298 if ((r = sef_receive(ANY, &m)) != OK)
299 panic("rtl8169", "sef_receive failed", r);
301 if (is_notify(m.m_type)) {
302 switch (_ENDPOINT_P(m.m_source)) {
303 case CLOCK:
305 * Under MINIX, synchronous alarms are used
306 * instead of watchdog functions.
307 * The approach is very different: MINIX VMD
308 * timeouts are handled within the kernel
309 * (the watchdog is executed by CLOCK), and
310 * notify() the driver in some cases. MINIX
311 * timeouts result in a SYN_ALARM message to
312 * the driver and thus are handled where they
313 * should be handled. Locally, watchdog
314 * functions are used again.
316 rl_watchdog_f(NULL);
317 break;
318 case HARDWARE:
319 do_hard_int();
320 if (int_event_check) {
321 check_int_events();
323 break ;
324 case PM_PROC_NR:
326 sigset_t set;
328 if (getsigset(&set) != 0) break;
330 if (sigismember(&set, SIGTERM))
331 rtl8169_stop();
333 break;
335 default:
336 panic("rtl8169", "illegal notify from",
337 m.m_type);
340 /* done, get nwe message */
341 continue;
344 switch (m.m_type) {
345 case DL_WRITEV_S: rl_writev_s(&m, FALSE); break;
346 case DL_READV_S: rl_readv_s(&m, FALSE); break;
347 case DL_CONF: rl_init(&m); break;
348 case DL_GETSTAT: rl_getstat(&m); break;
349 case DL_GETSTAT_S: rl_getstat_s(&m); break;
350 case DL_GETNAME: rl_getname(&m); break;
351 default:
352 panic("rtl8169", "illegal message", m.m_type);
357 /*===========================================================================*
358 * sef_local_startup *
359 *===========================================================================*/
360 PRIVATE void sef_local_startup()
362 /* Register init callbacks. */
363 sef_setcb_init_fresh(sef_cb_init_fresh);
364 sef_setcb_init_restart(sef_cb_init_fresh);
366 /* No live update support for now. */
368 /* Let SEF perform startup. */
369 sef_startup();
372 /*===========================================================================*
373 * sef_cb_init_fresh *
374 *===========================================================================*/
375 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
377 /* Initialize the rtl8169 driver. */
378 u32_t inet_proc_nr;
379 int r;
380 re_t *rep;
381 long v;
383 system_hz = sys_hz();
385 (progname = strrchr(env_argv[0], '/')) ? progname++
386 : (progname = env_argv[0]);
388 v = 0;
389 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
390 eth_ign_proto = htons((u16_t) v);
392 /* Claim buffer memory now under Minix, before MM takes it all. */
393 for (rep = &re_table[0]; rep < re_table + RE_PORT_NR; rep++)
394 rl_init_buf(rep);
397 * Try to notify INET that we are present (again). If INET cannot
398 * be found, assume this is the first time we started and INET is
399 * not yet alive.
401 #if 0
402 r = ds_retrieve_label_num("inet", &inet_proc_nr);
403 if (r == OK)
404 notify(inet_proc_nr);
405 else if (r != ESRCH)
406 printf("rtl8169: ds_retrieve_label_num failed for 'inet': %d\n",
408 #endif
410 return(OK);
413 static void mdio_write(U16_t port, int regaddr, int value)
415 int i;
417 rl_outl(port, RL_PHYAR, 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF));
419 for (i = 20; i > 0; i--) {
421 * Check if the RTL8169 has completed writing to the specified
422 * MII register
424 if (!(rl_inl(port, RL_PHYAR) & 0x80000000))
425 break;
426 else
427 micro_delay(50);
431 static int mdio_read(U16_t port, int regaddr)
433 int i, value = -1;
435 rl_outl(port, RL_PHYAR, (regaddr & 0x1F) << 16);
437 for (i = 20; i > 0; i--) {
439 * Check if the RTL8169 has completed retrieving data from
440 * the specified MII register
442 if (rl_inl(port, RL_PHYAR) & 0x80000000) {
443 value = (int)(rl_inl(port, RL_PHYAR) & 0xFFFF);
444 break;
445 } else
446 micro_delay(50);
448 return value;
451 /*===========================================================================*
452 * check_int_events *
453 *===========================================================================*/
454 static void check_int_events(void)
456 int i;
457 re_t *rep;
459 for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
460 if (rep->re_mode != REM_ENABLED)
461 continue;
462 if (!rep->re_got_int)
463 continue;
464 rep->re_got_int = 0;
465 assert(rep->re_flags & REF_ENABLED);
466 rl_check_ints(rep);
470 /*===========================================================================*
471 * rtl8169_stop *
472 *===========================================================================*/
473 static void rtl8169_stop()
475 int i;
476 re_t *rep;
478 for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
479 if (rep->re_mode != REM_ENABLED)
480 continue;
481 rl_outb(rep->re_base_port, RL_CR, 0);
484 exit(0);
487 static void rtl8169_update_stat(re_t *rep)
489 port_t port;
490 int i;
492 port = rep->re_base_port;
494 /* Fetch Missed Packets */
495 rep->re_stat.ets_missedP += rl_inw(port, RL_MPC);
496 rl_outw(port, RL_MPC, 0x00);
498 /* Dump Tally Counter Command */
499 rl_outl(port, RL_DTCCR_HI, 0); /* 64 bits */
500 rl_outl(port, RL_DTCCR_LO, rep->dtcc_buf | RL_DTCCR_CMD);
501 for (i = 0; i < 1000; i++) {
502 if (!(rl_inl(port, RL_DTCCR_LO) & RL_DTCCR_CMD))
503 break;
504 micro_delay(10);
507 /* Update counters */
508 rep->re_stat.ets_frameAll = rep->v_dtcc_buf->FAE;
509 rep->re_stat.ets_transDef = rep->v_dtcc_buf->TxUndrn;
510 rep->re_stat.ets_transAb = rep->v_dtcc_buf->TxAbt;
511 rep->re_stat.ets_collision =
512 rep->v_dtcc_buf->Tx1Col + rep->v_dtcc_buf->TxMCol;
515 /*===========================================================================*
516 * rtl8169_dump *
517 *===========================================================================*/
518 static void rtl8169_dump(void)
520 re_dtcc *dtcc;
521 re_t *rep;
522 int i;
524 printf("\n");
525 for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
526 if (rep->re_mode == REM_DISABLED)
527 printf("Realtek RTL 8169 port %d is disabled\n", i);
529 if (rep->re_mode != REM_ENABLED)
530 continue;
532 rtl8169_update_stat(rep);
534 printf("Realtek RTL 8169 statistics of port %d:\n", i);
536 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
537 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
538 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
540 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
541 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
542 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
544 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
545 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
546 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
548 printf("collision :%8ld\t", rep->re_stat.ets_collision);
549 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
550 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
552 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
553 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
554 printf("OWC :%8ld\n", rep->re_stat.ets_OWC);
555 printf("interrupts :%8lu\n", rep->interrupts);
557 printf("\nRealtek RTL 8169 Tally Counters:\n");
559 dtcc = rep->v_dtcc_buf;
561 if (dtcc->TxOk_high)
562 printf("TxOk :%8ld%08ld\t", dtcc->TxOk_high, dtcc->TxOk_low);
563 else
564 printf("TxOk :%16lu\t", dtcc->TxOk_low);
566 if (dtcc->RxOk_high)
567 printf("RxOk :%8ld%08ld\n", dtcc->RxOk_high, dtcc->RxOk_low);
568 else
569 printf("RxOk :%16lu\n", dtcc->RxOk_low);
571 if (dtcc->TxEr_high)
572 printf("TxEr :%8ld%08ld\t", dtcc->TxEr_high, dtcc->TxEr_low);
573 else
574 printf("TxEr :%16ld\t", dtcc->TxEr_low);
576 printf("RxEr :%16ld\n", dtcc->RxEr);
578 printf("Tx1Col :%16ld\t", dtcc->Tx1Col);
579 printf("TxMCol :%16ld\n", dtcc->TxMCol);
581 if (dtcc->RxOkPhy_high)
582 printf("RxOkPhy :%8ld%08ld\t", dtcc->RxOkPhy_high, dtcc->RxOkPhy_low);
583 else
584 printf("RxOkPhy :%16ld\t", dtcc->RxOkPhy_low);
586 if (dtcc->RxOkBrd_high)
587 printf("RxOkBrd :%8ld%08ld\n", dtcc->RxOkBrd_high, dtcc->RxOkBrd_low);
588 else
589 printf("RxOkBrd :%16ld\n", dtcc->RxOkBrd_low);
591 printf("RxOkMul :%16ld\t", dtcc->RxOkMul);
592 printf("MissPkt :%16d\n", dtcc->MissPkt);
594 printf("\nRealtek RTL 8169 Miscellaneous Info:\n");
596 printf("re_flags : 0x%08x\n", rep->re_flags);
597 printf("tx_head :%8d busy %d\t",
598 rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy);
602 /*===========================================================================*
603 * do_init *
604 *===========================================================================*/
605 static void rl_init(mp)
606 message *mp;
608 static int first_time = 1;
610 int port;
611 re_t *rep;
612 message reply_mess;
614 if (first_time) {
615 first_time = 0;
616 rl_pci_conf(); /* Configure PCI devices. */
618 tmr_inittimer(&rl_watchdog);
619 /* Use a synchronous alarm instead of a watchdog timer. */
620 sys_setalarm(system_hz, 0);
623 port = mp->DL_PORT;
624 if (port < 0 || port >= RE_PORT_NR) {
625 reply_mess.m_type = DL_CONF_REPLY;
626 reply_mess.m3_i1 = ENXIO;
627 mess_reply(mp, &reply_mess);
628 return;
630 rep = &re_table[port];
631 if (rep->re_mode == REM_DISABLED) {
632 /* This is the default, try to (re)locate the device. */
633 rl_conf_hw(rep);
634 if (rep->re_mode == REM_DISABLED) {
635 /* Probe failed, or the device is configured off. */
636 reply_mess.m_type = DL_CONF_REPLY;
637 reply_mess.m3_i1 = ENXIO;
638 mess_reply(mp, &reply_mess);
639 return;
641 if (rep->re_mode == REM_ENABLED)
642 rl_init_hw(rep);
645 assert(rep->re_mode == REM_ENABLED);
646 assert(rep->re_flags & REF_ENABLED);
648 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
650 if (mp->DL_MODE & DL_PROMISC_REQ)
651 rep->re_flags |= REF_PROMISC;
652 if (mp->DL_MODE & DL_MULTI_REQ)
653 rep->re_flags |= REF_MULTI;
654 if (mp->DL_MODE & DL_BROAD_REQ)
655 rep->re_flags |= REF_BROAD;
657 rep->re_client = mp->m_source;
658 rl_rec_mode(rep);
660 reply_mess.m_type = DL_CONF_REPLY;
661 reply_mess.m3_i1 = mp->DL_PORT;
662 reply_mess.m3_i2 = RE_PORT_NR;
663 *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
665 mess_reply(mp, &reply_mess);
668 /*===========================================================================*
669 * rl_pci_conf *
670 *===========================================================================*/
671 static void rl_pci_conf()
673 int i, h;
674 re_t *rep;
675 static char envvar[] = RL_ENVVAR "#";
676 static char envfmt[] = "*:d.d.d";
677 static char val[128];
678 long v;
680 for (i = 0, rep = re_table; i < RE_PORT_NR; i++, rep++) {
681 strcpy(rep->re_name, "rtl8169#0");
682 rep->re_name[8] += i;
683 rep->re_seen = FALSE;
684 envvar[sizeof(RL_ENVVAR)-1] = '0' + i;
685 if (0 == env_get_param(envvar, val, sizeof(val)) &&
686 !env_prefix(envvar, "pci"))
688 env_panic(envvar);
690 v = 0;
691 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
692 rep->re_pcibus = v;
693 v = 0;
694 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
695 rep->re_pcidev = v;
696 v = 0;
697 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
698 rep->re_pcifunc = v;
701 pci_init();
703 for (h = 1; h >= 0; h--) {
704 for (i = 0, rep = re_table; i < RE_PORT_NR; i++, rep++) {
705 if (((rep->re_pcibus | rep->re_pcidev |
706 rep->re_pcifunc) != 0) != h) {
707 continue;
709 if (rl_probe(rep))
710 rep->re_seen = TRUE;
715 /*===========================================================================*
716 * rl_probe *
717 *===========================================================================*/
718 static int rl_probe(rep)
719 re_t *rep;
721 int i, r, devind, just_one;
722 u16_t vid, did;
723 u32_t bar;
724 u8_t ilr;
725 char *dname;
727 if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0) {
728 /* Look for specific PCI device */
729 r = pci_find_dev(rep->re_pcibus, rep->re_pcidev,
730 rep->re_pcifunc, &devind);
731 if (r == 0) {
732 printf("%s: no PCI found at %d.%d.%d\n",
733 rep->re_name, rep->re_pcibus,
734 rep->re_pcidev, rep->re_pcifunc);
735 return 0;
737 pci_ids(devind, &vid, &did);
738 just_one = TRUE;
739 } else {
740 r = pci_first_dev(&devind, &vid, &did);
741 if (r == 0)
742 return 0;
743 just_one = FALSE;
746 for (;;) {
747 for (i = 0; pcitab[i].vid != 0; i++) {
748 if (pcitab[i].vid != vid)
749 continue;
750 if (pcitab[i].did != did)
751 continue;
752 if (pcitab[i].checkclass) {
753 panic("rtl_probe",
754 "class check not implemented", NO_NUM);
756 break;
758 if (pcitab[i].vid != 0)
759 break;
761 if (just_one) {
762 printf("%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
763 rep->re_name, vid, did,
764 rep->re_pcibus,
765 rep->re_pcidev, rep->re_pcifunc);
766 return 0;
769 r = pci_next_dev(&devind, &vid, &did);
770 if (!r)
771 return 0;
774 dname = pci_dev_name(vid, did);
775 if (!dname)
776 dname = "unknown device";
777 printf("%s: ", rep->re_name);
778 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
780 pci_reserve(devind);
781 bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
782 if (bar < 0x400) {
783 panic("rtl_probe",
784 "base address is not properly configured", NO_NUM);
786 rep->re_base_port = bar;
788 ilr = pci_attr_r8(devind, PCI_ILR);
789 rep->re_irq = ilr;
790 if (debug) {
791 printf("%s: using I/O address 0x%lx, IRQ %d\n",
792 rep->re_name, (unsigned long)bar, ilr);
795 return TRUE;
798 /*===========================================================================*
799 * rl_conf_hw *
800 *===========================================================================*/
801 static void rl_conf_hw(rep)
802 re_t *rep;
804 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
806 rep->re_mode = REM_DISABLED; /* Superfluous */
808 if (rep->re_seen)
809 rep->re_mode = REM_ENABLED; /* PCI device is present */
810 if (rep->re_mode != REM_ENABLED)
811 return;
813 rep->re_flags = REF_EMPTY;
814 rep->re_link_up = 0;
815 rep->re_got_int = 0;
816 rep->re_send_int = 0;
817 rep->re_report_link = 0;
818 rep->re_need_reset = 0;
819 rep->re_tx_alive = 0;
820 rep->re_rx_head = 0;
821 rep->re_read_s = 0;
822 rep->re_tx_head = 0;
823 rep->re_stat = empty_stat;
824 rep->dtcc_counter = 0;
827 /*===========================================================================*
828 * rl_init_buf *
829 *===========================================================================*/
830 static void rl_init_buf(rep)
831 re_t *rep;
833 size_t rx_bufsize, tx_bufsize, rx_descsize, tx_descsize, tot_bufsize;
834 struct re_desc *desc;
835 phys_bytes buf;
836 char *mallocbuf;
837 int d;
839 assert(!rep->setup);
841 /* Allocate receive and transmit descriptors */
842 rx_descsize = (N_RX_DESC * sizeof(struct re_desc));
843 tx_descsize = (N_TX_DESC * sizeof(struct re_desc));
845 /* Allocate receive and transmit buffers */
846 tx_bufsize = ETH_MAX_PACK_SIZE_TAGGED;
847 if (tx_bufsize % 4)
848 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
849 rx_bufsize = RX_BUFSIZE;
850 tot_bufsize = rx_descsize + tx_descsize;
851 tot_bufsize += (N_TX_DESC * tx_bufsize) + (N_RX_DESC * rx_bufsize);
852 tot_bufsize += sizeof(struct re_dtcc);
854 if (tot_bufsize % 4096)
855 tot_bufsize += 4096 - (tot_bufsize % 4096);
857 if (!(mallocbuf = alloc_contig(tot_bufsize, AC_ALIGN64K, &buf)))
858 panic("RTL8169", "Couldn't allocate kernel buffer", NO_NUM);
860 /* Rx Descriptor */
861 rep->re_rx_desc = (re_desc *)mallocbuf;
862 rep->p_rx_desc = buf;
863 memset(mallocbuf, 0x00, rx_descsize);
864 buf += rx_descsize;
865 mallocbuf += rx_descsize;
867 /* Tx Descriptor */
868 rep->re_tx_desc = (re_desc *)mallocbuf;
869 rep->p_tx_desc = buf;
870 memset(mallocbuf, 0x00, tx_descsize);
871 buf += tx_descsize;
872 mallocbuf += tx_descsize;
874 desc = rep->re_rx_desc;
875 for (d = 0; d < N_RX_DESC; d++) {
876 /* Setting Rx buffer */
877 rep->re_rx[d].ret_buf = buf;
878 rep->re_rx[d].v_ret_buf = mallocbuf;
879 buf += rx_bufsize;
880 mallocbuf += rx_bufsize;
882 /* Setting Rx descriptor */
883 if (d == (N_RX_DESC - 1)) /* Last descriptor? if so, set the EOR bit */
884 desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
885 else
886 desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
888 desc->addr_low = rep->re_rx[d].ret_buf;
889 desc++;
891 desc = rep->re_tx_desc;
892 for (d = 0; d < N_TX_DESC; d++) {
893 rep->re_tx[d].ret_busy = FALSE;
894 rep->re_tx[d].ret_buf = buf;
895 rep->re_tx[d].v_ret_buf = mallocbuf;
896 buf += tx_bufsize;
897 mallocbuf += tx_bufsize;
899 /* Setting Tx descriptor */
900 desc->addr_low = rep->re_tx[d].ret_buf;
901 desc++;
904 /* Dump Tally Counter buffer */
905 rep->dtcc_buf = buf;
906 rep->v_dtcc_buf = (re_dtcc *)mallocbuf;
908 rep->setup = 1;
911 /*===========================================================================*
912 * rl_init_hw *
913 *===========================================================================*/
914 static void rl_init_hw(rep)
915 re_t *rep;
917 int s, i;
919 rep->re_flags = REF_EMPTY;
920 rep->re_flags |= REF_ENABLED;
923 * Set the interrupt handler. The policy is to only send HARD_INT
924 * notifications. Don't reenable interrupts automatically. The id
925 * that is passed back is the interrupt line number.
927 rep->re_hook_id = rep->re_irq;
928 if ((s = sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
929 printf("RTL8169: error, couldn't set IRQ policy: %d\n", s);
931 rl_reset_hw(rep);
933 if ((s = sys_irqenable(&rep->re_hook_id)) != OK)
934 printf("RTL8169: error, couldn't enable interrupts: %d\n", s);
936 printf("%s: model: %s mac: 0x%08lx\n",
937 rep->re_name, rep->re_model, rep->re_mac);
939 rl_confaddr(rep);
940 if (debug) {
941 printf("%s: Ethernet address ", rep->re_name);
942 for (i = 0; i < 6; i++) {
943 printf("%x%c", rep->re_address.ea_addr[i],
944 i < 5 ? ':' : '\n');
949 static void rtl8169s_phy_config(port_t port)
951 mdio_write(port, 0x1f, 0x0001);
952 mdio_write(port, 0x06, 0x006e);
953 mdio_write(port, 0x08, 0x0708);
954 mdio_write(port, 0x15, 0x4000);
955 mdio_write(port, 0x18, 0x65c7);
957 mdio_write(port, 0x1f, 0x0001);
958 mdio_write(port, 0x03, 0x00a1);
959 mdio_write(port, 0x02, 0x0008);
960 mdio_write(port, 0x01, 0x0120);
961 mdio_write(port, 0x00, 0x1000);
962 mdio_write(port, 0x04, 0x0800);
963 mdio_write(port, 0x04, 0x0000);
965 mdio_write(port, 0x03, 0xff41);
966 mdio_write(port, 0x02, 0xdf60);
967 mdio_write(port, 0x01, 0x0140);
968 mdio_write(port, 0x00, 0x0077);
969 mdio_write(port, 0x04, 0x7800);
970 mdio_write(port, 0x04, 0x7000);
972 mdio_write(port, 0x03, 0x802f);
973 mdio_write(port, 0x02, 0x4f02);
974 mdio_write(port, 0x01, 0x0409);
975 mdio_write(port, 0x00, 0xf0f9);
976 mdio_write(port, 0x04, 0x9800);
977 mdio_write(port, 0x04, 0x9000);
979 mdio_write(port, 0x03, 0xdf01);
980 mdio_write(port, 0x02, 0xdf20);
981 mdio_write(port, 0x01, 0xff95);
982 mdio_write(port, 0x00, 0xba00);
983 mdio_write(port, 0x04, 0xa800);
984 mdio_write(port, 0x04, 0xa000);
986 mdio_write(port, 0x03, 0xff41);
987 mdio_write(port, 0x02, 0xdf20);
988 mdio_write(port, 0x01, 0x0140);
989 mdio_write(port, 0x00, 0x00bb);
990 mdio_write(port, 0x04, 0xb800);
991 mdio_write(port, 0x04, 0xb000);
993 mdio_write(port, 0x03, 0xdf41);
994 mdio_write(port, 0x02, 0xdc60);
995 mdio_write(port, 0x01, 0x6340);
996 mdio_write(port, 0x00, 0x007d);
997 mdio_write(port, 0x04, 0xd800);
998 mdio_write(port, 0x04, 0xd000);
1000 mdio_write(port, 0x03, 0xdf01);
1001 mdio_write(port, 0x02, 0xdf20);
1002 mdio_write(port, 0x01, 0x100a);
1003 mdio_write(port, 0x00, 0xa0ff);
1004 mdio_write(port, 0x04, 0xf800);
1005 mdio_write(port, 0x04, 0xf000);
1007 mdio_write(port, 0x1f, 0x0000);
1008 mdio_write(port, 0x0b, 0x0000);
1009 mdio_write(port, 0x00, 0x9200);
1012 static void rtl8169scd_phy_config(port_t port)
1014 mdio_write(port, 0x1f, 0x0001);
1015 mdio_write(port, 0x04, 0x0000);
1016 mdio_write(port, 0x03, 0x00a1);
1017 mdio_write(port, 0x02, 0x0008);
1018 mdio_write(port, 0x01, 0x0120);
1019 mdio_write(port, 0x00, 0x1000);
1020 mdio_write(port, 0x04, 0x0800);
1021 mdio_write(port, 0x04, 0x9000);
1022 mdio_write(port, 0x03, 0x802f);
1023 mdio_write(port, 0x02, 0x4f02);
1024 mdio_write(port, 0x01, 0x0409);
1025 mdio_write(port, 0x00, 0xf099);
1026 mdio_write(port, 0x04, 0x9800);
1027 mdio_write(port, 0x04, 0xa000);
1028 mdio_write(port, 0x03, 0xdf01);
1029 mdio_write(port, 0x02, 0xdf20);
1030 mdio_write(port, 0x01, 0xff95);
1031 mdio_write(port, 0x00, 0xba00);
1032 mdio_write(port, 0x04, 0xa800);
1033 mdio_write(port, 0x04, 0xf000);
1034 mdio_write(port, 0x03, 0xdf01);
1035 mdio_write(port, 0x02, 0xdf20);
1036 mdio_write(port, 0x01, 0x101a);
1037 mdio_write(port, 0x00, 0xa0ff);
1038 mdio_write(port, 0x04, 0xf800);
1039 mdio_write(port, 0x04, 0x0000);
1040 mdio_write(port, 0x1f, 0x0000);
1042 mdio_write(port, 0x1f, 0x0001);
1043 mdio_write(port, 0x10, 0xf41b);
1044 mdio_write(port, 0x14, 0xfb54);
1045 mdio_write(port, 0x18, 0xf5c7);
1046 mdio_write(port, 0x1f, 0x0000);
1048 mdio_write(port, 0x1f, 0x0001);
1049 mdio_write(port, 0x17, 0x0cc0);
1050 mdio_write(port, 0x1f, 0x0000);
1053 /*===========================================================================*
1054 * rl_reset_hw *
1055 *===========================================================================*/
1056 static void rl_reset_hw(rep)
1057 re_t *rep;
1059 port_t port;
1060 u32_t t;
1061 int i;
1062 clock_t t0, t1;
1064 port = rep->re_base_port;
1066 rl_outw(port, RL_IMR, 0x0000);
1068 /* Reset the device */
1069 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
1070 port, rl_inb(port, RL_CR));
1071 rl_outb(port, RL_CR, RL_CR_RST);
1072 getuptime(&t0);
1073 do {
1074 if (!(rl_inb(port, RL_CR) & RL_CR_RST))
1075 break;
1076 } while (getuptime(&t1) == OK && (t1 - t0) < system_hz);
1077 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
1078 port, rl_inb(port, RL_CR));
1079 if (rl_inb(port, RL_CR) & RL_CR_RST)
1080 printf("rtl8169: reset failed to complete");
1081 rl_outw(port, RL_ISR, 0xFFFF);
1083 /* Get Model and MAC info */
1084 t = rl_inl(port, RL_TCR);
1085 rep->re_mac = (t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
1086 switch (rep->re_mac) {
1087 case RL_TCR_HWVER_RTL8169:
1088 rep->re_model = "RTL8169";
1090 printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
1091 rl_outw(port, 0x82, 0x01);
1092 break;
1093 case RL_TCR_HWVER_RTL8169S:
1094 rep->re_model = "RTL8169S";
1096 rtl8169s_phy_config(port);
1098 printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
1099 rl_outw(port, 0x82, 0x01);
1100 printf("Set PHY Reg 0x0bh = 0x00h\n");
1101 mdio_write(port, 0x0b, 0x0000); /* w 0x0b 15 0 0 */
1102 break;
1103 case RL_TCR_HWVER_RTL8110S:
1104 rep->re_model = "RTL8110S";
1106 rtl8169s_phy_config(port);
1108 printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
1109 rl_outw(port, 0x82, 0x01);
1110 break;
1111 case RL_TCR_HWVER_RTL8169SB:
1112 rep->re_model = "RTL8169SB";
1114 mdio_write(port, 0x1f, 0x02);
1115 mdio_write(port, 0x01, 0x90d0);
1116 mdio_write(port, 0x1f, 0x00);
1118 printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
1119 rl_outw(port, 0x82, 0x01);
1120 break;
1121 case RL_TCR_HWVER_RTL8110SCd:
1122 rep->re_model = "RTL8110SCd";
1124 rtl8169scd_phy_config(port);
1126 printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
1127 rl_outw(port, 0x82, 0x01);
1128 break;
1129 default:
1130 rep->re_model = "Unknown";
1131 rep->re_mac = t;
1132 break;
1135 mdio_write(port, MII_CTRL, MII_CTRL_RST);
1136 for (i = 0; i < 1000; i++) {
1137 t = mdio_read(port, MII_CTRL);
1138 if (!(t & MII_CTRL_RST))
1139 break;
1140 else
1141 micro_delay(100);
1144 t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000;
1145 mdio_write(port, MII_CTRL, t);
1147 t = mdio_read(port, MII_ANA);
1148 t |= MII_ANA_10THD | MII_ANA_10TFD | MII_ANA_100TXHD | MII_ANA_100TXFD;
1149 t |= MII_ANA_PAUSE_SYM | MII_ANA_PAUSE_ASYM;
1150 mdio_write(port, MII_ANA, t);
1152 t = mdio_read(port, MII_1000_CTRL) | 0x300;
1153 mdio_write(port, MII_1000_CTRL, t);
1155 /* Restart Auto-Negotiation Process */
1156 t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_RAN;
1157 mdio_write(port, MII_CTRL, t);
1159 rl_outw(port, RL_9346CR, RL_9346CR_EEM_CONFIG); /* Unlock */
1161 t = rl_inw(port, RL_CPLUSCMD);
1162 if ((rep->re_mac == RL_TCR_HWVER_RTL8169S) ||
1163 (rep->re_mac == RL_TCR_HWVER_RTL8110S)) {
1164 printf("Set MAC Reg C+CR Offset 0xE0. "
1165 "Bit-3 and bit-14 MUST be 1\n");
1166 rl_outw(port, RL_CPLUSCMD, t | RL_CPLUS_MULRW | (1 << 14));
1167 } else
1168 rl_outw(port, RL_CPLUSCMD, t | RL_CPLUS_MULRW);
1170 rl_outw(port, RL_INTRMITIGATE, 0x00);
1172 t = rl_inb(port, RL_CR);
1173 rl_outb(port, RL_CR, t | RL_CR_RE | RL_CR_TE);
1175 /* Initialize Rx */
1176 rl_outw(port, RL_RMS, RX_BUFSIZE); /* Maximum rx packet size */
1177 t = rl_inl(port, RL_RCR) & RX_CONFIG_MASK;
1178 rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | t);
1179 rl_outl(port, RL_RDSAR_LO, rep->p_rx_desc);
1180 rl_outl(port, RL_RDSAR_HI, 0x00); /* For 64 bit */
1182 /* Initialize Tx */
1183 rl_outw(port, RL_ETTHR, 0x3f); /* No early transmit */
1184 rl_outl(port, RL_TCR, RL_TCR_MXDMA_2048 | RL_TCR_IFG_STD);
1185 rl_outl(port, RL_TNPDS_LO, rep->p_tx_desc);
1186 rl_outl(port, RL_TNPDS_HI, 0x00); /* For 64 bit */
1188 rl_outw(port, RL_9346CR, RL_9346CR_EEM_NORMAL); /* Lock */
1190 rl_outw(port, RL_MPC, 0x00);
1191 rl_outw(port, RL_MULINT, rl_inw(port, RL_MULINT) & 0xF000);
1192 rl_outw(port, RL_IMR, RE_INTR_MASK);
1195 /*===========================================================================*
1196 * rl_confaddr *
1197 *===========================================================================*/
1198 static void rl_confaddr(rep)
1199 re_t *rep;
1201 static char eakey[] = RL_ENVVAR "#_EA";
1202 static char eafmt[] = "x:x:x:x:x:x";
1204 int i;
1205 port_t port;
1206 u32_t w;
1207 long v;
1209 /* User defined ethernet address? */
1210 eakey[sizeof(RL_ENVVAR)-1] = '0' + (rep-re_table);
1212 port = rep->re_base_port;
1214 for (i = 0; i < 6; i++) {
1215 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
1216 break;
1217 rep->re_address.ea_addr[i] = v;
1220 if (i != 0 && i != 6)
1221 env_panic(eakey); /* It's all or nothing */
1223 /* Should update ethernet address in hardware */
1224 if (i == 6) {
1225 port = rep->re_base_port;
1226 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
1227 w = 0;
1228 for (i = 0; i < 4; i++)
1229 w |= (rep->re_address.ea_addr[i] << (i * 8));
1230 rl_outl(port, RL_IDR, w);
1231 w = 0;
1232 for (i = 4; i < 6; i++)
1233 w |= (rep->re_address.ea_addr[i] << ((i-4) * 8));
1234 rl_outl(port, RL_IDR + 4, w);
1235 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
1238 /* Get ethernet address */
1239 for (i = 0; i < 6; i++)
1240 rep->re_address.ea_addr[i] = rl_inb(port, RL_IDR+i);
1243 /*===========================================================================*
1244 * rl_rec_mode *
1245 *===========================================================================*/
1246 static void rl_rec_mode(rep)
1247 re_t *rep;
1249 port_t port;
1250 u32_t rcr;
1251 u32_t mc_filter[2]; /* Multicast hash filter */
1253 port = rep->re_base_port;
1255 mc_filter[1] = mc_filter[0] = 0xffffffff;
1256 rl_outl(port, RL_MAR + 0, mc_filter[0]);
1257 rl_outl(port, RL_MAR + 4, mc_filter[1]);
1259 rcr = rl_inl(port, RL_RCR);
1260 rcr &= ~(RL_RCR_AB | RL_RCR_AM | RL_RCR_APM | RL_RCR_AAP);
1261 if (rep->re_flags & REF_PROMISC)
1262 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
1263 if (rep->re_flags & REF_BROAD)
1264 rcr |= RL_RCR_AB;
1265 if (rep->re_flags & REF_MULTI)
1266 rcr |= RL_RCR_AM;
1267 rcr |= RL_RCR_APM;
1268 rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | rcr);
1271 void transmittest(re_t *rep)
1273 int tx_head;
1275 tx_head = rep->re_tx_head;
1277 if(rep->re_tx[tx_head].ret_busy) {
1278 do {
1279 message m;
1280 int r;
1281 if ((r = sef_receive(ANY, &m)) != OK)
1282 panic("rtl8169", "sef_receive failed", r);
1283 } while(m.m_source != HARDWARE);
1284 assert(!(rep->re_flags & REF_SEND_AVAIL));
1285 rep->re_flags |= REF_SEND_AVAIL;
1288 return;
1291 /*===========================================================================*
1292 * rl_readv_s *
1293 *===========================================================================*/
1294 static void rl_readv_s(message *mp, int from_int)
1296 int i, j, n, s, dl_port, re_client, count, size, index;
1297 port_t port;
1298 unsigned totlen, packlen;
1299 re_desc *desc;
1300 u32_t rxstat = 0x12345678;
1301 re_t *rep;
1302 iovec_s_t *iovp;
1303 int cps;
1304 int iov_offset = 0;
1306 dl_port = mp->DL_PORT;
1307 count = mp->DL_COUNT;
1308 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1309 panic("rtl8169", " illegal port", dl_port);
1310 rep = &re_table[dl_port];
1311 re_client = mp->DL_PROC;
1312 rep->re_client = re_client;
1314 assert(rep->re_mode == REM_ENABLED);
1315 assert(rep->re_flags & REF_ENABLED);
1317 port = rep->re_base_port;
1320 * Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1322 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1323 goto suspend; /* Receive buffer is empty, suspend */
1325 index = rep->re_rx_head;
1326 readvs_test_loop:
1327 desc = rep->re_rx_desc;
1328 desc += index;
1329 readvs_loop:
1330 rxstat = desc->status;
1332 if (rxstat & DESC_OWN)
1333 goto suspend;
1335 if (rxstat & DESC_RX_CRC)
1336 rep->re_stat.ets_CRCerr++;
1338 if ((rxstat & (DESC_FS | DESC_LS)) != (DESC_FS | DESC_LS)) {
1339 printf("rl_readv_s: packet is fragmented\n");
1340 /* Fix the fragmented packet */
1341 if (index == N_RX_DESC - 1) {
1342 desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
1343 index = 0;
1344 desc = rep->re_rx_desc;
1345 } else {
1346 desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
1347 index++;
1348 desc++;
1350 goto readvs_loop; /* Loop until we get correct packet */
1353 totlen = rxstat & DESC_RX_LENMASK;
1354 if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) {
1355 /* Someting went wrong */
1356 printf("rl_readv_s: bad length (%u) in status 0x%08lx\n",
1357 totlen, rxstat);
1358 panic(NULL, NULL, NO_NUM);
1361 /* Should subtract the CRC */
1362 packlen = totlen - ETH_CRC_SIZE;
1364 size = 0;
1365 for (i = 0; i < count; i += IOVEC_NR,
1366 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1368 n = IOVEC_NR;
1369 if (i + n > count)
1370 n = count-i;
1371 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1372 (vir_bytes) rep->re_iovec_s,
1373 n * sizeof(rep->re_iovec_s[0]), D);
1374 if (cps != OK) {
1375 panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed",
1376 cps);
1379 for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) {
1380 s = iovp->iov_size;
1381 if (size + s > packlen) {
1382 assert(packlen > size);
1383 s = packlen-size;
1386 cps = sys_safecopyto(re_client, iovp->iov_grant, 0,
1387 (vir_bytes) rep->re_rx[index].v_ret_buf + size, s, D);
1388 if (cps != OK)
1389 panic(__FILE__,
1390 "rl_readv_s: sys_safecopyto failed", cps);
1392 size += s;
1393 if (size == packlen)
1394 break;
1396 if (size == packlen)
1397 break;
1399 if (size < packlen)
1400 assert(0);
1402 rep->re_stat.ets_packetR++;
1403 rep->re_read_s = packlen;
1404 if (index == N_RX_DESC - 1) {
1405 desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
1406 index = 0;
1407 } else {
1408 desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK);
1409 index++;
1411 rep->re_rx_head = index;
1412 assert(rep->re_rx_head < N_RX_DESC);
1413 rep->re_flags = (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1415 if (!from_int)
1416 reply(rep, OK, FALSE);
1418 return;
1420 suspend:
1421 if (from_int) {
1422 assert(rep->re_flags & REF_READING);
1424 /* No need to store any state */
1425 return;
1428 rep->re_rx_mess = *mp;
1429 assert(!(rep->re_flags & REF_READING));
1430 rep->re_flags |= REF_READING;
1432 reply(rep, OK, FALSE);
1435 /*===========================================================================*
1436 * rl_writev_s *
1437 *===========================================================================*/
1438 static void rl_writev_s(message *mp, int from_int)
1440 int i, j, n, s, port, count, size;
1441 int tx_head, re_client;
1442 re_t *rep;
1443 iovec_s_t *iovp;
1444 re_desc *desc;
1445 char *ret;
1446 int cps;
1447 int iov_offset = 0;
1449 port = mp->DL_PORT;
1450 count = mp->DL_COUNT;
1451 if (port < 0 || port >= RE_PORT_NR)
1452 panic("rtl8169", "illegal port", port);
1453 rep = &re_table[port];
1454 assert(mp);
1455 assert(port >= 0 && port < RE_PORT_NR);
1456 assert(rep->setup);
1457 re_client = mp->DL_PROC;
1458 rep->re_client = re_client;
1460 assert(rep->re_mode == REM_ENABLED);
1461 assert(rep->re_flags & REF_ENABLED);
1463 if (from_int) {
1464 assert(rep->re_flags & REF_SEND_AVAIL);
1465 rep->re_flags &= ~REF_SEND_AVAIL;
1466 rep->re_send_int = FALSE;
1467 rep->re_tx_alive = TRUE;
1470 tx_head = rep->re_tx_head;
1472 desc = rep->re_tx_desc;
1473 desc += tx_head;
1475 if(!desc || !rep->re_tx_desc) {
1476 printf("desc 0x%lx, re_tx_desc 0x%lx, tx_head %d, setup %d\n",
1477 desc, rep->re_tx_desc, tx_head, rep->setup);
1480 assert(rep->re_tx_desc);
1481 assert(rep->re_tx_head >= 0 && rep->re_tx_head < N_TX_DESC);
1483 assert(desc);
1486 if (rep->re_tx[tx_head].ret_busy) {
1487 assert(!(rep->re_flags & REF_SEND_AVAIL));
1488 rep->re_flags |= REF_SEND_AVAIL;
1489 if (rep->re_tx[tx_head].ret_busy)
1490 goto suspend;
1493 * Race condition, the interrupt handler may clear re_busy
1494 * before we got a chance to set REF_SEND_AVAIL. Checking
1495 * ret_busy twice should be sufficient.
1497 #if VERBOSE
1498 printf("rl_writev_s: race detected\n");
1499 #endif
1500 rep->re_flags &= ~REF_SEND_AVAIL;
1501 rep->re_send_int = FALSE;
1504 assert(!(rep->re_flags & REF_SEND_AVAIL));
1505 assert(!(rep->re_flags & REF_PACK_SENT));
1507 size = 0;
1508 ret = rep->re_tx[tx_head].v_ret_buf;
1509 for (i = 0; i < count; i += IOVEC_NR,
1510 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1512 n = IOVEC_NR;
1513 if (i + n > count)
1514 n = count - i;
1515 cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
1516 (vir_bytes) rep->re_iovec_s,
1517 n * sizeof(rep->re_iovec_s[0]), D);
1518 if (cps != OK) {
1519 panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed",
1520 cps);
1523 for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) {
1524 s = iovp->iov_size;
1525 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1526 panic("rtl8169", "invalid packet size", NO_NUM);
1528 cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0,
1529 (vir_bytes) ret, s, D);
1530 if (cps != OK) {
1531 panic(__FILE__,
1532 "rl_writev_s: sys_safecopyfrom failed",
1533 cps);
1535 size += s;
1536 ret += s;
1539 assert(desc);
1540 if (size < ETH_MIN_PACK_SIZE)
1541 panic("rtl8169", "invalid packet size", size);
1543 rep->re_tx[tx_head].ret_busy = TRUE;
1545 if (tx_head == N_TX_DESC - 1) {
1546 desc->status = DESC_EOR | DESC_OWN | DESC_FS | DESC_LS | size;
1547 tx_head = 0;
1548 } else {
1549 desc->status = DESC_OWN | DESC_FS | DESC_LS | size;
1550 tx_head++;
1553 assert(tx_head < N_TX_DESC);
1554 rep->re_tx_head = tx_head;
1556 rl_outl(rep->re_base_port, RL_TPPOLL, RL_TPPOLL_NPQ);
1557 rep->re_flags |= REF_PACK_SENT;
1560 * If the interrupt handler called, don't send a reply. The reply
1561 * will be sent after all interrupts are handled.
1563 if (from_int)
1564 return;
1565 reply(rep, OK, FALSE);
1566 return;
1568 suspend:
1569 if (from_int)
1570 panic("rtl8169", "should not be sending\n", NO_NUM);
1572 rep->re_tx_mess = *mp;
1573 reply(rep, OK, FALSE);
1576 /*===========================================================================*
1577 * rl_check_ints *
1578 *===========================================================================*/
1579 static void rl_check_ints(rep)
1580 re_t *rep;
1582 int re_flags;
1584 re_flags = rep->re_flags;
1586 if ((re_flags & REF_READING) &&
1587 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1589 assert(rep->re_rx_mess.m_type == DL_READV_S);
1590 rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
1593 if (rep->re_need_reset)
1594 rl_do_reset(rep);
1596 if (rep->re_send_int) {
1597 assert(rep->re_tx_mess.m_type == DL_WRITEV_S);
1598 rl_writev_s(&rep->re_tx_mess, TRUE /* from int */);
1601 if (rep->re_report_link)
1602 rl_report_link(rep);
1604 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1605 reply(rep, OK, TRUE);
1608 /*===========================================================================*
1609 * rl_report_link *
1610 *===========================================================================*/
1611 static void rl_report_link(rep)
1612 re_t *rep;
1614 port_t port;
1615 u8_t mii_status;
1617 rep->re_report_link = FALSE;
1618 port = rep->re_base_port;
1620 mii_status = rl_inb(port, RL_PHYSTAT);
1622 if (mii_status & RL_STAT_LINK) {
1623 rep->re_link_up = 1;
1624 printf("%s: link up at ", rep->re_name);
1625 } else {
1626 rep->re_link_up = 0;
1627 printf("%s: link down\n", rep->re_name);
1628 return;
1631 if (mii_status & RL_STAT_1000)
1632 printf("1000 Mbps");
1633 else if (mii_status & RL_STAT_100)
1634 printf("100 Mbps");
1635 else if (mii_status & RL_STAT_10)
1636 printf("10 Mbps");
1638 if (mii_status & RL_STAT_FULLDUP)
1639 printf(", full duplex");
1640 else
1641 printf(", half duplex");
1642 printf("\n");
1644 dump_phy(rep);
1647 /*===========================================================================*
1648 * rl_do_reset *
1649 *===========================================================================*/
1650 static void rl_do_reset(rep)
1651 re_t *rep;
1653 rep->re_need_reset = FALSE;
1654 rl_reset_hw(rep);
1655 rl_rec_mode(rep);
1657 rep->re_tx_head = 0;
1658 if (rep->re_flags & REF_SEND_AVAIL) {
1659 rep->re_tx[rep->re_tx_head].ret_busy = FALSE;
1660 rep->re_send_int = TRUE;
1664 /*===========================================================================*
1665 * rl_getstat *
1666 *===========================================================================*/
1667 static void rl_getstat(mp)
1668 message *mp;
1670 int r, port;
1671 eth_stat_t stats;
1672 re_t *rep;
1674 port = mp->DL_PORT;
1675 if (port < 0 || port >= RE_PORT_NR)
1676 panic("rtl8169", "illegal port", port);
1677 rep = &re_table[port];
1678 rep->re_client = mp->DL_PROC;
1680 assert(rep->re_mode == REM_ENABLED);
1681 assert(rep->re_flags & REF_ENABLED);
1683 stats = rep->re_stat;
1685 r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC,
1686 (vir_bytes) mp->DL_ADDR, sizeof(stats));
1687 if (r != OK)
1688 panic(__FILE__, "rl_getstat: sys_datacopy failed", r);
1690 mp->m_type = DL_STAT_REPLY;
1691 mp->DL_PORT = port;
1692 mp->DL_STAT = OK;
1693 r = send(mp->m_source, mp);
1694 if (r != OK)
1695 panic("RTL8169", "rl_getstat: send failed: %d\n", r);
1698 /*===========================================================================*
1699 * rl_getstat_s *
1700 *===========================================================================*/
1701 static void rl_getstat_s(mp)
1702 message *mp;
1704 int r, port;
1705 eth_stat_t stats;
1706 re_t *rep;
1708 port = mp->DL_PORT;
1709 if (port < 0 || port >= RE_PORT_NR)
1710 panic("rtl8169", "illegal port", port);
1711 rep = &re_table[port];
1712 rep->re_client = mp->DL_PROC;
1714 assert(rep->re_mode == REM_ENABLED);
1715 assert(rep->re_flags & REF_ENABLED);
1717 stats = rep->re_stat;
1719 r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
1720 (vir_bytes) &stats, sizeof(stats), D);
1721 if (r != OK)
1722 panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r);
1724 mp->m_type = DL_STAT_REPLY;
1725 mp->DL_PORT = port;
1726 mp->DL_STAT = OK;
1727 r = send(mp->m_source, mp);
1728 if (r != OK)
1729 panic("RTL8169", "rl_getstat_s: send failed: %d\n", r);
1733 /*===========================================================================*
1734 * rl_getname *
1735 *===========================================================================*/
1736 static void rl_getname(mp)
1737 message *mp;
1739 int r;
1741 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
1742 mp->DL_NAME[sizeof(mp->DL_NAME)-1] = '\0';
1743 mp->m_type = DL_NAME_REPLY;
1744 r = send(mp->m_source, mp);
1745 if (r != OK)
1746 panic("RTL8169", "rl_getname: send failed: %d\n", r);
1750 /*===========================================================================*
1751 * reply *
1752 *===========================================================================*/
1753 static void reply(rep, err, may_block)
1754 re_t *rep;
1755 int err;
1756 int may_block;
1758 message reply;
1759 int status;
1760 int r;
1761 clock_t now;
1763 status = 0;
1764 if (rep->re_flags & REF_PACK_SENT)
1765 status |= DL_PACK_SEND;
1766 if (rep->re_flags & REF_PACK_RECV)
1767 status |= DL_PACK_RECV;
1769 reply.m_type = DL_TASK_REPLY;
1770 reply.DL_PORT = rep - re_table;
1771 reply.DL_PROC = rep->re_client;
1772 reply.DL_STAT = status | ((u32_t) err << 16);
1773 reply.DL_COUNT = rep->re_read_s;
1774 if (OK != (r = getuptime(&now)))
1775 panic("rtl8169", "getuptime() failed:", r);
1776 reply.DL_CLCK = now;
1778 r = send(rep->re_client, &reply);
1780 if (r == ELOCKED && may_block) {
1781 printW(); printf("send locked\n");
1782 return;
1785 if (r < 0) {
1786 printf("RTL8169 tried sending to %d, type %d\n",
1787 rep->re_client, reply.m_type);
1788 panic("rtl8169", "send failed:", r);
1791 rep->re_read_s = 0;
1792 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
1795 /*===========================================================================*
1796 * mess_reply *
1797 *===========================================================================*/
1798 static void mess_reply(req, reply_mess)
1799 message *req;
1800 message *reply_mess;
1802 if (send(req->m_source, reply_mess) != OK)
1803 panic("rtl8169", "unable to mess_reply", NO_NUM);
1806 static void dump_phy(re_t *rep)
1808 #if VERBOSE
1809 port_t port;
1810 u32_t t;
1812 port = rep->re_base_port;
1814 t = rl_inb(port, RL_CONFIG0);
1815 printf("CONFIG0\t\t:");
1816 t = t & RL_CFG0_ROM;
1817 if (t == RL_CFG0_ROM128K)
1818 printf(" 128K Boot ROM");
1819 else if (t == RL_CFG0_ROM64K)
1820 printf(" 64K Boot ROM");
1821 else if (t == RL_CFG0_ROM32K)
1822 printf(" 32K Boot ROM");
1823 else if (t == RL_CFG0_ROM16K)
1824 printf(" 16K Boot ROM");
1825 else if (t == RL_CFG0_ROM8K)
1826 printf(" 8K Boot ROM");
1827 else if (t == RL_CFG0_ROMNO)
1828 printf(" No Boot ROM");
1829 printf("\n");
1831 t = rl_inb(port, RL_CONFIG1);
1832 printf("CONFIG1\t\t:");
1833 if (t & RL_CFG1_LEDS1)
1834 printf(" LED1");
1835 if (t & RL_CFG1_LEDS0)
1836 printf(" LED0");
1837 if (t & RL_CFG1_DVRLOAD)
1838 printf(" Driver");
1839 if (t & RL_CFG1_LWACT)
1840 printf(" LWAKE");
1841 if (t & RL_CFG1_IOMAP)
1842 printf(" IOMAP");
1843 if (t & RL_CFG1_MEMMAP)
1844 printf(" MEMMAP");
1845 if (t & RL_CFG1_VPD)
1846 printf(" VPD");
1847 if (t & RL_CFG1_PME)
1848 printf(" PME");
1849 printf("\n");
1851 t = rl_inb(port, RL_CONFIG2);
1852 printf("CONFIG2\t\t:");
1853 if (t & RL_CFG2_AUX)
1854 printf(" AUX");
1855 if (t & RL_CFG2_PCIBW)
1856 printf(" PCI-64-Bit");
1857 else
1858 printf(" PCI-32-Bit");
1859 t = t & RL_CFG2_PCICLK;
1860 if (t == RL_CFG2_66MHZ)
1861 printf(" 66 MHz");
1862 else if (t == RL_CFG2_33MHZ)
1863 printf(" 33 MHz");
1864 printf("\n");
1866 t = mdio_read(port, MII_CTRL);
1867 printf("MII_CTRL\t:");
1868 if (t & MII_CTRL_RST)
1869 printf(" Reset");
1870 if (t & MII_CTRL_LB)
1871 printf(" Loopback");
1872 if (t & MII_CTRL_ANE)
1873 printf(" ANE");
1874 if (t & MII_CTRL_PD)
1875 printf(" Power-down");
1876 if (t & MII_CTRL_ISO)
1877 printf(" Isolate");
1878 if (t & MII_CTRL_RAN)
1879 printf(" RAN");
1880 if (t & MII_CTRL_DM)
1881 printf(" Full-duplex");
1882 if (t & MII_CTRL_CT)
1883 printf(" COL-signal");
1884 t = t & (MII_CTRL_SP_LSB | MII_CTRL_SP_MSB);
1885 if (t == MII_CTRL_SP_10)
1886 printf(" 10 Mb/s");
1887 else if (t == MII_CTRL_SP_100)
1888 printf(" 100 Mb/s");
1889 else if (t == MII_CTRL_SP_1000)
1890 printf(" 1000 Mb/s");
1891 printf("\n");
1893 t = mdio_read(port, MII_STATUS);
1894 printf("MII_STATUS\t:");
1895 if (t & MII_STATUS_100T4)
1896 printf(" 100Base-T4");
1897 if (t & MII_STATUS_100XFD)
1898 printf(" 100BaseX-FD");
1899 if (t & MII_STATUS_100XHD)
1900 printf(" 100BaseX-HD");
1901 if (t & MII_STATUS_10FD)
1902 printf(" 10Mbps-FD");
1903 if (t & MII_STATUS_10HD)
1904 printf(" 10Mbps-HD");
1905 if (t & MII_STATUS_100T2FD)
1906 printf(" 100Base-T2-FD");
1907 if (t & MII_STATUS_100T2HD)
1908 printf(" 100Base-T2-HD");
1909 if (t & MII_STATUS_EXT_STAT)
1910 printf(" Ext-stat");
1911 if (t & MII_STATUS_RES)
1912 printf(" res-0x%lx", t & MII_STATUS_RES);
1913 if (t & MII_STATUS_MFPS)
1914 printf(" MFPS");
1915 if (t & MII_STATUS_ANC)
1916 printf(" ANC");
1917 if (t & MII_STATUS_RF)
1918 printf(" remote-fault");
1919 if (t & MII_STATUS_ANA)
1920 printf(" ANA");
1921 if (t & MII_STATUS_LS)
1922 printf(" Link");
1923 if (t & MII_STATUS_JD)
1924 printf(" Jabber");
1925 if (t & MII_STATUS_EC)
1926 printf(" Extended-capability");
1927 printf("\n");
1929 t = mdio_read(port, MII_ANA);
1930 printf("MII_ANA\t\t: 0x%04lx\n", t);
1932 t = mdio_read(port, MII_ANLPA);
1933 printf("MII_ANLPA\t: 0x%04lx\n", t);
1935 t = mdio_read(port, MII_ANE);
1936 printf("MII_ANE\t\t:");
1937 if (t & MII_ANE_RES)
1938 printf(" res-0x%lx", t & MII_ANE_RES);
1939 if (t & MII_ANE_PDF)
1940 printf(" Par-Detect-Fault");
1941 if (t & MII_ANE_LPNPA)
1942 printf(" LP-Next-Page-Able");
1943 if (t & MII_ANE_NPA)
1944 printf(" Loc-Next-Page-Able");
1945 if (t & MII_ANE_PR)
1946 printf(" Page-Received");
1947 if (t & MII_ANE_LPANA)
1948 printf(" LP-Auto-Neg-Able");
1949 printf("\n");
1951 t = mdio_read(port, MII_1000_CTRL);
1952 printf("MII_1000_CTRL\t:");
1953 if (t & MII_1000C_FULL)
1954 printf(" 1000BaseT-FD");
1955 if (t & MII_1000C_HALF)
1956 printf(" 1000BaseT-HD");
1957 printf("\n");
1959 t = mdio_read(port, MII_1000_STATUS);
1960 if (t) {
1961 printf("MII_1000_STATUS\t:");
1962 if (t & MII_1000S_LRXOK)
1963 printf(" Local-Receiver");
1964 if (t & MII_1000S_RRXOK)
1965 printf(" Remote-Receiver");
1966 if (t & MII_1000S_HALF)
1967 printf(" 1000BaseT-HD");
1968 if (t & MII_1000S_FULL)
1969 printf(" 1000BaseT-FD");
1970 printf("\n");
1972 t = mdio_read(port, MII_EXT_STATUS);
1973 printf("MII_EXT_STATUS\t:");
1974 if (t & MII_ESTAT_1000XFD)
1975 printf(" 1000BaseX-FD");
1976 if (t & MII_ESTAT_1000XHD)
1977 printf(" 1000BaseX-HD");
1978 if (t & MII_ESTAT_1000TFD)
1979 printf(" 1000BaseT-FD");
1980 if (t & MII_ESTAT_1000THD)
1981 printf(" 1000BaseT-HD");
1982 printf("\n");
1984 #endif
1987 static void do_hard_int(void)
1989 int i, s;
1991 for (i = 0; i < RE_PORT_NR; i++) {
1993 /* Run interrupt handler at driver level. */
1994 rl_handler(&re_table[i]);
1996 /* Reenable interrupts for this hook. */
1997 if ((s = sys_irqenable(&re_table[i].re_hook_id)) != OK)
1998 printf("RTL8169: error, couldn't enable interrupts: %d\n", s);
2002 /*===========================================================================*
2003 * rl_handler *
2004 *===========================================================================*/
2005 static int rl_handler(rep)
2006 re_t *rep;
2008 int i, port, tx_head, tx_tail, link_up;
2009 u16_t isr;
2010 re_desc *desc;
2011 int_event_check = FALSE; /* disable check by default */
2013 port = rep->re_base_port;
2015 /* Ack interrupt */
2016 isr = rl_inw(port, RL_ISR);
2017 if(!isr)
2018 return;
2019 rl_outw(port, RL_ISR, isr);
2020 rep->interrupts++;
2022 if (isr & RL_IMR_FOVW) {
2023 isr &= ~RL_IMR_FOVW;
2024 /* Should do anything? */
2026 rep->re_stat.ets_fifoOver++;
2028 if (isr & RL_IMR_PUN) {
2029 isr &= ~RL_IMR_PUN;
2032 * Either the link status changed or there was a TX fifo
2033 * underrun.
2035 link_up = !(!(rl_inb(port, RL_PHYSTAT) & RL_STAT_LINK));
2036 if (link_up != rep->re_link_up) {
2037 rep->re_report_link = TRUE;
2038 rep->re_got_int = TRUE;
2039 int_event_check = TRUE;
2043 if (isr & (RL_ISR_RDU | RL_ISR_RER | RL_ISR_ROK)) {
2044 if (isr & RL_ISR_RER)
2045 rep->re_stat.ets_recvErr++;
2046 isr &= ~(RL_ISR_RDU | RL_ISR_RER | RL_ISR_ROK);
2048 if (!rep->re_got_int && (rep->re_flags & REF_READING)) {
2049 rep->re_got_int = TRUE;
2050 int_event_check = TRUE;
2054 if ((isr & (RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK)) || 1) {
2055 if (isr & RL_ISR_TER)
2056 rep->re_stat.ets_sendErr++;
2057 isr &= ~(RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK);
2059 /* Transmit completed */
2060 tx_head = rep->re_tx_head;
2061 tx_tail = tx_head+1;
2062 if (tx_tail >= N_TX_DESC)
2063 tx_tail = 0;
2064 for (i = 0; i < 2 * N_TX_DESC; i++) {
2065 if (!rep->re_tx[tx_tail].ret_busy) {
2066 /* Strange, this buffer is not in-use.
2067 * Increment tx_tail until tx_head is
2068 * reached (or until we find a buffer that
2069 * is in-use.
2071 if (tx_tail == tx_head)
2072 break;
2073 if (++tx_tail >= N_TX_DESC)
2074 tx_tail = 0;
2075 assert(tx_tail < N_TX_DESC);
2076 continue;
2078 desc = rep->re_tx_desc;
2079 desc += tx_tail;
2080 if (desc->status & DESC_OWN) {
2081 /* Buffer is not yet ready */
2082 break;
2085 rep->re_stat.ets_packetT++;
2086 rep->re_tx[tx_tail].ret_busy = FALSE;
2088 if (++tx_tail >= N_TX_DESC)
2089 tx_tail = 0;
2090 assert(tx_tail < N_TX_DESC);
2092 if (rep->re_flags & REF_SEND_AVAIL) {
2093 rep->re_send_int = TRUE;
2094 if (!rep->re_got_int) {
2095 rep->re_got_int = TRUE;
2096 int_event_check = TRUE;
2100 assert(i < 2 * N_TX_DESC);
2103 /* Ignore Reserved Interrupt */
2104 if (isr & RL_ISR_RES)
2105 isr &= ~RL_ISR_RES;
2107 if (isr)
2108 printf("rl_handler: unhandled interrupt isr = 0x%04x\n", isr);
2110 return 1;
2113 /*===========================================================================*
2114 * rl_watchdog_f *
2115 *===========================================================================*/
2116 static void rl_watchdog_f(tp)
2117 timer_t *tp;
2119 int i;
2120 re_t *rep;
2121 /* Use a synchronous alarm instead of a watchdog timer. */
2122 sys_setalarm(system_hz, 0);
2124 for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) {
2125 if (rep->re_mode != REM_ENABLED)
2126 continue;
2128 /* Should collect statistics */
2129 if (!(++rep->dtcc_counter % RE_DTCC_VALUE))
2130 rtl8169_update_stat(rep);
2132 if (!(rep->re_flags & REF_SEND_AVAIL)) {
2133 /* Assume that an idle system is alive */
2134 rep->re_tx_alive = TRUE;
2135 continue;
2137 if (rep->re_tx_alive) {
2138 rep->re_tx_alive = FALSE;
2139 continue;
2141 printf("rl_watchdog_f: resetting port %d mode 0x%x flags 0x%x\n",
2142 i, rep->re_mode, rep->re_flags);
2143 printf("tx_head :%8d busy %d\t",
2144 rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy);
2145 rep->re_need_reset = TRUE;
2146 rep->re_got_int = TRUE;
2148 check_int_events();