4 * This file contains a ethernet device driver for Realtek rtl8169 based
9 #include <minix/drivers.h>
10 #include <minix/netdriver.h>
12 #include <machine/pci.h>
17 #define VERBOSE 0 /* display message during init */
19 #define RE_DTCC_VALUE 600 /* DTCC Update once every 10 minutes */
21 #define RX_CONFIG_MASK 0xff7e1880 /* Clears the bits supported by chip */
23 #define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | \
24 RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK)
26 #define RL_ENVVAR "RTLETH" /* Configuration */
28 typedef struct re_desc
30 u32_t status
; /* command/status */
31 u32_t vlan
; /* VLAN */
32 u32_t addr_low
; /* low 32-bits of physical buffer address */
33 u32_t addr_high
; /* high 32-bits of physical buffer address */
36 typedef struct re_dtcc
38 u32_t TxOk_low
; /* low 32-bits of Tx Ok packets */
39 u32_t TxOk_high
; /* high 32-bits of Tx Ok packets */
40 u32_t RxOk_low
; /* low 32-bits of Rx Ok packets */
41 u32_t RxOk_high
; /* high 32-bits of Rx Ok packets */
42 u32_t TxEr_low
; /* low 32-bits of Tx errors */
43 u32_t TxEr_high
; /* high 32-bits of Tx errors */
44 u32_t RxEr
; /* Rx errors */
45 u16_t MissPkt
; /* Missed packets */
46 u16_t FAE
; /* Frame Alignment Error packets (MII only) */
47 u32_t Tx1Col
; /* Tx Ok packets with 1 collision before Tx */
48 u32_t TxMCol
; /* Tx Ok packets with 2..15 collisions */
49 u32_t RxOkPhy_low
; /* low 32-bits of Rx Ok packets for us */
50 u32_t RxOkPhy_high
; /* high 32-bits of Rx Ok packets for us */
51 u32_t RxOkBrd_low
; /* low 32-bits of Rx Ok broadcast packets */
52 u32_t RxOkBrd_high
; /* high 32-bits of Rx Ok broadcast packets */
53 u32_t RxOkMul
; /* Rx Ok multicast packets */
54 u16_t TxAbt
; /* Tx abort packets */
55 u16_t TxUndrn
; /* Tx underrun packets */
78 re_desc
*re_rx_desc
; /* Rx descriptor buffer */
79 phys_bytes p_rx_desc
; /* Rx descriptor buffer physical */
88 re_desc
*re_tx_desc
; /* Tx descriptor buffer */
89 phys_bytes p_tx_desc
; /* Tx descriptor buffer physical */
90 int re_tx_busy
; /* how many Tx descriptors are busy? */
92 int re_hook_id
; /* IRQ hook id at kernel */
94 phys_bytes dtcc_buf
; /* Dump Tally Counter buffer physical */
95 re_dtcc
*v_dtcc_buf
; /* Dump Tally Counter buffer */
96 u32_t dtcc_counter
; /* DTCC update counter */
97 char re_name
[sizeof("rtl8169#n")];
101 static re_t re_state
;
103 static int re_instance
;
105 static unsigned my_inb(u16_t port
)
109 if ((s
= sys_inb(port
, &value
)) != OK
)
110 printf("RTL8169: warning, sys_inb failed: %d\n", s
);
113 static unsigned my_inw(u16_t port
)
117 if ((s
= sys_inw(port
, &value
)) != OK
)
118 printf("RTL8169: warning, sys_inw failed: %d\n", s
);
121 static unsigned my_inl(u16_t port
)
125 if ((s
= sys_inl(port
, &value
)) != OK
)
126 printf("RTL8169: warning, sys_inl failed: %d\n", s
);
129 #define rl_inb(port, offset) (my_inb((port) + (offset)))
130 #define rl_inw(port, offset) (my_inw((port) + (offset)))
131 #define rl_inl(port, offset) (my_inl((port) + (offset)))
133 static void my_outb(u16_t port
, u8_t value
)
137 if ((s
= sys_outb(port
, value
)) != OK
)
138 printf("RTL8169: warning, sys_outb failed: %d\n", s
);
140 static void my_outw(u16_t port
, u16_t value
)
144 if ((s
= sys_outw(port
, value
)) != OK
)
145 printf("RTL8169: warning, sys_outw failed: %d\n", s
);
147 static void my_outl(u16_t port
, u32_t value
)
151 if ((s
= sys_outl(port
, value
)) != OK
)
152 printf("RTL8169: warning, sys_outl failed: %d\n", s
);
154 #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
155 #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
156 #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
158 static int rl_init(unsigned int instance
, ether_addr_t
*addr
);
159 static int rl_probe(re_t
*rep
, unsigned int skip
);
160 static void rl_init_buf(re_t
*rep
);
161 static void rl_init_hw(re_t
*rep
, ether_addr_t
*addr
);
162 static void rl_reset_hw(re_t
*rep
);
163 static void rl_confaddr(re_t
*rep
, ether_addr_t
*addr
);
164 static void rl_stop(void);
165 static void rl_rec_mode(re_t
*rep
);
166 static void rl_mode(unsigned int mode
);
167 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
);
168 static int rl_send(struct netdriver_data
*data
, size_t size
);
169 static void rl_intr(unsigned int mask
);
170 static void rl_check_ints(re_t
*rep
);
171 static void rl_do_reset(re_t
*rep
);
172 static void rl_stat(eth_stat_t
*stat
);
174 static void rl_report_link(re_t
*rep
);
175 static void dump_phy(const re_t
*rep
);
177 static void rl_handler(re_t
*rep
);
178 static void rl_alarm(clock_t stamp
);
180 static const struct netdriver rl_table
= {
188 .ndr_alarm
= rl_alarm
191 /*===========================================================================*
193 *===========================================================================*/
194 int main(int argc
, char *argv
[])
196 env_setargs(argc
, argv
);
198 netdriver_task(&rl_table
);
203 /*===========================================================================*
205 *===========================================================================*/
206 static int rl_init(unsigned int instance
, ether_addr_t
*addr
)
208 /* Initialize the rtl8169 driver. */
211 /* Initialize driver state. */
213 memset(rep
, 0, sizeof(*rep
));
215 strlcpy(rep
->re_name
, "rtl8169#0", sizeof(rep
->re_name
));
216 rep
->re_name
[8] += re_instance
;
218 re_instance
= instance
;
220 /* Try to find a matching device. */
221 if (!rl_probe(rep
, instance
))
224 /* Claim buffer memory now. */
225 rl_init_buf(&re_state
);
227 /* Initialize the device we found. */
228 rl_init_hw(rep
, addr
);
230 /* Use a synchronous alarm instead of a watchdog timer. */
231 sys_setalarm(sys_hz(), 0);
236 /*===========================================================================*
238 *===========================================================================*/
239 static void rl_stop(void)
245 rl_outb(rep
->re_base_port
, RL_CR
, RL_CR_RST
);
248 static void mdio_write(u16_t port
, int regaddr
, int value
)
252 rl_outl(port
, RL_PHYAR
,
253 0x80000000 | (regaddr
& 0x1F) << 16 | (value
& 0xFFFF));
255 for (i
= 20; i
> 0; i
--) {
257 * Check if the RTL8169 has completed writing to the specified
260 if (!(rl_inl(port
, RL_PHYAR
) & 0x80000000))
267 static int mdio_read(u16_t port
, int regaddr
)
271 rl_outl(port
, RL_PHYAR
, (regaddr
& 0x1F) << 16);
273 for (i
= 20; i
> 0; i
--) {
275 * Check if the RTL8169 has completed retrieving data from
276 * the specified MII register
278 if (rl_inl(port
, RL_PHYAR
) & 0x80000000) {
279 value
= (int)(rl_inl(port
, RL_PHYAR
) & 0xFFFF);
287 static void rtl8169_update_stat(re_t
*rep
)
292 port
= rep
->re_base_port
;
294 /* Fetch Missed Packets */
295 rep
->re_stat
.ets_missedP
+= rl_inw(port
, RL_MPC
);
296 rl_outw(port
, RL_MPC
, 0x00);
298 /* Dump Tally Counter Command */
299 rl_outl(port
, RL_DTCCR_HI
, 0); /* 64 bits */
300 rl_outl(port
, RL_DTCCR_LO
, rep
->dtcc_buf
| RL_DTCCR_CMD
);
301 for (i
= 0; i
< 1000; i
++) {
302 if (!(rl_inl(port
, RL_DTCCR_LO
) & RL_DTCCR_CMD
))
307 /* Update counters */
308 rep
->re_stat
.ets_frameAll
= rep
->v_dtcc_buf
->FAE
;
309 rep
->re_stat
.ets_transDef
= rep
->v_dtcc_buf
->TxUndrn
;
310 rep
->re_stat
.ets_transAb
= rep
->v_dtcc_buf
->TxAbt
;
311 rep
->re_stat
.ets_collision
=
312 rep
->v_dtcc_buf
->Tx1Col
+ rep
->v_dtcc_buf
->TxMCol
;
316 /*===========================================================================*
318 *===========================================================================*/
319 static void rtl8169_dump(void)
328 rtl8169_update_stat(rep
);
330 printf("Realtek RTL 8169 statistics of instance %d:\n", re_instance
);
332 printf("recvErr :%8ld\t", rep
->re_stat
.ets_recvErr
);
333 printf("sendErr :%8ld\t", rep
->re_stat
.ets_sendErr
);
334 printf("OVW :%8ld\n", rep
->re_stat
.ets_OVW
);
336 printf("CRCerr :%8ld\t", rep
->re_stat
.ets_CRCerr
);
337 printf("frameAll :%8ld\t", rep
->re_stat
.ets_frameAll
);
338 printf("missedP :%8ld\n", rep
->re_stat
.ets_missedP
);
340 printf("packetR :%8ld\t", rep
->re_stat
.ets_packetR
);
341 printf("packetT :%8ld\t", rep
->re_stat
.ets_packetT
);
342 printf("transDef :%8ld\n", rep
->re_stat
.ets_transDef
);
344 printf("collision :%8ld\t", rep
->re_stat
.ets_collision
);
345 printf("transAb :%8ld\t", rep
->re_stat
.ets_transAb
);
346 printf("carrSense :%8ld\n", rep
->re_stat
.ets_carrSense
);
348 printf("fifoUnder :%8ld\t", rep
->re_stat
.ets_fifoUnder
);
349 printf("fifoOver :%8ld\t", rep
->re_stat
.ets_fifoOver
);
350 printf("OWC :%8ld\n", rep
->re_stat
.ets_OWC
);
351 printf("interrupts :%8u\n", rep
->interrupts
);
353 printf("\nRealtek RTL 8169 Tally Counters:\n");
355 dtcc
= rep
->v_dtcc_buf
;
358 printf("TxOk :%8u%08u\t",
359 dtcc
->TxOk_high
, dtcc
->TxOk_low
);
361 printf("TxOk :%16u\t", dtcc
->TxOk_low
);
364 printf("RxOk :%8u%08u\n",
365 dtcc
->RxOk_high
, dtcc
->RxOk_low
);
367 printf("RxOk :%16u\n", dtcc
->RxOk_low
);
370 printf("TxEr :%8u%08u\t",
371 dtcc
->TxEr_high
, dtcc
->TxEr_low
);
373 printf("TxEr :%16u\t", dtcc
->TxEr_low
);
375 printf("RxEr :%16u\n", dtcc
->RxEr
);
377 printf("Tx1Col :%16u\t", dtcc
->Tx1Col
);
378 printf("TxMCol :%16u\n", dtcc
->TxMCol
);
380 if (dtcc
->RxOkPhy_high
)
381 printf("RxOkPhy :%8u%08u\t",
382 dtcc
->RxOkPhy_high
, dtcc
->RxOkPhy_low
);
384 printf("RxOkPhy :%16u\t", dtcc
->RxOkPhy_low
);
386 if (dtcc
->RxOkBrd_high
)
387 printf("RxOkBrd :%8u%08u\n",
388 dtcc
->RxOkBrd_high
, dtcc
->RxOkBrd_low
);
390 printf("RxOkBrd :%16u\n", dtcc
->RxOkBrd_low
);
392 printf("RxOkMul :%16u\t", dtcc
->RxOkMul
);
393 printf("MissPkt :%16d\n", dtcc
->MissPkt
);
395 printf("\nRealtek RTL 8169 Miscellaneous Info:\n");
397 printf("tx_head :%8d busy %d\t",
398 rep
->re_tx_head
, rep
->re_tx
[rep
->re_tx_head
].ret_busy
);
402 /*===========================================================================*
404 *===========================================================================*/
405 static void rl_mode(unsigned int mode
)
416 /*===========================================================================*
418 *===========================================================================*/
419 static int rl_probe(re_t
*rep
, unsigned int skip
)
431 r
= pci_first_dev(&devind
, &vid
, &did
);
436 r
= pci_next_dev(&devind
, &vid
, &did
);
442 dname
= pci_dev_name(vid
, did
);
444 dname
= "unknown device";
445 printf("%s: ", rep
->re_name
);
446 printf("%s (%x/%x) at %s\n", dname
, vid
, did
, pci_slot_name(devind
));
450 bar
= pci_attr_r32(devind
, PCI_BAR
) & 0xffffffe0;
452 panic("base address is not properly configured");
454 rep
->re_base_port
= bar
;
456 ilr
= pci_attr_r8(devind
, PCI_ILR
);
459 printf("%s: using I/O address 0x%lx, IRQ %d\n",
460 rep
->re_name
, (unsigned long)bar
, ilr
);
466 /*===========================================================================*
468 *===========================================================================*/
469 static void rl_init_buf(re_t
*rep
)
471 size_t rx_bufsize
, tx_bufsize
, rx_descsize
, tx_descsize
, tot_bufsize
;
472 struct re_desc
*desc
;
477 /* Allocate receive and transmit descriptors */
478 rx_descsize
= (N_RX_DESC
* sizeof(struct re_desc
));
479 tx_descsize
= (N_TX_DESC
* sizeof(struct re_desc
));
481 /* Allocate receive and transmit buffers */
482 tx_bufsize
= ETH_MAX_PACK_SIZE_TAGGED
;
484 tx_bufsize
+= 4-(tx_bufsize
% 4); /* Align */
485 rx_bufsize
= RX_BUFSIZE
;
486 tot_bufsize
= rx_descsize
+ tx_descsize
;
487 tot_bufsize
+= (N_TX_DESC
* tx_bufsize
) + (N_RX_DESC
* rx_bufsize
);
488 tot_bufsize
+= sizeof(struct re_dtcc
);
490 if (tot_bufsize
% 4096)
491 tot_bufsize
+= 4096 - (tot_bufsize
% 4096);
493 if (!(mallocbuf
= alloc_contig(tot_bufsize
, AC_ALIGN64K
, &buf
)))
494 panic("Couldn't allocate kernel buffer");
497 rep
->re_rx_desc
= (re_desc
*)mallocbuf
;
498 rep
->p_rx_desc
= buf
;
499 memset(mallocbuf
, 0x00, rx_descsize
);
501 mallocbuf
+= rx_descsize
;
504 rep
->re_tx_desc
= (re_desc
*)mallocbuf
;
505 rep
->p_tx_desc
= buf
;
506 memset(mallocbuf
, 0x00, tx_descsize
);
508 mallocbuf
+= tx_descsize
;
510 desc
= rep
->re_rx_desc
;
511 for (d
= 0; d
< N_RX_DESC
; d
++) {
512 /* Setting Rx buffer */
513 rep
->re_rx
[d
].ret_buf
= buf
;
514 rep
->re_rx
[d
].v_ret_buf
= mallocbuf
;
516 mallocbuf
+= rx_bufsize
;
518 /* Setting Rx descriptor */
519 if (d
== (N_RX_DESC
- 1)) /* Last descriptor: set EOR bit */
520 desc
->status
= DESC_EOR
| DESC_OWN
|
521 (RX_BUFSIZE
& DESC_RX_LENMASK
);
523 desc
->status
= DESC_OWN
|
524 (RX_BUFSIZE
& DESC_RX_LENMASK
);
526 desc
->addr_low
= rep
->re_rx
[d
].ret_buf
;
529 desc
= rep
->re_tx_desc
;
530 for (d
= 0; d
< N_TX_DESC
; d
++) {
531 rep
->re_tx
[d
].ret_busy
= FALSE
;
532 rep
->re_tx
[d
].ret_buf
= buf
;
533 rep
->re_tx
[d
].v_ret_buf
= mallocbuf
;
535 mallocbuf
+= tx_bufsize
;
537 /* Setting Tx descriptor */
538 desc
->addr_low
= rep
->re_tx
[d
].ret_buf
;
543 /* Dump Tally Counter buffer */
545 rep
->v_dtcc_buf
= (re_dtcc
*)mallocbuf
;
548 /*===========================================================================*
550 *===========================================================================*/
551 static void rl_init_hw(re_t
*rep
, ether_addr_t
*addr
)
559 * Set the interrupt handler. The policy is to only send HARD_INT
560 * notifications. Don't reenable interrupts automatically. The id
561 * that is passed back is the interrupt line number.
563 rep
->re_hook_id
= rep
->re_irq
;
564 if ((s
= sys_irqsetpolicy(rep
->re_irq
, 0, &rep
->re_hook_id
)) != OK
)
565 printf("RTL8169: error, couldn't set IRQ policy: %d\n", s
);
569 if ((s
= sys_irqenable(&rep
->re_hook_id
)) != OK
)
570 printf("RTL8169: error, couldn't enable interrupts: %d\n", s
);
573 printf("%s: model: %s mac: 0x%08x\n",
574 rep
->re_name
, rep
->re_model
, rep
->re_mac
);
577 rl_confaddr(rep
, addr
);
580 printf("%s: Ethernet address ", rep
->re_name
);
581 for (i
= 0; i
< 6; i
++) {
582 printf("%x%c", addr
->ea_addr
[i
],
588 static void rtl8169s_phy_config(port_t port
)
590 mdio_write(port
, 0x1f, 0x0001);
591 mdio_write(port
, 0x06, 0x006e);
592 mdio_write(port
, 0x08, 0x0708);
593 mdio_write(port
, 0x15, 0x4000);
594 mdio_write(port
, 0x18, 0x65c7);
596 mdio_write(port
, 0x1f, 0x0001);
597 mdio_write(port
, 0x03, 0x00a1);
598 mdio_write(port
, 0x02, 0x0008);
599 mdio_write(port
, 0x01, 0x0120);
600 mdio_write(port
, 0x00, 0x1000);
601 mdio_write(port
, 0x04, 0x0800);
602 mdio_write(port
, 0x04, 0x0000);
604 mdio_write(port
, 0x03, 0xff41);
605 mdio_write(port
, 0x02, 0xdf60);
606 mdio_write(port
, 0x01, 0x0140);
607 mdio_write(port
, 0x00, 0x0077);
608 mdio_write(port
, 0x04, 0x7800);
609 mdio_write(port
, 0x04, 0x7000);
611 mdio_write(port
, 0x03, 0x802f);
612 mdio_write(port
, 0x02, 0x4f02);
613 mdio_write(port
, 0x01, 0x0409);
614 mdio_write(port
, 0x00, 0xf0f9);
615 mdio_write(port
, 0x04, 0x9800);
616 mdio_write(port
, 0x04, 0x9000);
618 mdio_write(port
, 0x03, 0xdf01);
619 mdio_write(port
, 0x02, 0xdf20);
620 mdio_write(port
, 0x01, 0xff95);
621 mdio_write(port
, 0x00, 0xba00);
622 mdio_write(port
, 0x04, 0xa800);
623 mdio_write(port
, 0x04, 0xa000);
625 mdio_write(port
, 0x03, 0xff41);
626 mdio_write(port
, 0x02, 0xdf20);
627 mdio_write(port
, 0x01, 0x0140);
628 mdio_write(port
, 0x00, 0x00bb);
629 mdio_write(port
, 0x04, 0xb800);
630 mdio_write(port
, 0x04, 0xb000);
632 mdio_write(port
, 0x03, 0xdf41);
633 mdio_write(port
, 0x02, 0xdc60);
634 mdio_write(port
, 0x01, 0x6340);
635 mdio_write(port
, 0x00, 0x007d);
636 mdio_write(port
, 0x04, 0xd800);
637 mdio_write(port
, 0x04, 0xd000);
639 mdio_write(port
, 0x03, 0xdf01);
640 mdio_write(port
, 0x02, 0xdf20);
641 mdio_write(port
, 0x01, 0x100a);
642 mdio_write(port
, 0x00, 0xa0ff);
643 mdio_write(port
, 0x04, 0xf800);
644 mdio_write(port
, 0x04, 0xf000);
646 mdio_write(port
, 0x1f, 0x0000);
647 mdio_write(port
, 0x0b, 0x0000);
648 mdio_write(port
, 0x00, 0x9200);
651 static void rtl8169scd_phy_config(port_t port
)
653 mdio_write(port
, 0x1f, 0x0001);
654 mdio_write(port
, 0x04, 0x0000);
655 mdio_write(port
, 0x03, 0x00a1);
656 mdio_write(port
, 0x02, 0x0008);
657 mdio_write(port
, 0x01, 0x0120);
658 mdio_write(port
, 0x00, 0x1000);
659 mdio_write(port
, 0x04, 0x0800);
660 mdio_write(port
, 0x04, 0x9000);
661 mdio_write(port
, 0x03, 0x802f);
662 mdio_write(port
, 0x02, 0x4f02);
663 mdio_write(port
, 0x01, 0x0409);
664 mdio_write(port
, 0x00, 0xf099);
665 mdio_write(port
, 0x04, 0x9800);
666 mdio_write(port
, 0x04, 0xa000);
667 mdio_write(port
, 0x03, 0xdf01);
668 mdio_write(port
, 0x02, 0xdf20);
669 mdio_write(port
, 0x01, 0xff95);
670 mdio_write(port
, 0x00, 0xba00);
671 mdio_write(port
, 0x04, 0xa800);
672 mdio_write(port
, 0x04, 0xf000);
673 mdio_write(port
, 0x03, 0xdf01);
674 mdio_write(port
, 0x02, 0xdf20);
675 mdio_write(port
, 0x01, 0x101a);
676 mdio_write(port
, 0x00, 0xa0ff);
677 mdio_write(port
, 0x04, 0xf800);
678 mdio_write(port
, 0x04, 0x0000);
679 mdio_write(port
, 0x1f, 0x0000);
681 mdio_write(port
, 0x1f, 0x0001);
682 mdio_write(port
, 0x10, 0xf41b);
683 mdio_write(port
, 0x14, 0xfb54);
684 mdio_write(port
, 0x18, 0xf5c7);
685 mdio_write(port
, 0x1f, 0x0000);
687 mdio_write(port
, 0x1f, 0x0001);
688 mdio_write(port
, 0x17, 0x0cc0);
689 mdio_write(port
, 0x1f, 0x0000);
692 /*===========================================================================*
694 *===========================================================================*/
695 static void rl_reset_hw(re_t
*rep
)
701 port
= rep
->re_base_port
;
703 rl_outw(port
, RL_IMR
, 0x0000);
705 /* Reset the device */
706 rl_outb(port
, RL_CR
, RL_CR_RST
);
707 SPIN_UNTIL(!(rl_inb(port
, RL_CR
) & RL_CR_RST
), 1000000);
708 if (rl_inb(port
, RL_CR
) & RL_CR_RST
)
709 printf("rtl8169: reset failed to complete");
710 rl_outw(port
, RL_ISR
, 0xFFFF);
712 /* Get Model and MAC info */
713 t
= rl_inl(port
, RL_TCR
);
714 rep
->re_mac
= (t
& (RL_TCR_HWVER_AM
| RL_TCR_HWVER_BM
));
715 switch (rep
->re_mac
) {
716 case RL_TCR_HWVER_RTL8169
:
717 rep
->re_model
= "RTL8169";
719 rl_outw(port
, RL_CCR_UNDOC
, 0x01);
721 case RL_TCR_HWVER_RTL8169S
:
722 rep
->re_model
= "RTL8169S";
724 rtl8169s_phy_config(port
);
726 rl_outw(port
, RL_CCR_UNDOC
, 0x01);
727 mdio_write(port
, 0x0b, 0x0000); /* w 0x0b 15 0 0 */
729 case RL_TCR_HWVER_RTL8110S
:
730 rep
->re_model
= "RTL8110S";
732 rtl8169s_phy_config(port
);
734 rl_outw(port
, RL_CCR_UNDOC
, 0x01);
736 case RL_TCR_HWVER_RTL8169SB
:
737 rep
->re_model
= "RTL8169SB";
739 mdio_write(port
, 0x1f, 0x02);
740 mdio_write(port
, 0x01, 0x90d0);
741 mdio_write(port
, 0x1f, 0x00);
743 rl_outw(port
, RL_CCR_UNDOC
, 0x01);
745 case RL_TCR_HWVER_RTL8110SCd
:
746 rep
->re_model
= "RTL8110SCd";
748 rtl8169scd_phy_config(port
);
750 rl_outw(port
, RL_CCR_UNDOC
, 0x01);
752 case RL_TCR_HWVER_RTL8105E
:
753 rep
->re_model
= "RTL8105E";
756 rep
->re_model
= "Unknown";
761 mdio_write(port
, MII_CTRL
, MII_CTRL_RST
);
762 for (i
= 0; i
< 1000; i
++) {
763 t
= mdio_read(port
, MII_CTRL
);
764 if (!(t
& MII_CTRL_RST
))
770 t
= mdio_read(port
, MII_CTRL
);
771 t
|= MII_CTRL_ANE
| MII_CTRL_DM
| MII_CTRL_SP_1000
;
772 mdio_write(port
, MII_CTRL
, t
);
774 t
= mdio_read(port
, MII_ANA
);
775 t
|= MII_ANA_10THD
| MII_ANA_10TFD
| MII_ANA_100TXHD
| MII_ANA_100TXFD
;
776 t
|= MII_ANA_PAUSE_SYM
| MII_ANA_PAUSE_ASYM
;
777 mdio_write(port
, MII_ANA
, t
);
779 t
= mdio_read(port
, MII_1000_CTRL
) | 0x300;
780 mdio_write(port
, MII_1000_CTRL
, t
);
782 /* Restart Auto-Negotiation Process */
783 t
= mdio_read(port
, MII_CTRL
) | MII_CTRL_ANE
| MII_CTRL_RAN
;
784 mdio_write(port
, MII_CTRL
, t
);
786 rl_outw(port
, RL_9346CR
, RL_9346CR_EEM_CONFIG
); /* Unlock */
788 switch (rep
->re_mac
) {
789 case RL_TCR_HWVER_RTL8169S
:
790 case RL_TCR_HWVER_RTL8110S
:
791 /* Bit-3 and bit-14 of the C+CR register MUST be 1. */
792 t
= rl_inw(port
, RL_CPLUSCMD
);
793 rl_outw(port
, RL_CPLUSCMD
, t
| RL_CPLUS_MULRW
| (1 << 14));
795 case RL_TCR_HWVER_RTL8169
:
796 case RL_TCR_HWVER_RTL8169SB
:
797 case RL_TCR_HWVER_RTL8110SCd
:
798 t
= rl_inw(port
, RL_CPLUSCMD
);
799 rl_outw(port
, RL_CPLUSCMD
, t
| RL_CPLUS_MULRW
);
803 rl_outw(port
, RL_INTRMITIGATE
, 0x00);
805 t
= rl_inb(port
, RL_CR
);
806 rl_outb(port
, RL_CR
, t
| RL_CR_RE
| RL_CR_TE
);
809 rl_outw(port
, RL_RMS
, RX_BUFSIZE
); /* Maximum rx packet size */
810 t
= rl_inl(port
, RL_RCR
) & RX_CONFIG_MASK
;
811 rl_outl(port
, RL_RCR
, RL_RCR_RXFTH_UNLIM
| RL_RCR_MXDMA_1024
| t
);
812 rl_outl(port
, RL_RDSAR_LO
, rep
->p_rx_desc
);
813 rl_outl(port
, RL_RDSAR_HI
, 0x00); /* For 64 bit */
816 rl_outw(port
, RL_ETTHR
, 0x3f); /* No early transmit */
817 rl_outl(port
, RL_TCR
, RL_TCR_MXDMA_2048
| RL_TCR_IFG_STD
);
818 rl_outl(port
, RL_TNPDS_LO
, rep
->p_tx_desc
);
819 rl_outl(port
, RL_TNPDS_HI
, 0x00); /* For 64 bit */
821 rl_outw(port
, RL_9346CR
, RL_9346CR_EEM_NORMAL
); /* Lock */
823 rl_outw(port
, RL_MPC
, 0x00);
824 rl_outw(port
, RL_MULINT
, rl_inw(port
, RL_MULINT
) & 0xF000);
825 rl_outw(port
, RL_IMR
, RE_INTR_MASK
);
828 /*===========================================================================*
830 *===========================================================================*/
831 static void rl_confaddr(re_t
*rep
, ether_addr_t
*addr
)
833 static char eakey
[] = RL_ENVVAR
"#_EA";
834 static char eafmt
[] = "x:x:x:x:x:x";
840 /* User defined ethernet address? */
841 eakey
[sizeof(RL_ENVVAR
)-1] = '0' + re_instance
;
843 port
= rep
->re_base_port
;
845 for (i
= 0; i
< 6; i
++) {
846 if (env_parse(eakey
, eafmt
, i
, &v
, 0x00L
, 0xFFL
) != EP_SET
)
848 addr
->ea_addr
[i
] = v
;
851 if (i
!= 0 && i
!= 6)
852 env_panic(eakey
); /* It's all or nothing */
854 /* Should update ethernet address in hardware */
856 port
= rep
->re_base_port
;
857 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_CONFIG
);
859 for (i
= 0; i
< 4; i
++)
860 w
|= (addr
->ea_addr
[i
] << (i
* 8));
861 rl_outl(port
, RL_IDR
, w
);
863 for (i
= 4; i
< 6; i
++)
864 w
|= (addr
->ea_addr
[i
] << ((i
-4) * 8));
865 rl_outl(port
, RL_IDR
+ 4, w
);
866 rl_outb(port
, RL_9346CR
, RL_9346CR_EEM_NORMAL
);
869 /* Get ethernet address */
870 for (i
= 0; i
< 6; i
++)
871 addr
->ea_addr
[i
] = rl_inb(port
, RL_IDR
+i
);
874 /*===========================================================================*
876 *===========================================================================*/
877 static void rl_rec_mode(re_t
*rep
)
881 u32_t mc_filter
[2]; /* Multicast hash filter */
883 port
= rep
->re_base_port
;
885 mc_filter
[1] = mc_filter
[0] = 0xffffffff;
886 rl_outl(port
, RL_MAR
+ 0, mc_filter
[0]);
887 rl_outl(port
, RL_MAR
+ 4, mc_filter
[1]);
889 rcr
= rl_inl(port
, RL_RCR
);
890 rcr
&= ~(RL_RCR_AB
| RL_RCR_AM
| RL_RCR_APM
| RL_RCR_AAP
);
891 if (rep
->re_mode
& NDEV_PROMISC
)
892 rcr
|= RL_RCR_AB
| RL_RCR_AM
| RL_RCR_AAP
;
893 if (rep
->re_mode
& NDEV_BROAD
)
895 if (rep
->re_mode
& NDEV_MULTI
)
898 rl_outl(port
, RL_RCR
, RL_RCR_RXFTH_UNLIM
| RL_RCR_MXDMA_1024
| rcr
);
901 /*===========================================================================*
903 *===========================================================================*/
904 static ssize_t
rl_recv(struct netdriver_data
*data
, size_t max
)
908 unsigned totlen
, packlen
;
915 port
= rep
->re_base_port
;
917 if (rl_inb(port
, RL_CR
) & RL_CR_BUFE
)
918 return SUSPEND
; /* Receive buffer is empty, suspend */
920 index
= rep
->re_rx_head
;
921 desc
= rep
->re_rx_desc
;
925 rxstat
= desc
->status
;
927 if (rxstat
& DESC_OWN
)
930 if (rxstat
& DESC_RX_CRC
)
931 rep
->re_stat
.ets_CRCerr
++;
933 if ((rxstat
& (DESC_FS
| DESC_LS
)) == (DESC_FS
| DESC_LS
))
937 printf("rl_recv: packet is fragmented\n");
939 /* Fix the fragmented packet */
940 if (index
== N_RX_DESC
- 1) {
941 desc
->status
= DESC_EOR
| DESC_OWN
|
942 (RX_BUFSIZE
& DESC_RX_LENMASK
);
944 desc
= rep
->re_rx_desc
;
946 desc
->status
= DESC_OWN
|
947 (RX_BUFSIZE
& DESC_RX_LENMASK
);
951 /* Loop until we get correct packet */
954 totlen
= rxstat
& DESC_RX_LENMASK
;
955 if (totlen
< 8 || totlen
> 2 * ETH_MAX_PACK_SIZE
) {
956 /* Someting went wrong */
957 printf("rl_recv: bad length (%u) in status 0x%08x\n",
962 /* Should subtract the CRC */
963 packlen
= totlen
- ETH_CRC_SIZE
;
967 netdriver_copyout(data
, 0, rep
->re_rx
[index
].v_ret_buf
, packlen
);
969 rep
->re_stat
.ets_packetR
++;
971 if (index
== N_RX_DESC
- 1) {
972 desc
->status
= DESC_EOR
| DESC_OWN
|
973 (RX_BUFSIZE
& DESC_RX_LENMASK
);
976 desc
->status
= DESC_OWN
| (RX_BUFSIZE
& DESC_RX_LENMASK
);
979 rep
->re_rx_head
= index
;
980 assert(rep
->re_rx_head
< N_RX_DESC
);
985 /*===========================================================================*
987 *===========================================================================*/
988 static int rl_send(struct netdriver_data
*data
, size_t size
)
996 tx_head
= rep
->re_tx_head
;
998 desc
= rep
->re_tx_desc
;
1002 assert(rep
->re_tx_desc
);
1003 assert(rep
->re_tx_head
>= 0 && rep
->re_tx_head
< N_TX_DESC
);
1005 if (rep
->re_tx
[tx_head
].ret_busy
)
1008 netdriver_copyin(data
, 0, rep
->re_tx
[tx_head
].v_ret_buf
, size
);
1010 rep
->re_tx
[tx_head
].ret_busy
= TRUE
;
1013 if (tx_head
== N_TX_DESC
- 1) {
1014 desc
->status
= DESC_EOR
| DESC_OWN
| DESC_FS
| DESC_LS
| size
;
1017 desc
->status
= DESC_OWN
| DESC_FS
| DESC_LS
| size
;
1021 assert(tx_head
< N_TX_DESC
);
1022 rep
->re_tx_head
= tx_head
;
1024 rl_outl(rep
->re_base_port
, RL_TPPOLL
, RL_TPPOLL_NPQ
);
1029 /*===========================================================================*
1031 *===========================================================================*/
1032 static void rl_check_ints(re_t
*rep
)
1034 if (!rep
->re_got_int
)
1036 rep
->re_got_int
= FALSE
;
1040 if (rep
->re_need_reset
)
1043 if (rep
->re_send_int
) {
1044 rep
->re_send_int
= FALSE
;
1049 if (rep
->re_report_link
) {
1050 rep
->re_report_link
= FALSE
;
1053 rl_report_link(rep
);
1058 /*===========================================================================*
1060 *===========================================================================*/
1062 static void rl_report_link(re_t
*rep
)
1067 port
= rep
->re_base_port
;
1069 mii_status
= rl_inb(port
, RL_PHYSTAT
);
1071 if (mii_status
& RL_STAT_LINK
) {
1072 rep
->re_link_up
= 1;
1073 printf("%s: link up at ", rep
->re_name
);
1075 rep
->re_link_up
= 0;
1076 printf("%s: link down\n", rep
->re_name
);
1080 if (mii_status
& RL_STAT_1000
)
1081 printf("1000 Mbps");
1082 else if (mii_status
& RL_STAT_100
)
1084 else if (mii_status
& RL_STAT_10
)
1087 if (mii_status
& RL_STAT_FULLDUP
)
1088 printf(", full duplex");
1090 printf(", half duplex");
1097 /*===========================================================================*
1099 *===========================================================================*/
1100 static void rl_do_reset(re_t
*rep
)
1102 rep
->re_need_reset
= FALSE
;
1106 rep
->re_tx_head
= 0;
1107 if (rep
->re_tx
[rep
->re_tx_head
].ret_busy
)
1109 rep
->re_tx
[rep
->re_tx_head
].ret_busy
= FALSE
;
1110 rep
->re_send_int
= TRUE
;
1113 /*===========================================================================*
1115 *===========================================================================*/
1116 static void rl_stat(eth_stat_t
*stat
)
1118 memcpy(stat
, &re_state
.re_stat
, sizeof(*stat
));
1122 static void dump_phy(const re_t
*rep
)
1127 port
= rep
->re_base_port
;
1129 t
= rl_inb(port
, RL_CONFIG0
);
1130 printf("CONFIG0\t\t:");
1131 t
= t
& RL_CFG0_ROM
;
1132 if (t
== RL_CFG0_ROM128K
)
1133 printf(" 128K Boot ROM");
1134 else if (t
== RL_CFG0_ROM64K
)
1135 printf(" 64K Boot ROM");
1136 else if (t
== RL_CFG0_ROM32K
)
1137 printf(" 32K Boot ROM");
1138 else if (t
== RL_CFG0_ROM16K
)
1139 printf(" 16K Boot ROM");
1140 else if (t
== RL_CFG0_ROM8K
)
1141 printf(" 8K Boot ROM");
1142 else if (t
== RL_CFG0_ROMNO
)
1143 printf(" No Boot ROM");
1146 t
= rl_inb(port
, RL_CONFIG1
);
1147 printf("CONFIG1\t\t:");
1148 if (t
& RL_CFG1_LEDS1
)
1150 if (t
& RL_CFG1_LEDS0
)
1152 if (t
& RL_CFG1_DVRLOAD
)
1154 if (t
& RL_CFG1_LWACT
)
1156 if (t
& RL_CFG1_IOMAP
)
1158 if (t
& RL_CFG1_MEMMAP
)
1160 if (t
& RL_CFG1_VPD
)
1162 if (t
& RL_CFG1_PME
)
1166 t
= rl_inb(port
, RL_CONFIG2
);
1167 printf("CONFIG2\t\t:");
1168 if (t
& RL_CFG2_AUX
)
1170 if (t
& RL_CFG2_PCIBW
)
1171 printf(" PCI-64-Bit");
1173 printf(" PCI-32-Bit");
1174 t
= t
& RL_CFG2_PCICLK
;
1175 if (t
== RL_CFG2_66MHZ
)
1177 else if (t
== RL_CFG2_33MHZ
)
1181 t
= mdio_read(port
, MII_CTRL
);
1182 printf("MII_CTRL\t:");
1183 if (t
& MII_CTRL_RST
)
1185 if (t
& MII_CTRL_LB
)
1186 printf(" Loopback");
1187 if (t
& MII_CTRL_ANE
)
1189 if (t
& MII_CTRL_PD
)
1190 printf(" Power-down");
1191 if (t
& MII_CTRL_ISO
)
1193 if (t
& MII_CTRL_RAN
)
1195 if (t
& MII_CTRL_DM
)
1196 printf(" Full-duplex");
1197 if (t
& MII_CTRL_CT
)
1198 printf(" COL-signal");
1199 t
= t
& (MII_CTRL_SP_LSB
| MII_CTRL_SP_MSB
);
1200 if (t
== MII_CTRL_SP_10
)
1202 else if (t
== MII_CTRL_SP_100
)
1203 printf(" 100 Mb/s");
1204 else if (t
== MII_CTRL_SP_1000
)
1205 printf(" 1000 Mb/s");
1208 t
= mdio_read(port
, MII_STATUS
);
1209 printf("MII_STATUS\t:");
1210 if (t
& MII_STATUS_100T4
)
1211 printf(" 100Base-T4");
1212 if (t
& MII_STATUS_100XFD
)
1213 printf(" 100BaseX-FD");
1214 if (t
& MII_STATUS_100XHD
)
1215 printf(" 100BaseX-HD");
1216 if (t
& MII_STATUS_10FD
)
1217 printf(" 10Mbps-FD");
1218 if (t
& MII_STATUS_10HD
)
1219 printf(" 10Mbps-HD");
1220 if (t
& MII_STATUS_100T2FD
)
1221 printf(" 100Base-T2-FD");
1222 if (t
& MII_STATUS_100T2HD
)
1223 printf(" 100Base-T2-HD");
1224 if (t
& MII_STATUS_EXT_STAT
)
1225 printf(" Ext-stat");
1226 if (t
& MII_STATUS_RES
)
1227 printf(" res-0x%x", t
& MII_STATUS_RES
);
1228 if (t
& MII_STATUS_MFPS
)
1230 if (t
& MII_STATUS_ANC
)
1232 if (t
& MII_STATUS_RF
)
1233 printf(" remote-fault");
1234 if (t
& MII_STATUS_ANA
)
1236 if (t
& MII_STATUS_LS
)
1238 if (t
& MII_STATUS_JD
)
1240 if (t
& MII_STATUS_EC
)
1241 printf(" Extended-capability");
1244 t
= mdio_read(port
, MII_ANA
);
1245 printf("MII_ANA\t\t: 0x%04x\n", t
);
1247 t
= mdio_read(port
, MII_ANLPA
);
1248 printf("MII_ANLPA\t: 0x%04x\n", t
);
1250 t
= mdio_read(port
, MII_ANE
);
1251 printf("MII_ANE\t\t:");
1252 if (t
& MII_ANE_RES
)
1253 printf(" res-0x%x", t
& MII_ANE_RES
);
1254 if (t
& MII_ANE_PDF
)
1255 printf(" Par-Detect-Fault");
1256 if (t
& MII_ANE_LPNPA
)
1257 printf(" LP-Next-Page-Able");
1258 if (t
& MII_ANE_NPA
)
1259 printf(" Loc-Next-Page-Able");
1261 printf(" Page-Received");
1262 if (t
& MII_ANE_LPANA
)
1263 printf(" LP-Auto-Neg-Able");
1266 t
= mdio_read(port
, MII_1000_CTRL
);
1267 printf("MII_1000_CTRL\t:");
1268 if (t
& MII_1000C_FULL
)
1269 printf(" 1000BaseT-FD");
1270 if (t
& MII_1000C_HALF
)
1271 printf(" 1000BaseT-HD");
1274 t
= mdio_read(port
, MII_1000_STATUS
);
1276 printf("MII_1000_STATUS\t:");
1277 if (t
& MII_1000S_LRXOK
)
1278 printf(" Local-Receiver");
1279 if (t
& MII_1000S_RRXOK
)
1280 printf(" Remote-Receiver");
1281 if (t
& MII_1000S_HALF
)
1282 printf(" 1000BaseT-HD");
1283 if (t
& MII_1000S_FULL
)
1284 printf(" 1000BaseT-FD");
1287 t
= mdio_read(port
, MII_EXT_STATUS
);
1288 printf("MII_EXT_STATUS\t:");
1289 if (t
& MII_ESTAT_1000XFD
)
1290 printf(" 1000BaseX-FD");
1291 if (t
& MII_ESTAT_1000XHD
)
1292 printf(" 1000BaseX-HD");
1293 if (t
& MII_ESTAT_1000TFD
)
1294 printf(" 1000BaseT-FD");
1295 if (t
& MII_ESTAT_1000THD
)
1296 printf(" 1000BaseT-HD");
1302 /*===========================================================================*
1304 *===========================================================================*/
1305 static void rl_intr(unsigned int __unused mask
)
1312 /* Run interrupt handler at driver level. */
1315 /* Reenable interrupts for this hook. */
1316 if ((s
= sys_irqenable(&rep
->re_hook_id
)) != OK
)
1317 printf("RTL8169: error, couldn't enable interrupts: %d\n", s
);
1319 /* Perform tasks based on the flagged conditions. */
1323 /*===========================================================================*
1325 *===========================================================================*/
1326 static void rl_handler(re_t
*rep
)
1328 int i
, port
, tx_head
, tx_tail
, link_up
;
1332 port
= rep
->re_base_port
;
1335 isr
= rl_inw(port
, RL_ISR
);
1338 rl_outw(port
, RL_ISR
, isr
);
1341 if (isr
& RL_IMR_FOVW
) {
1342 isr
&= ~RL_IMR_FOVW
;
1343 /* Should do anything? */
1345 rep
->re_stat
.ets_fifoOver
++;
1347 if (isr
& RL_IMR_PUN
) {
1351 * Either the link status changed or there was a TX fifo
1354 link_up
= !(!(rl_inb(port
, RL_PHYSTAT
) & RL_STAT_LINK
));
1355 if (link_up
!= rep
->re_link_up
) {
1356 rep
->re_report_link
= TRUE
;
1357 rep
->re_got_int
= TRUE
;
1361 if (isr
& (RL_ISR_RDU
| RL_ISR_RER
| RL_ISR_ROK
)) {
1362 if (isr
& RL_ISR_RER
)
1363 rep
->re_stat
.ets_recvErr
++;
1364 isr
&= ~(RL_ISR_RDU
| RL_ISR_RER
| RL_ISR_ROK
);
1366 rep
->re_got_int
= TRUE
;
1369 if ((isr
& (RL_ISR_TDU
| RL_ISR_TER
| RL_ISR_TOK
)) || 1) {
1370 if (isr
& RL_ISR_TER
)
1371 rep
->re_stat
.ets_sendErr
++;
1372 isr
&= ~(RL_ISR_TDU
| RL_ISR_TER
| RL_ISR_TOK
);
1374 /* Transmit completed */
1375 tx_head
= rep
->re_tx_head
;
1376 tx_tail
= tx_head
+1;
1377 if (tx_tail
>= N_TX_DESC
)
1379 for (i
= 0; i
< 2 * N_TX_DESC
; i
++) {
1380 if (!rep
->re_tx
[tx_tail
].ret_busy
) {
1381 /* Strange, this buffer is not in-use.
1382 * Increment tx_tail until tx_head is
1383 * reached (or until we find a buffer that
1386 if (tx_tail
== tx_head
)
1388 if (++tx_tail
>= N_TX_DESC
)
1390 assert(tx_tail
< N_TX_DESC
);
1393 desc
= rep
->re_tx_desc
;
1395 if (desc
->status
& DESC_OWN
) {
1396 /* Buffer is not yet ready */
1400 rep
->re_stat
.ets_packetT
++;
1401 rep
->re_tx
[tx_tail
].ret_busy
= FALSE
;
1404 if (++tx_tail
>= N_TX_DESC
)
1406 assert(tx_tail
< N_TX_DESC
);
1408 rep
->re_send_int
= TRUE
;
1409 rep
->re_got_int
= TRUE
;
1410 rep
->re_tx_alive
= TRUE
;
1412 assert(i
< 2 * N_TX_DESC
);
1415 /* Ignore Reserved Interrupt */
1416 if (isr
& RL_ISR_RES
)
1420 printf("rl_handler: unhandled interrupt isr = 0x%04x\n", isr
);
1423 /*===========================================================================*
1425 *===========================================================================*/
1426 static void rl_alarm(clock_t __unused stamp
)
1430 /* Use a synchronous alarm instead of a watchdog timer. */
1431 sys_setalarm(sys_hz(), 0);
1435 /* Should collect statistics */
1436 if (!(++rep
->dtcc_counter
% RE_DTCC_VALUE
))
1437 rtl8169_update_stat(rep
);
1439 assert(rep
->re_tx_busy
>= 0 && rep
->re_tx_busy
<= N_TX_DESC
);
1440 if (rep
->re_tx_busy
== 0) {
1441 /* Assume that an idle system is alive */
1442 rep
->re_tx_alive
= TRUE
;
1445 if (rep
->re_tx_alive
) {
1446 rep
->re_tx_alive
= FALSE
;
1449 printf("rl_alarm: resetting instance %d\n", re_instance
);
1450 printf("tx_head :%8d busy %d\t",
1451 rep
->re_tx_head
, rep
->re_tx
[rep
->re_tx_head
].ret_busy
);
1452 rep
->re_need_reset
= TRUE
;
1453 rep
->re_got_int
= TRUE
;