OSDN Git Service

soc: qcom: glink_debugfs: Fix strlcpy usage
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / soc / qcom / glink_debugfs.c
1 /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12 #include <linux/debugfs.h>
13 #include <linux/err.h>
14 #include <linux/ipc_logging.h>
15 #include <linux/list.h>
16 #include <linux/slab.h>
17 #include <soc/qcom/glink.h>
18 #include "glink_private.h"
19 #include "glink_core_if.h"
20
21
22 static const char * const ss_string[] = {
23         [GLINK_DBGFS_MPSS] = "mpss",
24         [GLINK_DBGFS_APSS] = "apss",
25         [GLINK_DBGFS_LPASS] = "lpass",
26         [GLINK_DBGFS_DSPS] = "dsps",
27         [GLINK_DBGFS_RPM] = "rpm",
28         [GLINK_DBGFS_WCNSS] = "wcnss",
29         [GLINK_DBGFS_LLOOP] = "lloop",
30         [GLINK_DBGFS_MOCK] = "mock"
31 };
32
33 static const char * const xprt_string[] = {
34         [GLINK_DBGFS_SMEM] = "smem",
35         [GLINK_DBGFS_SMD] = "smd",
36         [GLINK_DBGFS_XLLOOP] = "lloop",
37         [GLINK_DBGFS_XMOCK] = "mock",
38         [GLINK_DBGFS_XMOCK_LOW] = "mock_low",
39         [GLINK_DBGFS_XMOCK_HIGH] = "mock_high"
40 };
41
42 static const char * const ch_st_string[] = {
43         [GLINK_CHANNEL_CLOSED] = "CLOSED",
44         [GLINK_CHANNEL_OPENING] = "OPENING",
45         [GLINK_CHANNEL_OPENED] = "OPENED",
46         [GLINK_CHANNEL_CLOSING] = "CLOSING",
47 };
48
49 static const char * const xprt_st_string[] = {
50         [GLINK_XPRT_DOWN] = "DOWN",
51         [GLINK_XPRT_NEGOTIATING] = "NEGOT",
52         [GLINK_XPRT_OPENED] = "OPENED",
53         [GLINK_XPRT_FAILED] = "FAILED"
54 };
55
56 #if defined(CONFIG_DEBUG_FS)
57 #define GLINK_DBGFS_NAME_SIZE (2 * GLINK_NAME_SIZE + 1)
58
59 struct glink_dbgfs_dent {
60         struct list_head list_node;
61         char par_name[GLINK_DBGFS_NAME_SIZE];
62         char self_name[GLINK_DBGFS_NAME_SIZE];
63         struct dentry *parent;
64         struct dentry *self;
65         spinlock_t file_list_lock_lhb0;
66         struct list_head file_list;
67 };
68
69 static struct dentry *dent;
70 static LIST_HEAD(dent_list);
71 static DEFINE_MUTEX(dent_list_lock_lha0);
72
73 static int debugfs_show(struct seq_file *s, void *data)
74 {
75         struct glink_dbgfs_data *dfs_d;
76         dfs_d = s->private;
77         dfs_d->o_func(s);
78         return 0;
79 }
80
81 static int debug_open(struct inode *inode, struct file *file)
82 {
83         return single_open(file, debugfs_show, inode->i_private);
84 }
85
86 static const struct file_operations debug_ops = {
87         .open = debug_open,
88         .release = single_release,
89         .read = seq_read,
90         .llseek = seq_lseek,
91 };
92 #endif
93
94 /**
95  * glink_get_ss_enum_string() - get the name of the subsystem based on enum value
96  * @enum_id:    enum id of a specific subsystem.
97  *
98  * Return: name of the subsystem, NULL in case of invalid input
99  */
100 const char *glink_get_ss_enum_string(unsigned int enum_id)
101 {
102         if (enum_id >= ARRAY_SIZE(ss_string))
103                 return NULL;
104
105         return ss_string[enum_id];
106 }
107 EXPORT_SYMBOL(glink_get_ss_enum_string);
108
109 /**
110  * glink_get_xprt_enum_string() - get the name of the transport based on enum value
111  * @enum_id:    enum id of a specific transport.
112  *
113  * Return: name of the transport, NULL in case of invalid input
114  */
115 const char *glink_get_xprt_enum_string(unsigned int enum_id)
116 {
117         if (enum_id >= ARRAY_SIZE(xprt_string))
118                 return NULL;
119         return xprt_string[enum_id];
120 }
121 EXPORT_SYMBOL(glink_get_xprt_enum_string);
122
123 /**
124  * glink_get_xprt_state_string() - get the name of the transport based on enum value
125  * @enum_id:    enum id of the state of the transport.
126  *
127  * Return: name of the transport state, NULL in case of invalid input
128  */
129 const char *glink_get_xprt_state_string(
130                                 enum transport_state_e enum_id)
131 {
132         if (enum_id >= ARRAY_SIZE(xprt_st_string))
133                 return NULL;
134
135         return xprt_st_string[enum_id];
136 }
137 EXPORT_SYMBOL(glink_get_xprt_state_string);
138
139 /**
140  * glink_get_ch_state_string() - get the name of the transport based on enum value
141  * @enum_id:    enum id of a specific state of the channel.
142  *
143  * Return: name of the channel state, NULL in case of invalid input
144  */
145 const char *glink_get_ch_state_string(
146                                 enum local_channel_state_e enum_id)
147 {
148         if (enum_id >= ARRAY_SIZE(ch_st_string))
149                 return NULL;
150
151         return ch_st_string[enum_id];
152 }
153 EXPORT_SYMBOL(glink_get_ch_state_string);
154
155 #if defined(CONFIG_DEBUG_FS)
156 /**
157  * glink_dfs_create_file() - create the debugfs file
158  * @name:       debugfs file name
159  * @parent:     pointer to the parent dentry structure
160  * @show:       pointer to the actual function which will be invoked upon
161  *              opening this file.
162  *
163  * Return:      pointer to the allocated glink_dbgfs_data structure or
164  *              NULL in case of an error.
165  *
166  * This function actually create a debugfs file under the parent directory
167  */
168 static struct glink_dbgfs_data *glink_dfs_create_file(const char *name,
169                 struct dentry *parent, void (*show)(struct seq_file *s),
170                 void *dbgfs_data, bool b_free_req)
171 {
172         struct dentry *file;
173         struct glink_dbgfs_data *dfs_d;
174
175         dfs_d = kzalloc(sizeof(struct glink_dbgfs_data), GFP_KERNEL);
176         if (dfs_d == NULL)
177                 return NULL;
178
179         dfs_d->o_func = show;
180         if (dbgfs_data != NULL) {
181                 dfs_d->priv_data = dbgfs_data;
182                 dfs_d->b_priv_free_req = b_free_req;
183         }
184         file = debugfs_create_file(name, 0400, parent, dfs_d, &debug_ops);
185         if (!file)
186                 GLINK_DBG("%s: unable to create file '%s'\n", __func__,
187                                 name);
188         dfs_d->dent = file;
189         return dfs_d;
190 }
191
192 /**
193  * write_ch_intent() - write channel intent details
194  * @s:          pointer to the sequential file
195  * @intent:     pointer glink core intent structure
196  * @i_type:     type of intent
197  * @count:      serial number of the intent.
198  *
199  * This function is a helper function of glink_dfs_update_ch_intents()
200  * that prints out details of any specific intent.
201  */
202 static void write_ch_intent(struct seq_file *s,
203                         struct glink_core_rx_intent *intent,
204                         char *i_type, unsigned int count)
205 {
206         char *intent_type;
207         /*
208         * formatted, human readable channel state output, ie:
209         * TYPE       |SN  |ID |PKT_SIZE|W_OFFSET|INT_SIZE|
210         * --------------------------------------------------------------
211         * LOCAL_LIST|#2  |1   |0       |0       |8       |
212         */
213         if (count == 1) {
214                 intent_type = i_type;
215                 seq_puts(s,
216                 "\n--------------------------------------------------------\n");
217         } else {
218                 intent_type = "";
219         }
220         seq_printf(s, "%-20s|#%-5d|%-6u|%-10zu|%-10zu|%-10zu|\n",
221                         intent_type,
222                         count,
223                         intent->id,
224                         intent->pkt_size,
225                         intent->write_offset,
226                         intent->intent_size);
227 }
228
229 /**
230  * glink_dfs_update_ch_intent() - writes the intent details of a specific
231  *                                channel to the corresponding debugfs file
232  * @s:          pointer to the sequential file
233  *
234  * This function extracts the intent details of a channel & prints them to
235  * corrseponding debugfs file of that channel.
236  */
237 static void glink_dfs_update_ch_intent(struct seq_file *s)
238 {
239         struct glink_dbgfs_data *dfs_d;
240         struct channel_ctx *ch_ctx;
241         struct glink_core_rx_intent *intent;
242         struct glink_core_rx_intent *intent_temp;
243         struct glink_ch_intent_info ch_intent_info;
244         unsigned long flags;
245         unsigned int count = 0;
246
247         dfs_d = s->private;
248         ch_ctx = dfs_d->priv_data;
249         if (ch_ctx != NULL) {
250                 glink_get_ch_intent_info(ch_ctx, &ch_intent_info);
251                 seq_puts(s,
252                 "---------------------------------------------------------------\n");
253                 seq_printf(s, "%-20s|%-6s|%-6s|%-10s|%-10s|%-10s|\n",
254                                         "INTENT TYPE",
255                                         "SN",
256                                         "ID",
257                                         "PKT_SIZE",
258                                         "W_OFFSET",
259                                         "INT_SIZE");
260                 seq_puts(s,
261                 "---------------------------------------------------------------\n");
262                 spin_lock_irqsave(ch_intent_info.li_lst_lock, flags);
263                 list_for_each_entry_safe(intent, intent_temp,
264                                 ch_intent_info.li_avail_list, list) {
265                         count++;
266                         write_ch_intent(s, intent, "LOCAL_AVAIL_LIST", count);
267                 }
268
269                 count = 0;
270                 list_for_each_entry_safe(intent, intent_temp,
271                                 ch_intent_info.li_used_list, list) {
272                         count++;
273                         write_ch_intent(s, intent, "LOCAL_USED_LIST", count);
274                 }
275                 spin_unlock_irqrestore(ch_intent_info.li_lst_lock, flags);
276
277                 count = 0;
278                 spin_lock_irqsave(ch_intent_info.ri_lst_lock, flags);
279                 list_for_each_entry_safe(intent, intent_temp,
280                                 ch_intent_info.ri_list, list) {
281                         count++;
282                         write_ch_intent(s, intent, "REMOTE_LIST", count);
283                 }
284                 spin_unlock_irqrestore(ch_intent_info.ri_lst_lock,
285                                         flags);
286                 seq_puts(s,
287                 "---------------------------------------------------------------\n");
288         }
289 }
290
291 /**
292  * glink_dfs_update_ch_stats() - writes statistics of a specific
293  *                               channel to the corresponding debugfs file
294  * @s:          pointer to the sequential file
295  *
296  * This function extracts other statistics of a channel & prints them to
297  * corrseponding debugfs file of that channel
298  */
299 static void glink_dfs_update_ch_stats(struct seq_file *s)
300 {
301         /* FUTURE:  add channel statistics */
302         seq_puts(s, "not yet implemented\n");
303 }
304
305 /**
306  * glink_debugfs_remove_channel() - remove all channel specifc files & folder in
307  *                               debugfs when channel is fully closed
308  * @ch_ctx:             pointer to the channel_contenxt
309  * @xprt_ctx:           pointer to the transport_context
310  *
311  * This function is invoked when any channel is fully closed. It removes the
312  * folders & other files in debugfs for that channel.
313  */
314 void glink_debugfs_remove_channel(struct channel_ctx *ch_ctx,
315                         struct glink_core_xprt_ctx *xprt_ctx){
316
317         struct glink_dbgfs ch_rm_dbgfs;
318         char *edge_name;
319         char curr_dir_name[GLINK_DBGFS_NAME_SIZE];
320         char *xprt_name;
321
322         ch_rm_dbgfs.curr_name = glink_get_ch_name(ch_ctx);
323         edge_name = glink_get_xprt_edge_name(xprt_ctx);
324         xprt_name = glink_get_xprt_name(xprt_ctx);
325         if (!xprt_name || !edge_name) {
326                 GLINK_ERR("%s: Invalid xprt_name  or edge_name for ch '%s'\n",
327                                 __func__, ch_rm_dbgfs.curr_name);
328                 return;
329         }
330         snprintf(curr_dir_name, sizeof(curr_dir_name), "%s_%s",
331                                         edge_name, xprt_name);
332         ch_rm_dbgfs.par_name = curr_dir_name;
333         glink_debugfs_remove_recur(&ch_rm_dbgfs);
334 }
335 EXPORT_SYMBOL(glink_debugfs_remove_channel);
336
337 /**
338  * glink_debugfs_add_channel() - create channel specifc files & folder in
339  *                               debugfs when channel is added
340  * @ch_ctx:             pointer to the channel_contenxt
341  * @xprt_ctx:           pointer to the transport_context
342  *
343  * This function is invoked when a new channel is created. It creates the
344  * folders & other files in debugfs for that channel
345  */
346 void glink_debugfs_add_channel(struct channel_ctx *ch_ctx,
347                 struct glink_core_xprt_ctx *xprt_ctx)
348 {
349         struct glink_dbgfs ch_dbgfs;
350         char *ch_name;
351         char *edge_name;
352         char *xprt_name;
353         char curr_dir_name[GLINK_DBGFS_NAME_SIZE];
354
355         if (ch_ctx == NULL) {
356                 GLINK_ERR("%s: Channel Context is NULL\n", __func__);
357                 return;
358         }
359
360         ch_name = glink_get_ch_name(ch_ctx);
361         edge_name =  glink_get_xprt_edge_name(xprt_ctx);
362         xprt_name =  glink_get_xprt_name(xprt_ctx);
363         if (!xprt_name || !edge_name) {
364                 GLINK_ERR("%s: Invalid xprt_name  or edge_name for ch '%s'\n",
365                                 __func__, ch_name);
366                 return;
367         }
368         snprintf(curr_dir_name, sizeof(curr_dir_name), "%s_%s",
369                                         edge_name, xprt_name);
370
371         ch_dbgfs.curr_name = curr_dir_name;
372         ch_dbgfs.par_name = "channel";
373         ch_dbgfs.b_dir_create = true;
374         glink_debugfs_create(ch_name, NULL, &ch_dbgfs, NULL, false);
375
376         ch_dbgfs.par_name = ch_dbgfs.curr_name;
377         ch_dbgfs.curr_name = ch_name;
378         ch_dbgfs.b_dir_create = false;
379         glink_debugfs_create("stats", glink_dfs_update_ch_stats,
380                                 &ch_dbgfs, (void *)ch_ctx, false);
381         glink_debugfs_create("intents", glink_dfs_update_ch_intent,
382                         &ch_dbgfs, (void *)ch_ctx, false);
383 }
384 EXPORT_SYMBOL(glink_debugfs_add_channel);
385
386 /**
387  * glink_debugfs_add_xprt() - create transport specifc files & folder in
388  *                            debugfs when new transport is registerd
389  * @xprt_ctx:           pointer to the transport_context
390  *
391  * This function is invoked when a new transport is registered. It creates the
392  * folders & other files in debugfs for that transport
393  */
394 void glink_debugfs_add_xprt(struct glink_core_xprt_ctx *xprt_ctx)
395 {
396         struct glink_dbgfs xprt_dbgfs;
397         char *xprt_name;
398         char *edge_name;
399         char curr_dir_name[GLINK_DBGFS_NAME_SIZE];
400
401         if (xprt_ctx == NULL)
402                 GLINK_ERR("%s: Transport Context is NULL\n", __func__);
403         xprt_name = glink_get_xprt_name(xprt_ctx);
404         edge_name = glink_get_xprt_edge_name(xprt_ctx);
405         if (!xprt_name || !edge_name) {
406                 GLINK_ERR("%s: xprt name or edge name is NULL\n", __func__);
407                 return;
408         }
409         snprintf(curr_dir_name, sizeof(curr_dir_name), "%s_%s",
410                                         edge_name, xprt_name);
411         xprt_dbgfs.par_name = "glink";
412         xprt_dbgfs.curr_name = "xprt";
413         xprt_dbgfs.b_dir_create = true;
414         glink_debugfs_create(curr_dir_name, NULL, &xprt_dbgfs, NULL, false);
415         xprt_dbgfs.curr_name = "channel";
416         glink_debugfs_create(curr_dir_name, NULL, &xprt_dbgfs, NULL, false);
417 }
418 EXPORT_SYMBOL(glink_debugfs_add_xprt);
419
420 /**
421  * glink_dfs_create_channel_list() - create & update the channel details
422  * s:   pointer to seq_file
423  *
424  * This function updates channel details in debugfs
425  * file present in /glink/channel/channels
426  */
427 static void glink_dfs_create_channel_list(struct seq_file *s)
428 {
429         struct xprt_ctx_iterator xprt_iter;
430         struct ch_ctx_iterator ch_iter;
431
432         struct glink_core_xprt_ctx *xprt_ctx;
433         struct channel_ctx *ch_ctx;
434         int count = 0;
435         /*
436         * formatted, human readable channel state output, ie:
437         * NAME               |LCID|RCID|XPRT|EDGE|LSTATE |RSTATE|LINT-Q|RINT-Q|
438         * --------------------------------------------------------------------
439         * LOCAL_LOOPBACK_CLNT|2   |1  |lloop|local|OPENED|OPENED|5     |6    |
440         * N.B. Number of TX & RX Packets not implemented yet. -ENOSYS is printed
441         */
442         seq_printf(s, "%-20s|%-4s|%-4s|%-10s|%-6s|%-7s|%-7s|%-5s|%-5s|\n",
443                                                                 "NAME",
444                                                                 "LCID",
445                                                                 "RCID",
446                                                                 "XPRT",
447                                                                 "EDGE",
448                                                                 "LSTATE",
449                                                                 "RSTATE",
450                                                                 "LINTQ",
451                                                                 "RINTQ");
452         seq_puts(s,
453                 "-------------------------------------------------------------------------------\n");
454         glink_xprt_ctx_iterator_init(&xprt_iter);
455         xprt_ctx = glink_xprt_ctx_iterator_next(&xprt_iter);
456
457         while (xprt_ctx != NULL) {
458                 glink_ch_ctx_iterator_init(&ch_iter, xprt_ctx);
459                 ch_ctx = glink_ch_ctx_iterator_next(&ch_iter);
460                 while (ch_ctx != NULL) {
461                         count++;
462                         seq_printf(s, "%-20s|%-4i|%-4i|%-10s|%-6s|%-7s|",
463                                         glink_get_ch_name(ch_ctx),
464                                         glink_get_ch_lcid(ch_ctx),
465                                         glink_get_ch_rcid(ch_ctx),
466                                         glink_get_ch_xprt_name(ch_ctx),
467                                         glink_get_ch_edge_name(ch_ctx),
468                                         glink_get_ch_lstate(ch_ctx));
469                         seq_printf(s, "%-7s|%-5i|%-5i|\n",
470                         (glink_get_ch_rstate(ch_ctx) ? "OPENED" : "CLOSED"),
471                         glink_get_ch_lintents_queued(ch_ctx),
472                         glink_get_ch_rintents_queued(ch_ctx));
473
474                         ch_ctx = glink_ch_ctx_iterator_next(&ch_iter);
475                 }
476                 glink_ch_ctx_iterator_end(&ch_iter, xprt_ctx);
477                 xprt_ctx = glink_xprt_ctx_iterator_next(&xprt_iter);
478         }
479
480         glink_xprt_ctx_iterator_end(&xprt_iter);
481 }
482
483 /**
484  * glink_dfs_create_xprt_list() - create & update the transport details
485  * @s:  pointer to seq_file
486  *
487  * This function updates channel details in debugfs file present
488  * in /glink/xprt/xprts
489  */
490 static void glink_dfs_create_xprt_list(struct seq_file *s)
491 {
492         struct xprt_ctx_iterator xprt_iter;
493         struct glink_core_xprt_ctx *xprt_ctx;
494         const struct glink_core_version  *gver;
495         uint32_t version;
496         uint32_t features;
497         int count = 0;
498         /*
499         * formatted, human readable channel state output, ie:
500         * XPRT_NAME|REMOTE    |STATE|VERSION |FEATURES|
501         * ---------------------------------------------
502         * smd_trans|lpass     |2    |0       |1       |
503         * smem     |mpss      |0    |0       |0       |
504         */
505         seq_printf(s, "%-20s|%-20s|%-6s|%-8s|%-8s|\n",
506                                                         "XPRT_NAME",
507                                                         "REMOTE",
508                                                         "STATE",
509                                                         "VERSION",
510                                                         "FEATURES");
511         seq_puts(s,
512                 "-------------------------------------------------------------------------------\n");
513         glink_xprt_ctx_iterator_init(&xprt_iter);
514         xprt_ctx = glink_xprt_ctx_iterator_next(&xprt_iter);
515
516         while (xprt_ctx != NULL) {
517                 count++;
518                 seq_printf(s, "%-20s|%-20s|",
519                                         glink_get_xprt_name(xprt_ctx),
520                                         glink_get_xprt_edge_name(xprt_ctx));
521                 gver = glink_get_xprt_version_features(xprt_ctx);
522                 if (gver != NULL) {
523                         version = gver->version;
524                         features = gver->features;
525                         seq_printf(s, "%-6s|%-8i|%-8i|\n",
526                                         glink_get_xprt_state(xprt_ctx),
527                                         version,
528                                         features);
529                 } else {
530                         seq_printf(s, "%-6s|%-8i|%-8i|\n",
531                                         glink_get_xprt_state(xprt_ctx),
532                                         -ENODATA,
533                                         -ENODATA);
534                 }
535                 xprt_ctx = glink_xprt_ctx_iterator_next(&xprt_iter);
536
537         }
538
539         glink_xprt_ctx_iterator_end(&xprt_iter);
540 }
541
542 /**
543  * glink_dfs_update_list() - update the internally maintained dentry linked list
544  * @curr_dent:  pointer to the current dentry object
545  * @parent:     pointer to the parent dentry object
546  * @curr:       current directory name
547  * @par_dir:    parent directory name
548  */
549 void glink_dfs_update_list(struct dentry *curr_dent, struct dentry *parent,
550                         const char *curr, const char *par_dir)
551 {
552         struct glink_dbgfs_dent *dbgfs_dent_s;
553         if (curr_dent != NULL) {
554                 dbgfs_dent_s = kzalloc(sizeof(struct glink_dbgfs_dent),
555                                 GFP_KERNEL);
556                 if (dbgfs_dent_s != NULL) {
557                         INIT_LIST_HEAD(&dbgfs_dent_s->file_list);
558                         spin_lock_init(&dbgfs_dent_s->file_list_lock_lhb0);
559                         dbgfs_dent_s->parent = parent;
560                         dbgfs_dent_s->self = curr_dent;
561                         strscpy(dbgfs_dent_s->self_name, curr,
562                                 sizeof(dbgfs_dent_s->self_name));
563                         strscpy(dbgfs_dent_s->par_name, par_dir,
564                                 sizeof(dbgfs_dent_s->par_name));
565                         mutex_lock(&dent_list_lock_lha0);
566                         list_add_tail(&dbgfs_dent_s->list_node, &dent_list);
567                         mutex_unlock(&dent_list_lock_lha0);
568                 }
569         } else {
570                 GLINK_DBG("%s:create directory failed for par:curr [%s:%s]\n",
571                                 __func__, par_dir, curr);
572         }
573         return;
574 }
575
576 /**
577  * glink_remove_dfs_entry() - remove the the entries from dent_list
578  * @entry:      pointer to the glink_dbgfs_dent structure
579  *
580  * This function removes the removes the entries from internally maintained
581  * linked list of dentries. It also deletes the file list and associated memory
582  * if present.
583  */
584 void glink_remove_dfs_entry(struct glink_dbgfs_dent *entry)
585 {
586         struct glink_dbgfs_data *fentry, *fentry_temp;
587         unsigned long flags;
588
589         if (entry == NULL)
590                 return;
591         if (!list_empty(&entry->file_list)) {
592                 spin_lock_irqsave(&entry->file_list_lock_lhb0, flags);
593                 list_for_each_entry_safe(fentry, fentry_temp,
594                                 &entry->file_list, flist) {
595                         if (fentry->b_priv_free_req)
596                                 kfree(fentry->priv_data);
597                         list_del(&fentry->flist);
598                         kfree(fentry);
599                         fentry = NULL;
600                 }
601                 spin_unlock_irqrestore(&entry->file_list_lock_lhb0, flags);
602         }
603         list_del(&entry->list_node);
604         kfree(entry);
605         entry = NULL;
606 }
607
608 /**
609  * glink_debugfs_remove_recur() - remove the the directory & files recursively
610  * @rm_dfs:     pointer to the structure glink_dbgfs
611  *
612  * This function removes the files & directories below the given directory.
613  * This also takes care of freeing any memory associated with the debugfs file.
614  */
615 void glink_debugfs_remove_recur(struct glink_dbgfs *rm_dfs)
616 {
617         const char *c_dir_name;
618         const char *p_dir_name;
619         struct glink_dbgfs_dent *entry, *entry_temp;
620         struct dentry *par_dent = NULL;
621
622         if (rm_dfs == NULL)
623                 return;
624
625         c_dir_name = rm_dfs->curr_name;
626         p_dir_name = rm_dfs->par_name;
627
628         mutex_lock(&dent_list_lock_lha0);
629         list_for_each_entry_safe(entry, entry_temp, &dent_list, list_node) {
630                 if (!strcmp(entry->par_name, c_dir_name)) {
631                         glink_remove_dfs_entry(entry);
632                 } else if (!strcmp(entry->self_name, c_dir_name)
633                                 && !strcmp(entry->par_name, p_dir_name)) {
634                         par_dent = entry->self;
635                         glink_remove_dfs_entry(entry);
636                 }
637         }
638         mutex_unlock(&dent_list_lock_lha0);
639         if (par_dent != NULL)
640                 debugfs_remove_recursive(par_dent);
641 }
642 EXPORT_SYMBOL(glink_debugfs_remove_recur);
643
644 /**
645  * glink_debugfs_create() - create the debugfs file
646  * @name:       debugfs file name
647  * @show:       pointer to the actual function which will be invoked upon
648  *              opening this file.
649  * @dir:        pointer to a structure debugfs_dir
650  * dbgfs_data:  pointer to any private data need to be associated with debugfs
651  * b_free_req:  boolean value to decide to free the memory associated with
652  *              @dbgfs_data during deletion of the file
653  *
654  * Return:      pointer to the file/directory created, NULL in case of error
655  *
656  * This function checks which directory will be used to create the debugfs file
657  * and calls glink_dfs_create_file. Anybody who intend to allocate some memory
658  * for the dbgfs_data and required to free it in deletion, need to set
659  * b_free_req to true. Otherwise, there will be a memory leak.
660  */
661 struct dentry *glink_debugfs_create(const char *name,
662                 void (*show)(struct seq_file *),
663                 struct glink_dbgfs *dir, void *dbgfs_data, bool b_free_req)
664 {
665         struct dentry *parent =  NULL;
666         struct dentry *dent = NULL;
667         struct glink_dbgfs_dent *entry;
668         struct glink_dbgfs_data *file_data;
669         const char *c_dir_name;
670         const char *p_dir_name;
671         unsigned long flags;
672
673         if (dir == NULL) {
674                 GLINK_ERR("%s: debugfs_dir strucutre is null\n", __func__);
675                 return NULL;
676         }
677         c_dir_name = dir->curr_name;
678         p_dir_name = dir->par_name;
679
680         mutex_lock(&dent_list_lock_lha0);
681         list_for_each_entry(entry, &dent_list, list_node)
682                 if (!strcmp(entry->par_name, p_dir_name)
683                                 && !strcmp(entry->self_name, c_dir_name)) {
684                         parent = entry->self;
685                         break;
686                 }
687         mutex_unlock(&dent_list_lock_lha0);
688         p_dir_name = c_dir_name;
689         c_dir_name = name;
690         if (parent != NULL) {
691                 if (dir->b_dir_create) {
692                         dent = debugfs_create_dir(name, parent);
693                         if (dent != NULL)
694                                 glink_dfs_update_list(dent, parent,
695                                                         c_dir_name, p_dir_name);
696                 } else {
697                         file_data = glink_dfs_create_file(name, parent, show,
698                                                         dbgfs_data, b_free_req);
699                         spin_lock_irqsave(&entry->file_list_lock_lhb0, flags);
700                         if (file_data != NULL)
701                                 list_add_tail(&file_data->flist,
702                                                 &entry->file_list);
703                         spin_unlock_irqrestore(&entry->file_list_lock_lhb0,
704                                                 flags);
705                 }
706         } else {
707                 GLINK_DBG("%s: parent dentry is null for [%s]\n",
708                                 __func__, name);
709         }
710         return dent;
711 }
712 EXPORT_SYMBOL(glink_debugfs_create);
713
714 /**
715  * glink_debugfs_init() - initialize the glink debugfs directory structure
716  *
717  * Return:      0 in success otherwise appropriate error code
718  *
719  * This function initializes the debugfs directory for glink
720  */
721 int glink_debugfs_init(void)
722 {
723         struct glink_dbgfs dbgfs;
724
725         /* fake parent name */
726         dent = debugfs_create_dir("glink", NULL);
727         if (IS_ERR_OR_NULL(dent))
728                 return PTR_ERR(dent);
729
730         glink_dfs_update_list(dent, NULL, "glink", "root");
731
732         dbgfs.b_dir_create = true;
733         dbgfs.curr_name = "glink";
734         dbgfs.par_name = "root";
735         glink_debugfs_create("xprt", NULL, &dbgfs, NULL, false);
736         glink_debugfs_create("channel", NULL, &dbgfs, NULL, false);
737
738         dbgfs.curr_name = "channel";
739         dbgfs.par_name = "glink";
740         dbgfs.b_dir_create = false;
741         glink_debugfs_create("channels", glink_dfs_create_channel_list,
742                                 &dbgfs, NULL, false);
743         dbgfs.curr_name = "xprt";
744         glink_debugfs_create("xprts", glink_dfs_create_xprt_list,
745                                 &dbgfs, NULL, false);
746
747         return 0;
748 }
749 EXPORT_SYMBOL(glink_debugfs_init);
750
751 /**
752  * glink_debugfs_exit() - removes the glink debugfs directory
753  *
754  * This function recursively remove all the debugfs directories
755  * starting from dent
756  */
757 void glink_debugfs_exit(void)
758 {
759         if (dent != NULL)
760                 debugfs_remove_recursive(dent);
761 }
762 EXPORT_SYMBOL(glink_debugfs_exit);
763 #else
764 void glink_debugfs_remove_recur(struct glink_dbgfs *dfs) { }
765 EXPORT_SYMBOL(glink_debugfs_remove_recur);
766
767 void glink_debugfs_remove_channel(struct channel_ctx *ch_ctx,
768                         struct glink_core_xprt_ctx *xprt_ctx) { }
769 EXPORT_SYMBOL(glink_debugfs_remove_channel);
770
771 void glink_debugfs_add_channel(struct channel_ctx *ch_ctx,
772                 struct glink_core_xprt_ctx *xprt_ctx) { }
773 EXPORT_SYMBOL(glink_debugfs_add_channel);
774
775 void glink_debugfs_add_xprt(struct glink_core_xprt_ctx *xprt_ctx) { }
776 EXPORT_SYMBOL(glink_debugfs_add_xprt);
777
778 int glink_debugfs_init(void) { return 0; }
779 EXPORT_SYMBOL(glink_debugfs_init);
780
781 void glink_debugfs_exit(void) { }
782 EXPORT_SYMBOL(glink_debugfs_exit);
783 #endif /* CONFIG_DEBUG_FS */