xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/ath_procfs.c (revision 8b3dca18206e1a0461492f082fa6e270b092c035)
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_QCA5018) ||
121 	     (tgt_info->target_type == TARGET_TYPE_QCA5332) ||
122 	     (tgt_info->target_type == TARGET_TYPE_QCA6018) ||
123 	     (tgt_info->target_type == TARGET_TYPE_QCN7605) ||
124 	     (tgt_info->target_type == TARGET_TYPE_KIWI) ||
125 	     (tgt_info->target_type == TARGET_TYPE_MANGO))) ||
126 	    (scn->bus_type ==  QDF_BUS_TYPE_IPCI &&
127 	     (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
128 	    ((scn->bus_type ==  QDF_BUS_TYPE_USB) &&
129 	     (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
130 		memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
131 		offset = (uint32_t)(*pos) & 0xffffff;
132 		hif_debug("offset 0x%x memtype 0x%x, datalen %zu",
133 			 offset, memtype, count);
134 		rv = pld_athdiag_read(scn->qdf_dev->dev,
135 				      offset, memtype, count,
136 				      (uint8_t *)read_buffer);
137 		goto out;
138 	}
139 
140 	if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
141 		/* reading a word? */
142 		rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
143 					  (uint32_t *)read_buffer);
144 	} else {
145 		rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
146 				       (uint8_t *)read_buffer, count);
147 	}
148 
149 out:
150 	if (rv) {
151 		qdf_mem_free(read_buffer);
152 		return -EIO;
153 	}
154 
155 	if (copy_to_user(buf, read_buffer, count)) {
156 		qdf_mem_free(read_buffer);
157 		hif_err("copy_to_user error in /proc/%s", PROCFS_NAME);
158 		return -EFAULT;
159 	}
160 	qdf_mem_free(read_buffer);
161 	return count;
162 }
163 
164 static ssize_t ath_procfs_diag_write_legacy(struct file *file,
165 					    const char __user *buf,
166 					    size_t count, loff_t *pos)
167 {
168 	hif_handle_t hif_hdl;
169 	int rv;
170 	uint8_t *write_buffer = NULL;
171 	struct hif_softc *scn;
172 	uint32_t offset = 0, memtype = 0;
173 	struct hif_target_info *tgt_info;
174 
175 	hif_hdl = get_hif_hdl_from_file(file);
176 	scn = HIF_GET_SOFTC(hif_hdl);
177 
178 	write_buffer = qdf_mem_malloc(count);
179 	if (!write_buffer)
180 		return -ENOMEM;
181 
182 	if (copy_from_user(write_buffer, buf, count)) {
183 		qdf_mem_free(write_buffer);
184 		hif_err("copy_to_user error in /proc/%s", PROCFS_NAME);
185 		return -EFAULT;
186 	}
187 
188 	hif_debug("wr buff 0x%pK buf 0x%pK cnt %zu offset 0x%x value 0x%x",
189 		 write_buffer, buf, count,
190 		 (int)*pos, *((uint32_t *) write_buffer));
191 
192 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
193 	if ((scn->bus_type == QDF_BUS_TYPE_SNOC) ||
194 	    ((scn->bus_type ==  QDF_BUS_TYPE_PCI) &&
195 	     ((tgt_info->target_type == TARGET_TYPE_QCA6290) ||
196 	      (tgt_info->target_type == TARGET_TYPE_QCA6390) ||
197 	      (tgt_info->target_type == TARGET_TYPE_QCA6490) ||
198 	      (tgt_info->target_type == TARGET_TYPE_QCA8074) ||
199 	      (tgt_info->target_type == TARGET_TYPE_QCA8074V2) ||
200 	      (tgt_info->target_type == TARGET_TYPE_QCA9574) ||
201 	      (tgt_info->target_type == TARGET_TYPE_QCN9000) ||
202 	      (tgt_info->target_type == TARGET_TYPE_QCN9224) ||
203 	      (tgt_info->target_type == TARGET_TYPE_QCN6122) ||
204 	      (tgt_info->target_type == TARGET_TYPE_QCA5018) ||
205 	      (tgt_info->target_type == TARGET_TYPE_QCA5332) ||
206 	      (tgt_info->target_type == TARGET_TYPE_QCA6018) ||
207 	      (tgt_info->target_type == TARGET_TYPE_QCN7605) ||
208 	      (tgt_info->target_type == TARGET_TYPE_KIWI) ||
209 	      (tgt_info->target_type == TARGET_TYPE_MANGO))) ||
210 	    (scn->bus_type ==  QDF_BUS_TYPE_IPCI &&
211 	     (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
212 	    ((scn->bus_type ==  QDF_BUS_TYPE_USB) &&
213 	     (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
214 		memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
215 		offset = (uint32_t)(*pos) & 0xffffff;
216 		hif_debug("offset 0x%x memtype 0x%x, datalen %zu",
217 			 offset, memtype, count);
218 		rv = pld_athdiag_write(scn->qdf_dev->dev,
219 				      offset, memtype, count,
220 				      (uint8_t *)write_buffer);
221 		goto out;
222 	}
223 
224 	if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
225 		/* reading a word? */
226 		uint32_t value = *((uint32_t *)write_buffer);
227 
228 		rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
229 	} else {
230 		rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
231 					(uint8_t *)write_buffer, count);
232 	}
233 
234 out:
235 
236 	qdf_mem_free(write_buffer);
237 	if (rv == 0)
238 		return count;
239 	else
240 		return -EIO;
241 }
242 
243 #ifdef ATH_DIAG_EXT_DIRECT
244 /* Used to dump register or SRAM from target directly */
245 static int ath_procfs_direct_read(struct hif_softc *scn, uint32_t offset,
246 				  uint8_t *buf, size_t count)
247 {
248 	size_t remaining = count;
249 	uint32_t *p_val = (uint32_t *)buf;
250 	uint32_t val;
251 	uint8_t *buf_d, *buf_s;
252 
253 	if (!scn->bus_ops.hif_reg_read32)
254 		return -EIO;
255 
256 	while (remaining >= 4) {
257 		*p_val++ = scn->bus_ops.hif_reg_read32(scn,
258 						       offset);
259 		offset += 4;
260 		remaining -= 4;
261 	}
262 
263 	if (remaining) {
264 		val = scn->bus_ops.hif_reg_read32(scn,
265 						  offset);
266 		buf_d = (uint8_t *)p_val;
267 		buf_s = (uint8_t *)&val;
268 		while (remaining) {
269 			*buf_d++ = *buf_s++;
270 			remaining--;
271 		}
272 	}
273 
274 	return 0;
275 }
276 
277 /* Used to write register or SRAM to target directly */
278 static int ath_procfs_direct_write(struct hif_softc *scn, uint32_t offset,
279 				   uint8_t *buf, size_t count)
280 {
281 	size_t remaining = count;
282 	uint32_t *p_val = (uint32_t *)buf;
283 	uint32_t val;
284 	uint8_t *buf_d, *buf_s;
285 
286 	if (!scn->bus_ops.hif_reg_write32 || !scn->bus_ops.hif_reg_read32)
287 		return -EIO;
288 
289 	while (remaining >= 4) {
290 		scn->bus_ops.hif_reg_write32(scn,
291 					     offset,
292 					     *p_val++);
293 		offset += 4;
294 		remaining -= 4;
295 	}
296 
297 	if (remaining) {
298 		val = scn->bus_ops.hif_reg_read32(scn,
299 						  offset);
300 		buf_s = (uint8_t *)p_val;
301 		buf_d = (uint8_t *)&val;
302 		while (remaining) {
303 			*buf_d++ = *buf_s++;
304 			remaining--;
305 		}
306 		scn->bus_ops.hif_reg_write32(scn,
307 					     offset,
308 					     val);
309 	}
310 
311 	return 0;
312 }
313 #else
314 static int ath_procfs_direct_read(struct hif_softc *scn, uint32_t offset,
315 				  uint8_t *buf, size_t count)
316 {
317 	return -EIO;
318 }
319 
320 /* Used to write register or SRAM to target directly */
321 static int ath_procfs_direct_write(struct hif_softc *scn, uint32_t offset,
322 				   uint8_t *buf, size_t count)
323 {
324 	return -EIO;
325 }
326 
327 #endif
328 
329 static ssize_t ath_procfs_diag_read_ext(struct file *file, char __user *buf,
330 					size_t count,
331 					uint32_t op_type,
332 					uint32_t memtype,
333 					uint32_t offset)
334 {
335 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
336 	int rv = -EINVAL;
337 	uint8_t *read_buffer;
338 	struct hif_softc *scn;
339 	struct hif_target_info *tgt_info;
340 
341 	if (!hif_hdl)
342 		return -EINVAL;
343 
344 	read_buffer = qdf_mem_malloc(count);
345 	if (!read_buffer)
346 		return -ENOMEM;
347 
348 	scn = HIF_GET_SOFTC(hif_hdl);
349 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
350 	switch (scn->bus_type) {
351 	case QDF_BUS_TYPE_PCI:
352 		switch (tgt_info->target_type) {
353 		case TARGET_TYPE_QCA6390:
354 		case TARGET_TYPE_QCA6490:
355 		case TARGET_TYPE_KIWI:
356 		case TARGET_TYPE_MANGO:
357 			if (op_type == OP_TYPE_EXT_DIRECT)
358 				rv = ath_procfs_direct_read(scn,
359 							    offset,
360 							    read_buffer,
361 							    count);
362 			else
363 				rv = pld_athdiag_read(scn->qdf_dev->dev,
364 						      offset,
365 						      memtype,
366 						      count,
367 						      read_buffer);
368 			break;
369 		default:
370 			hif_err("Unrecognized target type %d",
371 				tgt_info->target_type);
372 		}
373 		break;
374 	default:
375 		hif_err("Unrecognized bus type %d", scn->bus_type);
376 		break;
377 	}
378 
379 	if (rv) {
380 		hif_err("fail to read from target %d", rv);
381 	} else {
382 		rv = count;
383 		if (copy_to_user(buf, read_buffer, count)) {
384 			hif_err("copy_to_user error in /proc/%s",
385 				PROCFS_NAME);
386 			rv = -EFAULT;
387 		}
388 	}
389 
390 	qdf_mem_free(read_buffer);
391 
392 	return rv;
393 }
394 
395 static ssize_t ath_procfs_diag_write_ext(struct file *file,
396 					 const char __user *buf,
397 					 size_t count,
398 					 uint32_t op_type,
399 					 uint32_t memtype,
400 					 uint32_t offset)
401 {
402 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
403 	int rv = -EINVAL;
404 	uint8_t *write_buffer;
405 	struct hif_softc *scn;
406 	struct hif_target_info *tgt_info;
407 
408 	if (!hif_hdl)
409 		return -EINVAL;
410 
411 	scn = HIF_GET_SOFTC(hif_hdl);
412 
413 	write_buffer = qdf_mem_malloc(count);
414 	if (!write_buffer)
415 		return -ENOMEM;
416 
417 	if (copy_from_user(write_buffer, buf, count)) {
418 		qdf_mem_free(write_buffer);
419 		hif_err("copy_to_user error in /proc/%s",
420 			PROCFS_NAME);
421 		return -EFAULT;
422 	}
423 
424 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
425 
426 	switch (scn->bus_type) {
427 	case QDF_BUS_TYPE_PCI:
428 		switch (tgt_info->target_type) {
429 		case TARGET_TYPE_QCA6390:
430 		case TARGET_TYPE_QCA6490:
431 		case TARGET_TYPE_KIWI:
432 		case TARGET_TYPE_MANGO:
433 			if (op_type == OP_TYPE_EXT_DIRECT)
434 				rv = ath_procfs_direct_write(scn,
435 							     offset,
436 							     write_buffer,
437 							     count);
438 			else
439 				rv = pld_athdiag_write(scn->qdf_dev->dev,
440 						       offset,
441 						       memtype,
442 						       count,
443 						       write_buffer);
444 			break;
445 		default:
446 			hif_err("Unrecognized target type %d",
447 				tgt_info->target_type);
448 		}
449 		break;
450 	default:
451 		hif_err("Unrecognized bus type %d", scn->bus_type);
452 		break;
453 	}
454 
455 	qdf_mem_free(write_buffer);
456 
457 	return (rv == 0) ? count : -EIO;
458 }
459 
460 static void get_fields_from_pos(loff_t pos,
461 				uint32_t *op_type,
462 				uint32_t *memtype,
463 				uint32_t *offset)
464 {
465 	*op_type = QDF_GET_BITS64(pos, ATH_DIAG_EXT_OP_TYPE_INDEX,
466 				  ATH_DIAG_EXT_OP_TYPE_BITS);
467 	*memtype = QDF_GET_BITS64(pos, ATH_DIAG_EXT_MEM_TYPE_INDEX,
468 				  ATH_DIAG_EXT_MEM_TYPE_BITS);
469 	*offset = QDF_GET_BITS64(pos, ATH_DIAG_EXT_OFFSET_INDEX,
470 				 ATH_DIAG_EXT_OFFSET_BITS);
471 }
472 
473 static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
474 				    size_t count, loff_t *pos)
475 {
476 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
477 	int rv = -EINVAL;
478 	struct hif_softc *scn;
479 	uint32_t offset, memtype;
480 	uint32_t op_type;
481 
482 	if (!hif_hdl)
483 		return -EINVAL;
484 
485 	get_fields_from_pos(*pos, &op_type, &memtype, &offset);
486 
487 	scn = HIF_GET_SOFTC(hif_hdl);
488 	if (scn->bus_ops.hif_addr_in_boundary(scn, offset))
489 		return -EINVAL;
490 
491 	if (offset & 0x3)
492 		return -EINVAL;
493 
494 	hif_info("rd cnt %zu offset 0x%x op_type %d type %d pos %llx",
495 		 count, offset, op_type, memtype, *pos);
496 
497 	switch (op_type) {
498 	case OP_TYPE_LEGACY:
499 		rv = ath_procfs_diag_read_legacy(file, buf, count, pos);
500 		break;
501 	case OP_TYPE_EXT_QMI:
502 	case OP_TYPE_EXT_DIRECT:
503 		rv = ath_procfs_diag_read_ext(file, buf, count, op_type,
504 					      memtype, offset);
505 		break;
506 	default:
507 		hif_err("Unrecognized op type %d", op_type);
508 		break;
509 	}
510 
511 	return rv;
512 }
513 
514 static ssize_t ath_procfs_diag_write(struct file *file,
515 				     const char __user *buf,
516 				     size_t count, loff_t *pos)
517 {
518 	hif_handle_t hif_hdl = get_hif_hdl_from_file(file);
519 	int rv = -EINVAL;
520 	struct hif_softc *scn;
521 	uint32_t offset, memtype;
522 	uint32_t op_type;
523 
524 	if (!hif_hdl)
525 		return -EINVAL;
526 
527 	get_fields_from_pos(*pos, &op_type, &memtype, &offset);
528 
529 	scn = HIF_GET_SOFTC(hif_hdl);
530 	if (scn->bus_ops.hif_addr_in_boundary(scn, offset))
531 		return -EINVAL;
532 
533 	if (offset & 0x3)
534 		return -EINVAL;
535 
536 	hif_info("wr cnt %zu offset 0x%x op_type %d mem_type %d",
537 		 count, offset, op_type, memtype);
538 
539 	switch (op_type) {
540 	case OP_TYPE_LEGACY:
541 		rv = ath_procfs_diag_write_legacy(file, buf, count, pos);
542 		break;
543 	case OP_TYPE_EXT_QMI:
544 	case OP_TYPE_EXT_DIRECT:
545 		rv = ath_procfs_diag_write_ext(file, buf, count, op_type,
546 					       memtype, offset);
547 		break;
548 	default:
549 		hif_err("Unrecognized op type %d", op_type);
550 		break;
551 	}
552 
553 	return rv;
554 }
555 
556 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
557 static const struct proc_ops athdiag_fops = {
558 	.proc_read = ath_procfs_diag_read,
559 	.proc_write = ath_procfs_diag_write,
560 	.proc_lseek = default_llseek,
561 };
562 #else
563 static const struct file_operations athdiag_fops = {
564 	.read = ath_procfs_diag_read,
565 	.write = ath_procfs_diag_write,
566 };
567 #endif
568 
569 /*
570  * This function is called when the module is loaded
571  *
572  */
573 int athdiag_procfs_init(void *scn)
574 {
575 	proc_dir = proc_mkdir(PROCFS_DIR, NULL);
576 	if (!proc_dir) {
577 		remove_proc_entry(PROCFS_DIR, NULL);
578 		hif_err("Could not initialize /proc/%s", PROCFS_DIR);
579 		return -ENOMEM;
580 	}
581 
582 	proc_file = proc_create_data(PROCFS_NAME, 0600, proc_dir,
583 				     &athdiag_fops, (void *)scn);
584 	if (!proc_file) {
585 		remove_proc_entry(PROCFS_NAME, proc_dir);
586 		hif_err("Could not initialize /proc/%s", PROCFS_NAME);
587 		return -ENOMEM;
588 	}
589 
590 	hif_debug("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
591 	return 0;
592 }
593 
594 /*
595  * This function is called when the module is unloaded
596  *
597  */
598 void athdiag_procfs_remove(void)
599 {
600 	if (proc_dir) {
601 		remove_proc_entry(PROCFS_NAME, proc_dir);
602 		hif_debug("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
603 		remove_proc_entry(PROCFS_DIR, NULL);
604 		hif_debug("/proc/%s removed", PROCFS_DIR);
605 		proc_dir = NULL;
606 	}
607 }
608 #else
609 int athdiag_procfs_init(void *scn)
610 {
611 	return 0;
612 }
613 void athdiag_procfs_remove(void) {}
614 #endif
615