1 /*
2 * Copyright 2022 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(nxp_s32_eth);
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/mbox.h>
14 #include <zephyr/drivers/pinctrl.h>
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/net_if.h>
17 #include <zephyr/net/net_pkt.h>
18 #include <zephyr/net/phy.h>
19 #include <ethernet/eth_stats.h>
20
21 #include <S32Z2.h>
22 #include <Netc_Eth_Ip.h>
23 #include <Netc_Eth_Ip_Irq.h>
24 #include <Netc_EthSwt_Ip.h>
25
26 #include "eth.h"
27 #include "eth_nxp_s32_netc_priv.h"
28
29 /* Global MAC filter hash table required for the baremetal driver */
30 Netc_Eth_Ip_MACFilterHashTableEntryType * MACFilterHashTableAddrs[FEATURE_NETC_ETH_NUMBER_OF_CTRLS];
31
32 static void nxp_s32_eth_rx_thread(void *arg1, void *unused1, void *unused2);
33
nxp_s32_eth_msix_wrapper(const struct device * dev,uint32_t channel,void * user_data,struct mbox_msg * msg)34 static void nxp_s32_eth_msix_wrapper(const struct device *dev, uint32_t channel,
35 void *user_data, struct mbox_msg *msg)
36 {
37 const struct nxp_s32_eth_msix *msix = (const struct nxp_s32_eth_msix *)user_data;
38
39 ARG_UNUSED(dev);
40 ARG_UNUSED(msg);
41
42 /* Handler doesn't require any data to be passed, used only for signalling */
43 msix->handler(channel, NULL, 0);
44 }
45
get_iface(struct nxp_s32_eth_data * ctx,uint16_t vlan_tag)46 static inline struct net_if *get_iface(struct nxp_s32_eth_data *ctx, uint16_t vlan_tag)
47 {
48 #if defined(CONFIG_NET_VLAN)
49 struct net_if *iface;
50
51 iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag);
52 if (!iface) {
53 return ctx->iface;
54 }
55
56 return iface;
57 #else
58 ARG_UNUSED(vlan_tag);
59
60 return ctx->iface;
61 #endif
62 }
63
nxp_s32_eth_initialize_common(const struct device * dev)64 int nxp_s32_eth_initialize_common(const struct device *dev)
65 {
66 const struct nxp_s32_eth_config *cfg = dev->config;
67 struct nxp_s32_eth_data *ctx = dev->data;
68 Netc_Eth_Ip_StatusType status;
69 const struct nxp_s32_eth_msix *msix;
70 int err;
71
72 /* Populate the MAC filter hash table addresses for this SI */
73 __ASSERT_NO_MSG(cfg->si_idx < FEATURE_NETC_ETH_NUMBER_OF_CTRLS);
74 MACFilterHashTableAddrs[cfg->si_idx] = cfg->mac_filter_hash_table;
75
76 status = Netc_Eth_Ip_Init(cfg->si_idx, &cfg->netc_cfg);
77 if (status != NETC_ETH_IP_STATUS_SUCCESS) {
78 LOG_ERR("Failed to initialize SI%d (%d)", cfg->si_idx, status);
79 return -EIO;
80 }
81
82 for (int i = 0; i < NETC_MSIX_EVENTS_COUNT; i++) {
83 msix = &cfg->msix[i];
84 if (msix->mbox_channel.dev != NULL) {
85 err = mbox_register_callback(&msix->mbox_channel,
86 nxp_s32_eth_msix_wrapper,
87 (void *)msix);
88 if (err != 0) {
89 LOG_ERR("Failed to register MRU callback on channel %u",
90 msix->mbox_channel.id);
91 return err;
92 }
93 }
94 }
95
96 k_mutex_init(&ctx->tx_mutex);
97 k_sem_init(&ctx->rx_sem, 0, 1);
98
99 k_thread_create(&ctx->rx_thread, ctx->rx_thread_stack,
100 K_KERNEL_STACK_SIZEOF(ctx->rx_thread_stack),
101 nxp_s32_eth_rx_thread, (void *)dev, NULL, NULL,
102 K_PRIO_COOP(CONFIG_ETH_NXP_S32_RX_THREAD_PRIO),
103 0, K_NO_WAIT);
104 k_thread_name_set(&ctx->rx_thread, "nxp_s32_eth_rx");
105
106 status = Netc_Eth_Ip_EnableController(cfg->si_idx);
107 if (status != NETC_ETH_IP_STATUS_SUCCESS) {
108 LOG_ERR("Failed to enable ENETC SI%d (%d)", cfg->si_idx, status);
109 return -EIO;
110 }
111
112 if (cfg->generate_mac) {
113 cfg->generate_mac(&ctx->mac_addr[0]);
114 }
115
116 return 0;
117 }
118
119 #if defined(CONFIG_NET_IPV6)
nxp_s32_eth_mcast_cb(struct net_if * iface,const struct net_addr * addr,bool is_joined)120 void nxp_s32_eth_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined)
121 {
122 const struct device *dev = net_if_get_device(iface);
123 const struct nxp_s32_eth_config *cfg = dev->config;
124 struct net_eth_addr mac_addr;
125 Netc_Eth_Ip_StatusType status;
126
127 if (addr->family != AF_INET6) {
128 return;
129 }
130
131 net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr);
132
133 if (is_joined) {
134 status = Netc_Eth_Ip_AddMulticastDstAddrToHashFilter(cfg->si_idx,
135 mac_addr.addr);
136 } else {
137 status = Netc_Eth_Ip_RemoveMulticastDstAddrFromHashFilter(cfg->si_idx,
138 mac_addr.addr);
139 }
140 if (status != NETC_ETH_IP_STATUS_SUCCESS) {
141 LOG_ERR("Failed to update multicast hash table: %d", status);
142 }
143 }
144 #endif /* CONFIG_NET_IPV6 */
145
nxp_s32_eth_tx(const struct device * dev,struct net_pkt * pkt)146 int nxp_s32_eth_tx(const struct device *dev, struct net_pkt *pkt)
147 {
148 struct nxp_s32_eth_data *ctx = dev->data;
149 const struct nxp_s32_eth_config *cfg = dev->config;
150 size_t pkt_len = net_pkt_get_len(pkt);
151 int res = 0;
152 Netc_Eth_Ip_StatusType status;
153 Netc_Eth_Ip_BufferType buf;
154
155 __ASSERT(pkt, "Packet pointer is NULL");
156
157 k_mutex_lock(&ctx->tx_mutex, K_FOREVER);
158
159 buf.length = (uint16_t)pkt_len;
160 buf.data = NULL;
161 status = Netc_Eth_Ip_GetTxBuff(cfg->si_idx, cfg->tx_ring_idx, &buf, NULL);
162 if (status == NETC_ETH_IP_STATUS_TX_BUFF_BUSY) {
163 /* Reclaim the buffers already transmitted and try again */
164 Netc_Eth_Ip_ReleaseTxBuffers(cfg->si_idx, cfg->tx_ring_idx);
165 status = Netc_Eth_Ip_GetTxBuff(cfg->si_idx, cfg->tx_ring_idx, &buf, NULL);
166 }
167 if (status != NETC_ETH_IP_STATUS_SUCCESS) {
168 LOG_ERR("Failed to get tx buffer: %d", status);
169 res = -ENOBUFS;
170 goto error;
171 }
172 buf.length = (uint16_t)pkt_len;
173
174 res = net_pkt_read(pkt, buf.data, pkt_len);
175 if (res) {
176 LOG_ERR("Failed to copy packet to tx buffer: %d", res);
177 res = -ENOBUFS;
178 goto error;
179 }
180
181 status = Netc_Eth_Ip_SendFrame(cfg->si_idx, cfg->tx_ring_idx, &buf, NULL);
182 if (status != NETC_ETH_IP_STATUS_SUCCESS) {
183 LOG_ERR("Failed to tx frame: %d", status);
184 res = -EIO;
185 goto error;
186 }
187
188 error:
189 k_mutex_unlock(&ctx->tx_mutex);
190
191 if (res != 0) {
192 eth_stats_update_errors_tx(ctx->iface);
193 }
194 return res;
195 }
196
nxp_s32_eth_get_pkt(const struct device * dev,Netc_Eth_Ip_BufferType * buf,uint16_t * vlan_tag)197 static struct net_pkt *nxp_s32_eth_get_pkt(const struct device *dev,
198 Netc_Eth_Ip_BufferType *buf,
199 uint16_t *vlan_tag)
200 {
201 struct nxp_s32_eth_data *ctx = dev->data;
202 struct net_pkt *pkt = NULL;
203 int res = 0;
204 #if defined(CONFIG_NET_VLAN)
205 struct net_eth_hdr *hdr;
206 struct net_eth_vlan_hdr *hdr_vlan;
207 #if CONFIG_NET_TC_RX_COUNT > 1
208 enum net_priority prio;
209 #endif
210 #endif /* CONFIG_NET_VLAN */
211
212 /* Use root iface, it will be updated later in net_recv_data() */
213 pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, buf->length,
214 AF_UNSPEC, 0, NETC_TIMEOUT);
215 if (!pkt) {
216 goto exit;
217 }
218
219 res = net_pkt_write(pkt, buf->data, buf->length);
220 if (res) {
221 net_pkt_unref(pkt);
222 pkt = NULL;
223 goto exit;
224 }
225
226 #if defined(CONFIG_NET_VLAN)
227 hdr = NET_ETH_HDR(pkt);
228 if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) {
229 hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
230 net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
231 *vlan_tag = net_pkt_vlan_tag(pkt);
232
233 #if CONFIG_NET_TC_RX_COUNT > 1
234 prio = net_vlan2priority(net_pkt_vlan_priority(pkt));
235 net_pkt_set_priority(pkt, prio);
236 #endif
237 }
238 #endif /* CONFIG_NET_VLAN */
239
240 exit:
241 if (!pkt) {
242 eth_stats_update_errors_rx(get_iface(ctx, *vlan_tag));
243 }
244
245 return pkt;
246 }
247
nxp_s32_eth_rx(const struct device * dev)248 static int nxp_s32_eth_rx(const struct device *dev)
249 {
250 struct nxp_s32_eth_data *ctx = dev->data;
251 const struct nxp_s32_eth_config *cfg = dev->config;
252 Netc_Eth_Ip_BufferType buf;
253 Netc_Eth_Ip_RxInfoType info;
254 Netc_Eth_Ip_StatusType status;
255 uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
256 struct net_pkt *pkt;
257 int key;
258 int res = 0;
259
260 key = irq_lock();
261 status = Netc_Eth_Ip_ReadFrame(cfg->si_idx, cfg->rx_ring_idx, &buf, &info);
262 if (status == NETC_ETH_IP_STATUS_RX_QUEUE_EMPTY) {
263 res = -ENOBUFS;
264 } else if (status != NETC_ETH_IP_STATUS_SUCCESS) {
265 LOG_ERR("Error on received frame: %d (0x%X)", status, info.rxStatus);
266 res = -EIO;
267 } else {
268 pkt = nxp_s32_eth_get_pkt(dev, &buf, &vlan_tag);
269 Netc_Eth_Ip_ProvideRxBuff(cfg->si_idx, cfg->rx_ring_idx, &buf);
270
271 if (pkt != NULL) {
272 res = net_recv_data(get_iface(ctx, vlan_tag), pkt);
273 if (res < 0) {
274 eth_stats_update_errors_rx(get_iface(ctx, vlan_tag));
275 net_pkt_unref(pkt);
276 LOG_ERR("Failed to enqueue frame into rx queue: %d", res);
277 }
278 }
279 }
280 irq_unlock(key);
281
282 return res;
283 }
284
nxp_s32_eth_rx_thread(void * arg1,void * unused1,void * unused2)285 static void nxp_s32_eth_rx_thread(void *arg1, void *unused1, void *unused2)
286 {
287 const struct device *dev = (const struct device *)arg1;
288 struct nxp_s32_eth_data *ctx = dev->data;
289 int res;
290 int work;
291
292 ARG_UNUSED(unused1);
293 ARG_UNUSED(unused2);
294 __ASSERT_NO_MSG(arg1 != NULL);
295 __ASSERT_NO_MSG(ctx != NULL);
296
297 while (1) {
298 res = k_sem_take(&ctx->rx_sem, K_FOREVER);
299 __ASSERT_NO_MSG(res == 0);
300
301 work = 0;
302 while (nxp_s32_eth_rx(dev) != -ENOBUFS) {
303 if (++work == CONFIG_ETH_NXP_S32_RX_BUDGET) {
304 /* more work to do, reschedule */
305 work = 0;
306 k_yield();
307 }
308 }
309 }
310 }
311
nxp_s32_eth_get_capabilities(const struct device * dev)312 enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev)
313 {
314 ARG_UNUSED(dev);
315
316 return (ETHERNET_LINK_10BASE_T
317 | ETHERNET_LINK_100BASE_T
318 | ETHERNET_LINK_1000BASE_T
319 | ETHERNET_HW_RX_CHKSUM_OFFLOAD
320 #if defined(CONFIG_NET_VLAN)
321 | ETHERNET_HW_VLAN
322 #endif
323 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
324 | ETHERNET_PROMISC_MODE
325 #endif
326 );
327 }
328
nxp_s32_eth_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)329 int nxp_s32_eth_set_config(const struct device *dev, enum ethernet_config_type type,
330 const struct ethernet_config *config)
331 {
332 struct nxp_s32_eth_data *ctx = dev->data;
333 const struct nxp_s32_eth_config *cfg = dev->config;
334 int res = 0;
335
336 switch (type) {
337 case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
338 /* Set new Ethernet MAC address and register it with the upper layer */
339 memcpy(ctx->mac_addr, config->mac_address.addr, sizeof(ctx->mac_addr));
340 Netc_Eth_Ip_SetMacAddr(cfg->si_idx, (const uint8_t *)ctx->mac_addr);
341 net_if_set_link_addr(ctx->iface, ctx->mac_addr, sizeof(ctx->mac_addr),
342 NET_LINK_ETHERNET);
343 LOG_INF("SI%d MAC set to: %02x:%02x:%02x:%02x:%02x:%02x", cfg->si_idx,
344 ctx->mac_addr[0], ctx->mac_addr[1], ctx->mac_addr[2],
345 ctx->mac_addr[3], ctx->mac_addr[4], ctx->mac_addr[5]);
346 break;
347 default:
348 res = -ENOTSUP;
349 break;
350 }
351
352 return res;
353 }
354
355 BUILD_ASSERT((CONFIG_ETH_NXP_S32_RX_RING_LEN % 8) == 0,
356 "Rx ring length must be multiple of 8");
357 BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_LEN % 8) == 0,
358 "Tx ring length must be multiple of 8");
359 BUILD_ASSERT((CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE % 8) == 0,
360 "Rx ring data buffer size must be multiple of 8");
361 BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % 8) == 0,
362 "Tx ring data buffer size must be multiple of 8");
363