Update for docs
[o-du/phy.git] / wls_lib / wls_drv.c
1 /******************************************************************************
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
53 typedef 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
63 char wls_driver_name[] = "wls";
64 char wls_driver_version[10];
65 char wls_dev_device_name[10];
66
67 static long wls_ioctl(struct file * filp, unsigned int cmd, unsigned long arg);
68 static int  wls_open(struct inode * inode, struct file * filp);
69 static int  wls_release(struct inode * inode, struct file * filp);
70 static int  wls_mmap(struct file * filp, struct vm_area_struct * vma);
71 static int  wls_wait(wls_sema_priv_t *priv, unsigned long arg);
72 static int  wls_wake_up_user_thread(char *buf, wls_sema_priv_t *semap);
73
74 static 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
83 static struct wls_dev_t*  wls_dev[WLS_MAX_CLIENTS];
84 static wls_drv_ctx_t    wls_drv_ctx[WLS_MAX_CLIENTS];
85
86 static struct class * wls_class;
87
88 /**********************************************************************
89 *                      Module Parameters                              *
90 **********************************************************************/
91 int     wlsMaxClients               = 1;
92
93
94 /**********************************************************************/
95 module_param(wlsMaxClients,             int, S_IRUSR);
96
97 /**********************************************************************/
98
99 static 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
107 int 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
129 void 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
143 static 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
156 static 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
225 static 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
264 static unsigned wls_is_us_opened(wls_open_req_t *param)
265 {
266     // TODO: add check
267
268         return 0;
269 }
270
271 wls_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);
338 err1:
339     dma_free_coherent(wls_loc->device, param->size, pUsCtx, param->ctx_pa);
340 err0:
341     return NULL;
342 }
343
344
345 int 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
396 static int wls_process_wait(wls_us_ctx_t* pUsCtx)
397 {
398     int n = WLS_GetNumItemsInTheQueue(&pUsCtx->get_queue);
399
400     return n;
401 }
402
403 static 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
449 static 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
674 static 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
697 static 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
822 static 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
850 MODULE_DESCRIPTION("Wirelsess Sybsytem Communication interface");
851 MODULE_AUTHOR("Intel Corporation");
852 MODULE_LICENSE("GPL v2");
853 MODULE_VERSION("WLS_DRV_VERSION_FORMAT");
854
855 module_init(wls_init);
856 module_exit(wls_exit);