• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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  * Description: implementation for lowpower
15  * Author: none
16  * Create: 2019
17  */
18 
19 #include "lwip/opt.h"
20 
21 #include "lwip/priv/tcp_priv.h"
22 
23 #include "lwip/def.h"
24 #include "lwip/memp.h"
25 #include "lwip/priv/tcpip_priv.h"
26 
27 #include "lwip/ip4_frag.h"
28 #include "lwip/etharp.h"
29 #include "lwip/dhcp.h"
30 #include "lwip/autoip.h"
31 #include "lwip/igmp.h"
32 #include "lwip/dns.h"
33 #include "lwip/nd6.h"
34 #include "lwip/ip6_frag.h"
35 #include "lwip/mld6.h"
36 #include "lwip/dhcp6.h"
37 #include "lwip/sys.h"
38 #include "lwip/pbuf.h"
39 #include "netif/lowpan6.h"
40 #include "lwip/nat64.h"
41 #include "lwip/api.h"
42 #include "lwip/ip6in4.h"
43 
44 #if LWIP_LOWPOWER
45 #include "lwip/lowpower.h"
46 
47 #define TIMEOUT_MAX 120000 /* two min */
48 #define SYS_TIMEOUT_WAIT_TICKS    30
49 #define SYS_TIMEOUT_WAIT_TIME_MS  3
50 
51 static u32_t g_wake_up_time = TIMEOUT_MAX;
52 static enum lowpower_mod g_lowpower_switch = LOW_TMR_LOWPOWER_MOD;
53 static struct timer_entry *g_timer_header = NULL;
54 static struct timer_mng g_timer_mng = { LOW_TMR_TIMER_HANDLING, 0 };
55 static u32_t g_last_check_timeout = 0;
56 
57 static const struct timer_handler lowpower_timer_handler[] = {
58 #if LWIP_TCP
59   /*
60    * The TCP timer is a special case: it does not have to run always and
61    * is triggered to start from TCP using tcp_timer_needed()
62    */
63   {TCP_FAST_INTERVAL, tcp_fasttmr, tcp_fast_tmr_tick TCP_FASTTMR_NAME},
64   {TCP_SLOW_INTERVAL, tcp_slowtmr, tcp_slow_tmr_tick TCP_SLOWTMR_NAME},
65 #endif /* LWIP_TCP */
66 
67 #if LWIP_IPV4
68 #if IP_REASSEMBLY
69   {IP_TMR_INTERVAL, ip_reass_tmr, ip_reass_tmr_tick IP_REASSTRM_NAME},
70 #endif /* IP_REASSEMBLY */
71 
72 #if LWIP_ARP
73   {ARP_TMR_INTERVAL, etharp_tmr, etharp_tmr_tick ETHARPTMR_NAME},
74 #endif /* LWIP_ARP */
75 
76 #if LWIP_DHCP
77   {DHCP_FINE_TIMER_MSECS, dhcp_fine_tmr, dhcp_fine_tmr_tick DHCP_FINETMR_NAME},
78   {DHCP_COARSE_TIMER_MSECS, dhcp_coarse_tmr, dhcp_coarse_tmr_tick DHCP_COARSETMR_NAME},
79 #endif /* LWIP_DHCP */
80 
81 #if LWIP_AUTOIP
82   {AUTOIP_TMR_INTERVAL, autoip_tmr, autoip_tmr_tick AUTOIPTMR_NAME},
83 #endif /* LWIP_AUTOIP */
84 
85 #if LWIP_IGMP
86   {IGMP_TMR_INTERVAL, igmp_tmr, igmp_tmr_tick IGMPTMR_NAME},
87 #endif /* LWIP_IGMP */
88 #endif /* LWIP_IPV4 */
89 
90 #if LWIP_DNS
91   {DNS_TMR_INTERVAL, dns_tmr, dns_tmr_tick DNSTMR_NAME},
92 #endif /* LWIP_DNS */
93 
94 #if LWIP_NAT64
95   {NAT64_TMR_INTERVAL, nat64_tmr, nat64_tmr_tick NAT64TMR_NAME},
96 #endif /* LWIP_NAT64 */
97 
98 #if LWIP_IP6IN4
99   {IP6IN4_TMR_INTERVAL, ip6in4_tmr, ip6in4_tmr_tick IP6IN4TMR_NAME},
100 #endif /* LWIP_IP6IN4 */
101 
102 #if LWIP_IPV6
103   {ND6_TMR_INTERVAL, nd6_tmr, nd6_tmr_tick ND6TMR_NAME},
104 #if LWIP_IPV6_REASS
105   {IP6_REASS_TMR_INTERVAL, ip6_reass_tmr, ip6_reass_tmr_tick IP6_TREASSTMR_NAME},
106 #endif /* LWIP_IPV6_REASS */
107 
108 #if LWIP_IPV6_MLD
109   {MLD6_TMR_INTERVAL, mld6_tmr, mld6_tmr_tick MLD6TMR_NAME},
110 #endif /* LWIP_IPV6_MLD */
111 
112 #if LWIP_IPV6_DHCP6
113   {DHCP6_TIMER_MSECS, dhcp6_tmr, dhcp6_tmr_tick DHCP6TMR_NAME},
114 #endif /* LWIP_IPV6_DHCP6 */
115 
116 #if LWIP_6LOWPAN
117   {LOWPAN6_TMR_INTERVAL, lowpan6_tmr, lowpan6_tmr_tick LOWPAN6TMR_NAME},
118 #endif /* LWIP_6LOWPAN */
119 #endif /* LWIP_IPV6 */
120 };
121 
122 void
set_timer_state(enum timer_state state,u32_t waiting_time)123 set_timer_state(enum timer_state state, u32_t waiting_time)
124 {
125   g_timer_mng.waiting_time = waiting_time;
126   g_timer_mng.state = state;
127 }
128 
129 /* should not call by tcpip_thread */
130 u8_t
sys_timeout_waiting_long(void)131 sys_timeout_waiting_long(void)
132 {
133   u8_t i = 0;
134   u8_t j = 0;
135 
136   while (g_timer_mng.state == LOW_TMR_GETING_TICKS) {
137     i++;
138     if (i == SYS_TIMEOUT_WAIT_TICKS) {
139       i = 0;
140       j++;
141       if (j == SYS_TIMEOUT_WAIT_TIME_MS) {
142         break;
143       }
144       sys_msleep(1);
145     }
146   }
147 
148   if (g_timer_mng.state == LOW_TMR_TIMER_WAITING) {
149     return ((g_timer_mng.waiting_time > TIMEOUT_TICK) ? 1 : 0);
150   }
151 
152   return 0;
153 }
154 
155 err_t
sys_timeout_reg(u32_t msec,sys_timeout_handler handler,void * arg,char * name,get_next_timeout next_tick)156 sys_timeout_reg(
157   u32_t msec,
158   sys_timeout_handler handler,
159   void *arg,
160 #if LOWPOWER_TIMER_DEBUG
161   char *name,
162 #endif
163   get_next_timeout next_tick)
164 {
165   struct timer_entry *timeout = NULL;
166   struct timer_entry *temp = NULL;
167 
168   if (handler == NULL) {
169     return -1;
170   }
171 
172   timeout = (struct timer_entry *)memp_malloc(MEMP_SYS_TIMEOUT);
173   if (timeout == NULL) {
174     LOWPOWER_DEBUG(("sys_timeout_reg: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty"));
175     return -1;
176   }
177 
178   timeout->handler = handler;
179   timeout->clock_max = msec / TIMEOUT_TICK; /* time interval */
180   timeout->next_tick = next_tick;
181   timeout->timeout = sys_now();
182   timeout->args = arg;
183   timeout->enable = 0;
184 
185 #if LOWPOWER_TIMER_DEBUG
186   timeout->name = name;
187 #endif
188 
189   /* add list tail */
190   timeout->next = NULL;
191   if (g_timer_header == NULL) {
192     g_timer_header = timeout;
193   } else {
194     temp = g_timer_header;
195     while (temp->next != NULL) {
196       temp = temp->next;
197     }
198     temp->next = timeout;
199   }
200 
201   return 0;
202 }
203 
204 /* deal timeout and return next timer prev */
205 static void
timeout_handler(struct timer_entry * t,u32_t now)206 timeout_handler(struct timer_entry *t, u32_t now)
207 {
208 #if LOWPOWER_TIMER_DEBUG
209   if (t->name != NULL) {
210     LOWPOWER_DEBUG(("%s timeout: now:%u\n", t->name, now));
211   }
212 #endif
213 
214   t->handler(t->args);
215   LWIP_UNUSED_ARG(now);
216   t->timeout += t->clock_max * TIMEOUT_TICK;
217 }
218 
219 static u32_t
get_timer_tick(struct timer_entry * t)220 get_timer_tick(struct timer_entry *t)
221 {
222   u32_t tick;
223 
224   /* disable lowpower, need to timeout once a tick */
225   if (g_lowpower_switch == LOW_TMR_NORMAL_MOD) {
226     return t->clock_max;
227   }
228 
229   if (t->next_tick != NULL) {
230     tick = t->next_tick();
231   } else {
232     tick = 1;
233     LOWPOWER_DEBUG(("next->tick is NULL\n"));
234   }
235   tick *= t->clock_max;
236   return tick;
237 }
238 
239 static void
handle_timer_and_free(struct timer_entry ** pt,struct timer_entry ** pn,struct timer_entry * p)240 handle_timer_and_free(struct timer_entry **pt, struct timer_entry **pn, struct timer_entry *p)
241 {
242   struct timer_entry *t = *pt;
243   struct timer_entry *n = *pn;
244   /* insert after previous node or as the header */
245   if (p == NULL) {
246     g_timer_header = n;
247   } else {
248     p->next = n;
249   }
250 
251   t->next = NULL;
252   sys_timeout_handler handler = t->handler;
253   void *args = t->args;
254   memp_free(MEMP_SYS_TIMEOUT, t);
255   *pt = NULL;
256   handler(args);
257 
258   /* the last entry */
259   if ((n == NULL) && (p != NULL)) {
260     *pn = p->next;
261   }
262 }
263 
264 static u32_t
get_sleep_time(u32_t now)265 get_sleep_time(u32_t now)
266 {
267   struct timer_entry *t = NULL;
268   struct timer_entry *n = NULL;
269   struct timer_entry *p = NULL;
270   u32_t msec = TIMEOUT_MAX;
271   u32_t tick;
272   u32_t temp;
273 
274   LOWPOWER_DEBUG(("\n*******get_sleep_time*****************\n"));
275 
276   for (t = g_timer_header, p = NULL; t != NULL; t = n) {
277     n = t->next;
278 again:
279     tick = get_timer_tick(t);
280     if (tick == 0) {
281       t->enable = 0;
282       p = t;
283       continue;
284     }
285 
286     if (t->enable == 0) {
287       t->timeout = now;
288     }
289     t->enable = 1;
290     temp = tick * TIMEOUT_TICK;
291 
292     if (temp <= now - t->timeout) {
293       if (t->next_tick == NULL) {
294         handle_timer_and_free(&t, &n, p);
295         /* t is free p=p */
296         continue;
297       }
298       timeout_handler(t, now);
299       goto again;
300     }
301 
302     temp = temp - (now - t->timeout);
303     msec = msec > temp ? temp : msec;
304     p = t;
305   }
306 
307   LOWPOWER_DEBUG(("msec = %u now = %u\n", msec, now));
308   return msec;
309 }
310 
311 static void
check_timeout(u32_t now)312 check_timeout(u32_t now)
313 {
314   struct timer_entry *t = NULL;
315   struct timer_entry *n = NULL;
316   struct timer_entry *p = NULL;
317   u32_t msec;
318   u32_t ticks;
319   u32_t i;
320 
321   LOWPOWER_DEBUG(("\n**********timeout**************\n"));
322   LOWPOWER_DEBUG(("now = %u\n", now));
323 
324   for (t = g_timer_header, p = NULL; t != NULL; t = n) {
325     n = t->next;
326     if (t->enable == 0) {
327       p = t;
328       continue;
329     }
330 
331     msec = now - t->timeout;
332     ticks = msec / TIMEOUT_TICK;
333     ticks = ticks / t->clock_max;
334 
335     for (i = 0; i < ticks; i++) {
336       /* remove timer_entry form list */
337       if (t->next_tick == NULL) {
338         handle_timer_and_free(&t, &n, p);
339         break;
340       }
341       timeout_handler(t, now);
342       PBUF_CHECK_FREE_OOSEQ();
343     }
344     if (t != NULL) {
345       p = t;
346     }
347   }
348 }
349 
350 void
tcpip_timeouts_mbox_fetch(sys_mbox_t * mbox,void ** msg)351 tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
352 {
353   u32_t sleeptime;
354   u32_t ret;
355   u32_t now;
356 
357 again:
358   if (g_timer_header == NULL) {
359     UNLOCK_TCPIP_CORE();
360     (void)sys_arch_mbox_fetch_ext(mbox, msg, 0, 0);
361     LOCK_TCPIP_CORE();
362     return;
363   }
364 
365   set_timer_state(LOW_TMR_GETING_TICKS, 0);
366   sleeptime = get_sleep_time(sys_now());
367   sleeptime = sleeptime > sys_timeout_get_wake_time() ? sys_timeout_get_wake_time() : sleeptime;
368   set_timer_state(LOW_TMR_TIMER_WAITING, sleeptime);
369 
370   sys_timeout_set_wake_time(TIMEOUT_MAX);
371   UNLOCK_TCPIP_CORE();
372   ret = sys_arch_mbox_fetch_ext(mbox, msg, sleeptime, 0);
373   LOCK_TCPIP_CORE();
374   set_timer_state(LOW_TMR_TIMER_HANDLING, 0);
375   now = sys_now();
376   if ((now - g_last_check_timeout) >= TIMEOUT_CHECK) {
377     check_timeout(sys_now());
378     g_last_check_timeout = sys_now();
379   }
380 
381   if (ret == SYS_ARCH_TIMEOUT) {
382     goto again;
383   }
384 }
385 
386 void
lowpower_cycle_tmr(void * args)387 lowpower_cycle_tmr(void *args)
388 {
389   struct timer_handler *handler = (struct timer_handler *)args;
390 
391   handler->handler();
392 }
393 
394 err_t
set_timer_interval(u8_t i,u32_t interval)395 set_timer_interval(u8_t i, u32_t interval)
396 {
397   if (i >= LWIP_ARRAYSIZE(lowpower_timer_handler)) {
398     return -1;
399   }
400   return sys_timeout_reg(interval, lowpower_cycle_tmr,
401                          (void *)(&lowpower_timer_handler[i]),
402 #if LOWPOWER_TIMER_DEBUG
403                          lowpower_timer_handler[i].name,
404 #endif
405                          lowpower_timer_handler[i].next_tick);
406 }
407 
408 /* registed when init */
409 void
tcp_timer_needed(void)410 tcp_timer_needed(void)
411 {}
412 
413 void
sys_timeouts_init(void)414 sys_timeouts_init(void)
415 {
416   u8_t i;
417 
418   for (i = 0; i < LWIP_ARRAYSIZE(lowpower_timer_handler); i++) {
419     if (set_timer_interval(i, lowpower_timer_handler[i].interval) != 0) {
420       LOWPOWER_DEBUG(("ERROR:regist timer faild! i = %u\n", i));
421     }
422   }
423 }
424 
425 void
sys_untimeout(sys_timeout_handler handler,void * arg)426 sys_untimeout(sys_timeout_handler handler, void *arg)
427 {
428   struct timer_entry *t = NULL;
429   struct timer_entry *p = NULL;
430   struct timer_entry *n = NULL;
431 
432   for (t = g_timer_header, p = NULL; t != NULL; t = n) {
433     n = t->next;
434     if ((t->handler == handler) && (t->args == arg)) {
435       if (p == NULL) {
436         g_timer_header = t->next;
437       } else {
438         p->next = t->next;
439       }
440       t->next = NULL;
441       memp_free(MEMP_SYS_TIMEOUT, t);
442       t = NULL;
443     }
444     if (t != NULL) {
445       p = t;
446     }
447   }
448 }
449 void
sys_restart_timeouts(void)450 sys_restart_timeouts(void)
451 {}
452 
453 err_t
sys_timeout(u32_t msecs,sys_timeout_handler handler,void * arg)454 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
455 {
456   return sys_timeout_reg(msecs, handler, arg,
457 #if LOWPOWER_TIMER_DEBUG
458                          NULL,
459 #endif
460                          NULL);
461 }
462 
463 void
sys_timeout_set_wake_time(u32_t val)464 sys_timeout_set_wake_time(u32_t val)
465 {
466   g_wake_up_time = val;
467 }
468 
469 u32_t
sys_timeout_get_wake_time(void)470 sys_timeout_get_wake_time(void)
471 {
472   return g_wake_up_time;
473 }
474 
475 void
set_lowpower_mod(enum lowpower_mod sw)476 set_lowpower_mod(enum lowpower_mod sw)
477 {
478   g_lowpower_switch = sw;
479 }
480 
481 enum lowpower_mod
get_lowpowper_mod(void)482 get_lowpowper_mod(void)
483 {
484   return g_lowpower_switch;
485 }
486 #endif /* LWIP_LOWPOWER */
487