1 /*
2  * Copyright (c) 2017-2018 ARM Limited
3  * Copyright (c) 2018 Linaro Limited
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT smsc_lan9220
9 
10 /* SMSC911x/SMSC9220 driver. Partly based on mbedOS driver. */
11 
12 #define LOG_MODULE_NAME eth_smsc911x
13 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
17 
18 #include <soc.h>
19 #include <zephyr/device.h>
20 #include <errno.h>
21 #include <zephyr/init.h>
22 #include <zephyr/kernel.h>
23 #include <zephyr/sys/__assert.h>
24 #include <zephyr/net/net_core.h>
25 #include <zephyr/net/net_pkt.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <zephyr/sys/sys_io.h>
30 #include <zephyr/net/ethernet.h>
31 #include <zephyr/irq.h>
32 #include "ethernet/eth_stats.h"
33 
34 #ifdef CONFIG_SHARED_IRQ
35 #include <zephyr/shared_irq.h>
36 #endif
37 
38 #include "eth_smsc911x_priv.h"
39 
40 #define RESET_TIMEOUT     10
41 #define PHY_RESET_TIMEOUT K_MSEC(100)
42 #define REG_WRITE_TIMEOUT 50
43 
44 /* Controller has only one PHY with address 1 */
45 #define PHY_ADDR 1
46 
47 struct eth_context {
48 	struct net_if *iface;
49 	uint8_t mac[6];
50 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
51 	struct net_stats_eth stats;
52 #endif
53 };
54 
55 /* SMSC911x helper functions */
56 
smsc_mac_regread(uint8_t reg,uint32_t * val)57 static int smsc_mac_regread(uint8_t reg, uint32_t *val)
58 {
59 	uint32_t cmd = MAC_CSR_CMD_BUSY | MAC_CSR_CMD_READ | reg;
60 
61 	SMSC9220->MAC_CSR_CMD = cmd;
62 
63 	while ((SMSC9220->MAC_CSR_CMD & MAC_CSR_CMD_BUSY) != 0) {
64 	}
65 
66 	*val = SMSC9220->MAC_CSR_DATA;
67 
68 	return 0;
69 }
70 
smsc_mac_regwrite(uint8_t reg,uint32_t val)71 static int smsc_mac_regwrite(uint8_t reg, uint32_t val)
72 {
73 	uint32_t cmd = MAC_CSR_CMD_BUSY | MAC_CSR_CMD_WRITE | reg;
74 
75 	SMSC9220->MAC_CSR_DATA = val;
76 
77 	SMSC9220->MAC_CSR_CMD = cmd;
78 
79 	while ((SMSC9220->MAC_CSR_CMD & MAC_CSR_CMD_BUSY) != 0) {
80 	}
81 
82 	return 0;
83 }
84 
smsc_phy_regread(uint8_t regoffset,uint32_t * data)85 int smsc_phy_regread(uint8_t regoffset, uint32_t *data)
86 {
87 	uint32_t val = 0U;
88 	uint32_t phycmd = 0U;
89 	unsigned int time_out = REG_WRITE_TIMEOUT;
90 
91 	if (smsc_mac_regread(SMSC9220_MAC_MII_ACC, &val) < 0) {
92 		return -1;
93 	}
94 
95 	if (val & MAC_MII_ACC_MIIBZY) {
96 		*data = 0U;
97 		return -EBUSY;
98 	}
99 
100 	phycmd = 0U;
101 	phycmd |= PHY_ADDR << 11;
102 	phycmd |= (regoffset & 0x1F) << 6;
103 	phycmd |= MAC_MII_ACC_READ;
104 	phycmd |= MAC_MII_ACC_MIIBZY; /* Operation start */
105 
106 	if (smsc_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd)) {
107 		return -1;
108 	}
109 
110 	val = 0U;
111 	do {
112 		k_sleep(K_MSEC(1));
113 		time_out--;
114 		if (smsc_mac_regread(SMSC9220_MAC_MII_ACC, &val)) {
115 			return -1;
116 		}
117 	} while (time_out != 0U && (val & MAC_MII_ACC_MIIBZY));
118 
119 	if (time_out == 0U) {
120 		return -ETIMEDOUT;
121 	}
122 
123 	if (smsc_mac_regread(SMSC9220_MAC_MII_DATA, data) < 0) {
124 		return -1;
125 	}
126 
127 	return 0;
128 }
129 
smsc_phy_regwrite(uint8_t regoffset,uint32_t data)130 int smsc_phy_regwrite(uint8_t regoffset, uint32_t data)
131 {
132 	uint32_t val = 0U;
133 	uint32_t phycmd = 0U;
134 	unsigned int time_out = REG_WRITE_TIMEOUT;
135 
136 	if (smsc_mac_regread(SMSC9220_MAC_MII_ACC, &val) < 0) {
137 		return -1;
138 	}
139 
140 	if (val & MAC_MII_ACC_MIIBZY) {
141 		return -EBUSY;
142 	}
143 
144 	if (smsc_mac_regwrite(SMSC9220_MAC_MII_DATA, data & 0xFFFF) < 0) {
145 		return -1;
146 	}
147 
148 	phycmd |= PHY_ADDR << 11;
149 	phycmd |= (regoffset & 0x1F) << 6;
150 	phycmd |= MAC_MII_ACC_WRITE;
151 	phycmd |= MAC_MII_ACC_MIIBZY; /* Operation start */
152 
153 	if (smsc_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd) < 0) {
154 		return -1;
155 	}
156 
157 	do {
158 		k_sleep(K_MSEC(1));
159 		time_out--;
160 		if (smsc_mac_regread(SMSC9220_MAC_MII_ACC, &phycmd)) {
161 			return -1;
162 		}
163 	} while (time_out != 0U && (phycmd & MAC_MII_ACC_MIIBZY));
164 
165 	if (time_out == 0U) {
166 		return -ETIMEDOUT;
167 	}
168 
169 	return 0;
170 }
171 
smsc_read_mac_address(uint8_t * mac)172 static int smsc_read_mac_address(uint8_t *mac)
173 {
174 	uint32_t tmp;
175 	int res;
176 
177 	res = smsc_mac_regread(SMSC9220_MAC_ADDRL, &tmp);
178 	if (res < 0) {
179 		return res;
180 	}
181 
182 	mac[0] = (uint8_t)(tmp >> 0);
183 	mac[1] = (uint8_t)(tmp >> 8);
184 	mac[2] = (uint8_t)(tmp >> 16);
185 	mac[3] = (uint8_t)(tmp >> 24);
186 
187 	res = smsc_mac_regread(SMSC9220_MAC_ADDRH, &tmp);
188 	if (res < 0) {
189 		return res;
190 	}
191 
192 	mac[4] = (uint8_t)(tmp >> 0);
193 	mac[5] = (uint8_t)(tmp >> 8);
194 
195 	return 0;
196 }
197 
smsc_check_id(void)198 static int smsc_check_id(void)
199 {
200 	uint32_t id = SMSC9220->ID_REV;
201 
202 	/* If bottom and top halves of the word are the same,
203 	 * the hardware is (likely) not present.
204 	 */
205 	if (((id >> 16) & 0xFFFF) == (id & 0xFFFF)) {
206 		return -1;
207 	}
208 
209 	switch (((id >> 16) & 0xFFFF)) {
210 	case 0x9220: /* SMSC9220 on MPS2 */
211 	case 0x0118: /* SMS9118 as emulated by QEMU */
212 		break;
213 
214 	default:
215 		return -1;
216 	}
217 
218 	return 0;
219 }
220 
smsc_soft_reset(void)221 static int smsc_soft_reset(void)
222 {
223 	unsigned int time_out = RESET_TIMEOUT;
224 
225 	SMSC9220->HW_CFG |= HW_CFG_SRST;
226 
227 	do {
228 		k_sleep(K_MSEC(1));
229 		time_out--;
230 	} while (time_out != 0U && (SMSC9220->HW_CFG & HW_CFG_SRST));
231 
232 	if (time_out == 0U) {
233 		return -1;
234 	}
235 
236 	return 0;
237 }
238 
smsc_set_txfifo(unsigned int val)239 void smsc_set_txfifo(unsigned int val)
240 {
241 	/* 2kb minimum, 14kb maximum */
242 	if (val >= 2U && val <= 14U) {
243 		SMSC9220->HW_CFG = val << 16;
244 	}
245 }
246 
smsc_init_irqs(void)247 void smsc_init_irqs(void)
248 {
249 	SMSC9220->INT_EN = 0;
250 	/* Clear all interrupts */
251 	SMSC9220->INT_STS = 0xFFFFFFFF;
252 	/* Polarity config which works with QEMU */
253 	/* IRQ deassertion at 220 usecs and master IRQ enable */
254 	SMSC9220->IRQ_CFG = 0x22000111;
255 }
256 
smsc_check_phy(void)257 static int smsc_check_phy(void)
258 {
259 	uint32_t phyid1, phyid2;
260 
261 	if (smsc_phy_regread(SMSC9220_PHY_ID1, &phyid1)) {
262 		return -1;
263 	}
264 
265 	if (smsc_phy_regread(SMSC9220_PHY_ID2, &phyid2)) {
266 		return -1;
267 	}
268 
269 	return ((phyid1 == 0xFFFF && phyid2 == 0xFFFF) ||
270 	    (phyid1 == 0x0 && phyid2 == 0x0));
271 }
272 
smsc_reset_phy(void)273 int smsc_reset_phy(void)
274 {
275 	uint32_t val;
276 
277 	if (smsc_phy_regread(SMSC9220_PHY_BCONTROL, &val)) {
278 		return -1;
279 	}
280 
281 	val |= 1 << 15;
282 
283 	if (smsc_phy_regwrite(SMSC9220_PHY_BCONTROL, val)) {
284 		return -1;
285 	}
286 
287 	return 0;
288 }
289 
290 /**
291  * Advertise all speeds and pause capabilities
292  */
smsc_advertise_caps(void)293 void smsc_advertise_caps(void)
294 {
295 	uint32_t aneg_adv = 0U;
296 
297 	smsc_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv);
298 	aneg_adv |= 0xDE0;
299 
300 	smsc_phy_regwrite(SMSC9220_PHY_ANEG_ADV, aneg_adv);
301 	smsc_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv);
302 }
303 
smsc_establish_link(void)304 void smsc_establish_link(void)
305 {
306 	uint32_t bcr = 0U;
307 	uint32_t hw_cfg = 0U;
308 
309 	smsc_phy_regread(SMSC9220_PHY_BCONTROL, &bcr);
310 	bcr |= (1 << 12) | (1 << 9);
311 	smsc_phy_regwrite(SMSC9220_PHY_BCONTROL, bcr);
312 	smsc_phy_regread(SMSC9220_PHY_BCONTROL, &bcr);
313 
314 	hw_cfg = SMSC9220->HW_CFG;
315 	hw_cfg &= 0xF0000;
316 	hw_cfg |= (1 << 20);
317 	SMSC9220->HW_CFG = hw_cfg;
318 }
319 
smsc_enable_xmit(void)320 static inline void smsc_enable_xmit(void)
321 {
322 	SMSC9220->TX_CFG = 0x2 /*TX_CFG_TX_ON*/;
323 }
324 
smsc_enable_mac_xmit(void)325 void smsc_enable_mac_xmit(void)
326 {
327 	uint32_t mac_cr = 0U;
328 
329 	smsc_mac_regread(SMSC9220_MAC_CR, &mac_cr);
330 
331 	mac_cr |= (1 << 3);     /* xmit enable */
332 	mac_cr |= (1 << 28);    /* Heartbeat disable */
333 
334 	smsc_mac_regwrite(SMSC9220_MAC_CR, mac_cr);
335 }
336 
smsc_enable_mac_recv(void)337 void smsc_enable_mac_recv(void)
338 {
339 	uint32_t mac_cr = 0U;
340 
341 	smsc_mac_regread(SMSC9220_MAC_CR, &mac_cr);
342 	mac_cr |= (1 << 2);     /* Recv enable */
343 	smsc_mac_regwrite(SMSC9220_MAC_CR, mac_cr);
344 }
345 
smsc_init(void)346 int smsc_init(void)
347 {
348 	unsigned int phyreset = 0U;
349 
350 	if (smsc_check_id() < 0) {
351 		return -1;
352 	}
353 
354 	if (smsc_soft_reset() < 0) {
355 		return -1;
356 	}
357 
358 	smsc_set_txfifo(5);
359 
360 	/* Sets automatic flow control thresholds, and backpressure */
361 	/* threshold to defaults specified. */
362 	SMSC9220->AFC_CFG = 0x006E3740;
363 
364 	/* May need to initialize EEPROM/read MAC from it on real HW. */
365 
366 	/* Configure GPIOs as LED outputs. */
367 	SMSC9220->GPIO_CFG = 0x70070000;
368 
369 	smsc_init_irqs();
370 
371 	/* Configure MAC addresses here if needed. */
372 
373 	if (smsc_check_phy() < 0) {
374 		return -1;
375 	}
376 
377 	if (smsc_reset_phy() < 0) {
378 		return -1;
379 	}
380 
381 	k_sleep(PHY_RESET_TIMEOUT);
382 	/* Checking whether phy reset completed successfully.*/
383 	if (smsc_phy_regread(SMSC9220_PHY_BCONTROL, &phyreset)) {
384 		return 1;
385 	}
386 
387 	if (phyreset & (1 << 15)) {
388 		return 1;
389 	}
390 
391 	smsc_advertise_caps();
392 	/* bit [12] of BCONTROL seems self-clearing. */
393 	/* Although it's not so in the manual. */
394 	smsc_establish_link();
395 
396 	/* Interrupt threshold */
397 	SMSC9220->FIFO_INT = 0xFF000000;
398 
399 	smsc_enable_mac_xmit();
400 	smsc_enable_xmit();
401 	SMSC9220->RX_CFG = 0;
402 	smsc_enable_mac_recv();
403 
404 	/* Rx status FIFO level irq threshold */
405 	SMSC9220->FIFO_INT &= ~(0xFF);  /* Clear 2 bottom nibbles */
406 
407 	/* This sleep is compulsory otherwise txmit/receive will fail. */
408 	k_sleep(K_MSEC(2000));
409 
410 	return 0;
411 }
412 
413 /* Driver functions */
414 
eth_smsc911x_get_capabilities(const struct device * dev)415 static enum ethernet_hw_caps eth_smsc911x_get_capabilities(const struct device *dev)
416 {
417 	ARG_UNUSED(dev);
418 
419 	return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T;
420 }
421 
422 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
get_stats(const struct device * dev)423 static struct net_stats_eth *get_stats(const struct device *dev)
424 {
425 	struct eth_context *context = dev->data;
426 
427 	return &context->stats;
428 }
429 #endif
430 
eth_initialize(struct net_if * iface)431 static void eth_initialize(struct net_if *iface)
432 {
433 	const struct device *dev = net_if_get_device(iface);
434 	struct eth_context *context = dev->data;
435 
436 	LOG_DBG("eth_initialize");
437 
438 	smsc_read_mac_address(context->mac);
439 
440 	SMSC9220->INT_EN |= BIT(SMSC9220_INTERRUPT_RXSTATUS_FIFO_LEVEL);
441 
442 	net_if_set_link_addr(iface, context->mac, sizeof(context->mac),
443 			     NET_LINK_ETHERNET);
444 
445 	context->iface = iface;
446 
447 	ethernet_init(iface);
448 }
449 
smsc_write_tx_fifo(const uint8_t * buf,uint32_t len,bool is_last)450 static int smsc_write_tx_fifo(const uint8_t *buf, uint32_t len, bool is_last)
451 {
452 	uint32_t *buf32;
453 
454 	__ASSERT_NO_MSG(((uintptr_t)buf & 3) == 0);
455 
456 	if (is_last) {
457 		/* Last fragment may be not full */
458 		len = (len + 3) & ~3;
459 	}
460 
461 	if ((len & 3) != 0U || len == 0U) {
462 		LOG_ERR("Chunk size not aligned: %u", len);
463 		return -1;
464 	}
465 
466 	buf32 = (uint32_t *)buf;
467 	len /= 4U;
468 	do {
469 		SMSC9220->TX_DATA_PORT = *buf32++;
470 	} while (--len);
471 
472 	return 0;
473 }
474 
eth_tx(const struct device * dev,struct net_pkt * pkt)475 static int eth_tx(const struct device *dev, struct net_pkt *pkt)
476 {
477 	uint16_t total_len = net_pkt_get_len(pkt);
478 	static uint8_t tx_buf[NET_ETH_MAX_FRAME_SIZE] __aligned(4);
479 	uint32_t txcmd_a, txcmd_b;
480 	uint32_t tx_stat;
481 	int res;
482 
483 	txcmd_a = (1/*is_first_segment*/ << 13) | (1/*is_last_segment*/ << 12)
484 		  | total_len;
485 	/* Use len as a tag */
486 	txcmd_b = total_len << 16 | total_len;
487 	SMSC9220->TX_DATA_PORT = txcmd_a;
488 	SMSC9220->TX_DATA_PORT = txcmd_b;
489 
490 	if (net_pkt_read(pkt, tx_buf, total_len)) {
491 		goto error;
492 	}
493 
494 	res = smsc_write_tx_fifo(tx_buf, total_len, true);
495 	if (res < 0) {
496 		goto error;
497 	}
498 
499 	tx_stat = SMSC9220->TX_STAT_PORT;
500 	LOG_DBG("TX_STAT: %x", tx_stat);
501 
502 	return 0;
503 
504 error:
505 	LOG_ERR("Writing pkt to FIFO failed");
506 	return -1;
507 }
508 
509 static const struct ethernet_api api_funcs = {
510 	.iface_api.init = eth_initialize,
511 
512 	.get_capabilities = eth_smsc911x_get_capabilities,
513 	.send = eth_tx,
514 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
515 	.get_stats = get_stats,
516 #endif
517 };
518 
smsc_discard_pkt(void)519 static void smsc_discard_pkt(void)
520 {
521 	/* TODO: */
522 	/* Datasheet p.43: */
523 	/* When performing a fast-forward, there must be at least 4 DWORDs
524 	 * of data in the RX data FIFO for the packet being discarded. For
525 	 * less than 4 DWORDs do not use RX_FFWD. In this case data must be
526 	 * read from the RX data FIFO and discarded using standard PIO read
527 	 * operations.
528 	 */
529 	SMSC9220->RX_DP_CTRL = RX_DP_CTRL_RX_FFWD;
530 }
531 
smsc_wait_discard_pkt(void)532 static inline void smsc_wait_discard_pkt(void)
533 {
534 	while ((SMSC9220->RX_DP_CTRL & RX_DP_CTRL_RX_FFWD) != 0) {
535 	}
536 }
537 
smsc_read_rx_fifo(struct net_pkt * pkt,uint32_t len)538 static int smsc_read_rx_fifo(struct net_pkt *pkt, uint32_t len)
539 {
540 	uint32_t buf32;
541 
542 	__ASSERT_NO_MSG((len & 3) == 0U && len >= 4U);
543 
544 	len /= 4U;
545 
546 	do {
547 		buf32 = SMSC9220->RX_DATA_PORT;
548 
549 		if (net_pkt_write(pkt, &buf32, sizeof(uint32_t))) {
550 			return -1;
551 		}
552 	} while (--len);
553 
554 	return 0;
555 }
556 
smsc_recv_pkt(const struct device * dev,uint32_t pkt_size)557 static struct net_pkt *smsc_recv_pkt(const struct device *dev,
558 				     uint32_t pkt_size)
559 {
560 	struct eth_context *context = dev->data;
561 	struct net_pkt *pkt;
562 	uint32_t rem_size;
563 
564 	/* Round up to next DWORD size */
565 	rem_size = (pkt_size + 3) & ~3;
566 	/* Don't account for FCS when filling net pkt */
567 	rem_size -= 4U;
568 
569 	pkt = net_pkt_rx_alloc_with_buffer(context->iface, rem_size,
570 					   AF_UNSPEC, 0, K_NO_WAIT);
571 	if (!pkt) {
572 		LOG_ERR("Failed to obtain RX buffer");
573 		smsc_discard_pkt();
574 		return NULL;
575 	}
576 
577 	if (smsc_read_rx_fifo(pkt, rem_size) < 0) {
578 		smsc_discard_pkt();
579 		net_pkt_unref(pkt);
580 		return NULL;
581 	}
582 
583 	/* Discard FCS */
584 	{
585 		uint32_t __unused dummy = SMSC9220->RX_DATA_PORT;
586 	}
587 
588 	/* Adjust len of the last buf down for DWORD alignment */
589 	if (pkt_size & 3) {
590 		net_pkt_update_length(pkt, net_pkt_get_len(pkt) -
591 				      (4 - (pkt_size & 3)));
592 	}
593 
594 	return pkt;
595 }
596 
eth_smsc911x_isr(const struct device * dev)597 static void eth_smsc911x_isr(const struct device *dev)
598 {
599 	uint32_t int_status = SMSC9220->INT_STS;
600 	struct eth_context *context = dev->data;
601 
602 	LOG_DBG("%s: INT_STS=%x INT_EN=%x", __func__,
603 		int_status, SMSC9220->INT_EN);
604 
605 	if (int_status & BIT(SMSC9220_INTERRUPT_RXSTATUS_FIFO_LEVEL)) {
606 		struct net_pkt *pkt;
607 		uint32_t pkt_size, val;
608 		uint32_t rx_stat;
609 
610 		val = SMSC9220->RX_FIFO_INF;
611 		uint32_t pkt_pending = BFIELD(val, RX_FIFO_INF_RXSUSED);
612 
613 		LOG_DBG("in RX FIFO: pkts: %u, bytes: %u",
614 			pkt_pending,
615 			BFIELD(val, RX_FIFO_INF_RXDUSED));
616 
617 		/* Ack rxstatus_fifo_level only when no packets pending. The
618 		 * idea is to serve 1 packet per interrupt (e.g. to allow
619 		 * higher priority interrupts to fire) by keeping interrupt
620 		 * pending for as long as there're packets in FIFO. And when
621 		 * there's none, finally acknowledge it.
622 		 */
623 		if (pkt_pending == 0U) {
624 			goto done;
625 		}
626 
627 		int_status &= ~BIT(SMSC9220_INTERRUPT_RXSTATUS_FIFO_LEVEL);
628 
629 		/* Make sure that any previously started discard op is
630 		 * finished.
631 		 */
632 		smsc_wait_discard_pkt();
633 
634 		rx_stat = SMSC9220->RX_STAT_PORT;
635 		pkt_size = BFIELD(rx_stat, RX_STAT_PORT_PKT_LEN);
636 		LOG_DBG("pkt sz: %u", pkt_size);
637 
638 		pkt = smsc_recv_pkt(dev, pkt_size);
639 
640 		LOG_DBG("out RX FIFO: pkts: %u, bytes: %u",
641 			SMSC9220_BFIELD(RX_FIFO_INF, RXSUSED),
642 			SMSC9220_BFIELD(RX_FIFO_INF, RXDUSED));
643 
644 		if (pkt != NULL) {
645 			int res = net_recv_data(context->iface, pkt);
646 
647 			if (res < 0) {
648 				LOG_ERR("net_recv_data: %d", res);
649 				net_pkt_unref(pkt);
650 			}
651 		}
652 	}
653 
654 done:
655 	/* Ack pending interrupts */
656 	SMSC9220->INT_STS = int_status;
657 
658 }
659 
660 /* Bindings to the platform */
661 
eth_init(const struct device * dev)662 int eth_init(const struct device *dev)
663 {
664 	IRQ_CONNECT(DT_INST_IRQN(0),
665 		    DT_INST_IRQ(0, priority),
666 		    eth_smsc911x_isr, DEVICE_DT_INST_GET(0), 0);
667 
668 	int ret = smsc_init();
669 
670 	if (ret != 0) {
671 		LOG_ERR("smsc911x failed to initialize");
672 		return -ENODEV;
673 	}
674 
675 	irq_enable(DT_INST_IRQN(0));
676 
677 	return ret;
678 }
679 
680 static struct eth_context eth_0_context;
681 
682 ETH_NET_DEVICE_DT_INST_DEFINE(0,
683 		eth_init, NULL, &eth_0_context,
684 		NULL /*&eth_config_0*/, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
685 		NET_ETH_MTU /*MTU*/);
686