/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #include "phl_headers.h" #define _PHL_UTIL_C_ /* phl queue general API */ void pq_init(void *d, struct phl_queue *q) { INIT_LIST_HEAD(&q->queue); _os_spinlock_init(d, &q->lock); q->cnt = 0; } void pq_deinit(void *d, struct phl_queue *q) { _os_spinlock_free(d, &q->lock); } void pq_reset(void *d, struct phl_queue *q, enum lock_type type) { _os_spinlockfg sp_flags; _os_spinlock(d, &q->lock, type, &sp_flags); INIT_LIST_HEAD(&q->queue); q->cnt = 0; _os_spinunlock(d, &q->lock, type, &sp_flags); } u8 pq_push(void *d, struct phl_queue *q, _os_list *obj, u8 pos, enum lock_type type) { _os_spinlockfg sp_flags; _os_spinlock(d, &q->lock, type, &sp_flags); if(pos == _first) list_add(obj, &q->queue); else list_add_tail(obj, &q->queue); q->cnt++; _os_spinunlock(d, &q->lock, type, &sp_flags); return true; } u8 pq_pop(void *d, struct phl_queue *q, _os_list **obj, u8 pos, enum lock_type type) { _os_spinlockfg sp_flags = 0; (*obj) = NULL; _os_spinlock(d, &q->lock, type, &sp_flags); if(!list_empty(&q->queue) && (q->cnt > 0)) { if(pos == _first) (*obj) = _get_next(&q->queue); else (*obj) = _get_prev(&q->queue); list_del(*obj); q->cnt--; } _os_spinunlock(d, &q->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &q->queue) ? (false) : (true); } u8 pq_get_front(void *d, struct phl_queue *q, _os_list **obj, enum lock_type type) { _os_spinlockfg sp_flags = 0; (*obj) = NULL; _os_spinlock(d, &q->lock, type, &sp_flags); if(!list_empty(&q->queue) && (q->cnt > 0)) (*obj) = q->queue.next; _os_spinunlock(d, &q->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &q->queue) ? (false) : (true); } u8 pq_get_next(void *d, struct phl_queue *queue, _os_list *cur_obj, _os_list **obj, enum lock_type type) { _os_spinlockfg sp_flags; (*obj) = NULL; if(cur_obj == NULL) return false; _os_spinlock(d, &queue->lock, type, &sp_flags); (*obj) = cur_obj->next; _os_spinunlock(d, &queue->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &(queue->queue)) ? (false) : (true); } u8 pq_get_tail(void *d, struct phl_queue *q, _os_list **obj, enum lock_type type) { _os_spinlockfg sp_flags = 0; (*obj) = NULL; _os_spinlock(d, &q->lock, type, &sp_flags); if(!list_empty(&q->queue) && (q->cnt > 0)) (*obj) = q->queue.prev; _os_spinunlock(d, &q->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &q->queue) ? (false) : (true); } u8 pq_get_prev(void *d, struct phl_queue *queue, _os_list *cur_obj, _os_list **obj, enum lock_type type) { _os_spinlockfg sp_flags; (*obj) = NULL; if(cur_obj == NULL) return false; _os_spinlock(d, &queue->lock, type, &sp_flags); (*obj) = cur_obj->prev; _os_spinunlock(d, &queue->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &(queue->queue)) ? (false) : (true); } u8 pq_search_node(void *d, struct phl_queue *q, _os_list **obj, enum lock_type type, bool bdel, void *priv, u8 (*search_fun)(void *d, void *obj, void *priv)) { _os_spinlockfg sp_flags = 0; _os_list *newobj = NULL; bool bhit = false; (*obj) = NULL; _os_spinlock(d, &q->lock, type, &sp_flags); if(!list_empty(&q->queue) && (q->cnt > 0)) newobj = _get_next(&q->queue); while(newobj && (newobj != &(q->queue))) { if(search_fun) bhit = search_fun(d, newobj, priv); if(bhit && bdel) { list_del(newobj); q->cnt--; } if(bhit) { (*obj) = newobj; break; } newobj = newobj->next; }; _os_spinunlock(d, &q->lock, type, &sp_flags); return ((*obj) == NULL || (*obj) == &(q->queue)) ? (false) : (true); } void pq_del_node(void *d, struct phl_queue *q, _os_list *obj, enum lock_type type) { _os_spinlockfg sp_flags; if(obj == NULL) return; _os_spinlock(d, &q->lock, type, &sp_flags); list_del(obj); q->cnt--; _os_spinunlock(d, &q->lock, type, &sp_flags); } u8 pq_insert(void *d, struct phl_queue *q, enum lock_type type, void *priv, _os_list *input, u8 (*pq_predicate)(void *d, void *priv,_os_list *input, _os_list *obj)) { _os_spinlockfg sp_flags; _os_list *obj = NULL; _os_spinlock(d, &q->lock, type, &sp_flags); obj = q->queue.next; while (obj != &(q->queue)) { if (pq_predicate && (pq_predicate(d, priv, input, obj) == true)) break; obj = obj->next; } list_add_tail(input, obj); q->cnt++; _os_spinunlock(d, &q->lock, type, &sp_flags); return true; } u32 phl_get_passing_time_us(u32 start) { u32 now = _os_get_cur_time_us(); u32 pass = 0; if (now == start) pass = 0; else if (now > start) /* -- start -- now -- */ pass = now - start; else /* -- now -- start -- */ pass = 0xffffffff - start + now; return pass; } u32 phl_get_passing_time_ms(u32 start) { u32 now = _os_get_cur_time_ms(); u32 pass = 0; if (now == start) pass = 0; else if (now > start) /* -- start -- now -- */ pass = now - start; else /* -- now -- start -- */ pass = 0xffffffff - start + now; return pass; }