From: Jia-Ju Bai Date: Sun, 15 Jan 2017 03:20:36 +0000 (+0000) Subject: IP1000: Restructure the code and correct function order in initialization X-Git-Url: http://zhaoyanbai.com/repos/man.delv.html?a=commitdiff_plain;h=3afdc1200b0091fc1e6a49ed676d48b62607f33e;p=minix.git IP1000: Restructure the code and correct function order in initialization Change-Id: I7c887a777205ea0ae38b4ef1830535d035c5a976 --- diff --git a/minix/drivers/net/ip1000/README b/minix/drivers/net/ip1000/README index 399dba793..d7529cce2 100644 --- a/minix/drivers/net/ip1000/README +++ b/minix/drivers/net/ip1000/README @@ -1,11 +1,8 @@ The ip1000 driver is for IC Plus 1000A/Family (ST1023) Ethernet card. -This driver is referred to Minix(3.4.0) vt6105 driver, +This driver is referred to Minix(3.4.0) rtl8169 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 @@ -13,7 +10,10 @@ Revision 1.1 2016/11/12 Modification: Remove and rewrite Linux-derived code Authored by Jia-Ju Bai +Revision 1.2 2017/1/12 +Modification: Restructure the code and correct function order in initialization +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 index 14d67d531..6db8d002b 100644 --- a/minix/drivers/net/ip1000/io.h +++ b/minix/drivers/net/ip1000/io.h @@ -9,76 +9,76 @@ static u8_t my_inb(u32_t port) { u32_t value; int r; -#ifdef DMA_REG_MODE - value = *(u8_t *)(port); +#ifdef DMA_BASE_IOMAP + value = *(volatile u8_t *)(port); #else if ((r = sys_inb(port, &value)) != OK) - printf("ip1000: sys_inb failed: %d\n", r); + printf("NDR: sys_inb failed: %d\n", r); #endif return (u8_t)value; } -#define ic_in8(port, offset) (my_inb((port) + (offset))) +#define ndr_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); +#ifdef DMA_BASE_IOMAP + value = *(volatile u16_t *)(port); #else if ((r = sys_inw(port, &value)) != OK) - printf("ip1000: sys_inw failed: %d\n", r); + printf("NDR: sys_inw failed: %d\n", r); #endif return (u16_t)value; } -#define ic_in16(port, offset) (my_inw((port) + (offset))) +#define ndr_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); +#ifdef DMA_BASE_IOMAP + value = *(volatile u32_t *)(port); #else if ((r = sys_inl(port, &value)) != OK) - printf("ip1000: sys_inl failed: %d\n", r); + printf("NDR: sys_inl failed: %d\n", r); #endif return value; } -#define ic_in32(port, offset) (my_inl((port) + (offset))) +#define ndr_in32(port, offset) (my_inl((port) + (offset))) -static void my_outb(u32_t port, u8_t value) { +static void my_outb(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u8_t *)(port) = value; +#ifdef DMA_BASE_IOMAP + *(volatile u8_t *)(port) = value; #else - if ((r = sys_outb(port, value)) != OK) - printf("ip1000: sys_outb failed: %d\n", r); + if ((r = sys_outb(port, (u8_t)value)) != OK) + printf("NDR: sys_outb failed: %d\n", r); #endif } -#define ic_out8(port, offset, value) \ +#define ndr_out8(port, offset, value) \ (my_outb(((port) + (offset)), (value))) -static void my_outw(u32_t port, u16_t value) { +static void my_outw(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u16_t *)(port) = value; +#ifdef DMA_BASE_IOMAP + *(volatile u16_t *)(port) = value; #else - if ((r = sys_outw(port, value)) != OK) - printf("ip1000: sys_outw failed: %d\n", r); + if ((r = sys_outw(port, (u16_t)value)) != OK) + printf("NDR: sys_outw failed: %d\n", r); #endif } -#define ic_out16(port, offset, value) \ +#define ndr_out16(port, offset, value) \ (my_outw(((port) + (offset)), (value))) -static void my_outl(u16_t port, u32_t value) { +static void my_outl(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u32_t *)(port) = value; +#ifdef DMA_BASE_IOMAP + *(volatile u32_t *)(port) = value; #else if ((r = sys_outl(port, value)) != OK) - printf("ip1000: sys_outl failed: %d\n", r); + printf("NDR: sys_outl failed: %d\n", r); #endif } -#define ic_out32(port, offset, value) \ +#define ndr_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 index 7da45e301..2044c4b97 100644 --- a/minix/drivers/net/ip1000/ip1000.c +++ b/minix/drivers/net/ip1000/ip1000.c @@ -1,62 +1,70 @@ #include #include #include +#include #include "ip1000.h" #include "io.h" /* global value */ -static ic_driver g_driver; +static NDR_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); +static int NDR_init(unsigned int instance, ether_addr_t *addr); +static void NDR_stop(void); +static void NDR_mode(unsigned int mode); +static ssize_t NDR_recv(struct netdriver_data *data, size_t max); +static int NDR_send(struct netdriver_data *data, size_t size); +static void NDR_intr(unsigned int mask); +static void NDR_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); +static int dev_probe(NDR_driver *pdev, int instance); +static int dev_init_buf(NDR_driver *pdev); +static int dev_init_hw(NDR_driver *pdev, ether_addr_t *addr); +static int dev_reset_hw(NDR_driver *pdev); +static void dev_conf_addr(NDR_driver *pdev, ether_addr_t *addr); +static void dev_handler(NDR_driver *pdev); +static void dev_check_ints(NDR_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 ======= */ +static int dev_real_reset(u32_t *base); +static int dev_init_io(u32_t *base); +static int dev_init_mii(u32_t *base); +static void dev_intr_control(u32_t *base, int flag); +static void dev_rx_tx_control(u32_t *base, int flag); +static void dev_get_addr(u32_t *base, u8_t *pa); +static int dev_check_link(u32_t *base); +static void dev_set_rec_mode(u32_t *base, int mode); +static void dev_start_tx(u32_t *base); +static u32_t dev_read_clear_intr_status(u32_t *base); +static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size, + phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start); +static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size, + phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start); +static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr, + phys_bytes tx_addr); +static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index); +static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index); +static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index); +static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index, + size_t data_size); +static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index); +static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index); + +/* ======= Developer implemented function ======= */ /* ====== Self-defined function ======*/ - static u16_t read_eeprom(u32_t base, int addr) { - u16_t ret, data, val; + u32_t ret, data, val; int i; val = EC_READ | (addr & 0xff); - ic_out16(base, REG_EEPROM_CTRL, val); + ndr_out16(base, REG_EEPROM_CTRL, val); for (i = 0; i < 100; i++) { micro_delay(10000); - data = ic_in16(base, REG_EEPROM_CTRL); + data = ndr_in16(base, REG_EEPROM_CTRL); if (!(data & EC_BUSY)) { - ret = ic_in16(base, REG_EEPROM_DATA); + ret = ndr_in16(base, REG_EEPROM_DATA); break; } } @@ -73,48 +81,48 @@ static u16_t read_phy_reg(u32_t base, int phy_addr, int phy_reg) { 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[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; + polar = ndr_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); + ndr_out8(base, REG_PHY_CTRL, data); micro_delay(10); - ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + ndr_out8(base, REG_PHY_CTRL, (data | 0x01)); micro_delay(10); } } - ic_out8(base, REG_PHY_CTRL, (polar | 0x04)); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x04)); micro_delay(10); - ic_out8(base, REG_PHY_CTRL, (polar | 0x05)); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x05)); micro_delay(10); - ic_out8(base, REG_PHY_CTRL, polar); + ndr_out8(base, REG_PHY_CTRL, polar); micro_delay(10); - data = ic_in8(base, REG_PHY_CTRL); - ic_out8(base, REG_PHY_CTRL, (polar | 0x01)); + data = ndr_in8(base, REG_PHY_CTRL); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x01)); micro_delay(10); for (i = 0; i < fieldlen[6]; i++) { - ic_out8(base, REG_PHY_CTRL, polar); + ndr_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)); + data = ((ndr_in8(base, REG_PHY_CTRL) & 0x02) >> 1) & 0x01; + ndr_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)); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x04)); micro_delay(10); - ic_out8(base, REG_PHY_CTRL, (polar | 0x05)); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x05)); micro_delay(10); } - ic_out8(base, REG_PHY_CTRL, (polar | 0x04)); + ndr_out8(base, REG_PHY_CTRL, (polar | 0x04)); return field[6]; } @@ -132,63 +140,46 @@ static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) { field[6] = val; fieldlen[6] = 16; field[7] = 0x0000; fieldlen[7] = 1; - polar = ic_in8(base, REG_PHY_CTRL) & 0x28; + polar = ndr_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); + ndr_out8(base, REG_PHY_CTRL, data); micro_delay(10); - ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + ndr_out8(base, REG_PHY_CTRL, (data | 0x01)); micro_delay(10); } } for (i = 0; i < fieldlen[7]; i ++) { - ic_out8(base, REG_PHY_CTRL, polar); + ndr_out8(base, REG_PHY_CTRL, polar); micro_delay(10); - field[7] |= ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1) + field[7] |= ((ndr_in8(base, REG_PHY_CTRL) & 0x02) >> 1) << (fieldlen[7] - i -1); - ic_out8(base, REG_PHY_CTRL, (data | 0x01)); + ndr_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) +static int dev_real_reset(u32_t *base) { + u32_t data, base0 = base[0]; + data = ndr_in32(base0, REG_ASIC_CTRL); + ndr_out32(base0, REG_ASIC_CTRL, data | AC_RESET_ALL); + micro_delay(5000); + if (ndr_in32(base0, REG_ASIC_CTRL) & AC_RESET_BUSY) return -EIO; return OK; } -/* Intialize power (### POWER_INIT_CAN_FAIL ###) +/* Intialize other hardware I/O registers (### INIT_HARDWARE_IO_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); +static int dev_init_io(u32_t *base) { + u32_t mac_ctrl, physet, mode0, mode1, base0 = base[0]; + mode0 = read_eeprom(base0, 6); + mode1 = ndr_in16(base0, REG_ASIC_CTRL); mode1 &= ~(AC_LED_MODE_B1 | AC_LED_MODE | AC_LED_SPEED); if ((mode0 & 0x03) > 1) mode1 |= AC_LED_MODE_B1; @@ -196,38 +187,48 @@ static int ic_init_power(u32_t base) { 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); - + ndr_out32(base0, REG_ASIC_CTRL, mode1); + physet = ndr_in8(base0, REG_PHY_SET); + physet = (physet & 0xf8) | ((mode0 & 0x70) >> 4); + ndr_out8(base0, REG_PHY_SET, physet); + mac_ctrl = ndr_in32(base0, REG_MAC_CTRL); + mac_ctrl |= (MC_STAT_DISABLE | MC_TX_FC_ENA | MC_RX_FC_ENA); + ndr_out32(base0, REG_MAC_CTRL, 0); + ndr_out16(base0, REG_MAX_FRAME, RX_BUF_SIZE); + ndr_out8(base0, REG_RX_DMA_PERIOD, 0x01); + ndr_out8(base0, REG_RX_DMA_UTH, 0x30); + ndr_out8(base0, REG_RX_DMA_BTH, 0x30); + ndr_out8(base0, REG_TX_DMA_PERIOD, 0x26); + ndr_out8(base0, REG_TX_DMA_UTH, 0x04); + ndr_out8(base0, REG_TX_DMA_BTH, 0x30); + ndr_out16(base0, REG_FLOW_ON_TH, 0x0740); + ndr_out16(base0, REG_FLOW_OFF_TH, 0x00bf); + ndr_out32(base0, REG_MAC_CTRL, mac_ctrl); return OK; } /* Intialize MII interface (### MII_INIT_CAN_FAIL ###) * -- Return OK means success, Others means failure */ -static int ic_init_mii(u32_t base) { +static int dev_init_mii(u32_t *base) { int i, phyaddr; u8_t revision; u16_t phyctrl, cr1000, length, address, value; u16_t *param; - u32_t status; + u32_t status, base0 = base[0]; for (i = 0; i < 32; i++) { phyaddr = (i + 0x01) % 32; - status = read_phy_reg(base, phyaddr, 0x01); + status = read_phy_reg(base0, phyaddr, 0x01); if ((status != 0xffff) && (status != 0)) break; } if (i == 32) return -EIO; if (phyaddr != -1) { - cr1000 = read_phy_reg(base, phyaddr, 0x09); + cr1000 = read_phy_reg(base0, phyaddr, 0x09); cr1000 |= 0x0700; - write_phy_reg(base, phyaddr, 0x09, cr1000); - phyctrl = read_phy_reg(base, phyaddr, 0x00); + write_phy_reg(base0, phyaddr, 0x09, cr1000); + phyctrl = read_phy_reg(base0, phyaddr, 0x00); } param = &PhyParam[0]; @@ -240,7 +241,7 @@ static int ic_init_mii(u32_t base) { address = *param; value = *(param + 1); param += 2; - write_phy_reg(base, phyaddr, address, value); + write_phy_reg(base0, phyaddr, address, value); length -= 4; } break; @@ -252,68 +253,55 @@ static int ic_init_mii(u32_t base) { param++; } } - - phyctrl |= 0x8200; - write_phy_reg(base, phyaddr, 0x00, phyctrl); - + write_phy_reg(base0, phyaddr, 0x00, phyctrl | 0x8200); 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; +/* Enable or disable interrupt (### INTR_ENABLE_DISABLE ###) */ +static void dev_intr_control(u32_t *base, int flag) { + u32_t base0 = base[0]; + if (flag == INTR_ENABLE) + ndr_out16(base0, REG_IMR, CMD_INTR_ENABLE); + else if (flag == INTR_DISABLE) + ndr_out16(base0, REG_IMR, 0); } -/* 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); +/* Enable or disable Rx/Tx (### RX_TX_ENABLE_DISABLE ###) */ +static void dev_rx_tx_control(u32_t *base, int flag) { + u32_t data, base0 = base[0]; + data = ndr_in32(base0, REG_MAC_CTRL); + if (flag == RX_TX_ENABLE) + ndr_out32(base0, REG_MAC_CTRL, data | (MC_RX_ENABLE | MC_TX_ENABLE)); + else if (flag == RX_TX_DISABLE) { + ndr_out32(base0, REG_MAC_CTRL, 0); + ndr_out32(base0, REG_ASIC_CTRL, AC_RESET_ALL); + } } /* 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]); +static void dev_get_addr(u32_t *base, u8_t *pa) { + u32_t i, sta_addr[3], base0 = base[0]; + for (i = 0; i < 3; i++) { + sta_addr[i] = read_eeprom(base0, 16 + i); + ndr_out16(base0, (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); + pa[0] = (u8_t)(ndr_in16(base0, REG_STA_ADDR0) & 0x00ff); + pa[1] = (u8_t)((ndr_in16(base0, REG_STA_ADDR0) & 0xff00) >> 8); + pa[2] = (u8_t)(ndr_in16(base0, REG_STA_ADDR1) & 0x00ff); + pa[3] = (u8_t)((ndr_in16(base0, REG_STA_ADDR1) & 0xff00) >> 8); + pa[4] = (u8_t)(ndr_in16(base0, REG_STA_ADDR2) & 0x00ff); + pa[5] = (u8_t)((ndr_in16(base0, 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; +static int dev_check_link(u32_t *base) { + u32_t phy_ctrl, mac_ctrl, base0 = base[0]; int ret; char speed[20], duplex[20]; - phy_ctrl = ic_in8(base, REG_PHY_CTRL); - mac_ctrl = ic_in8(base, REG_MAC_CTRL); + phy_ctrl = ndr_in8(base0, REG_PHY_CTRL); + mac_ctrl = ndr_in8(base0, REG_MAC_CTRL); switch (phy_ctrl & PC_LINK_SPEED) { case PC_LINK_SPEED10: strcpy(speed, "10Mbps"); @@ -338,105 +326,189 @@ static int ic_check_link(u32_t base) { } else strcpy(duplex, "half"); - ic_out32(base, REG_MAC_CTRL, mac_ctrl); + ndr_out32(base0, REG_MAC_CTRL, mac_ctrl); #ifdef MY_DEBUG - printf("ip1000: Link speed is %s, %s duplex\n", speed, duplex); + printf("NDR: 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); +/* Set driver receive mode (### SET_REC_MODE ###) */ +static void dev_set_rec_mode(u32_t *base, int mode) { + u32_t data, base0 = base[0]; + data = ndr_in8(base0, REG_RCR); + data &= ~(CMD_RCR_UNICAST | CMD_RCR_MULTICAST | CMD_RCR_BROADCAST); + if (mode & NDEV_PROMISC) + data |= CMD_RCR_UNICAST | CMD_RCR_MULTICAST | CMD_RCR_MULTICAST; + if (mode & NDEV_BROAD) + data |= CMD_RCR_BROADCAST; + if (mode & NDEV_MULTI) + data |= CMD_RCR_MULTICAST; + data |= CMD_RCR_UNICAST; + ndr_out8(base0, REG_RCR, data); +} + +/* Start Tx channel (### START_TX_CHANNEL ###) */ +static void dev_start_tx(u32_t *base) { + u32_t base0 = base[0]; + ndr_out32(base0, REG_DMA_CTRL, CMD_TX_START); +} + +/* Read and clear interrupt (### READ_CLEAR_INTR_STS ###) */ +static u32_t dev_read_clear_intr_status(u32_t *base) { + u32_t data, base0 = base[0]; + data = ndr_in16(base0, REG_ISR); + ndr_out16(base0, REG_ISR, 0); + return data; +} + +/* ---------- WITH DESCRIPTOR ---------- */ +/* Intialize Rx descriptor (### INIT_RX_DESC ###) */ +static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size, + phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) { + NDR_desc *desc = desc_start + index; + desc->status = 0; + desc->frag_info = (u64_t)(buf_dma); + desc->frag_info |= ((u64_t)buf_size << 48) & RFI_FRAG_LEN; + if (index == max_desc_num - 1) + desc->next = desc_dma_start; + else + desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc); +} + +/* Intialize Tx descriptor (### INIT_TX_DESC ###) */ +static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size, + phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) { + NDR_desc *desc = desc_start + index; + desc->status = TFS_TFD_DONE; + desc->frag_info = (u64_t)(buf_dma); + if (index == max_desc_num - 1) + desc->next = desc_dma_start; + else + desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc); } -/* 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; +/* Set Rx/Tx descriptor address into device register (### SET_DESC_REG ###) */ +static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr, + phys_bytes tx_addr) { + u32_t base0 = base[0]; + ndr_out32(base0, REG_RX_DESC_BASEL, rx_addr); + ndr_out32(base0, REG_RX_DESC_BASEU, 0); + ndr_out32(base0, REG_TX_DESC_BASEL, tx_addr); + ndr_out32(base0, REG_TX_DESC_BASEU, 0); } -/* Get Rx data length from descriptor (### GET_RX_LEN ###) - * --- Return the length */ -static int ic_get_rx_len(ic_desc *desc) { +/* Check whether Rx is OK from Rx descriptor (### CHECK_RX_OK_FROM_DESC ###) + * -- Current buffer number is index + * -- Return RX_OK or RX_SUSPEND or RX_ERROR */ +static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index) { + if (desc->status & RFS_RFD_DONE) { + if (desc->status & RFS_ERROR) + return RX_ERROR; + if ((desc->status & RFS_NORMAL) == RFS_NORMAL) + return RX_OK; + } + return RX_SUSPEND; +} + +/* Get length from Rx descriptor (### GET_RX_LENGTH_FROM_DESC ###) + * -- Current buffer number is index + * -- Return the length */ +static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index) { int totlen; - totlen = (u32_t)(desc->status & RFS_FRAME_LEN); + totlen = (int)(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) { +/* Set Rx descriptor after Rx done (### SET_RX_DESC_DONE ###) + * -- Current buffer number is index */ +static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index) { + desc->status = 0; +} + +/* Set Tx descriptor to prepare transmitting (### SET_TX_DESC_PREPARE) + * -- Current buffer number is index */ +static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index, + size_t data_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_WORD_ALIGN | (TFS_FRAMEID & index) + | (TFS_FRAG_COUNT & (1 << 24))) | TFS_TX_DMA_INDICATE; + desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((data_size > 60 ? data_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 is OK from Tx descriptor (### CHECK_TX_OK_FROM_DESC ###) + * -- Current buffer number is index + * -- Return TX_OK or TX_SUSPEND or TX_ERROR */ +static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index) { + if (desc->status & TFS_TFD_DONE) + return TX_OK; + return TX_SUSPEND; } -/* 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; +/* Set Tx descriptor after Tx done (### SET_TX_DESC_DONE ###) + * -- Current buffer number is index */ +static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index) { + desc->status = 0; } /* 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, +static const struct netdriver NDR_table = { + .ndr_init = NDR_init, + .ndr_stop = NDR_stop, + .ndr_mode = NDR_mode, + .ndr_recv = NDR_recv, + .ndr_send = NDR_send, + .ndr_intr = NDR_intr, + .ndr_stat = NDR_stat }; int main(int argc, char *argv[]) { env_setargs(argc, argv); - netdriver_task(&ic_table); + netdriver_task(&NDR_table); } /* Initialize the driver */ -static int ic_init(unsigned int instance, ether_addr_t *addr) { - int ret = 0; +static int NDR_init(unsigned int instance, ether_addr_t *addr) { + int i, 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; + strcpy(g_driver.name, DRIVER_NAME); + strcat(g_driver.name, "#0"); + g_driver.name[strlen(g_driver.name) - 1] += instance; g_instance = instance; /* Probe the device */ - if (ic_probe(&g_driver, instance)) { - printf("ip1000: Device is not found\n"); + if (dev_probe(&g_driver, instance)) { + printf("NDR: Device is not found\n"); ret = -ENODEV; goto err_probe; } + /* Intialize hardware */ + if (dev_init_hw(&g_driver, addr)) { + printf("NDR: Fail to initialize hardware\n"); + ret = -EIO; + goto err_init_hw; + } + /* Allocate and initialize buffer */ - if (ic_init_buf(&g_driver)) { - printf("ip1000: Fail to initialize buffer\n"); + if (dev_init_buf(&g_driver)) { + printf("NDR: 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; - } + /* Enable interrupts */ + /* ### INTR_ENABLE_DISABLE ### */ + dev_intr_control(g_driver.base, INTR_ENABLE); + + /* Start Rx and Tx */ + /* ### RX_TX_ENABLE_DISABLE ### */ + dev_rx_tx_control(g_driver.base, RX_TX_ENABLE); /* Use a synchronous alarm instead of a watchdog timer */ sys_setalarm(sys_hz(), 0); @@ -447,208 +519,240 @@ static int ic_init(unsigned int instance, ether_addr_t *addr) { return 0; -err_init_hw: - free_contig(g_driver.buf, g_driver.buf_size); err_init_buf: +err_init_hw: 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; +/* Stop the driver */ +static void NDR_stop(void) { + /* Free Rx and Tx buffer*/ + free_contig(g_driver.buf, g_driver.buf_size); - /* 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); + /* Stop interrupt */ + /* ### INTR_ENABLE_DISABLE ### */ + dev_intr_control(g_driver.base, INTR_DISABLE); - /* 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); + /* Stop Rx and Tx */ + /* ### RX_TX_ENABLE_DISABLE ### */ + dev_rx_tx_control(g_driver.base, RX_TX_DISABLE); +} - /* 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; +/* Set driver mode */ +static void NDR_mode(unsigned int mode) { + g_driver.mode = mode; + /* Set driver receive mode */ + /* ### SET_REC_MODE ### */ + dev_set_rec_mode(g_driver.base, mode); +} + +/* Receive data */ +static ssize_t NDR_recv(struct netdriver_data *data, size_t max) { + NDR_driver *pdev = &g_driver; + u32_t totlen, packlen; + int index, ret, offset = 0; + NDR_desc *desc; + + index = pdev->rx_head; + desc = pdev->rx_desc; + desc += index; + /* Check whether Rx is OK from Rx descriptor */ + /* ### CHECK_RX_OK_FROM_DESC ### */ + ret = dev_rx_ok_desc(pdev->base, desc, index); + if (ret == RX_SUSPEND) + return SUSPEND; + else if (ret == RX_ERROR) + printf("NDR: Rx error now\n"); + /* Get length from Rx descriptor */ + /* ### GET_RX_LENGTH_FROM_DESC ### */ + totlen = dev_rx_len_desc(pdev->base, desc, index); + + /* Get data length */ + /* ### Get , int inde, int indexxRx data length ### */ + if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) { + printf("NDR: Bad data length: %d\n", totlen); + panic(NULL); } - pdev->base_addr = bar; -#endif - /* Get irq number */ - irq = pci_attr_r8(devind, PCI_ILR); - pdev->irq = irq; + packlen = totlen; + if (packlen > max) + packlen = max; + + /* Copy data to user */ + netdriver_copyout(data, 0, pdev->rx[index].buf + offset, packlen); + pdev->stat.ets_packetR++; - /* Get revision ID */ - rev = pci_attr_r8(devind, PCI_REV); - pdev->revision = rev; + /* Set Rx descriptor after Rx done */ + /* ### SET_RX_DESC_DONE ### */ + dev_set_rx_desc_done(pdev->base, desc, index); + if (index == RX_BUFFER_NUM - 1) + index = 0; + else + index++; + pdev->rx_head = index; #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); + printf("NDR: Successfully receive a packet, length = %d\n", packlen); #endif - return 0; + return packlen; } -/* 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; +/* Transmit data */ +static int NDR_send(struct netdriver_data *data, size_t size) { + NDR_driver *pdev = &g_driver; + int tx_head, i; + NDR_desc *desc; - /* Build Rx and Tx descriptor buffer */ - rx_desc_size = RX_DESC_NUM * sizeof(ic_desc); - tx_desc_size = TX_DESC_NUM * sizeof(ic_desc); + tx_head = pdev->tx_head; + if (pdev->tx[tx_head].busy) + return SUSPEND; - /* 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); + /* Copy data from user */ + netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size); - 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; + /* Set busy */ + pdev->tx[tx_head].busy = TRUE; + pdev->tx_busy_num++; - /* 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; + desc = pdev->tx_desc; + desc += tx_head; + /* Set Tx descriptor to prepare transmitting */ + /* ### SET_TX_DESC_PREPARE ### */ + dev_set_tx_desc_prepare(pdev->base, desc, tx_head, size); + if (tx_head == TX_BUFFER_NUM - 1) + tx_head = 0; + else + tx_head++; + pdev->tx_head = tx_head; - /* 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; + /* Start Tx channel */ + /* ### START_TX ### */ + dev_start_tx(pdev->base); - /* 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; + return 0; +} - /* 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++; - } +/* Handle interrupt */ +static void NDR_intr(unsigned int mask) { + int s; + + /* Run interrupt handler at driver level */ + dev_handler(&g_driver); + + /* Reenable interrupts for this hook */ + if ((s = sys_irqenable(&g_driver.hook)) != OK) + printf("NDR: Cannot enable OS interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions */ + dev_check_ints(&g_driver); +} + +/* Get driver status */ +static void NDR_stat(eth_stat_t *stat) { + memcpy(stat, &g_driver.stat, sizeof(*stat)); +} + +/* Match the device and get base address */ +static int dev_probe(NDR_driver *pdev, int instance) { + int devind, ioflag, i; + u16_t cr, vid, did; + u32_t bar, size, base; + 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); - /* 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; + /* Enable bus mastering and I/O space */ + cr = pci_attr_r16(devind, PCI_CR); + pci_attr_w16(devind, PCI_CR, cr | 0x105); - /* 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++; + /* Get base address */ + for (i = 0; i < 6; i++) + pdev->base[i] = 0; +#ifdef DMA_BASE_IOMAP + for (i = 0; i < 6; i++) { + if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) { + /* printf("NDR: Fail to get PCI BAR\n"); */ + continue; } + if (ioflag) { + /* printf("NDR: PCI BAR is not for memory\n"); */ + continue; + } + if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) { + printf("NDR: Fail to map hardware registers from PCI\n"); + return -EIO; + } + pdev->base[i] = (u32_t)reg; } - pdev->tx_busy_num = 0; - pdev->tx_head = 0; - pdev->tx_tail = 0; - pdev->rx_head = 0; +#else + for (i = 0; i < 6; i++) + pdev->base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0; +#endif + pdev->dev_name = pci_dev_name(vid, did); + pdev->irq = pci_attr_r8(devind, PCI_ILR); + pdev->revision = pci_attr_r8(devind, PCI_REV); + pdev->did = did; + pdev->vid = vid; + pdev->devind = devind; + +#ifdef MY_DEBUG + printf("NDR: Hardware name is %s\n", pdev->dev_name); + for (i = 0; i < 6; i++) + printf("NDR: PCI BAR%d is 0x%08x\n", i, pdev->base[i]); + printf("NDR: IRQ number is 0x%02x\n", pdev->irq); +#endif return 0; } /* Intialize hardware */ -static int ic_init_hw(ic_driver *pdev, ether_addr_t *addr) { +static int dev_init_hw(NDR_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); + printf("NDR: 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"); + if (dev_reset_hw(pdev)) { + printf("NDR: 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); + printf("NDR: Fail to enable OS IRQ: %d\n", r); ret = -EFAULT; goto err_irq_enable; } /* Configure MAC address */ - ic_conf_addr(pdev, addr); + dev_conf_addr(pdev, addr); /* Detect link status */ - pdev->link = ic_check_link(pdev->base_addr); + /* ### CHECK_LINK ### */ + pdev->link = dev_check_link(pdev->base); #ifdef MY_DEBUG if (pdev->link) - printf("ip1000: Link up\n"); + printf("NDR: Link up\n"); else - printf("ip1000: Link down\n"); + printf("NDR: Link down\n"); #endif return 0; @@ -660,79 +764,48 @@ err_irq_policy: } /* Reset hardware */ -static int ic_reset_hw(ic_driver *pdev) { - u32_t base = pdev->base_addr; +static int dev_reset_hw(NDR_driver *pdev) { int ret; /* Reset the chip */ /* ### RESET_HARDWARE_CAN_FAIL ### */ - if (ic_real_reset(base)) { - printf("ip1000: Fail to reset the hardware\n"); + if (dev_real_reset(pdev->base)) { + printf("NDR: 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"); + /* Initialize other hardware I/O registers */ + /* ### SET_RX_DESC_REG ### */ + if (dev_init_io(pdev->base)) { + printf("NDR: Fail to initialize I/O registers\n"); ret = -EIO; - goto err_init_power; + goto err_init_io; } /* Initialize MII interface */ /* ### MII_INIT_CAN_FAIL ### */ - if (ic_init_mii(base)) { - printf("ip1000: Fail to initialize MII interface\n"); + if (dev_init_mii(pdev->base)) { + printf("NDR: 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_init_io: err_real_reset: return ret; } /* Configure MAC address */ -static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr) { +static void dev_conf_addr(NDR_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); + dev_get_addr(pdev->base, pa); addr->ea_addr[0] = pa[0]; addr->ea_addr[1] = pa[1]; addr->ea_addr[2] = pa[2]; @@ -740,201 +813,123 @@ static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr) { 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", + printf("NDR: 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; +/* Allocate and initialize buffer */ +static int dev_init_buf(NDR_driver *pdev) { + size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size; + phys_bytes buf_dma; + char *buf; + int i; - /* Check Rx status error */ - /* ### CHECK_RX_STATUS_ERROR ### */ - if (desc->status & DESC_STATUS_RX_RECV_ERR) - printf("ip1000: Rx error\n"); + /* Build 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; + if (rx_buf_size % 4) + rx_buf_size += 4 - (rx_buf_size % 4); + tot_buf_size = TX_BUFFER_NUM * tx_buf_size + RX_BUFFER_NUM * rx_buf_size; + rx_desc_size = RX_BUFFER_NUM * sizeof(NDR_desc); + tx_desc_size = TX_BUFFER_NUM * sizeof(NDR_desc); + tot_buf_size += rx_desc_size + tx_desc_size; + if (tot_buf_size % 4096) + tot_buf_size += 4096 - (tot_buf_size % 4096); - /* 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); + if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) { + printf("NDR: Fail to allocate memory\n"); + return -ENOMEM; } + pdev->buf_size = tot_buf_size; + pdev->buf = buf; - 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; + /* Rx descriptor buffer location */ + pdev->rx_desc = (NDR_desc *)buf; + pdev->rx_desc_dma = buf_dma; + memset(buf, 0, rx_desc_size); + buf += rx_desc_size; + buf_dma += rx_desc_size; - if (pdev->tx[tx_head].busy) - return SUSPEND; + /* Tx descriptor buffer location */ + pdev->tx_desc = (NDR_desc *)buf; + pdev->tx_desc_dma = buf_dma; + memset(buf, 0, tx_desc_size); + buf += tx_desc_size; + buf_dma += tx_desc_size; - /* Copy data from user */ - netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size); + /* Rx buffer assignment */ + for (i = 0; i < RX_BUFFER_NUM; i++) { + /* Initialize 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 */ + /* ### INIT_RX_DESC ### */ + dev_init_rx_desc(pdev->rx_desc, i, rx_buf_size, pdev->rx[i].buf_dma, + RX_BUFFER_NUM, pdev->rx_desc_dma); + } - /* Set busy */ - pdev->tx[tx_head].busy = TRUE; - pdev->tx_busy_num++; + /* Tx buffer assignment */ + for (i = 0; i < TX_BUFFER_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; + /* Initialize Tx descriptor */ + /* ### INIT_TX_DESC ### */ + dev_init_tx_desc(pdev->tx_desc, i, tx_buf_size, pdev->tx[i].buf_dma, + TX_BUFFER_NUM, pdev->tx_desc_dma); + } - /* 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; + /* Set Rx/Tx descriptor address into device register */ + /* ### SET_DESC_REG ### */ + dev_set_desc_reg(pdev->base, g_driver.rx_desc_dma, + g_driver.tx_desc_dma); - /* Wake up transmit channel */ - /* ### WAKE_UP_TX ### */ - ic_wakeup_tx(base); + pdev->tx_busy_num = 0; + pdev->tx_head = 0; + pdev->tx_tail = 0; + pdev->rx_head = 0; 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); +static void dev_handler(NDR_driver *pdev) { + u32_t intr_status; + int tx_head, tx_tail, index, flag = 0, ret; + NDR_desc *desc; - /* Clear interrupt */ - /* ### CLEAR_INTR ### */ - ic_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); + /* Read and clear interrupt status */ + /* ### READ_CLEAR_INTR_STS ### */ + intr_status = dev_read_clear_intr_status(pdev->base); /* 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; - } + /* ### INTR_ENABLE_DISABLE ### */ + dev_intr_control(pdev->base, INTR_ENABLE); /* Check link status */ - /* ### CHECK_LINK_INTR ### */ - if (intr_status & INTR_ISR_LINK_EVENT) { - pdev->link = ic_check_link(base); + if (intr_status & INTR_STS_LINK) { + pdev->link = dev_check_link(pdev->base); #ifdef MY_DEBUG - printf("ip1000: Link state change\n"); + printf("NDR: Link state change\n"); #endif flag++; } - /* Check Rx request status */ - /* ### CHECK_RX_INTR ### */ - if (intr_status & INTR_ISR_RX_DONE) { + if (intr_status & INTR_STS_RX) { pdev->recv_flag = TRUE; flag++; } - /* Check Tx request status */ - /* ### CHECK_TX_INTR ### */ - if (intr_status & INTR_ISR_TX_DONE) { + if (intr_status & INTR_STS_TX) { pdev->send_flag = TRUE; flag++; @@ -942,51 +937,48 @@ static void ic_handler(ic_driver *pdev) { tx_head = pdev->tx_head; tx_tail = pdev->tx_tail; while (tx_tail != tx_head) { + if (!pdev->tx[tx_tail].busy) + printf("NDR: Strange, buffer not busy?\n"); + index = tx_tail; 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) + /* Check whether Tx is OK from Tx descriptor */ + /* ### CHECK_TX_OK_FROM_DESC ### */ + ret = dev_tx_ok_desc(pdev->base, desc, index); + if (ret == TX_SUSPEND) break; - - /* Check Tx status error */ - /* ### CHECK_TX_STATUS_ERROR ### */ - if (desc->status & DESC_STATUS_TX_SEND_ERR) - printf("ip1000: Tx error\n"); + else if (ret == TX_ERROR) + printf("NDR: Tx error now\n"); pdev->stat.ets_packetT++; pdev->tx[tx_tail].busy = FALSE; pdev->tx_busy_num--; - if (++tx_tail >= TX_DESC_NUM) + if (++tx_tail >= TX_BUFFER_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; - + /* Set Tx descriptor after Tx done */ + /* ### SET_TX_DESC_DONE ### */ + dev_set_tx_desc_done(pdev->base, desc, index); #ifdef MY_DEBUG - printf("ip1000: Successfully send a packet\n"); + printf("NDR: Successfully send a packet\n"); #endif } pdev->tx_tail = tx_tail; } #ifdef MY_DEBUG if (!flag) { - printf("ip1000: Unknown error in interrupt\n"); + printf("NDR: Unknown error in interrupt 0x%08x\n", intr_status); return; } #endif } /* Check interrupt and perform */ -static void ic_check_ints(ic_driver *pdev) { +static void dev_check_ints(NDR_driver *pdev) { if (!pdev->recv_flag) return; pdev->recv_flag = FALSE; @@ -1000,7 +992,3 @@ static void ic_check_ints(ic_driver *pdev) { 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.h b/minix/drivers/net/ip1000/ip1000.h index 3219fdc68..d07f4f431 100644 --- a/minix/drivers/net/ip1000/ip1000.h +++ b/minix/drivers/net/ip1000/ip1000.h @@ -1,59 +1,46 @@ -#ifndef _ic_H -#define _ic_H - -#include +#ifndef _NDR_H +#define _NDR_H /* ======= 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 +#include -#ifdef DESC_BASE_DMA64 -#define REG_RX_DESC_BASEU 0x20 -#define REG_TX_DESC_BASEU 0x14 -#endif +#define DRIVER_NAME "IP1000" + +/* Rx/Tx buffer parameter */ +#define RX_BUF_SIZE 1536 +#define TX_BUF_SIZE 1536 +#define RX_BUFFER_NUM 64 +#define TX_BUFFER_NUM 64 -/* 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 +/* Interrupt status */ +#define INTR_STS_LINK 0x0100 +#define INTR_STS_RX 0x0400 +#define INTR_STS_TX 0x0200 /* 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 +/* Interrupt control */ +#define INTR_ENABLE 1 +#define INTR_DISABLE 0 + +/* Rx status */ +#define RX_ERROR 1 +#define RX_OK 0 +#define RX_SUSPEND -1 + +/* Tx status */ +#define TX_ERROR 1 +#define TX_OK 0 +#define TX_SUSPEND -1 + +/* Rx/Tx control */ +#define RX_TX_ENABLE 1 +#define RX_TX_DISABLE 0 /* ======= Self-defined Parameter ======= */ #define RFI_FRAG_LEN 0xffff000000000000ULL @@ -61,6 +48,7 @@ #define RFS_FRAME_START 0x0000000020000000ULL #define RFS_FRAME_END 0x0000000040000000ULL #define RFS_RFD_DONE 0x0000000080000000ULL +#define RFS_ERROR 0x00000000003f0000ULL #define RFS_NORMAL (RFS_RFD_DONE | RFS_FRAME_START | RFS_FRAME_END) #define TFI_FRAG_LEN 0xffff000000000000ULL @@ -71,9 +59,13 @@ #define TFS_TFD_DONE 0x0000000080000000ULL #define REG_DMA_CTRL 0x00 +#define REG_TX_DESC_BASEL 0x10 +#define REG_TX_DESC_BASEU 0x14 #define REG_TX_DMA_BTH 0x18 #define REG_TX_DMA_UTH 0x19 #define REG_TX_DMA_PERIOD 0x1a +#define REG_RX_DESC_BASEL 0x1c +#define REG_RX_DESC_BASEU 0x20 #define REG_RX_DMA_BTH 0x24 #define REG_RX_DMA_UTH 0x25 #define REG_RX_DMA_PERIOD 0x26 @@ -82,6 +74,8 @@ #define REG_FLOW_ON_TH 0x3e #define REG_EEPROM_DATA 0x48 #define REG_EEPROM_CTRL 0x4a +#define REG_ISR 0x5a +#define REG_IMR 0x5c #define REG_MAC_CTRL 0x6c #define REG_PHY_SET 0x75 #define REG_PHY_CTRL 0x76 @@ -89,6 +83,7 @@ #define REG_STA_ADDR1 0x7a #define REG_STA_ADDR2 0x7c #define REG_MAX_FRAME 0x86 +#define REG_RCR 0x88 #define AC_LED_MODE 0x00004000 #define AC_GB_RESET 0x00010000 @@ -121,6 +116,12 @@ #define PC_LINK_SPEED100 0x80 #define PC_LINK_SPEED1000 0xc0 +#define CMD_INTR_ENABLE 0x17e6 +#define CMD_RCR_UNICAST 0x01 +#define CMD_RCR_MULTICAST 0x02 +#define CMD_RCR_BROADCAST 0x04 +#define CMD_TX_START 0x1000 + #define EC_READ 0x0200 #define EC_BUSY 0x8000 @@ -136,22 +137,26 @@ static u16_t PhyParam[] = { }; /* ======= Data Descriptor ======= */ -typedef struct ic_desc { - u64_t next;; - u64_t status;; - u64_t frag_info;; -} ic_desc; +typedef struct NDR_desc { + u64_t next; + u64_t status; + u64_t frag_info; +} NDR_desc; /* Driver Data Structure */ -typedef struct ic_driver { - u32_t base_addr; /* Base address */ - int revision; /* Revision ID */ - int irq; /* IRQ number */ +typedef struct NDR_driver { + char *dev_name; /* Device name */ + u16_t vid, did; /* Vendor and device ID */ + u32_t devind; /* Device index */ + u32_t base[6]; /* Base address */ + char irq; /* IRQ number */ + char revision; /* Revision ID */ + int mode; int link; /* Whether link-up */ int recv_flag; /* Receive flag */ int send_flag; /* Send flag */ - int tx_busy; + int tx_busy; /* Whether Tx is busy */ /* Buffer */ size_t buf_size; @@ -162,9 +167,7 @@ typedef struct ic_driver { 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 */ + } rx[RX_BUFFER_NUM]; /* Tx data */ int tx_head; @@ -173,15 +176,17 @@ typedef struct ic_driver { 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 */ + } tx[TX_BUFFER_NUM]; + int tx_busy_num; /* Number of busy Tx buffer */ - int hook; /* IRQ hook id at kernel */ - eth_stat_t stat; + NDR_desc *rx_desc; /* Rx descriptor buffer */ + phys_bytes rx_desc_dma; /* Rx descriptor DMA buffer */ + NDR_desc *tx_desc; /* Tx descriptor buffer */ + phys_bytes tx_desc_dma; /* Tx descriptor DMA buffer */ - char name[20]; -} ic_driver; + int hook; /* IRQ hook id at kernel */ + eth_stat_t stat; /* Ethernet status */ + char name[50]; /* Driver name */ +} NDR_driver; #endif