xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wb_regon_coordinator.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * DHD BT WiFi Coex RegON Coordinator
3  *
4  * Copyright (C) 2020, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *
21  * <<Broadcom-WL-IPTag/Open:>>
22  *
23  */
24 #include <linux/cdev.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/device.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
30 #include <linux/fs.h>
31 #include <linux/uaccess.h>
32 #include <linux/poll.h>
33 #include <linux/eventpoll.h>
34 #include <linux/version.h>
35 
36 #define DESCRIPTION "Broadcom WiFi BT Regon coordinator Driver"
37 #define AUTHOR "Broadcom Corporation"
38 
39 #define DEVICE_NAME "wbrc"
40 #define CLASS_NAME "bcm"
41 
42 #ifndef TRUE
43 #define TRUE (1)
44 #endif
45 
46 #ifndef FALSE
47 #define FALSE (0)
48 #endif
49 
50 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
51 typedef unsigned int __poll_t;
52 #endif
53 
54 /*
55  * 4 byte message to sync with BT stack.
56  * Byte 0 - header
57  * Byte 1 - length of LTV now fixed to 2
58  * Byte 2 - type
59  * Byte 3 - command value
60 */
61 #define WBRC_MSG_LEN	4u
62 
63 /* Below defines to be mapped in the user space. */
64 /* TODO have these as enums and define new structure with members */
65 
66 /* Byte 0 - Define header for direction of command */
67 #define HEADER_DIR_WL2BT 0x01
68 #define HEADER_DIR_BT2WL 0x02
69 
70 /*
71  * Byte 2 - Define Type of Command (Followed LTV format)
72  * wifi/bt, signal/ack types
73  */
74 #define TYPE_WIFI_CMD 0x01
75 #define TYPE_WIFI_ACK 0x02
76 #define TYPE_BT_CMD 0x03
77 #define TYPE_BT_ACK 0x04
78 
79 /* Byte 3 - Define Value field: commands/acks */
80 #define CMD_RESET_WIFI 0x40
81 #define CMD_RESET_WIFI_WITH_ACK 0x41
82 #define CMD_RESET_BT 0x42
83 #define CMD_RESET_BT_WITH_ACK 0x43
84 #define ACK_RESET_WIFI_COMPLETE 0x80
85 #define ACK_RESET_BT_COMPLETE 0x81
86 
87 struct wbrc_pvt_data {
88 	int wbrc_bt_dev_major_number;		/* BT char dev major number */
89 	struct class *wbrc_bt_dev_class;	/* BT char dev class */
90 	struct device *wbrc_bt_dev_device;	/* BT char dev */
91 	struct mutex wbrc_mutex;		/* mutex to synchronise */
92 	bool bt_dev_opened;			/* To check if bt dev open is called */
93 	wait_queue_head_t bt_reset_waitq;	/* waitq to wait till bt reset is done */
94 	unsigned int bt_reset_ack;		/* condition variable to be check for bt reset */
95 	wait_queue_head_t wlan_reset_waitq;	/* waitq to wait till wlan reset is done */
96 	unsigned int wlan_reset_ack;		/* condition variable to be check for wlan reset */
97 	wait_queue_head_t outmsg_waitq;		/* wait queue for poll */
98 	char wl2bt_message[WBRC_MSG_LEN];	/* message to communicate with Bt stack */
99 	bool read_data_available;		/* condition to check if read data is present */
100 };
101 
102 static struct wbrc_pvt_data *g_wbrc_data;
103 
104 #define WBRC_LOCK(wbrc_data)	{if (wbrc_data) mutex_lock(&(wbrc_data)->wbrc_mutex);}
105 #define WBRC_UNLOCK(wbrc_data)	{if (wbrc_data) mutex_unlock(&(wbrc_data)->wbrc_mutex);}
106 
107 int wbrc_wl2bt_reset(void);
108 int wbrc_bt_reset_ack(struct wbrc_pvt_data *wbrc_data);
109 
110 int wbrc_bt2wl_reset(void);
111 int wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data);
112 
113 static int wbrc_bt_dev_open(struct inode *, struct file *);
114 static int wbrc_bt_dev_release(struct inode *, struct file *);
115 static ssize_t wbrc_bt_dev_read(struct file *, char *, size_t, loff_t *);
116 static ssize_t wbrc_bt_dev_write(struct file *, const char *, size_t, loff_t *);
117 static __poll_t wbrc_bt_dev_poll(struct file *filep, poll_table *wait);
118 
119 static struct file_operations wbrc_bt_dev_fops = {
120 	.open = wbrc_bt_dev_open,
121 	.read = wbrc_bt_dev_read,
122 	.write = wbrc_bt_dev_write,
123 	.release = wbrc_bt_dev_release,
124 	.poll = wbrc_bt_dev_poll,
125 };
126 
wbrc_bt_dev_read(struct file * filep,char * buffer,size_t len,loff_t * offset)127 static ssize_t wbrc_bt_dev_read(struct file *filep, char *buffer, size_t len,
128                              loff_t *offset)
129 {
130 	struct wbrc_pvt_data *wbrc_data = filep->private_data;
131 	int err_count = 0;
132 	int ret = 0;
133 
134 	WBRC_LOCK(wbrc_data);
135 	pr_info("%s\n", __func__);
136 	if (wbrc_data->read_data_available == FALSE) {
137 		goto exit;
138 	}
139 	if (len < WBRC_MSG_LEN) {
140 		pr_err("%s: invalid length:%d\n", __func__, (int)len);
141 		ret = -EFAULT;
142 		goto exit;
143 	}
144 	err_count = copy_to_user(buffer, &wbrc_data->wl2bt_message,
145 		sizeof(wbrc_data->wl2bt_message));
146 	if (err_count == 0) {
147 		pr_info("Sent %d bytes\n",
148 			(int)sizeof(wbrc_data->wl2bt_message));
149 		err_count = sizeof(wbrc_data->wl2bt_message);
150 	} else {
151 		pr_err("Failed to send %d bytes\n", err_count);
152 		ret = -EFAULT;
153 	}
154 	wbrc_data->read_data_available = FALSE;
155 
156 exit:
157 	WBRC_UNLOCK(wbrc_data);
158 	return ret;
159 }
160 
wbrc_bt_dev_write(struct file * filep,const char * buffer,size_t len,loff_t * offset)161 static ssize_t wbrc_bt_dev_write(struct file *filep, const char *buffer,
162 	size_t len, loff_t *offset)
163 {
164 	struct wbrc_pvt_data *wbrc_data = filep->private_data;
165 	int err_count = 0;
166 	int ret = 0;
167 	char message[WBRC_MSG_LEN] = {};
168 
169 	WBRC_LOCK(wbrc_data);
170 
171 	pr_info("%s Received %zu bytes\n", __func__, len);
172 	if (len < WBRC_MSG_LEN) {
173 		pr_err("%s: Received malformed packet:%d\n", __func__, (int)len);
174 		ret = -EFAULT;
175 		goto exit;
176 	}
177 
178 	err_count = copy_from_user(message, buffer, len);
179 	if (err_count) {
180 		pr_err("%s: copy_from_user failed:%d\n", __func__, err_count);
181 		ret = -EFAULT;
182 		goto exit;
183 	}
184 
185 	if (message[0] != HEADER_DIR_BT2WL) {
186 		pr_err("%s: invalid header:%d\n", __func__, message[0]);
187 		ret = -EFAULT;
188 		goto exit;
189 	}
190 
191 	if (message[2] == TYPE_BT_CMD) {
192 		switch (message[3]) {
193 			case CMD_RESET_WIFI:
194 				pr_info("RCVD CMD_RESET_WIFI\n");
195 				break;
196 			case CMD_RESET_WIFI_WITH_ACK:
197 				pr_info("RCVD CMD_RESET_WIFI_WITH_ACK\n");
198 				break;
199 		}
200 	}
201 
202 	if (message[2] == TYPE_BT_ACK && message[3] == ACK_RESET_BT_COMPLETE) {
203 		pr_info("RCVD ACK_RESET_BT_COMPLETE");
204 		wbrc_bt_reset_ack(wbrc_data);
205 	}
206 
207 exit:
208 	WBRC_UNLOCK(wbrc_data);
209 	return ret;
210 }
211 
wbrc_bt_dev_poll(struct file * filep,poll_table * wait)212 static __poll_t wbrc_bt_dev_poll(struct file *filep, poll_table *wait)
213 {
214 	struct wbrc_pvt_data *wbrc_data = filep->private_data;
215 	__poll_t mask = 0;
216 
217 	poll_wait(filep, &wbrc_data->outmsg_waitq, wait);
218 
219 	if (wbrc_data->read_data_available)
220 		mask |= EPOLLIN | EPOLLRDNORM;
221 
222 	if (!wbrc_data->bt_dev_opened)
223 		mask |= EPOLLHUP;
224 
225 	return mask;
226 }
227 
wbrc_bt_dev_open(struct inode * inodep,struct file * filep)228 static int wbrc_bt_dev_open(struct inode *inodep, struct file *filep)
229 {
230 	struct wbrc_pvt_data *wbrc_data = g_wbrc_data;
231 	int ret = 0;
232 	WBRC_LOCK(wbrc_data);
233 	if (wbrc_data->bt_dev_opened) {
234 		pr_err("%s already opened\n", __func__);
235 		ret = -EFAULT;
236 		goto exit;
237 	}
238 	wbrc_data->bt_dev_opened = TRUE;
239 	pr_info("%s Device opened %d time(s)\n", __func__,
240 		wbrc_data->bt_dev_opened);
241 	filep->private_data = wbrc_data;
242 
243 exit:
244 	WBRC_UNLOCK(wbrc_data);
245 	return ret;
246 }
247 
wbrc_bt_dev_release(struct inode * inodep,struct file * filep)248 static int wbrc_bt_dev_release(struct inode *inodep, struct file *filep)
249 {
250 	struct wbrc_pvt_data *wbrc_data = filep->private_data;
251 	WBRC_LOCK(wbrc_data);
252 	pr_info("%s Device closed %d\n", __func__, wbrc_data->bt_dev_opened);
253 	wbrc_data->bt_dev_opened = FALSE;
254 	WBRC_UNLOCK(wbrc_data);
255 	wake_up_interruptible(&wbrc_data->outmsg_waitq);
256 	return 0;
257 }
258 
wbrc_signal_bt_reset(struct wbrc_pvt_data * wbrc_data)259 void wbrc_signal_bt_reset(struct wbrc_pvt_data *wbrc_data)
260 {
261 	pr_info("%s\n", __func__);
262 
263 	/* Below message will be read by userspace using .read */
264 	wbrc_data->wl2bt_message[0] = HEADER_DIR_WL2BT;       // Minimal Header
265 	wbrc_data->wl2bt_message[1] = 2;                      // Length
266 	wbrc_data->wl2bt_message[2] = TYPE_WIFI_CMD;          // Type
267 	wbrc_data->wl2bt_message[3] = CMD_RESET_BT_WITH_ACK;  // Value
268 	wbrc_data->read_data_available = TRUE;
269 	smp_wmb();
270 
271 	wake_up_interruptible(&wbrc_data->outmsg_waitq);
272 }
273 
wbrc_init(void)274 int wbrc_init(void)
275 {
276 	int err = 0;
277 	struct wbrc_pvt_data *wbrc_data;
278 	pr_info("%s\n", __func__);
279 	wbrc_data = kzalloc(sizeof(struct wbrc_pvt_data), GFP_KERNEL);
280 	if (wbrc_data == NULL) {
281 		return -ENOMEM;
282 	}
283 	mutex_init(&wbrc_data->wbrc_mutex);
284 	init_waitqueue_head(&wbrc_data->bt_reset_waitq);
285 	init_waitqueue_head(&wbrc_data->wlan_reset_waitq);
286 	init_waitqueue_head(&wbrc_data->outmsg_waitq);
287 	g_wbrc_data = wbrc_data;
288 
289 	wbrc_data->wbrc_bt_dev_major_number = register_chrdev(0, DEVICE_NAME, &wbrc_bt_dev_fops);
290 	err = wbrc_data->wbrc_bt_dev_major_number;
291 	if (wbrc_data->wbrc_bt_dev_major_number < 0) {
292 		pr_alert("wbrc_sequencer failed to register a major number\n");
293 		goto err_register;
294 	}
295 
296 	wbrc_data->wbrc_bt_dev_class = class_create(THIS_MODULE, CLASS_NAME);
297 	err = PTR_ERR(wbrc_data->wbrc_bt_dev_class);
298 	if (IS_ERR(wbrc_data->wbrc_bt_dev_class)) {
299 		pr_alert("Failed to register device class\n");
300 		goto err_class;
301 	}
302 
303 	wbrc_data->wbrc_bt_dev_device = device_create(
304 		wbrc_data->wbrc_bt_dev_class, NULL, MKDEV(wbrc_data->wbrc_bt_dev_major_number, 0),
305 		NULL, DEVICE_NAME);
306 	err = PTR_ERR(wbrc_data->wbrc_bt_dev_device);
307 	if (IS_ERR(wbrc_data->wbrc_bt_dev_device)) {
308 		pr_alert("Failed to create the device\n");
309 		goto err_device;
310 	}
311 	pr_info("device class created correctly\n");
312 
313 	return 0;
314 
315 err_device:
316 	class_destroy(wbrc_data->wbrc_bt_dev_class);
317 err_class:
318 	unregister_chrdev(wbrc_data->wbrc_bt_dev_major_number, DEVICE_NAME);
319 err_register:
320 	kfree(wbrc_data);
321 	g_wbrc_data = NULL;
322 	return err;
323 }
324 
wbrc_exit(void)325 void wbrc_exit(void)
326 {
327 	struct wbrc_pvt_data *wbrc_data = g_wbrc_data;
328 	pr_info("%s\n", __func__);
329 	wake_up_interruptible(&wbrc_data->outmsg_waitq);
330 	device_destroy(wbrc_data->wbrc_bt_dev_class, MKDEV(wbrc_data->wbrc_bt_dev_major_number, 0));
331 	class_destroy(wbrc_data->wbrc_bt_dev_class);
332 	unregister_chrdev(wbrc_data->wbrc_bt_dev_major_number, DEVICE_NAME);
333 	kfree(wbrc_data);
334 	g_wbrc_data = NULL;
335 }
336 
337 #ifndef BCMDHD_MODULAR
338 /* Required only for Built-in DHD */
339 module_init(wbrc_init);
340 module_exit(wbrc_exit);
341 #endif /* BOARD_MODULAR */
342 
343 MODULE_LICENSE("GPL v2");
344 MODULE_DESCRIPTION(DESCRIPTION);
345 MODULE_AUTHOR(AUTHOR);
346 
347 /*
348  * Wait until the condition *var == condition is met.
349  * Returns 0 if the @condition evaluated to false after the timeout elapsed
350  * Returns 1 if the @condition evaluated to true
351  */
352 #define WBRC_RESET_WAIT_TIMEOUT 4000
353 int
wbrc_reset_wait_on_condition(wait_queue_head_t * reset_waitq,uint * var,uint condition)354 wbrc_reset_wait_on_condition(wait_queue_head_t *reset_waitq, uint *var, uint condition)
355 {
356 	int timeout;
357 
358 	/* Convert timeout in millsecond to jiffies */
359 	timeout = msecs_to_jiffies(WBRC_RESET_WAIT_TIMEOUT);
360 
361 	timeout = wait_event_timeout(*reset_waitq, (*var == condition), timeout);
362 
363 	return timeout;
364 }
365 
366 /* WBRC_LOCK should be held from caller */
wbrc_bt_reset_ack(struct wbrc_pvt_data * wbrc_data)367 int wbrc_bt_reset_ack(struct wbrc_pvt_data *wbrc_data)
368 {
369 	pr_info("%s\n", __func__);
370 	wbrc_data->bt_reset_ack = TRUE;
371 	smp_wmb();
372 	wake_up(&wbrc_data->bt_reset_waitq);
373 	return 0;
374 }
375 
wbrc_wl2bt_reset(void)376 int wbrc_wl2bt_reset(void)
377 {
378 	int ret = 0;
379 	struct wbrc_pvt_data *wbrc_data = g_wbrc_data;
380 
381 	pr_info("%s\n", __func__);
382 
383 	WBRC_LOCK(wbrc_data);
384 	if (!wbrc_data->bt_dev_opened) {
385 		pr_info("%s: no BT\n", __func__);
386 		WBRC_UNLOCK(wbrc_data);
387 		return ret;
388 	}
389 
390 	wbrc_data->bt_reset_ack = FALSE;
391 
392 	wbrc_signal_bt_reset(wbrc_data);
393 
394 	WBRC_UNLOCK(wbrc_data);
395 	/* Wait till BT reset is done */
396 	wbrc_reset_wait_on_condition(&wbrc_data->bt_reset_waitq,
397 		&wbrc_data->bt_reset_ack, TRUE);
398 	if (wbrc_data->bt_reset_ack == FALSE) {
399 		pr_err("%s: BT reset timeout\n", __func__);
400 		ret = -1;
401 	}
402 	return ret;
403 }
404 EXPORT_SYMBOL(wbrc_wl2bt_reset);
405 
wbrc_signal_wlan_reset(struct wbrc_pvt_data * wbrc_data)406 int wbrc_signal_wlan_reset(struct wbrc_pvt_data *wbrc_data)
407 {
408 	/* TODO call dhd reset, right now just send ack from here */
409 	wbrc_wl_reset_ack(wbrc_data);
410 	return 0;
411 }
412 
413 /* WBRC_LOCK should be held from caller, this will be called from DHD */
wbrc_wl_reset_ack(struct wbrc_pvt_data * wbrc_data)414 int wbrc_wl_reset_ack(struct wbrc_pvt_data *wbrc_data)
415 {
416 	pr_info("%s\n", __func__);
417 	wbrc_data->wlan_reset_ack = TRUE;
418 	smp_wmb();
419 	wake_up(&wbrc_data->wlan_reset_waitq);
420 	return 0;
421 }
422 EXPORT_SYMBOL(wbrc_wl_reset_ack);
423 
wbrc_bt2wl_reset(void)424 int wbrc_bt2wl_reset(void)
425 {
426 	int ret = 0;
427 	struct wbrc_pvt_data *wbrc_data = g_wbrc_data;
428 
429 	pr_info("%s\n", __func__);
430 
431 	WBRC_LOCK(wbrc_data);
432 	wbrc_data->wlan_reset_ack = FALSE;
433 	wbrc_signal_wlan_reset(wbrc_data);
434 	/* Wait till WLAN reset is done */
435 	wbrc_reset_wait_on_condition(&wbrc_data->wlan_reset_waitq,
436 		&wbrc_data->wlan_reset_ack, TRUE);
437 	if (wbrc_data->wlan_reset_ack == FALSE) {
438 		pr_err("%s: WLAN reset timeout\n", __func__);
439 		ret = -1;
440 	}
441 	WBRC_UNLOCK(wbrc_data);
442 	return ret;
443 }
444 EXPORT_SYMBOL(wbrc_bt2wl_reset);
445