xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wl_timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 #include <wl_android.h>
2 #ifdef WL_TIMER
3 
4 #define TIMER_ERROR(name, arg1, args...) \
5 	do { \
6 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
7 			printf("[%s] TIMER-ERROR) %s : " arg1, name, __func__, ## args); \
8 		} \
9 	} while (0)
10 #define TIMER_TRACE(name, arg1, args...) \
11 	do { \
12 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
13 			printf("[%s] TIMER-TRACE) %s : " arg1, name, __func__, ## args); \
14 		} \
15 	} while (0)
16 
17 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18 	4 && __GNUC_MINOR__ >= 6))
19 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
20 _Pragma("GCC diagnostic push") \
21 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
22 (entry) = list_first_entry((ptr), type, member); \
23 _Pragma("GCC diagnostic pop") \
24 
25 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
26 _Pragma("GCC diagnostic push") \
27 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
28 entry = container_of((ptr), type, member); \
29 _Pragma("GCC diagnostic pop") \
30 
31 #else
32 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
33 (entry) = list_first_entry((ptr), type, member); \
34 
35 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
36 entry = container_of((ptr), type, member); \
37 
38 #endif /* STRICT_GCC_WARNINGS */
39 
40 typedef void(*FUNC_HANDLER) (void *cb_argu);
41 
42 struct wl_func_q {
43 	struct list_head eq_list;
44 	FUNC_HANDLER cb_func;
45 	void *cb_argu;
46 };
47 
48 typedef void(*TIMER_HANDLER) (void *cb_argu);
49 
50 typedef struct timer_handler_list {
51 	struct list_head list;
52 	struct net_device *net;
53 	timer_list_compat_t *timer;
54 	TIMER_HANDLER cb_func;
55 	void *cb_argu;
56 	uint tmo_ms;
57 	ulong tmo_jiffies;
58 } timer_handler_list_t;
59 
60 typedef struct wl_timer_params {
61 	dhd_pub_t *pub;
62 	struct list_head timer_list;
63 	struct list_head eq_list;
64 	timer_list_compat_t timer;
65 	spinlock_t eq_lock;
66 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
67 	struct workqueue_struct *timer_workq;
68 	struct work_struct timer_work;
69 	struct workqueue_struct *func_workq;
70 	struct work_struct func_work;
71 #else
72 	tsk_ctl_t thr_timer_ctl;
73 	tsk_ctl_t thr_func_ctl;
74 #endif
75 } wl_timer_params_t;
76 
77 static unsigned long
wl_func_lock_eq(struct wl_timer_params * timer_params)78 wl_func_lock_eq(struct wl_timer_params *timer_params)
79 {
80 	unsigned long flags;
81 
82 	spin_lock_irqsave(&timer_params->eq_lock, flags);
83 	return flags;
84 }
85 
86 static void
wl_func_unlock_eq(struct wl_timer_params * timer_params,unsigned long flags)87 wl_func_unlock_eq(struct wl_timer_params *timer_params, unsigned long flags)
88 {
89 	spin_unlock_irqrestore(&timer_params->eq_lock, flags);
90 }
91 
92 static void
wl_func_init_eq_lock(struct wl_timer_params * timer_params)93 wl_func_init_eq_lock(struct wl_timer_params *timer_params)
94 {
95 	spin_lock_init(&timer_params->eq_lock);
96 }
97 
98 static void
wl_func_init_eq(struct wl_timer_params * timer_params)99 wl_func_init_eq(struct wl_timer_params *timer_params)
100 {
101 	wl_func_init_eq_lock(timer_params);
102 	INIT_LIST_HEAD(&timer_params->eq_list);
103 }
104 
105 static void
wl_func_flush_eq(struct wl_timer_params * timer_params)106 wl_func_flush_eq(struct wl_timer_params *timer_params)
107 {
108 	struct wl_func_q *e;
109 	unsigned long flags;
110 
111 	flags = wl_func_lock_eq(timer_params);
112 	while (!list_empty_careful(&timer_params->eq_list)) {
113 		BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list);
114 		list_del(&e->eq_list);
115 		kfree(e);
116 	}
117 	wl_func_unlock_eq(timer_params, flags);
118 }
119 
120 static struct wl_func_q *
wl_func_deq(struct wl_timer_params * timer_params)121 wl_func_deq(struct wl_timer_params *timer_params)
122 {
123 	struct wl_func_q *e = NULL;
124 	unsigned long flags;
125 
126 	flags = wl_func_lock_eq(timer_params);
127 	if (likely(!list_empty(&timer_params->eq_list))) {
128 		BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list);
129 		list_del(&e->eq_list);
130 	}
131 	wl_func_unlock_eq(timer_params, flags);
132 
133 	return e;
134 }
135 
136 static s32
wl_func_enq(struct wl_timer_params * timer_params,void * cb_func,void * cb_argu)137 wl_func_enq(struct wl_timer_params *timer_params,
138 	void *cb_func, void *cb_argu)
139 {
140 	struct wl_func_q *e;
141 	s32 err = 0;
142 	uint32 funcq_size;
143 	unsigned long flags;
144 	gfp_t aflags;
145 
146 	funcq_size = sizeof(struct wl_func_q);
147 	aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
148 	e = kzalloc(funcq_size, aflags);
149 	if (unlikely(!e)) {
150 		TIMER_ERROR("wlan", "funcq_size alloc failed %d\n", funcq_size);
151 		return -ENOMEM;
152 	}
153 	e->cb_func = cb_func;
154 	e->cb_argu = cb_argu;
155 	flags = wl_func_lock_eq(timer_params);
156 	list_add_tail(&e->eq_list, &timer_params->eq_list);
157 	wl_func_unlock_eq(timer_params, flags);
158 
159 	return err;
160 }
161 
162 static void
wl_func_put(struct wl_func_q * e)163 wl_func_put(struct wl_func_q *e)
164 {
165 	kfree(e);
166 }
167 
168 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
169 static void wl_func_handler(struct work_struct *data);
170 #define WL_FUNC_HANDLER() static void wl_func_handler(struct work_struct *data)
171 #else
172 static int wl_func_handler(void *data);
173 #define WL_FUNC_HANDLER() static int wl_func_handler(void *data)
174 #endif
175 
WL_FUNC_HANDLER()176 WL_FUNC_HANDLER()
177 {
178 	struct wl_timer_params *timer_params = NULL;
179 	struct wl_func_q *e;
180 	struct net_device *net = NULL;
181 	dhd_pub_t *dhd;
182 	unsigned long flags = 0;
183 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
184 	tsk_ctl_t *tsk = (tsk_ctl_t *)data;
185 	timer_params = (struct wl_timer_params *)tsk->parent;
186 #else
187 	BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, func_work);
188 #endif
189 
190 	dhd = timer_params->pub;
191 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
192 	while (1) {
193 	if (down_interruptible(&tsk->sema) == 0) {
194 		SMP_RD_BARRIER_DEPENDS();
195 		if (tsk->terminated) {
196 			break;
197 		}
198 #endif
199 	DHD_EVENT_WAKE_LOCK(dhd);
200 	while ((e = wl_func_deq(timer_params))) {
201 		DHD_GENERAL_LOCK(dhd, flags);
202 		if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) {
203 			TIMER_ERROR(net->name, "BUS is DOWN.\n");
204 			DHD_GENERAL_UNLOCK(dhd, flags);
205 			goto fail;
206 		}
207 		DHD_GENERAL_UNLOCK(dhd, flags);
208 		e->cb_func(e->cb_argu);
209 fail:
210 		wl_func_put(e);
211 	}
212 	DHD_EVENT_WAKE_UNLOCK(dhd);
213 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
214 	} else {
215 		break;
216 	}
217 	}
218 	complete_and_exit(&tsk->completed, 0);
219 #endif
220 }
221 
222 void
wl_func_send(void * params,void * cb_func,void * cb_argu)223 wl_func_send(void *params, void *cb_func, void *cb_argu)
224 {
225 	struct wl_timer_params *timer_params = params;
226 
227 	if (timer_params == NULL) {
228 		TIMER_ERROR("wlan", "Stale ignored\n");
229 		return;
230 	}
231 
232 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
233 	if (timer_params->func_workq == NULL) {
234 		TIMER_ERROR("wlan", "Event handler is not created\n");
235 		return;
236 	}
237 #endif
238 
239 	if (likely(!wl_func_enq(timer_params, cb_func, cb_argu))) {
240 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
241 		queue_work(timer_params->func_workq, &timer_params->func_work);
242 #else
243 		if (timer_params->thr_func_ctl.thr_pid >= 0) {
244 			up(&timer_params->thr_func_ctl.sema);
245 		}
246 #endif
247 	}
248 }
249 
250 static s32
wl_func_create_handler(struct wl_timer_params * timer_params)251 wl_func_create_handler(struct wl_timer_params *timer_params)
252 {
253 	int ret = 0;
254 	TIMER_TRACE("wlan", "Enter\n");
255 
256 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
257 	if (!timer_params->func_workq) {
258 		timer_params->func_workq = alloc_workqueue("timer_funcd",
259 			WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);
260 	}
261 	if (!timer_params->func_workq) {
262 		TIMER_ERROR("wlan", "func_workq alloc_workqueue failed\n");
263 		ret = -ENOMEM;
264 	} else {
265 		INIT_WORK(&timer_params->func_work, wl_func_handler);
266 	}
267 #else
268 	PROC_START(wl_func_handler, timer_params, &timer_params->thr_func_ctl, 0, "timer_funcd");
269 	if (timer_params->thr_func_ctl.thr_pid < 0) {
270 		ret = -ENOMEM;
271 	}
272 #endif
273 
274 	return ret;
275 }
276 
277 static void
wl_func_destroy_handler(struct wl_timer_params * timer_params)278 wl_func_destroy_handler(struct wl_timer_params *timer_params)
279 {
280 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
281 	if (timer_params && timer_params->func_workq) {
282 		cancel_work_sync(&timer_params->func_work);
283 		destroy_workqueue(timer_params->func_workq);
284 		timer_params->func_workq = NULL;
285 	}
286 #else
287 	if (timer_params->thr_func_ctl.thr_pid >= 0) {
288 		PROC_STOP(&timer_params->thr_func_ctl);
289 	}
290 #endif
291 }
292 
293 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
294 static void wl_timer_handler(struct work_struct *data);
295 #define WL_TIMER_HANDLER() static void wl_timer_handler(struct work_struct *data)
296 #else
297 static int wl_timer_handler(void *data);
298 #define WL_TIMER_HANDLER() static int wl_timer_handler(void *data)
299 #endif
300 
WL_TIMER_HANDLER()301 WL_TIMER_HANDLER()
302 {
303 	struct wl_timer_params *timer_params = NULL;
304 	struct timer_handler_list *node, *next;
305 	dhd_pub_t *dhd;
306 	unsigned long flags = 0;
307 	unsigned long cur_jiffies, diff_jiffies, min_jiffies = 0;
308 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
309 	tsk_ctl_t *tsk = (tsk_ctl_t *)data;
310 	timer_params = (struct wl_timer_params *)tsk->parent;
311 #else
312 	BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, timer_work);
313 #endif
314 
315 	dhd = timer_params->pub;
316 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
317 	while (1) {
318 	if (down_interruptible(&tsk->sema) == 0) {
319 		SMP_RD_BARRIER_DEPENDS();
320 		if (tsk->terminated) {
321 			break;
322 		}
323 #endif
324 	DHD_EVENT_WAKE_LOCK(dhd);
325 	DHD_GENERAL_LOCK(dhd, flags);
326 	if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) {
327 		TIMER_ERROR("wlan", "BUS is DOWN.\n");
328 		DHD_GENERAL_UNLOCK(dhd, flags);
329 		goto exit;
330 	}
331 	DHD_GENERAL_UNLOCK(dhd, flags);
332 	cur_jiffies = jiffies;
333 	list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {
334 		if (node->tmo_ms) {
335 			if (time_after(cur_jiffies, node->tmo_jiffies)) {
336 				wl_func_send(timer_params, node->cb_func, node->cb_argu);
337 				node->tmo_ms = 0;
338 			} else {
339 				diff_jiffies = node->tmo_jiffies - cur_jiffies;
340 				if (min_jiffies == 0)
341 					min_jiffies = diff_jiffies;
342 				else if (diff_jiffies < min_jiffies)
343 					min_jiffies = diff_jiffies;
344 			}
345 		}
346 	}
347 	if (min_jiffies)
348 		mod_timer(&timer_params->timer, jiffies + min_jiffies);
349 exit:
350 	DHD_EVENT_WAKE_UNLOCK(dhd);
351 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
352 	} else {
353 		break;
354 	}
355 	}
356 	complete_and_exit(&tsk->completed, 0);
357 #endif
358 }
359 
360 void
wl_timer_kick_handler(wl_timer_params_t * timer_params)361 wl_timer_kick_handler(wl_timer_params_t *timer_params)
362 {
363 	if (timer_params == NULL) {
364 		TIMER_ERROR("wlan", "timer_params not ready\n");
365 		return;
366 	}
367 
368 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
369 	if (timer_params->timer_workq == NULL) {
370 		TIMER_ERROR("wlan", "timer handler is not created\n");
371 		return;
372 	}
373 	queue_work(timer_params->timer_workq, &timer_params->timer_work);
374 #else
375 	if (timer_params->thr_timer_ctl.thr_pid >= 0) {
376 		up(&timer_params->thr_timer_ctl.sema);
377 	}
378 #endif
379 }
380 
381 static void
wl_timer_timeout(unsigned long data)382 wl_timer_timeout(unsigned long data)
383 {
384 	struct wl_timer_params *timer_params = (struct wl_timer_params *)data;
385 
386 	if (!timer_params) {
387 		TIMER_ERROR("wlan", "timer_params is not ready\n");
388 		return;
389 	}
390 
391 	TIMER_TRACE("wlan", "timer expired\n");
392 	wl_timer_kick_handler(timer_params);
393 }
394 
395 static s32
wl_timer_create_handler(struct wl_timer_params * timer_params)396 wl_timer_create_handler(struct wl_timer_params *timer_params)
397 {
398 	int ret = 0;
399 
400 	TIMER_TRACE("wlan", "Enter\n");
401 
402 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
403 	if (!timer_params->timer_workq) {
404 		timer_params->timer_workq = alloc_workqueue("timerd",
405 			WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);
406 	}
407 	if (!timer_params->timer_workq) {
408 		TIMER_ERROR("wlan", "timer_workq alloc_workqueue failed\n");
409 		ret = -ENOMEM;
410 	} else {
411 		INIT_WORK(&timer_params->timer_work, wl_timer_handler);
412 	}
413 #else
414 	PROC_START(wl_timer_handler, timer_params, &timer_params->thr_timer_ctl, 0, "timerd");
415 	if (timer_params->thr_timer_ctl.thr_pid < 0) {
416 		ret = -ENOMEM;
417 	}
418 #endif
419 
420 	return ret;
421 }
422 
423 static void
wl_timer_destroy_handler(struct wl_timer_params * timer_params)424 wl_timer_destroy_handler(struct wl_timer_params *timer_params)
425 {
426 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
427 	if (timer_params && timer_params->timer_workq) {
428 		cancel_work_sync(&timer_params->timer_work);
429 		destroy_workqueue(timer_params->timer_workq);
430 		timer_params->timer_workq = NULL;
431 	}
432 #else
433 	if (timer_params->thr_timer_ctl.thr_pid >= 0) {
434 		PROC_STOP(&timer_params->thr_timer_ctl);
435 	}
436 #endif
437 }
438 
439 static void
wl_timer_free(struct wl_timer_params * timer_params)440 wl_timer_free(struct wl_timer_params *timer_params)
441 {
442 	timer_handler_list_t *node, *next;
443 
444 	list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {
445 		TIMER_TRACE(node->net->name, "Free timer\n");
446 		list_del(&node->list);
447 		kfree(node);
448 	}
449 }
450 
451 void
wl_timer_mod(dhd_pub_t * dhd,timer_list_compat_t * timer,uint32 tmo_ms)452 wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms)
453 {
454 	wl_timer_params_t *timer_params = dhd->timer_params;
455 	timer_handler_list_t *node, *next;
456 	bool found = FALSE;
457 
458 	list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {
459 		if (node->timer == timer) {
460 			node->tmo_ms = tmo_ms;
461 			if (tmo_ms) {
462 				TIMER_TRACE(node->net->name, "update timer %dms\n", tmo_ms);
463 				node->tmo_jiffies = jiffies + msecs_to_jiffies(tmo_ms);
464 				wl_timer_kick_handler(timer_params);
465 			}
466 			found = TRUE;
467 			break;
468 		}
469 	}
470 	if (!found)
471 		TIMER_ERROR("wlan", "timer not found\n");
472 }
473 
474 void
wl_timer_register(struct net_device * net,timer_list_compat_t * timer,void * cb_func)475 wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func)
476 {
477 	dhd_pub_t *dhd = dhd_get_pub(net);
478 	wl_timer_params_t *timer_params = dhd->timer_params;
479 	timer_handler_list_t *node, *next, *leaf;
480 
481 	list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {
482 		if (node->timer == timer) {
483 			TIMER_TRACE(net->name, "timer already registered\n");
484 			return;
485 		}
486 	}
487 
488 	leaf = kmalloc(sizeof(timer_handler_list_t), GFP_KERNEL);
489 	if (!leaf) {
490 		TIMER_ERROR(net->name, "Memory alloc failure %d\n",
491 			(int)sizeof(timer_handler_list_t));
492 		return;
493 	}
494 	memset(leaf, 0, sizeof(timer_handler_list_t));
495 	leaf->net = net;
496 	leaf->timer = timer;
497 	leaf->cb_func = cb_func;
498 	leaf->cb_argu = net;
499 	TIMER_ERROR(net->name, "timer registered tmo=%d\n", leaf->tmo_ms);
500 	list_add_tail(&leaf->list, &timer_params->timer_list);
501 
502 	return;
503 }
504 
505 void
wl_timer_deregister(struct net_device * net,timer_list_compat_t * timer)506 wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer)
507 {
508 	dhd_pub_t *dhd = dhd_get_pub(net);
509 	wl_timer_params_t *timer_params = dhd->timer_params;
510 	timer_handler_list_t *node, *next;
511 
512 	list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {
513 		if (node->timer == timer) {
514 			TIMER_TRACE(net->name, "timer deregistered\n");
515 			list_del(&node->list);
516 			kfree(node);
517 		}
518 	}
519 	return;
520 }
521 
522 static s32
wl_timer_init_priv(struct wl_timer_params * timer_params)523 wl_timer_init_priv(struct wl_timer_params *timer_params)
524 {
525 	s32 err = 0;
526 
527 	INIT_LIST_HEAD(&timer_params->timer_list);
528 	if (wl_timer_create_handler(timer_params))
529 		return -ENOMEM;
530 	wl_func_init_eq(timer_params);
531 	if (wl_func_create_handler(timer_params))
532 		return -ENOMEM;
533 
534 	return err;
535 }
536 
537 static void
wl_timer_deinit_priv(struct wl_timer_params * timer_params)538 wl_timer_deinit_priv(struct wl_timer_params *timer_params)
539 {
540 	wl_timer_free(timer_params);
541 	wl_func_destroy_handler(timer_params);
542 	wl_func_flush_eq(timer_params);
543 	wl_timer_destroy_handler(timer_params);
544 }
545 
546 void
wl_timer_dettach(dhd_pub_t * dhdp)547 wl_timer_dettach(dhd_pub_t *dhdp)
548 {
549 	struct wl_timer_params *timer_params = dhdp->timer_params;
550 
551 	if (timer_params) {
552 		if (timer_pending(&timer_params->timer))
553 			del_timer_sync(&timer_params->timer);
554 		wl_timer_deinit_priv(timer_params);
555 		kfree(timer_params);
556 		dhdp->timer_params = NULL;
557 	}
558 }
559 
560 s32
wl_timer_attach(struct net_device * net)561 wl_timer_attach(struct net_device *net)
562 {
563 	struct dhd_pub *dhdp = dhd_get_pub(net);
564 	struct wl_timer_params *timer_params = NULL;
565 	s32 err = 0;
566 
567 	timer_params = kmalloc(sizeof(wl_timer_params_t), GFP_KERNEL);
568 	if (!timer_params) {
569 		TIMER_ERROR(net->name, "Failed to allocate memory (%zu)\n",
570 			sizeof(wl_timer_params_t));
571 		return -ENOMEM;
572 	}
573 	dhdp->timer_params = timer_params;
574 	memset(timer_params, 0, sizeof(wl_timer_params_t));
575 	timer_params->pub = dhdp;
576 
577 	err = wl_timer_init_priv(timer_params);
578 	if (err) {
579 		TIMER_ERROR(net->name, "Failed to wl_timer_init_priv (%d)\n", err);
580 		goto exit;
581 	}
582 	init_timer_compat(&timer_params->timer, wl_timer_timeout, timer_params);
583 
584 exit:
585 	if (err)
586 		wl_timer_dettach(dhdp);
587 	return err;
588 }
589 #else
590 void
wl_timer_mod(dhd_pub_t * dhd,timer_list_compat_t * timer,uint32 tmo_ms)591 wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms)
592 {
593 	if (timer_pending(timer))
594 		del_timer_sync(timer);
595 	if (tmo_ms)
596 		mod_timer(timer, jiffies + msecs_to_jiffies(tmo_ms));
597 }
598 
599 void
wl_timer_register(struct net_device * net,timer_list_compat_t * timer,void * cb_func)600 wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func)
601 {
602 	init_timer_compat(timer, cb_func, net);
603 }
604 
605 void
wl_timer_deregister(struct net_device * net,timer_list_compat_t * timer)606 wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer)
607 {
608 	if (timer_pending(timer))
609 		del_timer_sync(timer);
610 }
611 #endif
612