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 unsigned my_inb(u16_t port
) {
24 if ((s
=sys_inb(port
, &value
)) !=OK
)
25 printf("RTL8139: warning, sys_inb failed: %d\n", s
);
28 static unsigned my_inw(u16_t port
) {
31 if ((s
=sys_inw(port
, &value
)) !=OK
)
32 printf("RTL8139: warning, sys_inw failed: %d\n", s
);
35 static unsigned my_inl(u16_t port
) {
38 if ((s
=sys_inl(port
, &value
)) !=OK
)
39 printf("RTL8139: warning, sys_inl failed: %d\n", s
);
42 #define rl_inb(port, offset) (my_inb((port) + (offset)))
43 #define rl_inw(port, offset) (my_inw((port) + (offset)))
44 #define rl_inl(port, offset) (my_inl((port) + (offset)))
46 static void my_outb(u16_t port
, u8_t value
) {
48 if ((s
=sys_outb(port
, value
)) !=OK
)
49 printf("RTL8139: warning, sys_outb failed: %d\n", s
);
51 static void my_outw(u16_t port
, u16_t value
) {
53 if ((s
=sys_outw(port
, value
)) !=OK
)
54 printf("RTL8139: warning, sys_outw failed: %d\n", s
);
56 static void my_outl(u16_t port
, u32_t value
) {
58 if ((s
=sys_outl(port
, value
)) !=OK
)
59 printf("RTL8139: warning, sys_outl failed: %d\n", s
);
61 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
62 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
63 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
65 static int rl_init(unsigned int instance
, netdriver_addr_t
*addr
,
66 uint32_t *caps
, unsigned int *ticks
);
67 static int rl_probe(re_t
*rep
, unsigned int skip
);
68 static void rl_init_buf(re_t
*rep
);
69 static void rl_init_hw(re_t
*rep
, netdriver_addr_t
*addr
,
70 unsigned int instance
);
71 static void rl_reset_hw(re_t
*rep
);
72 static void rl_set_hwaddr(const netdriver_addr_t
*addr
);
73 static void rl_confaddr(re_t
*rep
, netdriver_addr_t
*addr
,
74 unsigned int instance
);
75 static void rl_stop(void);
76 static void rl_rec_mode(re_t
*rep
);
77 static void rl_set_mode(unsigned int mode
, const netdriver_addr_t
*mcast_list
,
78 unsigned int mcast_count
);
79 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
);
80 static int rl_send(struct netdriver_data
*data
, size_t size
);
81 static unsigned int rl_get_link(uint32_t *media
);
82 static void rl_intr(unsigned int mask
);
83 static void rl_check_ints(re_t
*rep
);
85 static void rl_report_link(re_t
*rep
);
86 static void mii_print_techab(u16_t techab
);
87 static void mii_print_stat_speed(u16_t stat
, u16_t extstat
);
89 static void rl_clear_rx(re_t
*rep
);
90 static void rl_do_reset(re_t
*rep
);
91 static void rl_other(const message
*m_ptr
, int ipc_status
);
92 static void rl_dump(void);
94 static void dump_phy(re_t
*rep
);
96 static int rl_handler(re_t
*rep
);
97 static void rl_tick(void);
98 static void tell_iommu(vir_bytes start
, size_t size
, int pci_bus
, int
99 pci_dev
, int pci_func
);
101 static const struct netdriver rl_table
= {
105 .ndr_set_mode
= rl_set_mode
,
106 .ndr_set_hwaddr
= rl_set_hwaddr
,
109 .ndr_get_link
= rl_get_link
,
112 .ndr_other
= rl_other
,
115 /*===========================================================================*
117 *===========================================================================*/
118 int main(int argc
, char *argv
[])
121 env_setargs(argc
, argv
);
123 netdriver_task(&rl_table
);
128 /*===========================================================================*
130 *===========================================================================*/
131 static void rl_intr(unsigned int __unused mask
)
138 /* Run interrupt handler at driver level. */
141 /* Reenable interrupts for this hook. */
142 if ((s
= sys_irqenable(&rep
->re_hook_id
)) != OK
)
143 printf("RTL8139: error, couldn't enable interrupts: %d\n", s
);
145 /* Perform tasks based on the flagged conditions. */
149 /*===========================================================================*
151 *===========================================================================*/
152 static void rl_other(const message
*m_ptr
, int ipc_status
)
154 if (is_ipc_notify(ipc_status
) && m_ptr
->m_source
== TTY_PROC_NR
)
158 /*===========================================================================*
160 *===========================================================================*/
161 static void rl_stop(void)
167 rl_outb(rep
->re_base_port
, RL_CR
, 0);
170 /*===========================================================================*
172 *===========================================================================*/
173 static void rl_dump(void)
180 printf("Realtek RTL 8139 device %s:\n", netdriver_name());
182 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
183 rl_inw(rep
->re_base_port
, RL_TSAD
),
184 rl_inl(rep
->re_base_port
, RL_TSD0
+0*4),
185 rl_inl(rep
->re_base_port
, RL_TSD0
+1*4),
186 rl_inl(rep
->re_base_port
, RL_TSD0
+2*4),
187 rl_inl(rep
->re_base_port
, RL_TSD0
+3*4));
188 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
189 rep
->re_tx_head
, rep
->re_tx_tail
,
190 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
191 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
194 /*===========================================================================*
196 *===========================================================================*/
197 static void rl_set_mode(unsigned int mode
, const netdriver_addr_t
*mcast_list
,
198 unsigned int mcast_count
)
209 /*===========================================================================*
211 *===========================================================================*/
212 static int rl_init(unsigned int instance
, netdriver_addr_t
*addr
,
213 uint32_t *caps
, unsigned int *ticks
)
215 /* Initialize the rtl8139 driver. */
218 int r
, fkeys
, sfkeys
;
221 /* Initialize driver state. */
223 memset(rep
, 0, sizeof(*rep
));
225 rep
->re_link_up
= -1; /* Unknown */
226 rep
->re_ertxth
= RL_TSD_ERTXTH_8
;
228 /* Try to find a matching device. */
229 if (!rl_probe(rep
, instance
))
232 /* Claim buffer memory. */
235 /* Initialize the device we found. */
236 rl_init_hw(rep
, addr
, instance
);
239 /* Report initial link status. */
244 /* Observe some function key for debug dumps. */
245 fkeys
= sfkeys
= 0; bit_set(sfkeys
, 9);
246 if ((r
= fkey_map(&fkeys
, &sfkeys
)) != OK
)
247 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r
);
250 *caps
= NDEV_CAP_MCAST
| NDEV_CAP_BCAST
| NDEV_CAP_HWADDR
;
255 /*===========================================================================*
257 *===========================================================================*/
258 static int rl_probe(re_t
*rep
, unsigned int skip
)
270 r
= pci_first_dev(&devind
, &vid
, &did
);
276 r
= pci_next_dev(&devind
, &vid
, &did
);
281 #if VERBOSE /* stay silent at startup, can always get status later */
282 dname
= pci_dev_name(vid
, did
);
284 dname
= "unknown device";
285 printf("%s: ", netdriver_name());
286 printf("%s (%x/%x) at %s\n", dname
, vid
, did
, pci_slot_name(devind
));
290 /* Enable bus mastering if necessary. */
291 cr
= pci_attr_r16(devind
, PCI_CR
);
292 /* printf("cr = 0x%x\n", cr); */
293 if (!(cr
& PCI_CR_MAST_EN
))
294 pci_attr_w16(devind
, PCI_CR
, cr
| PCI_CR_MAST_EN
);
296 bar
= pci_attr_r32(devind
, PCI_BAR
) & 0xffffffe0;
298 panic("base address is not properly configured");
300 rep
->re_base_port
= bar
;
302 ilr
= pci_attr_r8(devind
, PCI_ILR
);
305 printf("%s: using I/O address 0x%lx, IRQ %d\n",
306 netdriver_name(), (unsigned long)bar
, ilr
);
312 /*===========================================================================*
314 *===========================================================================*/
315 static void rl_init_buf(re_t
*rep
)
317 size_t rx_bufsize
, tx_bufsize
, tot_bufsize
;
322 /* Allocate receive and transmit buffers */
323 tx_bufsize
= NDEV_ETH_PACKET_MAX_TAGGED
;
325 tx_bufsize
+= 4-(tx_bufsize
% 4); /* Align */
326 rx_bufsize
= RX_BUFSIZE
;
327 tot_bufsize
= N_TX_BUF
*tx_bufsize
+ rx_bufsize
;
329 if (tot_bufsize
% 4096)
330 tot_bufsize
+= 4096-(tot_bufsize
% 4096);
332 #define BUF_ALIGNMENT (64*1024)
334 if (!(mallocbuf
= alloc_contig(BUF_ALIGNMENT
+ tot_bufsize
, 0, &buf
)))
335 panic("Couldn't allocate kernel buffer");
337 /* click-align mallocced buffer. this is what we used to get
338 * from kmalloc() too.
340 if((off
= buf
% BUF_ALIGNMENT
)) {
341 mallocbuf
+= BUF_ALIGNMENT
- off
;
342 buf
+= BUF_ALIGNMENT
- off
;
345 tell_iommu((vir_bytes
)mallocbuf
, tot_bufsize
, 0, 0, 0);
347 for (i
= 0; i
<N_TX_BUF
; i
++)
349 rep
->re_tx
[i
].ret_buf
= buf
;
350 rep
->re_tx
[i
].v_ret_buf
= mallocbuf
;
352 mallocbuf
+= tx_bufsize
;
355 rep
->v_re_rx_buf
= mallocbuf
;
358 /*===========================================================================*
360 *===========================================================================*/
361 static void rl_init_hw(re_t
*rep
, netdriver_addr_t
*addr
,
362 unsigned int instance
)
369 /* Set the interrupt handler. The policy is to only send HARD_INT
370 * notifications. Don't reenable interrupts automatically. The id
371 * that is passed back is the interrupt line number.
373 rep
->re_hook_id
= rep
->re_irq
;
374 if ((s
=sys_irqsetpolicy(rep
->re_irq
, 0, &rep
->re_hook_id
)) != OK
)
375 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s
);
379 if ((s
=sys_irqenable(&rep
->re_hook_id
)) != OK
)
380 printf("RTL8139: error, couldn't enable interrupts: %d\n", s
);
382 #if VERBOSE /* stay silent during startup, can always get status later */
384 printf("%s: model %s\n", netdriver_name(), rep
->re_model
);
387 printf("%s: unknown model 0x%08x\n",
389 rl_inl(rep
->re_base_port
, RL_TCR
) &
390 (RL_TCR_HWVER_AM
| RL_TCR_HWVER_BM
));
394 rl_confaddr(rep
, addr
, instance
);
397 printf("%s: Ethernet address ", netdriver_name());
398 for (i
= 0; i
< 6; i
++)
399 printf("%x%c", addr
->na_addr
[i
], i
< 5 ? ':' : '\n');
403 /*===========================================================================*
405 *===========================================================================*/
406 static void rl_reset_hw(re_t
*rep
)
413 port
= rep
->re_base_port
;
417 rl_outb(port
, RL_BMCR
, MII_CTRL_RST
);
418 SPIN_UNTIL(!(rl_inb(port
, RL_BMCR
) & MII_CTRL_RST
), 1000000);
419 if (rl_inb(port
, RL_BMCR
) & MII_CTRL_RST
)
420 panic("reset PHY failed to complete");
423 /* Reset the device */
425 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
426 port
, rl_inb(port
, RL_CR
));
428 rl_outb(port
, RL_CR
, RL_CR_RST
);
429 SPIN_UNTIL(!(rl_inb(port
, RL_CR
) & RL_CR_RST
), 1000000);
431 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
432 port
, rl_inb(port
, RL_CR
));
434 if (rl_inb(port
, RL_CR
) & RL_CR_RST
)
435 printf("rtl8139: reset failed to complete");
437 t
= rl_inl(port
, RL_TCR
);
438 switch(t
& (RL_TCR_HWVER_AM
| RL_TCR_HWVER_BM
))
440 case RL_TCR_HWVER_RTL8139
: rep
->re_model
= "RTL8139"; break;
441 case RL_TCR_HWVER_RTL8139A
: rep
->re_model
= "RTL8139A"; break;
442 case RL_TCR_HWVER_RTL8139AG
:
443 rep
->re_model
= "RTL8139A-G / RTL8139C";
445 case RL_TCR_HWVER_RTL8139B
:
446 rep
->re_model
= "RTL8139B / RTL8130";
448 case RL_TCR_HWVER_RTL8100
: rep
->re_model
= "RTL8100"; break;
449 case RL_TCR_HWVER_RTL8100B
:
450 rep
->re_model
= "RTL8100B/RTL8139D";
452 case RL_TCR_HWVER_RTL8139CP
: rep
->re_model
= "RTL8139C+"; break;
453 case RL_TCR_HWVER_RTL8101
: rep
->re_model
= "RTL8101"; break;
460 printf("REVID: 0x%02x\n", rl_inb(port
, RL_REVID
));
465 /* Should init multicast mask */
467 08-0f R
/W MAR
[0-7] multicast
469 bus_buf
= vm_1phys2bus(rep
->re_rx_buf
);
470 rl_outl(port
, RL_RBSTART
, bus_buf
);
473 for (i
= 0; i
<N_TX_BUF
; i
++)
475 rep
->re_tx
[i
].ret_busy
= FALSE
;
476 bus_buf
= vm_1phys2bus(rep
->re_tx
[i
].ret_buf
);
477 rl_outl(port
, RL_TSAD0
+i
*4, bus_buf
);
478 t
= rl_inl(port
, RL_TSD0
+i
*4);
479 assert(t
& RL_TSD_OWN
);
488 t
= rl_inw(port
, RL_IMR
);
489 rl_outw(port
, RL_IMR
, t
| (RL_IMR_SERR
| RL_IMR_TIMEOUT
|
492 t
= rl_inw(port
, RL_IMR
);
493 rl_outw(port
, RL_IMR
, t
| (RL_IMR_FOVW
| RL_IMR_PUN
|
494 RL_IMR_RXOVW
| RL_IMR_RER
| RL_IMR_ROK
));
496 t
= rl_inw(port
, RL_IMR
);
497 rl_outw(port
, RL_IMR
, t
| (RL_IMR_TER
| RL_IMR_TOK
));
499 t
= rl_inb(port
, RL_CR
);
500 rl_outb(port
, RL_CR
, t
| RL_CR_RE
);
502 t
= rl_inb(port
, RL_CR
);
503 rl_outb(port
, RL_CR
, t
| RL_CR_TE
);
505 rl_outl(port
, RL_RCR
, RX_BUFBITS
);
507 t
= rl_inl(port
, RL_TCR
);
508 rl_outl(port
, RL_TCR
, t
| RL_TCR_IFG_STD
);
511 /*===========================================================================*
513 *===========================================================================*/
514 static void rl_set_hwaddr(const netdriver_addr_t
*addr
)
523 port
= rep
->re_base_port
;
524 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_CONFIG
);
527 w
|= (addr
->na_addr
[i
] << (i
*8));
528 rl_outl(port
, RL_IDR
, w
);
531 w
|= (addr
->na_addr
[i
] << ((i
-4)*8));
532 rl_outl(port
, RL_IDR
+4, w
);
533 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_NORMAL
);
536 /*===========================================================================*
538 *===========================================================================*/
539 static void rl_confaddr(re_t
*rep
, netdriver_addr_t
*addr
,
540 unsigned int instance
)
542 static char eakey
[]= RL_ENVVAR
"#_EA";
543 static char eafmt
[]= "x:x:x:x:x:x";
548 /* User defined ethernet address? */
549 eakey
[sizeof(RL_ENVVAR
)-1]= '0' + instance
;
551 for (i
= 0; i
< 6; i
++)
553 if (env_parse(eakey
, eafmt
, i
, &v
, 0x00L
, 0xFFL
) != EP_SET
)
558 if (i
!= 0 && i
!= 6) env_panic(eakey
); /* It's all or nothing */
560 /* Should update ethernet address in hardware */
564 /* Get ethernet address */
565 port
= rep
->re_base_port
;
568 addr
->na_addr
[i
]= rl_inb(port
, RL_IDR
+i
);
571 /*===========================================================================*
573 *===========================================================================*/
574 static void rl_rec_mode(re_t
*rep
)
579 port
= rep
->re_base_port
;
580 rcr
= rl_inl(port
, RL_RCR
);
581 rcr
&= ~(RL_RCR_AB
|RL_RCR_AM
|RL_RCR_APM
|RL_RCR_AAP
);
582 if (rep
->re_mode
& NDEV_MODE_PROMISC
)
583 rcr
|= RL_RCR_AB
| RL_RCR_AM
| RL_RCR_AAP
;
584 if (rep
->re_mode
& NDEV_MODE_BCAST
)
586 if (rep
->re_mode
& (NDEV_MODE_MCAST_LIST
| NDEV_MODE_MCAST_ALL
))
590 rl_outl(port
, RL_RCR
, rcr
);
593 /*===========================================================================*
595 *===========================================================================*/
596 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
)
600 unsigned amount
, totlen
, packlen
;
601 u16_t d_start
, d_end
;
607 if (rep
->re_clear_rx
)
608 return SUSPEND
; /* Buffer overflow */
610 port
= rep
->re_base_port
;
612 if (rl_inb(port
, RL_CR
) & RL_CR_BUFE
)
614 /* Receive buffer is empty, suspend */
618 d_start
= rl_inw(port
, RL_CAPR
) + RL_CAPR_DATA_OFF
;
619 d_end
= rl_inw(port
, RL_CBR
) % RX_BUFSIZE
;
621 #if RX_BUFSIZE <= USHRT_MAX
622 if (d_start
>= RX_BUFSIZE
)
624 printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
625 rl_inw(port
, RL_CAPR
));
626 d_start
%= RX_BUFSIZE
;
631 amount
= d_end
-d_start
;
633 amount
= d_end
+RX_BUFSIZE
- d_start
;
635 rxstat
= *(u32_t
*) (rep
->v_re_rx_buf
+ d_start
);
637 /* Should convert from little endian to host byte order */
639 if (!(rxstat
& RL_RXS_ROK
))
641 printf("rxstat = 0x%08x\n", rxstat
);
642 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
643 d_start
, d_end
, rxstat
);
644 panic("received packet not OK");
646 totlen
= (rxstat
>> RL_RXS_LEN_S
);
647 if (totlen
< 8 || totlen
> 2*NDEV_ETH_PACKET_MAX
)
649 /* Someting went wrong */
651 "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
652 totlen
, rxstat
, d_start
);
654 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
655 d_start
, d_end
, totlen
, rxstat
);
660 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
661 d_start
, d_end
, totlen
, rxstat
);
664 if (totlen
+4 > amount
)
666 printf("rl_recv: packet not yet ready\n");
670 /* Should subtract the CRC */
671 packlen
= MIN(totlen
- NDEV_ETH_PACKET_CRC
, max
);
673 /* Copy out the data. The packet may wrap in the receive buffer. */
674 o
= (d_start
+4) % RX_BUFSIZE
;
675 s
= MIN(RX_BUFSIZE
- o
, (int)packlen
);
677 netdriver_copyout(data
, 0, rep
->v_re_rx_buf
+ o
, s
);
678 if (s
< (int)packlen
)
679 netdriver_copyout(data
, s
, rep
->v_re_rx_buf
, packlen
- s
);
681 /* Avoid overflow in 16-bit computations */
684 l
= (l
+3) & ~3; /* align */
688 assert(l
< RX_BUFSIZE
);
690 rl_outw(port
, RL_CAPR
, l
-RL_CAPR_DATA_OFF
);
695 /*===========================================================================*
697 *===========================================================================*/
698 static int rl_send(struct netdriver_data
*data
, size_t size
)
705 tx_head
= rep
->re_tx_head
;
706 if (rep
->re_tx
[tx_head
].ret_busy
)
709 netdriver_copyin(data
, 0, rep
->re_tx
[tx_head
].v_ret_buf
, size
);
711 rl_outl(rep
->re_base_port
, RL_TSD0
+tx_head
*4, rep
->re_ertxth
| size
);
712 rep
->re_tx
[tx_head
].ret_busy
= TRUE
;
715 if (++tx_head
== N_TX_BUF
)
717 assert(tx_head
< RL_N_TX
);
718 rep
->re_tx_head
= tx_head
;
723 /*===========================================================================*
725 *===========================================================================*/
726 static void rl_check_ints(re_t
*rep
)
729 10-1f R
/W TSD
[0-3] Transmit Status of Descriptor
[0-3]
730 31 R CRS Carrier Sense Lost
731 30 R TABT Transmit Abort
732 29 R OWC Out of Window Collision
733 27-24 R NCC
[3-0] Number of Collision Count
735 21-16 R
/W ERTXH
[5-0] Early Tx Threshold
737 14 R TUN Transmit FIFO Underrun
739 12-0 R
/W SIZE Descriptor Size
740 3e-3f R
/W ISR Interrupt Status Register
741 6 R
/W FOVW Fx FIFO Overflow Interrupt
742 5 R
/W PUN
/LinkChg Packet Underrun
/ Link Change Interrupt
743 3 R
/W TER Transmit Error Interrupt
744 2 R
/W TOK Transmit OK Interrupt
745 3e-3f R
/W ISR Interrupt Status Register
746 15 R
/W SERR System Error Interrupt
747 14 R
/W TimeOut Time Out Interrupt
748 13 R
/W LenChg Cable Length Change Interrupt
749 3e-3f R
/W ISR Interrupt Status Register
750 4 R
/W RXOVW Rx Buffer Overflow Interrupt
751 1 R
/W RER Receive Error Interrupt
752 0 R
/W ROK Receive OK Interrupt
753 4c
-4f R
/W MPC Missed Packet Counter
754 60-61 R TSAD Transmit Status of All Descriptors
755 15-12 R TOK
[3-0] TOK bit of Descriptor
[3-0]
756 11-8 R TUN
[3-0] TUN bit of Descriptor
[3-0]
757 7-4 R TABT
[3-0] TABT bit of Descriptor
[3-0]
758 3-0 R OWN
[3-0] OWN bit of Descriptor
[3-0]
759 6c
-6d R DIS Disconnect Counter
760 15-0 R DCNT Disconnect Counter
761 6e-6f R FCSC False Carrier Sense Counter
762 15-0 R FCSCNT False Carrier event counter
763 72-73 R REC RX_ER Counter
764 15-0 R RXERCNT Received packet counter
767 if (!rep
->re_got_int
)
769 rep
->re_got_int
= FALSE
;
773 if (rep
->re_clear_rx
)
776 if (rep
->re_need_reset
)
779 if (rep
->re_send_int
) {
780 rep
->re_send_int
= FALSE
;
785 if (rep
->re_report_link
) {
786 rep
->re_report_link
= FALSE
;
795 /*===========================================================================*
797 *===========================================================================*/
798 static unsigned int rl_get_link(uint32_t *media
)
807 port
= rep
->re_base_port
;
808 msr
= rl_inb(port
, RL_MSR
);
810 if (msr
& RL_MSR_LINKB
)
811 return NDEV_LINK_DOWN
;
813 if (msr
& RL_MSR_SPEED_10
)
814 *media
= IFM_ETHER
| IFM_10_T
;
816 *media
= IFM_ETHER
| IFM_100_TX
;
818 mii_ctrl
= rl_inw(port
, RL_BMCR
);
819 if (mii_ctrl
& MII_CTRL_DM
)
828 /*===========================================================================*
830 *===========================================================================*/
831 static void rl_report_link(re_t
*rep
)
834 u16_t mii_ctrl
, mii_status
, mii_ana
, mii_anlpa
, mii_ane
, mii_extstat
;
838 port
= rep
->re_base_port
;
839 msr
= rl_inb(port
, RL_MSR
);
840 link_up
= !(msr
& RL_MSR_LINKB
);
841 rep
->re_link_up
= link_up
;
844 printf("%s: link down\n", netdriver_name());
848 mii_ctrl
= rl_inw(port
, RL_BMCR
);
849 mii_status
= rl_inw(port
, RL_BMSR
);
850 mii_ana
= rl_inw(port
, RL_ANAR
);
851 mii_anlpa
= rl_inw(port
, RL_ANLPAR
);
852 mii_ane
= rl_inw(port
, RL_ANER
);
855 if (mii_ctrl
& (MII_CTRL_LB
|MII_CTRL_PD
|MII_CTRL_ISO
))
857 printf("%s: PHY: ", netdriver_name());
859 if (mii_ctrl
& MII_CTRL_LB
)
861 printf("loopback mode");
864 if (mii_ctrl
& MII_CTRL_PD
)
866 if (!f
) printf(", ");
868 printf("powered down");
870 if (mii_ctrl
& MII_CTRL_ISO
)
872 if (!f
) printf(", ");
879 if (!(mii_ctrl
& MII_CTRL_ANE
))
881 printf("%s: manual config: ", netdriver_name());
882 switch(mii_ctrl
& (MII_CTRL_SP_LSB
|MII_CTRL_SP_MSB
))
884 case MII_CTRL_SP_10
: printf("10 Mbps"); break;
885 case MII_CTRL_SP_100
: printf("100 Mbps"); break;
886 case MII_CTRL_SP_1000
: printf("1000 Mbps"); break;
887 case MII_CTRL_SP_RES
: printf("reserved speed"); break;
889 if (mii_ctrl
& MII_CTRL_DM
)
890 printf(", full duplex");
892 printf(", half duplex");
898 printf("%s: ", netdriver_name());
899 mii_print_stat_speed(mii_status
, mii_extstat
);
902 if (!(mii_status
& MII_STATUS_ANC
))
903 printf("%s: auto-negotiation not complete\n",
905 if (mii_status
& MII_STATUS_RF
)
906 printf("%s: remote fault detected\n", netdriver_name());
907 if (!(mii_status
& MII_STATUS_ANA
))
909 printf("%s: local PHY has no auto-negotiation ability\n",
912 if (!(mii_status
& MII_STATUS_LS
))
913 printf("%s: link down\n", netdriver_name());
914 if (mii_status
& MII_STATUS_JD
)
915 printf("%s: jabber condition detected\n",
917 if (!(mii_status
& MII_STATUS_EC
))
919 printf("%s: no extended register set\n", netdriver_name());
922 if (!(mii_status
& MII_STATUS_ANC
))
925 printf("%s: local cap.: ", netdriver_name());
926 mii_print_techab(mii_ana
);
929 if (mii_ane
& MII_ANE_PDF
)
930 printf("%s: parallel detection fault\n", netdriver_name());
931 if (!(mii_ane
& MII_ANE_LPANA
))
933 printf("%s: link-partner does not support auto-negotiation\n",
938 printf("%s: remote cap.: ", netdriver_name());
939 mii_print_techab(mii_anlpa
);
944 printf("%s: ", netdriver_name());
945 printf("link up at %d Mbps, ", (msr
& RL_MSR_SPEED_10
) ? 10 : 100);
946 printf("%s duplex\n", ((mii_ctrl
& MII_CTRL_DM
) ? "full" : "half"));
950 static void mii_print_techab(u16_t techab
)
953 if ((techab
& MII_ANA_SEL_M
) != MII_ANA_SEL_802_3
)
955 printf("strange selector 0x%x, value 0x%x",
956 techab
& MII_ANA_SEL_M
,
957 (techab
& MII_ANA_TAF_M
) >> MII_ANA_TAF_S
);
961 if (techab
& (MII_ANA_100T4
| MII_ANA_100TXFD
| MII_ANA_100TXHD
))
963 printf("100 Mbps: ");
966 if (techab
& MII_ANA_100T4
)
971 if (techab
& (MII_ANA_100TXFD
| MII_ANA_100TXHD
))
977 switch(techab
& (MII_ANA_100TXFD
|MII_ANA_100TXHD
))
979 case MII_ANA_100TXFD
: printf("FD"); break;
980 case MII_ANA_100TXHD
: printf("HD"); break;
981 default: printf("FD/HD"); break;
985 if (techab
& (MII_ANA_10TFD
| MII_ANA_10THD
))
992 switch(techab
& (MII_ANA_10TFD
|MII_ANA_10THD
))
994 case MII_ANA_10TFD
: printf("FD"); break;
995 case MII_ANA_10THD
: printf("HD"); break;
996 default: printf("FD/HD"); break;
999 if (techab
& MII_ANA_PAUSE_SYM
)
1004 printf("pause(SYM)");
1006 if (techab
& MII_ANA_PAUSE_ASYM
)
1011 printf("pause(ASYM)");
1013 if (techab
& MII_ANA_TAF_RES
)
1018 printf("0x%x", (techab
& MII_ANA_TAF_RES
) >> MII_ANA_TAF_S
);
1022 static void mii_print_stat_speed(u16_t stat
, u16_t extstat
)
1026 if (stat
& MII_STATUS_EXT_STAT
)
1028 if (extstat
& (MII_ESTAT_1000XFD
| MII_ESTAT_1000XHD
|
1029 MII_ESTAT_1000TFD
| MII_ESTAT_1000THD
))
1031 printf("1000 Mbps: ");
1034 if (extstat
& (MII_ESTAT_1000XFD
| MII_ESTAT_1000XHD
))
1039 (MII_ESTAT_1000XFD
|MII_ESTAT_1000XHD
))
1041 case MII_ESTAT_1000XFD
: printf("FD"); break;
1042 case MII_ESTAT_1000XHD
: printf("HD"); break;
1043 default: printf("FD/HD"); break;
1046 if (extstat
& (MII_ESTAT_1000TFD
| MII_ESTAT_1000THD
))
1053 (MII_ESTAT_1000TFD
|MII_ESTAT_1000THD
))
1055 case MII_ESTAT_1000TFD
: printf("FD"); break;
1056 case MII_ESTAT_1000THD
: printf("HD"); break;
1057 default: printf("FD/HD"); break;
1062 if (stat
& (MII_STATUS_100T4
|
1063 MII_STATUS_100XFD
| MII_STATUS_100XHD
|
1064 MII_STATUS_100T2FD
| MII_STATUS_100T2HD
))
1069 printf("100 Mbps: ");
1071 if (stat
& MII_STATUS_100T4
)
1076 if (stat
& (MII_STATUS_100XFD
| MII_STATUS_100XHD
))
1082 switch(stat
& (MII_STATUS_100XFD
|MII_STATUS_100XHD
))
1084 case MII_STATUS_100XFD
: printf("FD"); break;
1085 case MII_STATUS_100XHD
: printf("HD"); break;
1086 default: printf("FD/HD"); break;
1089 if (stat
& (MII_STATUS_100T2FD
| MII_STATUS_100T2HD
))
1095 switch(stat
& (MII_STATUS_100T2FD
|MII_STATUS_100T2HD
))
1097 case MII_STATUS_100T2FD
: printf("FD"); break;
1098 case MII_STATUS_100T2HD
: printf("HD"); break;
1099 default: printf("FD/HD"); break;
1103 if (stat
& (MII_STATUS_10FD
| MII_STATUS_10HD
))
1107 printf("10 Mbps: ");
1110 switch(stat
& (MII_STATUS_10FD
|MII_STATUS_10HD
))
1112 case MII_STATUS_10FD
: printf("FD"); break;
1113 case MII_STATUS_10HD
: printf("HD"); break;
1114 default: printf("FD/HD"); break;
1118 #endif /* VERBOSE */
1120 /*===========================================================================*
1122 *===========================================================================*/
1123 static void rl_clear_rx(re_t
*rep
)
1128 rep
->re_clear_rx
= FALSE
;
1129 port
= rep
->re_base_port
;
1131 /* Reset the receiver */
1132 cr
= rl_inb(port
, RL_CR
);
1134 rl_outb(port
, RL_CR
, cr
);
1135 SPIN_UNTIL(!(rl_inb(port
, RL_CR
) & RL_CR_RE
), 1000000);
1136 if (rl_inb(port
, RL_CR
) & RL_CR_RE
)
1137 panic("cannot disable receiver");
1140 printf("RBSTART = 0x%08x\n", rl_inl(port
, RL_RBSTART
));
1141 printf("CAPR = 0x%04x\n", rl_inw(port
, RL_CAPR
));
1142 printf("CBR = 0x%04x\n", rl_inw(port
, RL_CBR
));
1143 printf("RCR = 0x%08x\n", rl_inl(port
, RL_RCR
));
1146 rl_outb(port
, RL_CR
, cr
| RL_CR_RE
);
1148 rl_outl(port
, RL_RCR
, RX_BUFBITS
);
1152 netdriver_stat_ierror(1);
1155 /*===========================================================================*
1157 *===========================================================================*/
1158 static void rl_do_reset(re_t
*rep
)
1160 rep
->re_need_reset
= FALSE
;
1165 if (rep
->re_tx
[rep
->re_tx_head
].ret_busy
)
1167 rep
->re_tx
[rep
->re_tx_head
].ret_busy
= FALSE
;
1168 rep
->re_send_int
= TRUE
;
1172 /*===========================================================================*
1174 *===========================================================================*/
1175 static void dump_phy(re_t
*rep
)
1180 port
= rep
->re_base_port
;
1182 t
= rl_inb(port
, RL_MSR
);
1183 printf("MSR: 0x%02lx\n", t
);
1184 if (t
& RL_MSR_SPEED_10
)
1185 printf("\t10 Mbps\n");
1186 if (t
& RL_MSR_LINKB
)
1187 printf("\tLink failed\n");
1189 t
= rl_inb(port
, RL_CONFIG1
);
1190 printf("CONFIG1: 0x%02lx\n", t
);
1192 t
= rl_inb(port
, RL_CONFIG3
);
1193 printf("CONFIG3: 0x%02lx\n", t
);
1195 t
= rl_inb(port
, RL_CONFIG4
);
1196 printf("CONFIG4: 0x%02lx\n", t
);
1198 t
= rl_inw(port
, RL_BMCR
);
1199 printf("BMCR (MII_CTRL): 0x%04lx\n", t
);
1201 t
= rl_inw(port
, RL_BMSR
);
1203 if (t
& MII_STATUS_100T4
)
1204 printf(" 100Base-T4");
1205 if (t
& MII_STATUS_100XFD
)
1206 printf(" 100Base-X-FD");
1207 if (t
& MII_STATUS_100XHD
)
1208 printf(" 100Base-X-HD");
1209 if (t
& MII_STATUS_10FD
)
1210 printf(" 10Mbps-FD");
1211 if (t
& MII_STATUS_10HD
)
1212 printf(" 10Mbps-HD");
1213 if (t
& MII_STATUS_100T2FD
)
1214 printf(" 100Base-T2-FD");
1215 if (t
& MII_STATUS_100T2HD
)
1216 printf(" 100Base-T2-HD");
1217 if (t
& MII_STATUS_EXT_STAT
)
1218 printf(" Ext-stat");
1219 if (t
& MII_STATUS_RES
)
1220 printf(" res-0x%lx", t
& MII_STATUS_RES
);
1221 if (t
& MII_STATUS_MFPS
)
1223 if (t
& MII_STATUS_ANC
)
1225 if (t
& MII_STATUS_RF
)
1226 printf(" remote-fault");
1227 if (t
& MII_STATUS_ANA
)
1229 if (t
& MII_STATUS_LS
)
1231 if (t
& MII_STATUS_JD
)
1233 if (t
& MII_STATUS_EC
)
1234 printf(" Extended-capability");
1237 t
= rl_inw(port
, RL_ANAR
);
1238 printf("ANAR (MII_ANA): 0x%04lx\n", t
);
1240 t
= rl_inw(port
, RL_ANLPAR
);
1241 printf("ANLPAR: 0x%04lx\n", t
);
1243 t
= rl_inw(port
, RL_ANER
);
1244 printf("ANER (MII_ANE): ");
1245 if (t
& MII_ANE_RES
)
1246 printf(" res-0x%lx", t
& MII_ANE_RES
);
1247 if (t
& MII_ANE_PDF
)
1248 printf(" Par-Detect-Fault");
1249 if (t
& MII_ANE_LPNPA
)
1250 printf(" LP-Next-Page-Able");
1251 if (t
& MII_ANE_NPA
)
1252 printf(" Loc-Next-Page-Able");
1254 printf(" Page-Received");
1255 if (t
& MII_ANE_LPANA
)
1256 printf(" LP-Auto-Neg-Able");
1259 t
= rl_inw(port
, RL_NWAYTR
);
1260 printf("NWAYTR: 0x%04lx\n", t
);
1261 t
= rl_inw(port
, RL_CSCR
);
1262 printf("CSCR: 0x%04lx\n", t
);
1264 t
= rl_inb(port
, RL_CONFIG5
);
1265 printf("CONFIG5: 0x%02lx\n", t
);
1269 /*===========================================================================*
1271 *===========================================================================*/
1272 static int rl_handler(re_t
*rep
)
1274 int i
, port
, tx_head
, tx_tail
, link_up
;
1276 u32_t tsd
, tcr
, ertxth
;
1278 port
= rep
->re_base_port
;
1281 isr
= rl_inw(port
, RL_ISR
);
1282 rl_outw(port
, RL_ISR
, isr
);
1284 if (isr
& RL_IMR_FOVW
)
1286 isr
&= ~RL_IMR_FOVW
;
1287 /* Should do anything? */
1289 if (isr
& RL_IMR_PUN
)
1293 /* Either the link status changed or there was a TX fifo
1296 link_up
= !(rl_inb(port
, RL_MSR
) & RL_MSR_LINKB
);
1297 if (link_up
!= rep
->re_link_up
)
1299 rep
->re_report_link
= TRUE
;
1300 rep
->re_got_int
= TRUE
;
1303 if (isr
& RL_IMR_RXOVW
)
1305 isr
&= ~RL_IMR_RXOVW
;
1307 /* Clear the receive buffer */
1308 rep
->re_clear_rx
= TRUE
;
1309 rep
->re_got_int
= TRUE
;
1312 if (isr
& (RL_ISR_RER
| RL_ISR_ROK
))
1314 isr
&= ~(RL_ISR_RER
| RL_ISR_ROK
);
1316 rep
->re_got_int
= TRUE
;
1318 if ((isr
& (RL_ISR_TER
| RL_ISR_TOK
)) || 1)
1320 isr
&= ~(RL_ISR_TER
| RL_ISR_TOK
);
1322 tsad
= rl_inw(port
, RL_TSAD
);
1323 if (tsad
& (RL_TSAD_TABT0
|RL_TSAD_TABT1
|
1324 RL_TSAD_TABT2
|RL_TSAD_TABT3
))
1326 printf("rl_handler, TABT, tasd = 0x%04x\n",
1329 /* Find the aborted transmit request */
1330 for (i
= 0; i
< N_TX_BUF
; i
++)
1332 tsd
= rl_inl(port
, RL_TSD0
+i
*4);
1333 if (tsd
& RL_TSD_TABT
)
1339 "rl_handler: can't find aborted TX req.\n");
1343 printf("TSD%d = 0x%04x\n", i
, tsd
);
1345 /* Set head and tail to this buffer */
1346 rep
->re_tx_head
= rep
->re_tx_tail
= i
;
1349 /* Aborted transmission, just kick the device
1350 * and be done with it.
1352 netdriver_stat_oerror(1);
1354 tcr
= rl_inl(port
, RL_TCR
);
1355 rl_outl(port
, RL_TCR
, tcr
| RL_TCR_CLRABT
);
1358 /* Transmit completed */
1359 tx_head
= rep
->re_tx_head
;
1360 tx_tail
= rep
->re_tx_tail
;
1361 for (i
= 0; i
< 2*N_TX_BUF
; i
++)
1363 if (rep
->re_tx_busy
== 0)
1365 if (!rep
->re_tx
[tx_tail
].ret_busy
)
1367 /* Strange, this buffer is not in-use.
1368 * Increment tx_tail until tx_head is
1369 * reached (or until we find a buffer that
1372 if (tx_tail
== tx_head
)
1374 if (++tx_tail
>= N_TX_BUF
)
1376 assert(tx_tail
< RL_N_TX
);
1377 rep
->re_tx_tail
= tx_tail
;
1380 tsd
= rl_inl(port
, RL_TSD0
+tx_tail
*4);
1381 if (!(tsd
& (RL_TSD_TABT
| RL_TSD_TOK
| RL_TSD_TUN
)))
1383 /* Buffer is not yet ready */
1387 /* Should collect statistics */
1388 if (tsd
& RL_TSD_TABT
)
1390 printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1392 panic("TX abort"); /* CLRABT is not all that
1393 * that effective, why not?
1395 tcr
= rl_inl(port
, RL_TCR
);
1396 rl_outl(port
, RL_TCR
, tcr
| RL_TCR_CLRABT
);
1399 /* What about collisions? */
1400 if (!(tsd
& RL_TSD_TOK
))
1401 netdriver_stat_oerror(1);
1402 if (tsd
& RL_TSD_TUN
)
1404 /* Increase ERTXTH */
1405 ertxth
= tsd
+ (1 << RL_TSD_ERTXTH_S
);
1406 ertxth
&= RL_TSD_ERTXTH_M
;
1408 if (ertxth
> rep
->re_ertxth
)
1410 printf("%s: new ertxth: %d bytes\n",
1412 (ertxth
>> RL_TSD_ERTXTH_S
) *
1414 rep
->re_ertxth
= ertxth
;
1418 rep
->re_tx
[tx_tail
].ret_busy
= FALSE
;
1422 printf("TSD%d: %08lx\n", tx_tail
, tsd
);
1424 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1426 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
1427 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
1430 if (++tx_tail
>= N_TX_BUF
)
1432 assert(tx_tail
< RL_N_TX
);
1433 rep
->re_tx_tail
= tx_tail
;
1435 rep
->re_send_int
= TRUE
;
1436 rep
->re_got_int
= TRUE
;
1437 rep
->re_tx_alive
= TRUE
;
1439 assert(i
< 2*N_TX_BUF
);
1443 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1450 /*===========================================================================*
1452 *===========================================================================*/
1453 static void rl_tick(void)
1459 assert(rep
->re_tx_busy
>= 0 && rep
->re_tx_busy
<= N_TX_BUF
);
1460 if (rep
->re_tx_busy
== 0)
1462 /* Assume that an idle system is alive */
1463 rep
->re_tx_alive
= TRUE
;
1466 if (rep
->re_tx_alive
)
1468 rep
->re_tx_alive
= FALSE
;
1471 printf("%s: TX timeout, resetting\n", netdriver_name());
1472 printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1473 rl_inw(rep
->re_base_port
, RL_TSAD
),
1474 rl_inl(rep
->re_base_port
, RL_TSD0
+0*4),
1475 rl_inl(rep
->re_base_port
, RL_TSD0
+1*4),
1476 rl_inl(rep
->re_base_port
, RL_TSD0
+2*4),
1477 rl_inl(rep
->re_base_port
, RL_TSD0
+3*4));
1478 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1479 rep
->re_tx_head
, rep
->re_tx_tail
,
1480 rep
->re_tx
[0].ret_busy
, rep
->re_tx
[1].ret_busy
,
1481 rep
->re_tx
[2].ret_busy
, rep
->re_tx
[3].ret_busy
);
1482 rep
->re_need_reset
= TRUE
;
1483 rep
->re_got_int
= TRUE
;
1488 /* TODO: obviously this needs a lot of work. */
1489 static void tell_iommu(vir_bytes buf
, size_t size
, int pci_bus
, int pci_dev
,
1496 r
= ds_retrieve_label_endpt("amddev", &dev_e
);
1500 printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
1501 "for 'amddev': %d\n", r
);
1506 m
.m_type
= IOMMU_MAP
;
1513 r
= ipc_sendrec(dev_e
, &m
);
1516 printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1522 printf("rtl8139`tell_dev: dma map request failed: %d\n",
1529 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $