Remove building with NOCRYPTO option
[minix3.git] / minix / drivers / net / rtl8139 / rtl8139.c
blob1aedde49980c286b96b7e36c6e487f73e50b64ff
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 unsigned my_inb(u16_t port) {
22 u32_t value;
23 int s;
24 if ((s=sys_inb(port, &value)) !=OK)
25 printf("RTL8139: warning, sys_inb failed: %d\n", s);
26 return value;
28 static unsigned my_inw(u16_t port) {
29 u32_t value;
30 int s;
31 if ((s=sys_inw(port, &value)) !=OK)
32 printf("RTL8139: warning, sys_inw failed: %d\n", s);
33 return value;
35 static unsigned my_inl(u16_t port) {
36 u32_t value;
37 int s;
38 if ((s=sys_inl(port, &value)) !=OK)
39 printf("RTL8139: warning, sys_inl failed: %d\n", s);
40 return value;
42 #define rl_inb(port, offset) (my_inb((port) + (offset)))
43 #define rl_inw(port, offset) (my_inw((port) + (offset)))
44 #define rl_inl(port, offset) (my_inl((port) + (offset)))
46 static void my_outb(u16_t port, u8_t value) {
47 int s;
48 if ((s=sys_outb(port, value)) !=OK)
49 printf("RTL8139: warning, sys_outb failed: %d\n", s);
51 static void my_outw(u16_t port, u16_t value) {
52 int s;
53 if ((s=sys_outw(port, value)) !=OK)
54 printf("RTL8139: warning, sys_outw failed: %d\n", s);
56 static void my_outl(u16_t port, u32_t value) {
57 int s;
58 if ((s=sys_outl(port, value)) !=OK)
59 printf("RTL8139: warning, sys_outl failed: %d\n", s);
61 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
62 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
63 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
65 static int rl_init(unsigned int instance, netdriver_addr_t *addr,
66 uint32_t *caps, unsigned int *ticks);
67 static int rl_probe(re_t *rep, unsigned int skip);
68 static void rl_init_buf(re_t *rep);
69 static void rl_init_hw(re_t *rep, netdriver_addr_t *addr,
70 unsigned int instance);
71 static void rl_reset_hw(re_t *rep);
72 static void rl_set_hwaddr(const netdriver_addr_t *addr);
73 static void rl_confaddr(re_t *rep, netdriver_addr_t *addr,
74 unsigned int instance);
75 static void rl_stop(void);
76 static void rl_rec_mode(re_t *rep);
77 static void rl_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
78 unsigned int mcast_count);
79 static ssize_t rl_recv(struct netdriver_data *data, size_t max);
80 static int rl_send(struct netdriver_data *data, size_t size);
81 static unsigned int rl_get_link(uint32_t *media);
82 static void rl_intr(unsigned int mask);
83 static void rl_check_ints(re_t *rep);
84 #if VERBOSE
85 static void rl_report_link(re_t *rep);
86 static void mii_print_techab(u16_t techab);
87 static void mii_print_stat_speed(u16_t stat, u16_t extstat);
88 #endif
89 static void rl_clear_rx(re_t *rep);
90 static void rl_do_reset(re_t *rep);
91 static void rl_other(const message *m_ptr, int ipc_status);
92 static void rl_dump(void);
93 #if 0
94 static void dump_phy(re_t *rep);
95 #endif
96 static int rl_handler(re_t *rep);
97 static void rl_tick(void);
98 static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int
99 pci_dev, int pci_func);
101 static const struct netdriver rl_table = {
102 .ndr_name = "rl",
103 .ndr_init = rl_init,
104 .ndr_stop = rl_stop,
105 .ndr_set_mode = rl_set_mode,
106 .ndr_set_hwaddr = rl_set_hwaddr,
107 .ndr_recv = rl_recv,
108 .ndr_send = rl_send,
109 .ndr_get_link = rl_get_link,
110 .ndr_intr = rl_intr,
111 .ndr_tick = rl_tick,
112 .ndr_other = rl_other,
115 /*===========================================================================*
116 * main *
117 *===========================================================================*/
118 int main(int argc, char *argv[])
121 env_setargs(argc, argv);
123 netdriver_task(&rl_table);
125 return 0;
128 /*===========================================================================*
129 * rl_intr *
130 *===========================================================================*/
131 static void rl_intr(unsigned int __unused mask)
133 re_t *rep;
134 int s;
136 rep = &re_state;
138 /* Run interrupt handler at driver level. */
139 rl_handler(rep);
141 /* Reenable interrupts for this hook. */
142 if ((s = sys_irqenable(&rep->re_hook_id)) != OK)
143 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
145 /* Perform tasks based on the flagged conditions. */
146 rl_check_ints(rep);
149 /*===========================================================================*
150 * rl_other *
151 *===========================================================================*/
152 static void rl_other(const message *m_ptr, int ipc_status)
154 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
155 rl_dump();
158 /*===========================================================================*
159 * rl_stop *
160 *===========================================================================*/
161 static void rl_stop(void)
163 re_t *rep;
165 rep = &re_state;
167 rl_outb(rep->re_base_port, RL_CR, 0);
170 /*===========================================================================*
171 * rl_dump *
172 *===========================================================================*/
173 static void rl_dump(void)
175 re_t *rep;
177 rep= &re_state;
179 printf("\n");
180 printf("Realtek RTL 8139 device %s:\n", netdriver_name());
182 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
183 rl_inw(rep->re_base_port, RL_TSAD),
184 rl_inl(rep->re_base_port, RL_TSD0+0*4),
185 rl_inl(rep->re_base_port, RL_TSD0+1*4),
186 rl_inl(rep->re_base_port, RL_TSD0+2*4),
187 rl_inl(rep->re_base_port, RL_TSD0+3*4));
188 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
189 rep->re_tx_head, rep->re_tx_tail,
190 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
191 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
194 /*===========================================================================*
195 * rl_set_mode *
196 *===========================================================================*/
197 static void rl_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
198 unsigned int mcast_count)
200 re_t *rep;
202 rep= &re_state;
204 rep->re_mode = mode;
206 rl_rec_mode(rep);
209 /*===========================================================================*
210 * rl_init *
211 *===========================================================================*/
212 static int rl_init(unsigned int instance, netdriver_addr_t *addr,
213 uint32_t *caps, unsigned int *ticks)
215 /* Initialize the rtl8139 driver. */
216 re_t *rep;
217 #if RTL8139_FKEY
218 int r, fkeys, sfkeys;
219 #endif
221 /* Initialize driver state. */
222 rep= &re_state;
223 memset(rep, 0, sizeof(*rep));
225 rep->re_link_up= -1; /* Unknown */
226 rep->re_ertxth= RL_TSD_ERTXTH_8;
228 /* Try to find a matching device. */
229 if (!rl_probe(rep, instance))
230 return ENXIO;
232 /* Claim buffer memory. */
233 rl_init_buf(rep);
235 /* Initialize the device we found. */
236 rl_init_hw(rep, addr, instance);
238 #if VERBOSE
239 /* Report initial link status. */
240 rl_report_link(rep);
241 #endif
243 #if RTL8139_FKEY
244 /* Observe some function key for debug dumps. */
245 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
246 if ((r = fkey_map(&fkeys, &sfkeys)) != OK)
247 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
248 #endif
250 *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST | NDEV_CAP_HWADDR;
251 *ticks = sys_hz();
252 return OK;
255 /*===========================================================================*
256 * rl_probe *
257 *===========================================================================*/
258 static int rl_probe(re_t *rep, unsigned int skip)
260 int r, devind;
261 u16_t cr, vid, did;
262 u32_t bar;
263 u8_t ilr;
264 #if VERBOSE
265 const char *dname;
266 #endif
268 pci_init();
270 r= pci_first_dev(&devind, &vid, &did);
271 if (r == 0)
272 return 0;
274 while (skip--)
276 r= pci_next_dev(&devind, &vid, &did);
277 if (!r)
278 return 0;
281 #if VERBOSE /* stay silent at startup, can always get status later */
282 dname= pci_dev_name(vid, did);
283 if (!dname)
284 dname= "unknown device";
285 printf("%s: ", netdriver_name());
286 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
287 #endif
288 pci_reserve(devind);
290 /* Enable bus mastering if necessary. */
291 cr = pci_attr_r16(devind, PCI_CR);
292 /* printf("cr = 0x%x\n", cr); */
293 if (!(cr & PCI_CR_MAST_EN))
294 pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
296 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
297 if (bar < 0x400) {
298 panic("base address is not properly configured");
300 rep->re_base_port= bar;
302 ilr= pci_attr_r8(devind, PCI_ILR);
303 rep->re_irq= ilr;
304 #if VERBOSE
305 printf("%s: using I/O address 0x%lx, IRQ %d\n",
306 netdriver_name(), (unsigned long)bar, ilr);
307 #endif
309 return TRUE;
312 /*===========================================================================*
313 * rl_init_buf *
314 *===========================================================================*/
315 static void rl_init_buf(re_t *rep)
317 size_t rx_bufsize, tx_bufsize, tot_bufsize;
318 phys_bytes buf;
319 char *mallocbuf;
320 int i, off;
322 /* Allocate receive and transmit buffers */
323 tx_bufsize= NDEV_ETH_PACKET_MAX_TAGGED;
324 if (tx_bufsize % 4)
325 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
326 rx_bufsize= RX_BUFSIZE;
327 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
329 if (tot_bufsize % 4096)
330 tot_bufsize += 4096-(tot_bufsize % 4096);
332 #define BUF_ALIGNMENT (64*1024)
334 if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf)))
335 panic("Couldn't allocate kernel buffer");
337 /* click-align mallocced buffer. this is what we used to get
338 * from kmalloc() too.
340 if((off = buf % BUF_ALIGNMENT)) {
341 mallocbuf += BUF_ALIGNMENT - off;
342 buf += BUF_ALIGNMENT - off;
345 tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0);
347 for (i= 0; i<N_TX_BUF; i++)
349 rep->re_tx[i].ret_buf= buf;
350 rep->re_tx[i].v_ret_buf= mallocbuf;
351 buf += tx_bufsize;
352 mallocbuf += tx_bufsize;
354 rep->re_rx_buf= buf;
355 rep->v_re_rx_buf= mallocbuf;
358 /*===========================================================================*
359 * rl_init_hw *
360 *===========================================================================*/
361 static void rl_init_hw(re_t *rep, netdriver_addr_t *addr,
362 unsigned int instance)
364 #if VERBOSE
365 int i;
366 #endif
367 int s;
369 /* Set the interrupt handler. The policy is to only send HARD_INT
370 * notifications. Don't reenable interrupts automatically. The id
371 * that is passed back is the interrupt line number.
373 rep->re_hook_id = rep->re_irq;
374 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
375 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
377 rl_reset_hw(rep);
379 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
380 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
382 #if VERBOSE /* stay silent during startup, can always get status later */
383 if (rep->re_model) {
384 printf("%s: model %s\n", netdriver_name(), rep->re_model);
385 } else
387 printf("%s: unknown model 0x%08x\n",
388 netdriver_name(),
389 rl_inl(rep->re_base_port, RL_TCR) &
390 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
392 #endif
394 rl_confaddr(rep, addr, instance);
396 #if VERBOSE
397 printf("%s: Ethernet address ", netdriver_name());
398 for (i= 0; i < 6; i++)
399 printf("%x%c", addr->na_addr[i], i < 5 ? ':' : '\n');
400 #endif
403 /*===========================================================================*
404 * rl_reset_hw *
405 *===========================================================================*/
406 static void rl_reset_hw(re_t *rep)
408 port_t port;
409 u32_t t;
410 phys_bytes bus_buf;
411 int i;
413 port= rep->re_base_port;
415 #if 0
416 /* Reset the PHY */
417 rl_outb(port, RL_BMCR, MII_CTRL_RST);
418 SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
419 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
420 panic("reset PHY failed to complete");
421 #endif
423 /* Reset the device */
424 #if VERBOSE
425 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
426 port, rl_inb(port, RL_CR));
427 #endif
428 rl_outb(port, RL_CR, RL_CR_RST);
429 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
430 #if VERBOSE
431 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
432 port, rl_inb(port, RL_CR));
433 #endif
434 if (rl_inb(port, RL_CR) & RL_CR_RST)
435 printf("rtl8139: reset failed to complete");
437 t= rl_inl(port, RL_TCR);
438 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
440 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
441 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
442 case RL_TCR_HWVER_RTL8139AG:
443 rep->re_model= "RTL8139A-G / RTL8139C";
444 break;
445 case RL_TCR_HWVER_RTL8139B:
446 rep->re_model= "RTL8139B / RTL8130";
447 break;
448 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
449 case RL_TCR_HWVER_RTL8100B:
450 rep->re_model= "RTL8100B/RTL8139D";
451 break;
452 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
453 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
454 default:
455 rep->re_model= NULL;
456 break;
459 #if 0
460 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
461 #endif
463 /* Intialize Rx */
465 /* Should init multicast mask */
466 #if 0
467 08-0f R/W MAR[0-7] multicast
468 #endif
469 bus_buf= vm_1phys2bus(rep->re_rx_buf);
470 rl_outl(port, RL_RBSTART, bus_buf);
472 /* Initialize Tx */
473 for (i= 0; i<N_TX_BUF; i++)
475 rep->re_tx[i].ret_busy= FALSE;
476 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
477 rl_outl(port, RL_TSAD0+i*4, bus_buf);
478 t= rl_inl(port, RL_TSD0+i*4);
479 assert(t & RL_TSD_OWN);
482 rep->re_tx_busy = 0;
484 #if 0
485 dump_phy(rep);
486 #endif
488 t= rl_inw(port, RL_IMR);
489 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
490 RL_IMR_LENCHG));
492 t= rl_inw(port, RL_IMR);
493 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
494 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
496 t= rl_inw(port, RL_IMR);
497 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
499 t= rl_inb(port, RL_CR);
500 rl_outb(port, RL_CR, t | RL_CR_RE);
502 t= rl_inb(port, RL_CR);
503 rl_outb(port, RL_CR, t | RL_CR_TE);
505 rl_outl(port, RL_RCR, RX_BUFBITS);
507 t= rl_inl(port, RL_TCR);
508 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
511 /*===========================================================================*
512 * rl_set_hwaddr *
513 *===========================================================================*/
514 static void rl_set_hwaddr(const netdriver_addr_t *addr)
516 re_t *rep;
517 port_t port;
518 u32_t w;
519 int i;
521 rep = &re_state;
523 port= rep->re_base_port;
524 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
525 w= 0;
526 for (i= 0; i<4; i++)
527 w |= (addr->na_addr[i] << (i*8));
528 rl_outl(port, RL_IDR, w);
529 w= 0;
530 for (i= 4; i<6; i++)
531 w |= (addr->na_addr[i] << ((i-4)*8));
532 rl_outl(port, RL_IDR+4, w);
533 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
536 /*===========================================================================*
537 * rl_confaddr *
538 *===========================================================================*/
539 static void rl_confaddr(re_t *rep, netdriver_addr_t *addr,
540 unsigned int instance)
542 static char eakey[]= RL_ENVVAR "#_EA";
543 static char eafmt[]= "x:x:x:x:x:x";
544 port_t port;
545 int i;
546 long v;
548 /* User defined ethernet address? */
549 eakey[sizeof(RL_ENVVAR)-1]= '0' + instance;
551 for (i= 0; i < 6; i++)
553 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
554 break;
555 addr->na_addr[i]= v;
558 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
560 /* Should update ethernet address in hardware */
561 if (i == 6)
562 rl_set_hwaddr(addr);
564 /* Get ethernet address */
565 port= rep->re_base_port;
567 for (i= 0; i<6; i++)
568 addr->na_addr[i]= rl_inb(port, RL_IDR+i);
571 /*===========================================================================*
572 * rl_rec_mode *
573 *===========================================================================*/
574 static void rl_rec_mode(re_t *rep)
576 port_t port;
577 u32_t rcr;
579 port= rep->re_base_port;
580 rcr= rl_inl(port, RL_RCR);
581 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
582 if (rep->re_mode & NDEV_MODE_PROMISC)
583 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
584 if (rep->re_mode & NDEV_MODE_BCAST)
585 rcr |= RL_RCR_AB;
586 if (rep->re_mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
587 rcr |= RL_RCR_AM;
588 rcr |= RL_RCR_APM;
590 rl_outl(port, RL_RCR, rcr);
593 /*===========================================================================*
594 * rl_recv *
595 *===========================================================================*/
596 static ssize_t rl_recv(struct netdriver_data *data, size_t max)
598 int o, s;
599 port_t port;
600 unsigned amount, totlen, packlen;
601 u16_t d_start, d_end;
602 u32_t l, rxstat;
603 re_t *rep;
605 rep= &re_state;
607 if (rep->re_clear_rx)
608 return SUSPEND; /* Buffer overflow */
610 port= rep->re_base_port;
612 if (rl_inb(port, RL_CR) & RL_CR_BUFE)
614 /* Receive buffer is empty, suspend */
615 return SUSPEND;
618 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
619 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
621 #if RX_BUFSIZE <= USHRT_MAX
622 if (d_start >= RX_BUFSIZE)
624 printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
625 rl_inw(port, RL_CAPR));
626 d_start %= RX_BUFSIZE;
628 #endif
630 if (d_end > d_start)
631 amount= d_end-d_start;
632 else
633 amount= d_end+RX_BUFSIZE - d_start;
635 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
637 /* Should convert from little endian to host byte order */
639 if (!(rxstat & RL_RXS_ROK))
641 printf("rxstat = 0x%08x\n", rxstat);
642 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
643 d_start, d_end, rxstat);
644 panic("received packet not OK");
646 totlen= (rxstat >> RL_RXS_LEN_S);
647 if (totlen < 8 || totlen > 2*NDEV_ETH_PACKET_MAX)
649 /* Someting went wrong */
650 printf(
651 "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
652 totlen, rxstat, d_start);
653 printf(
654 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
655 d_start, d_end, totlen, rxstat);
656 panic(NULL);
659 #if 0
660 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
661 d_start, d_end, totlen, rxstat);
662 #endif
664 if (totlen+4 > amount)
666 printf("rl_recv: packet not yet ready\n");
667 return SUSPEND;
670 /* Should subtract the CRC */
671 packlen = MIN(totlen - NDEV_ETH_PACKET_CRC, max);
673 /* Copy out the data. The packet may wrap in the receive buffer. */
674 o = (d_start+4) % RX_BUFSIZE;
675 s = MIN(RX_BUFSIZE - o, (int)packlen);
677 netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s);
678 if (s < (int)packlen)
679 netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s);
681 /* Avoid overflow in 16-bit computations */
682 l= d_start;
683 l += totlen+4;
684 l= (l+3) & ~3; /* align */
685 if (l >= RX_BUFSIZE)
687 l -= RX_BUFSIZE;
688 assert(l < RX_BUFSIZE);
690 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
692 return packlen;
695 /*===========================================================================*
696 * rl_send *
697 *===========================================================================*/
698 static int rl_send(struct netdriver_data *data, size_t size)
700 int tx_head;
701 re_t *rep;
703 rep= &re_state;
705 tx_head= rep->re_tx_head;
706 if (rep->re_tx[tx_head].ret_busy)
707 return SUSPEND;
709 netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size);
711 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size);
712 rep->re_tx[tx_head].ret_busy= TRUE;
713 rep->re_tx_busy++;
715 if (++tx_head == N_TX_BUF)
716 tx_head= 0;
717 assert(tx_head < RL_N_TX);
718 rep->re_tx_head= tx_head;
720 return OK;
723 /*===========================================================================*
724 * rl_check_ints *
725 *===========================================================================*/
726 static void rl_check_ints(re_t *rep)
728 #if 0
729 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
730 31 R CRS Carrier Sense Lost
731 30 R TABT Transmit Abort
732 29 R OWC Out of Window Collision
733 27-24 R NCC[3-0] Number of Collision Count
734 23-22 reserved
735 21-16 R/W ERTXH[5-0] Early Tx Threshold
736 15 R TOK Transmit OK
737 14 R TUN Transmit FIFO Underrun
738 13 R/W OWN OWN
739 12-0 R/W SIZE Descriptor Size
740 3e-3f R/W ISR Interrupt Status Register
741 6 R/W FOVW Fx FIFO Overflow Interrupt
742 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
743 3 R/W TER Transmit Error Interrupt
744 2 R/W TOK Transmit OK Interrupt
745 3e-3f R/W ISR Interrupt Status Register
746 15 R/W SERR System Error Interrupt
747 14 R/W TimeOut Time Out Interrupt
748 13 R/W LenChg Cable Length Change Interrupt
749 3e-3f R/W ISR Interrupt Status Register
750 4 R/W RXOVW Rx Buffer Overflow Interrupt
751 1 R/W RER Receive Error Interrupt
752 0 R/W ROK Receive OK Interrupt
753 4c-4f R/W MPC Missed Packet Counter
754 60-61 R TSAD Transmit Status of All Descriptors
755 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
756 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
757 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
758 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
759 6c-6d R DIS Disconnect Counter
760 15-0 R DCNT Disconnect Counter
761 6e-6f R FCSC False Carrier Sense Counter
762 15-0 R FCSCNT False Carrier event counter
763 72-73 R REC RX_ER Counter
764 15-0 R RXERCNT Received packet counter
765 #endif
767 if (!rep->re_got_int)
768 return;
769 rep->re_got_int = FALSE;
771 netdriver_recv();
773 if (rep->re_clear_rx)
774 rl_clear_rx(rep);
776 if (rep->re_need_reset)
777 rl_do_reset(rep);
779 if (rep->re_send_int) {
780 rep->re_send_int = FALSE;
782 netdriver_send();
785 if (rep->re_report_link) {
786 rep->re_report_link = FALSE;
788 netdriver_link();
789 #if VERBOSE
790 rl_report_link(rep);
791 #endif
795 /*===========================================================================*
796 * rl_get_link *
797 *===========================================================================*/
798 static unsigned int rl_get_link(uint32_t *media)
800 port_t port;
801 u8_t msr;
802 u16_t mii_ctrl;
803 re_t *rep;
805 rep = &re_state;
807 port= rep->re_base_port;
808 msr= rl_inb(port, RL_MSR);
810 if (msr & RL_MSR_LINKB)
811 return NDEV_LINK_DOWN;
813 if (msr & RL_MSR_SPEED_10)
814 *media = IFM_ETHER | IFM_10_T;
815 else
816 *media = IFM_ETHER | IFM_100_TX;
818 mii_ctrl= rl_inw(port, RL_BMCR);
819 if (mii_ctrl & MII_CTRL_DM)
820 *media |= IFM_FDX;
821 else
822 *media |= IFM_HDX;
824 return NDEV_LINK_UP;
827 #if VERBOSE
828 /*===========================================================================*
829 * rl_report_link *
830 *===========================================================================*/
831 static void rl_report_link(re_t *rep)
833 port_t port;
834 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
835 u8_t msr;
836 int f, link_up;
838 port= rep->re_base_port;
839 msr= rl_inb(port, RL_MSR);
840 link_up= !(msr & RL_MSR_LINKB);
841 rep->re_link_up= link_up;
842 if (!link_up)
844 printf("%s: link down\n", netdriver_name());
845 return;
848 mii_ctrl= rl_inw(port, RL_BMCR);
849 mii_status= rl_inw(port, RL_BMSR);
850 mii_ana= rl_inw(port, RL_ANAR);
851 mii_anlpa= rl_inw(port, RL_ANLPAR);
852 mii_ane= rl_inw(port, RL_ANER);
853 mii_extstat= 0;
855 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
857 printf("%s: PHY: ", netdriver_name());
858 f= 1;
859 if (mii_ctrl & MII_CTRL_LB)
861 printf("loopback mode");
862 f= 0;
864 if (mii_ctrl & MII_CTRL_PD)
866 if (!f) printf(", ");
867 f= 0;
868 printf("powered down");
870 if (mii_ctrl & MII_CTRL_ISO)
872 if (!f) printf(", ");
873 f= 0;
874 printf("isolated");
876 printf("\n");
877 return;
879 if (!(mii_ctrl & MII_CTRL_ANE))
881 printf("%s: manual config: ", netdriver_name());
882 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
884 case MII_CTRL_SP_10: printf("10 Mbps"); break;
885 case MII_CTRL_SP_100: printf("100 Mbps"); break;
886 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
887 case MII_CTRL_SP_RES: printf("reserved speed"); break;
889 if (mii_ctrl & MII_CTRL_DM)
890 printf(", full duplex");
891 else
892 printf(", half duplex");
893 printf("\n");
894 return;
897 #if VERBOSE
898 printf("%s: ", netdriver_name());
899 mii_print_stat_speed(mii_status, mii_extstat);
900 printf("\n");
902 if (!(mii_status & MII_STATUS_ANC))
903 printf("%s: auto-negotiation not complete\n",
904 netdriver_name());
905 if (mii_status & MII_STATUS_RF)
906 printf("%s: remote fault detected\n", netdriver_name());
907 if (!(mii_status & MII_STATUS_ANA))
909 printf("%s: local PHY has no auto-negotiation ability\n",
910 netdriver_name());
912 if (!(mii_status & MII_STATUS_LS))
913 printf("%s: link down\n", netdriver_name());
914 if (mii_status & MII_STATUS_JD)
915 printf("%s: jabber condition detected\n",
916 netdriver_name());
917 if (!(mii_status & MII_STATUS_EC))
919 printf("%s: no extended register set\n", netdriver_name());
920 goto resspeed;
922 if (!(mii_status & MII_STATUS_ANC))
923 goto resspeed;
925 printf("%s: local cap.: ", netdriver_name());
926 mii_print_techab(mii_ana);
927 printf("\n");
929 if (mii_ane & MII_ANE_PDF)
930 printf("%s: parallel detection fault\n", netdriver_name());
931 if (!(mii_ane & MII_ANE_LPANA))
933 printf("%s: link-partner does not support auto-negotiation\n",
934 netdriver_name());
935 goto resspeed;
938 printf("%s: remote cap.: ", netdriver_name());
939 mii_print_techab(mii_anlpa);
940 printf("\n");
941 resspeed:
942 #endif
944 printf("%s: ", netdriver_name());
945 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
946 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
950 static void mii_print_techab(u16_t techab)
952 int fs, ft;
953 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
955 printf("strange selector 0x%x, value 0x%x",
956 techab & MII_ANA_SEL_M,
957 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
958 return;
960 fs= 1;
961 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
963 printf("100 Mbps: ");
964 fs= 0;
965 ft= 1;
966 if (techab & MII_ANA_100T4)
968 printf("T4");
969 ft= 0;
971 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
973 if (!ft)
974 printf(", ");
975 ft= 0;
976 printf("TX-");
977 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
979 case MII_ANA_100TXFD: printf("FD"); break;
980 case MII_ANA_100TXHD: printf("HD"); break;
981 default: printf("FD/HD"); break;
985 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
987 if (!fs)
988 printf(", ");
989 printf("10 Mbps: ");
990 fs= 0;
991 printf("T-");
992 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
994 case MII_ANA_10TFD: printf("FD"); break;
995 case MII_ANA_10THD: printf("HD"); break;
996 default: printf("FD/HD"); break;
999 if (techab & MII_ANA_PAUSE_SYM)
1001 if (!fs)
1002 printf(", ");
1003 fs= 0;
1004 printf("pause(SYM)");
1006 if (techab & MII_ANA_PAUSE_ASYM)
1008 if (!fs)
1009 printf(", ");
1010 fs= 0;
1011 printf("pause(ASYM)");
1013 if (techab & MII_ANA_TAF_RES)
1015 if (!fs)
1016 printf(", ");
1017 fs= 0;
1018 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
1022 static void mii_print_stat_speed(u16_t stat, u16_t extstat)
1024 int fs, ft;
1025 fs= 1;
1026 if (stat & MII_STATUS_EXT_STAT)
1028 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1029 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1031 printf("1000 Mbps: ");
1032 fs= 0;
1033 ft= 1;
1034 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1036 ft= 0;
1037 printf("X-");
1038 switch(extstat &
1039 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1041 case MII_ESTAT_1000XFD: printf("FD"); break;
1042 case MII_ESTAT_1000XHD: printf("HD"); break;
1043 default: printf("FD/HD"); break;
1046 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1048 if (!ft)
1049 printf(", ");
1050 ft= 0;
1051 printf("T-");
1052 switch(extstat &
1053 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1055 case MII_ESTAT_1000TFD: printf("FD"); break;
1056 case MII_ESTAT_1000THD: printf("HD"); break;
1057 default: printf("FD/HD"); break;
1062 if (stat & (MII_STATUS_100T4 |
1063 MII_STATUS_100XFD | MII_STATUS_100XHD |
1064 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1066 if (!fs)
1067 printf(", ");
1068 fs= 0;
1069 printf("100 Mbps: ");
1070 ft= 1;
1071 if (stat & MII_STATUS_100T4)
1073 printf("T4");
1074 ft= 0;
1076 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1078 if (!ft)
1079 printf(", ");
1080 ft= 0;
1081 printf("TX-");
1082 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1084 case MII_STATUS_100XFD: printf("FD"); break;
1085 case MII_STATUS_100XHD: printf("HD"); break;
1086 default: printf("FD/HD"); break;
1089 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1091 if (!ft)
1092 printf(", ");
1093 ft= 0;
1094 printf("T2-");
1095 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1097 case MII_STATUS_100T2FD: printf("FD"); break;
1098 case MII_STATUS_100T2HD: printf("HD"); break;
1099 default: printf("FD/HD"); break;
1103 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1105 if (!fs)
1106 printf(", ");
1107 printf("10 Mbps: ");
1108 fs= 0;
1109 printf("T-");
1110 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1112 case MII_STATUS_10FD: printf("FD"); break;
1113 case MII_STATUS_10HD: printf("HD"); break;
1114 default: printf("FD/HD"); break;
1118 #endif /* VERBOSE */
1120 /*===========================================================================*
1121 * rl_clear_rx *
1122 *===========================================================================*/
1123 static void rl_clear_rx(re_t *rep)
1125 port_t port;
1126 u8_t cr;
1128 rep->re_clear_rx= FALSE;
1129 port= rep->re_base_port;
1131 /* Reset the receiver */
1132 cr= rl_inb(port, RL_CR);
1133 cr &= ~RL_CR_RE;
1134 rl_outb(port, RL_CR, cr);
1135 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
1136 if (rl_inb(port, RL_CR) & RL_CR_RE)
1137 panic("cannot disable receiver");
1139 #if 0
1140 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1141 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1142 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1143 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1144 #endif
1146 rl_outb(port, RL_CR, cr | RL_CR_RE);
1148 rl_outl(port, RL_RCR, RX_BUFBITS);
1150 rl_rec_mode(rep);
1152 netdriver_stat_ierror(1);
1155 /*===========================================================================*
1156 * rl_do_reset *
1157 *===========================================================================*/
1158 static void rl_do_reset(re_t *rep)
1160 rep->re_need_reset= FALSE;
1161 rl_reset_hw(rep);
1162 rl_rec_mode(rep);
1164 rep->re_tx_head= 0;
1165 if (rep->re_tx[rep->re_tx_head].ret_busy)
1166 rep->re_tx_busy--;
1167 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1168 rep->re_send_int= TRUE;
1171 #if 0
1172 /*===========================================================================*
1173 * dump_phy *
1174 *===========================================================================*/
1175 static void dump_phy(re_t *rep)
1177 port_t port;
1178 u32_t t;
1180 port= rep->re_base_port;
1182 t= rl_inb(port, RL_MSR);
1183 printf("MSR: 0x%02lx\n", t);
1184 if (t & RL_MSR_SPEED_10)
1185 printf("\t10 Mbps\n");
1186 if (t & RL_MSR_LINKB)
1187 printf("\tLink failed\n");
1189 t= rl_inb(port, RL_CONFIG1);
1190 printf("CONFIG1: 0x%02lx\n", t);
1192 t= rl_inb(port, RL_CONFIG3);
1193 printf("CONFIG3: 0x%02lx\n", t);
1195 t= rl_inb(port, RL_CONFIG4);
1196 printf("CONFIG4: 0x%02lx\n", t);
1198 t= rl_inw(port, RL_BMCR);
1199 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
1201 t= rl_inw(port, RL_BMSR);
1202 printf("BMSR:");
1203 if (t & MII_STATUS_100T4)
1204 printf(" 100Base-T4");
1205 if (t & MII_STATUS_100XFD)
1206 printf(" 100Base-X-FD");
1207 if (t & MII_STATUS_100XHD)
1208 printf(" 100Base-X-HD");
1209 if (t & MII_STATUS_10FD)
1210 printf(" 10Mbps-FD");
1211 if (t & MII_STATUS_10HD)
1212 printf(" 10Mbps-HD");
1213 if (t & MII_STATUS_100T2FD)
1214 printf(" 100Base-T2-FD");
1215 if (t & MII_STATUS_100T2HD)
1216 printf(" 100Base-T2-HD");
1217 if (t & MII_STATUS_EXT_STAT)
1218 printf(" Ext-stat");
1219 if (t & MII_STATUS_RES)
1220 printf(" res-0x%lx", t & MII_STATUS_RES);
1221 if (t & MII_STATUS_MFPS)
1222 printf(" MFPS");
1223 if (t & MII_STATUS_ANC)
1224 printf(" ANC");
1225 if (t & MII_STATUS_RF)
1226 printf(" remote-fault");
1227 if (t & MII_STATUS_ANA)
1228 printf(" ANA");
1229 if (t & MII_STATUS_LS)
1230 printf(" Link");
1231 if (t & MII_STATUS_JD)
1232 printf(" Jabber");
1233 if (t & MII_STATUS_EC)
1234 printf(" Extended-capability");
1235 printf("\n");
1237 t= rl_inw(port, RL_ANAR);
1238 printf("ANAR (MII_ANA): 0x%04lx\n", t);
1240 t= rl_inw(port, RL_ANLPAR);
1241 printf("ANLPAR: 0x%04lx\n", t);
1243 t= rl_inw(port, RL_ANER);
1244 printf("ANER (MII_ANE): ");
1245 if (t & MII_ANE_RES)
1246 printf(" res-0x%lx", t & MII_ANE_RES);
1247 if (t & MII_ANE_PDF)
1248 printf(" Par-Detect-Fault");
1249 if (t & MII_ANE_LPNPA)
1250 printf(" LP-Next-Page-Able");
1251 if (t & MII_ANE_NPA)
1252 printf(" Loc-Next-Page-Able");
1253 if (t & MII_ANE_PR)
1254 printf(" Page-Received");
1255 if (t & MII_ANE_LPANA)
1256 printf(" LP-Auto-Neg-Able");
1257 printf("\n");
1259 t= rl_inw(port, RL_NWAYTR);
1260 printf("NWAYTR: 0x%04lx\n", t);
1261 t= rl_inw(port, RL_CSCR);
1262 printf("CSCR: 0x%04lx\n", t);
1264 t= rl_inb(port, RL_CONFIG5);
1265 printf("CONFIG5: 0x%02lx\n", t);
1267 #endif
1269 /*===========================================================================*
1270 * rl_handler *
1271 *===========================================================================*/
1272 static int rl_handler(re_t *rep)
1274 int i, port, tx_head, tx_tail, link_up;
1275 u16_t isr, tsad;
1276 u32_t tsd, tcr, ertxth;
1278 port= rep->re_base_port;
1280 /* Ack interrupt */
1281 isr= rl_inw(port, RL_ISR);
1282 rl_outw(port, RL_ISR, isr);
1284 if (isr & RL_IMR_FOVW)
1286 isr &= ~RL_IMR_FOVW;
1287 /* Should do anything? */
1289 if (isr & RL_IMR_PUN)
1291 isr &= ~RL_IMR_PUN;
1293 /* Either the link status changed or there was a TX fifo
1294 * underrun.
1296 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
1297 if (link_up != rep->re_link_up)
1299 rep->re_report_link= TRUE;
1300 rep->re_got_int= TRUE;
1303 if (isr & RL_IMR_RXOVW)
1305 isr &= ~RL_IMR_RXOVW;
1307 /* Clear the receive buffer */
1308 rep->re_clear_rx= TRUE;
1309 rep->re_got_int= TRUE;
1312 if (isr & (RL_ISR_RER | RL_ISR_ROK))
1314 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
1316 rep->re_got_int= TRUE;
1318 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
1320 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
1322 tsad= rl_inw(port, RL_TSAD);
1323 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
1324 RL_TSAD_TABT2|RL_TSAD_TABT3))
1326 printf("rl_handler, TABT, tasd = 0x%04x\n",
1327 tsad);
1329 /* Find the aborted transmit request */
1330 for (i= 0; i< N_TX_BUF; i++)
1332 tsd= rl_inl(port, RL_TSD0+i*4);
1333 if (tsd & RL_TSD_TABT)
1334 break;
1336 if (i >= N_TX_BUF)
1338 printf(
1339 "rl_handler: can't find aborted TX req.\n");
1341 else
1343 printf("TSD%d = 0x%04x\n", i, tsd);
1345 /* Set head and tail to this buffer */
1346 rep->re_tx_head= rep->re_tx_tail= i;
1349 /* Aborted transmission, just kick the device
1350 * and be done with it.
1352 netdriver_stat_oerror(1);
1354 tcr= rl_inl(port, RL_TCR);
1355 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1358 /* Transmit completed */
1359 tx_head= rep->re_tx_head;
1360 tx_tail= rep->re_tx_tail;
1361 for (i= 0; i< 2*N_TX_BUF; i++)
1363 if (rep->re_tx_busy == 0)
1364 break;
1365 if (!rep->re_tx[tx_tail].ret_busy)
1367 /* Strange, this buffer is not in-use.
1368 * Increment tx_tail until tx_head is
1369 * reached (or until we find a buffer that
1370 * is in-use.
1372 if (tx_tail == tx_head)
1373 break;
1374 if (++tx_tail >= N_TX_BUF)
1375 tx_tail= 0;
1376 assert(tx_tail < RL_N_TX);
1377 rep->re_tx_tail= tx_tail;
1378 continue;
1380 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
1381 if (!(tsd & (RL_TSD_TABT | RL_TSD_TOK | RL_TSD_TUN)))
1383 /* Buffer is not yet ready */
1384 break;
1387 /* Should collect statistics */
1388 if (tsd & RL_TSD_TABT)
1390 printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1391 tx_tail, tsd);
1392 panic("TX abort"); /* CLRABT is not all that
1393 * that effective, why not?
1395 tcr= rl_inl(port, RL_TCR);
1396 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1399 /* What about collisions? */
1400 if (!(tsd & RL_TSD_TOK))
1401 netdriver_stat_oerror(1);
1402 if (tsd & RL_TSD_TUN)
1404 /* Increase ERTXTH */
1405 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
1406 ertxth &= RL_TSD_ERTXTH_M;
1407 #if VERBOSE
1408 if (ertxth > rep->re_ertxth)
1410 printf("%s: new ertxth: %d bytes\n",
1411 netdriver_name(),
1412 (ertxth >> RL_TSD_ERTXTH_S) *
1413 32);
1414 rep->re_ertxth= ertxth;
1416 #endif
1418 rep->re_tx[tx_tail].ret_busy= FALSE;
1419 rep->re_tx_busy--;
1421 #if 0
1422 printf("TSD%d: %08lx\n", tx_tail, tsd);
1423 printf(
1424 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1425 tx_head, tx_tail,
1426 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1427 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1428 #endif
1430 if (++tx_tail >= N_TX_BUF)
1431 tx_tail= 0;
1432 assert(tx_tail < RL_N_TX);
1433 rep->re_tx_tail= tx_tail;
1435 rep->re_send_int= TRUE;
1436 rep->re_got_int= TRUE;
1437 rep->re_tx_alive= TRUE;
1439 assert(i < 2*N_TX_BUF);
1441 if (isr)
1443 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1444 isr);
1447 return 1;
1450 /*===========================================================================*
1451 * rl_tick *
1452 *===========================================================================*/
1453 static void rl_tick(void)
1455 re_t *rep;
1457 rep= &re_state;
1459 assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF);
1460 if (rep->re_tx_busy == 0)
1462 /* Assume that an idle system is alive */
1463 rep->re_tx_alive= TRUE;
1464 return;
1466 if (rep->re_tx_alive)
1468 rep->re_tx_alive= FALSE;
1469 return;
1471 printf("%s: TX timeout, resetting\n", netdriver_name());
1472 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1473 rl_inw(rep->re_base_port, RL_TSAD),
1474 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1475 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1476 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1477 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1478 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1479 rep->re_tx_head, rep->re_tx_tail,
1480 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1481 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1482 rep->re_need_reset= TRUE;
1483 rep->re_got_int= TRUE;
1485 rl_check_ints(rep);
1488 /* TODO: obviously this needs a lot of work. */
1489 static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev,
1490 int pci_func)
1492 int r;
1493 endpoint_t dev_e;
1494 message m;
1496 r= ds_retrieve_label_endpt("amddev", &dev_e);
1497 if (r != OK)
1499 #if 0
1500 printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
1501 "for 'amddev': %d\n", r);
1502 #endif
1503 return;
1506 m.m_type= IOMMU_MAP;
1507 m.m2_i1= pci_bus;
1508 m.m2_i2= pci_dev;
1509 m.m2_i3= pci_func;
1510 m.m2_l1= buf;
1511 m.m2_l2= size;
1513 r= ipc_sendrec(dev_e, &m);
1514 if (r != OK)
1516 printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1517 dev_e, r);
1518 return;
1520 if (m.m_type != OK)
1522 printf("rtl8139`tell_dev: dma map request failed: %d\n",
1523 m.m_type);
1524 return;
1529 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $