xref: /wlan-driver/platform/cnss_utils/cnss_utils.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2017, 2019, 2021 The Linux Foundation. All rights reserved.
4  * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
5  */
6 
7 #define pr_fmt(fmt) "cnss_utils: " fmt
8 
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/etherdevice.h>
13 #include <linux/debugfs.h>
14 #include <linux/of.h>
15 #ifdef CONFIG_CNSS_OUT_OF_TREE
16 #include "cnss_utils.h"
17 #else
18 #include <net/cnss_utils.h>
19 #endif
20 
21 #ifdef CONFIG_FEATURE_SMEM_MAILBOX
22 #include <smem-mailbox.h>
23 #endif
24 
25 #define CNSS_MAX_CH_NUM 157
26 struct cnss_unsafe_channel_list {
27 	u16 unsafe_ch_count;
28 	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
29 };
30 
31 struct cnss_dfs_nol_info {
32 	void *dfs_nol_info;
33 	u16 dfs_nol_info_len;
34 };
35 
36 #define MAX_NO_OF_MAC_ADDR 4
37 #define MAC_PREFIX_LEN 2
38 struct cnss_wlan_mac_addr {
39 	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
40 	u32 no_of_mac_addr_set;
41 };
42 
43 enum mac_type {
44 	CNSS_MAC_PROVISIONED,
45 	CNSS_MAC_DERIVED,
46 };
47 
48 static struct cnss_utils_priv {
49 	struct cnss_unsafe_channel_list unsafe_channel_list;
50 	struct cnss_dfs_nol_info dfs_nol_info;
51 	/* generic mutex for unsafe channel */
52 	struct mutex unsafe_channel_list_lock;
53 	/* generic spin-lock for dfs_nol info */
54 	spinlock_t dfs_nol_info_lock;
55 	int driver_load_cnt;
56 	struct cnss_wlan_mac_addr wlan_mac_addr;
57 	struct cnss_wlan_mac_addr wlan_der_mac_addr;
58 	enum cnss_utils_cc_src cc_source;
59 	struct dentry *root_dentry;
60 	/* generic mutex for device_id */
61 	struct mutex cnss_device_id_lock;
62 	enum cnss_utils_device_type cnss_device_type;
63 #ifdef CONFIG_FEATURE_SMEM_MAILBOX
64 	bool smem_mailbox_initialized;
65 	int smem_mailbox_id;
66 #endif
67 } *cnss_utils_priv;
68 
cnss_utils_set_wlan_unsafe_channel(struct device * dev,u16 * unsafe_ch_list,u16 ch_count)69 int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
70 				       u16 *unsafe_ch_list, u16 ch_count)
71 {
72 	struct cnss_utils_priv *priv = cnss_utils_priv;
73 
74 	if (!priv)
75 		return -EINVAL;
76 
77 	mutex_lock(&priv->unsafe_channel_list_lock);
78 	if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) {
79 		mutex_unlock(&priv->unsafe_channel_list_lock);
80 		return -EINVAL;
81 	}
82 
83 	priv->unsafe_channel_list.unsafe_ch_count = ch_count;
84 
85 	if (ch_count == 0)
86 		goto end;
87 
88 	memcpy(priv->unsafe_channel_list.unsafe_ch_list,
89 	       unsafe_ch_list, ch_count * sizeof(u16));
90 
91 end:
92 	mutex_unlock(&priv->unsafe_channel_list_lock);
93 
94 	return 0;
95 }
96 EXPORT_SYMBOL(cnss_utils_set_wlan_unsafe_channel);
97 
cnss_utils_get_wlan_unsafe_channel(struct device * dev,u16 * unsafe_ch_list,u16 * ch_count,u16 buf_len)98 int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
99 				       u16 *unsafe_ch_list,
100 				       u16 *ch_count, u16 buf_len)
101 {
102 	struct cnss_utils_priv *priv = cnss_utils_priv;
103 
104 	if (!priv)
105 		return -EINVAL;
106 
107 	mutex_lock(&priv->unsafe_channel_list_lock);
108 	if (!unsafe_ch_list || !ch_count) {
109 		mutex_unlock(&priv->unsafe_channel_list_lock);
110 		return -EINVAL;
111 	}
112 
113 	if (buf_len <
114 	    (priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
115 		mutex_unlock(&priv->unsafe_channel_list_lock);
116 		return -ENOMEM;
117 	}
118 
119 	*ch_count = priv->unsafe_channel_list.unsafe_ch_count;
120 	memcpy(unsafe_ch_list, priv->unsafe_channel_list.unsafe_ch_list,
121 	       priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16));
122 	mutex_unlock(&priv->unsafe_channel_list_lock);
123 
124 	return 0;
125 }
126 EXPORT_SYMBOL(cnss_utils_get_wlan_unsafe_channel);
127 
cnss_utils_update_device_type(enum cnss_utils_device_type device_type)128 enum cnss_utils_device_type cnss_utils_update_device_type(
129 			enum cnss_utils_device_type  device_type)
130 {
131 	struct cnss_utils_priv *priv = cnss_utils_priv;
132 
133 	if (!priv)
134 		return -EINVAL;
135 
136 	mutex_lock(&priv->cnss_device_id_lock);
137 	pr_info("cnss_utils: device type:%d\n", device_type);
138 	if (priv->cnss_device_type == CNSS_UNSUPPORETD_DEVICE_TYPE) {
139 		priv->cnss_device_type = device_type;
140 		pr_info("cnss_utils: set device type:%d\n",
141 			priv->cnss_device_type);
142 	} else {
143 		pr_info("cnss_utils: device type already set :%d\n",
144 			priv->cnss_device_type);
145 	}
146 	mutex_unlock(&priv->cnss_device_id_lock);
147 	return priv->cnss_device_type;
148 }
149 EXPORT_SYMBOL(cnss_utils_update_device_type);
150 
cnss_utils_wlan_set_dfs_nol(struct device * dev,const void * info,u16 info_len)151 int cnss_utils_wlan_set_dfs_nol(struct device *dev,
152 				const void *info, u16 info_len)
153 {
154 	void *temp;
155 	void *old_nol_info;
156 	struct cnss_dfs_nol_info *dfs_info;
157 	struct cnss_utils_priv *priv = cnss_utils_priv;
158 
159 	if (!priv)
160 		return -EINVAL;
161 
162 	if (!info || !info_len)
163 		return -EINVAL;
164 
165 	temp = kmemdup(info, info_len, GFP_ATOMIC);
166 	if (!temp)
167 		return -ENOMEM;
168 
169 	spin_lock_bh(&priv->dfs_nol_info_lock);
170 	dfs_info = &priv->dfs_nol_info;
171 	old_nol_info = dfs_info->dfs_nol_info;
172 	dfs_info->dfs_nol_info = temp;
173 	dfs_info->dfs_nol_info_len = info_len;
174 	spin_unlock_bh(&priv->dfs_nol_info_lock);
175 	kfree(old_nol_info);
176 
177 	return 0;
178 }
179 EXPORT_SYMBOL(cnss_utils_wlan_set_dfs_nol);
180 
cnss_utils_wlan_get_dfs_nol(struct device * dev,void * info,u16 info_len)181 int cnss_utils_wlan_get_dfs_nol(struct device *dev,
182 				void *info, u16 info_len)
183 {
184 	int len;
185 	struct cnss_dfs_nol_info *dfs_info;
186 	struct cnss_utils_priv *priv = cnss_utils_priv;
187 
188 	if (!priv)
189 		return -EINVAL;
190 
191 	if (!info || !info_len)
192 		return -EINVAL;
193 
194 	spin_lock_bh(&priv->dfs_nol_info_lock);
195 
196 	dfs_info = &priv->dfs_nol_info;
197 	if (!dfs_info->dfs_nol_info ||
198 	    dfs_info->dfs_nol_info_len == 0) {
199 		spin_unlock_bh(&priv->dfs_nol_info_lock);
200 		return -ENOENT;
201 	}
202 
203 	len = min(info_len, dfs_info->dfs_nol_info_len);
204 	memcpy(info, dfs_info->dfs_nol_info, len);
205 	spin_unlock_bh(&priv->dfs_nol_info_lock);
206 
207 	return len;
208 }
209 EXPORT_SYMBOL(cnss_utils_wlan_get_dfs_nol);
210 
cnss_utils_increment_driver_load_cnt(struct device * dev)211 void cnss_utils_increment_driver_load_cnt(struct device *dev)
212 {
213 	struct cnss_utils_priv *priv = cnss_utils_priv;
214 
215 	if (!priv)
216 		return;
217 
218 	++(priv->driver_load_cnt);
219 }
220 EXPORT_SYMBOL(cnss_utils_increment_driver_load_cnt);
221 
cnss_utils_get_driver_load_cnt(struct device * dev)222 int cnss_utils_get_driver_load_cnt(struct device *dev)
223 {
224 	struct cnss_utils_priv *priv = cnss_utils_priv;
225 
226 	if (!priv)
227 		return -EINVAL;
228 
229 	return priv->driver_load_cnt;
230 }
231 EXPORT_SYMBOL(cnss_utils_get_driver_load_cnt);
232 
set_wlan_mac_address(const u8 * mac_list,const uint32_t len,enum mac_type type)233 static int set_wlan_mac_address(const u8 *mac_list, const uint32_t len,
234 				enum mac_type type)
235 {
236 	struct cnss_utils_priv *priv = cnss_utils_priv;
237 	u32 no_of_mac_addr;
238 	struct cnss_wlan_mac_addr *addr = NULL;
239 	int iter;
240 	u8 *temp = NULL;
241 
242 	if (!priv)
243 		return -EINVAL;
244 
245 	if (len == 0 || (len % ETH_ALEN) != 0) {
246 		pr_err("Invalid length %d\n", len);
247 		return -EINVAL;
248 	}
249 
250 	no_of_mac_addr = len / ETH_ALEN;
251 	if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
252 		pr_err("Exceed maximum supported MAC address %u %u\n",
253 		       MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
254 		return -EINVAL;
255 	}
256 
257 	if (type == CNSS_MAC_PROVISIONED)
258 		addr = &priv->wlan_mac_addr;
259 	else
260 		addr = &priv->wlan_der_mac_addr;
261 
262 	if (addr->no_of_mac_addr_set) {
263 		pr_err("WLAN MAC address is already set, num %d type %d\n",
264 		       addr->no_of_mac_addr_set, type);
265 		return 0;
266 	}
267 
268 	addr->no_of_mac_addr_set = no_of_mac_addr;
269 	temp = &addr->mac_addr[0][0];
270 
271 	for (iter = 0; iter < no_of_mac_addr;
272 	     ++iter, temp += ETH_ALEN, mac_list += ETH_ALEN) {
273 		ether_addr_copy(temp, mac_list);
274 		pr_debug("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
275 			 temp[0], temp[1], temp[2],
276 			 temp[3], temp[4], temp[5]);
277 	}
278 	return 0;
279 }
280 
cnss_utils_set_wlan_mac_address(const u8 * mac_list,const uint32_t len)281 int cnss_utils_set_wlan_mac_address(const u8 *mac_list, const uint32_t len)
282 {
283 	return set_wlan_mac_address(mac_list, len, CNSS_MAC_PROVISIONED);
284 }
285 EXPORT_SYMBOL(cnss_utils_set_wlan_mac_address);
286 
cnss_utils_set_wlan_derived_mac_address(const u8 * mac_list,const uint32_t len)287 int cnss_utils_set_wlan_derived_mac_address(const u8 *mac_list,
288 					    const uint32_t len)
289 {
290 	return set_wlan_mac_address(mac_list, len, CNSS_MAC_DERIVED);
291 }
292 EXPORT_SYMBOL(cnss_utils_set_wlan_derived_mac_address);
293 
get_wlan_mac_address(struct device * dev,u32 * num,enum mac_type type)294 static u8 *get_wlan_mac_address(struct device *dev,
295 				u32 *num, enum mac_type type)
296 {
297 	struct cnss_utils_priv *priv = cnss_utils_priv;
298 	struct cnss_wlan_mac_addr *addr = NULL;
299 
300 	if (!priv)
301 		goto out;
302 
303 	if (type == CNSS_MAC_PROVISIONED)
304 		addr = &priv->wlan_mac_addr;
305 	else
306 		addr = &priv->wlan_der_mac_addr;
307 
308 	if (!addr->no_of_mac_addr_set) {
309 		pr_err("WLAN MAC address is not set, type %d\n", type);
310 		goto out;
311 	}
312 	*num = addr->no_of_mac_addr_set;
313 	return &addr->mac_addr[0][0];
314 
315 out:
316 	*num = 0;
317 	return NULL;
318 }
319 
cnss_utils_get_wlan_mac_address(struct device * dev,uint32_t * num)320 u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num)
321 {
322 	return get_wlan_mac_address(dev, num, CNSS_MAC_PROVISIONED);
323 }
324 EXPORT_SYMBOL(cnss_utils_get_wlan_mac_address);
325 
cnss_utils_get_wlan_derived_mac_address(struct device * dev,uint32_t * num)326 u8 *cnss_utils_get_wlan_derived_mac_address(struct device *dev,
327 					    uint32_t *num)
328 {
329 	return get_wlan_mac_address(dev, num, CNSS_MAC_DERIVED);
330 }
331 EXPORT_SYMBOL(cnss_utils_get_wlan_derived_mac_address);
332 
cnss_utils_set_cc_source(struct device * dev,enum cnss_utils_cc_src cc_source)333 void cnss_utils_set_cc_source(struct device *dev,
334 			      enum cnss_utils_cc_src cc_source)
335 {
336 	struct cnss_utils_priv *priv = cnss_utils_priv;
337 
338 	if (!priv)
339 		return;
340 
341 	priv->cc_source = cc_source;
342 }
343 EXPORT_SYMBOL(cnss_utils_set_cc_source);
344 
cnss_utils_get_cc_source(struct device * dev)345 enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev)
346 {
347 	struct cnss_utils_priv *priv = cnss_utils_priv;
348 
349 	if (!priv)
350 		return -EINVAL;
351 
352 	return priv->cc_source;
353 }
354 EXPORT_SYMBOL(cnss_utils_get_cc_source);
355 
356 #ifdef CONFIG_FEATURE_SMEM_MAILBOX
cnss_utils_smem_mailbox_write(struct device * dev,int flags,const __u8 * data,uint32_t len)357 int cnss_utils_smem_mailbox_write(struct device *dev, int flags,
358 				  const __u8 *data, uint32_t len)
359 {
360 	struct cnss_utils_priv *priv = cnss_utils_priv;
361 
362 	if (!priv)
363 		return -EINVAL;
364 	if (!priv->smem_mailbox_initialized) {
365 		if (smem_mailbox_start(priv->smem_mailbox_id, NULL) != 1) {
366 			pr_err("Didn't init smem mailbox properly\n");
367 			return -EINVAL;
368 		} else
369 			priv->smem_mailbox_initialized = true;
370 	}
371 	return smem_mailbox_write(priv->smem_mailbox_id, flags, (__u8 *)data,
372 				  len);
373 }
374 EXPORT_SYMBOL(cnss_utils_smem_mailbox_write);
375 #endif
376 
cnss_utils_mac_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)377 static ssize_t cnss_utils_mac_write(struct file *fp,
378 				    const char __user *user_buf,
379 				    size_t count, loff_t *off)
380 {
381 	struct cnss_utils_priv *priv =
382 		((struct seq_file *)fp->private_data)->private;
383 	char buf[128];
384 	char *input, *mac_type, *mac_address;
385 	u8 *dest_mac;
386 	u8 val;
387 	const char *delim = "\n";
388 	size_t len = 0;
389 	char temp[3] = "";
390 
391 	len = min_t(size_t, count, sizeof(buf) - 1);
392 	if (copy_from_user(buf, user_buf, len))
393 		return -EINVAL;
394 	buf[len] = '\0';
395 
396 	input = buf;
397 
398 	mac_type = strsep(&input, delim);
399 	if (!mac_type)
400 		return -EINVAL;
401 	if (!input)
402 		return -EINVAL;
403 
404 	mac_address = strsep(&input, delim);
405 	if (!mac_address)
406 		return -EINVAL;
407 	if (strcmp("0x", mac_address)) {
408 		pr_err("Invalid MAC prefix\n");
409 		return -EINVAL;
410 	}
411 
412 	len = strlen(mac_address);
413 	mac_address += MAC_PREFIX_LEN;
414 	len -= MAC_PREFIX_LEN;
415 	if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
416 	    len % (ETH_ALEN * 2) != 0) {
417 		pr_err("Invalid MAC address length %zu\n", len);
418 		return -EINVAL;
419 	}
420 
421 	if (!strcmp("provisioned", mac_type)) {
422 		dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
423 		priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
424 	} else if (!strcmp("derived", mac_type)) {
425 		dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
426 		priv->wlan_der_mac_addr.no_of_mac_addr_set =
427 			len / (ETH_ALEN * 2);
428 	} else {
429 		pr_err("Invalid MAC address type %s\n", mac_type);
430 		return -EINVAL;
431 	}
432 
433 	while (len--) {
434 		temp[0] = *mac_address++;
435 		temp[1] = *mac_address++;
436 		if (kstrtou8(temp, 16, &val))
437 			return -EINVAL;
438 		*dest_mac++ = val;
439 	}
440 	return count;
441 }
442 
cnss_utils_mac_show(struct seq_file * s,void * data)443 static int cnss_utils_mac_show(struct seq_file *s, void *data)
444 {
445 	u8 mac[6];
446 	int i;
447 	struct cnss_utils_priv *priv = s->private;
448 	struct cnss_wlan_mac_addr *addr = NULL;
449 
450 	addr = &priv->wlan_mac_addr;
451 	if (addr->no_of_mac_addr_set) {
452 		seq_puts(s, "\nProvisioned MAC addresseses\n");
453 		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
454 			ether_addr_copy(mac, addr->mac_addr[i]);
455 			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
456 				   mac[0], mac[1], mac[2],
457 				   mac[3], mac[4], mac[5]);
458 		}
459 	}
460 
461 	addr = &priv->wlan_der_mac_addr;
462 	if (addr->no_of_mac_addr_set) {
463 		seq_puts(s, "\nDerived MAC addresseses\n");
464 		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
465 			ether_addr_copy(mac, addr->mac_addr[i]);
466 			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
467 				   mac[0], mac[1], mac[2],
468 				   mac[3], mac[4], mac[5]);
469 		}
470 	}
471 
472 	return 0;
473 }
474 
cnss_utils_mac_open(struct inode * inode,struct file * file)475 static int cnss_utils_mac_open(struct inode *inode, struct file *file)
476 {
477 	return single_open(file, cnss_utils_mac_show, inode->i_private);
478 }
479 
480 static const struct file_operations cnss_utils_mac_fops = {
481 	.read		= seq_read,
482 	.write		= cnss_utils_mac_write,
483 	.release	= single_release,
484 	.open		= cnss_utils_mac_open,
485 	.owner		= THIS_MODULE,
486 	.llseek		= seq_lseek,
487 };
488 
cnss_utils_debugfs_create(struct cnss_utils_priv * priv)489 static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
490 {
491 	int ret = 0;
492 	struct dentry *root_dentry;
493 
494 	root_dentry = debugfs_create_dir("cnss_utils", NULL);
495 
496 	if (IS_ERR(root_dentry)) {
497 		ret = PTR_ERR(root_dentry);
498 		pr_err("Unable to create debugfs %d\n", ret);
499 		goto out;
500 	}
501 	priv->root_dentry = root_dentry;
502 	debugfs_create_file("mac_address", 0600, root_dentry, priv,
503 			    &cnss_utils_mac_fops);
504 out:
505 	return ret;
506 }
507 
508 /**
509  * cnss_utils_is_valid_dt_node_found - Check if valid device tree node present
510  *
511  * Valid device tree node means a node with "qcom,wlan" property present and
512  * "status" property not disabled.
513  *
514  * Return: true if valid device tree node found, false if not found
515  */
cnss_utils_is_valid_dt_node_found(void)516 static bool cnss_utils_is_valid_dt_node_found(void)
517 {
518 	struct device_node *dn = NULL;
519 
520 	for_each_node_with_property(dn, "qcom,wlan") {
521 		if (of_device_is_available(dn))
522 			break;
523 	}
524 
525 	if (dn)
526 		return true;
527 
528 	return false;
529 }
530 
531 #ifdef CONFIG_FEATURE_SMEM_MAILBOX
cnss_utils_smem_mailbox_init(void)532 static void cnss_utils_smem_mailbox_init(void)
533 {
534 	struct cnss_utils_priv *priv = cnss_utils_priv;
535 
536 	priv->smem_mailbox_id = 0;
537 	priv->smem_mailbox_initialized = false;
538 }
539 
cnss_utils_smem_mailbox_deinit(void)540 static void cnss_utils_smem_mailbox_deinit(void)
541 {
542 	struct cnss_utils_priv *priv = cnss_utils_priv;
543 
544 	smem_mailbox_stop(priv->smem_mailbox_id);
545 }
546 #else
cnss_utils_smem_mailbox_init(void)547 static void cnss_utils_smem_mailbox_init(void)
548 {
549 }
550 
cnss_utils_smem_mailbox_deinit(void)551 static void cnss_utils_smem_mailbox_deinit(void)
552 {
553 }
554 #endif
555 
cnss_utils_init(void)556 static int __init cnss_utils_init(void)
557 {
558 	struct cnss_utils_priv *priv = NULL;
559 
560 	if (!cnss_utils_is_valid_dt_node_found())
561 		return -ENODEV;
562 
563 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
564 	if (!priv)
565 		return -ENOMEM;
566 
567 	priv->cc_source = CNSS_UTILS_SOURCE_CORE;
568 	priv->cnss_device_type = CNSS_UNSUPPORETD_DEVICE_TYPE;
569 
570 	mutex_init(&priv->unsafe_channel_list_lock);
571 	mutex_init(&priv->cnss_device_id_lock);
572 	spin_lock_init(&priv->dfs_nol_info_lock);
573 	cnss_utils_debugfs_create(priv);
574 	cnss_utils_priv = priv;
575 	cnss_utils_smem_mailbox_init();
576 	return 0;
577 }
578 
cnss_utils_exit(void)579 static void __exit cnss_utils_exit(void)
580 {
581 	cnss_utils_smem_mailbox_deinit();
582 	kfree(cnss_utils_priv);
583 	cnss_utils_priv = NULL;
584 }
585 
586 module_init(cnss_utils_init);
587 module_exit(cnss_utils_exit);
588 
589 MODULE_LICENSE("GPL v2");
590 MODULE_DESCRIPTION("CNSS Utilities Driver");
591