xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/ath_procfs.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT)
21 #include <linux/module.h>       /* Specifically, a module */
22 #include <linux/kernel.h>       /* We're doing kernel work */
23 #include <linux/version.h>      /* We're doing kernel work */
24 #include <linux/proc_fs.h>      /* Necessary because we use the proc fs */
25 #include <linux/uaccess.h>        /* for copy_from_user */
26 #include "hif.h"
27 #include "hif_main.h"
28 #if defined(HIF_USB)
29 #include "if_usb.h"
30 #endif
31 #if defined(HIF_SDIO)
32 #include "if_sdio.h"
33 #endif
34 #include "hif_debug.h"
35 #include "pld_common.h"
36 #include "target_type.h"
37 
38 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
39 /*
40  * Commit 359745d78351 ("proc: remove PDE_DATA() completely")
41  * Replaced PDE_DATA() with pde_data()
42  */
43 #define pde_data(inode) PDE_DATA(inode)
44 #endif
45 
46 #define PROCFS_NAME             "athdiagpfs"
47 #ifdef MULTI_IF_NAME
48 #define PROCFS_DIR              "cld" MULTI_IF_NAME
49 #else
50 #define PROCFS_DIR              "cld"
51 #endif
52 
53 /**
54  * Get op_type, mem_type and offset fields from pos of procfs
55  * It will reuse pos, which is long long type
56  *
57  * op_type:     4 bits
58  * memtype:     8 bits
59  * reserve1:    20 bits
60  * offset:      32 bits
61  */
62 #define OP_TYPE_LEGACY                  0
63 #define OP_TYPE_EXT_QMI                 1
64 #define OP_TYPE_EXT_DIRECT              2
65 
66 #define ATH_DIAG_EXT_OP_TYPE_BITS        4
67 #define ATH_DIAG_EXT_OP_TYPE_INDEX       60
68 #define ATH_DIAG_EXT_MEM_TYPE_BITS       8
69 #define ATH_DIAG_EXT_MEM_TYPE_INDEX      52
70 #define ATH_DIAG_EXT_OFFSET_BITS         32
71 #define ATH_DIAG_EXT_OFFSET_INDEX        0
72 
73 /**
74  * This structure hold information about the /proc file
75  *
76  */
77 static struct proc_dir_entry *proc_file, *proc_dir;
78 
79 static void *get_hif_hdl_from_file(struct file *file)
80 {
81 	struct hif_opaque_softc *scn;
82 
83 	scn = (struct hif_opaque_softc *)pde_data(file_inode(file));
84 	return (void *)scn;
85 }
86 
87 static ssize_t ath_procfs_diag_read_legacy(struct file *file,
88 					   char __user *buf,
89 					   size_t count, loff_t *pos)
90 {
91 	hif_handle_t hif_hdl;
92 	int rv;
93 	uint8_t *read_buffer = NULL;
94 	struct hif_softc *scn;
95 	uint32_t offset = 0, memtype = 0;
96 	struct hif_target_info *tgt_info;
97 
98 	hif_hdl = get_hif_hdl_from_file(file);
99 	scn = HIF_GET_SOFTC(hif_hdl);
100 
101 	read_buffer = qdf_mem_malloc(count);
102 	if (!read_buffer)
103 		return -ENOMEM;
104 
105 	hif_debug("rd buff 0x%pK cnt %zu offset 0x%x buf 0x%pK",
106 		 read_buffer, count, (int)*pos, buf);
107 
108 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
109 	if ((scn->bus_type == QDF_BUS_TYPE_SNOC) ||
110 	    (scn->bus_type ==  QDF_BUS_TYPE_PCI &&
111 	    ((tgt_info->target_type == TARGET_TYPE_QCA6290) ||
112 	     (tgt_info->target_type == TARGET_TYPE_QCA6390) ||
113 	     (tgt_info->target_type == TARGET_TYPE_QCA6490) ||
114 	     (tgt_info->target_type == TARGET_TYPE_QCA8074) ||
115 	     (tgt_info->target_type == TARGET_TYPE_QCA8074V2) ||
116 	     (tgt_info->target_type == TARGET_TYPE_QCA9574) ||
117 	     (tgt_info->target_type == TARGET_TYPE_QCN9000) ||
118 	     (tgt_info->target_type == TARGET_TYPE_QCN9224) ||
119 	     (tgt_info->target_type == TARGET_TYPE_QCN6122) ||
120 	     (tgt_info->target_type == TARGET_TYPE_QCN9160) ||
121 	     (tgt_info->target_type == TARGET_TYPE_QCA5018) ||
122 	     (tgt_info->target_type == TARGET_TYPE_QCA5332) ||
123 	     (tgt_info->target_type == TARGET_TYPE_QCA6018) ||
124 	     (tgt_info->target_type == TARGET_TYPE_QCN7605) ||
125 	     (tgt_info->target_type == TARGET_TYPE_KIWI) ||
126 	     (tgt_info->target_type == TARGET_TYPE_MANGO))) ||
127 	    (scn->bus_type ==  QDF_BUS_TYPE_IPCI &&
128 	     (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
129 	    ((scn->bus_type ==  QDF_BUS_TYPE_USB) &&
130 	     (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
131 		memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
132 		offset = (uint32_t)(*pos) & 0xffffff;
133 		hif_debug("offset 0x%x memtype 0x%x, datalen %zu",
134 			 offset, memtype, count);
135 		rv = pld_athdiag_read(scn->qdf_dev->dev,
136 				      offset, memtype, count,
137 				      (uint8_t *)read_buffer);
138 		goto out;
139 	}
140 
141 	if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
142 		/* reading a word? */
143 		rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
144 					  (uint32_t *)read_buffer);
145 	} else {
146 		rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
147 				       (uint8_t *)read_buffer, count);
148 	}
149 
150 out:
151 	if (rv) {
152 		qdf_mem_free(read_buffer);
153 		return -EIO;
154 	}
155 
156 	if (copy_to_user(buf, read_buffer, count)) {
157 		qdf_mem_free(read_buffer);
158 		hif_err("copy_to_user error in /proc/%s", PROCFS_NAME);
159 		return -EFAULT;
160 	}
161 	qdf_mem_free(read_buffer);
162 	return count;
163 }
164 
165 static ssize_t ath_procfs_diag_write_legacy(struct file *file,
166 					    const char __user *buf,
167 					    size_t count, loff_t *pos)
168 {
169 	hif_handle_t hif_hdl;
170 	int rv;
171 	uint8_t *write_buffer = NULL;
172 	struct hif_softc *scn;
173 	uint32_t offset = 0, memtype = 0;
174 	struct hif_target_info *tgt_info;
175 
176 	hif_hdl = get_hif_hdl_from_file(file);
177 	scn = HIF_GET_SOFTC(hif_hdl);
178 
179 	write_buffer = qdf_mem_malloc(count);
180 	if (!write_buffer)
181 		return -ENOMEM;
182 
183 	if (copy_from_user(write_buffer, buf, count)) {
184 		qdf_mem_free(write_buffer);
185 		hif_err("copy_to_user error in /proc/%s", PROCFS_NAME);
186 		return -EFAULT;
187 	}
188 
189 	hif_debug("wr buff 0x%pK buf 0x%pK cnt %zu offset 0x%x value 0x%x",
190 		 write_buffer, buf, count,
191 		 (int)*pos, *((uint32_t *) write_buffer));
192 
193 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
194 	if ((scn->bus_type == QDF_BUS_TYPE_SNOC) ||
195 	    ((scn->bus_type ==  QDF_BUS_TYPE_PCI) &&
196 	     ((tgt_info->target_type == TARGET_TYPE_QCA6290) ||
197 	      (tgt_info->target_type == TARGET_TYPE_QCA6390) ||
198 	      (tgt_info->target_type == TARGET_TYPE_QCA6490) ||
199 	      (tgt_info->target_type == TARGET_TYPE_QCA8074) ||
200 	      (tgt_info->target_type == TARGET_TYPE_QCA8074V2) ||
201 	      (tgt_info->target_type == TARGET_TYPE_QCA9574) ||
202 	      (tgt_info->target_type == TARGET_TYPE_QCN9000) ||
203 	      (tgt_info->target_type == TARGET_TYPE_QCN9224) ||
204 	      (tgt_info->target_type == TARGET_TYPE_QCN6122) ||
205 	      (tgt_info->target_type == TARGET_TYPE_QCN9160) ||
206 	      (tgt_info->target_type == TARGET_TYPE_QCA5018) ||
207 	      (tgt_info->target_type == TARGET_TYPE_QCA5332) ||
208 	      (tgt_info->target_type == TARGET_TYPE_QCA6018) ||
209 	      (tgt_info->target_type == TARGET_TYPE_QCN7605) ||
210 	      (tgt_info->target_type == TARGET_TYPE_KIWI) ||
211 	      (tgt_info->target_type == TARGET_TYPE_MANGO))) ||
212 	    (scn->bus_type ==  QDF_BUS_TYPE_IPCI &&
213 	     (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
214 	    ((scn->bus_type ==  QDF_BUS_TYPE_USB) &&
215 	     (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
216 		memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
217 		offset = (uint32_t)(*pos) & 0xffffff;
218 		hif_debug("offset 0x%x memtype 0x%x, datalen %zu",
219 			 offset, memtype, count);
220 		rv = pld_athdiag_write(scn->qdf_dev->dev,
221 				      offset, memtype, count,
222 				      (uint8_t *)write_buffer);
223 		goto out;
224 	}
225 
226 	if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
227 		/* reading a word? */
228 		uint32_t value = *((uint32_t *)write_buffer);
229 
230 		rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
231 	} else {
232 		rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
233 					(uint8_t *)write_buffer, count);
234 	}
235 
236 out:
237 
238 	qdf_mem_free(write_buffer);
239 	if (rv == 0)
240 		return count;
241 	else
242 		return -EIO;
243 }
244 
245 #ifdef ATH_DIAG_EXT_DIRECT
246 /* Used to dump register or SRAM from target directly */
247 static int ath_procfs_direct_read(struct hif_softc *scn, uint32_t offset,
248 				  uint8_t *buf, size_t count)
249 {
250 	size_t remaining = count;
251 	uint32_t *p_val = (uint32_t *)buf;
252 	uint32_t val;
253 	uint8_t *buf_d, *buf_s;
254 
255 	if (!scn->bus_ops.hif_reg_read32)
256 		return -EIO;
257 
258 	while (remaining >= 4) {
259 		*p_val++ = scn->bus_ops.hif_reg_read32(scn,
260 						       offset);
261 		offset += 4;
262 		remaining -= 4;
263 	}
264 
265 	if (remaining) {
266 		val = scn->bus_ops.hif_reg_read32(scn,
267 						  offset);
268 		buf_d = (uint8_t *)p_val;
269 		buf_s = (uint8_t *)&val;
270 		while (remaining) {
271 			*buf_d++ = *buf_s++;
272 			remaining--;
273 		}
274 	}
275 
276 	return 0;
277 }
278 
279 /* Used to write register or SRAM to target directly */
280 static int ath_procfs_direct_write(struct hif_softc *scn, uint32_t offset,
281 				   uint8_t *buf, size_t count)
282 {
283 	size_t remaining = count;
284 	uint32_t *p_val = (uint32_t *)buf;
285 	uint32_t val;
286 	uint8_t *buf_d, *buf_s;
287 
288 	if (!scn->bus_ops.hif_reg_write32 || !scn->bus_ops.hif_reg_read32)
289 		return -EIO;
290 
291 	while (remaining >= 4) {
292 		scn->bus_ops.hif_reg_write32(scn,
293 					     offset,
294 					     *p_val++);
295 		offset += 4;
296 		remaining -= 4;
297 	}
298 
299 	if (remaining) {
300 		val = scn->bus_ops.hif_reg_read32(scn,
301 						  offset);
302 		buf_s = (uint8_t *)p_val;
303 		buf_d = (uint8_t *)&val;
304 		while (remaining) {
305 			*buf_d++ = *buf_s++;
306 			remaining--;
307 		}
308 		scn->bus_ops.hif_reg_write32(scn,
309 					     offset,
310 					     val);
311 	}
312 
313 	return 0;
314 }
315 #else
316 static int ath_procfs_direct_read(struct hif_softc *scn, uint32_t offset,
317 				  uint8_t *buf, size_t count)
318 {
319 	return -EIO;
320 }
321 
322 /* Used to write register or SRAM to target directly */
323 static int ath_procfs_direct_write(struct hif_softc *scn, uint32_t offset,
324 				   uint8_t *buf, size_t count)
325 {
326 	return -EIO;
327 }
328 
329 #endif
330 
331 static ssize_t ath_procfs_diag_read_ext(struct file *file, char __user *buf,
332 					size_t count,
333 					uint32_t op_type,
334 					uint32_t memtype,
335 					uint32_t offset)
336 {
337 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
338 	int rv = -EINVAL;
339 	uint8_t *read_buffer;
340 	struct hif_softc *scn;
341 	struct hif_target_info *tgt_info;
342 
343 	if (!hif_hdl)
344 		return -EINVAL;
345 
346 	read_buffer = qdf_mem_malloc(count);
347 	if (!read_buffer)
348 		return -ENOMEM;
349 
350 	scn = HIF_GET_SOFTC(hif_hdl);
351 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
352 	switch (scn->bus_type) {
353 	case QDF_BUS_TYPE_PCI:
354 		switch (tgt_info->target_type) {
355 		case TARGET_TYPE_QCA6390:
356 		case TARGET_TYPE_QCA6490:
357 		case TARGET_TYPE_KIWI:
358 		case TARGET_TYPE_MANGO:
359 			if (op_type == OP_TYPE_EXT_DIRECT)
360 				rv = ath_procfs_direct_read(scn,
361 							    offset,
362 							    read_buffer,
363 							    count);
364 			else
365 				rv = pld_athdiag_read(scn->qdf_dev->dev,
366 						      offset,
367 						      memtype,
368 						      count,
369 						      read_buffer);
370 			break;
371 		default:
372 			hif_err("Unrecognized target type %d",
373 				tgt_info->target_type);
374 		}
375 		break;
376 	default:
377 		hif_err("Unrecognized bus type %d", scn->bus_type);
378 		break;
379 	}
380 
381 	if (rv) {
382 		hif_err("fail to read from target %d", rv);
383 	} else {
384 		rv = count;
385 		if (copy_to_user(buf, read_buffer, count)) {
386 			hif_err("copy_to_user error in /proc/%s",
387 				PROCFS_NAME);
388 			rv = -EFAULT;
389 		}
390 	}
391 
392 	qdf_mem_free(read_buffer);
393 
394 	return rv;
395 }
396 
397 static ssize_t ath_procfs_diag_write_ext(struct file *file,
398 					 const char __user *buf,
399 					 size_t count,
400 					 uint32_t op_type,
401 					 uint32_t memtype,
402 					 uint32_t offset)
403 {
404 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
405 	int rv = -EINVAL;
406 	uint8_t *write_buffer;
407 	struct hif_softc *scn;
408 	struct hif_target_info *tgt_info;
409 
410 	if (!hif_hdl)
411 		return -EINVAL;
412 
413 	scn = HIF_GET_SOFTC(hif_hdl);
414 
415 	write_buffer = qdf_mem_malloc(count);
416 	if (!write_buffer)
417 		return -ENOMEM;
418 
419 	if (copy_from_user(write_buffer, buf, count)) {
420 		qdf_mem_free(write_buffer);
421 		hif_err("copy_to_user error in /proc/%s",
422 			PROCFS_NAME);
423 		return -EFAULT;
424 	}
425 
426 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
427 
428 	switch (scn->bus_type) {
429 	case QDF_BUS_TYPE_PCI:
430 		switch (tgt_info->target_type) {
431 		case TARGET_TYPE_QCA6390:
432 		case TARGET_TYPE_QCA6490:
433 		case TARGET_TYPE_KIWI:
434 		case TARGET_TYPE_MANGO:
435 			if (op_type == OP_TYPE_EXT_DIRECT)
436 				rv = ath_procfs_direct_write(scn,
437 							     offset,
438 							     write_buffer,
439 							     count);
440 			else
441 				rv = pld_athdiag_write(scn->qdf_dev->dev,
442 						       offset,
443 						       memtype,
444 						       count,
445 						       write_buffer);
446 			break;
447 		default:
448 			hif_err("Unrecognized target type %d",
449 				tgt_info->target_type);
450 		}
451 		break;
452 	default:
453 		hif_err("Unrecognized bus type %d", scn->bus_type);
454 		break;
455 	}
456 
457 	qdf_mem_free(write_buffer);
458 
459 	return (rv == 0) ? count : -EIO;
460 }
461 
462 static void get_fields_from_pos(loff_t pos,
463 				uint32_t *op_type,
464 				uint32_t *memtype,
465 				uint32_t *offset)
466 {
467 	*op_type = QDF_GET_BITS64(pos, ATH_DIAG_EXT_OP_TYPE_INDEX,
468 				  ATH_DIAG_EXT_OP_TYPE_BITS);
469 	*memtype = QDF_GET_BITS64(pos, ATH_DIAG_EXT_MEM_TYPE_INDEX,
470 				  ATH_DIAG_EXT_MEM_TYPE_BITS);
471 	*offset = QDF_GET_BITS64(pos, ATH_DIAG_EXT_OFFSET_INDEX,
472 				 ATH_DIAG_EXT_OFFSET_BITS);
473 }
474 
475 static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
476 				    size_t count, loff_t *pos)
477 {
478 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
479 	int rv = -EINVAL;
480 	struct hif_softc *scn;
481 	uint32_t offset, memtype;
482 	uint32_t op_type;
483 
484 	if (!hif_hdl)
485 		return -EINVAL;
486 
487 	get_fields_from_pos(*pos, &op_type, &memtype, &offset);
488 
489 	scn = HIF_GET_SOFTC(hif_hdl);
490 	if (scn->bus_ops.hif_addr_in_boundary(scn, offset))
491 		return -EINVAL;
492 
493 	if (offset & 0x3)
494 		return -EINVAL;
495 
496 	hif_info("rd cnt %zu offset 0x%x op_type %d type %d pos %llx",
497 		 count, offset, op_type, memtype, *pos);
498 
499 	switch (op_type) {
500 	case OP_TYPE_LEGACY:
501 		rv = ath_procfs_diag_read_legacy(file, buf, count, pos);
502 		break;
503 	case OP_TYPE_EXT_QMI:
504 	case OP_TYPE_EXT_DIRECT:
505 		rv = ath_procfs_diag_read_ext(file, buf, count, op_type,
506 					      memtype, offset);
507 		break;
508 	default:
509 		hif_err("Unrecognized op type %d", op_type);
510 		break;
511 	}
512 
513 	return rv;
514 }
515 
516 static ssize_t ath_procfs_diag_write(struct file *file,
517 				     const char __user *buf,
518 				     size_t count, loff_t *pos)
519 {
520 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
521 	int rv = -EINVAL;
522 	struct hif_softc *scn;
523 	uint32_t offset, memtype;
524 	uint32_t op_type;
525 
526 	if (!hif_hdl)
527 		return -EINVAL;
528 
529 	get_fields_from_pos(*pos, &op_type, &memtype, &offset);
530 
531 	scn = HIF_GET_SOFTC(hif_hdl);
532 	if (scn->bus_ops.hif_addr_in_boundary(scn, offset))
533 		return -EINVAL;
534 
535 	if (offset & 0x3)
536 		return -EINVAL;
537 
538 	hif_info("wr cnt %zu offset 0x%x op_type %d mem_type %d",
539 		 count, offset, op_type, memtype);
540 
541 	switch (op_type) {
542 	case OP_TYPE_LEGACY:
543 		rv = ath_procfs_diag_write_legacy(file, buf, count, pos);
544 		break;
545 	case OP_TYPE_EXT_QMI:
546 	case OP_TYPE_EXT_DIRECT:
547 		rv = ath_procfs_diag_write_ext(file, buf, count, op_type,
548 					       memtype, offset);
549 		break;
550 	default:
551 		hif_err("Unrecognized op type %d", op_type);
552 		break;
553 	}
554 
555 	return rv;
556 }
557 
558 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
559 static const struct proc_ops athdiag_fops = {
560 	.proc_read = ath_procfs_diag_read,
561 	.proc_write = ath_procfs_diag_write,
562 	.proc_lseek = default_llseek,
563 };
564 #else
565 static const struct file_operations athdiag_fops = {
566 	.read = ath_procfs_diag_read,
567 	.write = ath_procfs_diag_write,
568 };
569 #endif
570 
571 /*
572  * This function is called when the module is loaded
573  *
574  */
575 int athdiag_procfs_init(void *scn)
576 {
577 	proc_dir = proc_mkdir(PROCFS_DIR, NULL);
578 	if (!proc_dir) {
579 		remove_proc_entry(PROCFS_DIR, NULL);
580 		hif_err("Could not initialize /proc/%s", PROCFS_DIR);
581 		return -ENOMEM;
582 	}
583 
584 	proc_file = proc_create_data(PROCFS_NAME, 0600, proc_dir,
585 				     &athdiag_fops, (void *)scn);
586 	if (!proc_file) {
587 		remove_proc_entry(PROCFS_NAME, proc_dir);
588 		hif_err("Could not initialize /proc/%s", PROCFS_NAME);
589 		return -ENOMEM;
590 	}
591 
592 	hif_debug("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
593 	return 0;
594 }
595 
596 /*
597  * This function is called when the module is unloaded
598  *
599  */
600 void athdiag_procfs_remove(void)
601 {
602 	if (proc_dir) {
603 		remove_proc_entry(PROCFS_NAME, proc_dir);
604 		hif_debug("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
605 		remove_proc_entry(PROCFS_DIR, NULL);
606 		hif_debug("/proc/%s removed", PROCFS_DIR);
607 		proc_dir = NULL;
608 	}
609 }
610 #else
611 int athdiag_procfs_init(void *scn)
612 {
613 	return 0;
614 }
615 void athdiag_procfs_remove(void) {}
616 #endif
617