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