diff --git a/drivers/Makefile b/drivers/Makefile index c121e6b0e..4e3156125 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -23,6 +23,7 @@ all install depend clean: cd ./floppy && $(MAKE) $@ cd ./printer && $(MAKE) $@ cd ./rtl8139 && $(MAKE) $@ + cd ./rtl8169 && $(MAKE) $@ cd ./orinoco && $(MAKE) $@ cd ./fxp && $(MAKE) $@ cd ./dpeth && $(MAKE) $@ diff --git a/drivers/pci/pci_table.c b/drivers/pci/pci_table.c index c38a23cc4..3c401bab9 100644 --- a/drivers/pci/pci_table.c +++ b/drivers/pci/pci_table.c @@ -37,8 +37,13 @@ struct pci_vendor pci_vendor_table[]= { 0x10EC, "Realtek" }, { 0x1106, "VIA" }, { 0x110A, "Siemens Nixdorf AG" }, + { 0x1186, "D-Link" }, { 0x125D, "ESS Technology" }, + { 0x1259, "Allied Telesyn International" }, { 0x1274, "Ensoniq" }, + { 0x1385, "Netgear" }, + { 0x16ec, "US Robotics" }, + { 0x1737, "Linksys" }, { 0x5333, "S3" }, { 0x8086, "Intel" }, { 0x9004, "Adaptec" }, @@ -83,7 +88,10 @@ struct pci_device pci_device_table[]= { 0x10DE, 0x0020, "nVidia Riva TnT [NV04]" }, { 0x10DE, 0x0110, "nVidia GeForce2 MX [NV11]" }, { 0x10EC, 0x8029, "Realtek RTL8029" }, + { 0x10EC, 0x8129, "Realtek RTL8129" }, { 0x10EC, 0x8139, "Realtek RTL8139" }, + { 0x10EC, 0x8167, "Realtek RTL8169/8110 Family Gigabit NIC" }, + { 0x10EC, 0x8169, "Realtek RTL8169" }, { 0x1106, 0x0305, "VIA VT8363/8365 [KT133/KM133]" }, { 0x1106, 0x0571, "VIA IDE controller" }, { 0x1106, 0x0686, "VIA VT82C686 (Apollo South Bridge)" }, @@ -107,10 +115,15 @@ struct pci_device pci_device_table[]= { 0x1106, 0xB188, "VT8237 PCI bridge" }, { 0x110A, 0x0005, "Siemens Nixdorf Tulip Cntlr., Power Management" }, { 0x1186, 0x1300, "D-Link RTL8139" }, + { 0x1186, 0x4300, "D-Link Gigabit adapter" }, + { 0x1259, 0xc107, "Allied Telesyn International Gigabit Ethernet Adapter" }, { 0x125D, 0x1969, "ESS ES1969 Solo-1 Audiodrive" }, { 0x1274, 0x1371, "Ensoniq ES1371 [AudioPCI-97]" }, { 0x1274, 0x5000, "Ensoniq ES1370" }, { 0x1274, 0x5880, "Ensoniq CT5880 [AudioPCI]" }, + { 0x1385, 0x8169, "Netgear Gigabit Ethernet Adapter" }, + { 0x16ec, 0x0116, "US Robotics Realtek 8169S chip" }, + { 0x1737, 0x1032, "Linksys Instant Gigabit Desktop Network Interface" }, { 0x5333, 0x8811, "S3 86c764/765 [Trio32/64/64V+]" }, { 0x5333, 0x883d, "S3 Virge/VX" }, { 0x5333, 0x88d0, "S3 Vision 964 vers 0" }, diff --git a/drivers/rtl8169/Makefile b/drivers/rtl8169/Makefile new file mode 100644 index 000000000..0d9403a60 --- /dev/null +++ b/drivers/rtl8169/Makefile @@ -0,0 +1,41 @@ +# Makefile for the Realtek RTL8169 ethernet driver (RTL8169) +DRIVER = rtl8169 + +# directories +u = /usr +i = $u/include +s = $i/sys +m = $i/minix +b = $i/ibm +d = .. + +# programs, flags, etc. +MAKE = exec make +CC = exec cc +CFLAGS = -I$i $(CPROFILE) +LDFLAGS = -i +LIBS = -lsys -ltimers + +OBJ = rtl8169.o + +# build local binary +all build: $(DRIVER) +$(DRIVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + install -S 64kw $(DRIVER) + +# install with other drivers +install: /usr/sbin/$(DRIVER) +/usr/sbin/$(DRIVER): $(DRIVER) + install -o root -cs $? $@ + +# clean up local files +clean: + rm -f $(DRIVER) *.o *.bak + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/drivers/rtl8169/rtl8169.c b/drivers/rtl8169/rtl8169.c new file mode 100644 index 000000000..e3de8e398 --- /dev/null +++ b/drivers/rtl8169/rtl8169.c @@ -0,0 +1,2136 @@ +/* + * rtl8169.c + * + * This file contains a ethernet device driver for Realtek rtl8169 based + * ethernet cards. + * + */ + +#include "../drivers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "../../kernel/const.h" +#include "../../kernel/config.h" +#include "../../kernel/type.h" + +#define tmra_ut timer_t +#define tmra_inittimer(tp) tmr_inittimer(tp) +#define Proc_number(p) proc_number(p) +#define debug 1 +#define printW() ((void)0) + +#define VERBOSE 0 /* display message during init */ + +#include "rtl8169.h" + +#define RE_PORT_NR 1 /* Minix */ + +#define IOVEC_NR 16 /* I/O vectors are handled IOVEC_NR entries at a time. */ + +#define RE_DTCC_VALUE 600 /* DTCC Update after every 10 minutes */ + +#define RX_CONFIG_MASK 0xff7e1880 /* Clears the bits supported by chip */ + +#define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK) + +#define RL_ENVVAR "RTLETH" /* Configuration */ + +PRIVATE struct pcitab +{ + u16_t vid; + u16_t did; + int checkclass; +} pcitab[] = +{ + { 0x10ec, 0x8129, 0 }, /* Realtek RTL8129 */ + { 0x10ec, 0x8167, 0 }, /* Realtek RTL8169/8110 Family Gigabit NIC */ + { 0x10ec, 0x8169, 0 }, /* Realtek RTL8169 */ + + { 0x1186, 0x4300, 0 }, /* D-Link DGE-528T Gigabit adaptor */ + + { 0x1259, 0xc107, 0 }, /* Allied Telesyn International Gigabit Ethernet Adapter */ + + { 0x1385, 0x8169, 0 }, /* Netgear Gigabit Ethernet Adapter */ + + { 0x16ec, 0x0116, 0 }, /* US Robotics Realtek 8169S chip */ + + { 0x1737, 0x1032, 0 }, /* Linksys Instant Gigabit Desktop Network Interface */ + + { 0x0000, 0x0000, 0 } +}; + +typedef struct re_desc +{ + u32_t status; /* command/status */ + u32_t vlan; /* VLAN */ + u32_t addr_low; /* low 32-bits of physical buffer address */ + u32_t addr_high; /* high 32-bits of physical buffer address */ +} re_desc; + +typedef struct re_dtcc +{ + u32_t TxOk_low; /* low 32-bits of Tx Ok packets */ + u32_t TxOk_high; /* high 32-bits of Tx Ok packets */ + u32_t RxOk_low; /* low 32-bits of Rx Ok packets */ + u32_t RxOk_high; /* high 32-bits of Rx Ok packets */ + u32_t TxEr_low; /* low 32-bits of Tx errors */ + u32_t TxEr_high; /* high 32-bits of Tx errors */ + u32_t RxEr; /* Rx errors */ + u16_t MissPkt; /* Missed packets */ + u16_t FAE; /* Frame Aignment Error packets (MII mode only) */ + u32_t Tx1Col; /* Tx Ok packets with only 1 collision happened before Tx Ok */ + u32_t TxMCol; /* Tx Ok packets with > 1 and < 16 collisions happened before Tx Ok */ + u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets with physical addr destination ID */ + u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets with physical addr destination ID */ + u32_t RxOkBrd_low; /* low 32-bits of Rx Ok packets with broadcast destination ID */ + u32_t RxOkBrd_high; /* high 32-bits of Rx Ok packets with broadcast destination ID */ + u32_t RxOkMul; /* Rx Ok Packets with multicast destination ID */ + u16_t TxAbt; /* Tx abort packets */ + u16_t TxUndrn; /* Tx underrun packets */ +} re_dtcc; + +typedef struct re { + port_t re_base_port; + int re_irq; + int re_mode; + int re_flags; + endpoint_t re_client; + int re_link_up; + int re_got_int; + int re_send_int; + int re_report_link; + int re_need_reset; + int re_tx_alive; + int setup; + u32_t re_mac; + char *re_model; + + /* Rx */ + int re_rx_head; + struct { + int ret_busy; + phys_bytes ret_buf; + char *v_ret_buf; + } re_rx[N_RX_DESC]; + + vir_bytes re_read_s; + re_desc *re_rx_desc; /* Rx descriptor buffer */ + phys_bytes p_rx_desc; /* Rx descriptor buffer physical */ + + /* Tx */ + int re_tx_head; + struct { + int ret_busy; + phys_bytes ret_buf; + char *v_ret_buf; + } re_tx[N_TX_DESC]; + re_desc *re_tx_desc; /* Tx descriptor buffer */ + phys_bytes p_tx_desc; /* Tx descriptor buffer physical */ + + /* PCI related */ + int re_seen; /* TRUE iff device available */ + u8_t re_pcibus; + u8_t re_pcidev; + u8_t re_pcifunc; + + /* 'large' items */ + int re_hook_id; /* IRQ hook id at kernel */ + eth_stat_t re_stat; + phys_bytes dtcc_buf; /* Dump Tally Counter buffer physical */ + re_dtcc *v_dtcc_buf; /* Dump Tally Counter buffer */ + u32_t dtcc_counter; /* DTCC update counter */ + ether_addr_t re_address; + message re_rx_mess; + message re_tx_mess; + char re_name[sizeof("rtl8169#n")]; + iovec_t re_iovec[IOVEC_NR]; + iovec_s_t re_iovec_s[IOVEC_NR]; + u32_t interrupts; +} +re_t; + +#define REM_DISABLED 0x0 +#define REM_ENABLED 0x1 + +#define REF_PACK_SENT 0x001 +#define REF_PACK_RECV 0x002 +#define REF_SEND_AVAIL 0x004 +#define REF_READING 0x010 +#define REF_EMPTY 0x000 +#define REF_PROMISC 0x040 +#define REF_MULTI 0x080 +#define REF_BROAD 0x100 +#define REF_ENABLED 0x200 + +static re_t re_table[RE_PORT_NR]; + +static u16_t eth_ign_proto; +static tmra_ut rl_watchdog; + +FORWARD _PROTOTYPE(unsigned my_inb, (U16_t port)); +FORWARD _PROTOTYPE(unsigned my_inw, (U16_t port)); +FORWARD _PROTOTYPE(unsigned my_inl, (U16_t port)); +static unsigned my_inb(U16_t port) +{ + u32_t value; + int s; + if ((s = sys_inb(port, &value)) != OK) + printf("RTL8169: warning, sys_inb failed: %d\n", s); + return value; +} +static unsigned my_inw(U16_t port) +{ + u32_t value; + int s; + if ((s = sys_inw(port, &value)) != OK) + printf("RTL8169: warning, sys_inw failed: %d\n", s); + return value; +} +static unsigned my_inl(U16_t port) +{ + U32_t value; + int s; + if ((s = sys_inl(port, &value)) != OK) + printf("RTL8169: warning, sys_inl failed: %d\n", s); + return value; +} +#define rl_inb(port, offset) (my_inb((port) + (offset))) +#define rl_inw(port, offset) (my_inw((port) + (offset))) +#define rl_inl(port, offset) (my_inl((port) + (offset))) + +FORWARD _PROTOTYPE(void my_outb, (U16_t port, U8_t value)); +FORWARD _PROTOTYPE(void my_outw, (U16_t port, U16_t value)); +FORWARD _PROTOTYPE(void my_outl, (U16_t port, U32_t value)); +static void my_outb(U16_t port, U8_t value) +{ + int s; + + if ((s = sys_outb(port, value)) != OK) + printf("RTL8169: warning, sys_outb failed: %d\n", s); +} +static void my_outw(U16_t port, U16_t value) +{ + int s; + + if ((s = sys_outw(port, value)) != OK) + printf("RTL8169: warning, sys_outw failed: %d\n", s); +} +static void my_outl(U16_t port, U32_t value) +{ + int s; + + if ((s = sys_outl(port, value)) != OK) + printf("RTL8169: warning, sys_outl failed: %d\n", s); +} +#define rl_outb(port, offset, value) (my_outb((port) + (offset), (value))) +#define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) +#define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) + +_PROTOTYPE( static void rl_init, (message *mp) ); +_PROTOTYPE( static void rl_pci_conf, (void) ); +_PROTOTYPE( static int rl_probe, (re_t *rep) ); +_PROTOTYPE( static void rl_conf_hw, (re_t *rep) ); +_PROTOTYPE( static void rl_init_buf, (re_t *rep) ); +_PROTOTYPE( static void rl_init_hw, (re_t *rep) ); +_PROTOTYPE( static void rl_reset_hw, (re_t *rep) ); +_PROTOTYPE( static void rl_confaddr, (re_t *rep) ); +_PROTOTYPE( static void rl_rec_mode, (re_t *rep) ); +_PROTOTYPE( static void rl_readv_s, (message *mp, int from_int) ); +_PROTOTYPE( static void rl_writev_s, (message *mp, int from_int) ); +_PROTOTYPE( static void rl_check_ints, (re_t *rep) ); +_PROTOTYPE( static void rl_report_link, (re_t *rep) ); +_PROTOTYPE( static void rl_do_reset, (re_t *rep) ); +_PROTOTYPE( static void rl_getstat, (message *mp) ); +_PROTOTYPE( static void rl_getstat_s, (message *mp) ); +_PROTOTYPE( static void rl_getname, (message *mp) ); +_PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) ); +_PROTOTYPE( static void mess_reply, (message *req, message *reply) ); +_PROTOTYPE( static void rtl8169_stop, (void) ); +_PROTOTYPE( static void check_int_events, (void) ); +_PROTOTYPE( static void do_hard_int, (void) ); +_PROTOTYPE( static void rtl8169_dump, (void) ); +_PROTOTYPE( static void dump_phy, (re_t *rep) ); +_PROTOTYPE( static int rl_handler, (re_t *rep) ); +_PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) ); + +/* + * The message used in the main loop is made global, so that rl_watchdog_f() + * can change its message type to fake an interrupt message. + */ +PRIVATE message m; +PRIVATE int int_event_check; /* set to TRUE if events arrived */ + +static char *progname; +u32_t system_hz; + +/*===========================================================================* + * main * + *===========================================================================*/ +int main(int argc, char *argv[]) +{ + u32_t inet_proc_nr; + int r; + re_t *rep; + long v; + + system_hz = sys_hz(); + + (progname = strrchr(argv[0], '/')) ? progname++ : (progname = argv[0]); + + env_setargs(argc, argv); + + v = 0; + (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL); + eth_ign_proto = htons((u16_t) v); + + /* Claim buffer memory now under Minix, before MM takes it all. */ + for (rep = &re_table[0]; rep < re_table + RE_PORT_NR; rep++) + rl_init_buf(rep); + + /* + * Try to notify INET that we are present (again). If INET cannot + * be found, assume this is the first time we started and INET is + * not yet alive. + */ +#if 0 + r = ds_retrieve_u32("inet", &inet_proc_nr); + if (r == OK) + notify(inet_proc_nr); + else if (r != ESRCH) + printf("rtl8169: ds_retrieve_u32 failed for 'inet': %d\n", r); +#endif + while (TRUE) { + if ((r = receive(ANY, &m)) != OK) + panic("rtl8169", "receive failed", r); + + if (is_notify(m.m_type)) { + switch (_ENDPOINT_P(m.m_source)) { + case RS_PROC_NR: + notify(m.m_source); + break; + case CLOCK: + /* + * Under MINIX, synchronous alarms are used + * instead of watchdog functions. + * The approach is very different: MINIX VMD + * timeouts are handled within the kernel + * (the watchdog is executed by CLOCK), and + * notify() the driver in some cases. MINIX + * timeouts result in a SYN_ALARM message to + * the driver and thus are handled where they + * should be handled. Locally, watchdog + * functions are used again. + */ + rl_watchdog_f(NULL); + break; + case HARDWARE: + do_hard_int(); + if (int_event_check) { + check_int_events(); + } + break ; + case PM_PROC_NR: + { + sigset_t set; + + if (getsigset(&set) != 0) break; + + if (sigismember(&set, SIGTERM)) + rtl8169_stop(); + + break; + } + default: + panic("rtl8169", "illegal notify from", + m.m_type); + } + + /* done, get nwe message */ + continue; + } + + switch (m.m_type) { + case DL_WRITEV_S: rl_writev_s(&m, FALSE); break; + case DL_READV_S: rl_readv_s(&m, FALSE); break; + case DL_CONF: rl_init(&m); break; + case DL_GETSTAT: rl_getstat(&m); break; + case DL_GETSTAT_S: rl_getstat_s(&m); break; + case DL_GETNAME: rl_getname(&m); break; + default: + panic("rtl8169", "illegal message", m.m_type); + } + } +} + +static void mdio_write(U16_t port, int regaddr, int value) +{ + int i; + + rl_outl(port, RL_PHYAR, 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); + + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed writing to the specified + * MII register + */ + if (!(rl_inl(port, RL_PHYAR) & 0x80000000)) + break; + else + micro_delay(50); + } +} + +static int mdio_read(U16_t port, int regaddr) +{ + int i, value = -1; + + rl_outl(port, RL_PHYAR, (regaddr & 0x1F) << 16); + + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed retrieving data from + * the specified MII register + */ + if (rl_inl(port, RL_PHYAR) & 0x80000000) { + value = (int)(rl_inl(port, RL_PHYAR) & 0xFFFF); + break; + } else + micro_delay(50); + } + return value; +} + +/*===========================================================================* + * check_int_events * + *===========================================================================*/ +static void check_int_events(void) +{ + int i; + re_t *rep; + + for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) { + if (rep->re_mode != REM_ENABLED) + continue; + if (!rep->re_got_int) + continue; + rep->re_got_int = 0; + assert(rep->re_flags & REF_ENABLED); + rl_check_ints(rep); + } +} + +/*===========================================================================* + * rtl8169_stop * + *===========================================================================*/ +static void rtl8169_stop() +{ + int i; + re_t *rep; + + for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) { + if (rep->re_mode != REM_ENABLED) + continue; + rl_outb(rep->re_base_port, RL_CR, 0); + } + + exit(0); +} + +static void rtl8169_update_stat(re_t *rep) +{ + port_t port; + int i; + + port = rep->re_base_port; + + /* Fetch Missed Packets */ + rep->re_stat.ets_missedP += rl_inw(port, RL_MPC); + rl_outw(port, RL_MPC, 0x00); + + /* Dump Tally Counter Command */ + rl_outl(port, RL_DTCCR_HI, 0); /* 64 bits */ + rl_outl(port, RL_DTCCR_LO, rep->dtcc_buf | RL_DTCCR_CMD); + for (i = 0; i < 1000; i++) { + if (!(rl_inl(port, RL_DTCCR_LO) & RL_DTCCR_CMD)) + break; + micro_delay(10); + } + + /* Update counters */ + rep->re_stat.ets_frameAll = rep->v_dtcc_buf->FAE; + rep->re_stat.ets_transDef = rep->v_dtcc_buf->TxUndrn; + rep->re_stat.ets_transAb = rep->v_dtcc_buf->TxAbt; + rep->re_stat.ets_collision = + rep->v_dtcc_buf->Tx1Col + rep->v_dtcc_buf->TxMCol; +} + +/*===========================================================================* + * rtl8169_dump * + *===========================================================================*/ +static void rtl8169_dump(void) +{ + re_dtcc *dtcc; + re_t *rep; + int i; + + printf("\n"); + for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) { + if (rep->re_mode == REM_DISABLED) + printf("Realtek RTL 8169 port %d is disabled\n", i); + + if (rep->re_mode != REM_ENABLED) + continue; + + rtl8169_update_stat(rep); + + printf("Realtek RTL 8169 statistics of port %d:\n", i); + + printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr); + printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr); + printf("OVW :%8ld\n", rep->re_stat.ets_OVW); + + printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr); + printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll); + printf("missedP :%8ld\n", rep->re_stat.ets_missedP); + + printf("packetR :%8ld\t", rep->re_stat.ets_packetR); + printf("packetT :%8ld\t", rep->re_stat.ets_packetT); + printf("transDef :%8ld\n", rep->re_stat.ets_transDef); + + printf("collision :%8ld\t", rep->re_stat.ets_collision); + printf("transAb :%8ld\t", rep->re_stat.ets_transAb); + printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense); + + printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder); + printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver); + printf("OWC :%8ld\n", rep->re_stat.ets_OWC); + printf("interrupts :%8lu\n", rep->interrupts); + + printf("\nRealtek RTL 8169 Tally Counters:\n"); + + dtcc = rep->v_dtcc_buf; + + if (dtcc->TxOk_high) + printf("TxOk :%8ld%08ld\t", dtcc->TxOk_high, dtcc->TxOk_low); + else + printf("TxOk :%16lu\t", dtcc->TxOk_low); + + if (dtcc->RxOk_high) + printf("RxOk :%8ld%08ld\n", dtcc->RxOk_high, dtcc->RxOk_low); + else + printf("RxOk :%16lu\n", dtcc->RxOk_low); + + if (dtcc->TxEr_high) + printf("TxEr :%8ld%08ld\t", dtcc->TxEr_high, dtcc->TxEr_low); + else + printf("TxEr :%16ld\t", dtcc->TxEr_low); + + printf("RxEr :%16ld\n", dtcc->RxEr); + + printf("Tx1Col :%16ld\t", dtcc->Tx1Col); + printf("TxMCol :%16ld\n", dtcc->TxMCol); + + if (dtcc->RxOkPhy_high) + printf("RxOkPhy :%8ld%08ld\t", dtcc->RxOkPhy_high, dtcc->RxOkPhy_low); + else + printf("RxOkPhy :%16ld\t", dtcc->RxOkPhy_low); + + if (dtcc->RxOkBrd_high) + printf("RxOkBrd :%8ld%08ld\n", dtcc->RxOkBrd_high, dtcc->RxOkBrd_low); + else + printf("RxOkBrd :%16ld\n", dtcc->RxOkBrd_low); + + printf("RxOkMul :%16ld\t", dtcc->RxOkMul); + printf("MissPkt :%16d\n", dtcc->MissPkt); + + printf("\nRealtek RTL 8169 Miscellaneous Info:\n"); + + printf("re_flags : 0x%08x\n", rep->re_flags); + printf("tx_head :%8d busy %d\t", + rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); + } +} + +/*===========================================================================* + * do_init * + *===========================================================================*/ +static void rl_init(mp) +message *mp; +{ + static int first_time = 1; + + int port; + re_t *rep; + message reply_mess; + + if (first_time) { + first_time = 0; + rl_pci_conf(); /* Configure PCI devices. */ + + tmra_inittimer(&rl_watchdog); + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(system_hz, 0); + } + + port = mp->DL_PORT; + if (port < 0 || port >= RE_PORT_NR) { + reply_mess.m_type = DL_CONF_REPLY; + reply_mess.m3_i1 = ENXIO; + mess_reply(mp, &reply_mess); + return; + } + rep = &re_table[port]; + if (rep->re_mode == REM_DISABLED) { + /* This is the default, try to (re)locate the device. */ + rl_conf_hw(rep); + if (rep->re_mode == REM_DISABLED) { + /* Probe failed, or the device is configured off. */ + reply_mess.m_type = DL_CONF_REPLY; + reply_mess.m3_i1 = ENXIO; + mess_reply(mp, &reply_mess); + return; + } + if (rep->re_mode == REM_ENABLED) + rl_init_hw(rep); + } + + assert(rep->re_mode == REM_ENABLED); + assert(rep->re_flags & REF_ENABLED); + + rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD); + + if (mp->DL_MODE & DL_PROMISC_REQ) + rep->re_flags |= REF_PROMISC; + if (mp->DL_MODE & DL_MULTI_REQ) + rep->re_flags |= REF_MULTI; + if (mp->DL_MODE & DL_BROAD_REQ) + rep->re_flags |= REF_BROAD; + + rep->re_client = mp->m_source; + rl_rec_mode(rep); + + reply_mess.m_type = DL_CONF_REPLY; + reply_mess.m3_i1 = mp->DL_PORT; + reply_mess.m3_i2 = RE_PORT_NR; + *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address; + + mess_reply(mp, &reply_mess); +} + +/*===========================================================================* + * rl_pci_conf * + *===========================================================================*/ +static void rl_pci_conf() +{ + int i, h; + re_t *rep; + static char envvar[] = RL_ENVVAR "#"; + static char envfmt[] = "*:d.d.d"; + static char val[128]; + long v; + + for (i = 0, rep = re_table; i < RE_PORT_NR; i++, rep++) { + strcpy(rep->re_name, "rtl8169#0"); + rep->re_name[8] += i; + rep->re_seen = FALSE; + envvar[sizeof(RL_ENVVAR)-1] = '0' + i; + if (0 == env_get_param(envvar, val, sizeof(val)) && + !env_prefix(envvar, "pci")) + { + env_panic(envvar); + } + v = 0; + (void) env_parse(envvar, envfmt, 1, &v, 0, 255); + rep->re_pcibus = v; + v = 0; + (void) env_parse(envvar, envfmt, 2, &v, 0, 255); + rep->re_pcidev = v; + v = 0; + (void) env_parse(envvar, envfmt, 3, &v, 0, 255); + rep->re_pcifunc = v; + } + + pci_init(); + + for (h = 1; h >= 0; h--) { + for (i = 0, rep = re_table; i < RE_PORT_NR; i++, rep++) { + if (((rep->re_pcibus | rep->re_pcidev | + rep->re_pcifunc) != 0) != h) { + continue; + } + if (rl_probe(rep)) + rep->re_seen = TRUE; + } + } +} + +/*===========================================================================* + * rl_probe * + *===========================================================================*/ +static int rl_probe(rep) +re_t *rep; +{ + int i, r, devind, just_one; + u16_t vid, did; + u32_t bar; + u8_t ilr; + char *dname; + + if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0) { + /* Look for specific PCI device */ + r = pci_find_dev(rep->re_pcibus, rep->re_pcidev, + rep->re_pcifunc, &devind); + if (r == 0) { + printf("%s: no PCI found at %d.%d.%d\n", + rep->re_name, rep->re_pcibus, + rep->re_pcidev, rep->re_pcifunc); + return 0; + } + pci_ids(devind, &vid, &did); + just_one = TRUE; + } else { + r = pci_first_dev(&devind, &vid, &did); + if (r == 0) + return 0; + just_one = FALSE; + } + + for (;;) { + for (i = 0; pcitab[i].vid != 0; i++) { + if (pcitab[i].vid != vid) + continue; + if (pcitab[i].did != did) + continue; + if (pcitab[i].checkclass) { + panic("rtl_probe", + "class check not implemented", NO_NUM); + } + break; + } + if (pcitab[i].vid != 0) + break; + + if (just_one) { + printf("%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n", + rep->re_name, vid, did, + rep->re_pcibus, + rep->re_pcidev, rep->re_pcifunc); + return 0; + } + + r = pci_next_dev(&devind, &vid, &did); + if (!r) + return 0; + } + + dname = pci_dev_name(vid, did); + if (!dname) + dname = "unknown device"; + printf("%s: ", rep->re_name); + printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind)); + + pci_reserve(devind); + bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; + if (bar < 0x400) { + panic("rtl_probe", + "base address is not properly configured", NO_NUM); + } + rep->re_base_port = bar; + + ilr = pci_attr_r8(devind, PCI_ILR); + rep->re_irq = ilr; + if (debug) { + printf("%s: using I/O address 0x%lx, IRQ %d\n", + rep->re_name, (unsigned long)bar, ilr); + } + + return TRUE; +} + +/*===========================================================================* + * rl_conf_hw * + *===========================================================================*/ +static void rl_conf_hw(rep) +re_t *rep; +{ + static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; + + rep->re_mode = REM_DISABLED; /* Superfluous */ + + if (rep->re_seen) + rep->re_mode = REM_ENABLED; /* PCI device is present */ + if (rep->re_mode != REM_ENABLED) + return; + + rep->re_flags = REF_EMPTY; + rep->re_link_up = 0; + rep->re_got_int = 0; + rep->re_send_int = 0; + rep->re_report_link = 0; + rep->re_need_reset = 0; + rep->re_tx_alive = 0; + rep->re_rx_head = 0; + rep->re_read_s = 0; + rep->re_tx_head = 0; + rep->re_stat = empty_stat; + rep->dtcc_counter = 0; +} + +/*===========================================================================* + * rl_init_buf * + *===========================================================================*/ +static void rl_init_buf(rep) +re_t *rep; +{ + size_t rx_bufsize, tx_bufsize, rx_descsize, tx_descsize, tot_bufsize; + struct re_desc *desc; + phys_bytes buf; + char *mallocbuf; + int d; + + assert(!rep->setup); + + /* Allocate receive and transmit descriptors */ + rx_descsize = (N_RX_DESC * sizeof(struct re_desc)); + tx_descsize = (N_TX_DESC * sizeof(struct re_desc)); + + /* Allocate receive and transmit buffers */ + tx_bufsize = ETH_MAX_PACK_SIZE_TAGGED; + if (tx_bufsize % 4) + tx_bufsize += 4-(tx_bufsize % 4); /* Align */ + rx_bufsize = RX_BUFSIZE; + tot_bufsize = rx_descsize + tx_descsize; + tot_bufsize += (N_TX_DESC * tx_bufsize) + (N_RX_DESC * rx_bufsize); + tot_bufsize += sizeof(struct re_dtcc); + + if (tot_bufsize % 4096) + tot_bufsize += 4096 - (tot_bufsize % 4096); + + if (!(mallocbuf = alloc_contig(tot_bufsize, AC_ALIGN64K, &buf))) + panic("RTL8169", "Couldn't allocate kernel buffer", NO_NUM); + + /* Rx Descriptor */ + rep->re_rx_desc = (re_desc *)mallocbuf; + rep->p_rx_desc = buf; + memset(mallocbuf, 0x00, rx_descsize); + buf += rx_descsize; + mallocbuf += rx_descsize; + + /* Tx Descriptor */ + rep->re_tx_desc = (re_desc *)mallocbuf; + rep->p_tx_desc = buf; + memset(mallocbuf, 0x00, tx_descsize); + buf += tx_descsize; + mallocbuf += tx_descsize; + + desc = rep->re_rx_desc; + for (d = 0; d < N_RX_DESC; d++) { + /* Setting Rx buffer */ + rep->re_rx[d].ret_buf = buf; + rep->re_rx[d].v_ret_buf = mallocbuf; + buf += rx_bufsize; + mallocbuf += rx_bufsize; + + /* Setting Rx descriptor */ + if (d == (N_RX_DESC - 1)) /* Last descriptor? if so, set the EOR bit */ + desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + else + desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + + desc->addr_low = rep->re_rx[d].ret_buf; + desc++; + } + desc = rep->re_tx_desc; + for (d = 0; d < N_TX_DESC; d++) { + rep->re_tx[d].ret_busy = FALSE; + rep->re_tx[d].ret_buf = buf; + rep->re_tx[d].v_ret_buf = mallocbuf; + buf += tx_bufsize; + mallocbuf += tx_bufsize; + + /* Setting Tx descriptor */ + desc->addr_low = rep->re_tx[d].ret_buf; + desc++; + } + + /* Dump Tally Counter buffer */ + rep->dtcc_buf = buf; + rep->v_dtcc_buf = (re_dtcc *)mallocbuf; + + rep->setup = 1; +} + +/*===========================================================================* + * rl_init_hw * + *===========================================================================*/ +static void rl_init_hw(rep) +re_t *rep; +{ + int s, i; + + rep->re_flags = REF_EMPTY; + rep->re_flags |= REF_ENABLED; + + /* + * Set the interrupt handler. The policy is to only send HARD_INT + * notifications. Don't reenable interrupts automatically. The id + * that is passed back is the interrupt line number. + */ + rep->re_hook_id = rep->re_irq; + if ((s = sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK) + printf("RTL8169: error, couldn't set IRQ policy: %d\n", s); + + rl_reset_hw(rep); + + if ((s = sys_irqenable(&rep->re_hook_id)) != OK) + printf("RTL8169: error, couldn't enable interrupts: %d\n", s); + + printf("%s: model: %s mac: 0x%08lx\n", + rep->re_name, rep->re_model, rep->re_mac); + + rl_confaddr(rep); + if (debug) { + printf("%s: Ethernet address ", rep->re_name); + for (i = 0; i < 6; i++) { + printf("%x%c", rep->re_address.ea_addr[i], + i < 5 ? ':' : '\n'); + } + } +} + +static void rtl8169s_phy_config(port_t port) +{ + mdio_write(port, 0x1f, 0x0001); + mdio_write(port, 0x06, 0x006e); + mdio_write(port, 0x08, 0x0708); + mdio_write(port, 0x15, 0x4000); + mdio_write(port, 0x18, 0x65c7); + + mdio_write(port, 0x1f, 0x0001); + mdio_write(port, 0x03, 0x00a1); + mdio_write(port, 0x02, 0x0008); + mdio_write(port, 0x01, 0x0120); + mdio_write(port, 0x00, 0x1000); + mdio_write(port, 0x04, 0x0800); + mdio_write(port, 0x04, 0x0000); + + mdio_write(port, 0x03, 0xff41); + mdio_write(port, 0x02, 0xdf60); + mdio_write(port, 0x01, 0x0140); + mdio_write(port, 0x00, 0x0077); + mdio_write(port, 0x04, 0x7800); + mdio_write(port, 0x04, 0x7000); + + mdio_write(port, 0x03, 0x802f); + mdio_write(port, 0x02, 0x4f02); + mdio_write(port, 0x01, 0x0409); + mdio_write(port, 0x00, 0xf0f9); + mdio_write(port, 0x04, 0x9800); + mdio_write(port, 0x04, 0x9000); + + mdio_write(port, 0x03, 0xdf01); + mdio_write(port, 0x02, 0xdf20); + mdio_write(port, 0x01, 0xff95); + mdio_write(port, 0x00, 0xba00); + mdio_write(port, 0x04, 0xa800); + mdio_write(port, 0x04, 0xa000); + + mdio_write(port, 0x03, 0xff41); + mdio_write(port, 0x02, 0xdf20); + mdio_write(port, 0x01, 0x0140); + mdio_write(port, 0x00, 0x00bb); + mdio_write(port, 0x04, 0xb800); + mdio_write(port, 0x04, 0xb000); + + mdio_write(port, 0x03, 0xdf41); + mdio_write(port, 0x02, 0xdc60); + mdio_write(port, 0x01, 0x6340); + mdio_write(port, 0x00, 0x007d); + mdio_write(port, 0x04, 0xd800); + mdio_write(port, 0x04, 0xd000); + + mdio_write(port, 0x03, 0xdf01); + mdio_write(port, 0x02, 0xdf20); + mdio_write(port, 0x01, 0x100a); + mdio_write(port, 0x00, 0xa0ff); + mdio_write(port, 0x04, 0xf800); + mdio_write(port, 0x04, 0xf000); + + mdio_write(port, 0x1f, 0x0000); + mdio_write(port, 0x0b, 0x0000); + mdio_write(port, 0x00, 0x9200); +} + +static void rtl8169scd_phy_config(port_t port) +{ + mdio_write(port, 0x1f, 0x0001); + mdio_write(port, 0x04, 0x0000); + mdio_write(port, 0x03, 0x00a1); + mdio_write(port, 0x02, 0x0008); + mdio_write(port, 0x01, 0x0120); + mdio_write(port, 0x00, 0x1000); + mdio_write(port, 0x04, 0x0800); + mdio_write(port, 0x04, 0x9000); + mdio_write(port, 0x03, 0x802f); + mdio_write(port, 0x02, 0x4f02); + mdio_write(port, 0x01, 0x0409); + mdio_write(port, 0x00, 0xf099); + mdio_write(port, 0x04, 0x9800); + mdio_write(port, 0x04, 0xa000); + mdio_write(port, 0x03, 0xdf01); + mdio_write(port, 0x02, 0xdf20); + mdio_write(port, 0x01, 0xff95); + mdio_write(port, 0x00, 0xba00); + mdio_write(port, 0x04, 0xa800); + mdio_write(port, 0x04, 0xf000); + mdio_write(port, 0x03, 0xdf01); + mdio_write(port, 0x02, 0xdf20); + mdio_write(port, 0x01, 0x101a); + mdio_write(port, 0x00, 0xa0ff); + mdio_write(port, 0x04, 0xf800); + mdio_write(port, 0x04, 0x0000); + mdio_write(port, 0x1f, 0x0000); + + mdio_write(port, 0x1f, 0x0001); + mdio_write(port, 0x10, 0xf41b); + mdio_write(port, 0x14, 0xfb54); + mdio_write(port, 0x18, 0xf5c7); + mdio_write(port, 0x1f, 0x0000); + + mdio_write(port, 0x1f, 0x0001); + mdio_write(port, 0x17, 0x0cc0); + mdio_write(port, 0x1f, 0x0000); +} + +/*===========================================================================* + * rl_reset_hw * + *===========================================================================*/ +static void rl_reset_hw(rep) +re_t *rep; +{ + port_t port; + u32_t t; + int i; + clock_t t0, t1; + + port = rep->re_base_port; + + rl_outw(port, RL_IMR, 0x0000); + + /* Reset the device */ + printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n", + port, rl_inb(port, RL_CR)); + rl_outb(port, RL_CR, RL_CR_RST); + getuptime(&t0); + do { + if (!(rl_inb(port, RL_CR) & RL_CR_RST)) + break; + } while (getuptime(&t1) == OK && (t1 - t0) < system_hz); + printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n", + port, rl_inb(port, RL_CR)); + if (rl_inb(port, RL_CR) & RL_CR_RST) + printf("rtl8169: reset failed to complete"); + rl_outw(port, RL_ISR, 0xFFFF); + + /* Get Model and MAC info */ + t = rl_inl(port, RL_TCR); + rep->re_mac = (t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM)); + switch (rep->re_mac) { + case RL_TCR_HWVER_RTL8169: + rep->re_model = "RTL8169"; + + printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + rl_outw(port, 0x82, 0x01); + break; + case RL_TCR_HWVER_RTL8169S: + rep->re_model = "RTL8169S"; + + rtl8169s_phy_config(port); + + printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + rl_outw(port, 0x82, 0x01); + printf("Set PHY Reg 0x0bh = 0x00h\n"); + mdio_write(port, 0x0b, 0x0000); /* w 0x0b 15 0 0 */ + break; + case RL_TCR_HWVER_RTL8110S: + rep->re_model = "RTL8110S"; + + rtl8169s_phy_config(port); + + printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + rl_outw(port, 0x82, 0x01); + break; + case RL_TCR_HWVER_RTL8169SB: + rep->re_model = "RTL8169SB"; + + mdio_write(port, 0x1f, 0x02); + mdio_write(port, 0x01, 0x90d0); + mdio_write(port, 0x1f, 0x00); + + printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + rl_outw(port, 0x82, 0x01); + break; + case RL_TCR_HWVER_RTL8110SCd: + rep->re_model = "RTL8110SCd"; + + rtl8169scd_phy_config(port); + + printf("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + rl_outw(port, 0x82, 0x01); + break; + default: + rep->re_model = "Unknown"; + rep->re_mac = t; + break; + } + + mdio_write(port, MII_CTRL, MII_CTRL_RST); + for (i = 0; i < 1000; i++) { + t = mdio_read(port, MII_CTRL); + if (!(t & MII_CTRL_RST)) + break; + else + micro_delay(100); + } + + t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000; + mdio_write(port, MII_CTRL, t); + + t = mdio_read(port, MII_ANA); + t |= MII_ANA_10THD | MII_ANA_10TFD | MII_ANA_100TXHD | MII_ANA_100TXFD; + t |= MII_ANA_PAUSE_SYM | MII_ANA_PAUSE_ASYM; + mdio_write(port, MII_ANA, t); + + t = mdio_read(port, MII_1000_CTRL) | 0x300; + mdio_write(port, MII_1000_CTRL, t); + + /* Restart Auto-Negotiation Process */ + t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_RAN; + mdio_write(port, MII_CTRL, t); + + rl_outw(port, RL_9346CR, RL_9346CR_EEM_CONFIG); /* Unlock */ + + t = rl_inw(port, RL_CPLUSCMD); + if ((rep->re_mac == RL_TCR_HWVER_RTL8169S) || + (rep->re_mac == RL_TCR_HWVER_RTL8110S)) { + printf("Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n"); + rl_outw(port, RL_CPLUSCMD, t | RL_CPLUS_MULRW | (1 << 14)); + } else + rl_outw(port, RL_CPLUSCMD, t | RL_CPLUS_MULRW); + + rl_outw(port, RL_INTRMITIGATE, 0x00); + + t = rl_inb(port, RL_CR); + rl_outb(port, RL_CR, t | RL_CR_RE | RL_CR_TE); + + /* Initialize Rx */ + rl_outw(port, RL_RMS, RX_BUFSIZE); /* Maximum rx packet size */ + t = rl_inl(port, RL_RCR) & RX_CONFIG_MASK; + rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | t); + rl_outl(port, RL_RDSAR_LO, rep->p_rx_desc); + rl_outl(port, RL_RDSAR_HI, 0x00); /* For 64 bit */ + + /* Initialize Tx */ + rl_outw(port, RL_ETTHR, 0x3f); /* No early transmit */ + rl_outl(port, RL_TCR, RL_TCR_MXDMA_2048 | RL_TCR_IFG_STD); + rl_outl(port, RL_TNPDS_LO, rep->p_tx_desc); + rl_outl(port, RL_TNPDS_HI, 0x00); /* For 64 bit */ + + rl_outw(port, RL_9346CR, RL_9346CR_EEM_NORMAL); /* Lock */ + + rl_outw(port, RL_MPC, 0x00); + rl_outw(port, RL_MULINT, rl_inw(port, RL_MULINT) & 0xF000); + rl_outw(port, RL_IMR, RE_INTR_MASK); +} + +/*===========================================================================* + * rl_confaddr * + *===========================================================================*/ +static void rl_confaddr(rep) +re_t *rep; +{ + static char eakey[] = RL_ENVVAR "#_EA"; + static char eafmt[] = "x:x:x:x:x:x"; + + int i; + port_t port; + u32_t w; + long v; + + /* User defined ethernet address? */ + eakey[sizeof(RL_ENVVAR)-1] = '0' + (rep-re_table); + + port = rep->re_base_port; + + for (i = 0; i < 6; i++) { + if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) + break; + rep->re_address.ea_addr[i] = v; + } + + if (i != 0 && i != 6) + env_panic(eakey); /* It's all or nothing */ + + /* Should update ethernet address in hardware */ + if (i == 6) { + port = rep->re_base_port; + rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG); + w = 0; + for (i = 0; i < 4; i++) + w |= (rep->re_address.ea_addr[i] << (i * 8)); + rl_outl(port, RL_IDR, w); + w = 0; + for (i = 4; i < 6; i++) + w |= (rep->re_address.ea_addr[i] << ((i-4) * 8)); + rl_outl(port, RL_IDR + 4, w); + rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL); + } + + /* Get ethernet address */ + for (i = 0; i < 6; i++) + rep->re_address.ea_addr[i] = rl_inb(port, RL_IDR+i); +} + +/*===========================================================================* + * rl_rec_mode * + *===========================================================================*/ +static void rl_rec_mode(rep) +re_t *rep; +{ + port_t port; + u32_t rcr; + u32_t mc_filter[2]; /* Multicast hash filter */ + + port = rep->re_base_port; + + mc_filter[1] = mc_filter[0] = 0xffffffff; + rl_outl(port, RL_MAR + 0, mc_filter[0]); + rl_outl(port, RL_MAR + 4, mc_filter[1]); + + rcr = rl_inl(port, RL_RCR); + rcr &= ~(RL_RCR_AB | RL_RCR_AM | RL_RCR_APM | RL_RCR_AAP); + if (rep->re_flags & REF_PROMISC) + rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; + if (rep->re_flags & REF_BROAD) + rcr |= RL_RCR_AB; + if (rep->re_flags & REF_MULTI) + rcr |= RL_RCR_AM; + rcr |= RL_RCR_APM; + rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | rcr); +} + +void transmittest(re_t *rep) +{ + int tx_head; + re_desc *desc; + + tx_head = rep->re_tx_head; + desc = rep->re_tx_desc; + desc += tx_head; + + if(rep->re_tx[tx_head].ret_busy) { + do { + message m; + int r; + if ((r = receive(ANY, &m)) != OK) + panic("rtl8169", "receive failed", r); + } while(m.m_source != HARDWARE); + assert(!(rep->re_flags & REF_SEND_AVAIL)); + rep->re_flags |= REF_SEND_AVAIL; + } + + return; +} + +/*===========================================================================* + * rl_readv_s * + *===========================================================================*/ +static void rl_readv_s(mp, from_int) +message *mp; +int from_int; +{ + int i, j, n, s, dl_port, re_client, count, size, index; + port_t port; + unsigned totlen, packlen; + phys_bytes src_phys, iov_src; + re_desc *desc; + u32_t rxstat = 0x12345678; + re_t *rep; + iovec_s_t *iovp; + int cps; + int iov_offset = 0; + + dl_port = mp->DL_PORT; + count = mp->DL_COUNT; + if (dl_port < 0 || dl_port >= RE_PORT_NR) + panic("rtl8169", " illegal port", dl_port); + rep = &re_table[dl_port]; + re_client = mp->DL_PROC; + rep->re_client = re_client; + + assert(rep->re_mode == REM_ENABLED); + assert(rep->re_flags & REF_ENABLED); + + port = rep->re_base_port; + + /* + * Assume that the RL_CR_BUFE check was been done by rl_checks_ints + */ + if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE)) + goto suspend; /* Receive buffer is empty, suspend */ + + index = rep->re_rx_head; +readvs_test_loop: + desc = rep->re_rx_desc; + desc += index; +readvs_loop: + rxstat = desc->status; + + if (rxstat & DESC_OWN) + goto suspend; + + if (rxstat & DESC_RX_CRC) + rep->re_stat.ets_CRCerr++; + + if ((rxstat & (DESC_FS | DESC_LS)) != (DESC_FS | DESC_LS)) { + printf("rl_readv_s: packet is fragmented\n"); + /* Fix the fragmented packet */ + if (index == N_RX_DESC - 1) { + desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + index = 0; + desc = rep->re_rx_desc; + } else { + desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + index++; + desc++; + } + goto readvs_loop; /* Loop until we get correct packet */ + } + + totlen = rxstat & DESC_RX_LENMASK; + if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) { + /* Someting went wrong */ + printf("rl_readv_s: bad length (%u) in status 0x%08lx\n", + totlen, rxstat); + panic(NULL, NULL, NO_NUM); + } + + /* Should subtract the CRC */ + packlen = totlen - ETH_CRC_SIZE; + + size = 0; + src_phys = rep->re_rx[index].ret_buf; + for (i = 0; i < count; i += IOVEC_NR, + iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]), + iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) + { + n = IOVEC_NR; + if (i + n > count) + n = count-i; + cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset, + (vir_bytes) rep->re_iovec_s, + n * sizeof(rep->re_iovec_s[0]), D); + if (cps != OK) { + panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed", + cps); + } + + for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { + s = iovp->iov_size; + if (size + s > packlen) { + assert(packlen > size); + s = packlen-size; + } + + cps = sys_safecopyto(re_client, iovp->iov_grant, 0, + (vir_bytes) rep->re_rx[index].v_ret_buf + size, s, D); + if (cps != OK) + panic(__FILE__, + "rl_readv_s: sys_safecopyto failed", cps); + + size += s; + if (size == packlen) + break; + } + if (size == packlen) + break; + } + if (size < packlen) + assert(0); + + rep->re_stat.ets_packetR++; + rep->re_read_s = packlen; + if (index == N_RX_DESC - 1) { + desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + index = 0; + } else { + desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + index++; + } + rep->re_rx_head = index; + assert(rep->re_rx_head < N_RX_DESC); + rep->re_flags = (rep->re_flags & ~REF_READING) | REF_PACK_RECV; + + if (!from_int) + reply(rep, OK, FALSE); + + return; + +suspend: + if (from_int) { + assert(rep->re_flags & REF_READING); + + /* No need to store any state */ + return; + } + + rep->re_rx_mess = *mp; + assert(!(rep->re_flags & REF_READING)); + rep->re_flags |= REF_READING; + + reply(rep, OK, FALSE); +} + +/*===========================================================================* + * rl_writev_s * + *===========================================================================*/ +static void rl_writev_s(mp, from_int) +message *mp; +int from_int; +{ + phys_bytes iov_src; + int i, j, n, s, port, count, size; + int tx_head, re_client; + re_t *rep; + iovec_s_t *iovp; + re_desc *desc; + char *ret; + int cps; + int iov_offset = 0; + + port = mp->DL_PORT; + count = mp->DL_COUNT; + if (port < 0 || port >= RE_PORT_NR) + panic("rtl8169", "illegal port", port); + rep = &re_table[port]; + assert(mp); + assert(port >= 0 && port < RE_PORT_NR); + assert(rep->setup); + re_client = mp->DL_PROC; + rep->re_client = re_client; + + assert(rep->re_mode == REM_ENABLED); + assert(rep->re_flags & REF_ENABLED); + + if (from_int) { + assert(rep->re_flags & REF_SEND_AVAIL); + rep->re_flags &= ~REF_SEND_AVAIL; + rep->re_send_int = FALSE; + rep->re_tx_alive = TRUE; + } + + tx_head = rep->re_tx_head; + + desc = rep->re_tx_desc; + desc += tx_head; + + if(!desc || !rep->re_tx_desc) { + printf("desc 0x%lx, re_tx_desc 0x%lx, tx_head %d, setup %d\n", + desc, rep->re_tx_desc, tx_head, rep->setup); + } + + assert(rep->re_tx_desc); + assert(rep->re_tx_head >= 0 && rep->re_tx_head < N_TX_DESC); + + assert(desc); + + + if (rep->re_tx[tx_head].ret_busy) { + assert(!(rep->re_flags & REF_SEND_AVAIL)); + rep->re_flags |= REF_SEND_AVAIL; + if (rep->re_tx[tx_head].ret_busy) + goto suspend; + + /* + * Race condition, the interrupt handler may clear re_busy + * before we got a chance to set REF_SEND_AVAIL. Checking + * ret_busy twice should be sufficient. + */ +#if VERBOSE + printf("rl_writev_s: race detected\n"); +#endif + rep->re_flags &= ~REF_SEND_AVAIL; + rep->re_send_int = FALSE; + } + + assert(!(rep->re_flags & REF_SEND_AVAIL)); + assert(!(rep->re_flags & REF_PACK_SENT)); + + size = 0; + ret = rep->re_tx[tx_head].v_ret_buf; + for (i = 0; i < count; i += IOVEC_NR, + iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]), + iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) + { + n = IOVEC_NR; + if (i + n > count) + n = count - i; + cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset, + (vir_bytes) rep->re_iovec_s, + n * sizeof(rep->re_iovec_s[0]), D); + if (cps != OK) { + panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed", + cps); + } + + for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { + s = iovp->iov_size; + if (size + s > ETH_MAX_PACK_SIZE_TAGGED) + panic("rtl8169", "invalid packet size", NO_NUM); + + cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0, + (vir_bytes) ret, s, D); + if (cps != OK) { + panic(__FILE__, + "rl_writev_s: sys_safecopyfrom failed", + cps); + } + size += s; + ret += s; + } + } + assert(desc); + if (size < ETH_MIN_PACK_SIZE) + panic("rtl8169", "invalid packet size", size); + + rep->re_tx[tx_head].ret_busy = TRUE; + + if (tx_head == N_TX_DESC - 1) { + desc->status = DESC_EOR | DESC_OWN | DESC_FS | DESC_LS | size; + tx_head = 0; + } else { + desc->status = DESC_OWN | DESC_FS | DESC_LS | size; + tx_head++; + } + + assert(tx_head < N_TX_DESC); + rep->re_tx_head = tx_head; + + rl_outl(rep->re_base_port, RL_TPPOLL, RL_TPPOLL_NPQ); + rep->re_flags |= REF_PACK_SENT; + + /* + * If the interrupt handler called, don't send a reply. The reply + * will be sent after all interrupts are handled. + */ + if (from_int) + return; + reply(rep, OK, FALSE); + return; + +suspend: + if (from_int) + panic("rtl8169", "should not be sending\n", NO_NUM); + + rep->re_tx_mess = *mp; + reply(rep, OK, FALSE); +} + +/*===========================================================================* + * rl_check_ints * + *===========================================================================*/ +static void rl_check_ints(rep) +re_t *rep; +{ + int re_flags; + + re_flags = rep->re_flags; + + if ((re_flags & REF_READING) && + !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE)) + { + assert(rep->re_rx_mess.m_type == DL_READV_S); + rl_readv_s(&rep->re_rx_mess, TRUE /* from int */); + } + + if (rep->re_need_reset) + rl_do_reset(rep); + + if (rep->re_send_int) { + assert(rep->re_tx_mess.m_type == DL_WRITEV_S); + rl_writev_s(&rep->re_tx_mess, TRUE /* from int */); + } + + if (rep->re_report_link) + rl_report_link(rep); + + if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV)) + reply(rep, OK, TRUE); +} + +/*===========================================================================* + * rl_report_link * + *===========================================================================*/ +static void rl_report_link(rep) +re_t *rep; +{ + port_t port; + u8_t mii_status; + + rep->re_report_link = FALSE; + port = rep->re_base_port; + + mii_status = rl_inb(port, RL_PHYSTAT); + + if (mii_status & RL_STAT_LINK) { + rep->re_link_up = 1; + printf("%s: link up at ", rep->re_name); + } else { + rep->re_link_up = 0; + printf("%s: link down\n", rep->re_name); + return; + } + + if (mii_status & RL_STAT_1000) + printf("1000 Mbps"); + else if (mii_status & RL_STAT_100) + printf("100 Mbps"); + else if (mii_status & RL_STAT_10) + printf("10 Mbps"); + + if (mii_status & RL_STAT_FULLDUP) + printf(", full duplex"); + else + printf(", half duplex"); + printf("\n"); + + dump_phy(rep); +} + +/*===========================================================================* + * rl_do_reset * + *===========================================================================*/ +static void rl_do_reset(rep) +re_t *rep; +{ + rep->re_need_reset = FALSE; + rl_reset_hw(rep); + rl_rec_mode(rep); + + rep->re_tx_head = 0; + if (rep->re_flags & REF_SEND_AVAIL) { + rep->re_tx[rep->re_tx_head].ret_busy = FALSE; + rep->re_send_int = TRUE; + } +} + +/*===========================================================================* + * rl_getstat * + *===========================================================================*/ +static void rl_getstat(mp) +message *mp; +{ + int r, port; + eth_stat_t stats; + re_t *rep; + + port = mp->DL_PORT; + if (port < 0 || port >= RE_PORT_NR) + panic("rtl8169", "illegal port", port); + rep = &re_table[port]; + rep->re_client = mp->DL_PROC; + + assert(rep->re_mode == REM_ENABLED); + assert(rep->re_flags & REF_ENABLED); + + stats = rep->re_stat; + + r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC, + (vir_bytes) mp->DL_ADDR, sizeof(stats)); + if (r != OK) + panic(__FILE__, "rl_getstat: sys_datacopy failed", r); + + mp->m_type = DL_STAT_REPLY; + mp->DL_PORT = port; + mp->DL_STAT = OK; + r = send(mp->m_source, mp); + if (r != OK) + panic("RTL8169", "rl_getstat: send failed: %d\n", r); +} + +/*===========================================================================* + * rl_getstat_s * + *===========================================================================*/ +static void rl_getstat_s(mp) +message *mp; +{ + int r, port; + eth_stat_t stats; + re_t *rep; + + port = mp->DL_PORT; + if (port < 0 || port >= RE_PORT_NR) + panic("rtl8169", "illegal port", port); + rep = &re_table[port]; + rep->re_client = mp->DL_PROC; + + assert(rep->re_mode == REM_ENABLED); + assert(rep->re_flags & REF_ENABLED); + + stats = rep->re_stat; + + r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, + (vir_bytes) &stats, sizeof(stats), D); + if (r != OK) + panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r); + + mp->m_type = DL_STAT_REPLY; + mp->DL_PORT = port; + mp->DL_STAT = OK; + r = send(mp->m_source, mp); + if (r != OK) + panic("RTL8169", "rl_getstat_s: send failed: %d\n", r); +} + + +/*===========================================================================* + * rl_getname * + *===========================================================================*/ +static void rl_getname(mp) +message *mp; +{ + int r; + + strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME)); + mp->DL_NAME[sizeof(mp->DL_NAME)-1] = '\0'; + mp->m_type = DL_NAME_REPLY; + r = send(mp->m_source, mp); + if (r != OK) + panic("RTL8169", "rl_getname: send failed: %d\n", r); +} + + +/*===========================================================================* + * reply * + *===========================================================================*/ +static void reply(rep, err, may_block) +re_t *rep; +int err; +int may_block; +{ + message reply; + int status; + int r; + clock_t now; + + status = 0; + if (rep->re_flags & REF_PACK_SENT) + status |= DL_PACK_SEND; + if (rep->re_flags & REF_PACK_RECV) + status |= DL_PACK_RECV; + + reply.m_type = DL_TASK_REPLY; + reply.DL_PORT = rep - re_table; + reply.DL_PROC = rep->re_client; + reply.DL_STAT = status | ((u32_t) err << 16); + reply.DL_COUNT = rep->re_read_s; + if (OK != (r = getuptime(&now))) + panic("rtl8169", "getuptime() failed:", r); + reply.DL_CLCK = now; + + r = send(rep->re_client, &reply); + + if (r == ELOCKED && may_block) { + printW(); printf("send locked\n"); + return; + } + + if (r < 0) { + printf("RTL8169 tried sending to %d, type %d\n", + rep->re_client, reply.m_type); + panic("rtl8169", "send failed:", r); + } + + rep->re_read_s = 0; + rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV); +} + +/*===========================================================================* + * mess_reply * + *===========================================================================*/ +static void mess_reply(req, reply_mess) +message *req; +message *reply_mess; +{ + if (send(req->m_source, reply_mess) != OK) + panic("rtl8169", "unable to mess_reply", NO_NUM); +} + +static void dump_phy(re_t *rep) +{ +#if VERBOSE + port_t port; + u32_t t; + + port = rep->re_base_port; + + t = rl_inb(port, RL_CONFIG0); + printf("CONFIG0\t\t:"); + t = t & RL_CFG0_ROM; + if (t == RL_CFG0_ROM128K) + printf(" 128K Boot ROM"); + else if (t == RL_CFG0_ROM64K) + printf(" 64K Boot ROM"); + else if (t == RL_CFG0_ROM32K) + printf(" 32K Boot ROM"); + else if (t == RL_CFG0_ROM16K) + printf(" 16K Boot ROM"); + else if (t == RL_CFG0_ROM8K) + printf(" 8K Boot ROM"); + else if (t == RL_CFG0_ROMNO) + printf(" No Boot ROM"); + printf("\n"); + + t = rl_inb(port, RL_CONFIG1); + printf("CONFIG1\t\t:"); + if (t & RL_CFG1_LEDS1) + printf(" LED1"); + if (t & RL_CFG1_LEDS0) + printf(" LED0"); + if (t & RL_CFG1_DVRLOAD) + printf(" Driver"); + if (t & RL_CFG1_LWACT) + printf(" LWAKE"); + if (t & RL_CFG1_IOMAP) + printf(" IOMAP"); + if (t & RL_CFG1_MEMMAP) + printf(" MEMMAP"); + if (t & RL_CFG1_VPD) + printf(" VPD"); + if (t & RL_CFG1_PME) + printf(" PME"); + printf("\n"); + + t = rl_inb(port, RL_CONFIG2); + printf("CONFIG2\t\t:"); + if (t & RL_CFG2_AUX) + printf(" AUX"); + if (t & RL_CFG2_PCIBW) + printf(" PCI-64-Bit"); + else + printf(" PCI-32-Bit"); + t = t & RL_CFG2_PCICLK; + if (t == RL_CFG2_66MHZ) + printf(" 66 MHz"); + else if (t == RL_CFG2_33MHZ) + printf(" 33 MHz"); + printf("\n"); + + t = mdio_read(port, MII_CTRL); + printf("MII_CTRL\t:"); + if (t & MII_CTRL_RST) + printf(" Reset"); + if (t & MII_CTRL_LB) + printf(" Loopback"); + if (t & MII_CTRL_ANE) + printf(" ANE"); + if (t & MII_CTRL_PD) + printf(" Power-down"); + if (t & MII_CTRL_ISO) + printf(" Isolate"); + if (t & MII_CTRL_RAN) + printf(" RAN"); + if (t & MII_CTRL_DM) + printf(" Full-duplex"); + if (t & MII_CTRL_CT) + printf(" COL-signal"); + t = t & (MII_CTRL_SP_LSB | MII_CTRL_SP_MSB); + if (t == MII_CTRL_SP_10) + printf(" 10 Mb/s"); + else if (t == MII_CTRL_SP_100) + printf(" 100 Mb/s"); + else if (t == MII_CTRL_SP_1000) + printf(" 1000 Mb/s"); + printf("\n"); + + t = mdio_read(port, MII_STATUS); + printf("MII_STATUS\t:"); + if (t & MII_STATUS_100T4) + printf(" 100Base-T4"); + if (t & MII_STATUS_100XFD) + printf(" 100BaseX-FD"); + if (t & MII_STATUS_100XHD) + printf(" 100BaseX-HD"); + if (t & MII_STATUS_10FD) + printf(" 10Mbps-FD"); + if (t & MII_STATUS_10HD) + printf(" 10Mbps-HD"); + if (t & MII_STATUS_100T2FD) + printf(" 100Base-T2-FD"); + if (t & MII_STATUS_100T2HD) + printf(" 100Base-T2-HD"); + if (t & MII_STATUS_EXT_STAT) + printf(" Ext-stat"); + if (t & MII_STATUS_RES) + printf(" res-0x%lx", t & MII_STATUS_RES); + if (t & MII_STATUS_MFPS) + printf(" MFPS"); + if (t & MII_STATUS_ANC) + printf(" ANC"); + if (t & MII_STATUS_RF) + printf(" remote-fault"); + if (t & MII_STATUS_ANA) + printf(" ANA"); + if (t & MII_STATUS_LS) + printf(" Link"); + if (t & MII_STATUS_JD) + printf(" Jabber"); + if (t & MII_STATUS_EC) + printf(" Extended-capability"); + printf("\n"); + + t = mdio_read(port, MII_ANA); + printf("MII_ANA\t\t: 0x%04lx\n", t); + + t = mdio_read(port, MII_ANLPA); + printf("MII_ANLPA\t: 0x%04lx\n", t); + + t = mdio_read(port, MII_ANE); + printf("MII_ANE\t\t:"); + if (t & MII_ANE_RES) + printf(" res-0x%lx", t & MII_ANE_RES); + if (t & MII_ANE_PDF) + printf(" Par-Detect-Fault"); + if (t & MII_ANE_LPNPA) + printf(" LP-Next-Page-Able"); + if (t & MII_ANE_NPA) + printf(" Loc-Next-Page-Able"); + if (t & MII_ANE_PR) + printf(" Page-Received"); + if (t & MII_ANE_LPANA) + printf(" LP-Auto-Neg-Able"); + printf("\n"); + + t = mdio_read(port, MII_1000_CTRL); + printf("MII_1000_CTRL\t:"); + if (t & MII_1000C_FULL) + printf(" 1000BaseT-FD"); + if (t & MII_1000C_HALF) + printf(" 1000BaseT-HD"); + printf("\n"); + + t = mdio_read(port, MII_1000_STATUS); + if (t) { + printf("MII_1000_STATUS\t:"); + if (t & MII_1000S_LRXOK) + printf(" Local-Receiver"); + if (t & MII_1000S_RRXOK) + printf(" Remote-Receiver"); + if (t & MII_1000S_HALF) + printf(" 1000BaseT-HD"); + if (t & MII_1000S_FULL) + printf(" 1000BaseT-FD"); + printf("\n"); + + t = mdio_read(port, MII_EXT_STATUS); + printf("MII_EXT_STATUS\t:"); + if (t & MII_ESTAT_1000XFD) + printf(" 1000BaseX-FD"); + if (t & MII_ESTAT_1000XHD) + printf(" 1000BaseX-HD"); + if (t & MII_ESTAT_1000TFD) + printf(" 1000BaseT-FD"); + if (t & MII_ESTAT_1000THD) + printf(" 1000BaseT-HD"); + printf("\n"); + } +#endif +} + +static void do_hard_int(void) +{ + int i, s; + + for (i = 0; i < RE_PORT_NR; i++) { + + /* Run interrupt handler at driver level. */ + rl_handler(&re_table[i]); + + /* Reenable interrupts for this hook. */ + if ((s = sys_irqenable(&re_table[i].re_hook_id)) != OK) + printf("RTL8169: error, couldn't enable interrupts: %d\n", s); + } +} + +/*===========================================================================* + * rl_handler * + *===========================================================================*/ +static int rl_handler(rep) +re_t *rep; +{ + int i, port, tx_head, tx_tail, link_up; + u16_t isr; + re_desc *desc; + int_event_check = FALSE; /* disable check by default */ + + port = rep->re_base_port; + + /* Ack interrupt */ + isr = rl_inw(port, RL_ISR); + if(!isr) + return; + rl_outw(port, RL_ISR, isr); + rep->interrupts++; + + if (isr & RL_IMR_FOVW) { + isr &= ~RL_IMR_FOVW; + /* Should do anything? */ + + rep->re_stat.ets_fifoOver++; + } + if (isr & RL_IMR_PUN) { + isr &= ~RL_IMR_PUN; + + /* + * Either the link status changed or there was a TX fifo + * underrun. + */ + link_up = !(!(rl_inb(port, RL_PHYSTAT) & RL_STAT_LINK)); + if (link_up != rep->re_link_up) { + rep->re_report_link = TRUE; + rep->re_got_int = TRUE; + int_event_check = TRUE; + } + } + + if (isr & (RL_ISR_RDU | RL_ISR_RER | RL_ISR_ROK)) { + if (isr & RL_ISR_RER) + rep->re_stat.ets_recvErr++; + isr &= ~(RL_ISR_RDU | RL_ISR_RER | RL_ISR_ROK); + + if (!rep->re_got_int && (rep->re_flags & REF_READING)) { + rep->re_got_int = TRUE; + int_event_check = TRUE; + } + } + + if ((isr & (RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK)) || 1) { + if (isr & RL_ISR_TER) + rep->re_stat.ets_sendErr++; + isr &= ~(RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK); + + /* Transmit completed */ + tx_head = rep->re_tx_head; + tx_tail = tx_head+1; + if (tx_tail >= N_TX_DESC) + tx_tail = 0; + for (i = 0; i < 2 * N_TX_DESC; i++) { + if (!rep->re_tx[tx_tail].ret_busy) { + /* Strange, this buffer is not in-use. + * Increment tx_tail until tx_head is + * reached (or until we find a buffer that + * is in-use. + */ + if (tx_tail == tx_head) + break; + if (++tx_tail >= N_TX_DESC) + tx_tail = 0; + assert(tx_tail < N_TX_DESC); + continue; + } + desc = rep->re_tx_desc; + desc += tx_tail; + if (desc->status & DESC_OWN) { + /* Buffer is not yet ready */ + break; + } + + rep->re_stat.ets_packetT++; + rep->re_tx[tx_tail].ret_busy = FALSE; + + if (++tx_tail >= N_TX_DESC) + tx_tail = 0; + assert(tx_tail < N_TX_DESC); + + if (rep->re_flags & REF_SEND_AVAIL) { + rep->re_send_int = TRUE; + if (!rep->re_got_int) { + rep->re_got_int = TRUE; + int_event_check = TRUE; + } + } + } + assert(i < 2 * N_TX_DESC); + } + + /* Ignore Reserved Interrupt */ + if (isr & RL_ISR_RES) + isr &= ~RL_ISR_RES; + + if (isr) + printf("rl_handler: unhandled interrupt isr = 0x%04x\n", isr); + + return 1; +} + +/*===========================================================================* + * rl_watchdog_f * + *===========================================================================*/ +static void rl_watchdog_f(tp) +timer_t *tp; +{ + int i; + re_t *rep; + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(system_hz, 0); + + for (i = 0, rep = &re_table[0]; i < RE_PORT_NR; i++, rep++) { + if (rep->re_mode != REM_ENABLED) + continue; + + /* Should collect statistics */ + if (!(++rep->dtcc_counter % RE_DTCC_VALUE)) + rtl8169_update_stat(rep); + + if (!(rep->re_flags & REF_SEND_AVAIL)) { + /* Assume that an idle system is alive */ + rep->re_tx_alive = TRUE; + continue; + } + if (rep->re_tx_alive) { + rep->re_tx_alive = FALSE; + continue; + } + printf("rl_watchdog_f: resetting port %d mode 0x%x flags 0x%x\n", + i, rep->re_mode, rep->re_flags); + printf("tx_head :%8d busy %d\t", + rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); + rep->re_need_reset = TRUE; + rep->re_got_int = TRUE; + + check_int_events(); + } +} + diff --git a/drivers/rtl8169/rtl8169.h b/drivers/rtl8169/rtl8169.h new file mode 100644 index 000000000..d806c589a --- /dev/null +++ b/drivers/rtl8169/rtl8169.h @@ -0,0 +1,365 @@ +/* + * rtl8169.h + */ + +#define RL_N_DESC 1024 /* Number of descriptors */ +#define N_RX_DESC RL_N_DESC /* Number of receive descriptors */ +#define N_TX_DESC RL_N_DESC /* Number of transmit descriptors */ + +#define RX_BUFSIZE 1536 /* Maximum gigabit ethernet frame size */ + +/* Transmit Descriptor control */ +#define DESC_RX_LGSEN 0x08000000 /* Large Send */ +#define DESC_RX_IPCS 0x00040000 /* IP Checksum Offload */ +#define DESC_RX_UDPCS 0x00020000 /* UDP Checksum Offload */ +#define DESC_RX_TCPCS 0x00010000 /* TCP Checksum Offload */ +#define DESC_TX_LENMASK 0x0000FFFF /* Transmit Frame Length Mask */ + +/* Receive Descriptor control */ +#define DESC_RX_MAR 0x08000000 /* Multicast Address Received */ +#define DESC_RX_PAM 0x04000000 /* Physical Address Matched */ +#define DESC_RX_BAR 0x02000000 /* Broadcast Address Received */ +#define DESC_RX_BOVF 0x01000000 /* Buffer Overflow */ +#define DESC_RX_FOVF 0x00800000 /* FIFO Overflow */ +#define DESC_RX_RWT 0x00400000 /* Receive Watchdog Timer Expired */ +#define DESC_RX_RES 0x00200000 /* Receive Error Summary */ +#define DESC_RX_RUNT 0x00100000 /* Runt Packet */ +#define DESC_RX_CRC 0x00080000 /* CRC Error */ +#define DESC_RX_PID1 0x00040000 /* Protocol ID1 */ +#define DESC_RX_PID0 0x00020000 /* Protocol ID0 */ +#define DESC_RX_IPF 0x00010000 /* IP Checksum Failure */ +#define DESC_RX_UDPF 0x00008000 /* UDP Checksum Failure */ +#define DESC_RX_TCPF 0x00004000 /* TCP Checksum Failure */ +#define DESC_RX_LENMASK 0x00001FFF /* Receive Frame Length Mask */ + +/* General Descriptor control */ +#define DESC_OWN 0x80000000 /* Ownership */ +#define DESC_EOR 0x40000000 /* End of Descriptor Ring */ +#define DESC_FS 0x20000000 /* First Segment Descriptor */ +#define DESC_LS 0x10000000 /* Last Segment Descriptor */ + + +#define RL_IDR 0x00 /* Ethernet address + * Note: RL_9346CR_EEM_CONFIG mode is + * required the change the ethernet address. + * Note: 4-byte write access only. + */ +#define RL_MAR 0x08 /* Multicast */ +#define RL_DTCCR_LO 0x10 /* Dump Tally Counter Command Register LOW */ +#define RL_DTCCR_HI 0x14 /* Dump Tally Counter Command Register HIGH */ +#define RL_DTCCR_CMD 0x08 /* Command */ +#define RL_TNPDS_LO 0x20 /* Transmit Normal Priority Descriptors Start Address LOW */ +#define RL_TNPDS_HI 0x24 /* Transmit Normal Priority Descriptors Start Address HIGH */ +#define RL_THPDS_LO 0x28 /* Transmit High Priority Descriptors Start Address LOW */ +#define RL_THPDS_HI 0x2C /* Transmit High Priority Descriptors Start Address HIGH */ +#define RL_FLASH 0x30 /* Flash Memory Read/Write Register */ +#define RL_ERBCR 0x34 /* Early Receive (Rx) Byte Count Register */ +#define RL_ERSR 0x36 /* Early Rx Status Register */ +#define RL_ERSR_RES 0xF0 /* Reserved */ +#define RL_ERSR_ERGOOD 0x08 /* Early Rx Good packet */ +#define RL_ERSR_ERBAD 0x04 /* Early Rx Bad packet */ +#define RL_ERSR_EROVW 0x02 /* Early Rx OverWrite */ +#define RL_ERSR_EROK 0x01 /* Early Rx OK */ +#define RL_CR 0x37 /* Command Register */ +#define RL_CR_RES0 0xE0 /* Reserved */ +#define RL_CR_RST 0x10 /* Reset */ +#define RL_CR_RE 0x08 /* Receiver Enable */ +#define RL_CR_TE 0x04 /* Transmitter Enable * + * Note: start with transmit buffer + * 0 after RL_CR_TE has been reset. + */ +#define RL_CR_RES1 0x02 /* Reserved */ +#define RL_CR_BUFE 0x01 /* Receive Buffer Empty */ +#define RL_TPPOLL 0x38 /* Transmit Priority Polling Register */ +#define RL_TPPOLL_HPQ 0x80 /* High Priority Queue Polling */ +#define RL_TPPOLL_NPQ 0x40 /* Normal Priority Queue Polling */ +#define RL_TPPOLL_FSW 0x01 /* Forced Software Interrupt */ +#define RL_IMR 0x3C /* Interrupt Mask Register */ +#define RL_IMR_SERR 0x8000 /* System Error */ +#define RL_IMR_TIMEOUT 0x4000 /* Time Out */ +#define RL_IMR_RES 0x3E00 /* Reserved */ +#define RL_IMR_SWINT 0x0100 /* Software Interrupt */ +#define RL_IMR_TDU 0x0080 /* Tx Descriptor Unavailable */ +#define RL_IMR_FOVW 0x0040 /* Rx FIFO Overflow */ +#define RL_IMR_PUN 0x0020 /* Packet Underrun / Link Change */ +#define RL_IMR_RDU 0x0010 /* Rx Descriptor Unavailable */ +#define RL_IMR_TER 0x0008 /* Transmit Error */ +#define RL_IMR_TOK 0x0004 /* Transmit OK */ +#define RL_IMR_RER 0x0002 /* Receive Error */ +#define RL_IMR_ROK 0x0001 /* Receive OK */ +#define RL_ISR 0x3E /* Interrupt Status Register */ +#define RL_ISR_SERR 0x8000 /* System Error */ +#define RL_ISR_TIMEOUT 0x4000 /* Time Out */ +#define RL_ISR_RES 0x3E00 /* Reserved */ +#define RL_ISR_SWINT 0x0100 /* Software Interrupt */ +#define RL_ISR_TDU 0x0080 /* Tx Descriptor Unavailable */ +#define RL_ISR_FOVW 0x0040 /* Rx FIFO Overflow */ +#define RL_ISR_PUN 0x0020 /* Packet Underrun / Link Change */ +#define RL_ISR_RDU 0x0010 /* Rx Descriptor Unavailable */ +#define RL_ISR_TER 0x0008 /* Transmit Error */ +#define RL_ISR_TOK 0x0004 /* Transmit OK */ +#define RL_ISR_RER 0x0002 /* Receive Error */ +#define RL_ISR_ROK 0x0001 /* Receive OK */ +#define RL_TCR 0x40 /* Transmit Configuration Register + * Note: RL_CR_TE has to be set to + * set/change RL_TCR. + */ +#define RL_TCR_RES0 0x80000000 /* Reserved */ +#define RL_TCR_HWVER_AM 0x7C000000 /* Hardware Version ID A */ +#define RL_TCR_IFG_M 0x03000000 /* Interframe Gap Time */ +#define RL_TCR_IFG_STD 0x03000000 /* IEEE 802.3 std */ +#define RL_TCR_HWVER_BM 0x00800000 /* Hardware Version ID B */ +#define RL_TCR_HWVER_RTL8169 0x00000000 /* RTL8169 */ +#define RL_TCR_HWVER_RTL8169S 0x00800000 /* RTL8169S */ +#define RL_TCR_HWVER_RTL8110S 0x04000000 /* RTL8110S */ +#define RL_TCR_HWVER_RTL8169SB 0x10000000 /* RTL8169sb/8110sb */ +#define RL_TCR_HWVER_RTL8110SCd 0x18000000 /* RTL8169sc/8110sc */ +#define RL_TCR_RES1 0x00380000 /* Reserved */ +#define RL_TCR_LBK_M 0x00060000 /* Loopback Test */ +#define RL_TCR_LBK_NORMAL 0x00000000 /* Normal */ +#define RL_TCR_LBK_LOOKBOCK 0x00060000 /* Loopback Mode */ +#define RL_TCR_CRC 0x00010000 /* (Do not) Append CRC */ +#define RL_TCR_RES2 0x0000F800 /* Reserved */ +#define RL_TCR_MXDMA_M 0x00000700 /* Max DMA Burst Size Tx */ +#define RL_TCR_MXDMA_16 0x00000000 /* 16 bytes */ +#define RL_TCR_MXDMA_32 0x00000100 /* 32 bytes */ +#define RL_TCR_MXDMA_64 0x00000200 /* 64 bytes */ +#define RL_TCR_MXDMA_128 0x00000300 /* 128 bytes */ +#define RL_TCR_MXDMA_128 0x00000300 /* 128 bytes */ +#define RL_TCR_MXDMA_256 0x00000400 /* 256 bytes */ +#define RL_TCR_MXDMA_512 0x00000500 /* 512 bytes */ +#define RL_TCR_MXDMA_1024 0x00000600 /* 1024 bytes */ +#define RL_TCR_MXDMA_2048 0x00000700 /* 2048 bytes */ +#define RL_TCR_TXRR_M 0x000000F0 /* Tx Retry Count */ +#define RL_TCR_RES3 0x0000000E /* Reserved */ +#define RL_TCR_CLRABT 0x00000001 /* Clear Abort */ +#define RL_RCR 0x44 /* Receive Configuration Register + * Note: RL_CR_RE has to be set to + * set/change RL_RCR. + */ +#define RL_RCR_RES0 0xF0000000 /* Reserved */ +#define RL_RCR_ERTH_M 0x0F000000 /* Early Rx Threshold */ +#define RL_RCR_ERTH_0 0x00000000 /* No threshold */ +#define RL_RCR_ERTH_1 0x01000000 /* 1/16 */ +#define RL_RCR_ERTH_2 0x02000000 /* 2/16 */ +#define RL_RCR_ERTH_3 0x03000000 /* 3/16 */ +#define RL_RCR_ERTH_4 0x04000000 /* 4/16 */ +#define RL_RCR_ERTH_5 0x05000000 /* 5/16 */ +#define RL_RCR_ERTH_6 0x06000000 /* 6/16 */ +#define RL_RCR_ERTH_7 0x07000000 /* 7/16 */ +#define RL_RCR_ERTH_8 0x08000000 /* 8/16 */ +#define RL_RCR_ERTH_9 0x09000000 /* 9/16 */ +#define RL_RCR_ERTH_10 0x0A000000 /* 10/16 */ +#define RL_RCR_ERTH_11 0x0B000000 /* 11/16 */ +#define RL_RCR_ERTH_12 0x0C000000 /* 12/16 */ +#define RL_RCR_ERTH_13 0x0D000000 /* 13/16 */ +#define RL_RCR_ERTH_14 0x0E000000 /* 14/16 */ +#define RL_RCR_ERTH_15 0x0F000000 /* 15/16 */ +#define RL_RCR_RES1 0x00FC0000 /* Reserved */ +#define RL_RCR_MULERINT 0x00020000 /* Multiple Early Int Select */ +#define RL_RCR_RER8 0x00010000 /* Receive small error packet */ +#define RL_RCR_RXFTH_M 0x0000E000 /* Rx FIFO Threshold */ +#define RL_RCR_RXFTH_16 0x00000000 /* 16 bytes */ +#define RL_RCR_RXFTH_32 0x00002000 /* 32 bytes */ +#define RL_RCR_RXFTH_64 0x00004000 /* 64 bytes */ +#define RL_RCR_RXFTH_128 0x00006000 /* 128 bytes */ +#define RL_RCR_RXFTH_256 0x00008000 /* 256 bytes */ +#define RL_RCR_RXFTH_512 0x0000A000 /* 512 bytes */ +#define RL_RCR_RXFTH_1024 0x0000C000 /* 1024 bytes */ +#define RL_RCR_RXFTH_UNLIM 0x0000E000 /* unlimited */ +#define RL_RCR_RBLEM_M 0x00001800 /* Rx Buffer Length */ +#define RL_RCR_RBLEN_8K 0x00000000 /* 8KB + 16 bytes */ +#define RL_RCR_RBLEN_8K_SIZE (8*1024) +#define RL_RCR_RBLEN_16K 0x00000800 /* 16KB + 16 bytes */ +#define RL_RCR_RBLEN_16K_SIZE (16*1024) +#define RL_RCR_RBLEN_32K 0x00001000 /* 32KB + 16 bytes */ +#define RL_RCR_RBLEN_32K_SIZE (32*1024) +#define RL_RCR_RBLEN_64K 0x00001800 /* 64KB + 16 bytes */ +#define RL_RCR_RBLEN_64K_SIZE (64*1024) +#define RL_RCR_MXDMA_M 0x00000700 /* Rx DMA burst size */ +#define RL_RCR_MXDMA_16 0x00000000 /* 16 bytes */ +#define RL_RCR_MXDMA_32 0x00000100 /* 32 bytes */ +#define RL_RCR_MXDMA_64 0x00000200 /* 64 bytes */ +#define RL_RCR_MXDMA_128 0x00000300 /* 128 bytes */ +#define RL_RCR_MXDMA_256 0x00000400 /* 256 bytes */ +#define RL_RCR_MXDMA_512 0x00000500 /* 512 bytes */ +#define RL_RCR_MXDMA_1024 0x00000600 /* 1024 bytes */ +#define RL_RCR_MXDMA_UNLIM 0x00000700 /* unlimited */ +#define RL_RCR_WRAP 0x00000080 /* (Do not) Wrap on receive */ +#define RL_RCR_9356 0x00000040 /* EEPROM 1:9356 0:9346 */ +#define RL_RCR_AER 0x00000020 /* Accept Error Packets */ +#define RL_RCR_AR 0x00000010 /* Accept Runt Packets */ +#define RL_RCR_AB 0x00000008 /* Accept Broadcast Packets */ +#define RL_RCR_AM 0x00000004 /* Accept Multicast Packets */ +#define RL_RCR_APM 0x00000002 /* Accept Physical Match Packets */ +#define RL_RCR_AAP 0x00000001 /* Accept All Packets */ +#define RL_TCTR 0x48 /* Timer Count Register */ +#define RL_MPC 0x4C /* Missed Packet Counter */ +#define RL_9346CR 0x50 /* 93C46 Command Register */ +#define RL_9346CR_EEM_M 0xC0 /* Operating Mode */ +#define RL_9346CR_EEM_NORMAL 0x00 /* Normal Mode */ +#define RL_9346CR_EEM_AUTOLOAD 0x40 /* Load from 93C46 */ +#define RL_9346CR_EEM_PROG 0x80 /* 93C46 Programming */ +#define RL_9346CR_EEM_CONFIG 0xC0 /* Config Write Enable */ +#define RL_9346CR_RES 0x30 /* Reserved */ +#define RL_9346CR_EECS 0x08 /* EECS Pin */ +#define RL_9346CR_EESK 0x04 /* EESK Pin */ +#define RL_9346CR_EEDI 0x02 /* EEDI Pin */ +#define RL_9346CR_EEDO 0x01 /* EEDO Pin */ +#define RL_CONFIG0 0x51 /* Configuration Register 0 */ +#define RL_CFG0_RES 0x000000F8 /* Reserved */ +#define RL_CFG0_ROM 0x00000007 /* Select Boot ROM Size */ +#define RL_CFG0_ROM128K 0x00000005 /* 128K Boot ROM */ +#define RL_CFG0_ROM64K 0x00000004 /* 64K Boot ROM */ +#define RL_CFG0_ROM32K 0x00000003 /* 32K Boot ROM */ +#define RL_CFG0_ROM16K 0x00000002 /* 16K Boot ROM */ +#define RL_CFG0_ROM8K 0x00000001 /* 8K Boot ROM */ +#define RL_CFG0_ROMNO 0x00000000 /* No Boot ROM */ +#define RL_CONFIG1 0x52 /* Configuration Register 1 */ +#define RL_CFG1_LEDS1 0x00000080 /* LED1 */ +#define RL_CFG1_LEDS0 0x00000040 /* LED0 */ +#define RL_CFG1_DVRLOAD 0x00000020 /* Driver Load */ +#define RL_CFG1_LWACT 0x00000010 /* LWAKE Active Mode */ +#define RL_CFG1_MEMMAP 0x00000008 /* Memory Mapping */ +#define RL_CFG1_IOMAP 0x00000004 /* I/O Mapping */ +#define RL_CFG1_VPD 0x00000002 /* Enable Vital Product Data */ +#define RL_CFG1_PME 0x00000001 /* Power Management Enable */ +#define RL_CONFIG2 0x53 /* Configuration Register 2 */ +#define RL_CFG2_RES 0x000000E0 /* Reserved */ +#define RL_CFG2_AUX 0x00000010 /* Auxiliary Power Present Status */ +#define RL_CFG2_PCIBW 0x00000008 /* PCI Bus Width 1:64 0:32 */ +#define RL_CFG2_PCICLK 0x00000007 /* PCI Clock Frequency */ +#define RL_CFG2_66MHZ 0x00000001 /* 66 MHz */ +#define RL_CFG2_33MHZ 0x00000000 /* 33 MHz */ +#define RL_CONFIG3 0x54 /* Configuration Register 3 */ +#define RL_CFG3_MAGIC 0x00000020 /* Wake up when receives a Magic Packet */ +#define RL_CFG3_LINKUP 0x00000010 /* Wake up when the cable connection is re-established */ +#define RL_CFG3_BEACON 0x00000001 /* 8168 only, Reserved in the 8168b */ +#define RL_CONFIG4 0x55 /* Configuration Register 4 */ +#define RL_CONFIG5 0x56 /* Configuration Register 5 */ +#define RL_CFG5_BWF 0x00000040 /* Accept Broadcast Wakeup Frame */ +#define RL_CFG5_MWF 0x00000020 /* Accept Multicast Eakeup Frame */ +#define RL_CFG5_UWF 0x00000010 /* Accept Unicast Wakeup Frame */ +#define RL_CFG5_LAN 0x00000002 /* LANWake Singnal enable/disable */ +#define RL_CFG5_PME 0x00000001 /* PME status can be reset by PCI RST# */ +#define RL_TIMERINT 0x58 /* Timer Interrupt Select */ +#define RL_MULINT 0x5C /* Multiple Interrupt Select */ +/* 0x5E */ /* Reserved */ +/* 0x5F */ /* Reserved */ +#define RL_PHYAR 0x60 /* PHY Access */ +#define RL_TBICSR0 0x64 /* TBI Control and Status Register */ +#define RL_TBIANAR 0x68 /* TBI Auto-Negotiation Advertisement Register */ +#define RL_TBILPAR 0x6A /* TBI Auto-Negotiation Link Partner Ability Register */ +#define RL_PHYSTAT 0x6C /* MII PHY Status */ +#define RL_STAT_TBI 0x00000080 /* TBI Enable */ +#define RL_STAT_TXFLOW 0x00000040 /* Tx Flow Control */ +#define RL_STAT_RXFLOW 0x00000020 /* Rx Flow Control */ +#define RL_STAT_1000 0x00000010 /* 1000 Mbps */ +#define RL_STAT_100 0x00000008 /* 100 Mbps */ +#define RL_STAT_10 0x00000004 /* 10 Mbps */ +#define RL_STAT_LINK 0x00000002 /* Link Status */ +#define RL_STAT_FULLDUP 0x00000001 /* Full Duplex */ + +#define RL_RMS 0xDA /* Rx Maximum Size */ +#define RL_CPLUSCMD 0xE0 /* C+ Command Register */ +#define RL_CPLUS_VLAN 0x00000040 /* Receive VLAN D-tagging Enable */ +#define RL_CPLUS_CHKSUM 0x00000020 /* Receive Checksum Offload Enable */ +#define RL_CPLUS_DAC 0x00000010 /* PCI Dual Address Cycles Enable */ +#define RL_CPLUS_MULRW 0x00000008 /* PCI Multiple Read/Write Enable */ +#define RL_INTRMITIGATE 0xE2 /* Interrupt Mitigate */ +#define RL_RDSAR_LO 0xE4 /* Receive Descriptor Start Address Register + * 256-byte alignment Low*/ +#define RL_RDSAR_HI 0xE8 /* Receive Descriptor Start Address High */ +#define RL_ETTHR 0xEC /* Early Transmit Threshold Register */ +#define RL_FER 0xF0 /* Function Event Register */ +#define RL_FEMR 0xF4 /* Function Event Mask Register */ +#define RL_FPSR 0xF8 /* Function Present State Register */ +#define RL_FFER 0xFC /* Function Force Event Register */ + +/* + * Registers in the Machine Independent Interface (MII) to the PHY. + * IEEE 802.3 (2000 Edition) Clause 22. + */ + +#define MII_CTRL 0x0 /* Control Register (basic) */ +#define MII_CTRL_RST 0x8000 /* Reset PHY */ +#define MII_CTRL_LB 0x4000 /* Enable Loopback Mode */ +#define MII_CTRL_SP_LSB 0x2000 /* Speed Selection (LSB) */ +#define MII_CTRL_ANE 0x1000 /* Auto Negotiation Enable */ +#define MII_CTRL_PD 0x0800 /* Power Down */ +#define MII_CTRL_ISO 0x0400 /* Isolate */ +#define MII_CTRL_RAN 0x0200 /* Restart Auto-Negotiation Process */ +#define MII_CTRL_DM 0x0100 /* Full Duplex */ +#define MII_CTRL_CT 0x0080 /* Enable COL Signal Test */ +#define MII_CTRL_SP_MSB 0x0040 /* Speed Selection (MSB) */ +#define MII_CTRL_SP_10 0x0000 /* 10 Mb/s */ +#define MII_CTRL_SP_100 0x2000 /* 100 Mb/s */ +#define MII_CTRL_SP_1000 0x0040 /* 1000 Mb/s */ +#define MII_CTRL_SP_RES 0x2040 /* Reserved */ +#define MII_CTRL_RES 0x003F /* Reserved */ +#define MII_STATUS 0x1 /* Status Register (basic) */ +#define MII_STATUS_100T4 0x8000 /* 100Base-T4 support */ +#define MII_STATUS_100XFD 0x4000 /* 100Base-X FD support */ +#define MII_STATUS_100XHD 0x2000 /* 100Base-X HD support */ +#define MII_STATUS_10FD 0x1000 /* 10 Mb/s FD support */ +#define MII_STATUS_10HD 0x0800 /* 10 Mb/s HD support */ +#define MII_STATUS_100T2FD 0x0400 /* 100Base-T2 FD support */ +#define MII_STATUS_100T2HD 0x0200 /* 100Base-T2 HD support */ +#define MII_STATUS_EXT_STAT 0x0100 /* Supports MII_EXT_STATUS */ +#define MII_STATUS_RES 0x0080 /* Reserved */ +#define MII_STATUS_MFPS 0x0040 /* MF Preamble Suppression */ +#define MII_STATUS_ANC 0x0020 /* Auto-Negotiation Completed */ +#define MII_STATUS_RF 0x0010 /* Remote Fault Detected */ +#define MII_STATUS_ANA 0x0008 /* Auto-Negotiation Ability */ +#define MII_STATUS_LS 0x0004 /* Link Up */ +#define MII_STATUS_JD 0x0002 /* Jabber Condition Detected */ +#define MII_STATUS_EC 0x0001 /* Ext Register Capabilities */ +#define MII_PHYID_H 0x2 /* PHY ID (high) */ +#define MII_PHYID_L 0x3 /* PHY ID (low) */ +#define MII_ANA 0x4 /* Auto-Negotiation Advertisement */ +#define MII_ANA_NP 0x8000 /* Next PAge */ +#define MII_ANA_RES 0x4000 /* Reserved */ +#define MII_ANA_RF 0x2000 /* Remote Fault */ +#define MII_ANA_TAF_M 0x1FE0 /* Technology Ability Field */ +#define MII_ANA_TAF_S 5 /* Shift */ +#define MII_ANA_TAF_RES 0x1000 /* Reserved */ +#define MII_ANA_PAUSE_ASYM 0x0800 /* Asym. Pause */ +#define MII_ANA_PAUSE_SYM 0x0400 /* Sym. Pause */ +#define MII_ANA_100T4 0x0200 /* 100Base-T4 */ +#define MII_ANA_100TXFD 0x0100 /* 100Base-TX FD */ +#define MII_ANA_100TXHD 0x0080 /* 100Base-TX HD */ +#define MII_ANA_10TFD 0x0040 /* 10Base-T FD */ +#define MII_ANA_10THD 0x0020 /* 10Base-T HD */ +#define MII_ANA_SEL_M 0x001F /* Selector Field */ +#define MII_ANA_SEL_802_3 0x0001 /* 802.3 */ +#define MII_ANLPA 0x5 /* Auto-Neg Link Partner Ability Register */ +#define MII_ANLPA_NP 0x8000 /* Next Page */ +#define MII_ANLPA_ACK 0x4000 /* Acknowledge */ +#define MII_ANLPA_RF 0x2000 /* Remote Fault */ +#define MII_ANLPA_TAF_M 0x1FC0 /* Technology Ability Field */ +#define MII_ANLPA_SEL_M 0x001F /* Selector Field */ +#define MII_ANE 0x6 /* Auto-Negotiation Expansion */ +#define MII_ANE_RES 0xFFE0 /* Reserved */ +#define MII_ANE_PDF 0x0010 /* Parallel Detection Fault */ +#define MII_ANE_LPNPA 0x0008 /* Link Partner is Next Page Able */ +#define MII_ANE_NPA 0x0002 /* Local Device is Next Page Able */ +#define MII_ANE_PR 0x0002 /* New Page has been received */ +#define MII_ANE_LPANA 0x0001 /* Link Partner is Auto-Neg.able */ +#define MII_ANNPT 0x7 /* Auto-Negotiation Next Page Transmit */ +#define MII_ANLPRNP 0x8 /* Auto-Neg Link Partner Received Next Page */ +#define MII_1000_CTRL 0x9 /* 1000BASE-T Control Register */ +#define MII_1000C_FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define MII_1000C_HALF 0x0100 /* Advertise 1000BASE-T half duplex */ +#define MII_1000_STATUS 0xA /* 1000BASE-T Status Register */ +#define MII_1000S_LRXOK 0x2000 /* Link partner local receiver status */ +#define MII_1000S_RRXOK 0x1000 /* Link partner remote receiver status */ +#define MII_1000S_FULL 0x0800 /* Link partner 1000BASE-T full duplex */ +#define MII_1000S_HALF 0x0400 /* Link partner 1000BASE-T half duplex */ +/* 0xB ... 0xE */ /* Reserved */ +#define MII_EXT_STATUS 0xF /* Extended Status */ +#define MII_ESTAT_1000XFD 0x8000 /* 1000Base-X Full Duplex */ +#define MII_ESTAT_1000XHD 0x4000 /* 1000Base-X Half Duplex */ +#define MII_ESTAT_1000TFD 0x2000 /* 1000Base-T Full Duplex */ +#define MII_ESTAT_1000THD 0x1000 /* 1000Base-T Half Duplex */ +#define MII_ESTAT_RES 0x0FFF /* Reserved */ +/* 0x10 ... 0x1F */ /* Vendor Specific */ diff --git a/etc/drivers.conf b/etc/drivers.conf index cd4e83c87..d886cae7b 100644 --- a/etc/drivers.conf +++ b/etc/drivers.conf @@ -465,6 +465,37 @@ driver osscore uid 0; }; +driver rtl8169 +{ + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + #SDEVIO # 22 + SETALARM # 24 + TIMES # 25 + GETINFO # 26 + SAFECOPYFROM # 31 + SAFECOPYTO # 32 + SETGRANT # 34 + MAPDMA # 41 + PROFBUF # 38 + SYSCTL + ; + pci device 10ec/8129; + pci device 10ec/8167; + pci device 10ec/8169; + pci device 1186/4300; + pci device 1259/c107; + pci device 1385/8169; + pci device 16ec/0116; + pci device 1737/1032; + ipc + SYSTEM PM RS LOG TTY DS VM + pci inet amddev + ; +}; + driver filter { system diff --git a/etc/usr/rc b/etc/usr/rc index 390d3f06e..0430f46e5 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -91,7 +91,7 @@ start) fi # start only network drivers that are in use - for driver in lance rtl8139 fxp dpeth dp8390 orinoco + for driver in lance rtl8139 rtl8169 fxp dpeth dp8390 orinoco do if grep " $driver " /etc/inet.conf > /dev/null 2>&1 then