xref: /minix/minix/drivers/net/lan8710a/lan8710a.c (revision 83133719)
1 #include <minix/drivers.h>
2 #include <minix/netdriver.h>
3 #include <net/gen/ether.h>
4 #include <net/gen/eth_io.h>
5 #include <minix/sysutil.h>
6 #include <minix/board.h>
7 #include "assert.h"
8 #include "lan8710a.h"
9 #include "lan8710a_reg.h"
10 
11 /* Local functions */
12 static void lan8710a_readv_s(message *m, int from_int);
13 static void lan8710a_writev_s(message *m, int from_int);
14 static void lan8710a_conf(message *m);
15 static void lan8710a_getstat(message *m);
16 
17 static void lan8710a_init(void);
18 static void lan8710a_enable_interrupt(int interrupt);
19 static void lan8710a_interrupt(message *m);
20 static void lan8710a_map_regs(void);
21 static void lan8710a_stop(void);
22 static void lan8710a_dma_config_tx(u8_t desc_idx);
23 static void lan8710a_dma_reset_init(void);
24 static void lan8710a_init_addr(void);
25 static void lan8710a_init_desc(void);
26 static void lan8710a_init_mdio(void);
27 static int lan8710a_init_hw(void);
28 static void lan8710a_reset_hw();
29 
30 static void lan8710a_phy_write(u32_t reg, u32_t value);
31 static u32_t lan8710a_phy_read(u32_t reg);
32 
33 static u32_t lan8710a_reg_read(volatile u32_t *reg);
34 static void lan8710a_reg_write(volatile u32_t *reg, u32_t value);
35 static void lan8710a_reg_set(volatile u32_t *reg, u32_t value);
36 static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value);
37 
38 static void mess_reply(message *req, message *reply);
39 static void reply(lan8710a_t *e);
40 
41 /* Local variables */
42 static lan8710a_t lan8710a_state;
43 
44 /* SEF functions and variables. */
45 static void sef_local_startup(void);
46 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
47 static void sef_cb_signal_handler(int signal);
48 
49 /*============================================================================*
50  *				main					      *
51  *============================================================================*/
52 int
53 main(int argc, char *argv[])
54 {
55 
56 	/* Local variables */
57 	message m;
58 	int r;
59 	int ipc_status;
60 	struct machine  machine ;
61 
62 	sys_getmachine(&machine);
63 	if ( BOARD_IS_BB(machine.board_id)) {
64 
65 		/* SEF local startup */
66 		env_setargs(argc, argv);
67 		sef_local_startup();
68 
69 		/* Main driver loop */
70 		for (;;) {
71 			r = netdriver_receive(ANY, &m, &ipc_status);
72 			if (r != OK) {
73 				panic("netdriver_receive failed: %d", r);
74 			}
75 
76 			if (is_ipc_notify(ipc_status)) {
77 				switch (_ENDPOINT_P(m.m_source)) {
78 				case HARDWARE:
79 					lan8710a_interrupt(&m);
80 					break;
81 				}
82 			} else {
83 				switch (m.m_type) {
84 				case DL_WRITEV_S:
85 					lan8710a_writev_s(&m, FALSE);
86 					break;
87 				case DL_READV_S:
88 					lan8710a_readv_s(&m, FALSE);
89 					break;
90 				case DL_CONF:
91 					lan8710a_conf(&m);
92 					break;
93 				case DL_GETSTAT_S:
94 					lan8710a_getstat(&m);
95 					break;
96 				default:
97 					panic("Illegal message: %d", m.m_type);
98 				}
99 			}
100 		}
101 	}
102 	return EXIT_SUCCESS;
103 }
104 
105 /*============================================================================*
106  *				sef_local_startup			      *
107  *============================================================================*/
108 static void
109 sef_local_startup()
110 {
111 	/* Register init callbacks. */
112 	sef_setcb_init_fresh(sef_cb_init_fresh);
113 	sef_setcb_init_lu(sef_cb_init_fresh);
114 	sef_setcb_init_restart(sef_cb_init_fresh);
115 
116 	/* Register live update callbacks. */
117 	sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
118 	sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
119 
120 	/* Register signal callbacks. */
121 	sef_setcb_signal_handler(sef_cb_signal_handler);
122 
123 	/* Let SEF perform startup. */
124 	sef_startup();
125 }
126 
127 /*============================================================================*
128  *				sef_cb_init_fresh			      *
129  *============================================================================*/
130 static int
131 sef_cb_init_fresh(int UNUSED( type), sef_init_info_t *UNUSED( info))
132 {
133 	/* Initialize the ethernet driver. */
134 	long v = 0;
135 
136 	/* Clear state. */
137 	memset(&lan8710a_state, 0, sizeof(lan8710a_state));
138 
139 	/* Initialize driver. */
140 	lan8710a_init();
141 
142 	/* Get instance of ethernet device */
143 	env_parse("instance", "d", 0, &v, 0, 255);
144 	lan8710a_state.instance = (int) v;
145 
146 	/* Announce we are up! */
147 	netdriver_announce();
148 
149 	return OK;
150 }
151 
152 /*============================================================================*
153  *				sef_cb_signal_handler			      *
154  *============================================================================*/
155 static void
156 sef_cb_signal_handler(int signal)
157 {
158 	/* Only check for termination signal, ignore anything else. */
159 	if (signal != SIGTERM)
160 		return;
161 
162 	lan8710a_stop();
163 }
164 
165 /*============================================================================*
166  *				lan8710a_enable_interrupt		      *
167  *============================================================================*/
168 static void
169 lan8710a_enable_interrupt(interrupt)
170 u8_t interrupt;
171 {
172 	int r;
173 
174 	if (interrupt & RX_INT) {
175 		if ((r = sys_irqenable(&lan8710a_state.irq_rx_hook)) != OK) {
176 			panic("sys_irqenable failed: %d", r);
177 		}
178 	}
179 	if (interrupt & TX_INT) {
180 		if ((r = sys_irqenable(&lan8710a_state.irq_tx_hook)) != OK) {
181 			panic("sys_irqenable failed: %d", r);
182 		}
183 	}
184 }
185 /*============================================================================*
186  *				lan8710a_interrupt			      *
187  *============================================================================*/
188 static void
189 lan8710a_interrupt(m)
190 message *m;
191 {
192 	lan8710a_t *e = &lan8710a_state;
193 	u32_t dma_status;
194 
195 	/* Check the card for interrupt reason(s). */
196 	u32_t rx_stat = lan8710a_reg_read(CPSW_WR_C0_RX_STAT);
197 	u32_t tx_stat = lan8710a_reg_read(CPSW_WR_C0_TX_STAT);
198 	u32_t cp;
199 
200 	/* Handle interrupts. */
201 	if (rx_stat) {
202 		cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0));
203 
204 		lan8710a_readv_s(&(e->rx_message), TRUE);
205 
206 		lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp);
207 		lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT);
208 	}
209 	if (tx_stat) {
210 		cp = lan8710a_reg_read(CPDMA_STRAM_TX_CP(0));
211 
212 		/* Disabling channels, where Tx interrupt occurred */
213 		lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat);
214 
215 		lan8710a_writev_s(&(e->tx_message), TRUE);
216 
217 		lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp);
218 		lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT);
219 	}
220 
221 	dma_status = lan8710a_reg_read(CPDMA_STATUS);
222 
223 	if (dma_status & CPDMA_ERROR) {
224 		LAN8710A_DEBUG_PRINT(("CPDMA error: 0x%X, reset", dma_status));
225 		lan8710a_dma_reset_init();
226 	}
227 
228 	/* Re-enable Rx interrupt. */
229 	if(m->m_notify.interrupts & (1 << RX_INT))
230 		lan8710a_enable_interrupt(RX_INT);
231 
232 	/* Re-enable Tx interrupt. */
233 	if(m->m_notify.interrupts & (1 << TX_INT))
234 		lan8710a_enable_interrupt(TX_INT);
235 }
236 
237 /*============================================================================*
238  *				lan8710a_conf				      *
239  *============================================================================*/
240 static void
241 lan8710a_conf(m)
242 message *m;
243 {
244 	message reply;
245 
246 	if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
247 						!(lan8710a_init_hw())) {
248 		reply.m_type = DL_CONF_REPLY;
249 		reply.m_netdrv_net_dl_conf.stat = ENXIO;
250 		mess_reply(m, &reply);
251 		return;
252 	}
253 	/* Reply back to INET. */
254 	reply.m_type = DL_CONF_REPLY;
255 	reply.m_netdrv_net_dl_conf.stat = OK;
256 	memcpy(reply.m_netdrv_net_dl_conf.hw_addr,
257 		lan8710a_state.address.ea_addr,
258 		sizeof(reply.m_netdrv_net_dl_conf.hw_addr));
259 	mess_reply(m, &reply);
260 }
261 
262 /*============================================================================*
263  *				lan8710a_init				      *
264  *============================================================================*/
265 static void
266 lan8710a_init(void)
267 {
268 	lan8710a_map_regs();
269 	strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN);
270 	lan8710a_state.name[9] += lan8710a_state.instance;
271 	lan8710a_state.status |= LAN8710A_DETECTED;
272 
273 	if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
274 						!(lan8710a_init_hw())) {
275 		return;
276 	}
277 }
278 
279 /*============================================================================*
280  *				lan8710a_init_addr			      *
281  *============================================================================*/
282 static void
283 lan8710a_init_addr(void)
284 {
285 	static char eakey[]= LAN8710A_ENVVAR "#_EA";
286 	static char eafmt[]= "x:x:x:x:x:x";
287 	int i;
288 	long v;
289 
290 	/*
291 	 * Do we have a user defined ethernet address?
292 	 */
293 	eakey[sizeof(LAN8710A_ENVVAR)-1] = '0' + lan8710a_state.instance;
294 
295 	for (i= 0; i < 6; i++) {
296 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
297 			break;
298 		else
299 			lan8710a_state.address.ea_addr[i] = v;
300 	}
301 	if (i != 6) {
302 		lan8710a_state.address.ea_addr[0] =
303 			(lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF);
304 		lan8710a_state.address.ea_addr[1] =
305 			((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF00) >> 8);
306 		lan8710a_state.address.ea_addr[2] =
307 			((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF0000) >> 16);
308 		lan8710a_state.address.ea_addr[3] =
309 			((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF000000) >> 24);
310 		lan8710a_state.address.ea_addr[4] =
311 			(lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF);
312 		lan8710a_state.address.ea_addr[5] =
313 			((lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF00) >> 8);
314 	}
315 }
316 
317 /*============================================================================*
318  *				lan8710a_map_regs			      *
319  *============================================================================*/
320 static void
321 lan8710a_map_regs(void)
322 {
323 	struct minix_mem_range mr;
324 	mr.mr_base = CM_PER_BASE_ADR;
325 	mr.mr_limit = CM_PER_BASE_ADR + MEMORY_LIMIT;
326 
327 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
328 		panic("Unable to request permission to map memory");
329 	}
330 	lan8710a_state.regs_cp_per =
331 		(vir_bytes)vm_map_phys(SELF, (void *)CM_PER_BASE_ADR, 512);
332 	if ((void *)lan8710a_state.regs_cp_per == MAP_FAILED) {
333 		panic("lan8710a_state.regs_cp_per: vm_map_phys failed");
334 	}
335 	lan8710a_state.regs_cpdma_stram =
336 		(vir_bytes)vm_map_phys(SELF, (void *)CPDMA_STRAM_BASE_ADR, 512);
337 	if ((void *)lan8710a_state.regs_cpdma_stram == MAP_FAILED) {
338 		panic("lan8710a_state.regs_cpdma_stram: vm_map_phys failed");
339 	}
340 	lan8710a_state.regs_cpsw_cpdma =
341 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_CPDMA_BASE_ADR, 512);
342 	if ((void *)lan8710a_state.regs_cpsw_cpdma == MAP_FAILED) {
343 		panic("lan8710a_state.regs_cpsw_cpdma: vm_map_phys failed");
344 	}
345 	lan8710a_state.regs_cpsw_ale =
346 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_ALE_BASE_ADR, 256);
347 	if ((void *)lan8710a_state.regs_cpsw_ale == MAP_FAILED) {
348 		panic("lan8710a_state.regs_cpsw_ale: vm_map_phys failed");
349 	}
350 	lan8710a_state.regs_cpsw_sl =
351 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_SL_BASE_ADR, 512);
352 	if ((void *)lan8710a_state.regs_cpsw_sl == MAP_FAILED) {
353 		panic("lan8710a_state.regs_cpsw_sl: vm_map_phys failed");
354 	}
355 	lan8710a_state.regs_cpsw_ss =
356 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_SS_BASE_ADR, 512);
357 	if ((void *)lan8710a_state.regs_cpsw_ss == MAP_FAILED) {
358 		panic("lan8710a_state.regs_cpsw_ss: vm_map_phys failed");
359 	}
360 	lan8710a_state.regs_cpsw_wr =
361 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_WR_BASE_ADR, 512);
362 	if ((void *)lan8710a_state.regs_cpsw_wr == MAP_FAILED) {
363 		panic("lan8710a_state.regs_cpsw_wr: vm_map_phys failed");
364 	}
365 	lan8710a_state.regs_ctrl_mod =
366 		(vir_bytes)vm_map_phys(SELF, (void *)CTRL_MOD_BASE_ADR, 2560);
367 	if ((void *)lan8710a_state.regs_ctrl_mod == MAP_FAILED) {
368 		panic("lan8710a_state.regs_ctrl_mod: vm_map_phys failed");
369 	}
370 	lan8710a_state.regs_intc =
371 		(vir_bytes)vm_map_phys(SELF, (void *)INTC_BASE_ADR, 512);
372 	if ((void *)lan8710a_state.regs_intc == MAP_FAILED) {
373 		panic("lan8710a_state.regs_intc: vm_map_phys failed");
374 	}
375 	lan8710a_state.regs_mdio =
376 		(vir_bytes)vm_map_phys(SELF, (void *)MDIO_BASE_ADDR, 512);
377 	if ((void *)lan8710a_state.regs_mdio == MAP_FAILED) {
378 		panic("lan8710a_state.regs_mdio: vm_map_phys failed");
379 	}
380 
381 	mr.mr_base = BEGINNING_DESC_MEM;
382 	mr.mr_limit = BEGINNING_DESC_MEM + DESC_MEMORY_LIMIT;
383 
384 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
385 		panic("Unable to request permission to map memory");
386 	}
387 	lan8710a_state.rx_desc_phy = BEGINNING_RX_DESC_MEM;
388 	lan8710a_state.tx_desc_phy = BEGINNING_TX_DESC_MEM;
389 	lan8710a_state.rx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
390 				(void *)lan8710a_state.rx_desc_phy, 1024);
391 	if ((void *)lan8710a_state.rx_desc == MAP_FAILED) {
392 		panic("lan8710a_state.rx_desc: vm_map_phys failed");
393 	}
394 	lan8710a_state.tx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
395 				(void *)lan8710a_state.tx_desc_phy, 1024);
396 	if ((void *)lan8710a_state.tx_desc == MAP_FAILED) {
397 		panic("lan8710a_state.tx_desc: vm_map_phys failed");
398 	}
399 
400 	mr.mr_base = CPSW_STATS_BASE_ADR;
401 	mr.mr_limit = CPSW_STATS_BASE_ADR + CPSW_STATS_MEM_LIMIT;
402 
403 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
404 		panic("Unable to request permission to map memory");
405 	}
406 	lan8710a_state.regs_cpsw_stats =
407 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_STATS_BASE_ADR, 256);
408 	if ((void *)lan8710a_state.regs_cpsw_stats == MAP_FAILED) {
409 		panic("lan8710a_state.regs_cpsw_stats: vm_map_phys failed");
410 	}
411 }
412 
413 /*============================================================================*
414  *				lan8710a_getstat			      *
415  *============================================================================*/
416 static void
417 lan8710a_getstat(mp)
418 message *mp;
419 {
420 	int r;
421 	eth_stat_t stats;
422 
423 	stats.ets_recvErr   = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
424 				+ lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR)
425 				+ lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE);
426 	stats.ets_sendErr   = 0;
427 	stats.ets_OVW       = 0;
428 	stats.ets_CRCerr    = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
429 	stats.ets_frameAll  = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
430 	stats.ets_missedP   = 0;
431 	stats.ets_packetR   = lan8710a_reg_read(CPSW_STAT_RX_GOOD);
432 	stats.ets_packetT   = lan8710a_reg_read(CPSW_STAT_TX_GOOD);
433 	stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
434 	stats.ets_transAb   = 0;
435 	stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR);
436 	stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN);
437 	stats.ets_fifoOver  = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN);
438 	stats.ets_CDheartbeat = 0;
439 	stats.ets_OWC = 0;
440 
441 	sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
442 		(vir_bytes)&stats, sizeof(stats));
443 	mp->m_type  = DL_STAT_REPLY;
444 
445 	if ((r=ipc_send(mp->m_source, mp)) != OK) {
446 		panic("lan8710a_getstat: ipc_send() failed: %d", r);
447 	}
448 }
449 
450 /*============================================================================*
451  *				lan8710a_stop				      *
452  *============================================================================*/
453 static void
454 lan8710a_stop(void)
455 {
456 	/* Reset hardware. */
457 	lan8710a_reset_hw();
458 
459 	/* Exit driver. */
460 	exit(EXIT_SUCCESS);
461 }
462 
463 /*============================================================================*
464  *				lan8710a_dma_config_tx			      *
465  *============================================================================*/
466 static void
467 lan8710a_dma_config_tx(desc_idx)
468 u8_t desc_idx;
469 {
470 	phys_bytes phys_addr;
471 	int i;
472 	for (i = 0; i < TX_DMA_CHANNELS; ++i) {
473 		if (!lan8710a_reg_read(CPDMA_STRAM_TX_HDP(i))) break;
474 	}
475 	if (i == TX_DMA_CHANNELS) {
476 		panic("There are no free TX DMA channels.");
477 	}
478 
479 	/* Enabling only one channel Tx interrupt */
480 	lan8710a_reg_write(CPDMA_TX_INTMASK_SET, 1 << i);
481 	/* Routing only one channel Tx int to TX_PULSE signal */
482 	lan8710a_reg_write(CPSW_WR_C0_TX_EN, 1 << i);
483 
484 	/* Setting HDP */
485 	phys_addr = lan8710a_state.tx_desc_phy +
486 					(desc_idx * sizeof(lan8710a_desc_t));
487 	lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), (u32_t)phys_addr);
488 }
489 
490 /*============================================================================*
491  *				lan8710a_dma_reset_init			      *
492  *============================================================================*/
493 static void
494 lan8710a_dma_reset_init(void)
495 {
496 	int i;
497 	lan8710a_reg_write(CPDMA_SOFT_RESET, SOFT_RESET);
498 	while ((lan8710a_reg_read(CPDMA_SOFT_RESET) & SOFT_RESET));
499 
500 	/*
501 	 * Initialize the HDPs (Header Description Pointers) and
502 	 * CPs (Completion Pointers) to NULL.
503 	 */
504 	for (i = 0; i < DMA_MAX_CHANNELS; ++i) {
505 		lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), 0);
506 		lan8710a_reg_write(CPDMA_STRAM_RX_HDP(i), 0);
507 		lan8710a_reg_write(CPDMA_STRAM_TX_CP(i), 0);
508 		lan8710a_reg_write(CPDMA_STRAM_RX_CP(i), 0);
509 	}
510 
511 	lan8710a_reg_write(CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
512 	lan8710a_reg_write(CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
513 
514 	/* Configure the CPDMA controller. */
515 	lan8710a_reg_set(CPDMA_RX_CONTROL, CPDMA_RX_EN); /* RX Enabled */
516 	lan8710a_reg_set(CPDMA_TX_CONTROL, CPDMA_TX_EN); /* TX Enabled */
517 
518 	/* Enabling first channel Rx interrupt */
519 	lan8710a_reg_set(CPDMA_RX_INTMASK_SET, CPDMA_FIRST_CHAN_INT);
520 
521 	/*
522 	 * Writing the address of the first buffer descriptor in the queue
523 	 * (nonzero value)to the channel�s head descriptor pointer in the
524 	 * channel�s Rx DMA state.
525 	 */
526 	lan8710a_reg_write(CPDMA_STRAM_RX_HDP(0),
527 			  (u32_t)lan8710a_state.rx_desc_phy);
528 
529 	lan8710a_state.rx_desc_idx = 0;
530 	lan8710a_state.tx_desc_idx = 0;
531 }
532 
533 /*============================================================================*
534  *				lan8710a_init_desc			      *
535  *============================================================================*/
536 static void
537 lan8710a_init_desc(void)
538 {
539 	lan8710a_desc_t *p_rx_desc;
540 	lan8710a_desc_t *p_tx_desc;
541 	phys_bytes   buf_phys_addr;
542 	u8_t *p_buf;
543 	u8_t i;
544 
545 	/* Attempt to allocate. */
546 	if ((lan8710a_state.p_rx_buf = alloc_contig((LAN8710A_NUM_RX_DESC
547 			* LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
548 			&buf_phys_addr)) == NULL) {
549 		panic("failed to allocate RX buffers.");
550 	}
551 	p_buf = lan8710a_state.p_rx_buf;
552 	for (i = 0; i < LAN8710A_NUM_RX_DESC; i++) {
553 		p_rx_desc = &(lan8710a_state.rx_desc[i]);
554 		memset(p_rx_desc, 0x0, sizeof(lan8710a_desc_t));
555 		p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
556 		p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
557 		p_rx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
558 						(i * LAN8710A_IOBUF_SIZE));
559 
560 		p_rx_desc->next_pointer =
561 		   (u32_t)((i == (LAN8710A_NUM_RX_DESC - 1)) ?
562 			   (lan8710a_state.rx_desc_phy) :
563 			   (lan8710a_state.rx_desc_phy +
564 			     ((i + 1) * sizeof(lan8710a_desc_t))));
565 	}
566 
567 	/* Attempt to allocate. */
568 	if ((lan8710a_state.p_tx_buf = alloc_contig((LAN8710A_NUM_TX_DESC
569 			* LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
570 			&buf_phys_addr)) == NULL) {
571 		panic("failed to allocate TX buffers");
572 	}
573 	p_buf = lan8710a_state.p_tx_buf;
574 	for (i = 0; i < LAN8710A_NUM_TX_DESC; i++) {
575 		p_tx_desc = &(lan8710a_state.tx_desc[i]);
576 		memset(p_tx_desc, 0x0, sizeof(lan8710a_desc_t));
577 		p_tx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
578 				(i * LAN8710A_IOBUF_SIZE));
579 	}
580 	lan8710a_state.rx_desc_idx = 0;
581 	lan8710a_state.tx_desc_idx = 0;
582 }
583 
584 /*============================================================================*
585  *				lan8710a_init_hw			      *
586  *============================================================================*/
587 static int
588 lan8710a_init_hw(void)
589 {
590 	int r, i;
591 
592 	lan8710a_state.status |= LAN8710A_ENABLED;
593 
594 	/*
595 	 * Set the interrupt handler and policy. Do not automatically
596 	 * re-enable interrupts. Return the IRQ line number on interrupts.
597 	 */
598 	lan8710a_state.irq_rx_hook = RX_INT;
599 	if ((r = sys_irqsetpolicy(LAN8710A_RX_INTR, 0,
600 					&lan8710a_state.irq_rx_hook)) != OK) {
601 		panic("sys_irqsetpolicy failed: %d", r);
602 	}
603 	lan8710a_state.irq_tx_hook = TX_INT;
604 	if ((r = sys_irqsetpolicy(LAN8710A_TX_INTR, 0,
605 					&lan8710a_state.irq_tx_hook)) != OK) {
606 		panic("sys_irqsetpolicy failed: %d", r);
607 	}
608 
609 	/* Reset hardware. */
610 	lan8710a_reset_hw();
611 
612 	/*
613 	 * Select the Interface (GMII/RGMII/MII) Mode in the Control Module.
614 	 * Port1 GMII/MII Mode, Port2 not used.
615 	 */
616 	lan8710a_reg_write(GMII_SEL, (GMII2_SEL_BIT1 | GMII2_SEL_BIT0));
617 
618 	/*
619 	 * Configure pads (PIN muxing) as per the Interface Selected using the
620 	 * appropriate pin muxing conf_xxx registers in the Control Module.
621 	 *
622 	 * CONF_MOD_SLEW_CTRL when 0 - Fast Mode, when 1 - Slow Mode
623 	 * CONF_MOD_RX_ACTIVE when 0 - Only output, when 1 - Also input
624 	 * CONF_MOD_PU_TYPESEL when 0 - Pull-down, when 1 - Pull-up
625 	 * CONF_MOD_PUDEN when 0 Pull* enabled, when 1 Pull* disabled
626 	 * CONF_MOD_MMODE_MII selects pin to work for MII interface
627 	 */
628 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_SLEW_CTRL);
629 	lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_RX_ACTIVE);
630 	lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_PU_TYPESEL);
631 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_PUDEN);
632 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_MMODE_MII);
633 
634 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_SLEW_CTRL);
635 	lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_RX_ACTIVE);
636 	lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_PU_TYPESEL);
637 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_PUDEN);
638 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_MMODE_MII);
639 
640 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_SLEW_CTRL);
641 	lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_RX_ACTIVE);
642 	lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_PU_TYPESEL);
643 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_PUDEN);
644 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_MMODE_MII);
645 
646 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_SLEW_CTRL);
647 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_RX_ACTIVE);
648 	lan8710a_reg_set(CONF_MII1_TX_EN, CONF_MOD_PUDEN);
649 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_MMODE_MII);
650 
651 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_SLEW_CTRL);
652 	lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_RX_ACTIVE);
653 	lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_PU_TYPESEL);
654 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_PUDEN);
655 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_MMODE_MII);
656 
657 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_SLEW_CTRL);
658 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_RX_ACTIVE);
659 	lan8710a_reg_set(CONF_MII1_TXD3, CONF_MOD_PUDEN);
660 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_MMODE_MII);
661 
662 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_SLEW_CTRL);
663 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_RX_ACTIVE);
664 	lan8710a_reg_set(CONF_MII1_TXD2, CONF_MOD_PUDEN);
665 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_MMODE_MII);
666 
667 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_SLEW_CTRL);
668 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_RX_ACTIVE);
669 	lan8710a_reg_set(CONF_MII1_TXD1, CONF_MOD_PUDEN);
670 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_MMODE_MII);
671 
672 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_SLEW_CTRL);
673 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_RX_ACTIVE);
674 	lan8710a_reg_set(CONF_MII1_TXD0, CONF_MOD_PUDEN);
675 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_MMODE_MII);
676 
677 	lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_SLEW_CTRL);
678 	lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_RX_ACTIVE);
679 	lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_PUDEN);
680 	lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_MMODE_MII);
681 
682 	lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_SLEW_CTRL);
683 	lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_RX_ACTIVE);
684 	lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_PUDEN);
685 	lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_MMODE_MII);
686 
687 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_SLEW_CTRL);
688 	lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_RX_ACTIVE);
689 	lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_PU_TYPESEL);
690 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_PUDEN);
691 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_MMODE_MII);
692 
693 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_SLEW_CTRL);
694 	lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_RX_ACTIVE);
695 	lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_PU_TYPESEL);
696 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_PUDEN);
697 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_MMODE_MII);
698 
699 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_SLEW_CTRL);
700 	lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_RX_ACTIVE);
701 	lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_PU_TYPESEL);
702 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_PUDEN);
703 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_MMODE_MII);
704 
705 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_SLEW_CTRL);
706 	lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_RX_ACTIVE);
707 	lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_PU_TYPESEL);
708 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_PUDEN);
709 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_MMODE_MII);
710 
711 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_SLEW_CTRL);
712 	lan8710a_reg_set(CONF_MDIO, CONF_MOD_RX_ACTIVE);
713 	lan8710a_reg_set(CONF_MDIO, CONF_MOD_PU_TYPESEL);
714 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_PUDEN);
715 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_MMODE_MII);
716 
717 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_SLEW_CTRL);
718 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_RX_ACTIVE);
719 	lan8710a_reg_set(CONF_MDC, CONF_MOD_PUDEN);
720 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_MMODE_MII);
721 
722 	/* Apply soft reset to 3PSW Subsytem, CPSW_3G, CPGMAC_SL, and CPDMA. */
723 	lan8710a_reg_write(CPSW_SS_SOFT_RESET, SOFT_RESET);
724 	lan8710a_reg_write(CPSW_SL_SOFT_RESET(1), SOFT_RESET);
725 	lan8710a_reg_write(CPSW_SL_SOFT_RESET(2), SOFT_RESET);
726 
727 	/* Wait for software resets completion */
728 	while ((lan8710a_reg_read(CPSW_SS_SOFT_RESET) & SOFT_RESET) ||
729 		(lan8710a_reg_read(CPSW_SL_SOFT_RESET(1)) & SOFT_RESET) ||
730 		(lan8710a_reg_read(CPSW_SL_SOFT_RESET(2)) & SOFT_RESET));
731 
732 	/* Configure the Statistics Port Enable register. */
733 	/* Enable port 0 and 1 statistics. */
734 	lan8710a_reg_write(CPSW_SS_STAT_PORT_EN, (CPSW_P1_STAT_EN |
735 							CPSW_P0_STAT_EN));
736 
737 	/*
738 	 * Configure the ALE.
739 	 * Enabling Ale.
740 	 * All packets received on ports 1 are
741 	 * sent to the host (only to the host).
742 	 */
743 	lan8710a_reg_write(CPSW_ALE_CONTROL, (CPSW_ALE_ENABLE |
744 						CPSW_ALE_BYPASS));
745 	/* Port 0 (host) in forwarding mode. */
746 	lan8710a_reg_write(CPSW_ALE_PORTCTL0, CPSW_ALE_PORT_FWD);
747 	/* Port 1 in forwarding mode. */
748 	lan8710a_reg_write(CPSW_ALE_PORTCTL1, CPSW_ALE_PORT_FWD);
749 
750 	/*
751 	 * Configure CPSW_SL Register
752 	 * Full duplex mode.
753 	 */
754 	lan8710a_reg_write(CPSW_SL_MACCONTROL(1), CPSW_SL_FULLDUPLEX);
755 
756 	/* Initialize MDIO Protocol */
757 	lan8710a_init_mdio();
758 
759 	/* Getting MAC Address */
760 	lan8710a_init_addr();
761 
762 	/* Initialize descriptors */
763 	lan8710a_init_desc();
764 
765 	/* Reset and initialize CPDMA */
766 	lan8710a_dma_reset_init();
767 
768 	/*
769 	 * Configure the Interrupts.
770 	 * Routing all channel Rx int to RX_PULSE signal.
771 	 */
772 	lan8710a_reg_set(CPSW_WR_C0_RX_EN, CPSW_FIRST_CHAN_INT);
773 
774 	/*
775 	 * Enabling LAN8710A Auto-negotiation
776 	 */
777 	lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_AUTO_NEG);
778 
779 	/* Waiting for auto-negotiaion completion. */
780 	for (i = 0; !(lan8710a_phy_read(LAN8710A_STATUS_REG) &
781 					LAN8710A_AUTO_NEG_COMPL); ++i) {
782 		if (i == 100) {
783 			LAN8710A_DEBUG_PRINT(("Autonegotiation failed"));
784 			break;
785 		}
786 		tickdelay(100);
787 	}
788 
789 	/* GMII RX and TX release from reset. */
790 	lan8710a_reg_set(CPSW_SL_MACCONTROL(1), CPSW_SL_GMII_EN);
791 
792 	/* Enable interrupts. */
793 	lan8710a_enable_interrupt(RX_INT | TX_INT);
794 
795 	return TRUE;
796 }
797 
798 /*============================================================================*
799  *				lan8710a_init_mdio			      *
800  *============================================================================*/
801 static void
802 lan8710a_init_mdio(void)
803 {
804 	u16_t address = 0;
805 	u32_t r;
806 
807 	/* Clearing MDIOCONTROL register */
808 	lan8710a_reg_write(MDIOCONTROL, 0);
809 	/* Configure the PREAMBLE and CLKDIV in the MDIO control register */
810 	lan8710a_reg_unset(MDIOCONTROL, MDIO_PREAMBLE); /* CLKDIV default */
811 	/* Enable sending MDIO frame preambles */
812 	lan8710a_reg_set(MDIOCONTROL, (MDCLK_DIVIDER | MDIO_ENABLE));
813 	/* Enable the MDIO module by setting the ENABLE bit in MDIOCONTROL */
814 
815 	while (!(r = lan8710a_reg_read(MDIOALIVE)));
816 
817 	/* Get PHY address */
818 	while (r >>= 1) {
819 		++address;
820 	}
821 	lan8710a_state.phy_address = address;
822 
823 	/* Setup appropiate address in MDIOUSERPHYSEL0 */
824 	lan8710a_reg_set(MDIOUSERPHYSEL0, address);
825 }
826 
827 /*============================================================================*
828  *				lan8710a_writev_s			      *
829  *============================================================================*/
830 static void
831 lan8710a_writev_s(mp, from_int)
832 message *mp;
833 int from_int;
834 {
835 	iovec_s_t iovec[LAN8710A_IOVEC_NR];
836 	lan8710a_t *e = &lan8710a_state;
837 	lan8710a_desc_t *p_tx_desc;
838 	u8_t *p_buf;
839 	int r, size, buf_data_len, i;
840 
841 	/* Are we called from the interrupt handler? */
842 	if (!from_int) {
843 		/* We cannot write twice simultaneously. */
844 		assert(!(e->status & LAN8710A_WRITING));
845 
846 		/* Copy write message. */
847 		e->tx_message = *mp;
848 		e->client = mp->m_source;
849 		e->status |= LAN8710A_WRITING;
850 
851 		/* verify vector count */
852 		assert(mp->m_net_netdrv_dl_writev_s.count > 0);
853 		assert(mp->m_net_netdrv_dl_writev_s.count < LAN8710A_IOVEC_NR);
854 
855 		/*
856 		 * Copy the I/O vector table.
857 		 */
858 		if ((r = sys_safecopyfrom(mp->m_source,
859 				mp->m_net_netdrv_dl_writev_s.grant, 0,
860 				(vir_bytes) iovec,
861 				mp->m_net_netdrv_dl_writev_s.count *
862 				sizeof(iovec_s_t))) != OK) {
863 			panic("sys_safecopyfrom() failed: %d", r);
864 		}
865 		/* setup descriptors */
866 		p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
867 
868 		/*
869 		 * Check if descriptor is available for host
870 		 * and drop the packet if not.
871 		 */
872 		if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) {
873 			panic("No available transmit descriptor.");
874 		}
875 
876 		/* virtual address of buffer */
877 		p_buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE;
878 		buf_data_len = 0;
879 		for (i = 0; i < mp->m_net_netdrv_dl_writev_s.count; i++) {
880 			if ((buf_data_len + iovec[i].iov_size)
881 			     > LAN8710A_IOBUF_SIZE) {
882 				panic("packet too long");
883 			}
884 
885 			/* copy data to buffer */
886 			size = iovec[i].iov_size
887 				< (LAN8710A_IOBUF_SIZE - buf_data_len) ?
888 				    iovec[i].iov_size
889 				    : (LAN8710A_IOBUF_SIZE - buf_data_len);
890 
891 			/* Copy bytes to TX queue buffers. */
892 			if ((r = sys_safecopyfrom(mp->m_source,
893 					iovec[i].iov_grant, 0,
894 					(vir_bytes) p_buf, size)) != OK) {
895 				panic("sys_safecopyfrom() failed: %d", r);
896 			}
897 			p_buf += size;
898 			buf_data_len += size;
899 		}
900 
901 		/* set descriptor length */
902 		p_tx_desc->buffer_length_off = buf_data_len;
903 		/* set flags */
904 		p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN |
905 						LAN8710A_DESC_FLAG_SOP |
906 						LAN8710A_DESC_FLAG_EOP |
907 						TX_DESC_TO_PORT1 |
908 						TX_DESC_TO_PORT_EN);
909 		p_tx_desc->pkt_len_flags |= buf_data_len;
910 
911 		/* setup DMA transfer */
912 		lan8710a_dma_config_tx(e->tx_desc_idx);
913 
914 		e->tx_desc_idx++;
915 		if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) {
916 			e->tx_desc_idx = 0;
917 		}
918 	} else {
919 		e->status |= LAN8710A_TRANSMIT;
920 	}
921 	reply(e);
922 }
923 
924 /*============================================================================*
925  *				lan8710a_readv_s			      *
926  *============================================================================*/
927 static void
928 lan8710a_readv_s(mp, from_int)
929 message *mp;
930 int from_int;
931 {
932 	iovec_s_t iovec[LAN8710A_IOVEC_NR];
933 	lan8710a_t *e = &lan8710a_state;
934 	lan8710a_desc_t *p_rx_desc;
935 	u32_t  flags;
936 	u8_t *p_buf;
937 	u16_t pkt_data_len;
938 	u16_t buf_bytes, buf_len;
939 	int i, r, size;
940 
941 	/* Are we called from the interrupt handler? */
942 	if (!from_int) {
943 		e->rx_message = *mp;
944 		e->client = mp->m_source;
945 		e->status |= LAN8710A_READING;
946 		e->rx_size = 0;
947 
948 		assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0);
949 		assert(e->rx_message.m_net_netdrv_dl_readv_s.count < LAN8710A_IOVEC_NR);
950 	}
951 	if (e->status & LAN8710A_READING) {
952 		/*
953 		 * Copy the I/O vector table first.
954 		 */
955 		if ((r = sys_safecopyfrom(e->rx_message.m_source,
956 				e->rx_message.m_net_netdrv_dl_readv_s.grant, 0,
957 				(vir_bytes) iovec,
958 				e->rx_message.m_net_netdrv_dl_readv_s.count *
959 				    sizeof(iovec_s_t))) != OK) {
960 			panic("sys_safecopyfrom() failed: %d", r);
961 		}
962 
963 		/*
964 		 * Only handle one packet at a time.
965 		 */
966 		p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
967 		/* find next OWN descriptor with SOP flag */
968 		while ((0 == (LAN8710A_DESC_FLAG_SOP &
969 					p_rx_desc->pkt_len_flags)) &&
970 				(0 == (LAN8710A_DESC_FLAG_OWN &
971 					p_rx_desc->pkt_len_flags))) {
972 			p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
973 			/* set ownership of current descriptor to EMAC */
974 			p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
975 
976 			e->rx_desc_idx++;
977 			if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
978 				e->rx_desc_idx = 0;
979 			p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
980 		}
981 		if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) {
982 			/* SOP was not found */
983 			reply(e);
984 			return;
985 		}
986 
987 		/*
988 		 * Copy to vector elements.
989 		 */
990 		pkt_data_len = 0;
991 		buf_bytes = 0;
992 		p_buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE;
993 		for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count; i++) {
994 			buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
995 			if (buf_bytes == buf_len) {
996 				/* Whole buffer move to the next descriptor */
997 				p_rx_desc->buffer_length_off =
998 							LAN8710A_IOBUF_SIZE;
999 				/* set ownership of current desc to EMAC */
1000 				p_rx_desc->pkt_len_flags =
1001 							LAN8710A_DESC_FLAG_OWN;
1002 				buf_bytes = 0;
1003 
1004 				e->rx_desc_idx++;
1005 				if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
1006 					e->rx_desc_idx = 0;
1007 				p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
1008 				p_buf = e->p_rx_buf + (e->rx_desc_idx *
1009 					    LAN8710A_IOBUF_SIZE) +
1010 					    (p_rx_desc->buffer_length_off >> 16);
1011 				buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
1012 			}
1013 			size = iovec[i].iov_size < (buf_len - buf_bytes) ?
1014 				   iovec[i].iov_size :
1015 				   (buf_len - buf_bytes);
1016 
1017 			if ((r = sys_safecopyto(e->rx_message.m_source,
1018 						iovec[i].iov_grant, 0,
1019 						(vir_bytes) p_buf,
1020 						size)) != OK) {
1021 				panic("sys_safecopyto() failed: %d", r);
1022 			}
1023 			p_buf += size;
1024 			buf_bytes += size;
1025 			pkt_data_len += size;
1026 
1027 			/* if EOP flag is set -> stop processing */
1028 			if ((LAN8710A_DESC_FLAG_EOP & p_rx_desc->pkt_len_flags) &&
1029 							(buf_bytes == buf_len)) {
1030 				/* end of packet */
1031 				break;
1032 			}
1033 		}
1034 		do {
1035 			/* reset owned descriptors up to EOP flag */
1036 			flags = p_rx_desc->pkt_len_flags;
1037 			p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
1038 			/* set ownership of current descriptor to EMAC */
1039 			p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
1040 
1041 			e->rx_desc_idx++;
1042 			if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
1043 				e->rx_desc_idx = 0;
1044 
1045 			p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
1046 		}
1047 		while (0 == (flags & LAN8710A_DESC_FLAG_EOP));
1048 
1049 		/*
1050 		 * Update state.
1051 		 */
1052 		e->status |= LAN8710A_RECEIVED;
1053 		e->rx_size = pkt_data_len;
1054 
1055 	}
1056 	reply(e);
1057 }
1058 
1059 /*============================================================================*
1060  *				lan8710a_phy_write			      *
1061  *============================================================================*/
1062 static void
1063 lan8710a_phy_write(reg, value)
1064 u32_t reg;
1065 u32_t value;
1066 {
1067 	if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
1068 		/* Clearing MDIOUSERACCESS0 register */
1069 		lan8710a_reg_write(MDIOUSERACCESS0, 0);
1070 		/* Setting proper values in MDIOUSERACCESS0 */
1071 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_WRITE);
1072 		lan8710a_reg_set(MDIOUSERACCESS0, reg << MDIO_REGADR);
1073 		lan8710a_reg_set(MDIOUSERACCESS0,
1074 				lan8710a_state.phy_address << MDIO_PHYADR);
1075 		/* Data written only 16 bits. */
1076 		lan8710a_reg_set(MDIOUSERACCESS0, (value & 0xFFFF) << MDIO_DATA);
1077 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
1078 
1079 		/* Waiting for writing completion */
1080 		while (lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO);
1081 	}
1082 }
1083 
1084 /*============================================================================*
1085  *				lan8710a_phy_read			      *
1086  *============================================================================*/
1087 static u32_t
1088 lan8710a_phy_read(reg)
1089 u32_t reg;
1090 {
1091 	u32_t value = 0xFFFFFFFF;
1092 
1093 	if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
1094 		/* Clearing MDIOUSERACCESS0 register */
1095 		lan8710a_reg_write(MDIOUSERACCESS0, 0);
1096 		/* Setting proper values in MDIOUSERACCESS0 */
1097 		lan8710a_reg_unset(MDIOUSERACCESS0, MDIO_WRITE);
1098 		/* Reg number must be 5 bit long */
1099 		lan8710a_reg_set(MDIOUSERACCESS0, (reg & 0x1F) << MDIO_REGADR);
1100 		/* Addr must be 5 bit long */
1101 		lan8710a_reg_set(MDIOUSERACCESS0,
1102 			(lan8710a_state.phy_address & 0x1F) << MDIO_PHYADR);
1103 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
1104 
1105 		/* Waiting for reading completion */
1106 		while ((lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)
1107 			&& !(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_ACK));
1108 
1109 		/* Reading data */
1110 		value = lan8710a_reg_read(MDIOUSERACCESS0) & 0xFFFF;
1111 	}
1112 	return value;
1113 }
1114 
1115 /*============================================================================*
1116  *				lan8710a_reset_hw			      *
1117  *============================================================================*/
1118 static void
1119 lan8710a_reset_hw()
1120 {
1121 	/* Assert a Device Reset signal. */
1122 	lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET);
1123 
1124 	/* Waiting for reset completion. */
1125 	while (lan8710a_phy_read(LAN8710A_CTRL_REG) & LAN8710A_SOFT_RESET);
1126 }
1127 
1128 /*============================================================================*
1129  *				lan8710a_reg_read			      *
1130  *============================================================================*/
1131 static u32_t
1132 lan8710a_reg_read(reg)
1133 volatile u32_t *reg;
1134 {
1135 	u32_t value;
1136 
1137 	/* Read from memory mapped register. */
1138 	value = *reg;
1139 
1140 	/* Return the result. */
1141 	return value;
1142 }
1143 
1144 /*============================================================================*
1145  *				lan8710a_reg_write			      *
1146  *============================================================================*/
1147 static void
1148 lan8710a_reg_write(reg, value)
1149 volatile u32_t *reg;
1150 u32_t value;
1151 {
1152 	/* Write to memory mapped register. */
1153 	*reg = value;
1154 }
1155 
1156 /*============================================================================*
1157  *				lan8710a_reg_set			      *
1158  *============================================================================*/
1159 static void
1160 lan8710a_reg_set(reg, value)
1161 volatile u32_t *reg;
1162 u32_t value;
1163 {
1164 	u32_t data;
1165 
1166 	/* First read the current value. */
1167 	data = lan8710a_reg_read(reg);
1168 
1169 	/* Set value, and write back. */
1170 	lan8710a_reg_write(reg, data | value);
1171 }
1172 
1173 /*============================================================================*
1174  *				lan8710a_reg_unset			      *
1175  *============================================================================*/
1176 static void
1177 lan8710a_reg_unset(reg, value)
1178 volatile u32_t *reg;
1179 u32_t value;
1180 {
1181 	u32_t data;
1182 
1183 	/* First read the current value. */
1184 	data = lan8710a_reg_read(reg);
1185 
1186 	/* Unset value, and write back. */
1187 	lan8710a_reg_write(reg, data & ~value);
1188 }
1189 
1190 /*============================================================================*
1191  *				mess_reply				      *
1192  *============================================================================*/
1193 static void
1194 mess_reply(req, reply)
1195 message *req;message *reply;
1196 {
1197 	if (ipc_send(req->m_source, reply) != OK) {
1198 		panic("unable to send reply message");
1199 	}
1200 }
1201 
1202 /*============================================================================*
1203  *				reply					      *
1204  *============================================================================*/
1205 static void
1206 reply(e)
1207 lan8710a_t *e;
1208 {
1209 	message msg;
1210 	int r;
1211 
1212 	/* Only reply to client for read/write request. */
1213 	if (!(e->status & LAN8710A_READING ||
1214 			e->status & LAN8710A_WRITING)) {
1215 		return;
1216 	}
1217 	/* Construct reply message. */
1218 	msg.m_type   = DL_TASK_REPLY;
1219 	msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
1220 	msg.m_netdrv_net_dl_task.count = 0;
1221 
1222 	/* Did we successfully receive packet(s)? */
1223 	if (e->status & LAN8710A_READING &&
1224 	e->status & LAN8710A_RECEIVED) {
1225 		msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV;
1226 		msg.m_netdrv_net_dl_task.count =
1227 			 e->rx_size >= ETH_MIN_PACK_SIZE ?
1228 				e->rx_size : ETH_MIN_PACK_SIZE;
1229 
1230 		/* Clear flags. */
1231 		e->status &= ~(LAN8710A_READING | LAN8710A_RECEIVED);
1232 	}
1233 	/* Did we successfully transmit packet(s)? */
1234 	if (e->status & LAN8710A_TRANSMIT &&
1235 		e->status & LAN8710A_WRITING) {
1236 		msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND;
1237 
1238 		/* Clear flags. */
1239 		e->status &= ~(LAN8710A_WRITING | LAN8710A_TRANSMIT);
1240 	}
1241 
1242 	/* Acknowledge to INET. */
1243 	if ((r = ipc_send(e->client, &msg) != OK)) {
1244 		panic("ipc_send() failed: %d", r);
1245 	}
1246 }
1247