1*5113495bSYour Name /*
2*5113495bSYour Name *
3*5113495bSYour Name * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4*5113495bSYour Name * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
5*5113495bSYour Name *
6*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for
7*5113495bSYour Name * any purpose with or without fee is hereby granted, provided that the
8*5113495bSYour Name * above copyright notice and this permission notice appear in all
9*5113495bSYour Name * copies.
10*5113495bSYour Name *
11*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12*5113495bSYour Name * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13*5113495bSYour Name * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14*5113495bSYour Name * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15*5113495bSYour Name * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
16*5113495bSYour Name * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
17*5113495bSYour Name * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18*5113495bSYour Name * PERFORMANCE OF THIS SOFTWARE.
19*5113495bSYour Name */
20*5113495bSYour Name /*
21*5113495bSYour Name * DOC: Public APIs to perform debug operations on object manager
22*5113495bSYour Name */
23*5113495bSYour Name
24*5113495bSYour Name #include <wlan_objmgr_psoc_obj.h>
25*5113495bSYour Name #include <wlan_objmgr_pdev_obj.h>
26*5113495bSYour Name #include <wlan_objmgr_vdev_obj.h>
27*5113495bSYour Name #include <wlan_objmgr_peer_obj.h>
28*5113495bSYour Name #include <wlan_objmgr_debug.h>
29*5113495bSYour Name #include "wlan_objmgr_global_obj_i.h"
30*5113495bSYour Name #include <qdf_mem.h>
31*5113495bSYour Name #include <qdf_platform.h>
32*5113495bSYour Name #include <qdf_str.h>
33*5113495bSYour Name
34*5113495bSYour Name /*
35*5113495bSYour Name * Default TTL (of FW) for mgmt frames is 5 sec, by considering all the other
36*5113495bSYour Name * delays, arrived with this value
37*5113495bSYour Name */
38*5113495bSYour Name #ifndef LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC
39*5113495bSYour Name #define LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC 8000
40*5113495bSYour Name #endif
41*5113495bSYour Name #ifndef LOG_DEL_OBJ_DESTROY_DURATION_SEC
42*5113495bSYour Name #define LOG_DEL_OBJ_DESTROY_DURATION_SEC 8
43*5113495bSYour Name #endif
44*5113495bSYour Name
45*5113495bSYour Name /*
46*5113495bSYour Name * The max duration for which a obj can be allowed to remain in L-state
47*5113495bSYour Name * The duration should be higher than the psoc idle timeout.
48*5113495bSYour Name */
49*5113495bSYour Name #define LOG_DEL_OBJ_DESTROY_ASSERT_DURATION_SEC 32
50*5113495bSYour Name #define LOG_DEL_OBJ_LIST_MAX_COUNT (3 + 5 + 48 + 4096)
51*5113495bSYour Name
52*5113495bSYour Name union wlan_objmgr_del_obj {
53*5113495bSYour Name struct wlan_objmgr_psoc *obj_psoc;
54*5113495bSYour Name struct wlan_objmgr_pdev *obj_pdev;
55*5113495bSYour Name struct wlan_objmgr_vdev *obj_vdev;
56*5113495bSYour Name struct wlan_objmgr_peer *obj_peer;
57*5113495bSYour Name };
58*5113495bSYour Name
59*5113495bSYour Name /**
60*5113495bSYour Name * struct log_del_obj - Logically deleted Object
61*5113495bSYour Name * @obj: Represents peer/vdev/pdev/psoc
62*5113495bSYour Name * @node: List node from Logically deleted list
63*5113495bSYour Name * @obj_type: Object type for peer/vdev/pdev/psoc
64*5113495bSYour Name * @tstamp: Timestamp when node entered logically
65*5113495bSYour Name * deleted state
66*5113495bSYour Name */
67*5113495bSYour Name struct log_del_obj {
68*5113495bSYour Name union wlan_objmgr_del_obj obj;
69*5113495bSYour Name qdf_list_node_t node;
70*5113495bSYour Name enum wlan_objmgr_obj_type obj_type;
71*5113495bSYour Name qdf_time_t tstamp;
72*5113495bSYour Name };
73*5113495bSYour Name
74*5113495bSYour Name /**
75*5113495bSYour Name * struct wlan_objmgr_debug_info - Objmgr debug info
76*5113495bSYour Name * for Logically deleted object
77*5113495bSYour Name * @obj_timer: Timer object
78*5113495bSYour Name * @obj_list: list object having linking logically
79*5113495bSYour Name * deleted nodes
80*5113495bSYour Name * @list_lock: lock to protect list
81*5113495bSYour Name */
82*5113495bSYour Name struct wlan_objmgr_debug_info {
83*5113495bSYour Name qdf_timer_t obj_timer;
84*5113495bSYour Name qdf_list_t obj_list;
85*5113495bSYour Name qdf_spinlock_t list_lock;
86*5113495bSYour Name };
87*5113495bSYour Name
88*5113495bSYour Name static const char *
wlan_obj_type_get_obj_name(enum wlan_objmgr_obj_type obj_type)89*5113495bSYour Name wlan_obj_type_get_obj_name(enum wlan_objmgr_obj_type obj_type)
90*5113495bSYour Name {
91*5113495bSYour Name static const struct wlan_obj_type_to_name {
92*5113495bSYour Name enum wlan_objmgr_obj_type obj_type;
93*5113495bSYour Name const char *name;
94*5113495bSYour Name } obj_type_name[WLAN_OBJ_TYPE_MAX] = {
95*5113495bSYour Name {WLAN_PSOC_OP, "psoc"},
96*5113495bSYour Name {WLAN_PDEV_OP, "pdev"},
97*5113495bSYour Name {WLAN_VDEV_OP, "vdev"},
98*5113495bSYour Name {WLAN_PEER_OP, "peer"}
99*5113495bSYour Name };
100*5113495bSYour Name uint8_t idx;
101*5113495bSYour Name
102*5113495bSYour Name for (idx = 0; idx < WLAN_OBJ_TYPE_MAX; idx++) {
103*5113495bSYour Name if (obj_type == obj_type_name[idx].obj_type)
104*5113495bSYour Name return obj_type_name[idx].name;
105*5113495bSYour Name }
106*5113495bSYour Name
107*5113495bSYour Name return NULL;
108*5113495bSYour Name }
109*5113495bSYour Name
110*5113495bSYour Name static uint8_t*
wlan_objmgr_debug_get_macaddr(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)111*5113495bSYour Name wlan_objmgr_debug_get_macaddr(union wlan_objmgr_del_obj *obj,
112*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
113*5113495bSYour Name {
114*5113495bSYour Name switch (obj_type) {
115*5113495bSYour Name case WLAN_PSOC_OP:
116*5113495bSYour Name return wlan_psoc_get_hw_macaddr(obj->obj_psoc);
117*5113495bSYour Name case WLAN_PDEV_OP:
118*5113495bSYour Name return wlan_pdev_get_hw_macaddr(obj->obj_pdev);
119*5113495bSYour Name case WLAN_VDEV_OP:
120*5113495bSYour Name return wlan_vdev_mlme_get_macaddr(obj->obj_vdev);
121*5113495bSYour Name case WLAN_PEER_OP:
122*5113495bSYour Name return wlan_peer_get_macaddr(obj->obj_peer);
123*5113495bSYour Name default:
124*5113495bSYour Name obj_mgr_err("invalid obj_type");
125*5113495bSYour Name return NULL;
126*5113495bSYour Name }
127*5113495bSYour Name }
128*5113495bSYour Name
129*5113495bSYour Name static void
wlan_objmgr_insert_ld_obj_to_list(struct wlan_objmgr_debug_info * debug_info,qdf_list_node_t * node)130*5113495bSYour Name wlan_objmgr_insert_ld_obj_to_list(struct wlan_objmgr_debug_info *debug_info,
131*5113495bSYour Name qdf_list_node_t *node)
132*5113495bSYour Name {
133*5113495bSYour Name /* Insert object to list with lock being held*/
134*5113495bSYour Name qdf_spin_lock_bh(&debug_info->list_lock);
135*5113495bSYour Name
136*5113495bSYour Name /* Start timer only when list is empty */
137*5113495bSYour Name if (qdf_list_empty(&debug_info->obj_list))
138*5113495bSYour Name qdf_timer_start(&debug_info->obj_timer,
139*5113495bSYour Name LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
140*5113495bSYour Name
141*5113495bSYour Name qdf_list_insert_back(&debug_info->obj_list, node);
142*5113495bSYour Name qdf_spin_unlock_bh(&debug_info->list_lock);
143*5113495bSYour Name }
144*5113495bSYour Name
wlan_obj_type_get_obj(union wlan_objmgr_del_obj * obj,union wlan_objmgr_del_obj * del_obj,enum wlan_objmgr_obj_type obj_type)145*5113495bSYour Name static void wlan_obj_type_get_obj(union wlan_objmgr_del_obj *obj,
146*5113495bSYour Name union wlan_objmgr_del_obj *del_obj,
147*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
148*5113495bSYour Name {
149*5113495bSYour Name switch (obj_type) {
150*5113495bSYour Name case WLAN_PSOC_OP:
151*5113495bSYour Name del_obj->obj_psoc = obj->obj_psoc;
152*5113495bSYour Name return;
153*5113495bSYour Name case WLAN_PDEV_OP:
154*5113495bSYour Name del_obj->obj_pdev = obj->obj_pdev;
155*5113495bSYour Name return;
156*5113495bSYour Name case WLAN_VDEV_OP:
157*5113495bSYour Name del_obj->obj_vdev = obj->obj_vdev;
158*5113495bSYour Name return;
159*5113495bSYour Name case WLAN_PEER_OP:
160*5113495bSYour Name del_obj->obj_peer = obj->obj_peer;
161*5113495bSYour Name return;
162*5113495bSYour Name default:
163*5113495bSYour Name obj_mgr_err("invalid obj_type");
164*5113495bSYour Name return;
165*5113495bSYour Name }
166*5113495bSYour Name }
167*5113495bSYour Name
wlan_objmgr_notify_log_delete(void * obj,enum wlan_objmgr_obj_type obj_type)168*5113495bSYour Name void wlan_objmgr_notify_log_delete(void *obj,
169*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
170*5113495bSYour Name {
171*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info;
172*5113495bSYour Name const char *obj_name;
173*5113495bSYour Name uint8_t *macaddr;
174*5113495bSYour Name qdf_time_t tstamp;
175*5113495bSYour Name struct log_del_obj *node;
176*5113495bSYour Name union wlan_objmgr_del_obj *del_obj = (union wlan_objmgr_del_obj *)&obj;
177*5113495bSYour Name
178*5113495bSYour Name if (!obj) {
179*5113495bSYour Name obj_mgr_err("object is null");
180*5113495bSYour Name return;
181*5113495bSYour Name }
182*5113495bSYour Name
183*5113495bSYour Name debug_info = g_umac_glb_obj->debug_info;
184*5113495bSYour Name
185*5113495bSYour Name if (!debug_info) {
186*5113495bSYour Name obj_mgr_err("debug_info is null");
187*5113495bSYour Name return;
188*5113495bSYour Name }
189*5113495bSYour Name
190*5113495bSYour Name macaddr = wlan_objmgr_debug_get_macaddr(del_obj, obj_type);
191*5113495bSYour Name if (!macaddr) {
192*5113495bSYour Name obj_mgr_err("macaddr is null");
193*5113495bSYour Name return;
194*5113495bSYour Name }
195*5113495bSYour Name
196*5113495bSYour Name obj_name = wlan_obj_type_get_obj_name(obj_type);
197*5113495bSYour Name if (!obj_name) {
198*5113495bSYour Name obj_mgr_err("obj_name is null");
199*5113495bSYour Name return;
200*5113495bSYour Name }
201*5113495bSYour Name
202*5113495bSYour Name tstamp = qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000;
203*5113495bSYour Name node = qdf_mem_malloc(sizeof(*node));
204*5113495bSYour Name if (!node)
205*5113495bSYour Name return;
206*5113495bSYour Name
207*5113495bSYour Name wlan_obj_type_get_obj(del_obj, &node->obj, obj_type);
208*5113495bSYour Name node->obj_type = obj_type;
209*5113495bSYour Name node->tstamp = tstamp;
210*5113495bSYour Name obj_mgr_debug("#%s : mac_addr: "QDF_MAC_ADDR_FMT" entered L-state",
211*5113495bSYour Name obj_name, QDF_MAC_ADDR_REF(macaddr));
212*5113495bSYour Name wlan_objmgr_insert_ld_obj_to_list(debug_info, &node->node);
213*5113495bSYour Name }
214*5113495bSYour Name
wlan_objmgr_del_obj_match(union wlan_objmgr_del_obj * obj,union wlan_objmgr_del_obj * del_obj,enum wlan_objmgr_obj_type obj_type)215*5113495bSYour Name static bool wlan_objmgr_del_obj_match(union wlan_objmgr_del_obj *obj,
216*5113495bSYour Name union wlan_objmgr_del_obj *del_obj,
217*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
218*5113495bSYour Name {
219*5113495bSYour Name switch (obj_type) {
220*5113495bSYour Name case WLAN_PSOC_OP:
221*5113495bSYour Name return (del_obj->obj_psoc == obj->obj_psoc);
222*5113495bSYour Name case WLAN_PDEV_OP:
223*5113495bSYour Name return (del_obj->obj_pdev == obj->obj_pdev);
224*5113495bSYour Name case WLAN_VDEV_OP:
225*5113495bSYour Name return (del_obj->obj_vdev == obj->obj_vdev);
226*5113495bSYour Name case WLAN_PEER_OP:
227*5113495bSYour Name return (del_obj->obj_peer == obj->obj_peer);
228*5113495bSYour Name default:
229*5113495bSYour Name return false;
230*5113495bSYour Name }
231*5113495bSYour Name }
232*5113495bSYour Name
233*5113495bSYour Name static void
wlan_objmgr_rem_ld_obj_from_list(union wlan_objmgr_del_obj * obj,struct wlan_objmgr_debug_info * debug_info,enum wlan_objmgr_obj_type obj_type)234*5113495bSYour Name wlan_objmgr_rem_ld_obj_from_list(union wlan_objmgr_del_obj *obj,
235*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info,
236*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
237*5113495bSYour Name {
238*5113495bSYour Name qdf_list_node_t *node = NULL;
239*5113495bSYour Name struct log_del_obj *obj_to_remove = NULL;
240*5113495bSYour Name qdf_list_t *list;
241*5113495bSYour Name QDF_STATUS status;
242*5113495bSYour Name
243*5113495bSYour Name list = &debug_info->obj_list;
244*5113495bSYour Name qdf_spin_lock_bh(&debug_info->list_lock);
245*5113495bSYour Name status = qdf_list_peek_front(list, &node);
246*5113495bSYour Name
247*5113495bSYour Name while (QDF_IS_STATUS_SUCCESS(status)) {
248*5113495bSYour Name obj_to_remove = qdf_container_of(node,
249*5113495bSYour Name struct log_del_obj, node);
250*5113495bSYour Name if (wlan_objmgr_del_obj_match(obj, &obj_to_remove->obj,
251*5113495bSYour Name obj_type) &&
252*5113495bSYour Name obj_to_remove->obj_type == obj_type) {
253*5113495bSYour Name status = qdf_list_remove_node(list,
254*5113495bSYour Name &obj_to_remove->node);
255*5113495bSYour Name /* Stop timer if list is empty */
256*5113495bSYour Name if (QDF_IS_STATUS_SUCCESS(status)) {
257*5113495bSYour Name if (qdf_list_empty(&debug_info->obj_list))
258*5113495bSYour Name qdf_timer_stop(&debug_info->obj_timer);
259*5113495bSYour Name qdf_mem_free(obj_to_remove);
260*5113495bSYour Name }
261*5113495bSYour Name break;
262*5113495bSYour Name }
263*5113495bSYour Name status = qdf_list_peek_next(list, node, &node);
264*5113495bSYour Name };
265*5113495bSYour Name qdf_spin_unlock_bh(&debug_info->list_lock);
266*5113495bSYour Name }
267*5113495bSYour Name
wlan_objmgr_notify_destroy(void * obj,enum wlan_objmgr_obj_type obj_type)268*5113495bSYour Name void wlan_objmgr_notify_destroy(void *obj,
269*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
270*5113495bSYour Name {
271*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info;
272*5113495bSYour Name uint8_t *macaddr;
273*5113495bSYour Name const char *obj_name;
274*5113495bSYour Name union wlan_objmgr_del_obj *del_obj = (union wlan_objmgr_del_obj *)&obj;
275*5113495bSYour Name
276*5113495bSYour Name debug_info = g_umac_glb_obj->debug_info;
277*5113495bSYour Name
278*5113495bSYour Name if (!debug_info) {
279*5113495bSYour Name obj_mgr_err("debug_info is null");
280*5113495bSYour Name return;
281*5113495bSYour Name }
282*5113495bSYour Name macaddr = wlan_objmgr_debug_get_macaddr(del_obj, obj_type);
283*5113495bSYour Name if (!macaddr) {
284*5113495bSYour Name obj_mgr_err("macaddr is null");
285*5113495bSYour Name return;
286*5113495bSYour Name }
287*5113495bSYour Name obj_name = wlan_obj_type_get_obj_name(obj_type);
288*5113495bSYour Name if (!obj_name) {
289*5113495bSYour Name obj_mgr_err("obj_name is null");
290*5113495bSYour Name return;
291*5113495bSYour Name }
292*5113495bSYour Name obj_mgr_debug("#%s : macaddr: "QDF_MAC_ADDR_FMT" exited L-state",
293*5113495bSYour Name obj_name, QDF_MAC_ADDR_REF(macaddr));
294*5113495bSYour Name
295*5113495bSYour Name wlan_objmgr_rem_ld_obj_from_list(del_obj,
296*5113495bSYour Name debug_info, obj_type);
297*5113495bSYour Name }
298*5113495bSYour Name
299*5113495bSYour Name /**
300*5113495bSYour Name * wlan_objmgr_debug_obj_destroyed_panic() - Panic in case obj is in L-state
301*5113495bSYour Name * for long
302*5113495bSYour Name * @obj_name: The name of the module ID
303*5113495bSYour Name *
304*5113495bSYour Name * This will invoke panic in the case that the obj is in logically destroyed
305*5113495bSYour Name * state for a long time. The panic is invoked only in case feature flag
306*5113495bSYour Name * WLAN_OBJMGR_PANIC_ON_BUG is enabled
307*5113495bSYour Name *
308*5113495bSYour Name * Return: None
309*5113495bSYour Name */
310*5113495bSYour Name #ifdef CONFIG_LEAK_DETECTION
wlan_objmgr_debug_obj_destroyed_panic(const char * obj_name)311*5113495bSYour Name static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name)
312*5113495bSYour Name {
313*5113495bSYour Name obj_mgr_alert("#%s in L-state for too long!", obj_name);
314*5113495bSYour Name QDF_BUG(0);
315*5113495bSYour Name }
316*5113495bSYour Name #else
wlan_objmgr_debug_obj_destroyed_panic(const char * obj_name)317*5113495bSYour Name static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name)
318*5113495bSYour Name {
319*5113495bSYour Name }
320*5113495bSYour Name #endif
321*5113495bSYour Name
322*5113495bSYour Name /*
323*5113495bSYour Name * wlan_objmgr_print_pending_refs() - Print pending refs according to the obj
324*5113495bSYour Name * @obj: Represents peer/vdev/pdev/psoc
325*5113495bSYour Name * @obj_type: Object type for peer/vdev/pdev/psoc
326*5113495bSYour Name *
327*5113495bSYour Name * Return: None
328*5113495bSYour Name */
wlan_objmgr_print_pending_refs(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)329*5113495bSYour Name static void wlan_objmgr_print_pending_refs(union wlan_objmgr_del_obj *obj,
330*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
331*5113495bSYour Name {
332*5113495bSYour Name switch (obj_type) {
333*5113495bSYour Name case WLAN_PSOC_OP:
334*5113495bSYour Name wlan_objmgr_print_ref_ids(obj->obj_psoc->soc_objmgr.ref_id_dbg,
335*5113495bSYour Name QDF_TRACE_LEVEL_DEBUG);
336*5113495bSYour Name break;
337*5113495bSYour Name case WLAN_PDEV_OP:
338*5113495bSYour Name wlan_objmgr_print_ref_ids(obj->obj_pdev->pdev_objmgr.ref_id_dbg,
339*5113495bSYour Name QDF_TRACE_LEVEL_DEBUG);
340*5113495bSYour Name break;
341*5113495bSYour Name case WLAN_VDEV_OP:
342*5113495bSYour Name wlan_objmgr_print_ref_ids(obj->obj_vdev->vdev_objmgr.ref_id_dbg,
343*5113495bSYour Name QDF_TRACE_LEVEL_DEBUG);
344*5113495bSYour Name break;
345*5113495bSYour Name case WLAN_PEER_OP:
346*5113495bSYour Name wlan_objmgr_print_ref_ids(obj->obj_peer->peer_objmgr.ref_id_dbg,
347*5113495bSYour Name QDF_TRACE_LEVEL_DEBUG);
348*5113495bSYour Name break;
349*5113495bSYour Name default:
350*5113495bSYour Name obj_mgr_debug("invalid obj_type");
351*5113495bSYour Name }
352*5113495bSYour Name }
353*5113495bSYour Name
354*5113495bSYour Name #ifdef WLAN_OBJMGR_REF_ID_TRACE
355*5113495bSYour Name static void
wlan_objmgr_print_ref_func_line(struct wlan_objmgr_trace_func * func_head,uint32_t id)356*5113495bSYour Name wlan_objmgr_print_ref_func_line(struct wlan_objmgr_trace_func *func_head,
357*5113495bSYour Name uint32_t id)
358*5113495bSYour Name {
359*5113495bSYour Name uint32_t ref_cnt;
360*5113495bSYour Name struct wlan_objmgr_line_ref_node *tmp_ln_node;
361*5113495bSYour Name
362*5113495bSYour Name obj_mgr_debug("ID: %s(%d)", string_from_dbgid(id), id);
363*5113495bSYour Name while (func_head) {
364*5113495bSYour Name obj_mgr_debug("Func: %s", func_head->func);
365*5113495bSYour Name tmp_ln_node = func_head->line_head;
366*5113495bSYour Name while (tmp_ln_node) {
367*5113495bSYour Name ref_cnt = qdf_atomic_read(&tmp_ln_node->line_ref.cnt);
368*5113495bSYour Name obj_mgr_debug("line: %d cnt: %d",
369*5113495bSYour Name tmp_ln_node->line_ref.line,
370*5113495bSYour Name ref_cnt);
371*5113495bSYour Name tmp_ln_node = tmp_ln_node->next;
372*5113495bSYour Name }
373*5113495bSYour Name func_head = func_head->next;
374*5113495bSYour Name }
375*5113495bSYour Name }
376*5113495bSYour Name
377*5113495bSYour Name static void
wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)378*5113495bSYour Name wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj,
379*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
380*5113495bSYour Name {
381*5113495bSYour Name uint32_t id;
382*5113495bSYour Name struct wlan_objmgr_trace_func *func_head;
383*5113495bSYour Name struct wlan_objmgr_trace *trace;
384*5113495bSYour Name struct wlan_objmgr_vdev_objmgr *vdev_obj;
385*5113495bSYour Name struct wlan_objmgr_peer_objmgr *peer_obj;
386*5113495bSYour Name
387*5113495bSYour Name switch (obj_type) {
388*5113495bSYour Name case WLAN_VDEV_OP:
389*5113495bSYour Name vdev_obj = &obj->obj_vdev->vdev_objmgr;
390*5113495bSYour Name trace = &vdev_obj->trace;
391*5113495bSYour Name for (id = 0; id < WLAN_REF_ID_MAX; id++) {
392*5113495bSYour Name if (qdf_atomic_read(&vdev_obj->ref_id_dbg[id])) {
393*5113495bSYour Name obj_mgr_debug("Reference:");
394*5113495bSYour Name
395*5113495bSYour Name func_head = trace->references[id].head;
396*5113495bSYour Name wlan_objmgr_print_ref_func_line(func_head, id);
397*5113495bSYour Name
398*5113495bSYour Name obj_mgr_debug("Dereference:");
399*5113495bSYour Name func_head = trace->dereferences[id].head;
400*5113495bSYour Name wlan_objmgr_print_ref_func_line(func_head, id);
401*5113495bSYour Name }
402*5113495bSYour Name }
403*5113495bSYour Name break;
404*5113495bSYour Name case WLAN_PEER_OP:
405*5113495bSYour Name peer_obj = &obj->obj_peer->peer_objmgr;
406*5113495bSYour Name trace = &peer_obj->trace;
407*5113495bSYour Name for (id = 0; id < WLAN_REF_ID_MAX; id++) {
408*5113495bSYour Name if (qdf_atomic_read(&peer_obj->ref_id_dbg[id])) {
409*5113495bSYour Name obj_mgr_debug("Reference:");
410*5113495bSYour Name
411*5113495bSYour Name func_head = trace->references[id].head;
412*5113495bSYour Name wlan_objmgr_print_ref_func_line(func_head, id);
413*5113495bSYour Name
414*5113495bSYour Name obj_mgr_debug("Dereference:");
415*5113495bSYour Name func_head = trace->dereferences[id].head;
416*5113495bSYour Name wlan_objmgr_print_ref_func_line(func_head, id);
417*5113495bSYour Name }
418*5113495bSYour Name }
419*5113495bSYour Name break;
420*5113495bSYour Name default:
421*5113495bSYour Name break;
422*5113495bSYour Name }
423*5113495bSYour Name }
424*5113495bSYour Name #else
425*5113495bSYour Name static void
wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)426*5113495bSYour Name wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj,
427*5113495bSYour Name enum wlan_objmgr_obj_type obj_type)
428*5113495bSYour Name {
429*5113495bSYour Name }
430*5113495bSYour Name #endif
431*5113495bSYour Name
432*5113495bSYour Name /* timeout handler for iterating logically deleted object */
433*5113495bSYour Name
wlan_objmgr_iterate_log_del_obj_handler(void * timer_arg)434*5113495bSYour Name static void wlan_objmgr_iterate_log_del_obj_handler(void *timer_arg)
435*5113495bSYour Name {
436*5113495bSYour Name enum wlan_objmgr_obj_type obj_type;
437*5113495bSYour Name uint8_t *macaddr;
438*5113495bSYour Name const char *obj_name;
439*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info;
440*5113495bSYour Name qdf_list_node_t *node;
441*5113495bSYour Name qdf_list_t *log_del_obj_list = NULL;
442*5113495bSYour Name struct log_del_obj *del_obj = NULL;
443*5113495bSYour Name qdf_time_t cur_tstamp;
444*5113495bSYour Name QDF_STATUS status;
445*5113495bSYour Name
446*5113495bSYour Name debug_info = g_umac_glb_obj->debug_info;
447*5113495bSYour Name
448*5113495bSYour Name if (!debug_info) {
449*5113495bSYour Name obj_mgr_err("debug_info is not initialized");
450*5113495bSYour Name return;
451*5113495bSYour Name }
452*5113495bSYour Name
453*5113495bSYour Name log_del_obj_list = &debug_info->obj_list;
454*5113495bSYour Name qdf_spin_lock_bh(&debug_info->list_lock);
455*5113495bSYour Name
456*5113495bSYour Name status = qdf_list_peek_front(log_del_obj_list, &node);
457*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
458*5113495bSYour Name qdf_spin_unlock_bh(&debug_info->list_lock);
459*5113495bSYour Name return;
460*5113495bSYour Name }
461*5113495bSYour Name
462*5113495bSYour Name /* compute the current timestamp in seconds
463*5113495bSYour Name * need to compare with destroy duration of object
464*5113495bSYour Name */
465*5113495bSYour Name cur_tstamp = (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
466*5113495bSYour Name
467*5113495bSYour Name do {
468*5113495bSYour Name del_obj = qdf_container_of(node, struct log_del_obj, node);
469*5113495bSYour Name obj_type = del_obj->obj_type;
470*5113495bSYour Name macaddr = wlan_objmgr_debug_get_macaddr(&del_obj->obj,
471*5113495bSYour Name obj_type);
472*5113495bSYour Name obj_name = wlan_obj_type_get_obj_name(obj_type);
473*5113495bSYour Name
474*5113495bSYour Name /* If object is in logically deleted state for time more than
475*5113495bSYour Name * destroy duration, print the object type and MAC
476*5113495bSYour Name */
477*5113495bSYour Name if (cur_tstamp < (del_obj->tstamp +
478*5113495bSYour Name LOG_DEL_OBJ_DESTROY_DURATION_SEC)) {
479*5113495bSYour Name break;
480*5113495bSYour Name }
481*5113495bSYour Name if (!macaddr) {
482*5113495bSYour Name obj_mgr_err("macaddr is null");
483*5113495bSYour Name QDF_BUG(0);
484*5113495bSYour Name break;
485*5113495bSYour Name }
486*5113495bSYour Name if (!obj_name) {
487*5113495bSYour Name obj_mgr_err("obj_name is null");
488*5113495bSYour Name QDF_BUG(0);
489*5113495bSYour Name break;
490*5113495bSYour Name }
491*5113495bSYour Name
492*5113495bSYour Name obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_FMT,
493*5113495bSYour Name obj_name, QDF_MAC_ADDR_REF(macaddr));
494*5113495bSYour Name wlan_objmgr_print_pending_refs(&del_obj->obj, obj_type);
495*5113495bSYour Name
496*5113495bSYour Name wlan_objmgr_trace_print_ref(&del_obj->obj, obj_type);
497*5113495bSYour Name if (cur_tstamp > del_obj->tstamp +
498*5113495bSYour Name LOG_DEL_OBJ_DESTROY_ASSERT_DURATION_SEC) {
499*5113495bSYour Name if (!qdf_is_recovering() && !qdf_is_fw_down())
500*5113495bSYour Name wlan_objmgr_debug_obj_destroyed_panic(obj_name);
501*5113495bSYour Name }
502*5113495bSYour Name
503*5113495bSYour Name status = qdf_list_peek_next(log_del_obj_list, node, &node);
504*5113495bSYour Name
505*5113495bSYour Name } while (QDF_IS_STATUS_SUCCESS(status));
506*5113495bSYour Name
507*5113495bSYour Name qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
508*5113495bSYour Name qdf_spin_unlock_bh(&debug_info->list_lock);
509*5113495bSYour Name }
510*5113495bSYour Name
wlan_objmgr_debug_info_deinit(void)511*5113495bSYour Name void wlan_objmgr_debug_info_deinit(void)
512*5113495bSYour Name {
513*5113495bSYour Name struct log_del_obj *obj_to_remove;
514*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info;
515*5113495bSYour Name qdf_list_node_t *node = NULL;
516*5113495bSYour Name qdf_list_t *list;
517*5113495bSYour Name bool is_child_alive = false;
518*5113495bSYour Name
519*5113495bSYour Name debug_info = g_umac_glb_obj->debug_info;
520*5113495bSYour Name
521*5113495bSYour Name if (!debug_info) {
522*5113495bSYour Name obj_mgr_err("debug_info is not initialized");
523*5113495bSYour Name return;
524*5113495bSYour Name }
525*5113495bSYour Name list = &debug_info->obj_list;
526*5113495bSYour Name
527*5113495bSYour Name qdf_spin_lock_bh(&debug_info->list_lock);
528*5113495bSYour Name
529*5113495bSYour Name /* Check if any child of global object is in L-state and remove it,
530*5113495bSYour Name * ideally it shouldn't be
531*5113495bSYour Name */
532*5113495bSYour Name while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
533*5113495bSYour Name is_child_alive = true;
534*5113495bSYour Name obj_to_remove = qdf_container_of(node,
535*5113495bSYour Name struct log_del_obj, node);
536*5113495bSYour Name if (qdf_list_empty(&debug_info->obj_list))
537*5113495bSYour Name qdf_timer_stop(&debug_info->obj_timer);
538*5113495bSYour Name /* free the object */
539*5113495bSYour Name qdf_mem_free(obj_to_remove);
540*5113495bSYour Name }
541*5113495bSYour Name qdf_spin_unlock_bh(&debug_info->list_lock);
542*5113495bSYour Name
543*5113495bSYour Name if (is_child_alive) {
544*5113495bSYour Name obj_mgr_alert("This shouldn't happen!!, No child of global"
545*5113495bSYour Name "object should be in L-state, as global obj"
546*5113495bSYour Name "is going to destroy");
547*5113495bSYour Name QDF_BUG(0);
548*5113495bSYour Name }
549*5113495bSYour Name
550*5113495bSYour Name /* free timer, destroy spinlock, list and debug_info object as
551*5113495bSYour Name * global object is going to free
552*5113495bSYour Name */
553*5113495bSYour Name qdf_list_destroy(list);
554*5113495bSYour Name qdf_timer_free(&debug_info->obj_timer);
555*5113495bSYour Name qdf_spinlock_destroy(&debug_info->list_lock);
556*5113495bSYour Name qdf_mem_free(debug_info);
557*5113495bSYour Name
558*5113495bSYour Name qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
559*5113495bSYour Name g_umac_glb_obj->debug_info = NULL;
560*5113495bSYour Name qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
561*5113495bSYour Name }
562*5113495bSYour Name
wlan_objmgr_debug_info_init(void)563*5113495bSYour Name void wlan_objmgr_debug_info_init(void)
564*5113495bSYour Name {
565*5113495bSYour Name struct wlan_objmgr_debug_info *debug_info;
566*5113495bSYour Name
567*5113495bSYour Name debug_info = qdf_mem_malloc(sizeof(*debug_info));
568*5113495bSYour Name if (!debug_info) {
569*5113495bSYour Name g_umac_glb_obj->debug_info = NULL;
570*5113495bSYour Name return;
571*5113495bSYour Name }
572*5113495bSYour Name
573*5113495bSYour Name /* Initialize timer with timeout handler */
574*5113495bSYour Name qdf_timer_init(NULL, &debug_info->obj_timer,
575*5113495bSYour Name wlan_objmgr_iterate_log_del_obj_handler,
576*5113495bSYour Name NULL, QDF_TIMER_TYPE_WAKE_APPS);
577*5113495bSYour Name
578*5113495bSYour Name /* Initialize the node_count to 0 and create list*/
579*5113495bSYour Name qdf_list_create(&debug_info->obj_list,
580*5113495bSYour Name LOG_DEL_OBJ_LIST_MAX_COUNT);
581*5113495bSYour Name
582*5113495bSYour Name /* Initialize the spin_lock to protect list */
583*5113495bSYour Name qdf_spinlock_create(&debug_info->list_lock);
584*5113495bSYour Name
585*5113495bSYour Name /* attach debug_info object to global object */
586*5113495bSYour Name g_umac_glb_obj->debug_info = debug_info;
587*5113495bSYour Name }
588*5113495bSYour Name
589*5113495bSYour Name #ifdef WLAN_OBJMGR_REF_ID_TRACE
590*5113495bSYour Name void
wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace * trace)591*5113495bSYour Name wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace *trace)
592*5113495bSYour Name {
593*5113495bSYour Name qdf_spinlock_create(&trace->trace_lock);
594*5113495bSYour Name }
595*5113495bSYour Name
596*5113495bSYour Name void
wlan_objmgr_trace_deinit_lock(struct wlan_objmgr_trace * trace)597*5113495bSYour Name wlan_objmgr_trace_deinit_lock(struct wlan_objmgr_trace *trace)
598*5113495bSYour Name {
599*5113495bSYour Name qdf_spinlock_destroy(&trace->trace_lock);
600*5113495bSYour Name }
601*5113495bSYour Name #endif
602*5113495bSYour Name
603*5113495bSYour Name #ifdef WLAN_OBJMGR_REF_ID_TRACE
604*5113495bSYour Name static inline struct wlan_objmgr_line_ref_node*
wlan_objmgr_trace_line_node_alloc(int line)605*5113495bSYour Name wlan_objmgr_trace_line_node_alloc(int line)
606*5113495bSYour Name {
607*5113495bSYour Name struct wlan_objmgr_line_ref_node *line_node;
608*5113495bSYour Name
609*5113495bSYour Name line_node = qdf_mem_malloc_atomic(sizeof(*line_node));
610*5113495bSYour Name if (!line_node)
611*5113495bSYour Name return NULL;
612*5113495bSYour Name
613*5113495bSYour Name line_node->line_ref.line = line;
614*5113495bSYour Name qdf_atomic_set(&line_node->line_ref.cnt, 1);
615*5113495bSYour Name line_node->next = NULL;
616*5113495bSYour Name
617*5113495bSYour Name return line_node;
618*5113495bSYour Name }
619*5113495bSYour Name
620*5113495bSYour Name static inline struct wlan_objmgr_trace_func*
wlan_objmgr_trace_ref_node_alloc(const char * func,int line)621*5113495bSYour Name wlan_objmgr_trace_ref_node_alloc(const char *func, int line)
622*5113495bSYour Name {
623*5113495bSYour Name struct wlan_objmgr_trace_func *func_node;
624*5113495bSYour Name struct wlan_objmgr_line_ref_node *line_node;
625*5113495bSYour Name
626*5113495bSYour Name func_node = qdf_mem_malloc_atomic(sizeof(*func_node));
627*5113495bSYour Name if (!func_node)
628*5113495bSYour Name return NULL;
629*5113495bSYour Name
630*5113495bSYour Name line_node = wlan_objmgr_trace_line_node_alloc(line);
631*5113495bSYour Name if (!line_node) {
632*5113495bSYour Name qdf_mem_free(func_node);
633*5113495bSYour Name return NULL;
634*5113495bSYour Name }
635*5113495bSYour Name
636*5113495bSYour Name func_node->line_head = line_node;
637*5113495bSYour Name qdf_str_lcopy(func_node->func, func, WLAN_OBJMGR_TRACE_FUNC_SIZE);
638*5113495bSYour Name func_node->next = NULL;
639*5113495bSYour Name
640*5113495bSYour Name return func_node;
641*5113495bSYour Name }
642*5113495bSYour Name
643*5113495bSYour Name static inline void
wlan_objmgr_trace_check_line(struct wlan_objmgr_trace_func * tmp_func_node,struct wlan_objmgr_trace * trace,int line)644*5113495bSYour Name wlan_objmgr_trace_check_line(struct wlan_objmgr_trace_func *tmp_func_node,
645*5113495bSYour Name struct wlan_objmgr_trace *trace, int line)
646*5113495bSYour Name {
647*5113495bSYour Name struct wlan_objmgr_line_ref_node *tmp_ln_node;
648*5113495bSYour Name
649*5113495bSYour Name tmp_ln_node = tmp_func_node->line_head;
650*5113495bSYour Name while (tmp_ln_node) {
651*5113495bSYour Name if (tmp_ln_node->line_ref.line == line) {
652*5113495bSYour Name qdf_atomic_inc(&tmp_ln_node->line_ref.cnt);
653*5113495bSYour Name break;
654*5113495bSYour Name }
655*5113495bSYour Name tmp_ln_node = tmp_ln_node->next;
656*5113495bSYour Name }
657*5113495bSYour Name if (!tmp_ln_node) {
658*5113495bSYour Name tmp_ln_node = wlan_objmgr_trace_line_node_alloc(line);
659*5113495bSYour Name if (tmp_ln_node) {
660*5113495bSYour Name tmp_ln_node->next = tmp_func_node->line_head;
661*5113495bSYour Name tmp_func_node->line_head = tmp_ln_node;
662*5113495bSYour Name }
663*5113495bSYour Name }
664*5113495bSYour Name }
665*5113495bSYour Name
666*5113495bSYour Name void
wlan_objmgr_trace_ref(struct wlan_objmgr_trace_func ** func_head,struct wlan_objmgr_trace * trace,const char * func,int line)667*5113495bSYour Name wlan_objmgr_trace_ref(struct wlan_objmgr_trace_func **func_head,
668*5113495bSYour Name struct wlan_objmgr_trace *trace,
669*5113495bSYour Name const char *func, int line)
670*5113495bSYour Name {
671*5113495bSYour Name struct wlan_objmgr_trace_func *tmp_func_node;
672*5113495bSYour Name struct wlan_objmgr_trace_func *func_node;
673*5113495bSYour Name
674*5113495bSYour Name qdf_spin_lock_bh(&trace->trace_lock);
675*5113495bSYour Name if (!*func_head) {
676*5113495bSYour Name tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func, line);
677*5113495bSYour Name if (tmp_func_node)
678*5113495bSYour Name *func_head = tmp_func_node;
679*5113495bSYour Name } else {
680*5113495bSYour Name tmp_func_node = *func_head;
681*5113495bSYour Name while (tmp_func_node) {
682*5113495bSYour Name func_node = tmp_func_node;
683*5113495bSYour Name if (!qdf_str_ncmp(tmp_func_node->func, func,
684*5113495bSYour Name WLAN_OBJMGR_TRACE_FUNC_SIZE - 1)) {
685*5113495bSYour Name wlan_objmgr_trace_check_line(tmp_func_node,
686*5113495bSYour Name trace, line);
687*5113495bSYour Name break;
688*5113495bSYour Name }
689*5113495bSYour Name tmp_func_node = tmp_func_node->next;
690*5113495bSYour Name }
691*5113495bSYour Name
692*5113495bSYour Name if (!tmp_func_node) {
693*5113495bSYour Name tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func,
694*5113495bSYour Name line);
695*5113495bSYour Name if (tmp_func_node)
696*5113495bSYour Name func_node->next = tmp_func_node;
697*5113495bSYour Name }
698*5113495bSYour Name }
699*5113495bSYour Name qdf_spin_unlock_bh(&trace->trace_lock);
700*5113495bSYour Name }
701*5113495bSYour Name
702*5113495bSYour Name static void
wlan_objmgr_trace_del_line(struct wlan_objmgr_line_ref_node ** line_head)703*5113495bSYour Name wlan_objmgr_trace_del_line(struct wlan_objmgr_line_ref_node **line_head)
704*5113495bSYour Name {
705*5113495bSYour Name struct wlan_objmgr_line_ref_node *del_tmp_node;
706*5113495bSYour Name struct wlan_objmgr_line_ref_node *line_node;
707*5113495bSYour Name
708*5113495bSYour Name line_node = *line_head;
709*5113495bSYour Name while (line_node) {
710*5113495bSYour Name del_tmp_node = line_node;
711*5113495bSYour Name line_node = line_node->next;
712*5113495bSYour Name qdf_mem_free(del_tmp_node);
713*5113495bSYour Name }
714*5113495bSYour Name *line_head = NULL;
715*5113495bSYour Name }
716*5113495bSYour Name
717*5113495bSYour Name void
wlan_objmgr_trace_del_ref_list(struct wlan_objmgr_trace * trace)718*5113495bSYour Name wlan_objmgr_trace_del_ref_list(struct wlan_objmgr_trace *trace)
719*5113495bSYour Name {
720*5113495bSYour Name struct wlan_objmgr_trace_func *func_node;
721*5113495bSYour Name struct wlan_objmgr_trace_func *del_tmp_node;
722*5113495bSYour Name uint32_t id;
723*5113495bSYour Name
724*5113495bSYour Name qdf_spin_lock_bh(&trace->trace_lock);
725*5113495bSYour Name for (id = 0; id < WLAN_REF_ID_MAX; id++) {
726*5113495bSYour Name func_node = trace->references[id].head;
727*5113495bSYour Name while (func_node) {
728*5113495bSYour Name del_tmp_node = func_node;
729*5113495bSYour Name wlan_objmgr_trace_del_line(&del_tmp_node->line_head);
730*5113495bSYour Name func_node = func_node->next;
731*5113495bSYour Name qdf_mem_free(del_tmp_node);
732*5113495bSYour Name }
733*5113495bSYour Name trace->references[id].head = NULL;
734*5113495bSYour Name }
735*5113495bSYour Name for (id = 0; id < WLAN_REF_ID_MAX; id++) {
736*5113495bSYour Name func_node = trace->dereferences[id].head;
737*5113495bSYour Name while (func_node) {
738*5113495bSYour Name del_tmp_node = func_node;
739*5113495bSYour Name wlan_objmgr_trace_del_line(&del_tmp_node->line_head);
740*5113495bSYour Name func_node = func_node->next;
741*5113495bSYour Name qdf_mem_free(del_tmp_node);
742*5113495bSYour Name }
743*5113495bSYour Name trace->dereferences[id].head = NULL;
744*5113495bSYour Name }
745*5113495bSYour Name qdf_spin_unlock_bh(&trace->trace_lock);
746*5113495bSYour Name }
747*5113495bSYour Name #endif
748