xref: /minix3/minix/drivers/net/ip1000/ip1000.c (revision f7df02e7476731c31f12548e38bcadbaf0233f6a)
18d98f2e5SJia-Ju Bai #include <minix/drivers.h>
28d98f2e5SJia-Ju Bai #include <minix/netdriver.h>
38d98f2e5SJia-Ju Bai #include <machine/pci.h>
43afdc120SJia-Ju Bai #include <sys/mman.h>
58d98f2e5SJia-Ju Bai #include "ip1000.h"
68d98f2e5SJia-Ju Bai #include "io.h"
78d98f2e5SJia-Ju Bai 
88d98f2e5SJia-Ju Bai /* global value */
93afdc120SJia-Ju Bai static NDR_driver g_driver;
108d98f2e5SJia-Ju Bai static int g_instance;
118d98f2e5SJia-Ju Bai 
128d98f2e5SJia-Ju Bai /* driver interface */
13*f7df02e7SDavid van Moolenbroek static int NDR_init(unsigned int instance, netdriver_addr_t * addr,
14*f7df02e7SDavid van Moolenbroek 	uint32_t * caps, unsigned int * ticks);
153afdc120SJia-Ju Bai static void NDR_stop(void);
16*f7df02e7SDavid van Moolenbroek static void NDR_set_mode(unsigned int mode,
17*f7df02e7SDavid van Moolenbroek 	const netdriver_addr_t * mcast_list, unsigned int mcast_count);
183afdc120SJia-Ju Bai static ssize_t NDR_recv(struct netdriver_data *data, size_t max);
193afdc120SJia-Ju Bai static int NDR_send(struct netdriver_data *data, size_t size);
203afdc120SJia-Ju Bai static void NDR_intr(unsigned int mask);
218d98f2e5SJia-Ju Bai 
228d98f2e5SJia-Ju Bai /* internal function */
233afdc120SJia-Ju Bai static int dev_probe(NDR_driver *pdev, int instance);
243afdc120SJia-Ju Bai static int dev_init_buf(NDR_driver *pdev);
25*f7df02e7SDavid van Moolenbroek static int dev_init_hw(NDR_driver *pdev, netdriver_addr_t *addr);
263afdc120SJia-Ju Bai static int dev_reset_hw(NDR_driver *pdev);
27*f7df02e7SDavid van Moolenbroek static void dev_conf_addr(NDR_driver *pdev, netdriver_addr_t *addr);
283afdc120SJia-Ju Bai static void dev_handler(NDR_driver *pdev);
293afdc120SJia-Ju Bai static void dev_check_ints(NDR_driver *pdev);
308d98f2e5SJia-Ju Bai 
318d98f2e5SJia-Ju Bai /* developer interface */
323afdc120SJia-Ju Bai static int dev_real_reset(u32_t *base);
333afdc120SJia-Ju Bai static int dev_init_io(u32_t *base);
343afdc120SJia-Ju Bai static int dev_init_mii(u32_t *base);
353afdc120SJia-Ju Bai static void dev_intr_control(u32_t *base, int flag);
363afdc120SJia-Ju Bai static void dev_rx_tx_control(u32_t *base, int flag);
373afdc120SJia-Ju Bai static void dev_get_addr(u32_t *base, u8_t *pa);
383afdc120SJia-Ju Bai static int dev_check_link(u32_t *base);
393afdc120SJia-Ju Bai static void dev_set_rec_mode(u32_t *base, int mode);
403afdc120SJia-Ju Bai static void dev_start_tx(u32_t *base);
413afdc120SJia-Ju Bai static u32_t dev_read_clear_intr_status(u32_t *base);
423afdc120SJia-Ju Bai static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size,
433afdc120SJia-Ju Bai 			phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start);
443afdc120SJia-Ju Bai static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size,
453afdc120SJia-Ju Bai 			phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start);
463afdc120SJia-Ju Bai static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr,
473afdc120SJia-Ju Bai 								phys_bytes tx_addr);
483afdc120SJia-Ju Bai static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index);
493afdc120SJia-Ju Bai static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index);
503afdc120SJia-Ju Bai static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index);
513afdc120SJia-Ju Bai static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index,
523afdc120SJia-Ju Bai 										size_t data_size);
533afdc120SJia-Ju Bai static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index);
543afdc120SJia-Ju Bai static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index);
558d98f2e5SJia-Ju Bai 
563afdc120SJia-Ju Bai /* ======= Developer implemented function ======= */
578d98f2e5SJia-Ju Bai /* ====== Self-defined function ======*/
read_eeprom(u32_t base,int addr)588d98f2e5SJia-Ju Bai static u16_t read_eeprom(u32_t base, int addr) {
593afdc120SJia-Ju Bai 	u32_t ret, data, val;
608d98f2e5SJia-Ju Bai 	int i;
618d98f2e5SJia-Ju Bai 
628d98f2e5SJia-Ju Bai 	val = EC_READ | (addr & 0xff);
633afdc120SJia-Ju Bai 	ndr_out16(base, REG_EEPROM_CTRL, val);
648d98f2e5SJia-Ju Bai 	for (i = 0; i < 100; i++) {
658d98f2e5SJia-Ju Bai 		micro_delay(10000);
663afdc120SJia-Ju Bai 		data = ndr_in16(base, REG_EEPROM_CTRL);
678d98f2e5SJia-Ju Bai 		if (!(data & EC_BUSY)) {
683afdc120SJia-Ju Bai 			ret = ndr_in16(base, REG_EEPROM_DATA);
698d98f2e5SJia-Ju Bai 			break;
708d98f2e5SJia-Ju Bai 		}
718d98f2e5SJia-Ju Bai 	}
728d98f2e5SJia-Ju Bai 	if (i == 100)
738d98f2e5SJia-Ju Bai 		printf("IP1000: Fail to read EEPROM\n");
748d98f2e5SJia-Ju Bai 	return ret;
758d98f2e5SJia-Ju Bai }
768d98f2e5SJia-Ju Bai 
read_phy_reg(u32_t base,int phy_addr,int phy_reg)778d98f2e5SJia-Ju Bai static u16_t read_phy_reg(u32_t base, int phy_addr, int phy_reg) {
788d98f2e5SJia-Ju Bai 	int i, j, fieldlen[8];
798d98f2e5SJia-Ju Bai 	u32_t field[8];
808d98f2e5SJia-Ju Bai 	u8_t data, polar;
818d98f2e5SJia-Ju Bai 
828d98f2e5SJia-Ju Bai 	field[0] = 0xffffffff;		fieldlen[0] = 32;
838d98f2e5SJia-Ju Bai 	field[1] = 0x0001;		fieldlen[1] = 2;
848d98f2e5SJia-Ju Bai 	field[2] = 0x0002;		fieldlen[2] = 2;
858d98f2e5SJia-Ju Bai 	field[3] = phy_addr;		fieldlen[3] = 5;
868d98f2e5SJia-Ju Bai 	field[4] = phy_reg;		fieldlen[4] = 5;
878d98f2e5SJia-Ju Bai 	field[5] = 0x0000;		fieldlen[5] = 2;
888d98f2e5SJia-Ju Bai 	field[6] = 0x0000;		fieldlen[6] = 16;
898d98f2e5SJia-Ju Bai 	field[7] = 0x0000;		fieldlen[7] = 1;
908d98f2e5SJia-Ju Bai 
913afdc120SJia-Ju Bai 	polar = ndr_in8(base, REG_PHY_CTRL) & 0x28;
928d98f2e5SJia-Ju Bai 	for (i = 0; i < 5; i++) {
938d98f2e5SJia-Ju Bai 		for (j = 0; j < fieldlen[i]; j++) {
948d98f2e5SJia-Ju Bai 			data = (field[i] >> (fieldlen[i] - j - 1)) << 1;
958d98f2e5SJia-Ju Bai 			data = (0x02 & data) | (0x04 | polar);
963afdc120SJia-Ju Bai 			ndr_out8(base, REG_PHY_CTRL, data);
978d98f2e5SJia-Ju Bai 			micro_delay(10);
983afdc120SJia-Ju Bai 			ndr_out8(base, REG_PHY_CTRL, (data | 0x01));
998d98f2e5SJia-Ju Bai 			micro_delay(10);
1008d98f2e5SJia-Ju Bai 		}
1018d98f2e5SJia-Ju Bai 	}
1023afdc120SJia-Ju Bai 	ndr_out8(base, REG_PHY_CTRL, (polar | 0x04));
1038d98f2e5SJia-Ju Bai 	micro_delay(10);
1043afdc120SJia-Ju Bai 	ndr_out8(base, REG_PHY_CTRL, (polar | 0x05));
1058d98f2e5SJia-Ju Bai 	micro_delay(10);
1063afdc120SJia-Ju Bai 	ndr_out8(base, REG_PHY_CTRL, polar);
1078d98f2e5SJia-Ju Bai 	micro_delay(10);
1083afdc120SJia-Ju Bai 	data = ndr_in8(base, REG_PHY_CTRL);
1093afdc120SJia-Ju Bai 	ndr_out8(base, REG_PHY_CTRL, (polar | 0x01));
1108d98f2e5SJia-Ju Bai 	micro_delay(10);
1118d98f2e5SJia-Ju Bai 	for (i = 0; i < fieldlen[6]; i++) {
1123afdc120SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, polar);
1138d98f2e5SJia-Ju Bai 		micro_delay(10);
1143afdc120SJia-Ju Bai 		data = ((ndr_in8(base, REG_PHY_CTRL) & 0x02) >> 1) & 0x01;
1153afdc120SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, (polar | 0x01));
1168d98f2e5SJia-Ju Bai 		micro_delay(10);
1178d98f2e5SJia-Ju Bai 		field[6] |= (data << (fieldlen[6] - i - 1));
1188d98f2e5SJia-Ju Bai 	}
1198d98f2e5SJia-Ju Bai 
1208d98f2e5SJia-Ju Bai 	for (i = 0; i < 3; i++) {
1213afdc120SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, (polar | 0x04));
1228d98f2e5SJia-Ju Bai 		micro_delay(10);
1233afdc120SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, (polar | 0x05));
1248d98f2e5SJia-Ju Bai 		micro_delay(10);
1258d98f2e5SJia-Ju Bai 	}
1263afdc120SJia-Ju Bai 	ndr_out8(base, REG_PHY_CTRL, (polar | 0x04));
1278d98f2e5SJia-Ju Bai 	return field[6];
1288d98f2e5SJia-Ju Bai }
1298d98f2e5SJia-Ju Bai 
write_phy_reg(u32_t base,int phy_addr,int phy_reg,u16_t val)1308d98f2e5SJia-Ju Bai static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) {
1318d98f2e5SJia-Ju Bai 	int i, j, fieldlen[8];
1328d98f2e5SJia-Ju Bai 	u32_t field[8];
1338d98f2e5SJia-Ju Bai 	u8_t data, polar;
1348d98f2e5SJia-Ju Bai 
1358d98f2e5SJia-Ju Bai 	field[0] = 0xffffffff;		fieldlen[0] = 32;
1368d98f2e5SJia-Ju Bai 	field[1] = 0x0001;		fieldlen[1] = 2;
1378d98f2e5SJia-Ju Bai 	field[2] = 0x0001;		fieldlen[2] = 2;
1388d98f2e5SJia-Ju Bai 	field[3] = phy_addr;		fieldlen[3] = 5;
1398d98f2e5SJia-Ju Bai 	field[4] = phy_reg;		fieldlen[4] = 5;
1408d98f2e5SJia-Ju Bai 	field[5] = 0x0002;		fieldlen[5] = 2;
1418d98f2e5SJia-Ju Bai 	field[6] = val;			fieldlen[6] = 16;
1428d98f2e5SJia-Ju Bai 	field[7] = 0x0000;		fieldlen[7] = 1;
1438d98f2e5SJia-Ju Bai 
1443afdc120SJia-Ju Bai 	polar = ndr_in8(base, REG_PHY_CTRL) & 0x28;
1458d98f2e5SJia-Ju Bai 	for (i = 0; i < 7; i++) {
1468d98f2e5SJia-Ju Bai 		for (j = 0; j < fieldlen[i]; j++) {
1470d23d856SJia-Ju Bai 			data = (field[i] >> (field[i] - j - 1)) << 1;
1488d98f2e5SJia-Ju Bai 			data = (0x02 & data) | (0x04 | polar);
1493afdc120SJia-Ju Bai 			ndr_out8(base, REG_PHY_CTRL, data);
1508d98f2e5SJia-Ju Bai 			micro_delay(10);
1513afdc120SJia-Ju Bai 			ndr_out8(base, REG_PHY_CTRL, (data | 0x01));
1528d98f2e5SJia-Ju Bai 			micro_delay(10);
1538d98f2e5SJia-Ju Bai 		}
1548d98f2e5SJia-Ju Bai 	}
1558d98f2e5SJia-Ju Bai 	for (i = 0; i < fieldlen[7]; i ++) {
1563afdc120SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, polar);
1578d98f2e5SJia-Ju Bai 		micro_delay(10);
1583afdc120SJia-Ju Bai 		field[7] |= ((ndr_in8(base, REG_PHY_CTRL) & 0x02) >> 1)
1598d98f2e5SJia-Ju Bai 						<< (fieldlen[7] - i -1);
1600d23d856SJia-Ju Bai 		ndr_out8(base, REG_PHY_CTRL, (polar | 0x01));
1618d98f2e5SJia-Ju Bai 		micro_delay(10);
1628d98f2e5SJia-Ju Bai 	}
1638d98f2e5SJia-Ju Bai }
1648d98f2e5SJia-Ju Bai 
1658d98f2e5SJia-Ju Bai /* ====== Developer interface ======*/
1668d98f2e5SJia-Ju Bai /* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###)
1678d98f2e5SJia-Ju Bai  * -- Return OK means success, Others means failure */
dev_real_reset(u32_t * base)1683afdc120SJia-Ju Bai static int dev_real_reset(u32_t *base) {
1693afdc120SJia-Ju Bai 	u32_t data, base0 = base[0];
1703afdc120SJia-Ju Bai 	data = ndr_in32(base0, REG_ASIC_CTRL);
1713afdc120SJia-Ju Bai 	ndr_out32(base0, REG_ASIC_CTRL, data | AC_RESET_ALL);
1723afdc120SJia-Ju Bai 	micro_delay(5000);
1733afdc120SJia-Ju Bai 	if (ndr_in32(base0, REG_ASIC_CTRL) & AC_RESET_BUSY)
1748d98f2e5SJia-Ju Bai 		return -EIO;
1758d98f2e5SJia-Ju Bai 	return OK;
1768d98f2e5SJia-Ju Bai }
1778d98f2e5SJia-Ju Bai 
1783afdc120SJia-Ju Bai /* Intialize other hardware I/O registers (### INIT_HARDWARE_IO_CAN_FAIL ###)
1798d98f2e5SJia-Ju Bai  * -- Return OK means success, Others means failure */
dev_init_io(u32_t * base)1803afdc120SJia-Ju Bai static int dev_init_io(u32_t *base) {
1813afdc120SJia-Ju Bai 	u32_t mac_ctrl, physet, mode0, mode1, base0 = base[0];
1823afdc120SJia-Ju Bai 	mode0 = read_eeprom(base0, 6);
1833afdc120SJia-Ju Bai 	mode1 = ndr_in16(base0, REG_ASIC_CTRL);
1848d98f2e5SJia-Ju Bai 	mode1 &= ~(AC_LED_MODE_B1 | AC_LED_MODE | AC_LED_SPEED);
1858d98f2e5SJia-Ju Bai 	if ((mode0 & 0x03) > 1)
1868d98f2e5SJia-Ju Bai 		mode1 |= AC_LED_MODE_B1;
1878d98f2e5SJia-Ju Bai 	if ((mode0 & 0x01) == 1)
1888d98f2e5SJia-Ju Bai 		mode1 |= AC_LED_MODE;
1898d98f2e5SJia-Ju Bai 	if ((mode0 & 0x08) == 8)
1908d98f2e5SJia-Ju Bai 		mode1 |= AC_LED_SPEED;
1913afdc120SJia-Ju Bai 	ndr_out32(base0, REG_ASIC_CTRL, mode1);
1923afdc120SJia-Ju Bai 	physet = ndr_in8(base0, REG_PHY_SET);
1933afdc120SJia-Ju Bai 	physet = (physet & 0xf8) | ((mode0 & 0x70) >> 4);
1943afdc120SJia-Ju Bai 	ndr_out8(base0, REG_PHY_SET, physet);
1953afdc120SJia-Ju Bai 	mac_ctrl = ndr_in32(base0, REG_MAC_CTRL);
1963afdc120SJia-Ju Bai 	mac_ctrl |= (MC_STAT_DISABLE | MC_TX_FC_ENA | MC_RX_FC_ENA);
1973afdc120SJia-Ju Bai 	ndr_out32(base0, REG_MAC_CTRL, 0);
1983afdc120SJia-Ju Bai 	ndr_out16(base0, REG_MAX_FRAME, RX_BUF_SIZE);
1993afdc120SJia-Ju Bai 	ndr_out8(base0, REG_RX_DMA_PERIOD, 0x01);
2003afdc120SJia-Ju Bai 	ndr_out8(base0, REG_RX_DMA_UTH, 0x30);
2013afdc120SJia-Ju Bai 	ndr_out8(base0, REG_RX_DMA_BTH, 0x30);
2023afdc120SJia-Ju Bai 	ndr_out8(base0, REG_TX_DMA_PERIOD, 0x26);
2033afdc120SJia-Ju Bai 	ndr_out8(base0, REG_TX_DMA_UTH, 0x04);
2043afdc120SJia-Ju Bai 	ndr_out8(base0, REG_TX_DMA_BTH, 0x30);
2053afdc120SJia-Ju Bai 	ndr_out16(base0, REG_FLOW_ON_TH, 0x0740);
2063afdc120SJia-Ju Bai 	ndr_out16(base0, REG_FLOW_OFF_TH, 0x00bf);
2073afdc120SJia-Ju Bai 	ndr_out32(base0, REG_MAC_CTRL, mac_ctrl);
2088d98f2e5SJia-Ju Bai 	return OK;
2098d98f2e5SJia-Ju Bai }
2108d98f2e5SJia-Ju Bai 
2118d98f2e5SJia-Ju Bai /* Intialize MII interface (### MII_INIT_CAN_FAIL ###)
2128d98f2e5SJia-Ju Bai  * -- Return OK means success, Others means failure */
dev_init_mii(u32_t * base)2133afdc120SJia-Ju Bai static int dev_init_mii(u32_t *base) {
2148d98f2e5SJia-Ju Bai 	int i, phyaddr;
2158d98f2e5SJia-Ju Bai 	u8_t revision;
2168d98f2e5SJia-Ju Bai 	u16_t phyctrl, cr1000, length, address, value;
2178d98f2e5SJia-Ju Bai 	u16_t *param;
2183afdc120SJia-Ju Bai 	u32_t status, base0 = base[0];
2198d98f2e5SJia-Ju Bai 
2208d98f2e5SJia-Ju Bai 	for (i = 0; i < 32; i++) {
2218d98f2e5SJia-Ju Bai 		phyaddr = (i + 0x01) % 32;
2223afdc120SJia-Ju Bai 		status = read_phy_reg(base0, phyaddr, 0x01);
2238d98f2e5SJia-Ju Bai 		if ((status != 0xffff) && (status != 0))
2248d98f2e5SJia-Ju Bai 			break;
2258d98f2e5SJia-Ju Bai 	}
2268d98f2e5SJia-Ju Bai 	if (i == 32)
2278d98f2e5SJia-Ju Bai 		return -EIO;
2288d98f2e5SJia-Ju Bai 	if (phyaddr != -1) {
2293afdc120SJia-Ju Bai 		cr1000 = read_phy_reg(base0, phyaddr, 0x09);
2308d98f2e5SJia-Ju Bai 		cr1000 |= 0x0700;
2313afdc120SJia-Ju Bai 		write_phy_reg(base0, phyaddr, 0x09, cr1000);
2323afdc120SJia-Ju Bai 		phyctrl = read_phy_reg(base0, phyaddr, 0x00);
2338d98f2e5SJia-Ju Bai 	}
2348d98f2e5SJia-Ju Bai 
2358d98f2e5SJia-Ju Bai 	param = &PhyParam[0];
2368d98f2e5SJia-Ju Bai 	length = (*param) & 0x00ff;
2378d98f2e5SJia-Ju Bai 	revision = (u8_t)((*param) >> 8);
2388d98f2e5SJia-Ju Bai 	param++;
2398d98f2e5SJia-Ju Bai 	while (length != 0) {
2408d98f2e5SJia-Ju Bai 		if (g_driver.revision == revision) {
2418d98f2e5SJia-Ju Bai 			while (length > 1) {
2428d98f2e5SJia-Ju Bai 				address = *param;
2438d98f2e5SJia-Ju Bai 				value = *(param + 1);
2448d98f2e5SJia-Ju Bai 				param += 2;
2453afdc120SJia-Ju Bai 				write_phy_reg(base0, phyaddr, address, value);
2468d98f2e5SJia-Ju Bai 				length -= 4;
2478d98f2e5SJia-Ju Bai 			}
2488d98f2e5SJia-Ju Bai 			break;
2498d98f2e5SJia-Ju Bai 		}
2508d98f2e5SJia-Ju Bai 		else {
2518d98f2e5SJia-Ju Bai 			param += length / 2;
2528d98f2e5SJia-Ju Bai 			length = *param & 0x00ff;
2538d98f2e5SJia-Ju Bai 			revision = (u8_t)((*param) >> 8);
2548d98f2e5SJia-Ju Bai 			param++;
2558d98f2e5SJia-Ju Bai 		}
2568d98f2e5SJia-Ju Bai 	}
2573afdc120SJia-Ju Bai 	write_phy_reg(base0, phyaddr, 0x00, phyctrl | 0x8200);
2588d98f2e5SJia-Ju Bai 	return OK;
2598d98f2e5SJia-Ju Bai }
2608d98f2e5SJia-Ju Bai 
2613afdc120SJia-Ju Bai /* Enable or disable interrupt (### INTR_ENABLE_DISABLE ###) */
dev_intr_control(u32_t * base,int flag)2623afdc120SJia-Ju Bai static void dev_intr_control(u32_t *base, int flag) {
2633afdc120SJia-Ju Bai 	u32_t base0 = base[0];
2643afdc120SJia-Ju Bai 	if (flag == INTR_ENABLE)
2653afdc120SJia-Ju Bai 		ndr_out16(base0, REG_IMR, CMD_INTR_ENABLE);
2663afdc120SJia-Ju Bai 	else if (flag == INTR_DISABLE)
2673afdc120SJia-Ju Bai 		ndr_out16(base0, REG_IMR, 0);
2688d98f2e5SJia-Ju Bai }
2698d98f2e5SJia-Ju Bai 
2703afdc120SJia-Ju Bai /* Enable or disable Rx/Tx (### RX_TX_ENABLE_DISABLE ###) */
dev_rx_tx_control(u32_t * base,int flag)2713afdc120SJia-Ju Bai static void dev_rx_tx_control(u32_t *base, int flag) {
2723afdc120SJia-Ju Bai 	u32_t data, base0 = base[0];
2733afdc120SJia-Ju Bai 	data = ndr_in32(base0, REG_MAC_CTRL);
2743afdc120SJia-Ju Bai 	if (flag == RX_TX_ENABLE)
2753afdc120SJia-Ju Bai 		ndr_out32(base0, REG_MAC_CTRL, data | (MC_RX_ENABLE | MC_TX_ENABLE));
2763afdc120SJia-Ju Bai 	else if (flag == RX_TX_DISABLE) {
2773afdc120SJia-Ju Bai 		ndr_out32(base0, REG_MAC_CTRL, 0);
2783afdc120SJia-Ju Bai 		ndr_out32(base0, REG_ASIC_CTRL, AC_RESET_ALL);
2793afdc120SJia-Ju Bai 	}
2808d98f2e5SJia-Ju Bai }
2818d98f2e5SJia-Ju Bai 
2828d98f2e5SJia-Ju Bai /* Get MAC address to the array 'pa' (### GET_MAC_ADDR ###) */
dev_get_addr(u32_t * base,u8_t * pa)2833afdc120SJia-Ju Bai static void dev_get_addr(u32_t *base, u8_t *pa) {
2843afdc120SJia-Ju Bai 	u32_t i, sta_addr[3], base0 = base[0];
2858d98f2e5SJia-Ju Bai 	for (i = 0; i < 3; i++)	 {
2863afdc120SJia-Ju Bai 		sta_addr[i] = read_eeprom(base0, 16 + i);
2873afdc120SJia-Ju Bai 		ndr_out16(base0, (REG_STA_ADDR0 + i * 2), sta_addr[i]);
2888d98f2e5SJia-Ju Bai 	}
2893afdc120SJia-Ju Bai 	pa[0] = (u8_t)(ndr_in16(base0, REG_STA_ADDR0) & 0x00ff);
2903afdc120SJia-Ju Bai 	pa[1] = (u8_t)((ndr_in16(base0, REG_STA_ADDR0) & 0xff00) >> 8);
2913afdc120SJia-Ju Bai 	pa[2] = (u8_t)(ndr_in16(base0, REG_STA_ADDR1) & 0x00ff);
2923afdc120SJia-Ju Bai 	pa[3] = (u8_t)((ndr_in16(base0, REG_STA_ADDR1) & 0xff00) >> 8);
2933afdc120SJia-Ju Bai 	pa[4] = (u8_t)(ndr_in16(base0, REG_STA_ADDR2) & 0x00ff);
2943afdc120SJia-Ju Bai 	pa[5] = (u8_t)((ndr_in16(base0, REG_STA_ADDR2) & 0xff00) >> 8);
2958d98f2e5SJia-Ju Bai }
2968d98f2e5SJia-Ju Bai 
2978d98f2e5SJia-Ju Bai /* Check link status (### CHECK_LINK ###)
2988d98f2e5SJia-Ju Bai  * -- Return LINK_UP or LINK_DOWN */
dev_check_link(u32_t * base)2993afdc120SJia-Ju Bai static int dev_check_link(u32_t *base) {
3003afdc120SJia-Ju Bai 	u32_t phy_ctrl, mac_ctrl, base0 = base[0];
3018d98f2e5SJia-Ju Bai 	int ret;
3028d98f2e5SJia-Ju Bai 	char speed[20], duplex[20];
3038d98f2e5SJia-Ju Bai 
3043afdc120SJia-Ju Bai 	phy_ctrl = ndr_in8(base0, REG_PHY_CTRL);
3053afdc120SJia-Ju Bai 	mac_ctrl = ndr_in8(base0, REG_MAC_CTRL);
3068d98f2e5SJia-Ju Bai 	switch (phy_ctrl & PC_LINK_SPEED) {
3078d98f2e5SJia-Ju Bai 		case PC_LINK_SPEED10:
3088d98f2e5SJia-Ju Bai 			strcpy(speed, "10Mbps");
3098d98f2e5SJia-Ju Bai 			ret = LINK_UP;
3108d98f2e5SJia-Ju Bai 			break;
3118d98f2e5SJia-Ju Bai 		case PC_LINK_SPEED100:
3128d98f2e5SJia-Ju Bai 			strcpy(speed, "100Mbps");
3138d98f2e5SJia-Ju Bai 			ret = LINK_UP;
3148d98f2e5SJia-Ju Bai 			break;
3158d98f2e5SJia-Ju Bai 		case PC_LINK_SPEED1000:
3168d98f2e5SJia-Ju Bai 			strcpy(speed, "1000Mbps");
3178d98f2e5SJia-Ju Bai 			ret = LINK_UP;
3188d98f2e5SJia-Ju Bai 			break;
3198d98f2e5SJia-Ju Bai 		default:
3208d98f2e5SJia-Ju Bai 			strcpy(speed, "unknown");
3218d98f2e5SJia-Ju Bai 			ret = LINK_DOWN;
3228d98f2e5SJia-Ju Bai 			break;
3238d98f2e5SJia-Ju Bai 	}
3248d98f2e5SJia-Ju Bai 	if (phy_ctrl & PC_DUPLEX_STS) {
3258d98f2e5SJia-Ju Bai 		strcpy(duplex, "full");
3268d98f2e5SJia-Ju Bai 		mac_ctrl |= (MC_DUPLEX_SEL | MC_TX_FC_ENA | MC_RX_FC_ENA);
3278d98f2e5SJia-Ju Bai 	}
3288d98f2e5SJia-Ju Bai 	else
3298d98f2e5SJia-Ju Bai 		strcpy(duplex, "half");
3303afdc120SJia-Ju Bai 	ndr_out32(base0, REG_MAC_CTRL, mac_ctrl);
3318d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
3323afdc120SJia-Ju Bai 	printf("NDR: Link speed is %s, %s duplex\n", speed, duplex);
3338d98f2e5SJia-Ju Bai #endif
3348d98f2e5SJia-Ju Bai 	return ret;
3358d98f2e5SJia-Ju Bai }
3368d98f2e5SJia-Ju Bai 
3373afdc120SJia-Ju Bai /* Set driver receive mode (### SET_REC_MODE ###) */
dev_set_rec_mode(u32_t * base,int mode)3383afdc120SJia-Ju Bai static void dev_set_rec_mode(u32_t *base, int mode) {
3393afdc120SJia-Ju Bai 	u32_t data, base0 = base[0];
3403afdc120SJia-Ju Bai 	data = ndr_in8(base0, REG_RCR);
3413afdc120SJia-Ju Bai 	data &= ~(CMD_RCR_UNICAST | CMD_RCR_MULTICAST | CMD_RCR_BROADCAST);
342*f7df02e7SDavid van Moolenbroek 	if (mode & NDEV_MODE_PROMISC)
3433afdc120SJia-Ju Bai 		data |= CMD_RCR_UNICAST | CMD_RCR_MULTICAST | CMD_RCR_MULTICAST;
344*f7df02e7SDavid van Moolenbroek 	if (mode & NDEV_MODE_BCAST)
3453afdc120SJia-Ju Bai 		data |= CMD_RCR_BROADCAST;
346*f7df02e7SDavid van Moolenbroek 	if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
3473afdc120SJia-Ju Bai 		data |= CMD_RCR_MULTICAST;
3483afdc120SJia-Ju Bai 	data |= CMD_RCR_UNICAST;
3493afdc120SJia-Ju Bai 	ndr_out8(base0, REG_RCR, data);
3508d98f2e5SJia-Ju Bai }
3518d98f2e5SJia-Ju Bai 
3523afdc120SJia-Ju Bai /* Start Tx channel (### START_TX_CHANNEL ###) */
dev_start_tx(u32_t * base)3533afdc120SJia-Ju Bai static void dev_start_tx(u32_t *base) {
3543afdc120SJia-Ju Bai 	u32_t base0 = base[0];
3553afdc120SJia-Ju Bai 	ndr_out32(base0, REG_DMA_CTRL, CMD_TX_START);
3563afdc120SJia-Ju Bai }
3573afdc120SJia-Ju Bai 
3583afdc120SJia-Ju Bai /* Read and clear interrupt (### READ_CLEAR_INTR_STS ###) */
dev_read_clear_intr_status(u32_t * base)3593afdc120SJia-Ju Bai static u32_t dev_read_clear_intr_status(u32_t *base) {
3603afdc120SJia-Ju Bai 	u32_t data, base0 = base[0];
3613afdc120SJia-Ju Bai 	data = ndr_in16(base0, REG_ISR);
3623afdc120SJia-Ju Bai 	ndr_out16(base0, REG_ISR, 0);
3633afdc120SJia-Ju Bai 	return data;
3643afdc120SJia-Ju Bai }
3653afdc120SJia-Ju Bai 
3663afdc120SJia-Ju Bai /* ---------- WITH DESCRIPTOR ---------- */
3673afdc120SJia-Ju Bai /* Intialize Rx descriptor (### INIT_RX_DESC ###) */
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)3683afdc120SJia-Ju Bai static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size,
3693afdc120SJia-Ju Bai 			phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) {
3703afdc120SJia-Ju Bai 	NDR_desc *desc = desc_start + index;
3713afdc120SJia-Ju Bai 	desc->status = 0;
3723afdc120SJia-Ju Bai 	desc->frag_info = (u64_t)(buf_dma);
3733afdc120SJia-Ju Bai 	desc->frag_info |= ((u64_t)buf_size << 48) & RFI_FRAG_LEN;
3743afdc120SJia-Ju Bai 	if (index == max_desc_num - 1)
3753afdc120SJia-Ju Bai 		desc->next = desc_dma_start;
3763afdc120SJia-Ju Bai 	else
3773afdc120SJia-Ju Bai 		desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc);
3783afdc120SJia-Ju Bai }
3793afdc120SJia-Ju Bai 
3803afdc120SJia-Ju Bai /* Intialize Tx descriptor (### INIT_TX_DESC ###) */
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)3813afdc120SJia-Ju Bai static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size,
3823afdc120SJia-Ju Bai 			phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) {
3833afdc120SJia-Ju Bai 	NDR_desc *desc = desc_start + index;
3843afdc120SJia-Ju Bai 	desc->status = TFS_TFD_DONE;
3853afdc120SJia-Ju Bai 	desc->frag_info = (u64_t)(buf_dma);
3863afdc120SJia-Ju Bai 	if (index == max_desc_num - 1)
3873afdc120SJia-Ju Bai 		desc->next = desc_dma_start;
3883afdc120SJia-Ju Bai 	else
3893afdc120SJia-Ju Bai 		desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc);
3903afdc120SJia-Ju Bai }
3913afdc120SJia-Ju Bai 
3923afdc120SJia-Ju Bai /* Set Rx/Tx descriptor address into device register (### SET_DESC_REG ###) */
dev_set_desc_reg(u32_t * base,phys_bytes rx_addr,phys_bytes tx_addr)3933afdc120SJia-Ju Bai static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr,
3943afdc120SJia-Ju Bai 								phys_bytes tx_addr) {
3953afdc120SJia-Ju Bai 	u32_t base0 = base[0];
3963afdc120SJia-Ju Bai 	ndr_out32(base0, REG_RX_DESC_BASEL, rx_addr);
3973afdc120SJia-Ju Bai 	ndr_out32(base0, REG_RX_DESC_BASEU, 0);
3983afdc120SJia-Ju Bai 	ndr_out32(base0, REG_TX_DESC_BASEL, tx_addr);
3993afdc120SJia-Ju Bai 	ndr_out32(base0, REG_TX_DESC_BASEU, 0);
4003afdc120SJia-Ju Bai }
4013afdc120SJia-Ju Bai 
4023afdc120SJia-Ju Bai /* Check whether Rx is OK from Rx descriptor (### CHECK_RX_OK_FROM_DESC ###)
4033afdc120SJia-Ju Bai  * -- Current buffer number is index
4043afdc120SJia-Ju Bai  * -- Return RX_OK or RX_SUSPEND or RX_ERROR */
dev_rx_ok_desc(u32_t * base,NDR_desc * desc,int index)4053afdc120SJia-Ju Bai static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index) {
4063afdc120SJia-Ju Bai 	if (desc->status & RFS_RFD_DONE) {
4073afdc120SJia-Ju Bai 		if (desc->status & RFS_ERROR)
4083afdc120SJia-Ju Bai 			return RX_ERROR;
4098d98f2e5SJia-Ju Bai 		if ((desc->status & RFS_NORMAL) == RFS_NORMAL)
4103afdc120SJia-Ju Bai 			return RX_OK;
4113afdc120SJia-Ju Bai 	}
4123afdc120SJia-Ju Bai 	return RX_SUSPEND;
4138d98f2e5SJia-Ju Bai }
4148d98f2e5SJia-Ju Bai 
4153afdc120SJia-Ju Bai /* Get length from Rx descriptor (### GET_RX_LENGTH_FROM_DESC ###)
4163afdc120SJia-Ju Bai  * -- Current buffer number is index
4173afdc120SJia-Ju Bai  * -- Return the length */
dev_rx_len_desc(u32_t * base,NDR_desc * desc,int index)4183afdc120SJia-Ju Bai static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index) {
4198d98f2e5SJia-Ju Bai 	int totlen;
4203afdc120SJia-Ju Bai 	totlen = (int)(desc->status & RFS_FRAME_LEN);
4218d98f2e5SJia-Ju Bai 	return totlen;
4228d98f2e5SJia-Ju Bai }
4238d98f2e5SJia-Ju Bai 
4243afdc120SJia-Ju Bai /* Set Rx descriptor after Rx done (### SET_RX_DESC_DONE ###)
4253afdc120SJia-Ju Bai  * -- Current buffer number is index */
dev_set_rx_desc_done(u32_t * base,NDR_desc * desc,int index)4263afdc120SJia-Ju Bai static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index) {
4273afdc120SJia-Ju Bai 	desc->status = 0;
4283afdc120SJia-Ju Bai }
4293afdc120SJia-Ju Bai 
4303afdc120SJia-Ju Bai /* Set Tx descriptor to prepare transmitting (### SET_TX_DESC_PREPARE)
4313afdc120SJia-Ju Bai  * -- Current buffer number is index */
dev_set_tx_desc_prepare(u32_t * base,NDR_desc * desc,int index,size_t data_size)4323afdc120SJia-Ju Bai static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index,
4333afdc120SJia-Ju Bai 									size_t data_size) {
4348d98f2e5SJia-Ju Bai 	desc->status = TFS_TFD_DONE;
4353afdc120SJia-Ju Bai 	desc->status |= (u64_t)(TFS_WORD_ALIGN | (TFS_FRAMEID & index)
4363afdc120SJia-Ju Bai 					| (TFS_FRAG_COUNT & (1 << 24))) | TFS_TX_DMA_INDICATE;
4373afdc120SJia-Ju Bai 	desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((data_size > 60 ? data_size : 60)
4383afdc120SJia-Ju Bai 							& 0xffff) << 48);
4398d98f2e5SJia-Ju Bai 	desc->status &= (u64_t)(~(TFS_TFD_DONE));
4408d98f2e5SJia-Ju Bai }
4418d98f2e5SJia-Ju Bai 
4423afdc120SJia-Ju Bai /* Check whether Tx is OK from Tx descriptor (### CHECK_TX_OK_FROM_DESC ###)
4433afdc120SJia-Ju Bai  * -- Current buffer number is index
4443afdc120SJia-Ju Bai  * -- Return TX_OK or TX_SUSPEND or TX_ERROR */
dev_tx_ok_desc(u32_t * base,NDR_desc * desc,int index)4453afdc120SJia-Ju Bai static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index) {
4463afdc120SJia-Ju Bai 	if (desc->status & TFS_TFD_DONE)
4473afdc120SJia-Ju Bai 		return TX_OK;
4483afdc120SJia-Ju Bai 	return TX_SUSPEND;
4498d98f2e5SJia-Ju Bai }
4508d98f2e5SJia-Ju Bai 
4513afdc120SJia-Ju Bai /* Set Tx descriptor after Tx done (### SET_TX_DESC_DONE ###)
4523afdc120SJia-Ju Bai  * -- Current buffer number is index */
dev_set_tx_desc_done(u32_t * base,NDR_desc * desc,int index)4533afdc120SJia-Ju Bai static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index) {
4543afdc120SJia-Ju Bai 	desc->status = 0;
4558d98f2e5SJia-Ju Bai }
4568d98f2e5SJia-Ju Bai 
4578d98f2e5SJia-Ju Bai /* Driver interface table */
4583afdc120SJia-Ju Bai static const struct netdriver NDR_table = {
459*f7df02e7SDavid van Moolenbroek 	.ndr_name = "stge",
4603afdc120SJia-Ju Bai 	.ndr_init = NDR_init,
4613afdc120SJia-Ju Bai 	.ndr_stop = NDR_stop,
462*f7df02e7SDavid van Moolenbroek 	.ndr_set_mode = NDR_set_mode,
4633afdc120SJia-Ju Bai 	.ndr_recv = NDR_recv,
4643afdc120SJia-Ju Bai 	.ndr_send = NDR_send,
4653afdc120SJia-Ju Bai 	.ndr_intr = NDR_intr,
4668d98f2e5SJia-Ju Bai };
4678d98f2e5SJia-Ju Bai 
main(int argc,char * argv[])4688d98f2e5SJia-Ju Bai int main(int argc, char *argv[]) {
4698d98f2e5SJia-Ju Bai 	env_setargs(argc, argv);
4703afdc120SJia-Ju Bai 	netdriver_task(&NDR_table);
4718d98f2e5SJia-Ju Bai }
4728d98f2e5SJia-Ju Bai 
4738d98f2e5SJia-Ju Bai /* Initialize the driver */
474*f7df02e7SDavid van Moolenbroek static int
NDR_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks __unused)475*f7df02e7SDavid van Moolenbroek NDR_init(unsigned int instance, netdriver_addr_t * addr, uint32_t * caps,
476*f7df02e7SDavid van Moolenbroek 	unsigned int * ticks __unused)
477*f7df02e7SDavid van Moolenbroek {
4783afdc120SJia-Ju Bai 	int i, ret = 0;
4798d98f2e5SJia-Ju Bai 
4808d98f2e5SJia-Ju Bai 	/* Intialize driver data structure */
4818d98f2e5SJia-Ju Bai 	memset(&g_driver, 0, sizeof(g_driver));
4828d98f2e5SJia-Ju Bai 	g_driver.link = LINK_UNKNOWN;
4838d98f2e5SJia-Ju Bai 	g_instance = instance;
4848d98f2e5SJia-Ju Bai 
4858d98f2e5SJia-Ju Bai 	/* Probe the device */
4863afdc120SJia-Ju Bai 	if (dev_probe(&g_driver, instance)) {
4873afdc120SJia-Ju Bai 		printf("NDR: Device is not found\n");
4888d98f2e5SJia-Ju Bai 		ret = -ENODEV;
4898d98f2e5SJia-Ju Bai 		goto err_probe;
4908d98f2e5SJia-Ju Bai 	}
4918d98f2e5SJia-Ju Bai 
4923afdc120SJia-Ju Bai 	/* Intialize hardware */
4933afdc120SJia-Ju Bai 	if (dev_init_hw(&g_driver, addr)) {
4943afdc120SJia-Ju Bai 		printf("NDR: Fail to initialize hardware\n");
4953afdc120SJia-Ju Bai 		ret = -EIO;
4963afdc120SJia-Ju Bai 		goto err_init_hw;
4973afdc120SJia-Ju Bai 	}
4983afdc120SJia-Ju Bai 
4998d98f2e5SJia-Ju Bai 	/* Allocate and initialize buffer */
5003afdc120SJia-Ju Bai 	if (dev_init_buf(&g_driver)) {
5013afdc120SJia-Ju Bai 		printf("NDR: Fail to initialize buffer\n");
5028d98f2e5SJia-Ju Bai 		ret = -ENODEV;
5038d98f2e5SJia-Ju Bai 		goto err_init_buf;
5048d98f2e5SJia-Ju Bai 	}
5058d98f2e5SJia-Ju Bai 
5063afdc120SJia-Ju Bai 	/* Enable interrupts */
5073afdc120SJia-Ju Bai 	/* ### INTR_ENABLE_DISABLE ### */
5083afdc120SJia-Ju Bai 	dev_intr_control(g_driver.base, INTR_ENABLE);
5093afdc120SJia-Ju Bai 
5103afdc120SJia-Ju Bai 	/* Start Rx and Tx */
5113afdc120SJia-Ju Bai 	/* ### RX_TX_ENABLE_DISABLE ### */
5123afdc120SJia-Ju Bai 	dev_rx_tx_control(g_driver.base, RX_TX_ENABLE);
5138d98f2e5SJia-Ju Bai 
5148d98f2e5SJia-Ju Bai 	/* Clear send and recv flag */
5158d98f2e5SJia-Ju Bai 	g_driver.send_flag = FALSE;
5168d98f2e5SJia-Ju Bai 	g_driver.recv_flag = FALSE;
5178d98f2e5SJia-Ju Bai 
518*f7df02e7SDavid van Moolenbroek 	*caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
519*f7df02e7SDavid van Moolenbroek 	return OK;
5208d98f2e5SJia-Ju Bai 
5218d98f2e5SJia-Ju Bai err_init_buf:
5223afdc120SJia-Ju Bai err_init_hw:
5238d98f2e5SJia-Ju Bai err_probe:
5248d98f2e5SJia-Ju Bai 	return ret;
5258d98f2e5SJia-Ju Bai }
5268d98f2e5SJia-Ju Bai 
5273afdc120SJia-Ju Bai /* Stop the driver */
NDR_stop(void)5283afdc120SJia-Ju Bai static void NDR_stop(void) {
5293afdc120SJia-Ju Bai 	/* Free Rx and Tx buffer*/
5303afdc120SJia-Ju Bai 	free_contig(g_driver.buf, g_driver.buf_size);
5313afdc120SJia-Ju Bai 
5323afdc120SJia-Ju Bai 	/* Stop interrupt */
5333afdc120SJia-Ju Bai 	/* ### INTR_ENABLE_DISABLE ### */
5343afdc120SJia-Ju Bai 	dev_intr_control(g_driver.base, INTR_DISABLE);
5353afdc120SJia-Ju Bai 
5363afdc120SJia-Ju Bai 	/* Stop Rx and Tx */
5373afdc120SJia-Ju Bai 	/* ### RX_TX_ENABLE_DISABLE ### */
5383afdc120SJia-Ju Bai 	dev_rx_tx_control(g_driver.base, RX_TX_DISABLE);
5393afdc120SJia-Ju Bai }
5403afdc120SJia-Ju Bai 
5413afdc120SJia-Ju Bai /* Set driver mode */
542*f7df02e7SDavid van Moolenbroek static void
NDR_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)543*f7df02e7SDavid van Moolenbroek NDR_set_mode(unsigned int mode, const netdriver_addr_t * mcast_list __unused,
544*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count __unused)
545*f7df02e7SDavid van Moolenbroek {
5463afdc120SJia-Ju Bai 	g_driver.mode = mode;
5473afdc120SJia-Ju Bai 	/* Set driver receive mode */
5483afdc120SJia-Ju Bai 	/* ### SET_REC_MODE ### */
5493afdc120SJia-Ju Bai 	dev_set_rec_mode(g_driver.base, mode);
5503afdc120SJia-Ju Bai }
5513afdc120SJia-Ju Bai 
5523afdc120SJia-Ju Bai /* Receive data */
NDR_recv(struct netdriver_data * data,size_t max)5533afdc120SJia-Ju Bai static ssize_t NDR_recv(struct netdriver_data *data, size_t max) {
5543afdc120SJia-Ju Bai 	NDR_driver *pdev = &g_driver;
5553afdc120SJia-Ju Bai 	u32_t totlen, packlen;
5563afdc120SJia-Ju Bai 	int index, ret, offset = 0;
5573afdc120SJia-Ju Bai 	NDR_desc *desc;
5583afdc120SJia-Ju Bai 
5593afdc120SJia-Ju Bai 	index = pdev->rx_head;
5603afdc120SJia-Ju Bai 	desc = pdev->rx_desc;
5613afdc120SJia-Ju Bai 	desc += index;
5623afdc120SJia-Ju Bai 	/* Check whether Rx is OK from Rx descriptor */
5633afdc120SJia-Ju Bai 	/* ### CHECK_RX_OK_FROM_DESC ### */
5643afdc120SJia-Ju Bai 	ret = dev_rx_ok_desc(pdev->base, desc, index);
5653afdc120SJia-Ju Bai 	if (ret == RX_SUSPEND)
5663afdc120SJia-Ju Bai 		return SUSPEND;
5673afdc120SJia-Ju Bai 	else if (ret == RX_ERROR)
5683afdc120SJia-Ju Bai 		printf("NDR: Rx error now\n");
5693afdc120SJia-Ju Bai 	/* Get length from Rx descriptor */
5703afdc120SJia-Ju Bai 	/* ### GET_RX_LENGTH_FROM_DESC ### */
5713afdc120SJia-Ju Bai 	totlen = dev_rx_len_desc(pdev->base, desc, index);
5723afdc120SJia-Ju Bai 
5733afdc120SJia-Ju Bai 	/* Get data length */
5743afdc120SJia-Ju Bai 	/* ### Get , int inde, int indexxRx data length ### */
575*f7df02e7SDavid van Moolenbroek 	if (totlen < 8 || totlen > 2 * NDEV_ETH_PACKET_MAX) {
5763afdc120SJia-Ju Bai 		printf("NDR: Bad data length: %d\n", totlen);
5773afdc120SJia-Ju Bai 		panic(NULL);
5783afdc120SJia-Ju Bai 	}
5793afdc120SJia-Ju Bai 
5803afdc120SJia-Ju Bai 	packlen = totlen;
5813afdc120SJia-Ju Bai 	if (packlen > max)
5823afdc120SJia-Ju Bai 		packlen = max;
5833afdc120SJia-Ju Bai 
5843afdc120SJia-Ju Bai 	/* Copy data to user */
5853afdc120SJia-Ju Bai 	netdriver_copyout(data, 0, pdev->rx[index].buf + offset, packlen);
5863afdc120SJia-Ju Bai 
5873afdc120SJia-Ju Bai 	/* Set Rx descriptor after Rx done */
5883afdc120SJia-Ju Bai 	/* ### SET_RX_DESC_DONE ### */
5893afdc120SJia-Ju Bai 	dev_set_rx_desc_done(pdev->base, desc, index);
5903afdc120SJia-Ju Bai 	if (index == RX_BUFFER_NUM - 1)
5913afdc120SJia-Ju Bai 		index = 0;
5923afdc120SJia-Ju Bai 	else
5933afdc120SJia-Ju Bai 		index++;
5943afdc120SJia-Ju Bai 	pdev->rx_head = index;
5953afdc120SJia-Ju Bai 
5963afdc120SJia-Ju Bai #ifdef MY_DEBUG
5973afdc120SJia-Ju Bai 	printf("NDR: Successfully receive a packet, length = %d\n", packlen);
5983afdc120SJia-Ju Bai #endif
5993afdc120SJia-Ju Bai 
6003afdc120SJia-Ju Bai 	return packlen;
6013afdc120SJia-Ju Bai }
6023afdc120SJia-Ju Bai 
6033afdc120SJia-Ju Bai /* Transmit data */
NDR_send(struct netdriver_data * data,size_t size)6043afdc120SJia-Ju Bai static int NDR_send(struct netdriver_data *data, size_t size) {
6053afdc120SJia-Ju Bai 	NDR_driver *pdev = &g_driver;
6063afdc120SJia-Ju Bai 	int tx_head, i;
6073afdc120SJia-Ju Bai 	NDR_desc *desc;
6083afdc120SJia-Ju Bai 
6093afdc120SJia-Ju Bai 	tx_head = pdev->tx_head;
6103afdc120SJia-Ju Bai 	if (pdev->tx[tx_head].busy)
6113afdc120SJia-Ju Bai 		return SUSPEND;
6123afdc120SJia-Ju Bai 
6133afdc120SJia-Ju Bai 	/* Copy data from user */
6143afdc120SJia-Ju Bai 	netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size);
6153afdc120SJia-Ju Bai 
6163afdc120SJia-Ju Bai 	/* Set busy */
6173afdc120SJia-Ju Bai 	pdev->tx[tx_head].busy = TRUE;
6183afdc120SJia-Ju Bai 	pdev->tx_busy_num++;
6193afdc120SJia-Ju Bai 
6203afdc120SJia-Ju Bai 	desc = pdev->tx_desc;
6213afdc120SJia-Ju Bai 	desc += tx_head;
6223afdc120SJia-Ju Bai 	/* Set Tx descriptor to prepare transmitting */
6233afdc120SJia-Ju Bai 	/* ### SET_TX_DESC_PREPARE ### */
6243afdc120SJia-Ju Bai 	dev_set_tx_desc_prepare(pdev->base, desc, tx_head, size);
6253afdc120SJia-Ju Bai 	if (tx_head == TX_BUFFER_NUM - 1)
6263afdc120SJia-Ju Bai 		tx_head = 0;
6273afdc120SJia-Ju Bai 	else
6283afdc120SJia-Ju Bai 		tx_head++;
6293afdc120SJia-Ju Bai 	pdev->tx_head = tx_head;
6303afdc120SJia-Ju Bai 
6313afdc120SJia-Ju Bai 	/* Start Tx channel */
6323afdc120SJia-Ju Bai 	/* ### START_TX ### */
6333afdc120SJia-Ju Bai 	dev_start_tx(pdev->base);
6343afdc120SJia-Ju Bai 
6353afdc120SJia-Ju Bai 	return 0;
6363afdc120SJia-Ju Bai }
6373afdc120SJia-Ju Bai 
6383afdc120SJia-Ju Bai /* Handle interrupt */
NDR_intr(unsigned int mask)6393afdc120SJia-Ju Bai static void NDR_intr(unsigned int mask) {
6403afdc120SJia-Ju Bai 	int s;
6413afdc120SJia-Ju Bai 
6423afdc120SJia-Ju Bai 	/* Run interrupt handler at driver level */
6433afdc120SJia-Ju Bai 	dev_handler(&g_driver);
6443afdc120SJia-Ju Bai 
6453afdc120SJia-Ju Bai 	/* Reenable interrupts for this hook */
6463afdc120SJia-Ju Bai 	if ((s = sys_irqenable(&g_driver.hook)) != OK)
6473afdc120SJia-Ju Bai 		printf("NDR: Cannot enable OS interrupts: %d\n", s);
6483afdc120SJia-Ju Bai 
6493afdc120SJia-Ju Bai 	/* Perform tasks based on the flagged conditions */
6503afdc120SJia-Ju Bai 	dev_check_ints(&g_driver);
6513afdc120SJia-Ju Bai }
6523afdc120SJia-Ju Bai 
6538d98f2e5SJia-Ju Bai /* Match the device and get base address */
dev_probe(NDR_driver * pdev,int instance)6543afdc120SJia-Ju Bai static int dev_probe(NDR_driver *pdev, int instance) {
6553afdc120SJia-Ju Bai 	int devind, ioflag, i;
6568d98f2e5SJia-Ju Bai 	u16_t cr, vid, did;
6573afdc120SJia-Ju Bai 	u32_t bar, size, base;
6588d98f2e5SJia-Ju Bai 	u8_t irq, rev;
6598d98f2e5SJia-Ju Bai 	u8_t *reg;
6608d98f2e5SJia-Ju Bai 
6618d98f2e5SJia-Ju Bai 	/* Find pci device */
6628d98f2e5SJia-Ju Bai 	pci_init();
6638d98f2e5SJia-Ju Bai 	if (!pci_first_dev(&devind, &vid, &did))
6648d98f2e5SJia-Ju Bai 		return -EIO;
6658d98f2e5SJia-Ju Bai 	while (instance--) {
6668d98f2e5SJia-Ju Bai 		if (!pci_next_dev(&devind, &vid, &did))
6678d98f2e5SJia-Ju Bai 			return -EIO;
6688d98f2e5SJia-Ju Bai 	}
6698d98f2e5SJia-Ju Bai 	pci_reserve(devind);
6708d98f2e5SJia-Ju Bai 
6713afdc120SJia-Ju Bai 	/* Enable bus mastering and I/O space */
6728d98f2e5SJia-Ju Bai 	cr = pci_attr_r16(devind, PCI_CR);
6733afdc120SJia-Ju Bai 	pci_attr_w16(devind, PCI_CR, cr | 0x105);
6748d98f2e5SJia-Ju Bai 
6758d98f2e5SJia-Ju Bai 	/* Get base address */
6763afdc120SJia-Ju Bai 	for (i = 0; i < 6; i++)
6773afdc120SJia-Ju Bai 		pdev->base[i] = 0;
6783afdc120SJia-Ju Bai #ifdef DMA_BASE_IOMAP
6793afdc120SJia-Ju Bai 	for (i = 0; i < 6; i++) {
6803afdc120SJia-Ju Bai 		if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) {
6813afdc120SJia-Ju Bai 			/* printf("NDR: Fail to get PCI BAR\n"); */
6823afdc120SJia-Ju Bai 			continue;
6838d98f2e5SJia-Ju Bai 		}
6848d98f2e5SJia-Ju Bai 		if (ioflag) {
6853afdc120SJia-Ju Bai 			/* printf("NDR: PCI BAR is not for memory\n"); */
6863afdc120SJia-Ju Bai 			continue;
6878d98f2e5SJia-Ju Bai 		}
6888d98f2e5SJia-Ju Bai 		if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
6893afdc120SJia-Ju Bai 			printf("NDR: Fail to map hardware registers from PCI\n");
6908d98f2e5SJia-Ju Bai 			return -EIO;
6918d98f2e5SJia-Ju Bai 		}
6923afdc120SJia-Ju Bai 		pdev->base[i] = (u32_t)reg;
6933afdc120SJia-Ju Bai 	}
6948d98f2e5SJia-Ju Bai #else
6953afdc120SJia-Ju Bai 	for (i = 0; i < 6; i++)
6963afdc120SJia-Ju Bai 		pdev->base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0;
6978d98f2e5SJia-Ju Bai #endif
6983afdc120SJia-Ju Bai 	pdev->dev_name = pci_dev_name(vid, did);
6993afdc120SJia-Ju Bai 	pdev->irq = pci_attr_r8(devind, PCI_ILR);
7003afdc120SJia-Ju Bai 	pdev->revision = pci_attr_r8(devind, PCI_REV);
7013afdc120SJia-Ju Bai 	pdev->did = did;
7023afdc120SJia-Ju Bai 	pdev->vid = vid;
7033afdc120SJia-Ju Bai 	pdev->devind = devind;
7048d98f2e5SJia-Ju Bai 
7058d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
7063afdc120SJia-Ju Bai 	printf("NDR: Hardware name is %s\n", pdev->dev_name);
7073afdc120SJia-Ju Bai 	for (i = 0; i < 6; i++)
7083afdc120SJia-Ju Bai 		printf("NDR: PCI BAR%d is 0x%08x\n", i, pdev->base[i]);
7093afdc120SJia-Ju Bai 	printf("NDR: IRQ number is 0x%02x\n", pdev->irq);
7108d98f2e5SJia-Ju Bai #endif
7118d98f2e5SJia-Ju Bai 
7128d98f2e5SJia-Ju Bai 	return 0;
7138d98f2e5SJia-Ju Bai }
7148d98f2e5SJia-Ju Bai 
7158d98f2e5SJia-Ju Bai /* Intialize hardware */
dev_init_hw(NDR_driver * pdev,netdriver_addr_t * addr)716*f7df02e7SDavid van Moolenbroek static int dev_init_hw(NDR_driver *pdev, netdriver_addr_t *addr) {
7178d98f2e5SJia-Ju Bai 	int r, ret;
7188d98f2e5SJia-Ju Bai 
7198d98f2e5SJia-Ju Bai 	/* Set the OS interrupt handler */
7208d98f2e5SJia-Ju Bai 	pdev->hook = pdev->irq;
7218d98f2e5SJia-Ju Bai 	if ((r = sys_irqsetpolicy(pdev->irq, 0, &pdev->hook)) != OK) {
7223afdc120SJia-Ju Bai 		printf("NDR: Fail to set OS IRQ policy: %d\n", r);
7238d98f2e5SJia-Ju Bai 		ret = -EFAULT;
7248d98f2e5SJia-Ju Bai 		goto err_irq_policy;
7258d98f2e5SJia-Ju Bai 	}
7268d98f2e5SJia-Ju Bai 
7278d98f2e5SJia-Ju Bai 	/* Reset hardware */
7283afdc120SJia-Ju Bai 	if (dev_reset_hw(pdev)) {
7293afdc120SJia-Ju Bai 		printf("NDR: Fail to reset the device\n");
7308d98f2e5SJia-Ju Bai 		ret = -EIO;
7318d98f2e5SJia-Ju Bai 		goto err_reset_hw;
7328d98f2e5SJia-Ju Bai 	}
7338d98f2e5SJia-Ju Bai 
7348d98f2e5SJia-Ju Bai 	/* Enable OS IRQ */
7358d98f2e5SJia-Ju Bai 	if ((r = sys_irqenable(&pdev->hook)) != OK) {
7363afdc120SJia-Ju Bai 		printf("NDR: Fail to enable OS IRQ: %d\n", r);
7378d98f2e5SJia-Ju Bai 		ret = -EFAULT;
7388d98f2e5SJia-Ju Bai 		goto err_irq_enable;
7398d98f2e5SJia-Ju Bai 	}
7408d98f2e5SJia-Ju Bai 
7418d98f2e5SJia-Ju Bai 	/* Configure MAC address */
7423afdc120SJia-Ju Bai 	dev_conf_addr(pdev, addr);
7438d98f2e5SJia-Ju Bai 
7448d98f2e5SJia-Ju Bai 	/* Detect link status */
7453afdc120SJia-Ju Bai 	/* ### CHECK_LINK ### */
7463afdc120SJia-Ju Bai 	pdev->link = dev_check_link(pdev->base);
7478d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
7488d98f2e5SJia-Ju Bai 	if (pdev->link)
7493afdc120SJia-Ju Bai 		printf("NDR: Link up\n");
7508d98f2e5SJia-Ju Bai 	else
7513afdc120SJia-Ju Bai 		printf("NDR: Link down\n");
7528d98f2e5SJia-Ju Bai #endif
7538d98f2e5SJia-Ju Bai 
7548d98f2e5SJia-Ju Bai 	return 0;
7558d98f2e5SJia-Ju Bai 
7568d98f2e5SJia-Ju Bai err_reset_hw:
7578d98f2e5SJia-Ju Bai err_irq_enable:
7588d98f2e5SJia-Ju Bai err_irq_policy:
7598d98f2e5SJia-Ju Bai 	return ret;
7608d98f2e5SJia-Ju Bai }
7618d98f2e5SJia-Ju Bai 
7628d98f2e5SJia-Ju Bai /* Reset hardware */
dev_reset_hw(NDR_driver * pdev)7633afdc120SJia-Ju Bai static int dev_reset_hw(NDR_driver *pdev) {
7648d98f2e5SJia-Ju Bai 	int ret;
7658d98f2e5SJia-Ju Bai 
7668d98f2e5SJia-Ju Bai 	/* Reset the chip */
7678d98f2e5SJia-Ju Bai 	/* ### RESET_HARDWARE_CAN_FAIL ### */
7683afdc120SJia-Ju Bai 	if (dev_real_reset(pdev->base)) {
7693afdc120SJia-Ju Bai 		printf("NDR: Fail to reset the hardware\n");
7708d98f2e5SJia-Ju Bai 		ret = -EIO;
7718d98f2e5SJia-Ju Bai 		goto err_real_reset;
7728d98f2e5SJia-Ju Bai 	}
7738d98f2e5SJia-Ju Bai 
7743afdc120SJia-Ju Bai 	/* Initialize other hardware I/O registers */
7758d98f2e5SJia-Ju Bai 	/* ### SET_RX_DESC_REG ### */
7763afdc120SJia-Ju Bai 	if (dev_init_io(pdev->base)) {
7773afdc120SJia-Ju Bai 		printf("NDR: Fail to initialize I/O registers\n");
7788d98f2e5SJia-Ju Bai 		ret = -EIO;
7798d98f2e5SJia-Ju Bai 		goto err_init_io;
7808d98f2e5SJia-Ju Bai 	}
7818d98f2e5SJia-Ju Bai 
7823afdc120SJia-Ju Bai 	/* Initialize MII interface */
7833afdc120SJia-Ju Bai 	/* ### MII_INIT_CAN_FAIL ### */
7843afdc120SJia-Ju Bai 	if (dev_init_mii(pdev->base)) {
7853afdc120SJia-Ju Bai 		printf("NDR: Fail to initialize MII interface\n");
7863afdc120SJia-Ju Bai 		ret = -EIO;
7873afdc120SJia-Ju Bai 		goto err_init_mii;
7883afdc120SJia-Ju Bai 	}
7898d98f2e5SJia-Ju Bai 
7908d98f2e5SJia-Ju Bai 	return 0;
7918d98f2e5SJia-Ju Bai 
7928d98f2e5SJia-Ju Bai err_init_mii:
7933afdc120SJia-Ju Bai err_init_io:
7948d98f2e5SJia-Ju Bai err_real_reset:
7958d98f2e5SJia-Ju Bai 	return ret;
7968d98f2e5SJia-Ju Bai }
7978d98f2e5SJia-Ju Bai 
7988d98f2e5SJia-Ju Bai /* Configure MAC address */
dev_conf_addr(NDR_driver * pdev,netdriver_addr_t * addr)799*f7df02e7SDavid van Moolenbroek static void dev_conf_addr(NDR_driver *pdev, netdriver_addr_t *addr) {
8008d98f2e5SJia-Ju Bai 	u8_t pa[6];
8018d98f2e5SJia-Ju Bai 
8028d98f2e5SJia-Ju Bai 	/* Get MAC address */
8038d98f2e5SJia-Ju Bai 	/* ### GET_MAC_ADDR ### */
8043afdc120SJia-Ju Bai 	dev_get_addr(pdev->base, pa);
805*f7df02e7SDavid van Moolenbroek 	addr->na_addr[0] = pa[0];
806*f7df02e7SDavid van Moolenbroek 	addr->na_addr[1] = pa[1];
807*f7df02e7SDavid van Moolenbroek 	addr->na_addr[2] = pa[2];
808*f7df02e7SDavid van Moolenbroek 	addr->na_addr[3] = pa[3];
809*f7df02e7SDavid van Moolenbroek 	addr->na_addr[4] = pa[4];
810*f7df02e7SDavid van Moolenbroek 	addr->na_addr[5] = pa[5];
8118d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
8123afdc120SJia-Ju Bai 	printf("NDR: Ethernet address is %02x:%02x:%02x:%02x:%02x:%02x\n",
813*f7df02e7SDavid van Moolenbroek 			addr->na_addr[0], addr->na_addr[1], addr->na_addr[2],
814*f7df02e7SDavid van Moolenbroek 			addr->na_addr[3], addr->na_addr[4], addr->na_addr[5]);
8158d98f2e5SJia-Ju Bai #endif
8168d98f2e5SJia-Ju Bai }
8178d98f2e5SJia-Ju Bai 
8183afdc120SJia-Ju Bai /* Allocate and initialize buffer */
dev_init_buf(NDR_driver * pdev)8193afdc120SJia-Ju Bai static int dev_init_buf(NDR_driver *pdev) {
8203afdc120SJia-Ju Bai 	size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size;
8213afdc120SJia-Ju Bai 	phys_bytes buf_dma;
8223afdc120SJia-Ju Bai 	char *buf;
8233afdc120SJia-Ju Bai 	int i;
8248d98f2e5SJia-Ju Bai 
8253afdc120SJia-Ju Bai 	/* Build Rx and Tx buffer */
8263afdc120SJia-Ju Bai 	tx_buf_size = TX_BUF_SIZE;
8273afdc120SJia-Ju Bai 	if (tx_buf_size % 4)
8283afdc120SJia-Ju Bai 		tx_buf_size += 4 - (tx_buf_size % 4);
8293afdc120SJia-Ju Bai 	rx_buf_size = RX_BUF_SIZE;
8303afdc120SJia-Ju Bai 	if (rx_buf_size % 4)
8313afdc120SJia-Ju Bai 		rx_buf_size += 4 - (rx_buf_size % 4);
8323afdc120SJia-Ju Bai 	tot_buf_size = TX_BUFFER_NUM * tx_buf_size + RX_BUFFER_NUM * rx_buf_size;
8333afdc120SJia-Ju Bai 	rx_desc_size = RX_BUFFER_NUM * sizeof(NDR_desc);
8343afdc120SJia-Ju Bai 	tx_desc_size = TX_BUFFER_NUM * sizeof(NDR_desc);
8353afdc120SJia-Ju Bai 	tot_buf_size += rx_desc_size + tx_desc_size;
8363afdc120SJia-Ju Bai 	if (tot_buf_size % 4096)
8373afdc120SJia-Ju Bai 		tot_buf_size += 4096 - (tot_buf_size % 4096);
8388d98f2e5SJia-Ju Bai 
8393afdc120SJia-Ju Bai 	if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) {
8403afdc120SJia-Ju Bai 		printf("NDR: Fail to allocate memory\n");
8413afdc120SJia-Ju Bai 		return -ENOMEM;
8423afdc120SJia-Ju Bai 	}
8433afdc120SJia-Ju Bai 	pdev->buf_size = tot_buf_size;
8443afdc120SJia-Ju Bai 	pdev->buf = buf;
8458d98f2e5SJia-Ju Bai 
8463afdc120SJia-Ju Bai 	/* Rx descriptor buffer location */
8473afdc120SJia-Ju Bai 	pdev->rx_desc = (NDR_desc *)buf;
8483afdc120SJia-Ju Bai 	pdev->rx_desc_dma = buf_dma;
8493afdc120SJia-Ju Bai 	memset(buf, 0, rx_desc_size);
8503afdc120SJia-Ju Bai 	buf += rx_desc_size;
8513afdc120SJia-Ju Bai 	buf_dma += rx_desc_size;
8523afdc120SJia-Ju Bai 
8533afdc120SJia-Ju Bai 	/* Tx descriptor buffer location */
8543afdc120SJia-Ju Bai 	pdev->tx_desc = (NDR_desc *)buf;
8553afdc120SJia-Ju Bai 	pdev->tx_desc_dma = buf_dma;
8563afdc120SJia-Ju Bai 	memset(buf, 0, tx_desc_size);
8573afdc120SJia-Ju Bai 	buf += tx_desc_size;
8583afdc120SJia-Ju Bai 	buf_dma += tx_desc_size;
8593afdc120SJia-Ju Bai 
8603afdc120SJia-Ju Bai 	/* Rx buffer assignment */
8613afdc120SJia-Ju Bai 	for (i = 0; i < RX_BUFFER_NUM; i++) {
8623afdc120SJia-Ju Bai 		/* Initialize Rx buffer */
8633afdc120SJia-Ju Bai 		pdev->rx[i].buf_dma = buf_dma;
8643afdc120SJia-Ju Bai 		pdev->rx[i].buf = buf;
8653afdc120SJia-Ju Bai 		buf_dma += rx_buf_size;
8663afdc120SJia-Ju Bai 		buf += rx_buf_size;
8673afdc120SJia-Ju Bai 		/* Set Rx descriptor */
8683afdc120SJia-Ju Bai 		/* ### INIT_RX_DESC ### */
8693afdc120SJia-Ju Bai 		dev_init_rx_desc(pdev->rx_desc, i, rx_buf_size, pdev->rx[i].buf_dma,
8703afdc120SJia-Ju Bai 							RX_BUFFER_NUM, pdev->rx_desc_dma);
8718d98f2e5SJia-Ju Bai 	}
8728d98f2e5SJia-Ju Bai 
8733afdc120SJia-Ju Bai 	/* Tx buffer assignment */
8743afdc120SJia-Ju Bai 	for (i = 0; i < TX_BUFFER_NUM; i++) {
8753afdc120SJia-Ju Bai 		/* Set Tx buffer */
8763afdc120SJia-Ju Bai 		pdev->tx[i].busy = 0;
8773afdc120SJia-Ju Bai 		pdev->tx[i].buf_dma = buf_dma;
8783afdc120SJia-Ju Bai 		pdev->tx[i].buf = buf;
8793afdc120SJia-Ju Bai 		buf_dma += tx_buf_size;
8803afdc120SJia-Ju Bai 		buf += tx_buf_size;
8813afdc120SJia-Ju Bai 		/* Initialize Tx descriptor */
8823afdc120SJia-Ju Bai 		/* ### INIT_TX_DESC ### */
8833afdc120SJia-Ju Bai 		dev_init_tx_desc(pdev->tx_desc, i, tx_buf_size, pdev->tx[i].buf_dma,
8843afdc120SJia-Ju Bai 							TX_BUFFER_NUM, pdev->tx_desc_dma);
8858d98f2e5SJia-Ju Bai 	}
8868d98f2e5SJia-Ju Bai 
8873afdc120SJia-Ju Bai 	/* Set Rx/Tx descriptor address into device register */
8883afdc120SJia-Ju Bai 	/* ### SET_DESC_REG ### */
8893afdc120SJia-Ju Bai 	dev_set_desc_reg(pdev->base, g_driver.rx_desc_dma,
8903afdc120SJia-Ju Bai 						g_driver.tx_desc_dma);
8918d98f2e5SJia-Ju Bai 
8923afdc120SJia-Ju Bai 	pdev->tx_busy_num = 0;
8933afdc120SJia-Ju Bai 	pdev->tx_head = 0;
8943afdc120SJia-Ju Bai 	pdev->tx_tail = 0;
8953afdc120SJia-Ju Bai 	pdev->rx_head = 0;
8968d98f2e5SJia-Ju Bai 
8978d98f2e5SJia-Ju Bai 	return 0;
8988d98f2e5SJia-Ju Bai }
8998d98f2e5SJia-Ju Bai 
9008d98f2e5SJia-Ju Bai /* Real handler interrupt */
dev_handler(NDR_driver * pdev)9013afdc120SJia-Ju Bai static void dev_handler(NDR_driver *pdev) {
9023afdc120SJia-Ju Bai 	u32_t intr_status;
9033afdc120SJia-Ju Bai 	int tx_head, tx_tail, index, flag = 0, ret;
9043afdc120SJia-Ju Bai 	NDR_desc *desc;
9058d98f2e5SJia-Ju Bai 
9063afdc120SJia-Ju Bai 	/* Read and clear interrupt status */
9073afdc120SJia-Ju Bai 	/* ### READ_CLEAR_INTR_STS ### */
9083afdc120SJia-Ju Bai 	intr_status = dev_read_clear_intr_status(pdev->base);
9098d98f2e5SJia-Ju Bai 
9108d98f2e5SJia-Ju Bai 	/* Enable interrupt */
9113afdc120SJia-Ju Bai 	/* ### INTR_ENABLE_DISABLE ### */
9123afdc120SJia-Ju Bai 	dev_intr_control(pdev->base, INTR_ENABLE);
9138d98f2e5SJia-Ju Bai 
9148d98f2e5SJia-Ju Bai 	/* Check link status */
9153afdc120SJia-Ju Bai 	if (intr_status & INTR_STS_LINK) {
9163afdc120SJia-Ju Bai 		pdev->link = dev_check_link(pdev->base);
9178d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
9183afdc120SJia-Ju Bai 		printf("NDR: Link state change\n");
9198d98f2e5SJia-Ju Bai #endif
9208d98f2e5SJia-Ju Bai 		flag++;
9218d98f2e5SJia-Ju Bai 	}
9228d98f2e5SJia-Ju Bai 	/* Check Rx request status */
9233afdc120SJia-Ju Bai 	if (intr_status & INTR_STS_RX) {
9248d98f2e5SJia-Ju Bai 		pdev->recv_flag = TRUE;
9258d98f2e5SJia-Ju Bai 		flag++;
9268d98f2e5SJia-Ju Bai 	}
9278d98f2e5SJia-Ju Bai 	/* Check Tx request status */
9283afdc120SJia-Ju Bai 	if (intr_status & INTR_STS_TX) {
9298d98f2e5SJia-Ju Bai 		pdev->send_flag = TRUE;
9308d98f2e5SJia-Ju Bai 		flag++;
9318d98f2e5SJia-Ju Bai 
9328d98f2e5SJia-Ju Bai 		/* Manage Tx Buffer */
9338d98f2e5SJia-Ju Bai 		tx_head = pdev->tx_head;
9348d98f2e5SJia-Ju Bai 		tx_tail = pdev->tx_tail;
9358d98f2e5SJia-Ju Bai 		while (tx_tail != tx_head) {
9363afdc120SJia-Ju Bai 			if (!pdev->tx[tx_tail].busy)
9373afdc120SJia-Ju Bai 				printf("NDR: Strange, buffer not busy?\n");
9383afdc120SJia-Ju Bai 			index = tx_tail;
9398d98f2e5SJia-Ju Bai 			desc = pdev->tx_desc;
9408d98f2e5SJia-Ju Bai 			desc += tx_tail;
9413afdc120SJia-Ju Bai 			/* Check whether Tx is OK from Tx descriptor */
9423afdc120SJia-Ju Bai 			/* ### CHECK_TX_OK_FROM_DESC ### */
9433afdc120SJia-Ju Bai 			ret = dev_tx_ok_desc(pdev->base, desc, index);
9443afdc120SJia-Ju Bai 			if (ret == TX_SUSPEND)
9458d98f2e5SJia-Ju Bai 				break;
9463afdc120SJia-Ju Bai 			else if (ret == TX_ERROR)
9473afdc120SJia-Ju Bai 				printf("NDR: Tx error now\n");
9488d98f2e5SJia-Ju Bai 
9498d98f2e5SJia-Ju Bai 			pdev->tx[tx_tail].busy = FALSE;
9508d98f2e5SJia-Ju Bai 			pdev->tx_busy_num--;
9518d98f2e5SJia-Ju Bai 
9523afdc120SJia-Ju Bai 			if (++tx_tail >= TX_BUFFER_NUM)
9538d98f2e5SJia-Ju Bai 				tx_tail = 0;
9548d98f2e5SJia-Ju Bai 
9558d98f2e5SJia-Ju Bai 			pdev->send_flag = TRUE;
9568d98f2e5SJia-Ju Bai 			pdev->recv_flag = TRUE;
9578d98f2e5SJia-Ju Bai 
9583afdc120SJia-Ju Bai 			/* Set Tx descriptor after Tx done */
9593afdc120SJia-Ju Bai 			/* ### SET_TX_DESC_DONE ### */
9603afdc120SJia-Ju Bai 			dev_set_tx_desc_done(pdev->base, desc, index);
9618d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
9623afdc120SJia-Ju Bai 			printf("NDR: Successfully send a packet\n");
9638d98f2e5SJia-Ju Bai #endif
9648d98f2e5SJia-Ju Bai 		}
9658d98f2e5SJia-Ju Bai 		pdev->tx_tail = tx_tail;
9668d98f2e5SJia-Ju Bai 	}
9678d98f2e5SJia-Ju Bai #ifdef MY_DEBUG
9688d98f2e5SJia-Ju Bai 	if (!flag) {
9693afdc120SJia-Ju Bai 		printf("NDR: Unknown error in interrupt 0x%08x\n", intr_status);
9708d98f2e5SJia-Ju Bai 		return;
9718d98f2e5SJia-Ju Bai 	}
9728d98f2e5SJia-Ju Bai #endif
9738d98f2e5SJia-Ju Bai }
9748d98f2e5SJia-Ju Bai 
9758d98f2e5SJia-Ju Bai /* Check interrupt and perform */
dev_check_ints(NDR_driver * pdev)9763afdc120SJia-Ju Bai static void dev_check_ints(NDR_driver *pdev) {
9778d98f2e5SJia-Ju Bai 	if (!pdev->recv_flag)
9788d98f2e5SJia-Ju Bai 		return;
9798d98f2e5SJia-Ju Bai 	pdev->recv_flag = FALSE;
9808d98f2e5SJia-Ju Bai 
9818d98f2e5SJia-Ju Bai 	/* Handle data receive */
9828d98f2e5SJia-Ju Bai 	netdriver_recv();
9838d98f2e5SJia-Ju Bai 
9848d98f2e5SJia-Ju Bai 	/* Handle data transmit */
9858d98f2e5SJia-Ju Bai 	if (pdev->send_flag) {
9868d98f2e5SJia-Ju Bai 		pdev->send_flag = FALSE;
9878d98f2e5SJia-Ju Bai 		netdriver_send();
9888d98f2e5SJia-Ju Bai 	}
9898d98f2e5SJia-Ju Bai }
990