4 * This file contains a ethernet device driver for Realtek rtl8139 based
7 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
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 */
21 static int re_instance
;
23 static unsigned my_inb(u16_t port
) {
26 if ((s
=sys_inb(port
, &value
)) !=OK
)
27 printf("RTL8139: warning, sys_inb failed: %d\n", s
);
30 static unsigned my_inw(u16_t port
) {
33 if ((s
=sys_inw(port
, &value
)) !=OK
)
34 printf("RTL8139: warning, sys_inw failed: %d\n", s
);
37 static unsigned my_inl(u16_t port
) {
40 if ((s
=sys_inl(port
, &value
)) !=OK
)
41 printf("RTL8139: warning, sys_inl failed: %d\n", s
);
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
) {
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
) {
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
) {
60 if ((s
=sys_outl(port
, value
)) !=OK
)
61 printf("RTL8139: warning, sys_outl failed: %d\n", s
);
63 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
64 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
65 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
67 static int rl_init(unsigned int instance
, ether_addr_t
*addr
);
68 static int rl_probe(re_t
*rep
, unsigned int skip
);
69 static void rl_init_buf(re_t
*rep
);
70 static void rl_init_hw(re_t
*rep
, ether_addr_t
*addr
);
71 static void rl_reset_hw(re_t
*rep
);
72 static void rl_confaddr(re_t
*rep
, ether_addr_t
*addr
);
73 static void rl_stop(void);
74 static void rl_rec_mode(re_t
*rep
);
75 static void rl_mode(unsigned int mode
);
76 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
);
77 static int rl_send(struct netdriver_data
*data
, size_t size
);
78 static void rl_intr(unsigned int mask
);
79 static void rl_check_ints(re_t
*rep
);
80 static void rl_report_link(re_t
*rep
);
82 static void mii_print_techab(u16_t techab
);
83 static void mii_print_stat_speed(u16_t stat
, u16_t extstat
);
85 static void rl_clear_rx(re_t
*rep
);
86 static void rl_do_reset(re_t
*rep
);
87 static void rl_stat(eth_stat_t
*stat
);
88 static void rl_other(const message
*m_ptr
, int ipc_status
);
89 static void rl_dump(void);
91 static void dump_phy(re_t
*rep
);
93 static int rl_handler(re_t
*rep
);
94 static void rl_alarm(clock_t stamp
);
95 static void tell_iommu(vir_bytes start
, size_t size
, int pci_bus
, int
96 pci_dev
, int pci_func
);
98 static const struct netdriver rl_table
= {
106 .ndr_alarm
= rl_alarm
,
107 .ndr_other
= rl_other
,
110 /*===========================================================================*
112 *===========================================================================*/
113 int main(int argc
, char *argv
[])
116 env_setargs(argc
, argv
);
118 netdriver_task(&rl_table
);
123 /*===========================================================================*
125 *===========================================================================*/
126 static void rl_intr(unsigned int __unused mask
)
133 /* Run interrupt handler at driver level. */
136 /* Reenable interrupts for this hook. */
137 if ((s
= sys_irqenable(&rep
->re_hook_id
)) != OK
)
138 printf("RTL8139: error, couldn't enable interrupts: %d\n", s
);
140 /* Perform tasks based on the flagged conditions. */
144 /*===========================================================================*
146 *===========================================================================*/
147 static void rl_other(const message
*m_ptr
, int ipc_status
)
149 if (is_ipc_notify(ipc_status
) && m_ptr
->m_source
== TTY_PROC_NR
)
153 /*===========================================================================*
155 *===========================================================================*/
156 static void rl_stop(void)
162 rl_outb(rep
->re_base_port
, RL_CR
, 0);
165 /*===========================================================================*
167 *===========================================================================*/
168 static void rl_dump(void)
175 printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance
);
177 printf("recvErr :%8ld\t", rep
->re_stat
.ets_recvErr
);
178 printf("sendErr :%8ld\t", rep
->re_stat
.ets_sendErr
);
179 printf("OVW :%8ld\n", rep
->re_stat
.ets_OVW
);
181 printf("CRCerr :%8ld\t", rep
->re_stat
.ets_CRCerr
);
182 printf("frameAll :%8ld\t", rep
->re_stat
.ets_frameAll
);
183 printf("missedP :%8ld\n", rep
->re_stat
.ets_missedP
);
185 printf("packetR :%8ld\t", rep
->re_stat
.ets_packetR
);
186 printf("packetT :%8ld\t", rep
->re_stat
.ets_packetT
);
187 printf("transDef :%8ld\n", rep
->re_stat
.ets_transDef
);
189 printf("collision :%8ld\t", rep
->re_stat
.ets_collision
);
190 printf("transAb :%8ld\t", rep
->re_stat
.ets_transAb
);
191 printf("carrSense :%8ld\n", rep
->re_stat
.ets_carrSense
);
193 printf("fifoUnder :%8ld\t", rep
->re_stat
.ets_fifoUnder
);
194 printf("fifoOver :%8ld\t", rep
->re_stat
.ets_fifoOver
);
195 printf("CDheartbeat:%8ld\n", rep
->re_stat
.ets_CDheartbeat
);
197 printf("OWC :%8ld\t", rep
->re_stat
.ets_OWC
);
199 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
200 rl_inw(rep
->re_base_port
, RL_TSAD
),
201 rl_inl(rep
->re_base_port
, RL_TSD0
+0*4),
202 rl_inl(rep
->re_base_port
, RL_TSD0
+1*4),
203 rl_inl(rep
->re_base_port
, RL_TSD0
+2*4),
204 rl_inl(rep
->re_base_port
, RL_TSD0
+3*4));
205 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
206 rep
->re_tx_head
, rep
->re_tx_tail
,
207 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
208 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
211 /*===========================================================================*
213 *===========================================================================*/
214 static void rl_mode(unsigned int mode
)
225 /*===========================================================================*
227 *===========================================================================*/
228 static int rl_init(unsigned int instance
, ether_addr_t
*addr
)
230 /* Initialize the rtl8139 driver. */
233 int r
, fkeys
, sfkeys
;
236 /* Initialize driver state. */
238 memset(rep
, 0, sizeof(*rep
));
240 rep
->re_link_up
= -1; /* Unknown */
241 rep
->re_ertxth
= RL_TSD_ERTXTH_8
;
242 strlcpy(rep
->re_name
, "rtl8139#0", sizeof(rep
->re_name
));
243 rep
->re_name
[8] += instance
;
245 re_instance
= instance
;
247 /* Try to find a matching device. */
248 if (!rl_probe(rep
, instance
))
251 /* Claim buffer memory. */
254 /* Initialize the device we found. */
255 rl_init_hw(rep
, addr
);
258 /* Report initial link status. */
262 /* Use a synchronous alarm instead of a watchdog timer. */
263 sys_setalarm(sys_hz(), 0);
266 /* Observe some function key for debug dumps. */
267 fkeys
= sfkeys
= 0; bit_set(sfkeys
, 9);
268 if ((r
= fkey_map(&fkeys
, &sfkeys
)) != OK
)
269 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r
);
275 /*===========================================================================*
277 *===========================================================================*/
278 static int rl_probe(re_t
*rep
, unsigned int skip
)
290 r
= pci_first_dev(&devind
, &vid
, &did
);
296 r
= pci_next_dev(&devind
, &vid
, &did
);
301 #if VERBOSE /* stay silent at startup, can always get status later */
302 dname
= pci_dev_name(vid
, did
);
304 dname
= "unknown device";
305 printf("%s: ", rep
->re_name
);
306 printf("%s (%x/%x) at %s\n", dname
, vid
, did
, pci_slot_name(devind
));
310 /* Enable bus mastering if necessary. */
311 cr
= pci_attr_r16(devind
, PCI_CR
);
312 /* printf("cr = 0x%x\n", cr); */
313 if (!(cr
& PCI_CR_MAST_EN
))
314 pci_attr_w16(devind
, PCI_CR
, cr
| PCI_CR_MAST_EN
);
316 bar
= pci_attr_r32(devind
, PCI_BAR
) & 0xffffffe0;
318 panic("base address is not properly configured");
320 rep
->re_base_port
= bar
;
322 ilr
= pci_attr_r8(devind
, PCI_ILR
);
325 printf("%s: using I/O address 0x%lx, IRQ %d\n",
326 rep
->re_name
, (unsigned long)bar
, ilr
);
332 /*===========================================================================*
334 *===========================================================================*/
335 static void rl_init_buf(re_t
*rep
)
337 size_t rx_bufsize
, tx_bufsize
, tot_bufsize
;
342 /* Allocate receive and transmit buffers */
343 tx_bufsize
= ETH_MAX_PACK_SIZE_TAGGED
;
345 tx_bufsize
+= 4-(tx_bufsize
% 4); /* Align */
346 rx_bufsize
= RX_BUFSIZE
;
347 tot_bufsize
= N_TX_BUF
*tx_bufsize
+ rx_bufsize
;
349 if (tot_bufsize
% 4096)
350 tot_bufsize
+= 4096-(tot_bufsize
% 4096);
352 #define BUF_ALIGNMENT (64*1024)
354 if (!(mallocbuf
= alloc_contig(BUF_ALIGNMENT
+ tot_bufsize
, 0, &buf
)))
355 panic("Couldn't allocate kernel buffer");
357 /* click-align mallocced buffer. this is what we used to get
358 * from kmalloc() too.
360 if((off
= buf
% BUF_ALIGNMENT
)) {
361 mallocbuf
+= BUF_ALIGNMENT
- off
;
362 buf
+= BUF_ALIGNMENT
- off
;
365 tell_iommu((vir_bytes
)mallocbuf
, tot_bufsize
, 0, 0, 0);
367 for (i
= 0; i
<N_TX_BUF
; i
++)
369 rep
->re_tx
[i
].ret_buf
= buf
;
370 rep
->re_tx
[i
].v_ret_buf
= mallocbuf
;
372 mallocbuf
+= tx_bufsize
;
375 rep
->v_re_rx_buf
= mallocbuf
;
378 /*===========================================================================*
380 *===========================================================================*/
381 static void rl_init_hw(re_t
*rep
, ether_addr_t
*addr
)
388 /* Set the interrupt handler. The policy is to only send HARD_INT
389 * notifications. Don't reenable interrupts automatically. The id
390 * that is passed back is the interrupt line number.
392 rep
->re_hook_id
= rep
->re_irq
;
393 if ((s
=sys_irqsetpolicy(rep
->re_irq
, 0, &rep
->re_hook_id
)) != OK
)
394 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s
);
398 if ((s
=sys_irqenable(&rep
->re_hook_id
)) != OK
)
399 printf("RTL8139: error, couldn't enable interrupts: %d\n", s
);
401 #if VERBOSE /* stay silent during startup, can always get status later */
403 printf("%s: model %s\n", rep
->re_name
, rep
->re_model
);
406 printf("%s: unknown model 0x%08x\n",
408 rl_inl(rep
->re_base_port
, RL_TCR
) &
409 (RL_TCR_HWVER_AM
| RL_TCR_HWVER_BM
));
413 rl_confaddr(rep
, addr
);
416 printf("%s: Ethernet address ", rep
->re_name
);
417 for (i
= 0; i
< 6; i
++)
418 printf("%x%c", addr
->ea_addr
[i
], i
< 5 ? ':' : '\n');
422 /*===========================================================================*
424 *===========================================================================*/
425 static void rl_reset_hw(re_t
*rep
)
432 port
= rep
->re_base_port
;
436 rl_outb(port
, RL_BMCR
, MII_CTRL_RST
);
437 SPIN_UNTIL(!(rl_inb(port
, RL_BMCR
) & MII_CTRL_RST
), 1000000);
438 if (rl_inb(port
, RL_BMCR
) & MII_CTRL_RST
)
439 panic("reset PHY failed to complete");
442 /* Reset the device */
444 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
445 port
, rl_inb(port
, RL_CR
));
447 rl_outb(port
, RL_CR
, RL_CR_RST
);
448 SPIN_UNTIL(!(rl_inb(port
, RL_CR
) & RL_CR_RST
), 1000000);
450 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
451 port
, rl_inb(port
, RL_CR
));
453 if (rl_inb(port
, RL_CR
) & RL_CR_RST
)
454 printf("rtl8139: reset failed to complete");
456 t
= rl_inl(port
, RL_TCR
);
457 switch(t
& (RL_TCR_HWVER_AM
| RL_TCR_HWVER_BM
))
459 case RL_TCR_HWVER_RTL8139
: rep
->re_model
= "RTL8139"; break;
460 case RL_TCR_HWVER_RTL8139A
: rep
->re_model
= "RTL8139A"; break;
461 case RL_TCR_HWVER_RTL8139AG
:
462 rep
->re_model
= "RTL8139A-G / RTL8139C";
464 case RL_TCR_HWVER_RTL8139B
:
465 rep
->re_model
= "RTL8139B / RTL8130";
467 case RL_TCR_HWVER_RTL8100
: rep
->re_model
= "RTL8100"; break;
468 case RL_TCR_HWVER_RTL8100B
:
469 rep
->re_model
= "RTL8100B/RTL8139D";
471 case RL_TCR_HWVER_RTL8139CP
: rep
->re_model
= "RTL8139C+"; break;
472 case RL_TCR_HWVER_RTL8101
: rep
->re_model
= "RTL8101"; break;
479 printf("REVID: 0x%02x\n", rl_inb(port
, RL_REVID
));
484 /* Should init multicast mask */
486 08-0f R
/W MAR
[0-7] multicast
488 bus_buf
= vm_1phys2bus(rep
->re_rx_buf
);
489 rl_outl(port
, RL_RBSTART
, bus_buf
);
492 for (i
= 0; i
<N_TX_BUF
; i
++)
494 rep
->re_tx
[i
].ret_busy
= FALSE
;
495 bus_buf
= vm_1phys2bus(rep
->re_tx
[i
].ret_buf
);
496 rl_outl(port
, RL_TSAD0
+i
*4, bus_buf
);
497 t
= rl_inl(port
, RL_TSD0
+i
*4);
498 assert(t
& RL_TSD_OWN
);
507 t
= rl_inw(port
, RL_IMR
);
508 rl_outw(port
, RL_IMR
, t
| (RL_IMR_SERR
| RL_IMR_TIMEOUT
|
511 t
= rl_inw(port
, RL_IMR
);
512 rl_outw(port
, RL_IMR
, t
| (RL_IMR_FOVW
| RL_IMR_PUN
|
513 RL_IMR_RXOVW
| RL_IMR_RER
| RL_IMR_ROK
));
515 t
= rl_inw(port
, RL_IMR
);
516 rl_outw(port
, RL_IMR
, t
| (RL_IMR_TER
| RL_IMR_TOK
));
518 t
= rl_inb(port
, RL_CR
);
519 rl_outb(port
, RL_CR
, t
| RL_CR_RE
);
521 t
= rl_inb(port
, RL_CR
);
522 rl_outb(port
, RL_CR
, t
| RL_CR_TE
);
524 rl_outl(port
, RL_RCR
, RX_BUFBITS
);
526 t
= rl_inl(port
, RL_TCR
);
527 rl_outl(port
, RL_TCR
, t
| RL_TCR_IFG_STD
);
530 /*===========================================================================*
532 *===========================================================================*/
533 static void rl_confaddr(re_t
*rep
, ether_addr_t
*addr
)
535 static char eakey
[]= RL_ENVVAR
"#_EA";
536 static char eafmt
[]= "x:x:x:x:x:x";
543 /* User defined ethernet address? */
544 eakey
[sizeof(RL_ENVVAR
)-1]= '0' + re_instance
;
546 port
= rep
->re_base_port
;
548 for (i
= 0; i
< 6; i
++)
550 if (env_parse(eakey
, eafmt
, i
, &v
, 0x00L
, 0xFFL
) != EP_SET
)
555 if (i
!= 0 && i
!= 6) env_panic(eakey
); /* It's all or nothing */
557 /* Should update ethernet address in hardware */
560 port
= rep
->re_base_port
;
561 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_CONFIG
);
564 w
|= (addr
->ea_addr
[i
] << (i
*8));
565 rl_outl(port
, RL_IDR
, w
);
568 w
|= (addr
->ea_addr
[i
] << ((i
-4)*8));
569 rl_outl(port
, RL_IDR
+4, w
);
570 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_NORMAL
);
573 /* Get ethernet address */
575 addr
->ea_addr
[i
]= rl_inb(port
, RL_IDR
+i
);
578 /*===========================================================================*
580 *===========================================================================*/
581 static void rl_rec_mode(re_t
*rep
)
586 port
= rep
->re_base_port
;
587 rcr
= rl_inl(port
, RL_RCR
);
588 rcr
&= ~(RL_RCR_AB
|RL_RCR_AM
|RL_RCR_APM
|RL_RCR_AAP
);
589 if (rep
->re_mode
& NDEV_PROMISC
)
590 rcr
|= RL_RCR_AB
| RL_RCR_AM
| RL_RCR_AAP
;
591 if (rep
->re_mode
& NDEV_BROAD
)
593 if (rep
->re_mode
& NDEV_MULTI
)
597 rl_outl(port
, RL_RCR
, rcr
);
600 /*===========================================================================*
602 *===========================================================================*/
603 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
)
607 unsigned amount
, totlen
, packlen
;
608 u16_t d_start
, d_end
;
614 if (rep
->re_clear_rx
)
615 return SUSPEND
; /* Buffer overflow */
617 port
= rep
->re_base_port
;
619 if (rl_inb(port
, RL_CR
) & RL_CR_BUFE
)
621 /* Receive buffer is empty, suspend */
625 d_start
= rl_inw(port
, RL_CAPR
) + RL_CAPR_DATA_OFF
;
626 d_end
= rl_inw(port
, RL_CBR
) % RX_BUFSIZE
;
628 #if RX_BUFSIZE <= USHRT_MAX
629 if (d_start
>= RX_BUFSIZE
)
631 printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
632 rl_inw(port
, RL_CAPR
));
633 d_start
%= RX_BUFSIZE
;
638 amount
= d_end
-d_start
;
640 amount
= d_end
+RX_BUFSIZE
- d_start
;
642 rxstat
= *(u32_t
*) (rep
->v_re_rx_buf
+ d_start
);
644 /* Should convert from little endian to host byte order */
646 if (!(rxstat
& RL_RXS_ROK
))
648 printf("rxstat = 0x%08x\n", rxstat
);
649 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
650 d_start
, d_end
, rxstat
);
651 panic("received packet not OK");
653 totlen
= (rxstat
>> RL_RXS_LEN_S
);
654 if (totlen
< 8 || totlen
> 2*ETH_MAX_PACK_SIZE
)
656 /* Someting went wrong */
658 "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
659 totlen
, rxstat
, d_start
);
661 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
662 d_start
, d_end
, totlen
, rxstat
);
667 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
668 d_start
, d_end
, totlen
, rxstat
);
671 if (totlen
+4 > amount
)
673 printf("rl_recv: packet not yet ready\n");
677 /* Should subtract the CRC */
678 packlen
= MIN(totlen
- ETH_CRC_SIZE
, max
);
680 /* Copy out the data. The packet may wrap in the receive buffer. */
681 o
= (d_start
+4) % RX_BUFSIZE
;
682 s
= MIN(RX_BUFSIZE
- o
, packlen
);
684 netdriver_copyout(data
, 0, rep
->v_re_rx_buf
+ o
, s
);
686 netdriver_copyout(data
, s
, rep
->v_re_rx_buf
, packlen
- s
);
688 rep
->re_stat
.ets_packetR
++;
690 /* Avoid overflow in 16-bit computations */
693 l
= (l
+3) & ~3; /* align */
697 assert(l
< RX_BUFSIZE
);
699 rl_outw(port
, RL_CAPR
, l
-RL_CAPR_DATA_OFF
);
704 /*===========================================================================*
706 *===========================================================================*/
707 static int rl_send(struct netdriver_data
*data
, size_t size
)
714 tx_head
= rep
->re_tx_head
;
715 if (rep
->re_tx
[tx_head
].ret_busy
)
718 netdriver_copyin(data
, 0, rep
->re_tx
[tx_head
].v_ret_buf
, size
);
720 rl_outl(rep
->re_base_port
, RL_TSD0
+tx_head
*4, rep
->re_ertxth
| size
);
721 rep
->re_tx
[tx_head
].ret_busy
= TRUE
;
724 if (++tx_head
== N_TX_BUF
)
726 assert(tx_head
< RL_N_TX
);
727 rep
->re_tx_head
= tx_head
;
732 /*===========================================================================*
734 *===========================================================================*/
735 static void rl_check_ints(re_t
*rep
)
738 10-1f R
/W TSD
[0-3] Transmit Status of Descriptor
[0-3]
739 31 R CRS Carrier Sense Lost
740 30 R TABT Transmit Abort
741 29 R OWC Out of Window Collision
742 27-24 R NCC
[3-0] Number of Collision Count
744 21-16 R
/W ERTXH
[5-0] Early Tx Threshold
746 14 R TUN Transmit FIFO Underrun
748 12-0 R
/W SIZE Descriptor Size
749 3e-3f R
/W ISR Interrupt Status Register
750 6 R
/W FOVW Fx FIFO Overflow Interrupt
751 5 R
/W PUN
/LinkChg Packet Underrun
/ Link Change Interrupt
752 3 R
/W TER Transmit Error Interrupt
753 2 R
/W TOK Transmit OK Interrupt
754 3e-3f R
/W ISR Interrupt Status Register
755 15 R
/W SERR System Error Interrupt
756 14 R
/W TimeOut Time Out Interrupt
757 13 R
/W LenChg Cable Length Change Interrupt
758 3e-3f R
/W ISR Interrupt Status Register
759 4 R
/W RXOVW Rx Buffer Overflow Interrupt
760 1 R
/W RER Receive Error Interrupt
761 0 R
/W ROK Receive OK Interrupt
762 4c
-4f R
/W MPC Missed Packet Counter
763 60-61 R TSAD Transmit Status of All Descriptors
764 15-12 R TOK
[3-0] TOK bit of Descriptor
[3-0]
765 11-8 R TUN
[3-0] TUN bit of Descriptor
[3-0]
766 7-4 R TABT
[3-0] TABT bit of Descriptor
[3-0]
767 3-0 R OWN
[3-0] OWN bit of Descriptor
[3-0]
768 6c
-6d R DIS Disconnect Counter
769 15-0 R DCNT Disconnect Counter
770 6e-6f R FCSC False Carrier Sense Counter
771 15-0 R FCSCNT False Carrier event counter
772 72-73 R REC RX_ER Counter
773 15-0 R RXERCNT Received packet counter
776 if (!rep
->re_got_int
)
778 rep
->re_got_int
= FALSE
;
782 if (rep
->re_clear_rx
)
785 if (rep
->re_need_reset
)
788 if (rep
->re_send_int
) {
789 rep
->re_send_int
= FALSE
;
794 if (rep
->re_report_link
) {
795 rep
->re_report_link
= FALSE
;
801 /*===========================================================================*
803 *===========================================================================*/
804 static void rl_report_link(re_t
*rep
)
807 u16_t mii_ctrl
, mii_status
, mii_ana
, mii_anlpa
, mii_ane
, mii_extstat
;
811 port
= rep
->re_base_port
;
812 msr
= rl_inb(port
, RL_MSR
);
813 link_up
= !(msr
& RL_MSR_LINKB
);
814 rep
->re_link_up
= link_up
;
817 printf("%s: link down\n", rep
->re_name
);
821 mii_ctrl
= rl_inw(port
, RL_BMCR
);
822 mii_status
= rl_inw(port
, RL_BMSR
);
823 mii_ana
= rl_inw(port
, RL_ANAR
);
824 mii_anlpa
= rl_inw(port
, RL_ANLPAR
);
825 mii_ane
= rl_inw(port
, RL_ANER
);
828 if (mii_ctrl
& (MII_CTRL_LB
|MII_CTRL_PD
|MII_CTRL_ISO
))
830 printf("%s: PHY: ", rep
->re_name
);
832 if (mii_ctrl
& MII_CTRL_LB
)
834 printf("loopback mode");
837 if (mii_ctrl
& MII_CTRL_PD
)
839 if (!f
) printf(", ");
841 printf("powered down");
843 if (mii_ctrl
& MII_CTRL_ISO
)
845 if (!f
) printf(", ");
852 if (!(mii_ctrl
& MII_CTRL_ANE
))
854 printf("%s: manual config: ", rep
->re_name
);
855 switch(mii_ctrl
& (MII_CTRL_SP_LSB
|MII_CTRL_SP_MSB
))
857 case MII_CTRL_SP_10
: printf("10 Mbps"); break;
858 case MII_CTRL_SP_100
: printf("100 Mbps"); break;
859 case MII_CTRL_SP_1000
: printf("1000 Mbps"); break;
860 case MII_CTRL_SP_RES
: printf("reserved speed"); break;
862 if (mii_ctrl
& MII_CTRL_DM
)
863 printf(", full duplex");
865 printf(", half duplex");
871 printf("%s: ", rep
->re_name
);
872 mii_print_stat_speed(mii_status
, mii_extstat
);
875 if (!(mii_status
& MII_STATUS_ANC
))
876 printf("%s: auto-negotiation not complete\n", rep
->re_name
);
877 if (mii_status
& MII_STATUS_RF
)
878 printf("%s: remote fault detected\n", rep
->re_name
);
879 if (!(mii_status
& MII_STATUS_ANA
))
881 printf("%s: local PHY has no auto-negotiation ability\n",
884 if (!(mii_status
& MII_STATUS_LS
))
885 printf("%s: link down\n", rep
->re_name
);
886 if (mii_status
& MII_STATUS_JD
)
887 printf("%s: jabber condition detected\n", rep
->re_name
);
888 if (!(mii_status
& MII_STATUS_EC
))
890 printf("%s: no extended register set\n", rep
->re_name
);
893 if (!(mii_status
& MII_STATUS_ANC
))
896 printf("%s: local cap.: ", rep
->re_name
);
897 mii_print_techab(mii_ana
);
900 if (mii_ane
& MII_ANE_PDF
)
901 printf("%s: parallel detection fault\n", rep
->re_name
);
902 if (!(mii_ane
& MII_ANE_LPANA
))
904 printf("%s: link-partner does not support auto-negotiation\n",
909 printf("%s: remote cap.: ", rep
->re_name
);
910 mii_print_techab(mii_anlpa
);
915 printf("%s: ", rep
->re_name
);
916 printf("link up at %d Mbps, ", (msr
& RL_MSR_SPEED_10
) ? 10 : 100);
917 printf("%s duplex\n", ((mii_ctrl
& MII_CTRL_DM
) ? "full" : "half"));
922 static void mii_print_techab(u16_t techab
)
925 if ((techab
& MII_ANA_SEL_M
) != MII_ANA_SEL_802_3
)
927 printf("strange selector 0x%x, value 0x%x",
928 techab
& MII_ANA_SEL_M
,
929 (techab
& MII_ANA_TAF_M
) >> MII_ANA_TAF_S
);
933 if (techab
& (MII_ANA_100T4
| MII_ANA_100TXFD
| MII_ANA_100TXHD
))
935 printf("100 Mbps: ");
938 if (techab
& MII_ANA_100T4
)
943 if (techab
& (MII_ANA_100TXFD
| MII_ANA_100TXHD
))
949 switch(techab
& (MII_ANA_100TXFD
|MII_ANA_100TXHD
))
951 case MII_ANA_100TXFD
: printf("FD"); break;
952 case MII_ANA_100TXHD
: printf("HD"); break;
953 default: printf("FD/HD"); break;
957 if (techab
& (MII_ANA_10TFD
| MII_ANA_10THD
))
964 switch(techab
& (MII_ANA_10TFD
|MII_ANA_10THD
))
966 case MII_ANA_10TFD
: printf("FD"); break;
967 case MII_ANA_10THD
: printf("HD"); break;
968 default: printf("FD/HD"); break;
971 if (techab
& MII_ANA_PAUSE_SYM
)
976 printf("pause(SYM)");
978 if (techab
& MII_ANA_PAUSE_ASYM
)
983 printf("pause(ASYM)");
985 if (techab
& MII_ANA_TAF_RES
)
990 printf("0x%x", (techab
& MII_ANA_TAF_RES
) >> MII_ANA_TAF_S
);
994 static void mii_print_stat_speed(u16_t stat
, u16_t extstat
)
998 if (stat
& MII_STATUS_EXT_STAT
)
1000 if (extstat
& (MII_ESTAT_1000XFD
| MII_ESTAT_1000XHD
|
1001 MII_ESTAT_1000TFD
| MII_ESTAT_1000THD
))
1003 printf("1000 Mbps: ");
1006 if (extstat
& (MII_ESTAT_1000XFD
| MII_ESTAT_1000XHD
))
1011 (MII_ESTAT_1000XFD
|MII_ESTAT_1000XHD
))
1013 case MII_ESTAT_1000XFD
: printf("FD"); break;
1014 case MII_ESTAT_1000XHD
: printf("HD"); break;
1015 default: printf("FD/HD"); break;
1018 if (extstat
& (MII_ESTAT_1000TFD
| MII_ESTAT_1000THD
))
1025 (MII_ESTAT_1000TFD
|MII_ESTAT_1000THD
))
1027 case MII_ESTAT_1000TFD
: printf("FD"); break;
1028 case MII_ESTAT_1000THD
: printf("HD"); break;
1029 default: printf("FD/HD"); break;
1034 if (stat
& (MII_STATUS_100T4
|
1035 MII_STATUS_100XFD
| MII_STATUS_100XHD
|
1036 MII_STATUS_100T2FD
| MII_STATUS_100T2HD
))
1041 printf("100 Mbps: ");
1043 if (stat
& MII_STATUS_100T4
)
1048 if (stat
& (MII_STATUS_100XFD
| MII_STATUS_100XHD
))
1054 switch(stat
& (MII_STATUS_100XFD
|MII_STATUS_100XHD
))
1056 case MII_STATUS_100XFD
: printf("FD"); break;
1057 case MII_STATUS_100XHD
: printf("HD"); break;
1058 default: printf("FD/HD"); break;
1061 if (stat
& (MII_STATUS_100T2FD
| MII_STATUS_100T2HD
))
1067 switch(stat
& (MII_STATUS_100T2FD
|MII_STATUS_100T2HD
))
1069 case MII_STATUS_100T2FD
: printf("FD"); break;
1070 case MII_STATUS_100T2HD
: printf("HD"); break;
1071 default: printf("FD/HD"); break;
1075 if (stat
& (MII_STATUS_10FD
| MII_STATUS_10HD
))
1079 printf("10 Mbps: ");
1082 switch(stat
& (MII_STATUS_10FD
|MII_STATUS_10HD
))
1084 case MII_STATUS_10FD
: printf("FD"); break;
1085 case MII_STATUS_10HD
: printf("HD"); break;
1086 default: printf("FD/HD"); break;
1090 #endif /* VERBOSE */
1092 /*===========================================================================*
1094 *===========================================================================*/
1095 static void rl_clear_rx(re_t
*rep
)
1100 rep
->re_clear_rx
= FALSE
;
1101 port
= rep
->re_base_port
;
1103 /* Reset the receiver */
1104 cr
= rl_inb(port
, RL_CR
);
1106 rl_outb(port
, RL_CR
, cr
);
1107 SPIN_UNTIL(!(rl_inb(port
, RL_CR
) & RL_CR_RE
), 1000000);
1108 if (rl_inb(port
, RL_CR
) & RL_CR_RE
)
1109 panic("cannot disable receiver");
1112 printf("RBSTART = 0x%08x\n", rl_inl(port
, RL_RBSTART
));
1113 printf("CAPR = 0x%04x\n", rl_inw(port
, RL_CAPR
));
1114 printf("CBR = 0x%04x\n", rl_inw(port
, RL_CBR
));
1115 printf("RCR = 0x%08x\n", rl_inl(port
, RL_RCR
));
1118 rl_outb(port
, RL_CR
, cr
| RL_CR_RE
);
1120 rl_outl(port
, RL_RCR
, RX_BUFBITS
);
1124 rep
->re_stat
.ets_missedP
++;
1127 /*===========================================================================*
1129 *===========================================================================*/
1130 static void rl_do_reset(re_t
*rep
)
1132 rep
->re_need_reset
= FALSE
;
1137 if (rep
->re_tx
[rep
->re_tx_head
].ret_busy
)
1139 rep
->re_tx
[rep
->re_tx_head
].ret_busy
= FALSE
;
1140 rep
->re_send_int
= TRUE
;
1143 /*===========================================================================*
1145 *===========================================================================*/
1146 static void rl_stat(eth_stat_t
*stat
)
1148 memcpy(stat
, &re_state
.re_stat
, sizeof(*stat
));
1152 /*===========================================================================*
1154 *===========================================================================*/
1155 static void dump_phy(re_t
*rep
)
1160 port
= rep
->re_base_port
;
1162 t
= rl_inb(port
, RL_MSR
);
1163 printf("MSR: 0x%02lx\n", t
);
1164 if (t
& RL_MSR_SPEED_10
)
1165 printf("\t10 Mbps\n");
1166 if (t
& RL_MSR_LINKB
)
1167 printf("\tLink failed\n");
1169 t
= rl_inb(port
, RL_CONFIG1
);
1170 printf("CONFIG1: 0x%02lx\n", t
);
1172 t
= rl_inb(port
, RL_CONFIG3
);
1173 printf("CONFIG3: 0x%02lx\n", t
);
1175 t
= rl_inb(port
, RL_CONFIG4
);
1176 printf("CONFIG4: 0x%02lx\n", t
);
1178 t
= rl_inw(port
, RL_BMCR
);
1179 printf("BMCR (MII_CTRL): 0x%04lx\n", t
);
1181 t
= rl_inw(port
, RL_BMSR
);
1183 if (t
& MII_STATUS_100T4
)
1184 printf(" 100Base-T4");
1185 if (t
& MII_STATUS_100XFD
)
1186 printf(" 100Base-X-FD");
1187 if (t
& MII_STATUS_100XHD
)
1188 printf(" 100Base-X-HD");
1189 if (t
& MII_STATUS_10FD
)
1190 printf(" 10Mbps-FD");
1191 if (t
& MII_STATUS_10HD
)
1192 printf(" 10Mbps-HD");
1193 if (t
& MII_STATUS_100T2FD
)
1194 printf(" 100Base-T2-FD");
1195 if (t
& MII_STATUS_100T2HD
)
1196 printf(" 100Base-T2-HD");
1197 if (t
& MII_STATUS_EXT_STAT
)
1198 printf(" Ext-stat");
1199 if (t
& MII_STATUS_RES
)
1200 printf(" res-0x%lx", t
& MII_STATUS_RES
);
1201 if (t
& MII_STATUS_MFPS
)
1203 if (t
& MII_STATUS_ANC
)
1205 if (t
& MII_STATUS_RF
)
1206 printf(" remote-fault");
1207 if (t
& MII_STATUS_ANA
)
1209 if (t
& MII_STATUS_LS
)
1211 if (t
& MII_STATUS_JD
)
1213 if (t
& MII_STATUS_EC
)
1214 printf(" Extended-capability");
1217 t
= rl_inw(port
, RL_ANAR
);
1218 printf("ANAR (MII_ANA): 0x%04lx\n", t
);
1220 t
= rl_inw(port
, RL_ANLPAR
);
1221 printf("ANLPAR: 0x%04lx\n", t
);
1223 t
= rl_inw(port
, RL_ANER
);
1224 printf("ANER (MII_ANE): ");
1225 if (t
& MII_ANE_RES
)
1226 printf(" res-0x%lx", t
& MII_ANE_RES
);
1227 if (t
& MII_ANE_PDF
)
1228 printf(" Par-Detect-Fault");
1229 if (t
& MII_ANE_LPNPA
)
1230 printf(" LP-Next-Page-Able");
1231 if (t
& MII_ANE_NPA
)
1232 printf(" Loc-Next-Page-Able");
1234 printf(" Page-Received");
1235 if (t
& MII_ANE_LPANA
)
1236 printf(" LP-Auto-Neg-Able");
1239 t
= rl_inw(port
, RL_NWAYTR
);
1240 printf("NWAYTR: 0x%04lx\n", t
);
1241 t
= rl_inw(port
, RL_CSCR
);
1242 printf("CSCR: 0x%04lx\n", t
);
1244 t
= rl_inb(port
, RL_CONFIG5
);
1245 printf("CONFIG5: 0x%02lx\n", t
);
1249 /*===========================================================================*
1251 *===========================================================================*/
1252 static int rl_handler(re_t
*rep
)
1254 int i
, port
, tx_head
, tx_tail
, link_up
;
1256 u32_t tsd
, tcr
, ertxth
;
1258 port
= rep
->re_base_port
;
1261 isr
= rl_inw(port
, RL_ISR
);
1262 rl_outw(port
, RL_ISR
, isr
);
1264 if (isr
& RL_IMR_FOVW
)
1266 isr
&= ~RL_IMR_FOVW
;
1267 /* Should do anything? */
1269 rep
->re_stat
.ets_fifoOver
++;
1271 if (isr
& RL_IMR_PUN
)
1275 /* Either the link status changed or there was a TX fifo
1278 link_up
= !(rl_inb(port
, RL_MSR
) & RL_MSR_LINKB
);
1279 if (link_up
!= rep
->re_link_up
)
1281 rep
->re_report_link
= TRUE
;
1282 rep
->re_got_int
= TRUE
;
1285 if (isr
& RL_IMR_RXOVW
)
1287 isr
&= ~RL_IMR_RXOVW
;
1289 /* Clear the receive buffer */
1290 rep
->re_clear_rx
= TRUE
;
1291 rep
->re_got_int
= TRUE
;
1294 if (isr
& (RL_ISR_RER
| RL_ISR_ROK
))
1296 isr
&= ~(RL_ISR_RER
| RL_ISR_ROK
);
1298 rep
->re_got_int
= TRUE
;
1300 if ((isr
& (RL_ISR_TER
| RL_ISR_TOK
)) || 1)
1302 isr
&= ~(RL_ISR_TER
| RL_ISR_TOK
);
1304 tsad
= rl_inw(port
, RL_TSAD
);
1305 if (tsad
& (RL_TSAD_TABT0
|RL_TSAD_TABT1
|
1306 RL_TSAD_TABT2
|RL_TSAD_TABT3
))
1308 printf("rl_handler, TABT, tasd = 0x%04x\n",
1311 /* Find the aborted transmit request */
1312 for (i
= 0; i
< N_TX_BUF
; i
++)
1314 tsd
= rl_inl(port
, RL_TSD0
+i
*4);
1315 if (tsd
& RL_TSD_TABT
)
1321 "rl_handler: can't find aborted TX req.\n");
1325 printf("TSD%d = 0x%04x\n", i
, tsd
);
1327 /* Set head and tail to this buffer */
1328 rep
->re_tx_head
= rep
->re_tx_tail
= i
;
1331 /* Aborted transmission, just kick the device
1332 * and be done with it.
1334 rep
->re_stat
.ets_transAb
++;
1335 tcr
= rl_inl(port
, RL_TCR
);
1336 rl_outl(port
, RL_TCR
, tcr
| RL_TCR_CLRABT
);
1339 /* Transmit completed */
1340 tx_head
= rep
->re_tx_head
;
1341 tx_tail
= rep
->re_tx_tail
;
1342 for (i
= 0; i
< 2*N_TX_BUF
; i
++)
1344 if (!rep
->re_tx
[tx_tail
].ret_busy
)
1346 /* Strange, this buffer is not in-use.
1347 * Increment tx_tail until tx_head is
1348 * reached (or until we find a buffer that
1351 if (tx_tail
== tx_head
)
1353 if (++tx_tail
>= N_TX_BUF
)
1355 assert(tx_tail
< RL_N_TX
);
1356 rep
->re_tx_tail
= tx_tail
;
1359 tsd
= rl_inl(port
, RL_TSD0
+tx_tail
*4);
1360 if (!(tsd
& RL_TSD_OWN
))
1362 /* Buffer is not yet ready */
1366 /* Should collect statistics */
1367 if (tsd
& RL_TSD_CRS
)
1368 rep
->re_stat
.ets_carrSense
++;
1369 if (tsd
& RL_TSD_TABT
)
1371 printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1373 assert(0); /* CLRABT is not all that
1374 * effective, why not?
1376 rep
->re_stat
.ets_transAb
++;
1377 tcr
= rl_inl(port
, RL_TCR
);
1378 rl_outl(port
, RL_TCR
, tcr
| RL_TCR_CLRABT
);
1380 if (tsd
& RL_TSD_OWC
)
1381 rep
->re_stat
.ets_OWC
++;
1382 if (tsd
& RL_TSD_CDH
)
1383 rep
->re_stat
.ets_CDheartbeat
++;
1385 /* What about collisions? */
1386 if (tsd
& RL_TSD_TOK
)
1387 rep
->re_stat
.ets_packetT
++;
1389 rep
->re_stat
.ets_sendErr
++;
1390 if (tsd
& RL_TSD_TUN
)
1392 rep
->re_stat
.ets_fifoUnder
++;
1394 /* Increase ERTXTH */
1395 ertxth
= tsd
+ (1 << RL_TSD_ERTXTH_S
);
1396 ertxth
&= RL_TSD_ERTXTH_M
;
1398 if (ertxth
> rep
->re_ertxth
)
1400 printf("%s: new ertxth: %d bytes\n",
1402 (ertxth
>> RL_TSD_ERTXTH_S
) *
1404 rep
->re_ertxth
= ertxth
;
1408 rep
->re_tx
[tx_tail
].ret_busy
= FALSE
;
1412 printf("TSD%d: %08lx\n", tx_tail
, tsd
);
1414 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1416 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
1417 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
1420 if (++tx_tail
>= N_TX_BUF
)
1422 assert(tx_tail
< RL_N_TX
);
1423 rep
->re_tx_tail
= tx_tail
;
1425 rep
->re_send_int
= TRUE
;
1426 rep
->re_got_int
= TRUE
;
1427 rep
->re_tx_alive
= TRUE
;
1429 assert(i
< 2*N_TX_BUF
);
1433 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1440 /*===========================================================================*
1442 *===========================================================================*/
1443 static void rl_alarm(clock_t __unused stamp
)
1447 /* Use a synchronous alarm instead of a watchdog timer. */
1448 sys_setalarm(sys_hz(), 0);
1452 assert(rep
->re_tx_busy
>= 0 && rep
->re_tx_busy
<= N_TX_BUF
);
1453 if (rep
->re_tx_busy
== 0)
1455 /* Assume that an idle system is alive */
1456 rep
->re_tx_alive
= TRUE
;
1459 if (rep
->re_tx_alive
)
1461 rep
->re_tx_alive
= FALSE
;
1464 printf("rl_alarm: resetting instance %d\n", re_instance
);
1465 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1466 rl_inw(rep
->re_base_port
, RL_TSAD
),
1467 rl_inl(rep
->re_base_port
, RL_TSD0
+0*4),
1468 rl_inl(rep
->re_base_port
, RL_TSD0
+1*4),
1469 rl_inl(rep
->re_base_port
, RL_TSD0
+2*4),
1470 rl_inl(rep
->re_base_port
, RL_TSD0
+3*4));
1471 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1472 rep
->re_tx_head
, rep
->re_tx_tail
,
1473 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
1474 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
1475 rep
->re_need_reset
= TRUE
;
1476 rep
->re_got_int
= TRUE
;
1481 /* TODO: obviously this needs a lot of work. */
1482 static void tell_iommu(vir_bytes buf
, size_t size
, int pci_bus
, int pci_dev
,
1489 r
= ds_retrieve_label_endpt("amddev", &dev_e
);
1493 printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
1494 "for 'amddev': %d\n", r
);
1499 m
.m_type
= IOMMU_MAP
;
1506 r
= ipc_sendrec(dev_e
, &m
);
1509 printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1515 printf("rtl8139`tell_dev: dma map request failed: %d\n",
1522 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $