Improve the process for GNU tools
[minix3.git] / minix / drivers / net / rtl8139 / rtl8139.c
blob2a259e42aae584805c118921a0214748f13e8424
1 /*
2 * rtl8139.c
4 * This file contains a ethernet device driver for Realtek rtl8139 based
5 * ethernet cards.
7 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
8 * Changes:
9 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
10 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
14 #define VERBOSE 0 /* Verbose debugging output */
15 #define RTL8139_FKEY 0 /* Use function key to dump RTL8139 status */
17 #include "rtl8139.h"
19 static re_t re_state;
21 static int re_instance;
23 static unsigned my_inb(u16_t port) {
24 u32_t value;
25 int s;
26 if ((s=sys_inb(port, &value)) !=OK)
27 printf("RTL8139: warning, sys_inb failed: %d\n", s);
28 return value;
30 static unsigned my_inw(u16_t port) {
31 u32_t value;
32 int s;
33 if ((s=sys_inw(port, &value)) !=OK)
34 printf("RTL8139: warning, sys_inw failed: %d\n", s);
35 return value;
37 static unsigned my_inl(u16_t port) {
38 u32_t value;
39 int s;
40 if ((s=sys_inl(port, &value)) !=OK)
41 printf("RTL8139: warning, sys_inl failed: %d\n", s);
42 return value;
44 #define rl_inb(port, offset) (my_inb((port) + (offset)))
45 #define rl_inw(port, offset) (my_inw((port) + (offset)))
46 #define rl_inl(port, offset) (my_inl((port) + (offset)))
48 static void my_outb(u16_t port, u8_t value) {
49 int s;
50 if ((s=sys_outb(port, value)) !=OK)
51 printf("RTL8139: warning, sys_outb failed: %d\n", s);
53 static void my_outw(u16_t port, u16_t value) {
54 int s;
55 if ((s=sys_outw(port, value)) !=OK)
56 printf("RTL8139: warning, sys_outw failed: %d\n", s);
58 static void my_outl(u16_t port, u32_t value) {
59 int s;
60 if ((s=sys_outl(port, value)) !=OK)
61 printf("RTL8139: warning, sys_outl failed: %d\n", s);
63 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
64 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
65 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
67 static int rl_init(unsigned int instance, ether_addr_t *addr);
68 static int rl_probe(re_t *rep, unsigned int skip);
69 static void rl_init_buf(re_t *rep);
70 static void rl_init_hw(re_t *rep, ether_addr_t *addr);
71 static void rl_reset_hw(re_t *rep);
72 static void rl_confaddr(re_t *rep, ether_addr_t *addr);
73 static void rl_stop(void);
74 static void rl_rec_mode(re_t *rep);
75 static void rl_mode(unsigned int mode);
76 static ssize_t rl_recv(struct netdriver_data *data, size_t max);
77 static int rl_send(struct netdriver_data *data, size_t size);
78 static void rl_intr(unsigned int mask);
79 static void rl_check_ints(re_t *rep);
80 static void rl_report_link(re_t *rep);
81 #if VERBOSE
82 static void mii_print_techab(u16_t techab);
83 static void mii_print_stat_speed(u16_t stat, u16_t extstat);
84 #endif
85 static void rl_clear_rx(re_t *rep);
86 static void rl_do_reset(re_t *rep);
87 static void rl_stat(eth_stat_t *stat);
88 static void rl_other(const message *m_ptr, int ipc_status);
89 static void rl_dump(void);
90 #if 0
91 static void dump_phy(re_t *rep);
92 #endif
93 static int rl_handler(re_t *rep);
94 static void rl_alarm(clock_t stamp);
95 static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int
96 pci_dev, int pci_func);
98 static const struct netdriver rl_table = {
99 .ndr_init = rl_init,
100 .ndr_stop = rl_stop,
101 .ndr_mode = rl_mode,
102 .ndr_recv = rl_recv,
103 .ndr_send = rl_send,
104 .ndr_stat = rl_stat,
105 .ndr_intr = rl_intr,
106 .ndr_alarm = rl_alarm,
107 .ndr_other = rl_other,
110 /*===========================================================================*
111 * main *
112 *===========================================================================*/
113 int main(int argc, char *argv[])
116 env_setargs(argc, argv);
118 netdriver_task(&rl_table);
120 return 0;
123 /*===========================================================================*
124 * rl_intr *
125 *===========================================================================*/
126 static void rl_intr(unsigned int __unused mask)
128 re_t *rep;
129 int s;
131 rep = &re_state;
133 /* Run interrupt handler at driver level. */
134 rl_handler(rep);
136 /* Reenable interrupts for this hook. */
137 if ((s = sys_irqenable(&rep->re_hook_id)) != OK)
138 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
140 /* Perform tasks based on the flagged conditions. */
141 rl_check_ints(rep);
144 /*===========================================================================*
145 * rl_other *
146 *===========================================================================*/
147 static void rl_other(const message *m_ptr, int ipc_status)
149 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
150 rl_dump();
153 /*===========================================================================*
154 * rl_stop *
155 *===========================================================================*/
156 static void rl_stop(void)
158 re_t *rep;
160 rep = &re_state;
162 rl_outb(rep->re_base_port, RL_CR, 0);
165 /*===========================================================================*
166 * rl_dump *
167 *===========================================================================*/
168 static void rl_dump(void)
170 re_t *rep;
172 rep= &re_state;
174 printf("\n");
175 printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance);
177 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
178 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
179 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
181 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
182 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
183 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
185 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
186 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
187 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
189 printf("collision :%8ld\t", rep->re_stat.ets_collision);
190 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
191 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
193 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
194 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
195 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
197 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
199 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
200 rl_inw(rep->re_base_port, RL_TSAD),
201 rl_inl(rep->re_base_port, RL_TSD0+0*4),
202 rl_inl(rep->re_base_port, RL_TSD0+1*4),
203 rl_inl(rep->re_base_port, RL_TSD0+2*4),
204 rl_inl(rep->re_base_port, RL_TSD0+3*4));
205 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
206 rep->re_tx_head, rep->re_tx_tail,
207 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
208 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
211 /*===========================================================================*
212 * rl_mode *
213 *===========================================================================*/
214 static void rl_mode(unsigned int mode)
216 re_t *rep;
218 rep= &re_state;
220 rep->re_mode = mode;
222 rl_rec_mode(rep);
225 /*===========================================================================*
226 * rl_init *
227 *===========================================================================*/
228 static int rl_init(unsigned int instance, ether_addr_t *addr)
230 /* Initialize the rtl8139 driver. */
231 re_t *rep;
232 #if RTL8139_FKEY
233 int r, fkeys, sfkeys;
234 #endif
236 /* Initialize driver state. */
237 rep= &re_state;
238 memset(rep, 0, sizeof(*rep));
240 rep->re_link_up= -1; /* Unknown */
241 rep->re_ertxth= RL_TSD_ERTXTH_8;
242 strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name));
243 rep->re_name[8] += instance;
245 re_instance = instance;
247 /* Try to find a matching device. */
248 if (!rl_probe(rep, instance))
249 return ENXIO;
251 /* Claim buffer memory. */
252 rl_init_buf(rep);
254 /* Initialize the device we found. */
255 rl_init_hw(rep, addr);
257 #if VERBOSE
258 /* Report initial link status. */
259 rl_report_link(rep);
260 #endif
262 /* Use a synchronous alarm instead of a watchdog timer. */
263 sys_setalarm(sys_hz(), 0);
265 #if RTL8139_FKEY
266 /* Observe some function key for debug dumps. */
267 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
268 if ((r = fkey_map(&fkeys, &sfkeys)) != OK)
269 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
270 #endif
272 return OK;
275 /*===========================================================================*
276 * rl_probe *
277 *===========================================================================*/
278 static int rl_probe(re_t *rep, unsigned int skip)
280 int r, devind;
281 u16_t cr, vid, did;
282 u32_t bar;
283 u8_t ilr;
284 #if VERBOSE
285 char *dname;
286 #endif
288 pci_init();
290 r= pci_first_dev(&devind, &vid, &did);
291 if (r == 0)
292 return 0;
294 while (skip--)
296 r= pci_next_dev(&devind, &vid, &did);
297 if (!r)
298 return 0;
301 #if VERBOSE /* stay silent at startup, can always get status later */
302 dname= pci_dev_name(vid, did);
303 if (!dname)
304 dname= "unknown device";
305 printf("%s: ", rep->re_name);
306 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
307 #endif
308 pci_reserve(devind);
310 /* Enable bus mastering if necessary. */
311 cr = pci_attr_r16(devind, PCI_CR);
312 /* printf("cr = 0x%x\n", cr); */
313 if (!(cr & PCI_CR_MAST_EN))
314 pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
316 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
317 if (bar < 0x400) {
318 panic("base address is not properly configured");
320 rep->re_base_port= bar;
322 ilr= pci_attr_r8(devind, PCI_ILR);
323 rep->re_irq= ilr;
324 #if VERBOSE
325 printf("%s: using I/O address 0x%lx, IRQ %d\n",
326 rep->re_name, (unsigned long)bar, ilr);
327 #endif
329 return TRUE;
332 /*===========================================================================*
333 * rl_init_buf *
334 *===========================================================================*/
335 static void rl_init_buf(re_t *rep)
337 size_t rx_bufsize, tx_bufsize, tot_bufsize;
338 phys_bytes buf;
339 char *mallocbuf;
340 int i, off;
342 /* Allocate receive and transmit buffers */
343 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
344 if (tx_bufsize % 4)
345 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
346 rx_bufsize= RX_BUFSIZE;
347 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
349 if (tot_bufsize % 4096)
350 tot_bufsize += 4096-(tot_bufsize % 4096);
352 #define BUF_ALIGNMENT (64*1024)
354 if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf)))
355 panic("Couldn't allocate kernel buffer");
357 /* click-align mallocced buffer. this is what we used to get
358 * from kmalloc() too.
360 if((off = buf % BUF_ALIGNMENT)) {
361 mallocbuf += BUF_ALIGNMENT - off;
362 buf += BUF_ALIGNMENT - off;
365 tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0);
367 for (i= 0; i<N_TX_BUF; i++)
369 rep->re_tx[i].ret_buf= buf;
370 rep->re_tx[i].v_ret_buf= mallocbuf;
371 buf += tx_bufsize;
372 mallocbuf += tx_bufsize;
374 rep->re_rx_buf= buf;
375 rep->v_re_rx_buf= mallocbuf;
378 /*===========================================================================*
379 * rl_init_hw *
380 *===========================================================================*/
381 static void rl_init_hw(re_t *rep, ether_addr_t *addr)
383 #if VERBOSE
384 int i;
385 #endif
386 int s;
388 /* Set the interrupt handler. The policy is to only send HARD_INT
389 * notifications. Don't reenable interrupts automatically. The id
390 * that is passed back is the interrupt line number.
392 rep->re_hook_id = rep->re_irq;
393 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
394 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
396 rl_reset_hw(rep);
398 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
399 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
401 #if VERBOSE /* stay silent during startup, can always get status later */
402 if (rep->re_model) {
403 printf("%s: model %s\n", rep->re_name, rep->re_model);
404 } else
406 printf("%s: unknown model 0x%08x\n",
407 rep->re_name,
408 rl_inl(rep->re_base_port, RL_TCR) &
409 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
411 #endif
413 rl_confaddr(rep, addr);
415 #if VERBOSE
416 printf("%s: Ethernet address ", rep->re_name);
417 for (i= 0; i < 6; i++)
418 printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n');
419 #endif
422 /*===========================================================================*
423 * rl_reset_hw *
424 *===========================================================================*/
425 static void rl_reset_hw(re_t *rep)
427 port_t port;
428 u32_t t;
429 phys_bytes bus_buf;
430 int i;
432 port= rep->re_base_port;
434 #if 0
435 /* Reset the PHY */
436 rl_outb(port, RL_BMCR, MII_CTRL_RST);
437 SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
438 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
439 panic("reset PHY failed to complete");
440 #endif
442 /* Reset the device */
443 #if VERBOSE
444 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
445 port, rl_inb(port, RL_CR));
446 #endif
447 rl_outb(port, RL_CR, RL_CR_RST);
448 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
449 #if VERBOSE
450 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
451 port, rl_inb(port, RL_CR));
452 #endif
453 if (rl_inb(port, RL_CR) & RL_CR_RST)
454 printf("rtl8139: reset failed to complete");
456 t= rl_inl(port, RL_TCR);
457 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
459 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
460 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
461 case RL_TCR_HWVER_RTL8139AG:
462 rep->re_model= "RTL8139A-G / RTL8139C";
463 break;
464 case RL_TCR_HWVER_RTL8139B:
465 rep->re_model= "RTL8139B / RTL8130";
466 break;
467 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
468 case RL_TCR_HWVER_RTL8100B:
469 rep->re_model= "RTL8100B/RTL8139D";
470 break;
471 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
472 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
473 default:
474 rep->re_model= NULL;
475 break;
478 #if 0
479 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
480 #endif
482 /* Intialize Rx */
484 /* Should init multicast mask */
485 #if 0
486 08-0f R/W MAR[0-7] multicast
487 #endif
488 bus_buf= vm_1phys2bus(rep->re_rx_buf);
489 rl_outl(port, RL_RBSTART, bus_buf);
491 /* Initialize Tx */
492 for (i= 0; i<N_TX_BUF; i++)
494 rep->re_tx[i].ret_busy= FALSE;
495 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
496 rl_outl(port, RL_TSAD0+i*4, bus_buf);
497 t= rl_inl(port, RL_TSD0+i*4);
498 assert(t & RL_TSD_OWN);
501 rep->re_tx_busy = 0;
503 #if 0
504 dump_phy(rep);
505 #endif
507 t= rl_inw(port, RL_IMR);
508 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
509 RL_IMR_LENCHG));
511 t= rl_inw(port, RL_IMR);
512 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
513 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
515 t= rl_inw(port, RL_IMR);
516 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
518 t= rl_inb(port, RL_CR);
519 rl_outb(port, RL_CR, t | RL_CR_RE);
521 t= rl_inb(port, RL_CR);
522 rl_outb(port, RL_CR, t | RL_CR_TE);
524 rl_outl(port, RL_RCR, RX_BUFBITS);
526 t= rl_inl(port, RL_TCR);
527 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
530 /*===========================================================================*
531 * rl_confaddr *
532 *===========================================================================*/
533 static void rl_confaddr(re_t *rep, ether_addr_t *addr)
535 static char eakey[]= RL_ENVVAR "#_EA";
536 static char eafmt[]= "x:x:x:x:x:x";
538 int i;
539 port_t port;
540 u32_t w;
541 long v;
543 /* User defined ethernet address? */
544 eakey[sizeof(RL_ENVVAR)-1]= '0' + re_instance;
546 port= rep->re_base_port;
548 for (i= 0; i < 6; i++)
550 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
551 break;
552 addr->ea_addr[i]= v;
555 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
557 /* Should update ethernet address in hardware */
558 if (i == 6)
560 port= rep->re_base_port;
561 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
562 w= 0;
563 for (i= 0; i<4; i++)
564 w |= (addr->ea_addr[i] << (i*8));
565 rl_outl(port, RL_IDR, w);
566 w= 0;
567 for (i= 4; i<6; i++)
568 w |= (addr->ea_addr[i] << ((i-4)*8));
569 rl_outl(port, RL_IDR+4, w);
570 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
573 /* Get ethernet address */
574 for (i= 0; i<6; i++)
575 addr->ea_addr[i]= rl_inb(port, RL_IDR+i);
578 /*===========================================================================*
579 * rl_rec_mode *
580 *===========================================================================*/
581 static void rl_rec_mode(re_t *rep)
583 port_t port;
584 u32_t rcr;
586 port= rep->re_base_port;
587 rcr= rl_inl(port, RL_RCR);
588 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
589 if (rep->re_mode & NDEV_PROMISC)
590 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
591 if (rep->re_mode & NDEV_BROAD)
592 rcr |= RL_RCR_AB;
593 if (rep->re_mode & NDEV_MULTI)
594 rcr |= RL_RCR_AM;
595 rcr |= RL_RCR_APM;
597 rl_outl(port, RL_RCR, rcr);
600 /*===========================================================================*
601 * rl_recv *
602 *===========================================================================*/
603 static ssize_t rl_recv(struct netdriver_data *data, size_t max)
605 int o, s;
606 port_t port;
607 unsigned amount, totlen, packlen;
608 u16_t d_start, d_end;
609 u32_t l, rxstat;
610 re_t *rep;
612 rep= &re_state;
614 if (rep->re_clear_rx)
615 return SUSPEND; /* Buffer overflow */
617 port= rep->re_base_port;
619 if (rl_inb(port, RL_CR) & RL_CR_BUFE)
621 /* Receive buffer is empty, suspend */
622 return SUSPEND;
625 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
626 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
628 #if RX_BUFSIZE <= USHRT_MAX
629 if (d_start >= RX_BUFSIZE)
631 printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
632 rl_inw(port, RL_CAPR));
633 d_start %= RX_BUFSIZE;
635 #endif
637 if (d_end > d_start)
638 amount= d_end-d_start;
639 else
640 amount= d_end+RX_BUFSIZE - d_start;
642 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
644 /* Should convert from little endian to host byte order */
646 if (!(rxstat & RL_RXS_ROK))
648 printf("rxstat = 0x%08x\n", rxstat);
649 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
650 d_start, d_end, rxstat);
651 panic("received packet not OK");
653 totlen= (rxstat >> RL_RXS_LEN_S);
654 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
656 /* Someting went wrong */
657 printf(
658 "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
659 totlen, rxstat, d_start);
660 printf(
661 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
662 d_start, d_end, totlen, rxstat);
663 panic(NULL);
666 #if 0
667 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
668 d_start, d_end, totlen, rxstat);
669 #endif
671 if (totlen+4 > amount)
673 printf("rl_recv: packet not yet ready\n");
674 return SUSPEND;
677 /* Should subtract the CRC */
678 packlen = MIN(totlen - ETH_CRC_SIZE, max);
680 /* Copy out the data. The packet may wrap in the receive buffer. */
681 o = (d_start+4) % RX_BUFSIZE;
682 s = MIN(RX_BUFSIZE - o, packlen);
684 netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s);
685 if (s < packlen)
686 netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s);
688 rep->re_stat.ets_packetR++;
690 /* Avoid overflow in 16-bit computations */
691 l= d_start;
692 l += totlen+4;
693 l= (l+3) & ~3; /* align */
694 if (l >= RX_BUFSIZE)
696 l -= RX_BUFSIZE;
697 assert(l < RX_BUFSIZE);
699 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
701 return packlen;
704 /*===========================================================================*
705 * rl_send *
706 *===========================================================================*/
707 static int rl_send(struct netdriver_data *data, size_t size)
709 int tx_head;
710 re_t *rep;
712 rep= &re_state;
714 tx_head= rep->re_tx_head;
715 if (rep->re_tx[tx_head].ret_busy)
716 return SUSPEND;
718 netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size);
720 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size);
721 rep->re_tx[tx_head].ret_busy= TRUE;
722 rep->re_tx_busy++;
724 if (++tx_head == N_TX_BUF)
725 tx_head= 0;
726 assert(tx_head < RL_N_TX);
727 rep->re_tx_head= tx_head;
729 return OK;
732 /*===========================================================================*
733 * rl_check_ints *
734 *===========================================================================*/
735 static void rl_check_ints(re_t *rep)
737 #if 0
738 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
739 31 R CRS Carrier Sense Lost
740 30 R TABT Transmit Abort
741 29 R OWC Out of Window Collision
742 27-24 R NCC[3-0] Number of Collision Count
743 23-22 reserved
744 21-16 R/W ERTXH[5-0] Early Tx Threshold
745 15 R TOK Transmit OK
746 14 R TUN Transmit FIFO Underrun
747 13 R/W OWN OWN
748 12-0 R/W SIZE Descriptor Size
749 3e-3f R/W ISR Interrupt Status Register
750 6 R/W FOVW Fx FIFO Overflow Interrupt
751 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
752 3 R/W TER Transmit Error Interrupt
753 2 R/W TOK Transmit OK Interrupt
754 3e-3f R/W ISR Interrupt Status Register
755 15 R/W SERR System Error Interrupt
756 14 R/W TimeOut Time Out Interrupt
757 13 R/W LenChg Cable Length Change Interrupt
758 3e-3f R/W ISR Interrupt Status Register
759 4 R/W RXOVW Rx Buffer Overflow Interrupt
760 1 R/W RER Receive Error Interrupt
761 0 R/W ROK Receive OK Interrupt
762 4c-4f R/W MPC Missed Packet Counter
763 60-61 R TSAD Transmit Status of All Descriptors
764 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
765 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
766 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
767 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
768 6c-6d R DIS Disconnect Counter
769 15-0 R DCNT Disconnect Counter
770 6e-6f R FCSC False Carrier Sense Counter
771 15-0 R FCSCNT False Carrier event counter
772 72-73 R REC RX_ER Counter
773 15-0 R RXERCNT Received packet counter
774 #endif
776 if (!rep->re_got_int)
777 return;
778 rep->re_got_int = FALSE;
780 netdriver_recv();
782 if (rep->re_clear_rx)
783 rl_clear_rx(rep);
785 if (rep->re_need_reset)
786 rl_do_reset(rep);
788 if (rep->re_send_int) {
789 rep->re_send_int = FALSE;
791 netdriver_send();
794 if (rep->re_report_link) {
795 rep->re_report_link = FALSE;
797 rl_report_link(rep);
801 /*===========================================================================*
802 * rl_report_link *
803 *===========================================================================*/
804 static void rl_report_link(re_t *rep)
806 port_t port;
807 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
808 u8_t msr;
809 int f, link_up;
811 port= rep->re_base_port;
812 msr= rl_inb(port, RL_MSR);
813 link_up= !(msr & RL_MSR_LINKB);
814 rep->re_link_up= link_up;
815 if (!link_up)
817 printf("%s: link down\n", rep->re_name);
818 return;
821 mii_ctrl= rl_inw(port, RL_BMCR);
822 mii_status= rl_inw(port, RL_BMSR);
823 mii_ana= rl_inw(port, RL_ANAR);
824 mii_anlpa= rl_inw(port, RL_ANLPAR);
825 mii_ane= rl_inw(port, RL_ANER);
826 mii_extstat= 0;
828 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
830 printf("%s: PHY: ", rep->re_name);
831 f= 1;
832 if (mii_ctrl & MII_CTRL_LB)
834 printf("loopback mode");
835 f= 0;
837 if (mii_ctrl & MII_CTRL_PD)
839 if (!f) printf(", ");
840 f= 0;
841 printf("powered down");
843 if (mii_ctrl & MII_CTRL_ISO)
845 if (!f) printf(", ");
846 f= 0;
847 printf("isolated");
849 printf("\n");
850 return;
852 if (!(mii_ctrl & MII_CTRL_ANE))
854 printf("%s: manual config: ", rep->re_name);
855 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
857 case MII_CTRL_SP_10: printf("10 Mbps"); break;
858 case MII_CTRL_SP_100: printf("100 Mbps"); break;
859 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
860 case MII_CTRL_SP_RES: printf("reserved speed"); break;
862 if (mii_ctrl & MII_CTRL_DM)
863 printf(", full duplex");
864 else
865 printf(", half duplex");
866 printf("\n");
867 return;
870 #if VERBOSE
871 printf("%s: ", rep->re_name);
872 mii_print_stat_speed(mii_status, mii_extstat);
873 printf("\n");
875 if (!(mii_status & MII_STATUS_ANC))
876 printf("%s: auto-negotiation not complete\n", rep->re_name);
877 if (mii_status & MII_STATUS_RF)
878 printf("%s: remote fault detected\n", rep->re_name);
879 if (!(mii_status & MII_STATUS_ANA))
881 printf("%s: local PHY has no auto-negotiation ability\n",
882 rep->re_name);
884 if (!(mii_status & MII_STATUS_LS))
885 printf("%s: link down\n", rep->re_name);
886 if (mii_status & MII_STATUS_JD)
887 printf("%s: jabber condition detected\n", rep->re_name);
888 if (!(mii_status & MII_STATUS_EC))
890 printf("%s: no extended register set\n", rep->re_name);
891 goto resspeed;
893 if (!(mii_status & MII_STATUS_ANC))
894 goto resspeed;
896 printf("%s: local cap.: ", rep->re_name);
897 mii_print_techab(mii_ana);
898 printf("\n");
900 if (mii_ane & MII_ANE_PDF)
901 printf("%s: parallel detection fault\n", rep->re_name);
902 if (!(mii_ane & MII_ANE_LPANA))
904 printf("%s: link-partner does not support auto-negotiation\n",
905 rep->re_name);
906 goto resspeed;
909 printf("%s: remote cap.: ", rep->re_name);
910 mii_print_techab(mii_anlpa);
911 printf("\n");
912 resspeed:
913 #endif
915 printf("%s: ", rep->re_name);
916 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
917 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
921 #if VERBOSE
922 static void mii_print_techab(u16_t techab)
924 int fs, ft;
925 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
927 printf("strange selector 0x%x, value 0x%x",
928 techab & MII_ANA_SEL_M,
929 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
930 return;
932 fs= 1;
933 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
935 printf("100 Mbps: ");
936 fs= 0;
937 ft= 1;
938 if (techab & MII_ANA_100T4)
940 printf("T4");
941 ft= 0;
943 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
945 if (!ft)
946 printf(", ");
947 ft= 0;
948 printf("TX-");
949 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
951 case MII_ANA_100TXFD: printf("FD"); break;
952 case MII_ANA_100TXHD: printf("HD"); break;
953 default: printf("FD/HD"); break;
957 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
959 if (!fs)
960 printf(", ");
961 printf("10 Mbps: ");
962 fs= 0;
963 printf("T-");
964 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
966 case MII_ANA_10TFD: printf("FD"); break;
967 case MII_ANA_10THD: printf("HD"); break;
968 default: printf("FD/HD"); break;
971 if (techab & MII_ANA_PAUSE_SYM)
973 if (!fs)
974 printf(", ");
975 fs= 0;
976 printf("pause(SYM)");
978 if (techab & MII_ANA_PAUSE_ASYM)
980 if (!fs)
981 printf(", ");
982 fs= 0;
983 printf("pause(ASYM)");
985 if (techab & MII_ANA_TAF_RES)
987 if (!fs)
988 printf(", ");
989 fs= 0;
990 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
994 static void mii_print_stat_speed(u16_t stat, u16_t extstat)
996 int fs, ft;
997 fs= 1;
998 if (stat & MII_STATUS_EXT_STAT)
1000 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1001 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1003 printf("1000 Mbps: ");
1004 fs= 0;
1005 ft= 1;
1006 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1008 ft= 0;
1009 printf("X-");
1010 switch(extstat &
1011 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1013 case MII_ESTAT_1000XFD: printf("FD"); break;
1014 case MII_ESTAT_1000XHD: printf("HD"); break;
1015 default: printf("FD/HD"); break;
1018 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1020 if (!ft)
1021 printf(", ");
1022 ft= 0;
1023 printf("T-");
1024 switch(extstat &
1025 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1027 case MII_ESTAT_1000TFD: printf("FD"); break;
1028 case MII_ESTAT_1000THD: printf("HD"); break;
1029 default: printf("FD/HD"); break;
1034 if (stat & (MII_STATUS_100T4 |
1035 MII_STATUS_100XFD | MII_STATUS_100XHD |
1036 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1038 if (!fs)
1039 printf(", ");
1040 fs= 0;
1041 printf("100 Mbps: ");
1042 ft= 1;
1043 if (stat & MII_STATUS_100T4)
1045 printf("T4");
1046 ft= 0;
1048 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1050 if (!ft)
1051 printf(", ");
1052 ft= 0;
1053 printf("TX-");
1054 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1056 case MII_STATUS_100XFD: printf("FD"); break;
1057 case MII_STATUS_100XHD: printf("HD"); break;
1058 default: printf("FD/HD"); break;
1061 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1063 if (!ft)
1064 printf(", ");
1065 ft= 0;
1066 printf("T2-");
1067 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1069 case MII_STATUS_100T2FD: printf("FD"); break;
1070 case MII_STATUS_100T2HD: printf("HD"); break;
1071 default: printf("FD/HD"); break;
1075 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1077 if (!fs)
1078 printf(", ");
1079 printf("10 Mbps: ");
1080 fs= 0;
1081 printf("T-");
1082 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1084 case MII_STATUS_10FD: printf("FD"); break;
1085 case MII_STATUS_10HD: printf("HD"); break;
1086 default: printf("FD/HD"); break;
1090 #endif /* VERBOSE */
1092 /*===========================================================================*
1093 * rl_clear_rx *
1094 *===========================================================================*/
1095 static void rl_clear_rx(re_t *rep)
1097 port_t port;
1098 u8_t cr;
1100 rep->re_clear_rx= FALSE;
1101 port= rep->re_base_port;
1103 /* Reset the receiver */
1104 cr= rl_inb(port, RL_CR);
1105 cr &= ~RL_CR_RE;
1106 rl_outb(port, RL_CR, cr);
1107 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
1108 if (rl_inb(port, RL_CR) & RL_CR_RE)
1109 panic("cannot disable receiver");
1111 #if 0
1112 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1113 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1114 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1115 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1116 #endif
1118 rl_outb(port, RL_CR, cr | RL_CR_RE);
1120 rl_outl(port, RL_RCR, RX_BUFBITS);
1122 rl_rec_mode(rep);
1124 rep->re_stat.ets_missedP++;
1127 /*===========================================================================*
1128 * rl_do_reset *
1129 *===========================================================================*/
1130 static void rl_do_reset(re_t *rep)
1132 rep->re_need_reset= FALSE;
1133 rl_reset_hw(rep);
1134 rl_rec_mode(rep);
1136 rep->re_tx_head= 0;
1137 if (rep->re_tx[rep->re_tx_head].ret_busy)
1138 rep->re_tx_busy--;
1139 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1140 rep->re_send_int= TRUE;
1143 /*===========================================================================*
1144 * rl_stat *
1145 *===========================================================================*/
1146 static void rl_stat(eth_stat_t *stat)
1148 memcpy(stat, &re_state.re_stat, sizeof(*stat));
1151 #if 0
1152 /*===========================================================================*
1153 * dump_phy *
1154 *===========================================================================*/
1155 static void dump_phy(re_t *rep)
1157 port_t port;
1158 u32_t t;
1160 port= rep->re_base_port;
1162 t= rl_inb(port, RL_MSR);
1163 printf("MSR: 0x%02lx\n", t);
1164 if (t & RL_MSR_SPEED_10)
1165 printf("\t10 Mbps\n");
1166 if (t & RL_MSR_LINKB)
1167 printf("\tLink failed\n");
1169 t= rl_inb(port, RL_CONFIG1);
1170 printf("CONFIG1: 0x%02lx\n", t);
1172 t= rl_inb(port, RL_CONFIG3);
1173 printf("CONFIG3: 0x%02lx\n", t);
1175 t= rl_inb(port, RL_CONFIG4);
1176 printf("CONFIG4: 0x%02lx\n", t);
1178 t= rl_inw(port, RL_BMCR);
1179 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
1181 t= rl_inw(port, RL_BMSR);
1182 printf("BMSR:");
1183 if (t & MII_STATUS_100T4)
1184 printf(" 100Base-T4");
1185 if (t & MII_STATUS_100XFD)
1186 printf(" 100Base-X-FD");
1187 if (t & MII_STATUS_100XHD)
1188 printf(" 100Base-X-HD");
1189 if (t & MII_STATUS_10FD)
1190 printf(" 10Mbps-FD");
1191 if (t & MII_STATUS_10HD)
1192 printf(" 10Mbps-HD");
1193 if (t & MII_STATUS_100T2FD)
1194 printf(" 100Base-T2-FD");
1195 if (t & MII_STATUS_100T2HD)
1196 printf(" 100Base-T2-HD");
1197 if (t & MII_STATUS_EXT_STAT)
1198 printf(" Ext-stat");
1199 if (t & MII_STATUS_RES)
1200 printf(" res-0x%lx", t & MII_STATUS_RES);
1201 if (t & MII_STATUS_MFPS)
1202 printf(" MFPS");
1203 if (t & MII_STATUS_ANC)
1204 printf(" ANC");
1205 if (t & MII_STATUS_RF)
1206 printf(" remote-fault");
1207 if (t & MII_STATUS_ANA)
1208 printf(" ANA");
1209 if (t & MII_STATUS_LS)
1210 printf(" Link");
1211 if (t & MII_STATUS_JD)
1212 printf(" Jabber");
1213 if (t & MII_STATUS_EC)
1214 printf(" Extended-capability");
1215 printf("\n");
1217 t= rl_inw(port, RL_ANAR);
1218 printf("ANAR (MII_ANA): 0x%04lx\n", t);
1220 t= rl_inw(port, RL_ANLPAR);
1221 printf("ANLPAR: 0x%04lx\n", t);
1223 t= rl_inw(port, RL_ANER);
1224 printf("ANER (MII_ANE): ");
1225 if (t & MII_ANE_RES)
1226 printf(" res-0x%lx", t & MII_ANE_RES);
1227 if (t & MII_ANE_PDF)
1228 printf(" Par-Detect-Fault");
1229 if (t & MII_ANE_LPNPA)
1230 printf(" LP-Next-Page-Able");
1231 if (t & MII_ANE_NPA)
1232 printf(" Loc-Next-Page-Able");
1233 if (t & MII_ANE_PR)
1234 printf(" Page-Received");
1235 if (t & MII_ANE_LPANA)
1236 printf(" LP-Auto-Neg-Able");
1237 printf("\n");
1239 t= rl_inw(port, RL_NWAYTR);
1240 printf("NWAYTR: 0x%04lx\n", t);
1241 t= rl_inw(port, RL_CSCR);
1242 printf("CSCR: 0x%04lx\n", t);
1244 t= rl_inb(port, RL_CONFIG5);
1245 printf("CONFIG5: 0x%02lx\n", t);
1247 #endif
1249 /*===========================================================================*
1250 * rl_handler *
1251 *===========================================================================*/
1252 static int rl_handler(re_t *rep)
1254 int i, port, tx_head, tx_tail, link_up;
1255 u16_t isr, tsad;
1256 u32_t tsd, tcr, ertxth;
1258 port= rep->re_base_port;
1260 /* Ack interrupt */
1261 isr= rl_inw(port, RL_ISR);
1262 rl_outw(port, RL_ISR, isr);
1264 if (isr & RL_IMR_FOVW)
1266 isr &= ~RL_IMR_FOVW;
1267 /* Should do anything? */
1269 rep->re_stat.ets_fifoOver++;
1271 if (isr & RL_IMR_PUN)
1273 isr &= ~RL_IMR_PUN;
1275 /* Either the link status changed or there was a TX fifo
1276 * underrun.
1278 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
1279 if (link_up != rep->re_link_up)
1281 rep->re_report_link= TRUE;
1282 rep->re_got_int= TRUE;
1285 if (isr & RL_IMR_RXOVW)
1287 isr &= ~RL_IMR_RXOVW;
1289 /* Clear the receive buffer */
1290 rep->re_clear_rx= TRUE;
1291 rep->re_got_int= TRUE;
1294 if (isr & (RL_ISR_RER | RL_ISR_ROK))
1296 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
1298 rep->re_got_int= TRUE;
1300 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
1302 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
1304 tsad= rl_inw(port, RL_TSAD);
1305 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
1306 RL_TSAD_TABT2|RL_TSAD_TABT3))
1308 printf("rl_handler, TABT, tasd = 0x%04x\n",
1309 tsad);
1311 /* Find the aborted transmit request */
1312 for (i= 0; i< N_TX_BUF; i++)
1314 tsd= rl_inl(port, RL_TSD0+i*4);
1315 if (tsd & RL_TSD_TABT)
1316 break;
1318 if (i >= N_TX_BUF)
1320 printf(
1321 "rl_handler: can't find aborted TX req.\n");
1323 else
1325 printf("TSD%d = 0x%04x\n", i, tsd);
1327 /* Set head and tail to this buffer */
1328 rep->re_tx_head= rep->re_tx_tail= i;
1331 /* Aborted transmission, just kick the device
1332 * and be done with it.
1334 rep->re_stat.ets_transAb++;
1335 tcr= rl_inl(port, RL_TCR);
1336 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1339 /* Transmit completed */
1340 tx_head= rep->re_tx_head;
1341 tx_tail= rep->re_tx_tail;
1342 for (i= 0; i< 2*N_TX_BUF; i++)
1344 if (!rep->re_tx[tx_tail].ret_busy)
1346 /* Strange, this buffer is not in-use.
1347 * Increment tx_tail until tx_head is
1348 * reached (or until we find a buffer that
1349 * is in-use.
1351 if (tx_tail == tx_head)
1352 break;
1353 if (++tx_tail >= N_TX_BUF)
1354 tx_tail= 0;
1355 assert(tx_tail < RL_N_TX);
1356 rep->re_tx_tail= tx_tail;
1357 continue;
1359 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
1360 if (!(tsd & RL_TSD_OWN))
1362 /* Buffer is not yet ready */
1363 break;
1366 /* Should collect statistics */
1367 if (tsd & RL_TSD_CRS)
1368 rep->re_stat.ets_carrSense++;
1369 if (tsd & RL_TSD_TABT)
1371 printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1372 tx_tail, tsd);
1373 assert(0); /* CLRABT is not all that
1374 * effective, why not?
1376 rep->re_stat.ets_transAb++;
1377 tcr= rl_inl(port, RL_TCR);
1378 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1380 if (tsd & RL_TSD_OWC)
1381 rep->re_stat.ets_OWC++;
1382 if (tsd & RL_TSD_CDH)
1383 rep->re_stat.ets_CDheartbeat++;
1385 /* What about collisions? */
1386 if (tsd & RL_TSD_TOK)
1387 rep->re_stat.ets_packetT++;
1388 else
1389 rep->re_stat.ets_sendErr++;
1390 if (tsd & RL_TSD_TUN)
1392 rep->re_stat.ets_fifoUnder++;
1394 /* Increase ERTXTH */
1395 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
1396 ertxth &= RL_TSD_ERTXTH_M;
1397 #if VERBOSE
1398 if (ertxth > rep->re_ertxth)
1400 printf("%s: new ertxth: %d bytes\n",
1401 rep->re_name,
1402 (ertxth >> RL_TSD_ERTXTH_S) *
1403 32);
1404 rep->re_ertxth= ertxth;
1406 #endif
1408 rep->re_tx[tx_tail].ret_busy= FALSE;
1409 rep->re_tx_busy--;
1411 #if 0
1412 printf("TSD%d: %08lx\n", tx_tail, tsd);
1413 printf(
1414 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1415 tx_head, tx_tail,
1416 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1417 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1418 #endif
1420 if (++tx_tail >= N_TX_BUF)
1421 tx_tail= 0;
1422 assert(tx_tail < RL_N_TX);
1423 rep->re_tx_tail= tx_tail;
1425 rep->re_send_int= TRUE;
1426 rep->re_got_int= TRUE;
1427 rep->re_tx_alive= TRUE;
1429 assert(i < 2*N_TX_BUF);
1431 if (isr)
1433 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1434 isr);
1437 return 1;
1440 /*===========================================================================*
1441 * rl_alarm *
1442 *===========================================================================*/
1443 static void rl_alarm(clock_t __unused stamp)
1445 re_t *rep;
1447 /* Use a synchronous alarm instead of a watchdog timer. */
1448 sys_setalarm(sys_hz(), 0);
1450 rep= &re_state;
1452 assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF);
1453 if (rep->re_tx_busy == 0)
1455 /* Assume that an idle system is alive */
1456 rep->re_tx_alive= TRUE;
1457 return;
1459 if (rep->re_tx_alive)
1461 rep->re_tx_alive= FALSE;
1462 return;
1464 printf("rl_alarm: resetting instance %d\n", re_instance);
1465 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1466 rl_inw(rep->re_base_port, RL_TSAD),
1467 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1468 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1469 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1470 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1471 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1472 rep->re_tx_head, rep->re_tx_tail,
1473 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1474 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1475 rep->re_need_reset= TRUE;
1476 rep->re_got_int= TRUE;
1478 rl_check_ints(rep);
1481 /* TODO: obviously this needs a lot of work. */
1482 static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev,
1483 int pci_func)
1485 int r;
1486 endpoint_t dev_e;
1487 message m;
1489 r= ds_retrieve_label_endpt("amddev", &dev_e);
1490 if (r != OK)
1492 #if 0
1493 printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
1494 "for 'amddev': %d\n", r);
1495 #endif
1496 return;
1499 m.m_type= IOMMU_MAP;
1500 m.m2_i1= pci_bus;
1501 m.m2_i2= pci_dev;
1502 m.m2_i3= pci_func;
1503 m.m2_l1= buf;
1504 m.m2_l2= size;
1506 r= ipc_sendrec(dev_e, &m);
1507 if (r != OK)
1509 printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1510 dev_e, r);
1511 return;
1513 if (m.m_type != OK)
1515 printf("rtl8139`tell_dev: dma map request failed: %d\n",
1516 m.m_type);
1517 return;
1522 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $