/* * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /** * DOC: i_qdf_timer * This file provides OS dependent timer API's. */ #ifndef _I_QDF_TIMER_H #define _I_QDF_TIMER_H #include #include #include #include #include "qdf_mc_timer.h" #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) #include #endif typedef void (*qdf_timer_func_t)(void *); struct __qdf_timer_t { struct timer_list os_timer; qdf_timer_func_t callback; void *context; }; #ifdef QDF_TIMER_MULTIPLIER_FRAC #define __qdf_scaled_msecs_to_jiffies(msec) \ (QDF_TIMER_MULTIPLIER_FRAC * msecs_to_jiffies(msec)) #else #define __qdf_scaled_msecs_to_jiffies(msec) \ (qdf_timer_get_multiplier() * msecs_to_jiffies(msec)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) static inline void __os_timer_shim(struct timer_list *os_timer) { struct __qdf_timer_t *timer = from_timer(timer, os_timer, os_timer); timer->callback(timer->context); } static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer, qdf_timer_func_t func, void *arg, QDF_TIMER_TYPE type) { struct timer_list *os_timer = &timer->os_timer; uint32_t flags = 0; timer->callback = func; timer->context = arg; if (type == QDF_TIMER_TYPE_SW) flags |= TIMER_DEFERRABLE; else if (type == QDF_TIMER_TYPE_SW_SPIN) flags |= TIMER_DEFERRABLE | TIMER_PINNED; if (object_is_on_stack(os_timer)) timer_setup_on_stack(os_timer, __os_timer_shim, flags); else timer_setup(os_timer, __os_timer_shim, flags); return QDF_STATUS_SUCCESS; } #else #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) #define setup_deferrable_timer(timer, fn, data) \ __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE) #endif static inline void __os_timer_shim(unsigned long addr) { struct __qdf_timer_t *timer = (void *)addr; timer->callback(timer->context); } static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer, qdf_timer_func_t func, void *arg, QDF_TIMER_TYPE type) { struct timer_list *os_timer = &timer->os_timer; bool is_on_stack = object_is_on_stack(os_timer); unsigned long addr = (unsigned long)timer; timer->callback = func; timer->context = arg; if (type == QDF_TIMER_TYPE_SW) { if (is_on_stack) setup_deferrable_timer_on_stack(os_timer, __os_timer_shim, addr); else setup_deferrable_timer(os_timer, __os_timer_shim, addr); } else if (type == QDF_TIMER_TYPE_SW_SPIN) { if (is_on_stack) __setup_timer_on_stack(os_timer, __os_timer_shim, addr, TIMER_DEFERRABLE | TIMER_PINNED); else __setup_timer(os_timer, __os_timer_shim, addr, TIMER_DEFERRABLE | TIMER_PINNED); } else { if (is_on_stack) setup_timer_on_stack(os_timer, __os_timer_shim, addr); else setup_timer(os_timer, __os_timer_shim, addr); } return QDF_STATUS_SUCCESS; } #endif /* KERNEL_VERSION(4, 15, 0)*/ static inline void __qdf_timer_start(struct __qdf_timer_t *timer, uint32_t msec) { struct timer_list *os_timer = &timer->os_timer; os_timer->expires = jiffies + __qdf_scaled_msecs_to_jiffies(msec); add_timer(os_timer); } static inline void __qdf_timer_start_on(struct __qdf_timer_t *timer, uint32_t msec, int cpu) { struct timer_list *os_timer = &timer->os_timer; os_timer->expires = jiffies + __qdf_scaled_msecs_to_jiffies(msec); add_timer_on(os_timer, cpu); } static inline bool __qdf_timer_mod(struct __qdf_timer_t *timer, uint32_t msec) { return mod_timer(&timer->os_timer, jiffies + __qdf_scaled_msecs_to_jiffies(msec)); } static inline bool __qdf_timer_stop(struct __qdf_timer_t *timer) { return !!del_timer(&timer->os_timer); } static inline void __qdf_timer_free(struct __qdf_timer_t *timer) { struct timer_list *os_timer = &timer->os_timer; del_timer_sync(os_timer); if (object_is_on_stack(os_timer)) destroy_timer_on_stack(os_timer); } static inline bool __qdf_timer_sync_cancel(struct __qdf_timer_t *timer) { return del_timer_sync(&timer->os_timer); } #endif /* _I_QDF_TIMER_H */