• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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