__aeabi_ldivmod: fix sign logic
[minix.git] / drivers / rtl8139 / rtl8139.c
blob68c71661d541283f909fbb1b850f410d3ecd7d9b
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 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 void rl_init(message *mp);
68 static void rl_pci_conf(void);
69 static int rl_probe(re_t *rep, int skip);
70 static void rl_conf_hw(re_t *rep);
71 static void rl_init_buf(re_t *rep);
72 static void rl_init_hw(re_t *rep);
73 static void rl_reset_hw(re_t *rep);
74 static void rl_confaddr(re_t *rep);
75 static void rl_rec_mode(re_t *rep);
76 static void rl_readv_s(const message *mp, int from_int);
77 static void rl_writev_s(const message *mp, int from_int);
78 static void rl_check_ints(re_t *rep);
79 static void rl_report_link(re_t *rep);
80 static void mii_print_techab(u16_t techab);
81 static void mii_print_stat_speed(u16_t stat, u16_t extstat);
82 static void rl_clear_rx(re_t *rep);
83 static void rl_do_reset(re_t *rep);
84 static void rl_getstat_s(message *mp);
85 static void reply(re_t *rep);
86 static void mess_reply(message *req, message *reply);
87 static void check_int_events(void);
88 static void do_hard_int(void);
89 static void rtl8139_dump(message *m);
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_watchdog_f(timer_t *tp);
95 static void tell_dev(vir_bytes start, size_t size, int pci_bus, int
96 pci_dev, int pci_func);
98 /* The message used in the main loop is made global, so that rl_watchdog_f()
99 * can change its message type to fake an interrupt message.
101 static message m;
102 static int int_event_check; /* set to TRUE if events arrived */
104 static u32_t system_hz;
106 /* SEF functions and variables. */
107 static void sef_local_startup(void);
108 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
109 static void sef_cb_signal_handler(int signo);
110 EXTERN int sef_cb_lu_prepare(int state);
111 EXTERN int sef_cb_lu_state_isvalid(int state);
112 EXTERN void sef_cb_lu_state_dump(int state);
114 /*===========================================================================*
115 * main *
116 *===========================================================================*/
117 int main(int argc, char *argv[])
119 int r;
120 int ipc_status;
122 /* SEF local startup. */
123 env_setargs(argc, argv);
124 sef_local_startup();
126 while (TRUE)
128 if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
129 panic("netdriver_receive failed: %d", r);
131 if (is_ipc_notify(ipc_status)) {
132 switch (_ENDPOINT_P(m.m_source)) {
133 case CLOCK:
135 * Under MINIX, synchronous alarms are
136 * used instead of watchdog functions.
137 * The approach is very different: MINIX
138 * VMD timeouts are handled within the
139 * kernel (the watchdog is executed by
140 * CLOCK), and notify() the driver in
141 * some cases. MINIX timeouts result in
142 * a SYN_ALARM message to the driver and
143 * thus are handled where they should be
144 * handled. Locally, watchdog functions
145 * are used again.
147 rl_watchdog_f(NULL);
148 break;
149 case HARDWARE:
150 do_hard_int();
151 if (int_event_check)
152 check_int_events();
153 break ;
154 case TTY_PROC_NR:
155 rtl8139_dump(&m);
156 break;
157 default:
158 panic("illegal notify from: %d",
159 m.m_source);
162 /* done, get nwe message */
163 continue;
166 switch (m.m_type)
168 case DL_WRITEV_S: rl_writev_s(&m, FALSE); break;
169 case DL_READV_S: rl_readv_s(&m, FALSE); break;
170 case DL_CONF: rl_init(&m); break;
171 case DL_GETSTAT_S: rl_getstat_s(&m); break;
172 default:
173 panic("illegal message: %d", m.m_type);
178 /*===========================================================================*
179 * sef_local_startup *
180 *===========================================================================*/
181 static void sef_local_startup()
183 /* Register init callbacks. */
184 sef_setcb_init_fresh(sef_cb_init_fresh);
185 sef_setcb_init_lu(sef_cb_init_fresh);
186 sef_setcb_init_restart(sef_cb_init_fresh);
188 /* Register live update callbacks. */
189 sef_setcb_lu_prepare(sef_cb_lu_prepare);
190 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
191 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
193 /* Register signal callbacks. */
194 sef_setcb_signal_handler(sef_cb_signal_handler);
196 /* Let SEF perform startup. */
197 sef_startup();
200 /*===========================================================================*
201 * sef_cb_init_fresh *
202 *===========================================================================*/
203 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
205 /* Initialize the rtl8139 driver. */
206 long v;
207 #if RTL8139_FKEY
208 int r, fkeys, sfkeys;
209 #endif
211 system_hz = sys_hz();
213 v = 0;
214 (void) env_parse("instance", "d", 0, &v, 0, 255);
215 re_instance = (int) v;
217 #if RTL8139_FKEY
218 /* Observe some function key for debug dumps. */
219 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
220 if ((r=fkey_map(&fkeys, &sfkeys)) != OK)
221 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
222 #endif
224 /* Claim buffer memory now. */
225 rl_init_buf(&re_state);
227 /* Announce we are up! */
228 netdriver_announce();
230 return(OK);
233 /*===========================================================================*
234 * sef_cb_signal_handler *
235 *===========================================================================*/
236 static void sef_cb_signal_handler(int signo)
238 re_t *rep;
240 /* Only check for termination signal, ignore anything else. */
241 if (signo != SIGTERM) return;
243 rep = &re_state;
244 if (rep->re_mode == REM_ENABLED)
245 rl_outb(rep->re_base_port, RL_CR, 0);
247 exit(0);
250 /*===========================================================================*
251 * check_int_events *
252 *===========================================================================*/
253 static void check_int_events(void)
255 re_t *rep;
257 rep= &re_state;
259 if (rep->re_mode != REM_ENABLED)
260 return;
261 if (!rep->re_got_int)
262 return;
263 rep->re_got_int= 0;
264 assert(rep->re_flags & REF_ENABLED);
265 rl_check_ints(rep);
268 /*===========================================================================*
269 * rtl8139_dump *
270 *===========================================================================*/
271 static void rtl8139_dump(m)
272 message *m; /* pointer to request message */
274 re_t *rep;
276 rep= &re_state;
278 printf("\n");
279 if (rep->re_mode == REM_DISABLED)
280 printf("Realtek RTL 8139 instance %d is disabled\n",
281 re_instance);
283 if (rep->re_mode != REM_ENABLED)
284 return;
286 printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance);
288 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
289 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
290 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
292 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
293 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
294 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
296 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
297 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
298 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
300 printf("collision :%8ld\t", rep->re_stat.ets_collision);
301 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
302 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
304 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
305 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
306 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
308 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
310 printf("re_flags = 0x%x\n", rep->re_flags);
312 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
313 rl_inw(rep->re_base_port, RL_TSAD),
314 rl_inl(rep->re_base_port, RL_TSD0+0*4),
315 rl_inl(rep->re_base_port, RL_TSD0+1*4),
316 rl_inl(rep->re_base_port, RL_TSD0+2*4),
317 rl_inl(rep->re_base_port, RL_TSD0+3*4));
318 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
319 rep->re_tx_head, rep->re_tx_tail,
320 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
321 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
324 /*===========================================================================*
325 * rl_init *
326 *===========================================================================*/
327 static void rl_init(mp)
328 message *mp;
330 static int first_time= 1;
332 re_t *rep;
333 message reply_mess;
335 if (first_time)
337 first_time= 0;
338 rl_pci_conf(); /* Configure PCI devices. */
340 /* Use a synchronous alarm instead of a watchdog timer. */
341 sys_setalarm(system_hz, 0);
344 rep= &re_state;
345 if (rep->re_mode == REM_DISABLED)
347 /* This is the default, try to (re)locate the device. */
348 rl_conf_hw(rep);
349 if (rep->re_mode == REM_DISABLED)
351 /* Probe failed, or the device is configured off. */
352 reply_mess.m_type= DL_CONF_REPLY;
353 reply_mess.DL_STAT= ENXIO;
354 mess_reply(mp, &reply_mess);
355 return;
357 if (rep->re_mode == REM_ENABLED)
358 rl_init_hw(rep);
359 #if VERBOSE /* load silently ... can always check status later */
360 rl_report_link(rep);
361 #endif
364 assert(rep->re_mode == REM_ENABLED);
365 assert(rep->re_flags & REF_ENABLED);
367 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
369 if (mp->DL_MODE & DL_PROMISC_REQ)
370 rep->re_flags |= REF_PROMISC;
371 if (mp->DL_MODE & DL_MULTI_REQ)
372 rep->re_flags |= REF_MULTI;
373 if (mp->DL_MODE & DL_BROAD_REQ)
374 rep->re_flags |= REF_BROAD;
376 rl_rec_mode(rep);
378 reply_mess.m_type = DL_CONF_REPLY;
379 reply_mess.DL_STAT = OK;
380 *(ether_addr_t *) reply_mess.DL_HWADDR = rep->re_address;
382 mess_reply(mp, &reply_mess);
385 /*===========================================================================*
386 * rl_pci_conf *
387 *===========================================================================*/
388 static void rl_pci_conf()
390 re_t *rep;
392 rep= &re_state;
394 strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name));
395 rep->re_name[8] += re_instance;
396 rep->re_seen= FALSE;
398 pci_init();
400 if (rl_probe(rep, re_instance))
401 rep->re_seen= TRUE;
404 /*===========================================================================*
405 * rl_probe *
406 *===========================================================================*/
407 static int rl_probe(rep, skip)
408 re_t *rep;
409 int skip;
411 int r, devind;
412 u16_t vid, did;
413 u32_t bar;
414 u8_t ilr;
415 #if VERBOSE
416 char *dname;
417 #endif
419 r= pci_first_dev(&devind, &vid, &did);
420 if (r == 0)
421 return 0;
423 while (skip--)
425 r= pci_next_dev(&devind, &vid, &did);
426 if (!r)
427 return 0;
430 #if VERBOSE /* stay silent at startup, can always get status later */
431 dname= pci_dev_name(vid, did);
432 if (!dname)
433 dname= "unknown device";
434 printf("%s: ", rep->re_name);
435 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
436 #endif
437 pci_reserve(devind);
438 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
439 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
440 if (bar < 0x400) {
441 panic("base address is not properly configured");
443 rep->re_base_port= bar;
445 ilr= pci_attr_r8(devind, PCI_ILR);
446 rep->re_irq= ilr;
447 if (debug)
449 printf("%s: using I/O address 0x%lx, IRQ %d\n",
450 rep->re_name, (unsigned long)bar, ilr);
453 return TRUE;
456 /*===========================================================================*
457 * rl_conf_hw *
458 *===========================================================================*/
459 static void rl_conf_hw(rep)
460 re_t *rep;
462 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
464 rep->re_mode= REM_DISABLED; /* Superfluous */
466 if (rep->re_seen)
468 /* PCI device is present */
469 rep->re_mode= REM_ENABLED;
471 if (rep->re_mode != REM_ENABLED)
472 return;
474 rep->re_flags= REF_EMPTY;
475 rep->re_link_up= -1; /* Unknown */
476 rep->re_got_int= 0;
477 rep->re_send_int= 0;
478 rep->re_report_link= 0;
479 rep->re_clear_rx= 0;
480 rep->re_need_reset= 0;
481 rep->re_tx_alive= 0;
482 rep->re_read_s= 0;
483 rep->re_tx_head= 0;
484 rep->re_tx_tail= 0;
485 rep->re_ertxth= RL_TSD_ERTXTH_8;
486 rep->re_stat= empty_stat;
489 /*===========================================================================*
490 * rl_init_buf *
491 *===========================================================================*/
492 static void rl_init_buf(rep)
493 re_t *rep;
495 size_t rx_bufsize, tx_bufsize, tot_bufsize;
496 phys_bytes buf;
497 char *mallocbuf;
498 int i, off;
500 /* Allocate receive and transmit buffers */
501 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
502 if (tx_bufsize % 4)
503 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
504 rx_bufsize= RX_BUFSIZE;
505 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
507 if (tot_bufsize % 4096)
508 tot_bufsize += 4096-(tot_bufsize % 4096);
510 #define BUF_ALIGNMENT (64*1024)
512 if(!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) {
513 panic("Couldn't allocate kernel buffer");
516 /* click-align mallocced buffer. this is what we used to get
517 * from kmalloc() too.
519 if((off = buf % BUF_ALIGNMENT)) {
520 mallocbuf += BUF_ALIGNMENT - off;
521 buf += BUF_ALIGNMENT - off;
524 tell_dev((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0);
526 for (i= 0; i<N_TX_BUF; i++)
528 rep->re_tx[i].ret_buf= buf;
529 rep->re_tx[i].v_ret_buf= mallocbuf;
530 buf += tx_bufsize;
531 mallocbuf += tx_bufsize;
533 rep->re_rx_buf= buf;
534 rep->v_re_rx_buf= mallocbuf;
537 /*===========================================================================*
538 * rl_init_hw *
539 *===========================================================================*/
540 static void rl_init_hw(rep)
541 re_t *rep;
543 int s, i;
545 rep->re_flags = REF_EMPTY;
546 rep->re_flags |= REF_ENABLED;
548 /* Set the interrupt handler. The policy is to only send HARD_INT
549 * notifications. Don't reenable interrupts automatically. The id
550 * that is passed back is the interrupt line number.
552 rep->re_hook_id = rep->re_irq;
553 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
554 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
556 rl_reset_hw(rep);
558 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
559 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
561 #if VERBOSE /* stay silent during startup, can always get status later */
562 if (rep->re_model) {
563 printf("%s: model %s\n", rep->re_name, rep->re_model);
564 } else
566 printf("%s: unknown model 0x%08x\n",
567 rep->re_name,
568 rl_inl(rep->re_base_port, RL_TCR) &
569 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
571 #endif
573 rl_confaddr(rep);
574 if (debug)
576 printf("%s: Ethernet address ", rep->re_name);
577 for (i= 0; i < 6; i++)
579 printf("%x%c", rep->re_address.ea_addr[i],
580 i < 5 ? ':' : '\n');
585 /*===========================================================================*
586 * rl_reset_hw *
587 *===========================================================================*/
588 static void rl_reset_hw(rep)
589 re_t *rep;
591 port_t port;
592 u32_t t;
593 phys_bytes bus_buf;
594 int i;
596 port= rep->re_base_port;
598 #if 0
599 /* Reset the PHY */
600 rl_outb(port, RL_BMCR, MII_CTRL_RST);
601 SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
602 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
603 panic("reset PHY failed to complete");
604 #endif
606 /* Reset the device */
607 #if VERBOSE
608 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
609 port, rl_inb(port, RL_CR));
610 #endif
611 rl_outb(port, RL_CR, RL_CR_RST);
612 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
613 #if VERBOSE
614 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
615 port, rl_inb(port, RL_CR));
616 #endif
617 if (rl_inb(port, RL_CR) & RL_CR_RST)
618 printf("rtl8139: reset failed to complete");
620 t= rl_inl(port, RL_TCR);
621 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
623 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
624 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
625 case RL_TCR_HWVER_RTL8139AG:
626 rep->re_model= "RTL8139A-G / RTL8139C";
627 break;
628 case RL_TCR_HWVER_RTL8139B:
629 rep->re_model= "RTL8139B / RTL8130";
630 break;
631 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
632 case RL_TCR_HWVER_RTL8100B:
633 rep->re_model= "RTL8100B/RTL8139D";
634 break;
635 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
636 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
637 default:
638 rep->re_model= NULL;
639 break;
642 #if 0
643 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
644 #endif
646 /* Intialize Rx */
648 /* Should init multicast mask */
649 #if 0
650 08-0f R/W MAR[0-7] multicast
651 #endif
652 bus_buf= vm_1phys2bus(rep->re_rx_buf);
653 rl_outl(port, RL_RBSTART, bus_buf);
655 /* Initialize Tx */
656 for (i= 0; i<N_TX_BUF; i++)
658 rep->re_tx[i].ret_busy= FALSE;
659 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
660 rl_outl(port, RL_TSAD0+i*4, bus_buf);
661 t= rl_inl(port, RL_TSD0+i*4);
662 assert(t & RL_TSD_OWN);
665 #if 0
666 dump_phy(rep);
667 #endif
669 t= rl_inw(port, RL_IMR);
670 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
671 RL_IMR_LENCHG));
673 t= rl_inw(port, RL_IMR);
674 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
675 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
677 t= rl_inw(port, RL_IMR);
678 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
680 t= rl_inb(port, RL_CR);
681 rl_outb(port, RL_CR, t | RL_CR_RE);
683 t= rl_inb(port, RL_CR);
684 rl_outb(port, RL_CR, t | RL_CR_TE);
686 rl_outl(port, RL_RCR, RX_BUFBITS);
688 t= rl_inl(port, RL_TCR);
689 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
692 /*===========================================================================*
693 * rl_confaddr *
694 *===========================================================================*/
695 static void rl_confaddr(rep)
696 re_t *rep;
698 static char eakey[]= RL_ENVVAR "#_EA";
699 static char eafmt[]= "x:x:x:x:x:x";
701 int i;
702 port_t port;
703 u32_t w;
704 long v;
706 /* User defined ethernet address? */
707 eakey[sizeof(RL_ENVVAR)-1]= '0' + re_instance;
709 port= rep->re_base_port;
711 for (i= 0; i < 6; i++)
713 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
714 break;
715 rep->re_address.ea_addr[i]= v;
718 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
720 /* Should update ethernet address in hardware */
721 if (i == 6)
723 port= rep->re_base_port;
724 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
725 w= 0;
726 for (i= 0; i<4; i++)
727 w |= (rep->re_address.ea_addr[i] << (i*8));
728 rl_outl(port, RL_IDR, w);
729 w= 0;
730 for (i= 4; i<6; i++)
731 w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
732 rl_outl(port, RL_IDR+4, w);
733 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
736 /* Get ethernet address */
737 for (i= 0; i<6; i++)
738 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
741 /*===========================================================================*
742 * rl_rec_mode *
743 *===========================================================================*/
744 static void rl_rec_mode(rep)
745 re_t *rep;
747 port_t port;
748 u32_t rcr;
750 port= rep->re_base_port;
751 rcr= rl_inl(port, RL_RCR);
752 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
753 if (rep->re_flags & REF_PROMISC)
754 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
755 if (rep->re_flags & REF_BROAD)
756 rcr |= RL_RCR_AB;
757 if (rep->re_flags & REF_MULTI)
758 rcr |= RL_RCR_AM;
759 rcr |= RL_RCR_APM;
761 rl_outl(port, RL_RCR, rcr);
764 /*===========================================================================*
765 * rl_readv_s *
766 *===========================================================================*/
767 static void rl_readv_s(const message *mp, int from_int)
769 int i, j, n, o, s, s1, count, size;
770 port_t port;
771 unsigned amount, totlen, packlen;
772 u16_t d_start, d_end;
773 u32_t l, rxstat = 0x12345678;
774 re_t *rep;
775 iovec_s_t *iovp;
776 int cps;
777 int iov_offset = 0;
779 rep= &re_state;
781 rep->re_client= mp->m_source;
782 count = mp->DL_COUNT;
784 if (rep->re_clear_rx)
785 goto suspend; /* Buffer overflow */
787 assert(rep->re_mode == REM_ENABLED);
788 assert(rep->re_flags & REF_ENABLED);
790 port= rep->re_base_port;
792 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
794 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
796 /* Receive buffer is empty, suspend */
797 goto suspend;
800 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
801 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
803 #if RX_BUFSIZE <= USHRT_MAX
804 if (d_start >= RX_BUFSIZE)
806 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
807 rl_inw(port, RL_CAPR));
808 d_start %= RX_BUFSIZE;
810 #endif
812 if (d_end > d_start)
813 amount= d_end-d_start;
814 else
815 amount= d_end+RX_BUFSIZE - d_start;
817 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
819 if (rep->re_clear_rx)
821 #if 0
822 printf("rl_readv: late buffer overflow\n");
823 #endif
824 goto suspend; /* Buffer overflow */
827 /* Should convert from little endian to host byte order */
829 if (!(rxstat & RL_RXS_ROK))
831 printf("rxstat = 0x%08x\n", rxstat);
832 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
833 d_start, d_end, rxstat);
834 panic("received packet not OK");
836 totlen= (rxstat >> RL_RXS_LEN_S);
837 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
839 /* Someting went wrong */
840 printf(
841 "rl_readv: bad length (%u) in status 0x%08x at offset 0x%x\n",
842 totlen, rxstat, d_start);
843 printf(
844 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
845 d_start, d_end, totlen, rxstat);
846 panic(NULL);
849 #if 0
850 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
851 d_start, d_end, totlen, rxstat);
852 #endif
854 if (totlen+4 > amount)
856 printf("rl_readv: packet not yet ready\n");
857 goto suspend;
860 /* Should subtract the CRC */
861 packlen= totlen - ETH_CRC_SIZE;
863 size= 0;
864 o= d_start+4;
865 for (i= 0; i<count; i += IOVEC_NR,
866 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
868 n= IOVEC_NR;
869 if (i+n > count)
870 n= count-i;
872 cps = sys_safecopyfrom(mp->m_source, mp->DL_GRANT, iov_offset,
873 (vir_bytes) rep->re_iovec_s,
874 n * sizeof(rep->re_iovec_s[0]));
875 if (cps != OK) {
876 panic("rl_readv_s: sys_safecopyfrom failed: %d",
877 cps);
880 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
882 s= iovp->iov_size;
883 if (size + s > packlen)
885 assert(packlen > size);
886 s= packlen-size;
889 #if 0
890 if (sys_umap(mp->m_source, D, iovp->iov_addr, s, &dst_phys) != OK)
891 panic("umap_local failed");
892 #endif
894 if (o >= RX_BUFSIZE)
896 o -= RX_BUFSIZE;
897 assert(o < RX_BUFSIZE);
900 if (o+s > RX_BUFSIZE)
902 assert(o<RX_BUFSIZE);
903 s1= RX_BUFSIZE-o;
905 cps = sys_safecopyto(mp->m_source,
906 iovp->iov_grant, 0,
907 (vir_bytes) rep->v_re_rx_buf+o, s1);
908 if (cps != OK) {
909 panic("rl_readv_s: sys_safecopyto failed: %d",
910 cps);
912 cps = sys_safecopyto(mp->m_source,
913 iovp->iov_grant, s1,
914 (vir_bytes) rep->v_re_rx_buf, s-s1);
915 if (cps != OK) {
916 panic("rl_readv_s: sys_safecopyto failed: %d", cps);
919 else
921 cps = sys_safecopyto(mp->m_source,
922 iovp->iov_grant, 0,
923 (vir_bytes) rep->v_re_rx_buf+o, s);
924 if (cps != OK)
925 panic("rl_readv_s: sys_safecopyto failed: %d", cps);
928 size += s;
929 if (size == packlen)
930 break;
931 o += s;
933 if (size == packlen)
934 break;
936 if (size < packlen)
938 assert(0);
941 if (rep->re_clear_rx)
943 /* For some reason the receiver FIFO is not stopped when
944 * the buffer is full.
946 #if 0
947 printf("rl_readv: later buffer overflow\n");
948 #endif
949 goto suspend; /* Buffer overflow */
952 rep->re_stat.ets_packetR++;
953 rep->re_read_s= packlen;
954 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
956 /* Avoid overflow in 16-bit computations */
957 l= d_start;
958 l += totlen+4;
959 l= (l+3) & ~3; /* align */
960 if (l >= RX_BUFSIZE)
962 l -= RX_BUFSIZE;
963 assert(l < RX_BUFSIZE);
965 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
967 if (!from_int)
968 reply(rep);
970 return;
972 suspend:
973 if (from_int)
975 assert(rep->re_flags & REF_READING);
977 /* No need to store any state */
978 return;
981 rep->re_rx_mess= *mp;
982 assert(!(rep->re_flags & REF_READING));
983 rep->re_flags |= REF_READING;
985 reply(rep);
988 /*===========================================================================*
989 * rl_writev_s *
990 *===========================================================================*/
991 static void rl_writev_s(const message *mp, int from_int)
993 int i, j, n, s, count, size;
994 int tx_head;
995 re_t *rep;
996 iovec_s_t *iovp;
997 char *ret;
998 int cps;
999 int iov_offset = 0;
1001 rep= &re_state;
1003 rep->re_client= mp->m_source;
1004 count = mp->DL_COUNT;
1006 assert(rep->re_mode == REM_ENABLED);
1007 assert(rep->re_flags & REF_ENABLED);
1009 if (from_int)
1011 assert(rep->re_flags & REF_SEND_AVAIL);
1012 rep->re_flags &= ~REF_SEND_AVAIL;
1013 rep->re_send_int= FALSE;
1014 rep->re_tx_alive= TRUE;
1017 tx_head= rep->re_tx_head;
1018 if (rep->re_tx[tx_head].ret_busy)
1020 assert(!(rep->re_flags & REF_SEND_AVAIL));
1021 rep->re_flags |= REF_SEND_AVAIL;
1022 goto suspend;
1025 assert(!(rep->re_flags & REF_SEND_AVAIL));
1026 assert(!(rep->re_flags & REF_PACK_SENT));
1028 size= 0;
1029 ret = rep->re_tx[tx_head].v_ret_buf;
1030 for (i= 0; i<count; i += IOVEC_NR,
1031 iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
1033 n= IOVEC_NR;
1034 if (i+n > count)
1035 n= count-i;
1036 cps = sys_safecopyfrom(mp->m_source, mp->DL_GRANT, iov_offset,
1037 (vir_bytes) rep->re_iovec_s,
1038 n * sizeof(rep->re_iovec_s[0]));
1039 if (cps != OK) {
1040 panic("rl_writev_s: sys_safecopyfrom failed: %d", cps);
1043 for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
1045 s= iovp->iov_size;
1046 if (size + s > ETH_MAX_PACK_SIZE_TAGGED) {
1047 panic("invalid packet size");
1049 cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant,
1050 0, (vir_bytes) ret, s);
1051 if (cps != OK) {
1052 panic("rl_writev_s: sys_safecopyfrom failed: %d", cps);
1054 size += s;
1055 ret += s;
1058 if (size < ETH_MIN_PACK_SIZE)
1059 panic("invalid packet size: %d", size);
1061 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1062 rep->re_ertxth | size);
1063 rep->re_tx[tx_head].ret_busy= TRUE;
1065 if (++tx_head == N_TX_BUF)
1066 tx_head= 0;
1067 assert(tx_head < RL_N_TX);
1068 rep->re_tx_head= tx_head;
1070 rep->re_flags |= REF_PACK_SENT;
1072 /* If the interrupt handler called, don't send a reply. The reply
1073 * will be sent after all interrupts are handled.
1075 if (from_int)
1076 return;
1077 reply(rep);
1078 return;
1080 suspend:
1081 #if 0
1082 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1083 tx_head, rep->re_tx_tail,
1084 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1085 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1086 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1087 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1088 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1089 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1090 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1091 #endif
1093 if (from_int)
1094 panic("should not be sending");
1096 rep->re_tx_mess= *mp;
1097 reply(rep);
1100 /*===========================================================================*
1101 * rl_check_ints *
1102 *===========================================================================*/
1103 static void rl_check_ints(rep)
1104 re_t *rep;
1106 #if 0
1107 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
1108 31 R CRS Carrier Sense Lost
1109 30 R TABT Transmit Abort
1110 29 R OWC Out of Window Collision
1111 27-24 R NCC[3-0] Number of Collision Count
1112 23-22 reserved
1113 21-16 R/W ERTXH[5-0] Early Tx Threshold
1114 15 R TOK Transmit OK
1115 14 R TUN Transmit FIFO Underrun
1116 13 R/W OWN OWN
1117 12-0 R/W SIZE Descriptor Size
1118 3e-3f R/W ISR Interrupt Status Register
1119 6 R/W FOVW Fx FIFO Overflow Interrupt
1120 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
1121 3 R/W TER Transmit Error Interrupt
1122 2 R/W TOK Transmit OK Interrupt
1123 3e-3f R/W ISR Interrupt Status Register
1124 15 R/W SERR System Error Interrupt
1125 14 R/W TimeOut Time Out Interrupt
1126 13 R/W LenChg Cable Length Change Interrupt
1127 3e-3f R/W ISR Interrupt Status Register
1128 4 R/W RXOVW Rx Buffer Overflow Interrupt
1129 1 R/W RER Receive Error Interrupt
1130 0 R/W ROK Receive OK Interrupt
1131 4c-4f R/W MPC Missed Packet Counter
1132 60-61 R TSAD Transmit Status of All Descriptors
1133 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
1134 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
1135 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
1136 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
1137 6c-6d R DIS Disconnect Counter
1138 15-0 R DCNT Disconnect Counter
1139 6e-6f R FCSC False Carrier Sense Counter
1140 15-0 R FCSCNT False Carrier event counter
1141 72-73 R REC RX_ER Counter
1142 15-0 R RXERCNT Received packet counter
1143 #endif
1145 int re_flags;
1147 re_flags= rep->re_flags;
1149 if ((re_flags & REF_READING) &&
1150 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1152 rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
1154 if (rep->re_clear_rx)
1155 rl_clear_rx(rep);
1157 if (rep->re_need_reset)
1158 rl_do_reset(rep);
1160 if (rep->re_send_int)
1162 rl_writev_s(&rep->re_tx_mess, TRUE /* from int */);
1165 if (rep->re_report_link)
1166 rl_report_link(rep);
1168 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1169 reply(rep);
1172 /*===========================================================================*
1173 * rl_report_link *
1174 *===========================================================================*/
1175 static void rl_report_link(rep)
1176 re_t *rep;
1178 port_t port;
1179 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
1180 u8_t msr;
1181 int f, link_up;
1183 rep->re_report_link= FALSE;
1184 port= rep->re_base_port;
1185 msr= rl_inb(port, RL_MSR);
1186 link_up= !(msr & RL_MSR_LINKB);
1187 rep->re_link_up= link_up;
1188 if (!link_up)
1190 printf("%s: link down\n", rep->re_name);
1191 return;
1194 mii_ctrl= rl_inw(port, RL_BMCR);
1195 mii_status= rl_inw(port, RL_BMSR);
1196 mii_ana= rl_inw(port, RL_ANAR);
1197 mii_anlpa= rl_inw(port, RL_ANLPAR);
1198 mii_ane= rl_inw(port, RL_ANER);
1199 mii_extstat= 0;
1201 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1203 printf("%s: PHY: ", rep->re_name);
1204 f= 1;
1205 if (mii_ctrl & MII_CTRL_LB)
1207 printf("loopback mode");
1208 f= 0;
1210 if (mii_ctrl & MII_CTRL_PD)
1212 if (!f) printf(", ");
1213 f= 0;
1214 printf("powered down");
1216 if (mii_ctrl & MII_CTRL_ISO)
1218 if (!f) printf(", ");
1219 f= 0;
1220 printf("isolated");
1222 printf("\n");
1223 return;
1225 if (!(mii_ctrl & MII_CTRL_ANE))
1227 printf("%s: manual config: ", rep->re_name);
1228 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1230 case MII_CTRL_SP_10: printf("10 Mbps"); break;
1231 case MII_CTRL_SP_100: printf("100 Mbps"); break;
1232 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
1233 case MII_CTRL_SP_RES: printf("reserved speed"); break;
1235 if (mii_ctrl & MII_CTRL_DM)
1236 printf(", full duplex");
1237 else
1238 printf(", half duplex");
1239 printf("\n");
1240 return;
1243 if (!debug) goto resspeed;
1245 printf("%s: ", rep->re_name);
1246 mii_print_stat_speed(mii_status, mii_extstat);
1247 printf("\n");
1249 if (!(mii_status & MII_STATUS_ANC))
1250 printf("%s: auto-negotiation not complete\n", rep->re_name);
1251 if (mii_status & MII_STATUS_RF)
1252 printf("%s: remote fault detected\n", rep->re_name);
1253 if (!(mii_status & MII_STATUS_ANA))
1255 printf("%s: local PHY has no auto-negotiation ability\n",
1256 rep->re_name);
1258 if (!(mii_status & MII_STATUS_LS))
1259 printf("%s: link down\n", rep->re_name);
1260 if (mii_status & MII_STATUS_JD)
1261 printf("%s: jabber condition detected\n", rep->re_name);
1262 if (!(mii_status & MII_STATUS_EC))
1264 printf("%s: no extended register set\n", rep->re_name);
1265 goto resspeed;
1267 if (!(mii_status & MII_STATUS_ANC))
1268 goto resspeed;
1270 printf("%s: local cap.: ", rep->re_name);
1271 mii_print_techab(mii_ana);
1272 printf("\n");
1274 if (mii_ane & MII_ANE_PDF)
1275 printf("%s: parallel detection fault\n", rep->re_name);
1276 if (!(mii_ane & MII_ANE_LPANA))
1278 printf("%s: link-partner does not support auto-negotiation\n",
1279 rep->re_name);
1280 goto resspeed;
1283 printf("%s: remote cap.: ", rep->re_name);
1284 mii_print_techab(mii_anlpa);
1285 printf("\n");
1287 resspeed:
1288 printf("%s: ", rep->re_name);
1289 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
1290 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
1294 static void mii_print_techab(u16_t techab)
1296 int fs, ft;
1297 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
1299 printf("strange selector 0x%x, value 0x%x",
1300 techab & MII_ANA_SEL_M,
1301 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
1302 return;
1304 fs= 1;
1305 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
1307 printf("100 Mbps: ");
1308 fs= 0;
1309 ft= 1;
1310 if (techab & MII_ANA_100T4)
1312 printf("T4");
1313 ft= 0;
1315 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
1317 if (!ft)
1318 printf(", ");
1319 ft= 0;
1320 printf("TX-");
1321 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
1323 case MII_ANA_100TXFD: printf("FD"); break;
1324 case MII_ANA_100TXHD: printf("HD"); break;
1325 default: printf("FD/HD"); break;
1329 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
1331 if (!fs)
1332 printf(", ");
1333 printf("10 Mbps: ");
1334 fs= 0;
1335 printf("T-");
1336 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
1338 case MII_ANA_10TFD: printf("FD"); break;
1339 case MII_ANA_10THD: printf("HD"); break;
1340 default: printf("FD/HD"); break;
1343 if (techab & MII_ANA_PAUSE_SYM)
1345 if (!fs)
1346 printf(", ");
1347 fs= 0;
1348 printf("pause(SYM)");
1350 if (techab & MII_ANA_PAUSE_ASYM)
1352 if (!fs)
1353 printf(", ");
1354 fs= 0;
1355 printf("pause(ASYM)");
1357 if (techab & MII_ANA_TAF_RES)
1359 if (!fs)
1360 printf(", ");
1361 fs= 0;
1362 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
1366 static void mii_print_stat_speed(u16_t stat, u16_t extstat)
1368 int fs, ft;
1369 fs= 1;
1370 if (stat & MII_STATUS_EXT_STAT)
1372 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1373 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1375 printf("1000 Mbps: ");
1376 fs= 0;
1377 ft= 1;
1378 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1380 ft= 0;
1381 printf("X-");
1382 switch(extstat &
1383 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1385 case MII_ESTAT_1000XFD: printf("FD"); break;
1386 case MII_ESTAT_1000XHD: printf("HD"); break;
1387 default: printf("FD/HD"); break;
1390 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1392 if (!ft)
1393 printf(", ");
1394 ft= 0;
1395 printf("T-");
1396 switch(extstat &
1397 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1399 case MII_ESTAT_1000TFD: printf("FD"); break;
1400 case MII_ESTAT_1000THD: printf("HD"); break;
1401 default: printf("FD/HD"); break;
1406 if (stat & (MII_STATUS_100T4 |
1407 MII_STATUS_100XFD | MII_STATUS_100XHD |
1408 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1410 if (!fs)
1411 printf(", ");
1412 fs= 0;
1413 printf("100 Mbps: ");
1414 ft= 1;
1415 if (stat & MII_STATUS_100T4)
1417 printf("T4");
1418 ft= 0;
1420 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1422 if (!ft)
1423 printf(", ");
1424 ft= 0;
1425 printf("TX-");
1426 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1428 case MII_STATUS_100XFD: printf("FD"); break;
1429 case MII_STATUS_100XHD: printf("HD"); break;
1430 default: printf("FD/HD"); break;
1433 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1435 if (!ft)
1436 printf(", ");
1437 ft= 0;
1438 printf("T2-");
1439 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1441 case MII_STATUS_100T2FD: printf("FD"); break;
1442 case MII_STATUS_100T2HD: printf("HD"); break;
1443 default: printf("FD/HD"); break;
1447 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1449 if (!fs)
1450 printf(", ");
1451 printf("10 Mbps: ");
1452 fs= 0;
1453 printf("T-");
1454 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1456 case MII_STATUS_10FD: printf("FD"); break;
1457 case MII_STATUS_10HD: printf("HD"); break;
1458 default: printf("FD/HD"); break;
1463 /*===========================================================================*
1464 * rl_clear_rx *
1465 *===========================================================================*/
1466 static void rl_clear_rx(re_t *rep)
1468 port_t port;
1469 u8_t cr;
1471 rep->re_clear_rx= FALSE;
1472 port= rep->re_base_port;
1474 /* Reset the receiver */
1475 cr= rl_inb(port, RL_CR);
1476 cr &= ~RL_CR_RE;
1477 rl_outb(port, RL_CR, cr);
1478 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
1479 if (rl_inb(port, RL_CR) & RL_CR_RE)
1480 panic("cannot disable receiver");
1482 #if 0
1483 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1484 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1485 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1486 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1487 #endif
1489 rl_outb(port, RL_CR, cr | RL_CR_RE);
1491 rl_outl(port, RL_RCR, RX_BUFBITS);
1493 rl_rec_mode(rep);
1495 rep->re_stat.ets_missedP++;
1498 /*===========================================================================*
1499 * rl_do_reset *
1500 *===========================================================================*/
1501 static void rl_do_reset(rep)
1502 re_t *rep;
1504 rep->re_need_reset= FALSE;
1505 rl_reset_hw(rep);
1506 rl_rec_mode(rep);
1508 rep->re_tx_head= 0;
1509 if (rep->re_flags & REF_SEND_AVAIL)
1511 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1512 rep->re_send_int= TRUE;
1516 /*===========================================================================*
1517 * rl_getstat_s *
1518 *===========================================================================*/
1519 static void rl_getstat_s(mp)
1520 message *mp;
1522 int r;
1523 eth_stat_t stats;
1524 re_t *rep;
1526 rep= &re_state;
1528 assert(rep->re_mode == REM_ENABLED);
1529 assert(rep->re_flags & REF_ENABLED);
1531 stats= rep->re_stat;
1533 r = sys_safecopyto(mp->m_source, mp->DL_GRANT, 0,
1534 (vir_bytes) &stats, sizeof(stats));
1535 if (r != OK)
1536 panic("rl_getstat_s: sys_safecopyto failed: %d", r);
1538 mp->m_type= DL_STAT_REPLY;
1539 r= send(mp->m_source, mp);
1540 if (r != OK)
1541 panic("rl_getstat_s: send failed: %d", r);
1544 /*===========================================================================*
1545 * reply *
1546 *===========================================================================*/
1547 static void reply(rep)
1548 re_t *rep;
1550 message reply;
1551 int flags;
1552 int r;
1554 flags = DL_NOFLAGS;
1555 if (rep->re_flags & REF_PACK_SENT)
1556 flags |= DL_PACK_SEND;
1557 if (rep->re_flags & REF_PACK_RECV)
1558 flags |= DL_PACK_RECV;
1560 reply.m_type = DL_TASK_REPLY;
1561 reply.DL_FLAGS = flags;
1562 reply.DL_COUNT = rep->re_read_s;
1564 r= send(rep->re_client, &reply);
1566 if (r < 0) {
1567 printf("RTL8139 tried sending to %d, type %d\n",
1568 rep->re_client, reply.m_type);
1569 panic("send failed: %d", r);
1572 rep->re_read_s = 0;
1573 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
1576 /*===========================================================================*
1577 * mess_reply *
1578 *===========================================================================*/
1579 static void mess_reply(req, reply_mess)
1580 message *req;
1581 message *reply_mess;
1583 if (send(req->m_source, reply_mess) != OK)
1584 panic("unable to mess_reply");
1587 #if 0
1588 /*===========================================================================*
1589 * dump_phy *
1590 *===========================================================================*/
1591 static void dump_phy(rep)
1592 re_t *rep;
1594 port_t port;
1595 u32_t t;
1597 port= rep->re_base_port;
1599 t= rl_inb(port, RL_MSR);
1600 printf("MSR: 0x%02lx\n", t);
1601 if (t & RL_MSR_SPEED_10)
1602 printf("\t10 Mbps\n");
1603 if (t & RL_MSR_LINKB)
1604 printf("\tLink failed\n");
1606 t= rl_inb(port, RL_CONFIG1);
1607 printf("CONFIG1: 0x%02lx\n", t);
1609 t= rl_inb(port, RL_CONFIG3);
1610 printf("CONFIG3: 0x%02lx\n", t);
1612 t= rl_inb(port, RL_CONFIG4);
1613 printf("CONFIG4: 0x%02lx\n", t);
1615 t= rl_inw(port, RL_BMCR);
1616 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
1618 t= rl_inw(port, RL_BMSR);
1619 printf("BMSR:");
1620 if (t & MII_STATUS_100T4)
1621 printf(" 100Base-T4");
1622 if (t & MII_STATUS_100XFD)
1623 printf(" 100Base-X-FD");
1624 if (t & MII_STATUS_100XHD)
1625 printf(" 100Base-X-HD");
1626 if (t & MII_STATUS_10FD)
1627 printf(" 10Mbps-FD");
1628 if (t & MII_STATUS_10HD)
1629 printf(" 10Mbps-HD");
1630 if (t & MII_STATUS_100T2FD)
1631 printf(" 100Base-T2-FD");
1632 if (t & MII_STATUS_100T2HD)
1633 printf(" 100Base-T2-HD");
1634 if (t & MII_STATUS_EXT_STAT)
1635 printf(" Ext-stat");
1636 if (t & MII_STATUS_RES)
1637 printf(" res-0x%lx", t & MII_STATUS_RES);
1638 if (t & MII_STATUS_MFPS)
1639 printf(" MFPS");
1640 if (t & MII_STATUS_ANC)
1641 printf(" ANC");
1642 if (t & MII_STATUS_RF)
1643 printf(" remote-fault");
1644 if (t & MII_STATUS_ANA)
1645 printf(" ANA");
1646 if (t & MII_STATUS_LS)
1647 printf(" Link");
1648 if (t & MII_STATUS_JD)
1649 printf(" Jabber");
1650 if (t & MII_STATUS_EC)
1651 printf(" Extended-capability");
1652 printf("\n");
1654 t= rl_inw(port, RL_ANAR);
1655 printf("ANAR (MII_ANA): 0x%04lx\n", t);
1657 t= rl_inw(port, RL_ANLPAR);
1658 printf("ANLPAR: 0x%04lx\n", t);
1660 t= rl_inw(port, RL_ANER);
1661 printf("ANER (MII_ANE): ");
1662 if (t & MII_ANE_RES)
1663 printf(" res-0x%lx", t & MII_ANE_RES);
1664 if (t & MII_ANE_PDF)
1665 printf(" Par-Detect-Fault");
1666 if (t & MII_ANE_LPNPA)
1667 printf(" LP-Next-Page-Able");
1668 if (t & MII_ANE_NPA)
1669 printf(" Loc-Next-Page-Able");
1670 if (t & MII_ANE_PR)
1671 printf(" Page-Received");
1672 if (t & MII_ANE_LPANA)
1673 printf(" LP-Auto-Neg-Able");
1674 printf("\n");
1676 t= rl_inw(port, RL_NWAYTR);
1677 printf("NWAYTR: 0x%04lx\n", t);
1678 t= rl_inw(port, RL_CSCR);
1679 printf("CSCR: 0x%04lx\n", t);
1681 t= rl_inb(port, RL_CONFIG5);
1682 printf("CONFIG5: 0x%02lx\n", t);
1684 #endif
1686 /*===========================================================================*
1687 * do_hard_int *
1688 *===========================================================================*/
1689 static void do_hard_int(void)
1691 int s;
1693 /* Run interrupt handler at driver level. */
1694 rl_handler(&re_state);
1696 /* Reenable interrupts for this hook. */
1697 if ((s=sys_irqenable(&re_state.re_hook_id)) != OK)
1698 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
1701 /*===========================================================================*
1702 * rl_handler *
1703 *===========================================================================*/
1704 static int rl_handler(re_t *rep)
1706 int i, port, tx_head, tx_tail, link_up;
1707 u16_t isr, tsad;
1708 u32_t tsd, tcr, ertxth;
1709 #if 0
1710 u8_t cr;
1711 #endif
1712 int_event_check = FALSE; /* disable check by default */
1714 port= rep->re_base_port;
1716 /* Ack interrupt */
1717 isr= rl_inw(port, RL_ISR);
1718 rl_outw(port, RL_ISR, isr);
1720 if (isr & RL_IMR_FOVW)
1722 isr &= ~RL_IMR_FOVW;
1723 /* Should do anything? */
1725 rep->re_stat.ets_fifoOver++;
1727 if (isr & RL_IMR_PUN)
1729 isr &= ~RL_IMR_PUN;
1731 /* Either the link status changed or there was a TX fifo
1732 * underrun.
1734 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
1735 if (link_up != rep->re_link_up)
1737 rep->re_report_link= TRUE;
1738 rep->re_got_int= TRUE;
1739 int_event_check = TRUE;
1742 if (isr & RL_IMR_RXOVW)
1744 isr &= ~RL_IMR_RXOVW;
1746 /* Clear the receive buffer */
1747 rep->re_clear_rx= TRUE;
1748 rep->re_got_int= TRUE;
1749 int_event_check = TRUE;
1752 if (isr & (RL_ISR_RER | RL_ISR_ROK))
1754 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
1756 if (!rep->re_got_int && (rep->re_flags & REF_READING))
1758 rep->re_got_int= TRUE;
1759 int_event_check = TRUE;
1762 #if 0
1763 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
1764 (rep->re_flags & REF_SEND_AVAIL) &&
1765 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
1766 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
1769 printf(
1770 "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1771 rep->re_tx_head, rep->re_tx_tail,
1772 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1773 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1774 printf(
1775 "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1776 rl_inw(port, RL_TSAD),
1777 rl_inl(port, RL_TSD0+0*4),
1778 rl_inl(port, RL_TSD0+1*4),
1779 rl_inl(port, RL_TSD0+2*4),
1780 rl_inl(port, RL_TSD0+3*4));
1782 #endif
1783 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
1785 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
1787 tsad= rl_inw(port, RL_TSAD);
1788 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
1789 RL_TSAD_TABT2|RL_TSAD_TABT3))
1791 #if 0
1792 /* Do we need a watch dog? */
1793 /* Just reset the whole chip */
1794 rep->re_need_reset= TRUE;
1795 rep->re_got_int= TRUE;
1796 int_event_check = TRUE;
1797 #elif 0
1798 /* Reset transmitter */
1799 rep->re_stat.ets_transAb++;
1801 cr= rl_inb(port, RL_CR);
1802 cr &= ~RL_CR_TE;
1803 rl_outb(port, RL_CR, cr);
1804 SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_TE), 1000000);
1805 if (rl_inb(port, RL_CR) & RL_CR_TE) {
1806 panic("cannot disable transmitter");
1808 rl_outb(port, RL_CR, cr | RL_CR_TE);
1810 tcr= rl_inl(port, RL_TCR);
1811 rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
1813 printf("rl_handler: reset after abort\n");
1815 if (rep->re_flags & REF_SEND_AVAIL)
1817 printf("rl_handler: REF_SEND_AVAIL\n");
1818 rep->re_send_int= TRUE;
1819 rep->re_got_int= TRUE;
1820 int_event_check = TRUE;
1822 for (i= 0; i< N_TX_BUF; i++)
1823 rep->re_tx[i].ret_busy= FALSE;
1824 rep->re_tx_head= 0;
1825 #else
1826 printf("rl_handler, TABT, tasd = 0x%04x\n",
1827 tsad);
1829 /* Find the aborted transmit request */
1830 for (i= 0; i< N_TX_BUF; i++)
1832 tsd= rl_inl(port, RL_TSD0+i*4);
1833 if (tsd & RL_TSD_TABT)
1834 break;
1836 if (i >= N_TX_BUF)
1838 printf(
1839 "rl_handler: can't find aborted TX req.\n");
1841 else
1843 printf("TSD%d = 0x%04x\n", i, tsd);
1845 /* Set head and tail to this buffer */
1846 rep->re_tx_head= rep->re_tx_tail= i;
1849 /* Aborted transmission, just kick the device
1850 * and be done with it.
1852 rep->re_stat.ets_transAb++;
1853 tcr= rl_inl(port, RL_TCR);
1854 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1855 #endif
1858 /* Transmit completed */
1859 tx_head= rep->re_tx_head;
1860 tx_tail= rep->re_tx_tail;
1861 for (i= 0; i< 2*N_TX_BUF; i++)
1863 if (!rep->re_tx[tx_tail].ret_busy)
1865 /* Strange, this buffer is not in-use.
1866 * Increment tx_tail until tx_head is
1867 * reached (or until we find a buffer that
1868 * is in-use.
1870 if (tx_tail == tx_head)
1871 break;
1872 if (++tx_tail >= N_TX_BUF)
1873 tx_tail= 0;
1874 assert(tx_tail < RL_N_TX);
1875 rep->re_tx_tail= tx_tail;
1876 continue;
1878 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
1879 if (!(tsd & RL_TSD_OWN))
1881 /* Buffer is not yet ready */
1882 break;
1885 /* Should collect statistics */
1886 if (tsd & RL_TSD_CRS)
1887 rep->re_stat.ets_carrSense++;
1888 if (tsd & RL_TSD_TABT)
1890 printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1891 tx_tail, tsd);
1892 assert(0); /* CLRABT is not all that
1893 * effective, why not?
1895 rep->re_stat.ets_transAb++;
1896 tcr= rl_inl(port, RL_TCR);
1897 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1899 if (tsd & RL_TSD_OWC)
1900 rep->re_stat.ets_OWC++;
1901 if (tsd & RL_TSD_CDH)
1902 rep->re_stat.ets_CDheartbeat++;
1904 /* What about collisions? */
1905 if (tsd & RL_TSD_TOK)
1906 rep->re_stat.ets_packetT++;
1907 else
1908 rep->re_stat.ets_sendErr++;
1909 if (tsd & RL_TSD_TUN)
1911 rep->re_stat.ets_fifoUnder++;
1913 /* Increase ERTXTH */
1914 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
1915 ertxth &= RL_TSD_ERTXTH_M;
1916 if (debug && ertxth > rep->re_ertxth)
1918 printf("%s: new ertxth: %d bytes\n",
1919 rep->re_name,
1920 (ertxth >> RL_TSD_ERTXTH_S) *
1921 32);
1922 rep->re_ertxth= ertxth;
1925 rep->re_tx[tx_tail].ret_busy= FALSE;
1927 #if 0
1928 if (rep->re_flags & REF_SEND_AVAIL)
1930 printf("TSD%d: %08lx\n", tx_tail, tsd);
1931 printf(
1932 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1933 tx_head, tx_tail,
1934 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1935 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1937 #endif
1939 if (++tx_tail >= N_TX_BUF)
1940 tx_tail= 0;
1941 assert(tx_tail < RL_N_TX);
1942 rep->re_tx_tail= tx_tail;
1944 if (rep->re_flags & REF_SEND_AVAIL)
1946 #if 0
1947 printf("rl_handler: REF_SEND_AVAIL\n");
1948 #endif
1949 rep->re_send_int= TRUE;
1950 if (!rep->re_got_int)
1952 rep->re_got_int= TRUE;
1953 int_event_check = TRUE;
1957 assert(i < 2*N_TX_BUF);
1959 if (isr)
1961 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1962 isr);
1965 return 1;
1968 /*===========================================================================*
1969 * rl_watchdog_f *
1970 *===========================================================================*/
1971 static void rl_watchdog_f(tp)
1972 timer_t *tp;
1974 re_t *rep;
1975 /* Use a synchronous alarm instead of a watchdog timer. */
1976 sys_setalarm(system_hz, 0);
1978 rep= &re_state;
1980 if (rep->re_mode != REM_ENABLED)
1981 return;
1982 if (!(rep->re_flags & REF_SEND_AVAIL))
1984 /* Assume that an idle system is alive */
1985 rep->re_tx_alive= TRUE;
1986 return;
1988 if (rep->re_tx_alive)
1990 rep->re_tx_alive= FALSE;
1991 return;
1993 printf("rl_watchdog_f: resetting instance %d\n", re_instance);
1994 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1995 rl_inw(rep->re_base_port, RL_TSAD),
1996 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1997 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1998 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1999 rl_inl(rep->re_base_port, RL_TSD0+3*4));
2000 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2001 rep->re_tx_head, rep->re_tx_tail,
2002 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2003 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2004 rep->re_need_reset= TRUE;
2005 rep->re_got_int= TRUE;
2007 check_int_events();
2010 #if 0
2012 static void rtl_init(struct dpeth *dep);
2013 static u16_t get_ee_word(dpeth_t *dep, int a);
2014 static void ee_wen(dpeth_t *dep);
2015 static void set_ee_word(dpeth_t *dep, int a, u16_t w);
2016 static void ee_wds(dpeth_t *dep);
2018 static void rtl_init(dep)
2019 dpeth_t *dep;
2021 u8_t reg_a, reg_b, cr, config0, config2, config3;
2022 int i;
2023 char val[128];
2025 printf("rtl_init called\n");
2026 ne_init(dep);
2028 /* ID */
2029 outb_reg0(dep, DP_CR, CR_PS_P0);
2030 reg_a = inb_reg0(dep, DP_DUM1);
2031 reg_b = inb_reg0(dep, DP_DUM2);
2033 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
2035 outb_reg0(dep, DP_CR, CR_PS_P3);
2036 config0 = inb_reg3(dep, 3);
2037 config2 = inb_reg3(dep, 5);
2038 config3 = inb_reg3(dep, 6);
2039 outb_reg0(dep, DP_CR, CR_PS_P0);
2041 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
2042 config0, config2, config3);
2044 if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
2046 printf("rtl_init: setting full-duplex mode\n");
2047 outb_reg0(dep, DP_CR, CR_PS_P3);
2049 cr= inb_reg3(dep, 1);
2050 outb_reg3(dep, 1, cr | 0xc0);
2052 outb_reg3(dep, 6, config3 | 0x40);
2053 config3 = inb_reg3(dep, 6);
2055 config2= inb_reg3(dep, 5);
2056 outb_reg3(dep, 5, config2 | 0x20);
2057 config2= inb_reg3(dep, 5);
2059 outb_reg3(dep, 1, cr);
2061 outb_reg0(dep, DP_CR, CR_PS_P0);
2063 printf("rtl_init: config 2 = %x\n", config2);
2064 printf("rtl_init: config 3 = %x\n", config3);
2067 for (i= 0; i<64; i++)
2068 printf("%x ", get_ee_word(dep, i));
2069 printf("\n");
2071 if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
2073 ee_wen(dep);
2075 set_ee_word(dep, 0x78/2, 0x10ec);
2076 set_ee_word(dep, 0x7A/2, 0x8029);
2077 set_ee_word(dep, 0x7C/2, 0x10ec);
2078 set_ee_word(dep, 0x7E/2, 0x8029);
2080 ee_wds(dep);
2082 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
2083 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
2084 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
2085 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
2088 if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
2090 ee_wen(dep);
2092 set_ee_word(dep, 0x76/2, 0x8029);
2094 ee_wds(dep);
2096 assert(get_ee_word(dep, 0x76/2) == 0x8029);
2100 static u16_t get_ee_word(dep, a)
2101 dpeth_t *dep;
2102 int a;
2104 int b, i, cmd;
2105 u16_t w;
2107 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2109 /* Switch to 9346 mode and enable CS */
2110 outb_reg3(dep, 1, 0x80 | 0x8);
2112 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
2113 for (i= 8; i >= 0; i--)
2115 b= (cmd & (1 << i));
2116 b= (b ? 2 : 0);
2118 /* Cmd goes out on the rising edge of the clock */
2119 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2120 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2122 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2124 w= 0;
2125 for (i= 0; i<16; i++)
2127 w <<= 1;
2129 /* Data is shifted out on the rising edge. Read at the
2130 * falling edge.
2132 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
2133 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2134 b= inb_reg3(dep, 1);
2135 w |= (b & 1);
2138 outb_reg3(dep, 1, 0x80); /* drop CS */
2139 outb_reg3(dep, 1, 0x00); /* back to normal */
2140 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2142 return w;
2145 static void ee_wen(dep)
2146 dpeth_t *dep;
2148 int b, i, cmd;
2149 u16_t w;
2151 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2153 /* Switch to 9346 mode and enable CS */
2154 outb_reg3(dep, 1, 0x80 | 0x8);
2156 cmd= 0x130; /* 1 0 0 1 1 x x x x */
2157 for (i= 8; i >= 0; i--)
2159 b= (cmd & (1 << i));
2160 b= (b ? 2 : 0);
2162 /* Cmd goes out on the rising edge of the clock */
2163 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2164 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2166 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2167 outb_reg3(dep, 1, 0x80); /* Drop CS */
2168 /* micro_delay(1); */ /* Is this required? */
2171 static void set_ee_word(dpeth_t *dep, int a, u16_t w)
2172 dpeth_t *dep;
2173 int a;
2174 u16_t w;
2176 int b, i, cmd;
2178 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2180 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
2181 for (i= 8; i >= 0; i--)
2183 b= (cmd & (1 << i));
2184 b= (b ? 2 : 0);
2186 /* Cmd goes out on the rising edge of the clock */
2187 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2188 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2190 for (i= 15; i >= 0; i--)
2192 b= (w & (1 << i));
2193 b= (b ? 2 : 0);
2195 /* Cmd goes out on the rising edge of the clock */
2196 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2197 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2199 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
2200 outb_reg3(dep, 1, 0x80); /* Drop CS */
2201 /* micro_delay(1); */ /* Is this required? */
2202 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2203 SPIN_UNTIL(inb_reg3(dep, 1) & 1, 10000);
2204 if (!(inb_reg3(dep, 1) & 1))
2205 panic("device remains busy");
2208 static void ee_wds(dep)
2209 dpeth_t *dep;
2211 int b, i, cmd;
2212 u16_t w;
2214 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2216 /* Switch to 9346 mode and enable CS */
2217 outb_reg3(dep, 1, 0x80 | 0x8);
2219 cmd= 0x100; /* 1 0 0 0 0 x x x x */
2220 for (i= 8; i >= 0; i--)
2222 b= (cmd & (1 << i));
2223 b= (b ? 2 : 0);
2225 /* Cmd goes out on the rising edge of the clock */
2226 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2227 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2229 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2230 outb_reg3(dep, 1, 0x80); /* Drop CS */
2231 outb_reg3(dep, 1, 0x00); /* back to normal */
2232 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2234 #endif
2236 static void tell_dev(buf, size, pci_bus, pci_dev, pci_func)
2237 vir_bytes buf;
2238 size_t size;
2239 int pci_bus;
2240 int pci_dev;
2241 int pci_func;
2243 int r;
2244 endpoint_t dev_e;
2245 message m;
2247 r= ds_retrieve_label_endpt("amddev", &dev_e);
2248 if (r != OK)
2250 #if 0
2251 printf(
2252 "rtl8139`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
2254 #endif
2255 return;
2258 m.m_type= IOMMU_MAP;
2259 m.m2_i1= pci_bus;
2260 m.m2_i2= pci_dev;
2261 m.m2_i3= pci_func;
2262 m.m2_l1= buf;
2263 m.m2_l2= size;
2265 r= sendrec(dev_e, &m);
2266 if (r != OK)
2268 printf("rtl8139`tell_dev: sendrec to %d failed: %d\n",
2269 dev_e, r);
2270 return;
2272 if (m.m_type != OK)
2274 printf("rtl8139`tell_dev: dma map request failed: %d\n",
2275 m.m_type);
2276 return;
2281 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $