18dc24c06SJia-Ju Bai #include <minix/drivers.h>
28dc24c06SJia-Ju Bai #include <minix/netdriver.h>
38dc24c06SJia-Ju Bai #include <machine/pci.h>
4c28d8fefSJia-Ju Bai #include <sys/mman.h>
5022136b3SJia-Ju Bai #include "vt6105.h"
68dc24c06SJia-Ju Bai #include "io.h"
7022136b3SJia-Ju Bai
8022136b3SJia-Ju Bai /* global value */
9c28d8fefSJia-Ju Bai static NDR_driver g_driver;
10022136b3SJia-Ju Bai static int g_instance;
11022136b3SJia-Ju Bai
12022136b3SJia-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);
15c28d8fefSJia-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);
18c28d8fefSJia-Ju Bai static ssize_t NDR_recv(struct netdriver_data *data, size_t max);
19c28d8fefSJia-Ju Bai static int NDR_send(struct netdriver_data *data, size_t size);
20c28d8fefSJia-Ju Bai static void NDR_intr(unsigned int mask);
21022136b3SJia-Ju Bai
228dc24c06SJia-Ju Bai /* internal function */
23c28d8fefSJia-Ju Bai static int dev_probe(NDR_driver *pdev, int instance);
24c28d8fefSJia-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);
26c28d8fefSJia-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);
28c28d8fefSJia-Ju Bai static void dev_handler(NDR_driver *pdev);
29c28d8fefSJia-Ju Bai static void dev_check_ints(NDR_driver *pdev);
30022136b3SJia-Ju Bai
318dc24c06SJia-Ju Bai /* developer interface */
32c28d8fefSJia-Ju Bai static int dev_real_reset(u32_t *base);
33c28d8fefSJia-Ju Bai static int dev_init_io(u32_t *base);
34c28d8fefSJia-Ju Bai static int dev_init_mii(u32_t *base);
35c28d8fefSJia-Ju Bai static void dev_intr_control(u32_t *base, int flag);
36c28d8fefSJia-Ju Bai static void dev_rx_tx_control(u32_t *base, int flag);
37c28d8fefSJia-Ju Bai static void dev_get_addr(u32_t *base, u8_t *pa);
38c28d8fefSJia-Ju Bai static int dev_check_link(u32_t *base);
39c28d8fefSJia-Ju Bai static void dev_set_rec_mode(u32_t *base, int mode);
40c28d8fefSJia-Ju Bai static void dev_start_tx(u32_t *base);
41c28d8fefSJia-Ju Bai static u32_t dev_read_clear_intr_status(u32_t *base);
42c28d8fefSJia-Ju Bai static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size,
43c28d8fefSJia-Ju Bai phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start);
44c28d8fefSJia-Ju Bai static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size,
45c28d8fefSJia-Ju Bai phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start);
46c28d8fefSJia-Ju Bai static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr,
47c28d8fefSJia-Ju Bai phys_bytes tx_addr);
48c28d8fefSJia-Ju Bai static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index);
49c28d8fefSJia-Ju Bai static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index);
50c28d8fefSJia-Ju Bai static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index);
51c28d8fefSJia-Ju Bai static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index,
52c28d8fefSJia-Ju Bai size_t data_size);
53c28d8fefSJia-Ju Bai static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index);
54c28d8fefSJia-Ju Bai static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index);
558dc24c06SJia-Ju Bai
56c28d8fefSJia-Ju Bai /* ======= Developer implemented function ======= */
57c28d8fefSJia-Ju Bai /* ====== Self-defined function ======*/
588dc24c06SJia-Ju Bai
59c28d8fefSJia-Ju Bai /* ====== Developer interface ======*/
608dc24c06SJia-Ju Bai /* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###)
618dc24c06SJia-Ju Bai * -- Return OK means success, Others means failure */
dev_real_reset(u32_t * base)62c28d8fefSJia-Ju Bai static int dev_real_reset(u32_t *base) {
63c28d8fefSJia-Ju Bai u32_t base0 = base[0];
64c28d8fefSJia-Ju Bai ndr_out16(base0, REG_CR, CMD_RESET);
65c28d8fefSJia-Ju Bai micro_delay(5000);
66c28d8fefSJia-Ju Bai if (ndr_in16(base0, REG_CR) & CMD_RESET) {
67c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MCR, 0x40);
68c28d8fefSJia-Ju Bai micro_delay(5000);
69c28d8fefSJia-Ju Bai if (ndr_in16(base0, REG_CR) & CMD_RESET)
708dc24c06SJia-Ju Bai return -EIO;
718dc24c06SJia-Ju Bai }
728dc24c06SJia-Ju Bai return OK;
738dc24c06SJia-Ju Bai }
748dc24c06SJia-Ju Bai
75c28d8fefSJia-Ju Bai /* Intialize other hardware I/O registers (### INIT_HARDWARE_IO_CAN_FAIL ###)
768dc24c06SJia-Ju Bai * -- Return OK means success, Others means failure */
dev_init_io(u32_t * base)77c28d8fefSJia-Ju Bai static int dev_init_io(u32_t *base) {
78c28d8fefSJia-Ju Bai u32_t base0 = base[0];
798dc24c06SJia-Ju Bai u8_t stick;
80c28d8fefSJia-Ju Bai stick = ndr_in8(base0, REG_STICK);
81c28d8fefSJia-Ju Bai ndr_out8(base0, REG_STICK, stick & 0xfc);
82c28d8fefSJia-Ju Bai ndr_out16(base0, REG_BCR, 0x0006);
83c28d8fefSJia-Ju Bai ndr_out8(base0, REG_TCR, 0x20);
84c28d8fefSJia-Ju Bai ndr_out8(base0, REG_RCR, 0x78);
858dc24c06SJia-Ju Bai return OK;
868dc24c06SJia-Ju Bai }
878dc24c06SJia-Ju Bai
888dc24c06SJia-Ju Bai /* Intialize MII interface (### MII_INIT_CAN_FAIL ###)
89c28d8fefSJia-Ju Bai -- Return OK means success, Others means failure */
dev_init_mii(u32_t * base)90c28d8fefSJia-Ju Bai static int dev_init_mii(u32_t *base) {
91c28d8fefSJia-Ju Bai u32_t base0 = base[0];
92c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_CR, 0);
93c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_REG, 0x01);
94c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_CR, 0x80);
95c28d8fefSJia-Ju Bai micro_delay(5000);
96c28d8fefSJia-Ju Bai if (!(ndr_in8(base0, REG_MII_REG) & 0x20)) {
97c28d8fefSJia-Ju Bai printf("NDR: Fail to monitor linkage\n");
98c28d8fefSJia-Ju Bai return -EIO;
99c28d8fefSJia-Ju Bai }
100c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_REG, 0x41);
1018dc24c06SJia-Ju Bai return OK;
1028dc24c06SJia-Ju Bai }
1038dc24c06SJia-Ju Bai
104c28d8fefSJia-Ju Bai /* Enable or disable interrupt (### INTR_ENABLE_DISABLE ###) */
dev_intr_control(u32_t * base,int flag)105c28d8fefSJia-Ju Bai static void dev_intr_control(u32_t *base, int flag) {
106c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
107c28d8fefSJia-Ju Bai data = ndr_in16(base0, REG_IMR);
108c28d8fefSJia-Ju Bai if (flag == INTR_ENABLE)
109c28d8fefSJia-Ju Bai ndr_out16(base0, REG_IMR, data | CMD_INTR_ENABLE);
110c28d8fefSJia-Ju Bai else if (flag == INTR_DISABLE)
111c28d8fefSJia-Ju Bai ndr_out16(base0, REG_IMR, data & ~CMD_INTR_ENABLE);
1128dc24c06SJia-Ju Bai }
1138dc24c06SJia-Ju Bai
114c28d8fefSJia-Ju Bai /* Enable or disable Rx/Tx (### RX_TX_ENABLE_DISABLE ###) */
dev_rx_tx_control(u32_t * base,int flag)115c28d8fefSJia-Ju Bai static void dev_rx_tx_control(u32_t *base, int flag) {
116c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
117c28d8fefSJia-Ju Bai if (flag == RX_TX_ENABLE) {
118c28d8fefSJia-Ju Bai data = CMD_START | CMD_RX_ON | CMD_TX_ON | CMD_NO_POLL | CMD_FDUPLEX;
119c28d8fefSJia-Ju Bai ndr_out16(base0, REG_CR, data);
120c28d8fefSJia-Ju Bai }
121c28d8fefSJia-Ju Bai else if (flag == RX_TX_DISABLE) {
122c28d8fefSJia-Ju Bai ndr_out16(base0, REG_CR, CMD_STOP);
123c28d8fefSJia-Ju Bai }
1248dc24c06SJia-Ju Bai }
1258dc24c06SJia-Ju Bai
1268dc24c06SJia-Ju Bai /* Get MAC address to the array 'pa' (### GET_MAC_ADDR ###) */
dev_get_addr(u32_t * base,u8_t * pa)127c28d8fefSJia-Ju Bai static void dev_get_addr(u32_t *base, u8_t *pa) {
128c28d8fefSJia-Ju Bai u32_t i, base0 = base[0];
1298dc24c06SJia-Ju Bai for (i = 0; i < 6; i++)
130c28d8fefSJia-Ju Bai pa[i] = ndr_in8(base0, REG_ADDR + i);
1318dc24c06SJia-Ju Bai }
1328dc24c06SJia-Ju Bai
1338dc24c06SJia-Ju Bai /* Check link status (### CHECK_LINK ###)
1348dc24c06SJia-Ju Bai * -- Return LINK_UP or LINK_DOWN */
dev_check_link(u32_t * base)135c28d8fefSJia-Ju Bai static int dev_check_link(u32_t *base) {
136c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
137c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_PHY, 0x01);
138c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_REG, 0x01);
139c28d8fefSJia-Ju Bai ndr_out8(base0, REG_MII_CR, 0x40);
140c28d8fefSJia-Ju Bai micro_delay(5000);
141c28d8fefSJia-Ju Bai if (ndr_in8(base0, REG_MII_CR) & 0x40)
142c28d8fefSJia-Ju Bai printf("NDR: Fail to get linkage\n");
143c28d8fefSJia-Ju Bai data = ndr_in16(base0, REG_MII_DATA);
144c28d8fefSJia-Ju Bai if (data & LINK_STATUS)
1458dc24c06SJia-Ju Bai return LINK_UP;
1468dc24c06SJia-Ju Bai return LINK_DOWN;
1478dc24c06SJia-Ju Bai }
1488dc24c06SJia-Ju Bai
149c28d8fefSJia-Ju Bai /* Set driver receive mode (### SET_REC_MODE ###) */
dev_set_rec_mode(u32_t * base,int mode)150c28d8fefSJia-Ju Bai static void dev_set_rec_mode(u32_t *base, int mode) {
151c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
152c28d8fefSJia-Ju Bai data = ndr_in8(base0, REG_RCR);
153c28d8fefSJia-Ju Bai data &= ~(CMD_RCR_UNICAST | CMD_RCR_MULTICAST | CMD_RCR_BROADCAST);
154*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_PROMISC)
155c28d8fefSJia-Ju Bai data |= CMD_RCR_UNICAST | CMD_RCR_BROADCAST | CMD_RCR_MULTICAST;
156*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_BCAST)
157c28d8fefSJia-Ju Bai data |= CMD_RCR_BROADCAST;
158*f7df02e7SDavid van Moolenbroek if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
159c28d8fefSJia-Ju Bai data |= CMD_RCR_MULTICAST;
160c28d8fefSJia-Ju Bai data |= CMD_RCR_UNICAST;
161c28d8fefSJia-Ju Bai ndr_out8(base0, REG_RCR, data);
1628dc24c06SJia-Ju Bai }
1638dc24c06SJia-Ju Bai
164c28d8fefSJia-Ju Bai /* Start Tx channel (### START_TX_CHANNEL ###) */
dev_start_tx(u32_t * base)165c28d8fefSJia-Ju Bai static void dev_start_tx(u32_t *base) {
166c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
167c28d8fefSJia-Ju Bai data = ndr_in8(base0, REG_CR);
168c28d8fefSJia-Ju Bai ndr_out8(base0, REG_CR, data | CMD_TX_DEMAND);
169c28d8fefSJia-Ju Bai }
170c28d8fefSJia-Ju Bai
171c28d8fefSJia-Ju Bai /* Read and clear interrupt (### READ_CLEAR_INTR_STS ###) */
dev_read_clear_intr_status(u32_t * base)172c28d8fefSJia-Ju Bai static u32_t dev_read_clear_intr_status(u32_t *base) {
173c28d8fefSJia-Ju Bai u32_t data, base0 = base[0];
174c28d8fefSJia-Ju Bai data = ndr_in16(base0, REG_ISR);
175c28d8fefSJia-Ju Bai ndr_out16(base0, REG_ISR, data & INTR_STS_CLEAR);
176c28d8fefSJia-Ju Bai return data;
177c28d8fefSJia-Ju Bai }
178c28d8fefSJia-Ju Bai
179c28d8fefSJia-Ju Bai /* ---------- WITH DESCRIPTOR ---------- */
180c28d8fefSJia-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)181c28d8fefSJia-Ju Bai static void dev_init_rx_desc(NDR_desc *desc_start, int index, size_t buf_size,
182c28d8fefSJia-Ju Bai phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) {
183c28d8fefSJia-Ju Bai NDR_desc *desc = desc_start + index;
184c28d8fefSJia-Ju Bai desc->status = DESC_OWN | ((buf_size << 16) & DESC_RX_LENMASK);
185c28d8fefSJia-Ju Bai desc->addr = buf_dma;
186c28d8fefSJia-Ju Bai desc->length = buf_size;
187c28d8fefSJia-Ju Bai if (index == max_desc_num - 1)
188c28d8fefSJia-Ju Bai desc->next = desc_dma_start;
189c28d8fefSJia-Ju Bai else
190c28d8fefSJia-Ju Bai desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc);
191c28d8fefSJia-Ju Bai }
192c28d8fefSJia-Ju Bai
193c28d8fefSJia-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)194c28d8fefSJia-Ju Bai static void dev_init_tx_desc(NDR_desc *desc_start, int index, size_t buf_size,
195c28d8fefSJia-Ju Bai phys_bytes buf_dma, int max_desc_num, phys_bytes desc_dma_start) {
196c28d8fefSJia-Ju Bai NDR_desc *desc = desc_start + index;
197c28d8fefSJia-Ju Bai desc->addr = buf_dma;
198c28d8fefSJia-Ju Bai desc->length = buf_size;
199c28d8fefSJia-Ju Bai if (index == max_desc_num - 1)
200c28d8fefSJia-Ju Bai desc->next = desc_dma_start;
201c28d8fefSJia-Ju Bai else
202c28d8fefSJia-Ju Bai desc->next = desc_dma_start + (index + 1) * sizeof(NDR_desc);
203c28d8fefSJia-Ju Bai }
204c28d8fefSJia-Ju Bai
205c28d8fefSJia-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)206c28d8fefSJia-Ju Bai static void dev_set_desc_reg(u32_t *base, phys_bytes rx_addr,
207c28d8fefSJia-Ju Bai phys_bytes tx_addr) {
208c28d8fefSJia-Ju Bai u32_t base0 = base[0];
209c28d8fefSJia-Ju Bai ndr_out32(base0, REG_RX_DESC_BASE, rx_addr);
210c28d8fefSJia-Ju Bai ndr_out32(base0, REG_TX_DESC_BASE, tx_addr);
211c28d8fefSJia-Ju Bai }
212c28d8fefSJia-Ju Bai
213c28d8fefSJia-Ju Bai /* Check whether Rx is OK from Rx descriptor (### CHECK_RX_OK_FROM_DESC ###)
214c28d8fefSJia-Ju Bai * -- Current buffer number is index
215c28d8fefSJia-Ju Bai * -- Return RX_OK or RX_SUSPEND or RX_ERROR */
dev_rx_ok_desc(u32_t * base,NDR_desc * desc,int index)216c28d8fefSJia-Ju Bai static int dev_rx_ok_desc(u32_t *base, NDR_desc *desc, int index) {
2178dc24c06SJia-Ju Bai if (!(desc->status & DESC_OWN)) {
218c28d8fefSJia-Ju Bai if (desc->status & DESC_RX_ERROR)
219c28d8fefSJia-Ju Bai return RX_ERROR;
2208dc24c06SJia-Ju Bai if ((desc->status & DESC_RX_NORMAL) == DESC_RX_NORMAL)
221c28d8fefSJia-Ju Bai return RX_OK;
2228dc24c06SJia-Ju Bai }
223c28d8fefSJia-Ju Bai return RX_SUSPEND;
2248dc24c06SJia-Ju Bai }
2258dc24c06SJia-Ju Bai
226c28d8fefSJia-Ju Bai /* Get length from Rx descriptor (### GET_RX_LENGTH_FROM_DESC ###)
227c28d8fefSJia-Ju Bai * -- Current buffer number is index
228c28d8fefSJia-Ju Bai * -- Return the length */
dev_rx_len_desc(u32_t * base,NDR_desc * desc,int index)229c28d8fefSJia-Ju Bai static int dev_rx_len_desc(u32_t *base, NDR_desc *desc, int index) {
230*f7df02e7SDavid van Moolenbroek return ((desc->status & DESC_RX_LENMASK) >> 16) - NDEV_ETH_PACKET_CRC;
2318dc24c06SJia-Ju Bai }
2328dc24c06SJia-Ju Bai
233c28d8fefSJia-Ju Bai /* Set Rx descriptor after Rx done (### SET_RX_DESC_DONE ###)
234c28d8fefSJia-Ju Bai * -- Current buffer number is index */
dev_set_rx_desc_done(u32_t * base,NDR_desc * desc,int index)235c28d8fefSJia-Ju Bai static void dev_set_rx_desc_done(u32_t *base, NDR_desc *desc, int index) {
236c28d8fefSJia-Ju Bai desc->status = DESC_OWN;
237c28d8fefSJia-Ju Bai }
238c28d8fefSJia-Ju Bai
239c28d8fefSJia-Ju Bai /* Set Tx descriptor to prepare transmitting (### SET_TX_DESC_PREPARE)
240c28d8fefSJia-Ju Bai * -- Current buffer number is index */
dev_set_tx_desc_prepare(u32_t * base,NDR_desc * desc,int index,size_t data_size)241c28d8fefSJia-Ju Bai static void dev_set_tx_desc_prepare(u32_t *base, NDR_desc *desc, int index,
242c28d8fefSJia-Ju Bai size_t data_size) {
2438dc24c06SJia-Ju Bai desc->status = DESC_OWN | DESC_FIRST | DESC_LAST;
244c28d8fefSJia-Ju Bai desc->length = 0x00e08000 | (data_size > 60 ? data_size : 60);
2458dc24c06SJia-Ju Bai }
2468dc24c06SJia-Ju Bai
247c28d8fefSJia-Ju Bai /* Check whether Tx is OK from Tx descriptor (### CHECK_TX_OK_FROM_DESC ###)
248c28d8fefSJia-Ju Bai * -- Current buffer number is index
249c28d8fefSJia-Ju Bai * -- Return TX_OK or TX_SUSPEND or TX_ERROR */
dev_tx_ok_desc(u32_t * base,NDR_desc * desc,int index)250c28d8fefSJia-Ju Bai static int dev_tx_ok_desc(u32_t *base, NDR_desc *desc, int index) {
251c28d8fefSJia-Ju Bai if (!(desc->status & DESC_OWN)) {
252c28d8fefSJia-Ju Bai if (desc->status & DESC_TX_ERROR)
253c28d8fefSJia-Ju Bai return TX_ERROR;
254c28d8fefSJia-Ju Bai return TX_OK;
255c28d8fefSJia-Ju Bai }
256c28d8fefSJia-Ju Bai return TX_SUSPEND;
2578dc24c06SJia-Ju Bai }
2588dc24c06SJia-Ju Bai
259c28d8fefSJia-Ju Bai /* Set Tx descriptor after Tx done (### SET_TX_DESC_DONE ###)
260c28d8fefSJia-Ju Bai * -- Current buffer number is index */
dev_set_tx_desc_done(u32_t * base,NDR_desc * desc,int index)261c28d8fefSJia-Ju Bai static void dev_set_tx_desc_done(u32_t *base, NDR_desc *desc, int index) {
262c28d8fefSJia-Ju Bai desc->status = 0;
2638dc24c06SJia-Ju Bai }
2648dc24c06SJia-Ju Bai
2658dc24c06SJia-Ju Bai /* Driver interface table */
266c28d8fefSJia-Ju Bai static const struct netdriver NDR_table = {
267*f7df02e7SDavid van Moolenbroek .ndr_name = "vr",
268c28d8fefSJia-Ju Bai .ndr_init = NDR_init,
269c28d8fefSJia-Ju Bai .ndr_stop = NDR_stop,
270*f7df02e7SDavid van Moolenbroek .ndr_set_mode = NDR_set_mode,
271c28d8fefSJia-Ju Bai .ndr_recv = NDR_recv,
272c28d8fefSJia-Ju Bai .ndr_send = NDR_send,
273c28d8fefSJia-Ju Bai .ndr_intr = NDR_intr,
274022136b3SJia-Ju Bai };
275022136b3SJia-Ju Bai
main(int argc,char * argv[])276022136b3SJia-Ju Bai int main(int argc, char *argv[]) {
277022136b3SJia-Ju Bai env_setargs(argc, argv);
278c28d8fefSJia-Ju Bai netdriver_task(&NDR_table);
279022136b3SJia-Ju Bai }
280022136b3SJia-Ju Bai
281022136b3SJia-Ju Bai /* Initialize the driver */
282*f7df02e7SDavid van Moolenbroek static int
NDR_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks __unused)283*f7df02e7SDavid van Moolenbroek NDR_init(unsigned int instance, netdriver_addr_t * addr, uint32_t * caps,
284*f7df02e7SDavid van Moolenbroek unsigned int * ticks __unused)
285*f7df02e7SDavid van Moolenbroek {
286c28d8fefSJia-Ju Bai int i, ret = 0;
287022136b3SJia-Ju Bai
288022136b3SJia-Ju Bai /* Intialize driver data structure */
289022136b3SJia-Ju Bai memset(&g_driver, 0, sizeof(g_driver));
2908dc24c06SJia-Ju Bai g_driver.link = LINK_UNKNOWN;
291022136b3SJia-Ju Bai g_instance = instance;
292022136b3SJia-Ju Bai
293022136b3SJia-Ju Bai /* Probe the device */
294c28d8fefSJia-Ju Bai if (dev_probe(&g_driver, instance)) {
295c28d8fefSJia-Ju Bai printf("NDR: Device is not found\n");
296022136b3SJia-Ju Bai ret = -ENODEV;
297022136b3SJia-Ju Bai goto err_probe;
298022136b3SJia-Ju Bai }
299022136b3SJia-Ju Bai
300c28d8fefSJia-Ju Bai /* Intialize hardware */
301c28d8fefSJia-Ju Bai if (dev_init_hw(&g_driver, addr)) {
302c28d8fefSJia-Ju Bai printf("NDR: Fail to initialize hardware\n");
303c28d8fefSJia-Ju Bai ret = -EIO;
304c28d8fefSJia-Ju Bai goto err_init_hw;
305c28d8fefSJia-Ju Bai }
306c28d8fefSJia-Ju Bai
307022136b3SJia-Ju Bai /* Allocate and initialize buffer */
308c28d8fefSJia-Ju Bai if (dev_init_buf(&g_driver)) {
309c28d8fefSJia-Ju Bai printf("NDR: Fail to initialize buffer\n");
310022136b3SJia-Ju Bai ret = -ENODEV;
311022136b3SJia-Ju Bai goto err_init_buf;
312022136b3SJia-Ju Bai }
313022136b3SJia-Ju Bai
314c28d8fefSJia-Ju Bai /* Enable interrupts */
315c28d8fefSJia-Ju Bai /* ### INTR_ENABLE_DISABLE ### */
316c28d8fefSJia-Ju Bai dev_intr_control(g_driver.base, INTR_ENABLE);
317c28d8fefSJia-Ju Bai
318c28d8fefSJia-Ju Bai /* Start Rx and Tx */
319c28d8fefSJia-Ju Bai /* ### RX_TX_ENABLE_DISABLE ### */
320c28d8fefSJia-Ju Bai dev_rx_tx_control(g_driver.base, RX_TX_ENABLE);
321022136b3SJia-Ju Bai
322022136b3SJia-Ju Bai /* Clear send and recv flag */
3238dc24c06SJia-Ju Bai g_driver.send_flag = FALSE;
3248dc24c06SJia-Ju Bai g_driver.recv_flag = FALSE;
325022136b3SJia-Ju Bai
326*f7df02e7SDavid van Moolenbroek *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
327*f7df02e7SDavid van Moolenbroek return OK;
328022136b3SJia-Ju Bai
329022136b3SJia-Ju Bai err_init_buf:
330c28d8fefSJia-Ju Bai err_init_hw:
331022136b3SJia-Ju Bai err_probe:
332022136b3SJia-Ju Bai return ret;
333022136b3SJia-Ju Bai }
334022136b3SJia-Ju Bai
335c28d8fefSJia-Ju Bai /* Stop the driver */
NDR_stop(void)336c28d8fefSJia-Ju Bai static void NDR_stop(void) {
337c28d8fefSJia-Ju Bai /* Free Rx and Tx buffer*/
338c28d8fefSJia-Ju Bai free_contig(g_driver.buf, g_driver.buf_size);
339c28d8fefSJia-Ju Bai
340c28d8fefSJia-Ju Bai /* Stop interrupt */
341c28d8fefSJia-Ju Bai /* ### INTR_ENABLE_DISABLE ### */
342c28d8fefSJia-Ju Bai dev_intr_control(g_driver.base, INTR_DISABLE);
343c28d8fefSJia-Ju Bai
344c28d8fefSJia-Ju Bai /* Stop Rx and Tx */
345c28d8fefSJia-Ju Bai /* ### RX_TX_ENABLE_DISABLE ### */
346c28d8fefSJia-Ju Bai dev_rx_tx_control(g_driver.base, RX_TX_DISABLE);
347c28d8fefSJia-Ju Bai }
348c28d8fefSJia-Ju Bai
349c28d8fefSJia-Ju Bai /* Set driver mode */
350*f7df02e7SDavid van Moolenbroek static void
NDR_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)351*f7df02e7SDavid van Moolenbroek NDR_set_mode(unsigned int mode, const netdriver_addr_t * mcast_list __unused,
352*f7df02e7SDavid van Moolenbroek unsigned int mcast_count __unused)
353*f7df02e7SDavid van Moolenbroek {
354c28d8fefSJia-Ju Bai g_driver.mode = mode;
355c28d8fefSJia-Ju Bai /* Set driver receive mode */
356c28d8fefSJia-Ju Bai /* ### SET_REC_MODE ### */
357c28d8fefSJia-Ju Bai dev_set_rec_mode(g_driver.base, mode);
358c28d8fefSJia-Ju Bai }
359c28d8fefSJia-Ju Bai
360c28d8fefSJia-Ju Bai /* Receive data */
NDR_recv(struct netdriver_data * data,size_t max)361c28d8fefSJia-Ju Bai static ssize_t NDR_recv(struct netdriver_data *data, size_t max) {
362c28d8fefSJia-Ju Bai NDR_driver *pdev = &g_driver;
363c28d8fefSJia-Ju Bai u32_t totlen, packlen;
364c28d8fefSJia-Ju Bai int index, ret, offset = 0;
365c28d8fefSJia-Ju Bai NDR_desc *desc;
366c28d8fefSJia-Ju Bai
367c28d8fefSJia-Ju Bai index = pdev->rx_head;
368c28d8fefSJia-Ju Bai desc = pdev->rx_desc;
369c28d8fefSJia-Ju Bai desc += index;
370c28d8fefSJia-Ju Bai /* Check whether Rx is OK from Rx descriptor */
371c28d8fefSJia-Ju Bai /* ### CHECK_RX_OK_FROM_DESC ### */
372c28d8fefSJia-Ju Bai ret = dev_rx_ok_desc(pdev->base, desc, index);
373c28d8fefSJia-Ju Bai if (ret == RX_SUSPEND)
374c28d8fefSJia-Ju Bai return SUSPEND;
375c28d8fefSJia-Ju Bai else if (ret == RX_ERROR)
376c28d8fefSJia-Ju Bai printf("NDR: Rx error now\n");
377c28d8fefSJia-Ju Bai /* Get length from Rx descriptor */
378c28d8fefSJia-Ju Bai /* ### GET_RX_LENGTH_FROM_DESC ### */
379c28d8fefSJia-Ju Bai totlen = dev_rx_len_desc(pdev->base, desc, index);
380c28d8fefSJia-Ju Bai
381c28d8fefSJia-Ju Bai /* Get data length */
382c28d8fefSJia-Ju Bai /* ### Get , int inde, int indexxRx data length ### */
383*f7df02e7SDavid van Moolenbroek if (totlen < 8 || totlen > 2 * NDEV_ETH_PACKET_MAX) {
384c28d8fefSJia-Ju Bai printf("NDR: Bad data length: %d\n", totlen);
385c28d8fefSJia-Ju Bai panic(NULL);
386c28d8fefSJia-Ju Bai }
387c28d8fefSJia-Ju Bai
388c28d8fefSJia-Ju Bai packlen = totlen;
389c28d8fefSJia-Ju Bai if (packlen > max)
390c28d8fefSJia-Ju Bai packlen = max;
391c28d8fefSJia-Ju Bai
392c28d8fefSJia-Ju Bai /* Copy data to user */
393c28d8fefSJia-Ju Bai netdriver_copyout(data, 0, pdev->rx[index].buf + offset, packlen);
394c28d8fefSJia-Ju Bai
395c28d8fefSJia-Ju Bai /* Set Rx descriptor after Rx done */
396c28d8fefSJia-Ju Bai /* ### SET_RX_DESC_DONE ### */
397c28d8fefSJia-Ju Bai dev_set_rx_desc_done(pdev->base, desc, index);
398c28d8fefSJia-Ju Bai if (index == RX_BUFFER_NUM - 1)
399c28d8fefSJia-Ju Bai index = 0;
400c28d8fefSJia-Ju Bai else
401c28d8fefSJia-Ju Bai index++;
402c28d8fefSJia-Ju Bai pdev->rx_head = index;
403c28d8fefSJia-Ju Bai
404c28d8fefSJia-Ju Bai #ifdef MY_DEBUG
405c28d8fefSJia-Ju Bai printf("NDR: Successfully receive a packet, length = %d\n", packlen);
406c28d8fefSJia-Ju Bai #endif
407c28d8fefSJia-Ju Bai
408c28d8fefSJia-Ju Bai return packlen;
409c28d8fefSJia-Ju Bai }
410c28d8fefSJia-Ju Bai
411c28d8fefSJia-Ju Bai /* Transmit data */
NDR_send(struct netdriver_data * data,size_t size)412c28d8fefSJia-Ju Bai static int NDR_send(struct netdriver_data *data, size_t size) {
413c28d8fefSJia-Ju Bai NDR_driver *pdev = &g_driver;
414c28d8fefSJia-Ju Bai int tx_head, i;
415c28d8fefSJia-Ju Bai NDR_desc *desc;
416c28d8fefSJia-Ju Bai
417c28d8fefSJia-Ju Bai tx_head = pdev->tx_head;
418c28d8fefSJia-Ju Bai if (pdev->tx[tx_head].busy)
419c28d8fefSJia-Ju Bai return SUSPEND;
420c28d8fefSJia-Ju Bai
421c28d8fefSJia-Ju Bai /* Copy data from user */
422c28d8fefSJia-Ju Bai netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size);
423c28d8fefSJia-Ju Bai
424c28d8fefSJia-Ju Bai /* Set busy */
425c28d8fefSJia-Ju Bai pdev->tx[tx_head].busy = TRUE;
426c28d8fefSJia-Ju Bai pdev->tx_busy_num++;
427c28d8fefSJia-Ju Bai
428c28d8fefSJia-Ju Bai desc = pdev->tx_desc;
429c28d8fefSJia-Ju Bai desc += tx_head;
430c28d8fefSJia-Ju Bai /* Set Tx descriptor to prepare transmitting */
431c28d8fefSJia-Ju Bai /* ### SET_TX_DESC_PREPARE ### */
432c28d8fefSJia-Ju Bai dev_set_tx_desc_prepare(pdev->base, desc, tx_head, size);
433c28d8fefSJia-Ju Bai if (tx_head == TX_BUFFER_NUM - 1)
434c28d8fefSJia-Ju Bai tx_head = 0;
435c28d8fefSJia-Ju Bai else
436c28d8fefSJia-Ju Bai tx_head++;
437c28d8fefSJia-Ju Bai pdev->tx_head = tx_head;
438c28d8fefSJia-Ju Bai
439c28d8fefSJia-Ju Bai /* Start Tx channel */
440c28d8fefSJia-Ju Bai /* ### START_TX ### */
441c28d8fefSJia-Ju Bai dev_start_tx(pdev->base);
442c28d8fefSJia-Ju Bai
443c28d8fefSJia-Ju Bai return 0;
444c28d8fefSJia-Ju Bai }
445c28d8fefSJia-Ju Bai
446c28d8fefSJia-Ju Bai /* Handle interrupt */
NDR_intr(unsigned int mask)447c28d8fefSJia-Ju Bai static void NDR_intr(unsigned int mask) {
448c28d8fefSJia-Ju Bai int s;
449c28d8fefSJia-Ju Bai
450c28d8fefSJia-Ju Bai /* Run interrupt handler at driver level */
451c28d8fefSJia-Ju Bai dev_handler(&g_driver);
452c28d8fefSJia-Ju Bai
453c28d8fefSJia-Ju Bai /* Reenable interrupts for this hook */
454c28d8fefSJia-Ju Bai if ((s = sys_irqenable(&g_driver.hook)) != OK)
455c28d8fefSJia-Ju Bai printf("NDR: Cannot enable OS interrupts: %d\n", s);
456c28d8fefSJia-Ju Bai
457c28d8fefSJia-Ju Bai /* Perform tasks based on the flagged conditions */
458c28d8fefSJia-Ju Bai dev_check_ints(&g_driver);
459c28d8fefSJia-Ju Bai }
460c28d8fefSJia-Ju Bai
461022136b3SJia-Ju Bai /* Match the device and get base address */
dev_probe(NDR_driver * pdev,int instance)462c28d8fefSJia-Ju Bai static int dev_probe(NDR_driver *pdev, int instance) {
463c28d8fefSJia-Ju Bai int devind, ioflag, i;
464022136b3SJia-Ju Bai u16_t cr, vid, did;
465c28d8fefSJia-Ju Bai u32_t bar, size, base;
466022136b3SJia-Ju Bai u8_t irq, rev;
4678dc24c06SJia-Ju Bai u8_t *reg;
468022136b3SJia-Ju Bai
469022136b3SJia-Ju Bai /* Find pci device */
470022136b3SJia-Ju Bai pci_init();
471022136b3SJia-Ju Bai if (!pci_first_dev(&devind, &vid, &did))
472022136b3SJia-Ju Bai return -EIO;
473022136b3SJia-Ju Bai while (instance--) {
474022136b3SJia-Ju Bai if (!pci_next_dev(&devind, &vid, &did))
475022136b3SJia-Ju Bai return -EIO;
476022136b3SJia-Ju Bai }
477022136b3SJia-Ju Bai pci_reserve(devind);
478022136b3SJia-Ju Bai
479c28d8fefSJia-Ju Bai /* Enable bus mastering and I/O space */
480022136b3SJia-Ju Bai cr = pci_attr_r16(devind, PCI_CR);
481c28d8fefSJia-Ju Bai pci_attr_w16(devind, PCI_CR, cr | 0x105);
482022136b3SJia-Ju Bai
483022136b3SJia-Ju Bai /* Get base address */
484c28d8fefSJia-Ju Bai for (i = 0; i < 6; i++)
485c28d8fefSJia-Ju Bai pdev->base[i] = 0;
486c28d8fefSJia-Ju Bai #ifdef DMA_BASE_IOMAP
487c28d8fefSJia-Ju Bai for (i = 0; i < 6; i++) {
488c28d8fefSJia-Ju Bai if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) {
489c28d8fefSJia-Ju Bai /* printf("NDR: Fail to get PCI BAR\n"); */
490c28d8fefSJia-Ju Bai continue;
491022136b3SJia-Ju Bai }
4928dc24c06SJia-Ju Bai if (ioflag) {
493c28d8fefSJia-Ju Bai /* printf("NDR: PCI BAR is not for memory\n"); */
494c28d8fefSJia-Ju Bai continue;
4958dc24c06SJia-Ju Bai }
4968dc24c06SJia-Ju Bai if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
497c28d8fefSJia-Ju Bai printf("NDR: Fail to map hardware registers from PCI\n");
4988dc24c06SJia-Ju Bai return -EIO;
4998dc24c06SJia-Ju Bai }
500c28d8fefSJia-Ju Bai pdev->base[i] = (u32_t)reg;
501c28d8fefSJia-Ju Bai }
5028dc24c06SJia-Ju Bai #else
503c28d8fefSJia-Ju Bai for (i = 0; i < 6; i++)
504c28d8fefSJia-Ju Bai pdev->base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0;
5058dc24c06SJia-Ju Bai #endif
506c28d8fefSJia-Ju Bai pdev->dev_name = pci_dev_name(vid, did);
507c28d8fefSJia-Ju Bai pdev->irq = pci_attr_r8(devind, PCI_ILR);
508c28d8fefSJia-Ju Bai pdev->revision = pci_attr_r8(devind, PCI_REV);
509c28d8fefSJia-Ju Bai pdev->did = did;
510c28d8fefSJia-Ju Bai pdev->vid = vid;
511c28d8fefSJia-Ju Bai pdev->devind = devind;
512022136b3SJia-Ju Bai
5138dc24c06SJia-Ju Bai #ifdef MY_DEBUG
514c28d8fefSJia-Ju Bai printf("NDR: Hardware name is %s\n", pdev->dev_name);
515c28d8fefSJia-Ju Bai for (i = 0; i < 6; i++)
516c28d8fefSJia-Ju Bai printf("NDR: PCI BAR%d is 0x%08x\n", i, pdev->base[i]);
517c28d8fefSJia-Ju Bai printf("NDR: IRQ number is 0x%02x\n", pdev->irq);
518022136b3SJia-Ju Bai #endif
519022136b3SJia-Ju Bai
520022136b3SJia-Ju Bai return 0;
521022136b3SJia-Ju Bai }
522022136b3SJia-Ju Bai
523022136b3SJia-Ju Bai /* Intialize hardware */
dev_init_hw(NDR_driver * pdev,netdriver_addr_t * addr)524*f7df02e7SDavid van Moolenbroek static int dev_init_hw(NDR_driver *pdev, netdriver_addr_t *addr) {
525022136b3SJia-Ju Bai int r, ret;
526022136b3SJia-Ju Bai
5278dc24c06SJia-Ju Bai /* Set the OS interrupt handler */
5288dc24c06SJia-Ju Bai pdev->hook = pdev->irq;
5298dc24c06SJia-Ju Bai if ((r = sys_irqsetpolicy(pdev->irq, 0, &pdev->hook)) != OK) {
530c28d8fefSJia-Ju Bai printf("NDR: Fail to set OS IRQ policy: %d\n", r);
531022136b3SJia-Ju Bai ret = -EFAULT;
532022136b3SJia-Ju Bai goto err_irq_policy;
533022136b3SJia-Ju Bai }
534022136b3SJia-Ju Bai
535022136b3SJia-Ju Bai /* Reset hardware */
536c28d8fefSJia-Ju Bai if (dev_reset_hw(pdev)) {
537c28d8fefSJia-Ju Bai printf("NDR: Fail to reset the device\n");
5388dc24c06SJia-Ju Bai ret = -EIO;
5398dc24c06SJia-Ju Bai goto err_reset_hw;
5408dc24c06SJia-Ju Bai }
541022136b3SJia-Ju Bai
5428dc24c06SJia-Ju Bai /* Enable OS IRQ */
5438dc24c06SJia-Ju Bai if ((r = sys_irqenable(&pdev->hook)) != OK) {
544c28d8fefSJia-Ju Bai printf("NDR: Fail to enable OS IRQ: %d\n", r);
545022136b3SJia-Ju Bai ret = -EFAULT;
546022136b3SJia-Ju Bai goto err_irq_enable;
547022136b3SJia-Ju Bai }
548022136b3SJia-Ju Bai
549022136b3SJia-Ju Bai /* Configure MAC address */
550c28d8fefSJia-Ju Bai dev_conf_addr(pdev, addr);
551022136b3SJia-Ju Bai
552022136b3SJia-Ju Bai /* Detect link status */
553c28d8fefSJia-Ju Bai /* ### CHECK_LINK ### */
554c28d8fefSJia-Ju Bai pdev->link = dev_check_link(pdev->base);
5558dc24c06SJia-Ju Bai #ifdef MY_DEBUG
5568dc24c06SJia-Ju Bai if (pdev->link)
557c28d8fefSJia-Ju Bai printf("NDR: Link up\n");
558022136b3SJia-Ju Bai else
559c28d8fefSJia-Ju Bai printf("NDR: Link down\n");
560022136b3SJia-Ju Bai #endif
561022136b3SJia-Ju Bai
562022136b3SJia-Ju Bai return 0;
563022136b3SJia-Ju Bai
5648dc24c06SJia-Ju Bai err_reset_hw:
565022136b3SJia-Ju Bai err_irq_enable:
566022136b3SJia-Ju Bai err_irq_policy:
567022136b3SJia-Ju Bai return ret;
568022136b3SJia-Ju Bai }
569022136b3SJia-Ju Bai
570022136b3SJia-Ju Bai /* Reset hardware */
dev_reset_hw(NDR_driver * pdev)571c28d8fefSJia-Ju Bai static int dev_reset_hw(NDR_driver *pdev) {
5728dc24c06SJia-Ju Bai int ret;
573022136b3SJia-Ju Bai
574022136b3SJia-Ju Bai /* Reset the chip */
5758dc24c06SJia-Ju Bai /* ### RESET_HARDWARE_CAN_FAIL ### */
576c28d8fefSJia-Ju Bai if (dev_real_reset(pdev->base)) {
577c28d8fefSJia-Ju Bai printf("NDR: Fail to reset the hardware\n");
5788dc24c06SJia-Ju Bai ret = -EIO;
5798dc24c06SJia-Ju Bai goto err_real_reset;
580022136b3SJia-Ju Bai }
5818dc24c06SJia-Ju Bai
582c28d8fefSJia-Ju Bai /* Initialize other hardware I/O registers */
5838dc24c06SJia-Ju Bai /* ### SET_RX_DESC_REG ### */
584c28d8fefSJia-Ju Bai if (dev_init_io(pdev->base)) {
585c28d8fefSJia-Ju Bai printf("NDR: Fail to initialize I/O registers\n");
5868dc24c06SJia-Ju Bai ret = -EIO;
5878dc24c06SJia-Ju Bai goto err_init_io;
5888dc24c06SJia-Ju Bai }
5898dc24c06SJia-Ju Bai
590c28d8fefSJia-Ju Bai /* Initialize MII interface */
591c28d8fefSJia-Ju Bai /* ### MII_INIT_CAN_FAIL ### */
592c28d8fefSJia-Ju Bai if (dev_init_mii(pdev->base)) {
593c28d8fefSJia-Ju Bai printf("NDR: Fail to initialize MII interface\n");
594c28d8fefSJia-Ju Bai ret = -EIO;
595c28d8fefSJia-Ju Bai goto err_init_mii;
596c28d8fefSJia-Ju Bai }
597022136b3SJia-Ju Bai
5988dc24c06SJia-Ju Bai return 0;
5998dc24c06SJia-Ju Bai
6008dc24c06SJia-Ju Bai err_init_mii:
601c28d8fefSJia-Ju Bai err_init_io:
6028dc24c06SJia-Ju Bai err_real_reset:
6038dc24c06SJia-Ju Bai return ret;
604022136b3SJia-Ju Bai }
605022136b3SJia-Ju Bai
6068dc24c06SJia-Ju Bai /* Configure MAC address */
dev_conf_addr(NDR_driver * pdev,netdriver_addr_t * addr)607*f7df02e7SDavid van Moolenbroek static void dev_conf_addr(NDR_driver *pdev, netdriver_addr_t *addr) {
6088dc24c06SJia-Ju Bai u8_t pa[6];
609022136b3SJia-Ju Bai
6108dc24c06SJia-Ju Bai /* Get MAC address */
6118dc24c06SJia-Ju Bai /* ### GET_MAC_ADDR ### */
612c28d8fefSJia-Ju Bai dev_get_addr(pdev->base, pa);
613*f7df02e7SDavid van Moolenbroek addr->na_addr[0] = pa[0];
614*f7df02e7SDavid van Moolenbroek addr->na_addr[1] = pa[1];
615*f7df02e7SDavid van Moolenbroek addr->na_addr[2] = pa[2];
616*f7df02e7SDavid van Moolenbroek addr->na_addr[3] = pa[3];
617*f7df02e7SDavid van Moolenbroek addr->na_addr[4] = pa[4];
618*f7df02e7SDavid van Moolenbroek addr->na_addr[5] = pa[5];
6198dc24c06SJia-Ju Bai #ifdef MY_DEBUG
620c28d8fefSJia-Ju Bai printf("NDR: Ethernet address is %02x:%02x:%02x:%02x:%02x:%02x\n",
621*f7df02e7SDavid van Moolenbroek addr->na_addr[0], addr->na_addr[1], addr->na_addr[2],
622*f7df02e7SDavid van Moolenbroek addr->na_addr[3], addr->na_addr[4], addr->na_addr[5]);
623022136b3SJia-Ju Bai #endif
624022136b3SJia-Ju Bai }
625022136b3SJia-Ju Bai
626c28d8fefSJia-Ju Bai /* Allocate and initialize buffer */
dev_init_buf(NDR_driver * pdev)627c28d8fefSJia-Ju Bai static int dev_init_buf(NDR_driver *pdev) {
628c28d8fefSJia-Ju Bai size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size;
629c28d8fefSJia-Ju Bai phys_bytes buf_dma;
630c28d8fefSJia-Ju Bai char *buf;
631c28d8fefSJia-Ju Bai int i;
632022136b3SJia-Ju Bai
633c28d8fefSJia-Ju Bai /* Build Rx and Tx buffer */
634c28d8fefSJia-Ju Bai tx_buf_size = TX_BUF_SIZE;
635c28d8fefSJia-Ju Bai if (tx_buf_size % 4)
636c28d8fefSJia-Ju Bai tx_buf_size += 4 - (tx_buf_size % 4);
637c28d8fefSJia-Ju Bai rx_buf_size = RX_BUF_SIZE;
638c28d8fefSJia-Ju Bai if (rx_buf_size % 4)
639c28d8fefSJia-Ju Bai rx_buf_size += 4 - (rx_buf_size % 4);
640c28d8fefSJia-Ju Bai tot_buf_size = TX_BUFFER_NUM * tx_buf_size + RX_BUFFER_NUM * rx_buf_size;
641c28d8fefSJia-Ju Bai rx_desc_size = RX_BUFFER_NUM * sizeof(NDR_desc);
642c28d8fefSJia-Ju Bai tx_desc_size = TX_BUFFER_NUM * sizeof(NDR_desc);
643c28d8fefSJia-Ju Bai tot_buf_size += rx_desc_size + tx_desc_size;
644c28d8fefSJia-Ju Bai if (tot_buf_size % 4096)
645c28d8fefSJia-Ju Bai tot_buf_size += 4096 - (tot_buf_size % 4096);
646022136b3SJia-Ju Bai
647c28d8fefSJia-Ju Bai if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) {
648c28d8fefSJia-Ju Bai printf("NDR: Fail to allocate memory\n");
649c28d8fefSJia-Ju Bai return -ENOMEM;
650c28d8fefSJia-Ju Bai }
651c28d8fefSJia-Ju Bai pdev->buf_size = tot_buf_size;
652c28d8fefSJia-Ju Bai pdev->buf = buf;
6538dc24c06SJia-Ju Bai
654c28d8fefSJia-Ju Bai /* Rx descriptor buffer location */
655c28d8fefSJia-Ju Bai pdev->rx_desc = (NDR_desc *)buf;
656c28d8fefSJia-Ju Bai pdev->rx_desc_dma = buf_dma;
657c28d8fefSJia-Ju Bai memset(buf, 0, rx_desc_size);
658c28d8fefSJia-Ju Bai buf += rx_desc_size;
659c28d8fefSJia-Ju Bai buf_dma += rx_desc_size;
660c28d8fefSJia-Ju Bai
661c28d8fefSJia-Ju Bai /* Tx descriptor buffer location */
662c28d8fefSJia-Ju Bai pdev->tx_desc = (NDR_desc *)buf;
663c28d8fefSJia-Ju Bai pdev->tx_desc_dma = buf_dma;
664c28d8fefSJia-Ju Bai memset(buf, 0, tx_desc_size);
665c28d8fefSJia-Ju Bai buf += tx_desc_size;
666c28d8fefSJia-Ju Bai buf_dma += tx_desc_size;
667c28d8fefSJia-Ju Bai
668c28d8fefSJia-Ju Bai /* Rx buffer assignment */
669c28d8fefSJia-Ju Bai for (i = 0; i < RX_BUFFER_NUM; i++) {
670c28d8fefSJia-Ju Bai /* Initialize Rx buffer */
671c28d8fefSJia-Ju Bai pdev->rx[i].buf_dma = buf_dma;
672c28d8fefSJia-Ju Bai pdev->rx[i].buf = buf;
673c28d8fefSJia-Ju Bai buf_dma += rx_buf_size;
674c28d8fefSJia-Ju Bai buf += rx_buf_size;
675c28d8fefSJia-Ju Bai /* Set Rx descriptor */
676c28d8fefSJia-Ju Bai /* ### INIT_RX_DESC ### */
677c28d8fefSJia-Ju Bai dev_init_rx_desc(pdev->rx_desc, i, rx_buf_size, pdev->rx[i].buf_dma,
678c28d8fefSJia-Ju Bai RX_BUFFER_NUM, pdev->rx_desc_dma);
679022136b3SJia-Ju Bai }
680022136b3SJia-Ju Bai
681c28d8fefSJia-Ju Bai /* Tx buffer assignment */
682c28d8fefSJia-Ju Bai for (i = 0; i < TX_BUFFER_NUM; i++) {
683c28d8fefSJia-Ju Bai /* Set Tx buffer */
684c28d8fefSJia-Ju Bai pdev->tx[i].busy = 0;
685c28d8fefSJia-Ju Bai pdev->tx[i].buf_dma = buf_dma;
686c28d8fefSJia-Ju Bai pdev->tx[i].buf = buf;
687c28d8fefSJia-Ju Bai buf_dma += tx_buf_size;
688c28d8fefSJia-Ju Bai buf += tx_buf_size;
689c28d8fefSJia-Ju Bai /* Initialize Tx descriptor */
690c28d8fefSJia-Ju Bai /* ### INIT_TX_DESC ### */
691c28d8fefSJia-Ju Bai dev_init_tx_desc(pdev->tx_desc, i, tx_buf_size, pdev->tx[i].buf_dma,
692c28d8fefSJia-Ju Bai TX_BUFFER_NUM, pdev->tx_desc_dma);
693022136b3SJia-Ju Bai }
694022136b3SJia-Ju Bai
695c28d8fefSJia-Ju Bai /* Set Rx/Tx descriptor address into device register */
696c28d8fefSJia-Ju Bai /* ### SET_DESC_REG ### */
697c28d8fefSJia-Ju Bai dev_set_desc_reg(pdev->base, g_driver.rx_desc_dma,
698c28d8fefSJia-Ju Bai g_driver.tx_desc_dma);
699022136b3SJia-Ju Bai
700c28d8fefSJia-Ju Bai pdev->tx_busy_num = 0;
701c28d8fefSJia-Ju Bai pdev->tx_head = 0;
702c28d8fefSJia-Ju Bai pdev->tx_tail = 0;
703c28d8fefSJia-Ju Bai pdev->rx_head = 0;
704022136b3SJia-Ju Bai
705022136b3SJia-Ju Bai return 0;
706022136b3SJia-Ju Bai }
707022136b3SJia-Ju Bai
708022136b3SJia-Ju Bai /* Real handler interrupt */
dev_handler(NDR_driver * pdev)709c28d8fefSJia-Ju Bai static void dev_handler(NDR_driver *pdev) {
710c28d8fefSJia-Ju Bai u32_t intr_status;
711c28d8fefSJia-Ju Bai int tx_head, tx_tail, index, flag = 0, ret;
712c28d8fefSJia-Ju Bai NDR_desc *desc;
713022136b3SJia-Ju Bai
714c28d8fefSJia-Ju Bai /* Read and clear interrupt status */
715c28d8fefSJia-Ju Bai /* ### READ_CLEAR_INTR_STS ### */
716c28d8fefSJia-Ju Bai intr_status = dev_read_clear_intr_status(pdev->base);
717022136b3SJia-Ju Bai
7188dc24c06SJia-Ju Bai /* Enable interrupt */
719c28d8fefSJia-Ju Bai /* ### INTR_ENABLE_DISABLE ### */
720c28d8fefSJia-Ju Bai dev_intr_control(pdev->base, INTR_ENABLE);
721022136b3SJia-Ju Bai
7228dc24c06SJia-Ju Bai /* Check link status */
723c28d8fefSJia-Ju Bai if (intr_status & INTR_STS_LINK) {
724c28d8fefSJia-Ju Bai pdev->link = dev_check_link(pdev->base);
7258dc24c06SJia-Ju Bai #ifdef MY_DEBUG
726c28d8fefSJia-Ju Bai printf("NDR: Link state change\n");
7278dc24c06SJia-Ju Bai #endif
7288dc24c06SJia-Ju Bai flag++;
7298dc24c06SJia-Ju Bai }
7308dc24c06SJia-Ju Bai /* Check Rx request status */
731c28d8fefSJia-Ju Bai if (intr_status & INTR_STS_RX) {
7328dc24c06SJia-Ju Bai pdev->recv_flag = TRUE;
7338dc24c06SJia-Ju Bai flag++;
7348dc24c06SJia-Ju Bai }
7358dc24c06SJia-Ju Bai /* Check Tx request status */
736c28d8fefSJia-Ju Bai if (intr_status & INTR_STS_TX) {
7378dc24c06SJia-Ju Bai pdev->send_flag = TRUE;
7388dc24c06SJia-Ju Bai flag++;
7398dc24c06SJia-Ju Bai
7408dc24c06SJia-Ju Bai /* Manage Tx Buffer */
7418dc24c06SJia-Ju Bai tx_head = pdev->tx_head;
7428dc24c06SJia-Ju Bai tx_tail = pdev->tx_tail;
7438dc24c06SJia-Ju Bai while (tx_tail != tx_head) {
744c28d8fefSJia-Ju Bai if (!pdev->tx[tx_tail].busy)
745c28d8fefSJia-Ju Bai printf("NDR: Strange, buffer not busy?\n");
746c28d8fefSJia-Ju Bai index = tx_tail;
7478dc24c06SJia-Ju Bai desc = pdev->tx_desc;
7488dc24c06SJia-Ju Bai desc += tx_tail;
749c28d8fefSJia-Ju Bai /* Check whether Tx is OK from Tx descriptor */
750c28d8fefSJia-Ju Bai /* ### CHECK_TX_OK_FROM_DESC ### */
751c28d8fefSJia-Ju Bai ret = dev_tx_ok_desc(pdev->base, desc, index);
752c28d8fefSJia-Ju Bai if (ret == TX_SUSPEND)
7538dc24c06SJia-Ju Bai break;
754c28d8fefSJia-Ju Bai else if (ret == TX_ERROR)
755c28d8fefSJia-Ju Bai printf("NDR: Tx error now\n");
7568dc24c06SJia-Ju Bai
7578dc24c06SJia-Ju Bai pdev->tx[tx_tail].busy = FALSE;
7588dc24c06SJia-Ju Bai pdev->tx_busy_num--;
7598dc24c06SJia-Ju Bai
760c28d8fefSJia-Ju Bai if (++tx_tail >= TX_BUFFER_NUM)
7618dc24c06SJia-Ju Bai tx_tail = 0;
7628dc24c06SJia-Ju Bai
7638dc24c06SJia-Ju Bai pdev->send_flag = TRUE;
7648dc24c06SJia-Ju Bai pdev->recv_flag = TRUE;
7658dc24c06SJia-Ju Bai
766c28d8fefSJia-Ju Bai /* Set Tx descriptor after Tx done */
767c28d8fefSJia-Ju Bai /* ### SET_TX_DESC_DONE ### */
768c28d8fefSJia-Ju Bai dev_set_tx_desc_done(pdev->base, desc, index);
7698dc24c06SJia-Ju Bai #ifdef MY_DEBUG
770c28d8fefSJia-Ju Bai printf("NDR: Successfully send a packet\n");
7718dc24c06SJia-Ju Bai #endif
7728dc24c06SJia-Ju Bai }
7738dc24c06SJia-Ju Bai pdev->tx_tail = tx_tail;
7748dc24c06SJia-Ju Bai }
7758dc24c06SJia-Ju Bai #ifdef MY_DEBUG
7768dc24c06SJia-Ju Bai if (!flag) {
777c28d8fefSJia-Ju Bai printf("NDR: Unknown error in interrupt 0x%08x\n", intr_status);
7788dc24c06SJia-Ju Bai return;
7798dc24c06SJia-Ju Bai }
7808dc24c06SJia-Ju Bai #endif
781022136b3SJia-Ju Bai }
782022136b3SJia-Ju Bai
783022136b3SJia-Ju Bai /* Check interrupt and perform */
dev_check_ints(NDR_driver * pdev)784c28d8fefSJia-Ju Bai static void dev_check_ints(NDR_driver *pdev) {
7858dc24c06SJia-Ju Bai if (!pdev->recv_flag)
786022136b3SJia-Ju Bai return;
7878dc24c06SJia-Ju Bai pdev->recv_flag = FALSE;
788022136b3SJia-Ju Bai
789022136b3SJia-Ju Bai /* Handle data receive */
790022136b3SJia-Ju Bai netdriver_recv();
791022136b3SJia-Ju Bai
792022136b3SJia-Ju Bai /* Handle data transmit */
7938dc24c06SJia-Ju Bai if (pdev->send_flag) {
7948dc24c06SJia-Ju Bai pdev->send_flag = FALSE;
795022136b3SJia-Ju Bai netdriver_send();
796022136b3SJia-Ju Bai }
797022136b3SJia-Ju Bai }
798