blob: 8b7543c82a8145fd7c1e810fb104626b823d07e4 [file] [log] [blame]
Luis Farias9d66fca2020-05-28 19:01:58 -07001/******************************************************************************
2*
3* Copyright (c) 2019 Intel.
4*
5* Licensed under the Apache License, Version 2.0 (the "License");
6* you may not use this file except in compliance with the License.
7* You may obtain a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS,
13* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14* See the License for the specific language governing permissions and
15* limitations under the License.
16*
17*******************************************************************************/
18
19#include <linux/kernel.h>
20#include <linux/sched.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/interrupt.h>
25#include <linux/dma-mapping.h>
26#include <linux/kthread.h>
27#include <linux/fs.h>
28#include <linux/wait.h>
29#include <asm/uaccess.h>
30
31#include "wls.h"
32#include "wls_drv.h"
33#include "wls_debug.h"
34
35#if defined(_MLOG_TRACE_)
36#include "mlog.h"
37#endif
38
39#define WLS_VERSION_X 0
40#define WLS_VERSION_Y 0
41#define WLS_VERSION_Z 3
42#define WLS_VERSION_RESERVED 0
43#define WLS_DRV_VERSION ((WLS_VERSION_X << 24) | (WLS_VERSION_Y << 16) | (WLS_VERSION_Z << 8) | WLS_VERSION_RESERVED)
44
45#define WLS_DRV_VERSION_FORMAT "%d.%d.%d"
46#define WLS_DEV_DEVICE_FORMAT "wls%d"
47
48
49#define WLS_SEMA_COUNT 32
50#define WLS_MAX_CLIENTS 8
51
52
53typedef struct wls_us_priv_s
54{
55 wls_sema_priv_t sema;
56
57 U8 NeedToWakeUp;
58 U8 isWait;
59
60 U32 pid;
61} wls_us_priv_t;
62
63char wls_driver_name[] = "wls";
64char wls_driver_version[10];
65char wls_dev_device_name[10];
66
67static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg);
68static int wls_open(struct inode * inode, struct file * filp);
69static int wls_release(struct inode * inode, struct file * filp);
70static int wls_mmap(struct file * filp, struct vm_area_struct * vma);
71static int wls_wait(wls_sema_priv_t *priv, unsigned long arg);
72static int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap);
73
74static struct file_operations wls_fops = {
75 .owner = THIS_MODULE,
76 .open = wls_open,
77 .release = wls_release,
78 .unlocked_ioctl = wls_ioctl,
79 .compat_ioctl = wls_ioctl,
80 .mmap = wls_mmap,
81};
82
83static struct wls_dev_t* wls_dev[WLS_MAX_CLIENTS];
84static wls_drv_ctx_t wls_drv_ctx[WLS_MAX_CLIENTS];
85
86static struct class * wls_class;
87
88/**********************************************************************
89* Module Parameters *
90**********************************************************************/
91int wlsMaxClients = 1;
92
93
94/**********************************************************************/
95module_param(wlsMaxClients, int, S_IRUSR);
96
97/**********************************************************************/
98
99static wls_drv_ctx_t * wls_get_ctx(unsigned int id)
100{
101 if(id < WLS_MAX_CLIENTS)
102 return &wls_drv_ctx[id];
103 else
104 return NULL;
105}
106
107int wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap)
108{
109 if (likely(atomic_read(&semap->is_irq) < FIFO_LEN)) {
110 unsigned int put = semap->drv_block_put + 1;
111 if (put >= FIFO_LEN)
112 put = 0;
113 //copy data from user
114 memcpy(&semap->drv_block[put], buf, sizeof(wls_wait_req_t));
115
116 semap->drv_block_put = put;
117 atomic_inc(&semap->is_irq);
118#ifdef DEBUG
119 printk(KERN_INFO "[wls]:PUT: put=%d get=%d T=%lu is_irq=%d\n",
120 semap->drv_block_put, semap->drv_block_get,
121 semap->drv_block[put].start_time , atomic_read(&semap->is_irq));
122#endif /* DEBUG */
123 wake_up_interruptible(&semap->queue);
124 }
125
126 return 0;
127}
128
129void wls_show_data(void* ptr, unsigned int size)
130{
131 unsigned char *d = ptr;
132 int i;
133
134 for(i = 0; i < size; i++)
135 {
136 if ( !(i & 0xf) )
137 printk("\n");
138 printk("%02x ", d[i]);
139 }
140 printk("\n");
141}
142
143static int wls_open(struct inode * inode, struct file * filp)
144{
145 if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
146 filp->private_data = (void *)wls_dev[MINOR(inode->i_rdev)];
147 WLS_DEBUG("wls_open [%d] priv: 0x%p",MINOR(inode->i_rdev), filp->private_data);
148 WLS_DEBUG("wls_open PID [%d] ", current->pid);
149 } else {
150 WLS_ERROR("wls_open PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
151 }
152
153 return 0;
154}
155
156static int wls_release(struct inode * inode, struct file * filp)
157{
158 struct wls_dev_t* wls_loc = NULL;
159 wls_us_ctx_t* pUsCtx = NULL;
160 wls_us_priv_t* pUs_priv = NULL;
161 wls_drv_ctx_t* pDrv_ctx = NULL;
162 int i = 0;
163
164 WLS_DEBUG("priv: 0x%p", filp->private_data);
165 WLS_DEBUG("wls_release PID [%d] ",current->pid);
166
167 if((MINOR(inode->i_rdev ) >= 0) && (MINOR(inode->i_rdev) < wlsMaxClients) && (MINOR(inode->i_rdev ) < WLS_MAX_CLIENTS)){
168 if (filp->private_data != NULL) {
169 wls_loc = (struct wls_dev_t*)filp->private_data;
170 if((void *)wls_dev[MINOR(inode->i_rdev)] == (void *)wls_loc){
171 pDrv_ctx = (wls_drv_ctx_t*)wls_loc->pWlsDrvCtx;
172 if(pDrv_ctx){
173 for(i = 0; i < 2; i++ ){
174 pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
175 if(pUsCtx){
176 wls_us_ctx_t* dst = (wls_us_ctx_t*)pUsCtx->dst_kernel_va;
177 wls_wait_req_t drv_block;
178 if(dst){
179 wls_us_priv_t* pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
180 if(pDstPriv){
181 drv_block.start_time = wls_rdtsc();
182 pDstPriv->NeedToWakeUp = 1;
183 wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
184 }
185 }
186 //un-link ctx
187 pDrv_ctx->p_wls_us_ctx[i]->dst_kernel_va = (uint64_t)0;
188 pDrv_ctx->p_wls_us_ctx[i]->dst_user_va = (uint64_t)0;
189 pDrv_ctx->p_wls_us_ctx[i]->dst_pa = (uint64_t)0;
190 }
191 }
192
193 for(i = 0; i < 2; i++ ){
194 pUsCtx = (wls_us_ctx_t*)pDrv_ctx->p_wls_us_ctx[i];
195
196 if(pUsCtx){
197 pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
198 if(pUs_priv){
199 if(pUs_priv->pid == current->pid){
200 if (pUs_priv->isWait == 0){
201 pUsCtx->wls_us_private = NULL;
202 kfree(pUs_priv);
203 pDrv_ctx->p_wls_us_ctx[i] = NULL;
204 dma_free_coherent(wls_loc->device, sizeof(wls_us_ctx_t),(void*)pUsCtx, (long)pDrv_ctx->p_wls_us_pa_ctx[i]);
205 pDrv_ctx->p_wls_us_pa_ctx[i] = NULL;
206 pDrv_ctx->nWlsClients--;
207 } else {
208 WLS_PRINT("Wait is in process\n");
209 }
210 }
211 }
212 }
213 }
214 }
215 }
216 filp->private_data = NULL;
217 }
218 } else {
219 WLS_ERROR("wls_release PID [%d] incorrect inode->i_rdev %d", current->pid, MINOR(inode->i_rdev));
220 }
221
222 return 0;
223}
224
225static int wls_wait(wls_sema_priv_t *priv, unsigned long arg)
226{
227 char __user *buf = (char __user *)arg;
228
229 if (!likely(atomic_read(&priv->is_irq))) {
230 if (unlikely(wait_event_interruptible(priv->queue, atomic_read(&priv->is_irq)))) {
231 return -ERESTARTSYS;
232 }
233 }
234
235 atomic_dec(&priv->is_irq);
236
237 if (priv->drv_block_put != priv->drv_block_get) {
238 unsigned int get = priv->drv_block_get + 1;
239
240 if (get >= FIFO_LEN)
241 get = 0;
242
243 if (copy_to_user(buf, &priv->drv_block[get], sizeof(wls_wait_req_t))) {
244 return -EFAULT;
245 }
246
247 priv->drv_block_get = get;
248
249#ifdef DEBUG
250 printk(KERN_INFO "[wls]:GET: put=%d get=%d T=%lu is_irq=%d\n",
251 priv->drv_block_put, priv->drv_block_get,
252 priv->drv_block[get].start_time, atomic_read(&priv->is_irq));
253#endif /* DEBUG */
254
255 } else {
256#ifdef DEBUG
257 printk(KERN_ERR "[wls]: wrong computation of queueing\n");
258#endif /* DEBUG */
259 }
260
261 return 0;
262}
263
264static unsigned wls_is_us_opened(wls_open_req_t *param)
265{
266 // TODO: add check
267
268 return 0;
269}
270
271wls_us_ctx_t *wls_create_us_ctx(wls_open_req_t *param, struct wls_dev_t * wls_loc)
272{
273 wls_us_ctx_t* pUsCtx = NULL;
274 wls_drv_ctx_t* pDrv_ctx = wls_loc->pWlsDrvCtx;
275
276 // check if instance already registered
277 if(wls_is_us_opened(param))
278 goto err0;
279
280 // allocate memory for shared portion
281 pUsCtx = (wls_us_ctx_t*)dma_alloc_coherent(NULL, param->size, (dma_addr_t *)&param->ctx_pa, GFP_KERNEL);
282 WLS_DEBUG("wls_create_us_ctx: pUsCtx 0x%016lx\n", (unsigned long)pUsCtx);
283 if (pUsCtx){
284 // allocate memory for private
285 wls_us_priv_t *pUs_priv = kmalloc(sizeof(wls_us_priv_t), GFP_KERNEL);
286
287 if(pUs_priv == NULL)
288 goto err1;
289 // init shared
290 memset (pUsCtx, 0, sizeof(wls_us_ctx_t));
291
292 SFL_DefQueue(&pUsCtx->ul_free_block_pq, pUsCtx->ul_free_block_storage, UL_FREE_BLOCK_QUEUE_SIZE * sizeof(void*));
293 WLS_PRINT("ul free: off %lx\n",((U64) &pUsCtx->ul_free_block_pq -(U64)pUsCtx));
294
295 WLS_MsgDefineQueue(&pUsCtx->get_queue, pUsCtx->get_storage, WLS_GET_QUEUE_N_ELEMENTS, 0);
296 WLS_PRINT("get_queue: off %lx\n",((U64) &pUsCtx->get_queue -(U64)pUsCtx));
297
298 WLS_MsgDefineQueue(&pUsCtx->put_queue, pUsCtx->put_storage, WLS_PUT_QUEUE_N_ELEMENTS, 0);
299 WLS_PRINT("put_queue: off %lx\n",((U64) &pUsCtx->put_queue -(U64)pUsCtx));
300
301 // init private
302 memset (pUs_priv, 0, sizeof(wls_us_priv_t));
303 init_waitqueue_head(&pUs_priv->sema.queue);
304 atomic_set(&pUs_priv->sema.is_irq, 0);
305
306 pUs_priv->pid = current->pid;
307
308 pUsCtx->wls_us_private = pUs_priv;
309 WLS_DEBUG("wls_create_us_ctx: pUsCtx->wls_us_private 0x%016lx\n", (unsigned long)pUsCtx->wls_us_private);
310 } else
311 goto err0;
312
313 pDrv_ctx->p_wls_us_ctx[pDrv_ctx->nWlsClients] = pUsCtx;
314 pDrv_ctx->p_wls_us_pa_ctx[pDrv_ctx->nWlsClients++] = (wls_us_ctx_t*)param->ctx_pa;
315
316 if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
317 {
318 //link ctx
319 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
320 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
321
322 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
323 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
324
325 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[1];
326 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[1];
327 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)pDrv_ctx->p_wls_us_ctx[0];
328 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t) pDrv_ctx->p_wls_us_pa_ctx[0];
329
330 WLS_DEBUG("link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
331 (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
332 }
333
334 return pUsCtx;
335
336//err2:
337 kfree(pUsCtx->wls_us_private);
338err1:
339 dma_free_coherent(wls_loc->device, param->size, pUsCtx, param->ctx_pa);
340err0:
341 return NULL;
342}
343
344
345int wls_destroy_us_ctx(wls_close_req_t *param, struct wls_dev_t * wls_prv)
346{
347 wls_us_ctx_t* pUsCtx = NULL;
348 wls_us_priv_t* pUs_priv = NULL;
349
350 wls_drv_ctx_t* pDrv_ctx = wls_prv->pWlsDrvCtx;
351
352 if(pDrv_ctx->p_wls_us_ctx[0] && pDrv_ctx->p_wls_us_ctx[1])
353 {
354 //link ctx
355 pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va = (uint64_t)0;
356 pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va = (uint64_t)0;
357 pDrv_ctx->p_wls_us_ctx[0]->dst_user_va = (uint64_t)0;
358 pDrv_ctx->p_wls_us_ctx[1]->dst_user_va = (uint64_t)0;
359 pDrv_ctx->p_wls_us_ctx[0]->dst_pa = (uint64_t)0;
360 pDrv_ctx->p_wls_us_ctx[1]->dst_pa = (uint64_t)0;
361
362 WLS_DEBUG("un-link: 0 <-> 1: 0: 0x%016lx 1: 0x%016lx\n", (long unsigned int)pDrv_ctx->p_wls_us_ctx[0]->dst_kernel_va,
363 (long unsigned int)pDrv_ctx->p_wls_us_ctx[1]->dst_kernel_va);
364 }
365
366 pUsCtx = (wls_us_ctx_t*)param->ctx;
367
368 if(pUsCtx){
369 pUs_priv = (wls_us_priv_t*)pUsCtx->wls_us_private;
370 if(pUs_priv){
371 if (pUs_priv->isWait == 0){
372
373 pUsCtx->wls_us_private = NULL;
374 kfree(pUs_priv);
375 if(param->ctx_pa){
376 if( pDrv_ctx->p_wls_us_ctx[0] == pUsCtx){
377 pDrv_ctx->p_wls_us_ctx[0] = NULL;
378 pDrv_ctx->p_wls_us_pa_ctx[0] = NULL;
379 } else {
380 pDrv_ctx->p_wls_us_ctx[1] = NULL;
381 pDrv_ctx->p_wls_us_pa_ctx[1] = NULL;
382 }
383 pDrv_ctx->nWlsClients--;
384 dma_free_coherent(wls_prv->device, param->size, pUsCtx, param->ctx_pa);
385 }else{
386 WLS_ERROR("param->ctx_pa is NULL\n");
387 }
388 } else
389 WLS_PRINT("Wait is in process\n");
390 }
391 }
392
393 return 0;
394}
395
396static int wls_process_wait(wls_us_ctx_t* pUsCtx)
397{
398 int n = WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
399
400 return n;
401}
402
403static int wls_process_put(wls_us_ctx_t *src, wls_us_ctx_t *dst)
404{
405 int ret = 0;
406 WLS_MSG_HANDLE hMsg;
407 int n = 0;
408
409 wls_us_priv_t* pDstPriv = NULL;
410 wls_wait_req_t drv_block;
411
412 WLS_DEBUG("offset get_queue %lx\n",(U64)&src->get_queue - (U64)src);
413
414 n = WLS_GetNumItemsInTheQueue(&src->put_queue);
415
416 while(n--)
417 {
418 if (WLS_MsgDequeue(&src->put_queue, &hMsg, NULL, (void*)src))
419 {
420 WLS_DEBUG("WLS_Get %lx %d type %d\n",(U64) hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID);
421 if(WLS_MsgEnqueue(&dst->get_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)dst) == FALSE){ // try to send
422 if(WLS_MsgEnqueue(&src->put_queue, hMsg.pIaPaMsg, hMsg.MsgSize, hMsg.TypeID, hMsg.flags, NULL, (void*)src) == FALSE){ // return back
423 WLS_ERROR("wls_process_put: Cannot return block to back to queue \n");
424 ret = -1;
425 }
426 break;
427 }
428 }
429 else{
430 ret = -1;
431 break;
432 }
433
434 }
435
436 if(dst->wls_us_private){
437 pDstPriv = (wls_us_priv_t*)dst->wls_us_private;
438
439 drv_block.start_time = wls_rdtsc();
440 pDstPriv->NeedToWakeUp = 1;
441 wls_wake_up_user_thread((char *)&drv_block, &pDstPriv->sema);
442 }
443 else
444 ret = -1;
445
446 return ret;
447}
448
449static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
450{
451 struct wls_dev_t * wls_prv = (struct wls_dev_t *)filp->private_data;
452 void __user * to = (void __user *)arg;
453 const void __user * from = (const void __user *)arg;
454 long ret = 0;
455
456 WLS_DEBUG("wls_ioctl PID [%d] ", current->pid);
457
458 if (_IOC_TYPE(cmd) != WLS_IOC_MAGIC) {
459 return -ENOTTY;
460 }
461
462 if (_IOC_NR(cmd) >= WLS_IOC_COUNT) {
463 return -ENOTTY;
464 }
465
466 switch (cmd) {
467 case WLS_IOC_OPEN: {
468 wls_open_req_t param;
469
470 WLS_DEBUG("WLS_IOC_OPEN wls_us_ctx_t %ld\n", sizeof(wls_us_ctx_t));
471 ret = copy_from_user((void *)&param, from, sizeof(param));
472 if (ret != 0) {
473 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
474 (unsigned long)ret, (unsigned long)from);
475 break;
476 }
477
478 if (sizeof(wls_drv_ctx_t) >= param.size){
479 WLS_ERROR("incorrect size %lu > %u\n", sizeof(wls_drv_ctx_t), param.size);
480 ret = -1;
481 break;
482 }
483
484 param.ctx = (uint64_t)wls_create_us_ctx(&param, wls_prv);
485 if (param.ctx == 0) {
486 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
487 (unsigned long)ret, (unsigned long)from);
488 break;
489 }
490
491 WLS_DEBUG("WLS_IOC_OPEN: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
492
493 ret = copy_to_user(to, (const void *)&param, sizeof(wls_open_req_t));
494 if (ret != 0) {
495 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
496 (unsigned long)ret, (unsigned long)from);
497 break;
498 }
499 } break;
500 case WLS_IOC_CLOSE: {
501 wls_close_req_t param;
502
503 ret = copy_from_user((void *)&param, from, sizeof(param));
504 if (ret != 0) {
505 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
506 (unsigned long)ret, (unsigned long)from);
507 break;
508 }
509 WLS_DEBUG("WLS_IOC_CLOSE: kva %lx pa %lx sz [%d]\n", (long unsigned int)param.ctx, (long unsigned int)param.ctx_pa, param.size);
510
511 ret = wls_destroy_us_ctx(&param, wls_prv);
512
513 if (ret != 0) {
514 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
515 (unsigned long)ret, (unsigned long)from);
516 break;
517 }
518 } break;
519 case WLS_IOC_PUT: {
520 wls_put_req_t param;
521 wls_us_ctx_t* pUsCtx = NULL;
522
523#if defined(_MLOG_TRACE_)
524 unsigned long t = MLOG_GETTICK();
525#endif
526 ret = copy_from_user((void *)&param, from, sizeof(param));
527 if (ret != 0) {
528 WLS_ERROR("could not copy %lu bytes from user 0x%08lx",
529 (unsigned long)ret, (unsigned long)from);
530 break;
531 }
532
533 pUsCtx = (wls_us_ctx_t*)param.wls_us_kernel_va;
534 if (pUsCtx == NULL) {
535 WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
536 break;
537 }
538
539 if(pUsCtx->dst_kernel_va)
540 ret = wls_process_put(pUsCtx, (wls_us_ctx_t*)pUsCtx->dst_kernel_va);
541
542 if (ret != 0) {
543 WLS_ERROR("Transaction failed %ld\n", (unsigned long)ret);
544 break;
545 }
546
547 /* clean up for next time */
548#if defined(_MLOG_TRACE_)
549 MLogTask(PID_WLS_DRV_IOC_PUT, t, MLOG_GETTICK());
550#endif
551 } break;
552 case WLS_IOC_EVENT: {
553 wls_event_req_t param;
554
555 ret = copy_from_user((void *)&param, from, sizeof(param));
556
557 if (ret != 0) {
558 WLS_ERROR("Event %ld failed %ld\n", (unsigned long)param.event_to_wls,
559 (unsigned long)ret);
560 break;
561 }
562 }break;
563 case WLS_IOC_WAIT: {
564 wls_wait_req_t param;
565 wls_us_ctx_t* pUsCtx = NULL;
566 wls_us_priv_t* pUsPriv = NULL;
567#if defined(_MLOG_TRACE_)
568 unsigned long t = MLOG_GETTICK();
569 MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_ENTRY, t, 1250+t);
570#endif
571 ret = copy_from_user((void *)&param, from, sizeof(param));
572 if (ret != 0) {
573 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
574 break;
575 }
576
577 WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
578 pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
579 if(pUsCtx == NULL) {
580 ret = -EINVAL;
581 WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
582 break;
583 }
584
585 pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
586 WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
587
588 if(pUsPriv == NULL) {
589 ret = -EINVAL;
590 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
591 break;
592 }
593 pUsPriv->isWait = 1;
594 wls_wait(&pUsPriv->sema, (unsigned long)from);
595 pUsPriv->isWait = 0;
596 memset(&param, 0, sizeof(wls_wait_req_t));
597 param.nMsg = wls_process_wait(pUsCtx);
598
599#if defined(_MLOG_TRACE_)
600 t = MLOG_GETTICK();
601#endif
602 ret = copy_to_user(to, (const void *)&param, sizeof(wls_wait_req_t));
603 if (ret != 0) {
604 WLS_ERROR("could not copy %lu bytes to user 0x%08lx",
605 (unsigned long)ret, (unsigned long)from);
606 break;
607 }
608#if defined(_MLOG_TRACE_)
609 MLogTask(PID_WLS_DRV_IOC_WAIT_WAKE_UP, t, MLOG_GETTICK());
610#endif
611 } break;
612 case WLS_IOC_WAKE_UP: {
613 wls_wait_req_t param;
614 wls_us_ctx_t* pUsCtx = NULL;
615 wls_us_priv_t* pUsPriv = NULL;
616 wls_wait_req_t drv_block;
617
618 ret = copy_from_user((void *)&param, from, sizeof(param));
619 if (ret != 0) {
620 WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
621 (unsigned long)ret);
622 break;
623 }
624
625 WLS_DEBUG("Wait pUsCtx 0x%016lx\n", (unsigned long)param.wls_us_kernel_va);
626 pUsCtx = (wls_us_ctx_t*) param.wls_us_kernel_va;
627 if(pUsCtx == NULL) {
628 ret = -EINVAL;
629 WLS_ERROR("Wait failed on User context %ld\n", (unsigned long)ret);
630 break;
631 }
632
633 pUsPriv = (wls_us_priv_t*) pUsCtx->wls_us_private;
634 WLS_DEBUG("Wait pUsPriv 0x%016lx\n", (unsigned long)pUsPriv);
635
636 if(pUsPriv == NULL) {
637 ret = -EINVAL;
638 WLS_ERROR("Wait failed %ld\n", (unsigned long)ret);
639 break;
640 }
641
642 drv_block.start_time = wls_rdtsc();
643 wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
644 } break;
645 case WLS_IOC_CONNECT: {
646 wls_connect_req_t param;
647 wls_us_priv_t* pUsPriv = NULL;
648 wls_wait_req_t drv_block;
649
650 ret = copy_from_user((void *)&param, from, sizeof(param));
651 if (ret != 0) {
652 WLS_ERROR("WLS_IOC_WAKE_UP failed %ld\n",
653 (unsigned long)ret);
654 break;
655 }
656
657 pUsPriv = (wls_us_priv_t*)param.wls_us_kernel_va;
658 drv_block.start_time = wls_rdtsc();
659 wls_wake_up_user_thread((char *)&drv_block, &pUsPriv->sema);
660 } break;
661 default:{
662 WLS_ERROR("unknown ioctl cmd: '0x%08x'", cmd);
663 BUG();
664 } break;
665 }
666
667 if (ret != 0) {
668 WLS_ERROR("cmd_%x failed: %ld", cmd, ret);
669 }
670
671 return ret;
672}
673
674static int wls_mmap(struct file * filp, struct vm_area_struct * vma)
675{
676 struct wls_dev_t * wls = (struct wls_dev_t *)filp->private_data;
677
678 WLS_DEBUG("priv: 0x%p", filp->private_data);
679 WLS_DEBUG("WLS_mmap : mmap function called \n");
680 WLS_DEBUG("vma->start =%lx\n",vma->vm_start);
681 WLS_DEBUG("vma->end =%lx\n",vma->vm_end);
682
683 // non cached
684// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
685
686 WLS_DEBUG("vma->pgoff =%lx\n",vma->vm_pgoff);
687
688 if (wls == NULL) {
689 WLS_ERROR("WLS is NULL");
690 return -EIO;
691 }
692
693 return remap_pfn_range(vma,vma->vm_start,vma->vm_pgoff,vma->vm_end-vma->vm_start,\
694 vma->vm_page_prot);
695}
696
697static int __init wls_init(void)
698{
699 struct wls_dev_t* wls_dev_loc = NULL;
700 int res = 0;
701 dev_t dev_no = 0;
702 int minor_no = 0;
703 int dev_cnt = 0;
704
705 memset(&wls_dev[0], 0, sizeof(struct wls_dev_t*) * WLS_MAX_CLIENTS);
706
707 snprintf(wls_driver_version, 10, WLS_DRV_VERSION_FORMAT, WLS_VERSION_X, WLS_VERSION_Y, WLS_VERSION_Z);
708
709 WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s\n", wls_driver_version);
710 WLS_PRINT("Copyright(c) 2014 Intel Corporation.\n");
711 //WLS_PRINT("Build: Date: %s Time: %s\n", __DATE__, __TIME__);
712
713 if ((wlsMaxClients > WLS_MAX_CLIENTS) || (wlsMaxClients < 1))
714 {
715 WLS_ERROR("Invalid wlsMaxClients %d\n", wlsMaxClients);
716 wlsMaxClients = 1;
717 }
718 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
719 wls_dev_loc = (struct wls_dev_t *)kzalloc(sizeof(struct wls_dev_t), GFP_KERNEL);
720 WLS_DEBUG("wls_dev_loc %d %p", dev_cnt, wls_dev_loc);
721
722 if (wls_dev_loc == NULL) {
723 WLS_ERROR("no free memory (wanted %ld bytes)", sizeof(struct wls_dev_t));
724 res = -ENOMEM;
725 goto err0;
726 }
727 wls_dev[dev_cnt] = wls_dev_loc;
728 WLS_DEBUG("wls_init [%d]: 0x%p",dev_cnt, wls_dev[dev_cnt]);
729 }
730
731 res = alloc_chrdev_region(&dev_no, minor_no, wlsMaxClients, MODNAME);
732 if (res < 0) {
733 WLS_ERROR("failed alloc char dev region: %d", res);
734 goto err0;
735 }
736
737 wls_class = class_create(THIS_MODULE, wls_driver_name);
738
739 wls_dev_loc = wls_dev[0];
740 wls_dev_loc->dev_no = dev_no;
741
742 cdev_init(&wls_dev_loc->cdev, &wls_fops);
743 wls_dev_loc->cdev.owner = THIS_MODULE;
744 wls_dev_loc->cdev.ops = &wls_fops;
745 res = cdev_add(&wls_dev_loc->cdev, dev_no, wlsMaxClients);
746
747 if (res) {
748 WLS_ERROR("failed add char dev: %d", res);
749 res = -1;
750 goto err2;
751 }
752
753 if (IS_ERR((void *)wls_class)) {
754 WLS_ERROR("failed create class");
755 res = -EIO;
756 goto err1;
757 }
758
759 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
760 wls_dev_loc = wls_dev[dev_cnt];
761 if (wls_dev_loc == NULL ) {
762 WLS_ERROR("wls_dev_loc is NULL");
763 goto err2;
764 }
765
766 if(wlsMaxClients > 1){
767 snprintf(wls_dev_device_name, 10, WLS_DEV_DEVICE_FORMAT, dev_cnt);
768 } else {
769 snprintf(wls_dev_device_name, 10, "%s", MODNAME);
770 }
771
772 wls_dev_loc->dev_no = MKDEV(MAJOR(dev_no), dev_cnt);
773 wls_dev_loc->device = device_create(wls_class, NULL, wls_dev_loc->dev_no, NULL, wls_dev_device_name);
774
775 if (IS_ERR((void *)wls_dev_loc->device)) {
776 WLS_ERROR("failed create / device");
777 res = -2;
778 goto err2;
779 }
780
781 dev_info(wls_dev_loc->device, "Device: %s\n", wls_dev_device_name);
782 mutex_init(&wls_dev_loc->lock);
783
784 wls_dev_loc->pWlsDrvCtx = wls_get_ctx(dev_cnt);
785
786 if (wls_dev_loc->pWlsDrvCtx == NULL) {
787 WLS_ERROR("failed wls_get_ctx(%d)", dev_cnt);
788 res = -3;
789 goto err2;
790 }
791
792 //return res;
793// dev_no++;
794 continue;
795 }
796 WLS_PRINT("init %d /dev/wlsX communication devices [0-%d]\n", dev_cnt, dev_cnt-1);
797 return res;
798
799 err2:
800 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
801 wls_dev_loc = wls_dev[dev_cnt];
802 if(wls_dev_loc){
803 device_destroy(wls_class, wls_dev_loc->dev_no);
804 cdev_del(&wls_dev_loc->cdev);
805 }
806 }
807 class_destroy(wls_class);
808 err1:
809 unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
810 err0:
811 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
812 if(wls_dev[dev_cnt]){
813 kfree(wls_dev[dev_cnt]);
814 wls_dev[dev_cnt] = NULL;
815 }
816 }
817
818 WLS_ERROR("init failed");
819 return -1;
820}
821
822static void __exit wls_exit(void)
823{
824 struct wls_dev_t* wls_dev_loc = NULL;
825 int dev_cnt = 0;
826
827 if (wls_dev[0]) {
828 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
829 wls_dev_loc = wls_dev[dev_cnt];
830 device_destroy(wls_class, wls_dev_loc->dev_no);
831 }
832 wls_dev_loc = wls_dev[0];
833
834 cdev_del(&wls_dev_loc->cdev);
835 class_destroy(wls_class);
836
837 unregister_chrdev_region(wls_dev[0]->dev_no, wlsMaxClients);
838
839 for (dev_cnt = 0; dev_cnt < wlsMaxClients; dev_cnt++){
840 if(wls_dev[dev_cnt]){
841 kfree(wls_dev[dev_cnt]);
842 wls_dev[dev_cnt] = NULL;
843 }
844 }
845 }
846
847 WLS_PRINT("Intel(R) Wireless Subsystem Communication interface - %s was removed\n", wls_driver_version);
848}
849
850MODULE_DESCRIPTION("Wirelsess Sybsytem Communication interface");
851MODULE_AUTHOR("Intel Corporation");
852MODULE_LICENSE("GPL v2");
853MODULE_VERSION("WLS_DRV_VERSION_FORMAT");
854
855module_init(wls_init);
856module_exit(wls_exit);