1 /*
2 * Copyright (c) 2022 HPMicro
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "hpm_lwip.h"
16 #include "ethernetif.h"
17
18 #include "lwip/def.h"
19 #include "lwip/mem.h"
20 #include "lwip/pbuf.h"
21 #include "netif/etharp.h"
22 #include "lwip/err.h"
23 #include "lwip/timeouts.h"
24 #include "ethernetif.h"
25 #include "hpm_enet_drv.h"
26 #include <string.h>
27 #include <los_task.h>
28 #include <los_sem.h>
29
30 /**
31 * In this function, the hardware should be initialized.
32 * Called from ethernetif_init().
33 *
34 * @param netif the already initialized lwip network interface structure
35 * for this ethernetif
36 */
low_level_init(struct netif * netif)37 static void low_level_init(struct netif *netif)
38 {
39 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
40 /* set netif MAC hardware address length */
41 netif->hwaddr_len = ETHARP_HWADDR_LEN;
42
43 /* set netif MAC hardware address */
44 netif->hwaddr[0] = dev->macAddr[0];
45 netif->hwaddr[1] = dev->macAddr[1];
46 netif->hwaddr[2] = dev->macAddr[2];
47 netif->hwaddr[3] = dev->macAddr[3];
48 netif->hwaddr[4] = dev->macAddr[4];
49 netif->hwaddr[5] = dev->macAddr[5];
50
51 /* set netif maximum transfer unit */
52 netif->mtu = 1500;
53
54 /* need to judge from phy status */
55 netif->flags |= NETIF_FLAG_LINK_UP;
56
57 /* Accept broadcast address and ARP traffic */
58 netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
59 }
60
61
62 /**
63 * This function should do the actual transmission of the packet. The packet is
64 * contained in the pbuf that is passed to the function. This pbuf
65 * might be chained.
66 *
67 * @param netif the lwip network interface structure for this ethernetif
68 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
69 * @return ERR_OK if the packet could be sent
70 * an err_t value if the packet couldn't be sent
71 *
72 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
73 * strange results. You might consider waiting for space in the DMA queue
74 * to become availale since the stack doesn't retry to send a packet
75 * dropped because of memory failure (except for the TCP timers).
76 */
77
low_level_output(struct netif * netif,struct pbuf * p)78 static err_t low_level_output(struct netif *netif, struct pbuf *p)
79 {
80 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
81 enet_desc_t *desc = &dev->desc;
82 uint32_t tx_buff_size = desc->tx_buff_cfg.size;
83 struct pbuf *q;
84 uint8_t *buffer;
85 __IO enet_tx_desc_t *dma_tx_desc;
86 uint32_t frame_length = 0;
87 uint32_t buffer_offset = 0;
88 uint32_t bytes_left_to_copy = 0;
89 uint32_t payload_offset = 0;
90 enet_tx_desc_t *tx_desc_list_cur = desc->tx_desc_list_cur;
91
92 dma_tx_desc = tx_desc_list_cur;
93 buffer = (uint8_t *)(dma_tx_desc->tdes2_bm.buffer1);
94 buffer_offset = 0;
95
96 /* copy frame from pbufs to driver buffers */
97 for (q = p; q != NULL; q = q->next)
98 {
99 /* Get bytes in current lwIP buffer */
100 bytes_left_to_copy = q->len;
101 payload_offset = 0;
102
103 /* Check if the length of data to copy is bigger than Tx buffer size*/
104 while ((bytes_left_to_copy + buffer_offset) > tx_buff_size)
105 {
106 /* Copy data to Tx buffer*/
107 memcpy((uint8_t *)((uint8_t *)buffer + buffer_offset),
108 (uint8_t *)((uint8_t *)q->payload + payload_offset),
109 tx_buff_size - buffer_offset);
110
111 /* Point to next descriptor */
112 dma_tx_desc = (enet_tx_desc_t *)(dma_tx_desc->tdes3_bm.next_desc);
113
114 /* Check if the buffer is available */
115 if (dma_tx_desc->tdes0_bm.own != 0)
116 {
117 printf("DMA tx desc buffer is not valid\n");
118 return ERR_USE;
119 }
120
121 buffer = (uint8_t *)(dma_tx_desc->tdes2_bm.buffer1);
122
123 bytes_left_to_copy = bytes_left_to_copy - (tx_buff_size - buffer_offset);
124 payload_offset = payload_offset + (tx_buff_size - buffer_offset);
125 frame_length = frame_length + (tx_buff_size - buffer_offset);
126 buffer_offset = 0;
127 }
128
129 /* Copy the remaining bytes */
130 memcpy((uint8_t *)((uint8_t *)buffer + buffer_offset),
131 (uint8_t *)((uint8_t *)q->payload + payload_offset),
132 bytes_left_to_copy);
133
134 buffer_offset = buffer_offset + bytes_left_to_copy;
135 frame_length = frame_length + bytes_left_to_copy;
136 }
137
138 /* Prepare transmit descriptors to give to DMA */
139
140
141 frame_length += 4;
142 enet_prepare_transmission_descriptors(dev->base, &desc->tx_desc_list_cur, frame_length, desc->tx_buff_cfg.size);
143
144 return ERR_OK;
145 }
146
147 /**
148 * Should allocate a pbuf and transfer the bytes of the incoming
149 * packet from the interface into the pbuf.
150 *
151 * @param netif the lwip network interface structure for this ethernetif
152 * @return a pbuf filled with the received packet (including MAC header)
153 * NULL on memory error
154 */
low_level_input(struct netif * netif)155 static struct pbuf *low_level_input(struct netif *netif)
156 {
157 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
158 enet_desc_t *desc = &dev->desc;
159 struct pbuf *p = NULL, *q = NULL;
160 uint32_t rx_buff_size = desc->rx_buff_cfg.size;
161 uint16_t len = 0;
162 uint8_t *buffer;
163 enet_frame_t frame = {0, 0, 0};
164 enet_rx_desc_t *dma_rx_desc;
165 uint32_t buffer_offset = 0;
166 uint32_t payload_offset = 0;
167 uint32_t bytes_left_to_copy = 0;
168 uint32_t i = 0;
169
170 /* Get a received frame */
171 frame = enet_get_received_frame_interrupt(&desc->rx_desc_list_cur,
172 &desc->rx_frame_info,
173 desc->rx_buff_cfg.count);
174
175 /* Obtain the size of the packet and put it into the "len" variable. */
176 len = frame.length;
177 buffer = (uint8_t *)frame.buffer;
178
179 if (len > 0)
180 {
181 /* allocate a pbuf chain of pbufs from the Lwip buffer pool */
182 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
183 }
184
185 if (p != NULL)
186 {
187 dma_rx_desc = frame.rx_desc;
188 buffer_offset = 0;
189 for (q = p; q != NULL; q = q->next)
190 {
191 bytes_left_to_copy = q->len;
192 payload_offset = 0;
193
194 /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
195 while ((bytes_left_to_copy + buffer_offset) > rx_buff_size)
196 {
197 /* Copy data to pbuf */
198 memcpy((uint8_t *)((uint8_t *)q->payload + payload_offset), (uint8_t *)((uint8_t *)buffer + buffer_offset), (rx_buff_size - buffer_offset));
199
200 /* Point to next descriptor */
201 dma_rx_desc = (enet_rx_desc_t *)(dma_rx_desc->rdes3_bm.next_desc);
202 buffer = (uint8_t *)(dma_rx_desc->rdes2_bm.buffer1);
203
204 bytes_left_to_copy = bytes_left_to_copy - (rx_buff_size - buffer_offset);
205 payload_offset = payload_offset + (rx_buff_size - buffer_offset);
206 buffer_offset = 0;
207 }
208 /* Copy remaining data in pbuf */
209 memcpy((uint8_t *)((uint8_t *)q->payload + payload_offset), (uint8_t *)((uint8_t *)buffer + buffer_offset), bytes_left_to_copy);
210 buffer_offset = buffer_offset + bytes_left_to_copy;
211 }
212 }
213 else
214 {
215 return NULL;
216 }
217
218 /* Release descriptors to DMA */
219 /* Point to first descriptor */
220 dma_rx_desc = frame.rx_desc;
221
222 /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
223 for (i = 0; i < desc->rx_frame_info.seg_count; i++)
224 {
225 dma_rx_desc->rdes0_bm.own = 1;
226 dma_rx_desc = (enet_rx_desc_t*)(dma_rx_desc->rdes3_bm.next_desc);
227 }
228
229 /* Clear Segment_Count */
230 desc->rx_frame_info.seg_count = 0;
231
232 return p;
233 }
234
235
236 /**
237 * This function is the ethernetif_input task, it is processed when a packet
238 * is ready to be read from the interface. It uses the function low_level_input()
239 * that should handle the actual reception of bytes from the network
240 * interface. Then the type of the received packet is determined and
241 * the appropriate input function is called.
242 *
243 * @param netif the lwip network interface structure for this ethernetif
244 */
245
246 /*
247 invoked after receiving data packet
248 */
ethernetif_input(struct netif * netif)249 err_t ethernetif_input(struct netif *netif)
250 {
251 err_t err;
252 struct pbuf *p = NULL;
253 /* move received packet into a new pbuf */
254 while ((p = low_level_input(netif)) != NULL) {
255 /* no packet could be read, silently ignore this */
256 if (p == NULL) {
257 return ERR_MEM;
258 }
259
260 /* entry point to the LwIP stack */
261 err = netif->input(p, netif);
262
263 if (err != ERR_OK) {
264 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
265 pbuf_free(p);
266 }
267 }
268 return err;
269 }
270
ethernetif_recv_thread(UINT32 arg)271 static VOID *ethernetif_recv_thread(UINT32 arg)
272 {
273 struct netif *netif = (struct netif *)arg;
274 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
275
276 while (1) {
277 LOS_SemPend(dev->rxSemHandle, 0xffffffff);
278 ethernetif_input(netif);
279 }
280 }
281
hpm_enet_isr(VOID * parm)282 static __attribute__((section(".interrupt.text"))) VOID hpm_enet_isr(VOID *parm)
283 {
284 struct netif *netif = (struct netif *)parm;
285 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
286
287 uint32_t status = dev->base->DMA_STATUS;
288
289 if (ENET_DMA_STATUS_GLPII_GET(status)) {
290 dev->base->DMA_STATUS |= ENET_DMA_STATUS_GLPII_SET(ENET_DMA_STATUS_GLPII_GET(status));
291 }
292
293 if (ENET_DMA_STATUS_RI_GET(status)) {
294 dev->base->DMA_STATUS |= ENET_DMA_STATUS_RI_SET(ENET_DMA_STATUS_RI_GET(status));
295 LOS_SemPost(dev->rxSemHandle);
296 } else {
297 printf("error ---status = 0x%X\n", status);
298 }
299 }
300
ethernetif_recv_start(struct netif * netif)301 void ethernetif_recv_start(struct netif *netif)
302 {
303 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
304 UINT32 taskID = LOS_ERRNO_TSK_ID_INVALID;
305 UINT32 ret;
306 TSK_INIT_PARAM_S task = {0};
307
308 LOS_SemCreate(0, &dev->rxSemHandle);
309
310 HwiIrqParam irqParam;
311 irqParam.pDevId = netif;
312 LOS_HwiCreate(HPM2LITEOS_IRQ(dev->irqNum), 1, 0, (HWI_PROC_FUNC)hpm_enet_isr, &irqParam);
313 LOS_HwiEnable(HPM2LITEOS_IRQ(dev->irqNum));
314
315 /* Create host Task */
316 task.pfnTaskEntry = (TSK_ENTRY_FUNC)ethernetif_recv_thread;
317 task.uwStackSize = 4096;
318 task.pcName = (char *)(dev->name);
319 task.usTaskPrio = 3;
320 task.uwArg = (UINTPTR)netif;
321 task.uwResved = LOS_TASK_STATUS_DETACHED;
322 ret = LOS_TaskCreate(&taskID, &task);
323 if (ret != LOS_OK) {
324 LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: LOS_TaskCreate error %u\n", ret));
325 return -1;
326 }
327 }
328
329 /**
330 * Should be called at the beginning of the program to set up the
331 * network interface. It calls the function low_level_init() to do the
332 * actual setup of the hardware.
333 *
334 * This function should be passed as a parameter to netif_add().
335 *
336 * @param netif the lwip network interface structure for this ethernetif
337 * @return ERR_OK if the loopif is initialized
338 * ERR_MEM if private data couldn't be allocated
339 * any other err_t on error
340 */
ethernetif_init(struct netif * netif)341 err_t ethernetif_init(struct netif *netif)
342 {
343 LWIP_ASSERT("netif != NULL", (netif != NULL));
344 struct HpmEnetDevice *dev = (struct HpmEnetDevice *)netif->state;
345
346 #if LWIP_NETIF_HOSTNAME
347 /* Initialize interface hostname */
348 netif->hostname = "lwip";
349 #endif /* LWIP_NETIF_HOSTNAME */
350
351 netif->name[0] = dev->name[0];
352 netif->name[1] = dev->name[1];
353
354 netif->output = etharp_output;
355 netif->linkoutput = low_level_output;
356
357 /* initialize the hardware */
358 low_level_init(netif);
359
360 ethernetif_recv_start(netif);
361
362 return ERR_OK;
363 }
364