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