From: Jia-Ju Bai Date: Wed, 2 Nov 2016 13:18:48 +0000 (+0000) Subject: Add the driver for IC Plus 1000A Ethernet card X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=refs%2Fchanges%2F77%2F3377%2F1;p=minix.git Add the driver for IC Plus 1000A Ethernet card Change-Id: I9ac119c6285bc63a8b795b44d9ab7d245d9a8832 --- diff --git a/distrib/sets/lists/minix-base/md.i386 b/distrib/sets/lists/minix-base/md.i386 index c3f049cc2..8b9315ec1 100644 --- a/distrib/sets/lists/minix-base/md.i386 +++ b/distrib/sets/lists/minix-base/md.i386 @@ -15,6 +15,7 @@ ./etc/system.conf.d/es1371 minix-base ./etc/system.conf.d/e1000 minix-base ./etc/system.conf.d/fxp minix-base +./etc/system.conf.d/ip1000 minix-base ./etc/system.conf.d/lance minix-base ./etc/system.conf.d/printer minix-base ./etc/system.conf.d/rtl8139 minix-base @@ -41,6 +42,7 @@ ./service/floppy minix-base ./service/fxp minix-base ./service/hgfs minix-base +./service/ip1000 minix-base ./service/lance minix-base ./service/pci minix-base ./service/pckbd minix-base diff --git a/distrib/sets/lists/minix-debug/md.i386 b/distrib/sets/lists/minix-debug/md.i386 index ee66c819e..639c5c937 100644 --- a/distrib/sets/lists/minix-debug/md.i386 +++ b/distrib/sets/lists/minix-debug/md.i386 @@ -27,6 +27,7 @@ ./usr/libdata/debug/service/floppy.debug minix-debug debug ./usr/libdata/debug/service/fxp.debug minix-debug debug ./usr/libdata/debug/service/hgfs.debug minix-debug debug +./usr/libdata/debug/service/ip1000.debug minix-debug debug ./usr/libdata/debug/service/lance.debug minix-debug debug ./usr/libdata/debug/service/pci.debug minix-debug debug ./usr/libdata/debug/service/pckbd.debug minix-debug debug diff --git a/minix/drivers/net/Makefile b/minix/drivers/net/Makefile index b8c4e479b..7888a7d47 100644 --- a/minix/drivers/net/Makefile +++ b/minix/drivers/net/Makefile @@ -8,6 +8,7 @@ SUBDIR+= dp8390 SUBDIR+= dpeth SUBDIR+= e1000 SUBDIR+= fxp +SUBDIR+= ip1000 SUBDIR+= lance SUBDIR+= rtl8139 SUBDIR+= rtl8169 diff --git a/minix/drivers/net/ip1000/Makefile b/minix/drivers/net/ip1000/Makefile new file mode 100644 index 000000000..d8ac6c81c --- /dev/null +++ b/minix/drivers/net/ip1000/Makefile @@ -0,0 +1,14 @@ +# Makefile for the Ethernet drivers +PROG= ip1000 +SRCS= ip1000.c + +FILES=${PROG}.conf +FILESNAME=${PROG} +FILESDIR= /etc/system.conf.d + +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys + +CPPFLAGS+= -I${NETBSDSRCDIR}/minix + +.include diff --git a/minix/drivers/net/ip1000/README b/minix/drivers/net/ip1000/README new file mode 100644 index 000000000..399dba793 --- /dev/null +++ b/minix/drivers/net/ip1000/README @@ -0,0 +1,19 @@ +The ip1000 driver is for IC Plus 1000A/Family (ST1023) Ethernet card. + +This driver is referred to Minix(3.4.0) vt6105 driver, +Linux(4.2.1) ipg driver and IP1000A LF-DS-R08 datasheet. + +The supported PCI number is 13F0:1023:13F0:1023. +Maybe the Ethernet cards of other PCI numbers for IC Plus can be supported. + +Revision 1.0 2016/11/02 +Authored by Jia-Ju Bai + +Revision 1.1 2016/11/12 +Modification: Remove and rewrite Linux-derived code +Authored by Jia-Ju Bai + +Something can be improved: +1. Ethernet address can not be modified at present. +2. Dump interfaces are not provided. +3. The device needs serveral seconds to work normally after initialization. diff --git a/minix/drivers/net/ip1000/io.h b/minix/drivers/net/ip1000/io.h new file mode 100644 index 000000000..14d67d531 --- /dev/null +++ b/minix/drivers/net/ip1000/io.h @@ -0,0 +1,84 @@ +#ifndef _IO_H +#define _IO_H + +#include +#include +#include "ip1000.h" + +/* I/O function */ +static u8_t my_inb(u32_t port) { + u32_t value; + int r; +#ifdef DMA_REG_MODE + value = *(u8_t *)(port); +#else + if ((r = sys_inb(port, &value)) != OK) + printf("ip1000: sys_inb failed: %d\n", r); +#endif + return (u8_t)value; +} +#define ic_in8(port, offset) (my_inb((port) + (offset))) + +static u16_t my_inw(u32_t port) { + u32_t value; + int r; +#ifdef DMA_REG_MODE + value = *(u16_t *)(port); +#else + if ((r = sys_inw(port, &value)) != OK) + printf("ip1000: sys_inw failed: %d\n", r); +#endif + return (u16_t)value; +} +#define ic_in16(port, offset) (my_inw((port) + (offset))) + +static u32_t my_inl(u32_t port) { + u32_t value; + int r; +#ifdef DMA_REG_MODE + value = *(u32_t *)(port); +#else + if ((r = sys_inl(port, &value)) != OK) + printf("ip1000: sys_inl failed: %d\n", r); +#endif + return value; +} +#define ic_in32(port, offset) (my_inl((port) + (offset))) + +static void my_outb(u32_t port, u8_t value) { + int r; +#ifdef DMA_REG_MODE + *(u8_t *)(port) = value; +#else + if ((r = sys_outb(port, value)) != OK) + printf("ip1000: sys_outb failed: %d\n", r); +#endif +} +#define ic_out8(port, offset, value) \ + (my_outb(((port) + (offset)), (value))) + +static void my_outw(u32_t port, u16_t value) { + int r; +#ifdef DMA_REG_MODE + *(u16_t *)(port) = value; +#else + if ((r = sys_outw(port, value)) != OK) + printf("ip1000: sys_outw failed: %d\n", r); +#endif +} +#define ic_out16(port, offset, value) \ + (my_outw(((port) + (offset)), (value))) + +static void my_outl(u16_t port, u32_t value) { + int r; +#ifdef DMA_REG_MODE + *(u32_t *)(port) = value; +#else + if ((r = sys_outl(port, value)) != OK) + printf("ip1000: sys_outl failed: %d\n", r); +#endif +} +#define ic_out32(port, offset, value) \ + (my_outl(((port) + (offset)), (value))) + +#endif diff --git a/minix/drivers/net/ip1000/ip1000.c b/minix/drivers/net/ip1000/ip1000.c new file mode 100644 index 000000000..7da45e301 --- /dev/null +++ b/minix/drivers/net/ip1000/ip1000.c @@ -0,0 +1,1006 @@ +#include +#include +#include +#include "ip1000.h" +#include "io.h" + +/* global value */ +static ic_driver g_driver; +static int g_instance; + +/* driver interface */ +static int ic_init(unsigned int instance, ether_addr_t *addr); +static void ic_stop(void); +static void ic_mode(unsigned int mode); +static ssize_t ic_recv(struct netdriver_data *data, size_t max); +static int ic_send(struct netdriver_data *data, size_t size); +static void ic_intr(unsigned int mask); +static void ic_stat(eth_stat_t *stat); + +/* internal function */ +static int ic_probe(ic_driver *pdev, int instance); +static int ic_init_buf(ic_driver *pdev); +static int ic_init_hw(ic_driver *pdev, ether_addr_t *addr); +static int ic_reset_hw(ic_driver *pdev); +static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr); +static void ic_handler(ic_driver *pdev); +static void ic_check_ints(ic_driver *pdev); + +/* developer interface */ +static void ic_init_rx_desc(ic_desc *desc, size_t size, phys_bytes dma); +static void ic_init_tx_desc(ic_desc *desc, size_t size, phys_bytes dma); +static int ic_real_reset(u32_t base); +static int ic_init_power(u32_t base); +static int ic_init_mii(u32_t base); +static int ic_init_io(u32_t base); +static void ic_start_rx_tx(u32_t base); +static void ic_get_addr(u32_t base, u8_t *pa); +static int ic_check_link(u32_t base); +static void ic_stop_rx_tx(u32_t base); +static int ic_rx_status_ok(ic_desc *desc); +static int ic_get_rx_len(ic_desc *desc); +static void ic_tx_desc_start(ic_desc *desc, size_t size); +static void ic_wakeup_tx(u32_t base); +static int ic_tx_status_ok(ic_desc *desc); + +/* ======= Developer-defined function ======= */ +/* ====== Self-defined function ======*/ + +static u16_t read_eeprom(u32_t base, int addr) { + u16_t ret, data, val; + int i; + + val = EC_READ | (addr & 0xff); + ic_out16(base, REG_EEPROM_CTRL, val); + for (i = 0; i < 100; i++) { + micro_delay(10000); + data = ic_in16(base, REG_EEPROM_CTRL); + if (!(data & EC_BUSY)) { + ret = ic_in16(base, REG_EEPROM_DATA); + break; + } + } + if (i == 100) + printf("IP1000: Fail to read EEPROM\n"); + return ret; +} + +static u16_t read_phy_reg(u32_t base, int phy_addr, int phy_reg) { + int i, j, fieldlen[8]; + u32_t field[8]; + u8_t data, polar; + + field[0] = 0xffffffff; fieldlen[0] = 32; + field[1] = 0x0001; fieldlen[1] = 2; + field[2] = 0x0002; fieldlen[2] = 2; + field[3] = phy_addr; fieldlen[3] = 5; + field[4] = phy_reg; fieldlen[4] = 5; + field[5] = 0x0000; fieldlen[5] = 2; + field[6] = 0x0000; fieldlen[6] = 16; + field[7] = 0x0000; fieldlen[7] = 1; + + polar = ic_in8(base, REG_PHY_CTRL) & 0x28; + for (i = 0; i < 5; i++) { + for (j = 0; j < fieldlen[i]; j++) { + data = (field[i] >> (fieldlen[i] - j - 1)) << 1; + data = (0x02 & data) | (0x04 | polar); + ic_out8(base, REG_PHY_CTRL, data); + micro_delay(10); + ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + micro_delay(10); + } + } + ic_out8(base, REG_PHY_CTRL, (polar | 0x04)); + micro_delay(10); + ic_out8(base, REG_PHY_CTRL, (polar | 0x05)); + micro_delay(10); + ic_out8(base, REG_PHY_CTRL, polar); + micro_delay(10); + data = ic_in8(base, REG_PHY_CTRL); + ic_out8(base, REG_PHY_CTRL, (polar | 0x01)); + micro_delay(10); + for (i = 0; i < fieldlen[6]; i++) { + ic_out8(base, REG_PHY_CTRL, polar); + micro_delay(10); + data = ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1) & 0x01; + ic_out8(base, REG_PHY_CTRL, (polar | 0x01)); + micro_delay(10); + field[6] |= (data << (fieldlen[6] - i - 1)); + } + + for (i = 0; i < 3; i++) { + ic_out8(base, REG_PHY_CTRL, (polar | 0x04)); + micro_delay(10); + ic_out8(base, REG_PHY_CTRL, (polar | 0x05)); + micro_delay(10); + } + ic_out8(base, REG_PHY_CTRL, (polar | 0x04)); + return field[6]; +} + +static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) { + int i, j, fieldlen[8]; + u32_t field[8]; + u8_t data, polar; + + field[0] = 0xffffffff; fieldlen[0] = 32; + field[1] = 0x0001; fieldlen[1] = 2; + field[2] = 0x0001; fieldlen[2] = 2; + field[3] = phy_addr; fieldlen[3] = 5; + field[4] = phy_reg; fieldlen[4] = 5; + field[5] = 0x0002; fieldlen[5] = 2; + field[6] = val; fieldlen[6] = 16; + field[7] = 0x0000; fieldlen[7] = 1; + + polar = ic_in8(base, REG_PHY_CTRL) & 0x28; + for (i = 0; i < 7; i++) { + for (j = 0; j < fieldlen[i]; j++) { + data = (field[i] >> (field[j] - j - 1)) << 1; + data = (0x02 & data) | (0x04 | polar); + ic_out8(base, REG_PHY_CTRL, data); + micro_delay(10); + ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + micro_delay(10); + } + } + for (i = 0; i < fieldlen[7]; i ++) { + ic_out8(base, REG_PHY_CTRL, polar); + micro_delay(10); + field[7] |= ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1) + << (fieldlen[7] - i -1); + ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + micro_delay(10); + } +} + +/* ====== Developer interface ======*/ + +/* Intialize Rx descriptor (### RX_DESC_INIT ###) */ +static void ic_init_rx_desc(ic_desc *desc, size_t size, phys_bytes dma) { + desc->status = 0x0000000000000000ULL; + desc->frag_info = (u64_t)dma; + desc->frag_info |= ((u64_t)size << 48) & RFI_FRAG_LEN; +} + +/* Intialize Tx descriptor (### TX_DESC_INIT ###) */ +static void ic_init_tx_desc(ic_desc *desc, size_t size, phys_bytes dma) { + desc->status = TFS_TFD_DONE; + desc->frag_info = (u64_t)dma; +} + +/* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int ic_real_reset(u32_t base) { + u32_t data; + data = ic_in32(base, REG_ASIC_CTRL); + data |= AC_RESET_ALL; + ic_out32(base, REG_ASIC_CTRL, data); + micro_delay(10000); + if (ic_in32(base, REG_ASIC_CTRL) & AC_RESET_BUSY) + return -EIO; + return OK; +} + +/* Intialize power (### POWER_INIT_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int ic_init_power(u32_t base) { + u8_t physet; + u32_t mode0, mode1; + + mode0 = read_eeprom(base, 6); + mode1 = ic_in16(base, REG_ASIC_CTRL); + mode1 &= ~(AC_LED_MODE_B1 | AC_LED_MODE | AC_LED_SPEED); + if ((mode0 & 0x03) > 1) + mode1 |= AC_LED_MODE_B1; + if ((mode0 & 0x01) == 1) + mode1 |= AC_LED_MODE; + if ((mode0 & 0x08) == 8) + mode1 |= AC_LED_SPEED; + ic_out32(base, REG_ASIC_CTRL, mode1); + + physet = ic_in8(base, REG_PHY_SET); + physet &= ~(0x07); + physet |= (mode0 & 0x70) >> 4; + ic_out8(base, REG_PHY_SET, physet); + + return OK; +} + +/* Intialize MII interface (### MII_INIT_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int ic_init_mii(u32_t base) { + int i, phyaddr; + u8_t revision; + u16_t phyctrl, cr1000, length, address, value; + u16_t *param; + u32_t status; + + for (i = 0; i < 32; i++) { + phyaddr = (i + 0x01) % 32; + status = read_phy_reg(base, phyaddr, 0x01); + if ((status != 0xffff) && (status != 0)) + break; + } + if (i == 32) + return -EIO; + if (phyaddr != -1) { + cr1000 = read_phy_reg(base, phyaddr, 0x09); + cr1000 |= 0x0700; + write_phy_reg(base, phyaddr, 0x09, cr1000); + phyctrl = read_phy_reg(base, phyaddr, 0x00); + } + + param = &PhyParam[0]; + length = (*param) & 0x00ff; + revision = (u8_t)((*param) >> 8); + param++; + while (length != 0) { + if (g_driver.revision == revision) { + while (length > 1) { + address = *param; + value = *(param + 1); + param += 2; + write_phy_reg(base, phyaddr, address, value); + length -= 4; + } + break; + } + else { + param += length / 2; + length = *param & 0x00ff; + revision = (u8_t)((*param) >> 8); + param++; + } + } + + phyctrl |= 0x8200; + write_phy_reg(base, phyaddr, 0x00, phyctrl); + + return OK; +} + +/* Intialize other hardware I/O registers (### INIT_HARDWARE_IO_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int ic_init_io(u32_t base) { + u32_t mac_ctrl; + + mac_ctrl = ic_in32(base, REG_MAC_CTRL); + mac_ctrl |= (MC_STAT_DISABLE | MC_TX_FC_ENA | MC_RX_FC_ENA); + ic_out32(base, REG_MAC_CTRL, 0x00000000); + ic_out16(base, REG_MAX_FRAME, RX_BUF_SIZE); + ic_out8(base, REG_RX_DMA_PERIOD, 0x01); + ic_out8(base, REG_RX_DMA_UTH, 0x30); + ic_out8(base, REG_RX_DMA_BTH, 0x30); + ic_out8(base, REG_TX_DMA_PERIOD, 0x26); + ic_out8(base, REG_TX_DMA_UTH, 0x04); + ic_out8(base, REG_TX_DMA_BTH, 0x30); + ic_out16(base, REG_FLOW_ON_TH, 0x0740); + ic_out16(base, REG_FLOW_OFF_TH, 0x00bf); + ic_out32(base, REG_MAC_CTRL, mac_ctrl); + return OK; +} + +/* Start Rx/Tx (### START_RX_TX ###) */ +static void ic_start_rx_tx(u32_t base) { + u32_t mac_ctrl; + + mac_ctrl = ic_in32(base, REG_MAC_CTRL); + mac_ctrl |= (MC_RX_ENABLE | MC_TX_ENABLE); + ic_out32(base, REG_MAC_CTRL, mac_ctrl); +} + +/* Get MAC address to the array 'pa' (### GET_MAC_ADDR ###) */ +static void ic_get_addr(u32_t base, u8_t *pa) { + int i, sta_addr[3]; + for (i = 0; i < 3; i++) { + sta_addr[i] = read_eeprom(base, 16 + i); + ic_out16(base, (REG_STA_ADDR0 + i * 2), sta_addr[i]); + } + pa[0] = (u8_t)(ic_in16(base, REG_STA_ADDR0) & 0x00ff); + pa[1] = (u8_t)((ic_in16(base, REG_STA_ADDR0) & 0xff00) >> 8); + pa[2] = (u8_t)(ic_in16(base, REG_STA_ADDR1) & 0x00ff); + pa[3] = (u8_t)((ic_in16(base, REG_STA_ADDR1) & 0xff00) >> 8); + pa[4] = (u8_t)(ic_in16(base, REG_STA_ADDR2) & 0x00ff); + pa[5] = (u8_t)((ic_in16(base, REG_STA_ADDR2) & 0xff00) >> 8); +} + +/* Check link status (### CHECK_LINK ###) + * -- Return LINK_UP or LINK_DOWN */ +static int ic_check_link(u32_t base) { + u8_t phy_ctrl; + u32_t mac_ctrl; + int ret; + char speed[20], duplex[20]; + + phy_ctrl = ic_in8(base, REG_PHY_CTRL); + mac_ctrl = ic_in8(base, REG_MAC_CTRL); + switch (phy_ctrl & PC_LINK_SPEED) { + case PC_LINK_SPEED10: + strcpy(speed, "10Mbps"); + ret = LINK_UP; + break; + case PC_LINK_SPEED100: + strcpy(speed, "100Mbps"); + ret = LINK_UP; + break; + case PC_LINK_SPEED1000: + strcpy(speed, "1000Mbps"); + ret = LINK_UP; + break; + default: + strcpy(speed, "unknown"); + ret = LINK_DOWN; + break; + } + if (phy_ctrl & PC_DUPLEX_STS) { + strcpy(duplex, "full"); + mac_ctrl |= (MC_DUPLEX_SEL | MC_TX_FC_ENA | MC_RX_FC_ENA); + } + else + strcpy(duplex, "half"); + ic_out32(base, REG_MAC_CTRL, mac_ctrl); +#ifdef MY_DEBUG + printf("ip1000: Link speed is %s, %s duplex\n", speed, duplex); +#endif + return ret; +} + +/* Stop Rx/Tx (### STOP_RX_TX ###) */ +static void ic_stop_rx_tx(u32_t base) { + ic_out32(base, REG_ASIC_CTRL, AC_RESET_ALL); +} + +/* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###) + * -- Return TRUE or FALSE */ +static int ic_rx_status_ok(ic_desc *desc) { + if ((desc->status & RFS_NORMAL) == RFS_NORMAL) + return TRUE; + return FALSE; +} + +/* Get Rx data length from descriptor (### GET_RX_LEN ###) + * --- Return the length */ +static int ic_get_rx_len(ic_desc *desc) { + int totlen; + totlen = (u32_t)(desc->status & RFS_FRAME_LEN); + return totlen; +} + +/* Set Tx descriptor in send (### TX_DESC_START ###) */ +static void ic_tx_desc_start(ic_desc *desc, size_t size) { + desc->status = TFS_TFD_DONE; + desc->status |= (u64_t)(TFS_WORD_ALIGN | (TFS_FRAMEID & (g_driver.tx_head)) + | (TFS_FRAG_COUNT & (1 << 24))); + desc->status |= TFS_TX_DMA_INDICATE; + desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((size >= 60 ? size : 60) & + 0xffff) << 48); + desc->status &= (u64_t)(~(TFS_TFD_DONE)); +} + +/* Wake up Tx channel (### WAKE_UP_TX ###) */ +static void ic_wakeup_tx(u32_t base) { + ic_out32(base, REG_DMA_CTRL, 0x00001000); +} + +/* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###) + * -- Return TRUE or FALSE */ +static int ic_tx_status_ok(ic_desc *desc) { + if (desc->status & TFS_TFD_DONE) + return TRUE; + return FALSE; +} + +/* Driver interface table */ +static const struct netdriver ic_table = { + .ndr_init = ic_init, + .ndr_stop = ic_stop, + .ndr_mode = ic_mode, + .ndr_recv = ic_recv, + .ndr_send = ic_send, + .ndr_stat = ic_stat, + .ndr_intr = ic_intr, +}; + +int main(int argc, char *argv[]) { + env_setargs(argc, argv); + netdriver_task(&ic_table); +} + +/* Initialize the driver */ +static int ic_init(unsigned int instance, ether_addr_t *addr) { + int ret = 0; + + /* Intialize driver data structure */ + memset(&g_driver, 0, sizeof(g_driver)); + g_driver.link = LINK_UNKNOWN; + strcpy(g_driver.name, "netdriver#0"); + g_driver.name[10] += instance; + g_instance = instance; + + /* Probe the device */ + if (ic_probe(&g_driver, instance)) { + printf("ip1000: Device is not found\n"); + ret = -ENODEV; + goto err_probe; + } + + /* Allocate and initialize buffer */ + if (ic_init_buf(&g_driver)) { + printf("ip1000: Fail to initialize buffer\n"); + ret = -ENODEV; + goto err_init_buf; + } + + /* Intialize hardware */ + if (ic_init_hw(&g_driver, addr)) { + printf("ip1000: Fail to initialize hardware\n"); + ret = -EIO; + goto err_init_hw; + } + + /* Use a synchronous alarm instead of a watchdog timer */ + sys_setalarm(sys_hz(), 0); + + /* Clear send and recv flag */ + g_driver.send_flag = FALSE; + g_driver.recv_flag = FALSE; + + return 0; + +err_init_hw: + free_contig(g_driver.buf, g_driver.buf_size); +err_init_buf: +err_probe: + return ret; +} + +/* Match the device and get base address */ +static int ic_probe(ic_driver *pdev, int instance) { + int devind, ioflag; + u16_t cr, vid, did; + u32_t bar, size; + u8_t irq, rev; + u8_t *reg; + + /* Find pci device */ + pci_init(); + if (!pci_first_dev(&devind, &vid, &did)) + return -EIO; + while (instance--) { + if (!pci_next_dev(&devind, &vid, &did)) + return -EIO; + } + pci_reserve(devind); + + /* Enable bus mastering */ + cr = pci_attr_r16(devind, PCI_CR); + if (!(cr & PCI_CR_MAST_EN)) + pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); + + /* Get base address */ +#ifdef DMA_REG_MODE + if (pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) { + printf("ip1000: Fail to get PCI BAR\n"); + return -EIO; + } + if (ioflag) { + printf("ip1000: PCI BAR is not for memory\n"); + return -EIO; + } + if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) { + printf("ip1000: Fail to map hardware registers from PCI\n"); + return -EIO; + } + pdev->base_addr = (u32_t)reg; +#else + bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; + if (bar < 0x400) { + printf("ip1000: Base address is not properly configured\n"); + return -EIO; + } + pdev->base_addr = bar; +#endif + + /* Get irq number */ + irq = pci_attr_r8(devind, PCI_ILR); + pdev->irq = irq; + + /* Get revision ID */ + rev = pci_attr_r8(devind, PCI_REV); + pdev->revision = rev; + +#ifdef MY_DEBUG + printf("ip1000: Base address is 0x%08x\n", pdev->base_addr); + printf("ip1000: IRQ number is 0x%02x\n", pdev->irq); + printf("ip1000: Revision ID is 0x%02x\n", pdev->revision); +#endif + + return 0; +} + +/* Allocate and initialize buffer */ +static int ic_init_buf(ic_driver *pdev) { + size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size; + ic_desc *desc; + phys_bytes buf_dma, next; + char *buf; + int i; + + /* Build Rx and Tx descriptor buffer */ + rx_desc_size = RX_DESC_NUM * sizeof(ic_desc); + tx_desc_size = TX_DESC_NUM * sizeof(ic_desc); + + /* Allocate Rx and Tx buffer */ + tx_buf_size = TX_BUF_SIZE; + if (tx_buf_size % 4) + tx_buf_size += 4 - (tx_buf_size % 4); + rx_buf_size = RX_BUF_SIZE; + tot_buf_size = rx_desc_size + tx_desc_size; + tot_buf_size += TX_DESC_NUM * tx_buf_size + RX_DESC_NUM * rx_buf_size; + if (tot_buf_size % 4096) + tot_buf_size += 4096 - (tot_buf_size % 4096); + + if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) { + printf("ip1000: Fail to allocate memory\n"); + return -ENOMEM; + } + pdev->buf_size = tot_buf_size; + pdev->buf = buf; + + /* Rx descriptor */ + pdev->rx_desc = (ic_desc *)buf; + pdev->rx_desc_dma = buf_dma; + memset(buf, 0, rx_desc_size); + buf += rx_desc_size; + buf_dma += rx_desc_size; + + /* Tx descriptor */ + pdev->tx_desc = (ic_desc *)buf; + pdev->tx_desc_dma = buf_dma; + memset(buf, 0, tx_desc_size); + buf += tx_desc_size; + buf_dma += tx_desc_size; + + /* Rx buffer assignment */ + desc = pdev->rx_desc; + next = pdev->rx_desc_dma; + for (i = 0; i < RX_DESC_NUM; i++) { + /* Set Rx buffer */ + pdev->rx[i].buf_dma = buf_dma; + pdev->rx[i].buf = buf; + buf_dma += rx_buf_size; + buf += rx_buf_size; + + /* Set Rx descriptor */ + /* ### RX_DESC_INIT ### */ + ic_init_rx_desc(desc, rx_buf_size, pdev->rx[i].buf_dma); + if (i == (RX_DESC_NUM - 1)) + desc->next = pdev->rx_desc_dma; + else { + next += sizeof(ic_desc); + desc->next = next; + desc++; + } + } + + /* Tx buffer assignment */ + desc = pdev->tx_desc; + next = pdev->tx_desc_dma; + for (i = 0; i < TX_DESC_NUM; i++) { + /* Set Tx buffer */ + pdev->tx[i].busy = 0; + pdev->tx[i].buf_dma = buf_dma; + pdev->tx[i].buf = buf; + buf_dma += tx_buf_size; + buf += tx_buf_size; + + /* Set Rx descriptor */ + /* ### TX_DESC_INIT ### */ + ic_init_tx_desc(desc, tx_buf_size, pdev->tx[i].buf_dma); + if (i == (TX_DESC_NUM - 1)) + desc->next = pdev->tx_desc_dma; + else { + next += sizeof(ic_desc); + desc->next = next; + desc++; + } + } + pdev->tx_busy_num = 0; + pdev->tx_head = 0; + pdev->tx_tail = 0; + pdev->rx_head = 0; + + return 0; +} + +/* Intialize hardware */ +static int ic_init_hw(ic_driver *pdev, ether_addr_t *addr) { + int r, ret; + + /* Set the OS interrupt handler */ + pdev->hook = pdev->irq; + if ((r = sys_irqsetpolicy(pdev->irq, 0, &pdev->hook)) != OK) { + printf("ip1000: Fail to set OS IRQ policy: %d\n", r); + ret = -EFAULT; + goto err_irq_policy; + } + + /* Reset hardware */ + if (ic_reset_hw(pdev)) { + printf("ip1000: Fail to reset the device\n"); + ret = -EIO; + goto err_reset_hw; + } + + /* Enable OS IRQ */ + if ((r = sys_irqenable(&pdev->hook)) != OK) { + printf("ip1000: Fail to enable OS IRQ: %d\n", r); + ret = -EFAULT; + goto err_irq_enable; + } + + /* Configure MAC address */ + ic_conf_addr(pdev, addr); + + /* Detect link status */ + pdev->link = ic_check_link(pdev->base_addr); +#ifdef MY_DEBUG + if (pdev->link) + printf("ip1000: Link up\n"); + else + printf("ip1000: Link down\n"); +#endif + + return 0; + +err_reset_hw: +err_irq_enable: +err_irq_policy: + return ret; +} + +/* Reset hardware */ +static int ic_reset_hw(ic_driver *pdev) { + u32_t base = pdev->base_addr; + int ret; + + /* Reset the chip */ + /* ### RESET_HARDWARE_CAN_FAIL ### */ + if (ic_real_reset(base)) { + printf("ip1000: Fail to reset the hardware\n"); + ret = -EIO; + goto err_real_reset; + } + + /* Initialize power */ + /* ### POWER_INIT_CAN_FAIL ### */ + if (ic_init_power(base)) { + printf("ip1000: Fail to initialize power\n"); + ret = -EIO; + goto err_init_power; + } + + /* Initialize MII interface */ + /* ### MII_INIT_CAN_FAIL ### */ + if (ic_init_mii(base)) { + printf("ip1000: Fail to initialize MII interface\n"); + ret = -EIO; + goto err_init_mii; + } + + /* Initialize hardware I/O registers */ + /* ### SET_RX_DESC_REG ### */ + if (ic_init_io(base)) { + printf("ip1000: Fail to initialize I/O registers\n"); + ret = -EIO; + goto err_init_io; + } + + /* Set Rx/Tx descriptor into register */ + /* ### SET_RX_DESC_REG ### */ + ic_out32(base, REG_RX_DESC_BASEL, pdev->rx_desc_dma); +#ifdef DESC_BASE_DMA64 + ic_out32(base, REG_RX_DESC_BASEU, 0x00000000); +#endif + /* ### SET_TX_DESC_REG ### */ + ic_out32(base, REG_TX_DESC_BASEL, pdev->tx_desc_dma); +#ifdef DESC_BASE_DMA64 + ic_out32(base, REG_TX_DESC_BASEU, 0x00000000); +#endif + + /* Enable interrupts */ + /* ### ENABLE_INTR ### */ + ic_out16(base, REG_IMR, INTR_IMR_ENABLE); + + /* Start the device, Rx and Tx */ + /* ### START_RX_TX ### */ + ic_start_rx_tx(base); + + return 0; + +err_init_io: +err_init_mii: +err_init_power: +err_real_reset: + return ret; +} + +/* Configure MAC address */ +static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr) { + u8_t pa[6]; + u32_t base = pdev->base_addr; + + /* Get MAC address */ + /* ### GET_MAC_ADDR ### */ + ic_get_addr(base, pa); + addr->ea_addr[0] = pa[0]; + addr->ea_addr[1] = pa[1]; + addr->ea_addr[2] = pa[2]; + addr->ea_addr[3] = pa[3]; + addr->ea_addr[4] = pa[4]; + addr->ea_addr[5] = pa[5]; +#ifdef MY_DEBUG + printf("ip1000: Ethernet address is %02x:%02x:%02x:%02x:%02x:%02x\n", + addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2], + addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5]); +#endif +} + +/* Stop the driver */ +static void ic_stop(void) { + u32_t base = g_driver.base_addr; + + /* Free Rx and Tx buffer*/ + free_contig(g_driver.buf, g_driver.buf_size); + + /* Stop interrupt */ + /* ### DISABLE_INTR ### */ + ic_out16(base, REG_IMR, INTR_IMR_DISABLE); + + /* Stop Rx/Tx */ + /* ### STOP_RX_TX ### */ + ic_stop_rx_tx(base); +} + +/* Set driver mode */ +static void ic_mode(unsigned int mode) { + ic_driver *pdev = &g_driver; + u32_t base = pdev->base_addr; + u8_t rcr; + + pdev->mode = mode; + + /* ### READ_RCR ### */ + rcr = ic_in8(base, REG_RCR); + rcr &= ~(RCR_UNICAST | RCR_MULTICAST | RCR_BROADCAST); + if (pdev->mode & NDEV_PROMISC) + rcr |= RCR_UNICAST | RCR_MULTICAST; + if (pdev->mode & NDEV_BROAD) + rcr |= RCR_BROADCAST; + if (pdev->mode & NDEV_MULTI) + rcr |= RCR_MULTICAST; + rcr |= RCR_UNICAST; + /* ### WRITE_RCR ### */ + ic_out8(base, REG_RCR, rcr); +} + +/* Receive data */ +static ssize_t ic_recv(struct netdriver_data *data, size_t max) { + ic_driver *pdev = &g_driver; + u32_t totlen, packlen; + ic_desc *desc; + int index, i; + + index = pdev->rx_head; + desc = pdev->rx_desc; + desc += index; + + /* Check whether the receiving is OK */ + /* ### CHECK_RX_STATUS_OK ### */ + if (ic_rx_status_ok(desc) != TRUE) + return SUSPEND; + + /* Check Rx status error */ + /* ### CHECK_RX_STATUS_ERROR ### */ + if (desc->status & DESC_STATUS_RX_RECV_ERR) + printf("ip1000: Rx error\n"); + + /* Get data length */ + /* ### Get Rx data length ### */ + totlen = ic_get_rx_len(desc); + if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) { + printf("ip1000: Bad data length: %d\n", totlen); + panic(NULL); + } + + packlen = totlen; + if (packlen > max) + packlen = max; + + /* Copy data to user */ + netdriver_copyout(data, 0, pdev->rx[index].buf, packlen); + pdev->stat.ets_packetR++; + + /* Set Rx descriptor status */ + /* ### SET_RX_STATUS_INTR ### */ + desc->status = DESC_STATUS_RX_RECV_CLEAR; + if (index == RX_DESC_NUM - 1) + index = 0; + else + index++; + pdev->rx_head = index; + +#ifdef MY_DEBUG + printf("ip1000: Successfully receive a packet, length = %d\n", packlen); +#endif + + return packlen; +} + +/* Transmit data */ +static int ic_send(struct netdriver_data *data, size_t size) { + ic_driver *pdev = &g_driver; + ic_desc *desc; + int tx_head, i; + u32_t base = pdev->base_addr; + + tx_head = pdev->tx_head; + desc = pdev->tx_desc; + desc += tx_head; + + if (pdev->tx[tx_head].busy) + return SUSPEND; + + /* Copy data from user */ + netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size); + + /* Set busy */ + pdev->tx[tx_head].busy = TRUE; + pdev->tx_busy_num++; + + /* Set Tx descriptor status */ + /* ### TX_DESC_START ### */ + ic_tx_desc_start(desc, size); + if (tx_head == TX_DESC_NUM - 1) + tx_head = 0; + else + tx_head++; + pdev->tx_head = tx_head; + + /* Wake up transmit channel */ + /* ### WAKE_UP_TX ### */ + ic_wakeup_tx(base); + + return 0; +} + +/* Handle Interrupt */ +static void ic_intr(unsigned int mask) { + int s; + + /* Run interrupt handler at driver level */ + ic_handler(&g_driver); + + /* Reenable interrupts for this hook */ + if ((s = sys_irqenable(&g_driver.hook)) != OK) + printf("ip1000: Cannot enable OS interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions */ + ic_check_ints(&g_driver); +} + +/* Real handler interrupt */ +static void ic_handler(ic_driver *pdev) { + u32_t base = pdev->base_addr; + u16_t intr_status; + int flag = 0, tx_head, tx_tail; + ic_desc *desc; + + /* Get interrupt status */ + /* ### GET_INTR_STATUS ### */ + intr_status = ic_in16(base, REG_ISR); + + /* Clear interrupt */ + /* ### CLEAR_INTR ### */ + ic_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); + + /* Enable interrupt */ + /* ### ENABLE_INTR ### */ + ic_out16(base, REG_IMR, INTR_IMR_ENABLE); + + /* Check interrupt error */ + /* ### CHECK_INTR_ERROR ### */ + if (intr_status & INTR_ISR_ERR) { + printf("ip1000: interrupt error\n"); + return; + } + + /* Check link status */ + /* ### CHECK_LINK_INTR ### */ + if (intr_status & INTR_ISR_LINK_EVENT) { + pdev->link = ic_check_link(base); +#ifdef MY_DEBUG + printf("ip1000: Link state change\n"); +#endif + flag++; + } + + /* Check Rx request status */ + /* ### CHECK_RX_INTR ### */ + if (intr_status & INTR_ISR_RX_DONE) { + pdev->recv_flag = TRUE; + flag++; + } + + /* Check Tx request status */ + /* ### CHECK_TX_INTR ### */ + if (intr_status & INTR_ISR_TX_DONE) { + pdev->send_flag = TRUE; + flag++; + + /* Manage Tx Buffer */ + tx_head = pdev->tx_head; + tx_tail = pdev->tx_tail; + while (tx_tail != tx_head) { + desc = pdev->tx_desc; + desc += tx_tail; + if (!pdev->tx[tx_tail].busy) + printf("ip1000: Strange, buffer not busy?\n"); + + /* Check whether the transmiting is OK */ + /* ### CHECK_TX_STATUS_OK ### */ + if (ic_tx_status_ok(desc) != TRUE) + break; + + /* Check Tx status error */ + /* ### CHECK_TX_STATUS_ERROR ### */ + if (desc->status & DESC_STATUS_TX_SEND_ERR) + printf("ip1000: Tx error\n"); + + pdev->stat.ets_packetT++; + pdev->tx[tx_tail].busy = FALSE; + pdev->tx_busy_num--; + + if (++tx_tail >= TX_DESC_NUM) + tx_tail = 0; + + pdev->send_flag = TRUE; + pdev->recv_flag = TRUE; + + /* Set Tx descriptor status in interrupt */ + /* ### SET_TX_STATUS_INTR ### */ + desc->status = DESC_STATUS_TX_SEND_CLEAR; + +#ifdef MY_DEBUG + printf("ip1000: Successfully send a packet\n"); +#endif + } + pdev->tx_tail = tx_tail; + } +#ifdef MY_DEBUG + if (!flag) { + printf("ip1000: Unknown error in interrupt\n"); + return; + } +#endif +} + +/* Check interrupt and perform */ +static void ic_check_ints(ic_driver *pdev) { + if (!pdev->recv_flag) + return; + pdev->recv_flag = FALSE; + + /* Handle data receive */ + netdriver_recv(); + + /* Handle data transmit */ + if (pdev->send_flag) { + pdev->send_flag = FALSE; + netdriver_send(); + } +} + +static void ic_stat(eth_stat_t *stat) { + memcpy(stat, &g_driver.stat, sizeof(*stat)); +} diff --git a/minix/drivers/net/ip1000/ip1000.conf b/minix/drivers/net/ip1000/ip1000.conf new file mode 100644 index 000000000..d52af889a --- /dev/null +++ b/minix/drivers/net/ip1000/ip1000.conf @@ -0,0 +1,15 @@ +service ip1000 +{ + type net; + descr "IC Plus 1000A Ethernet Card"; + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 13f0:1023; + ipc + SYSTEM pm rs log tty ds vm + pci inet lwip amddev + ; +}; diff --git a/minix/drivers/net/ip1000/ip1000.h b/minix/drivers/net/ip1000/ip1000.h new file mode 100644 index 000000000..3219fdc68 --- /dev/null +++ b/minix/drivers/net/ip1000/ip1000.h @@ -0,0 +1,187 @@ +#ifndef _ic_H +#define _ic_H + +#include + +/* ======= General Parameter ======= */ +/* Global configure */ +#define DESC_BASE64 + +/* Key internal register */ +#define REG_RCR 0x88 +#define REG_ISR 0x5a +#define REG_IMR 0x5c +#define REG_RX_DESC_BASEL 0x1c +#define REG_TX_DESC_BASEL 0x10 + +#ifdef DESC_BASE_DMA64 +#define REG_RX_DESC_BASEU 0x20 +#define REG_TX_DESC_BASEU 0x14 +#endif + +/* Key internal register width */ +#define WIDTH_REG_RCR 8 +#define WIDTH_REG_ISR 16 +#define WIDTH_REG_IMR 16 + +/* Interrupt statu and command */ +#define INTR_ISR_ERR 0x0002 +#define INTR_ISR_LINK_EVENT 0x0100 +#define INTR_ISR_RX_DONE 0x0400 +#define INTR_ISR_TX_DONE 0x0200 +#define INTR_ISR_CLEAR 0x0000 +#define INTR_IMR_ENABLE 0x17f6 +#define INTR_IMR_DISABLE 0x0000 + +/* Descriptor status */ +#define DESC_STATUS_RX_RECV_ERR 0x00000000003f0000ULL +#define DESC_STATUS_RX_RECV_CLEAR 0x0000000000000000ULL +#define DESC_STATUS_TX_SEND_ERR 0x0000000000000000ULL +#define DESC_STATUS_TX_SEND_CLEAR 0x0000000000000000ULL + +/* Rx mode */ +#define RCR_UNICAST 0x01 +#define RCR_MULTICAST 0x02 +#define RCR_BROADCAST 0x04 + +/* Link status */ +#define LINK_UP 1 +#define LINK_DOWN 0 +#define LINK_UNKNOWN -1 + +/* Basic Rx/Tx parameters */ +#define RX_BUF_SIZE 1536 +#define TX_BUF_SIZE 1536 +#define RX_DESC_NUM 256 +#define TX_DESC_NUM 256 + +/* ======= Self-defined Parameter ======= */ +#define RFI_FRAG_LEN 0xffff000000000000ULL +#define RFS_FRAME_LEN 0x000000000000ffffULL +#define RFS_FRAME_START 0x0000000020000000ULL +#define RFS_FRAME_END 0x0000000040000000ULL +#define RFS_RFD_DONE 0x0000000080000000ULL +#define RFS_NORMAL (RFS_RFD_DONE | RFS_FRAME_START | RFS_FRAME_END) + +#define TFI_FRAG_LEN 0xffff000000000000ULL +#define TFS_FRAMEID 0x000000000000ffffULL +#define TFS_WORD_ALIGN 0x0000000000030000ULL +#define TFS_TX_DMA_INDICATE 0x0000000000800000ULL +#define TFS_FRAG_COUNT 0x000000000f000000ULL +#define TFS_TFD_DONE 0x0000000080000000ULL + +#define REG_DMA_CTRL 0x00 +#define REG_TX_DMA_BTH 0x18 +#define REG_TX_DMA_UTH 0x19 +#define REG_TX_DMA_PERIOD 0x1a +#define REG_RX_DMA_BTH 0x24 +#define REG_RX_DMA_UTH 0x25 +#define REG_RX_DMA_PERIOD 0x26 +#define REG_ASIC_CTRL 0x30 +#define REG_FLOW_OFF_TH 0x3c +#define REG_FLOW_ON_TH 0x3e +#define REG_EEPROM_DATA 0x48 +#define REG_EEPROM_CTRL 0x4a +#define REG_MAC_CTRL 0x6c +#define REG_PHY_SET 0x75 +#define REG_PHY_CTRL 0x76 +#define REG_STA_ADDR0 0x78 +#define REG_STA_ADDR1 0x7a +#define REG_STA_ADDR2 0x7c +#define REG_MAX_FRAME 0x86 + +#define AC_LED_MODE 0x00004000 +#define AC_GB_RESET 0x00010000 +#define AC_RX_RESET 0x00020000 +#define AC_TX_RESET 0x00040000 +#define AC_DMA 0x00080000 +#define AC_FIFO 0x00100000 +#define AC_NETWORK 0x00200000 +#define AC_HOST 0x00400000 +#define AC_AUTO_INIT 0x00800000 +#define AC_RESET_BUSY 0x04000000 +#define AC_LED_SPEED 0x08000000 +#define AC_LED_MODE_B1 0x20000000 +#define AC_RESET_ALL (AC_GB_RESET | AC_RX_RESET | AC_TX_RESET | AC_DMA | \ + AC_FIFO | AC_NETWORK | AC_HOST | AC_AUTO_INIT) + +#define MC_DUPLEX_SEL 0x00000020 +#define MC_TX_FC_ENA 0x00000080 +#define MC_RX_FC_ENA 0x00000100 +#define MC_STAT_DISABLE 0x00400000 +#define MC_TX_ENABLE 0x01000000 +#define MC_TX_DISABLE 0x02000000 +#define MC_RX_ENABLE 0x08000000 +#define MC_RX_DISABLE 0x10000000 +#define MC_PAUSED 0x40000000 + +#define PC_DUPLEX_STS 0x10 +#define PC_LINK_SPEED 0xc0 +#define PC_LINK_SPEED10 0x40 +#define PC_LINK_SPEED100 0x80 +#define PC_LINK_SPEED1000 0xc0 + +#define EC_READ 0x0200 +#define EC_BUSY 0x8000 + +static u16_t PhyParam[] = { + (0x4000|(07*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, + 30, 0x005e, 9, 0x0700, + (0x4100|(07*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, + 30, 0x005e, 9, 0x0700, + (0x4200|(07*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, + 30, 0x005e, 9, 0x0700, + (0x4300|(07*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, + 30, 0x005e, 9, 0x0700, 0x0000 +}; + +/* ======= Data Descriptor ======= */ +typedef struct ic_desc { + u64_t next;; + u64_t status;; + u64_t frag_info;; +} ic_desc; + +/* Driver Data Structure */ +typedef struct ic_driver { + u32_t base_addr; /* Base address */ + int revision; /* Revision ID */ + int irq; /* IRQ number */ + int mode; + int link; /* Whether link-up */ + int recv_flag; /* Receive flag */ + int send_flag; /* Send flag */ + int tx_busy; + + /* Buffer */ + size_t buf_size; + char *buf; + + /* Rx data */ + int rx_head; + struct { + phys_bytes buf_dma; + char *buf; + } rx[RX_DESC_NUM]; + ic_desc *rx_desc; /* Rx descriptor buffer */ + phys_bytes rx_desc_dma; /* Rx descriptor DMA buffer */ + + /* Tx data */ + int tx_head; + int tx_tail; + struct { + int busy; + phys_bytes buf_dma; + char *buf; + } tx[TX_DESC_NUM]; + ic_desc *tx_desc; /* Tx descriptor buffer */ + phys_bytes tx_desc_dma; /* Tx descriptor DMA buffer */ + int tx_busy_num; /* Number of busy Tx descriptors */ + + int hook; /* IRQ hook id at kernel */ + eth_stat_t stat; + + char name[20]; +} ic_driver; + +#endif diff --git a/minix/fs/procfs/service.c b/minix/fs/procfs/service.c index e8b06eef5..64a770c9b 100644 --- a/minix/fs/procfs/service.c +++ b/minix/fs/procfs/service.c @@ -66,6 +66,7 @@ service_get_policies(struct policies * pol, index_t slot) { .label = "dpeth", .policy_str = "reset" }, { .label = "e1000", .policy_str = "reset" }, { .label = "fxp", .policy_str = "reset" }, + { .label = "ip1000", .policy_str = "reset" }, { .label = "lance", .policy_str = "reset" }, { .label = "lan8710a", .policy_str = "reset" }, { .label = "orinoco", .policy_str = "reset" },