Staging: sep: Put all the ARM bits together
[linux-2.6-block.git] / drivers / staging / sep / sep_main_mod.c
CommitLineData
cd1bb431
MA
1/*
2 *
3 * sep_main_mod.c - Security Processor Driver main group of functions
4 *
5 * Copyright(c) 2009 Intel Corporation. All rights reserved.
6 * Copyright(c) 2009 Discretix. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * CONTACTS:
23 *
24 * Mark Allyn mark.a.allyn@intel.com
25 *
26 * CHANGES:
27 *
28 * 2009.06.26 Initial publish
29 *
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/fs.h>
35#include <linux/cdev.h>
36#include <linux/kdev_t.h>
37#include <linux/mutex.h>
38#include <linux/mm.h>
39#include <linux/poll.h>
40#include <linux/wait.h>
41#include <asm/ioctl.h>
42#include <linux/ioport.h>
43#include <asm/io.h>
44#include <linux/interrupt.h>
45#include <linux/pagemap.h>
46#include <asm/cacheflush.h>
47#include "sep_driver_hw_defs.h"
48#include "sep_driver_config.h"
49#include "sep_driver_api.h"
50#include "sep_driver_ext_api.h"
f5e3980f 51#include "sep_dev.h"
cd1bb431
MA
52
53/*----------------------------------------
54 DEFINES
55-----------------------------------------*/
56
57
58#define INT_MODULE_PARM(n, v) int n = v; module_param(n, int, 0)
59
60/*--------------------------------------
61 TYPEDEFS
62 -----------------------------------------*/
63
64
65
66/*--------------------------------------------
67 GLOBAL variables
68--------------------------------------------*/
69
70/* debug messages level */
71INT_MODULE_PARM(sepDebug, 0x0);
72MODULE_PARM_DESC(sepDebug, "Flag to enable SEP debug messages");
73
cd1bb431 74/* major and minor device numbers */
d19cf32f 75static dev_t g_sep_device_number;
cd1bb431
MA
76
77/* the files operations structure of the driver */
d19cf32f 78static struct file_operations g_sep_fops;
cd1bb431
MA
79
80/* cdev struct of the driver */
d19cf32f 81static struct cdev g_sep_cdev;
cd1bb431
MA
82
83/*
84 mutex for the access to the internals of the sep driver
85*/
86static DEFINE_MUTEX(sep_mutex);
87
88
89/* wait queue head (event) of the driver */
f5e3980f 90static DECLARE_WAIT_QUEUE_HEAD(g_sep_event);
cd1bb431 91
cd1bb431 92
cd1bb431
MA
93
94/*------------------------------------------------
95 PROTOTYPES
96---------------------------------------------------*/
97
98/*
99 interrupt handler function
100*/
101irqreturn_t sep_inthandler(int irq, void *dev_id);
102
103/*
104 this function registers the driver to the file system
105*/
d19cf32f 106static int sep_register_driver_to_fs(void);
cd1bb431
MA
107
108/*
109 this function unregisters driver from fs
110*/
111static void sep_unregister_driver_from_fs(void);
112
113/*
114 this function calculates the size of data that can be inserted into the lli
115 table from this array the condition is that either the table is full
116 (all etnries are entered), or there are no more entries in the lli array
117*/
d19cf32f 118static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries);
cd1bb431
MA
119/*
120 this functions builds ont lli table from the lli_array according to the
121 given size of data
122*/
d19cf32f 123static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size);
cd1bb431
MA
124
125/*
126 this function goes over the list of the print created tables and prints
127 all the data
128*/
d19cf32f 129static void sep_debug_print_lli_tables(struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size);
cd1bb431
MA
130
131
132
133/*
134 This function raises interrupt to SEPm that signals that is has a new
135 command from HOST
136*/
137static void sep_send_command_handler(void);
138
139
140/*
141 This function raises interrupt to SEP that signals that is has a
142 new reply from HOST
143*/
144static void sep_send_reply_command_handler(void);
145
146/*
147 This function handles the allocate data pool memory request
148 This function returns calculates the physical address of the allocated memory
149 and the offset of this area from the mapped address. Therefore, the FVOs in
150 user space can calculate the exact virtual address of this allocated memory
151*/
152static int sep_allocate_data_pool_memory_handler(unsigned long arg);
153
154
155/*
156 This function handles write into allocated data pool command
157*/
158static int sep_write_into_data_pool_handler(unsigned long arg);
159
160/*
161 this function handles the read from data pool command
162*/
163static int sep_read_from_data_pool_handler(unsigned long arg);
164
165/*
166 this function handles tha request for creation of the DMA table
167 for the synchronic symmetric operations (AES,DES)
168*/
169static int sep_create_sync_dma_tables_handler(unsigned long arg);
170
171/*
172 this function handles the request to create the DMA tables for flow
173*/
174static int sep_create_flow_dma_tables_handler(unsigned long arg);
175
176/*
177 This API handles the end transaction request
178*/
179static int sep_end_transaction_handler(unsigned long arg);
180
181
182/*
183 this function handles add tables to flow
184*/
185static int sep_add_flow_tables_handler(unsigned long arg);
186
187/*
188 this function add the flow add message to the specific flow
189*/
190static int sep_add_flow_tables_message_handler(unsigned long arg);
191
192/*
193 this function handles the request for SEP start
194*/
195static int sep_start_handler(void);
196
197/*
198 this function handles the request for SEP initialization
199*/
200static int sep_init_handler(unsigned long arg);
201
202/*
203 this function handles the request cache and resident reallocation
204*/
205static int sep_realloc_cache_resident_handler(unsigned long arg);
206
207
208/*
209 This api handles the setting of API mode to blocking or non-blocking
210*/
211static int sep_set_api_mode_handler(unsigned long arg);
212
213/* handler for flow done interrupt */
d19cf32f 214static void sep_flow_done_handler(struct work_struct *work);
cd1bb431
MA
215
216/*
217 This function locks all the physical pages of the kernel virtual buffer
218 and construct a basic lli array, where each entry holds the physical
219 page address and the size that application data holds in this physical pages
220*/
d19cf32f 221static int sep_lock_kernel_pages(unsigned long kernel_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr);
cd1bb431
MA
222
223/*
224 This function creates one DMA table for flow and returns its data,
225 and pointer to its info entry
226*/
d19cf32f 227static int sep_prepare_one_flow_dma_table(unsigned long virt_buff_addr, unsigned long virt_buff_size, struct sep_lli_entry_t *table_data, struct sep_lli_entry_t **info_entry_ptr, struct sep_flow_context_t *flow_data_ptr, bool isKernelVirtualAddress);
cd1bb431
MA
228
229/*
230 This function creates a list of tables for flow and returns the data for the
231 first and last tables of the list
232*/
d19cf32f
AC
233static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers,
234 unsigned long first_buff_addr, struct sep_flow_context_t *flow_data_ptr, struct sep_lli_entry_t *first_table_data_ptr, struct sep_lli_entry_t *last_table_data_ptr, bool isKernelVirtualAddress);
cd1bb431
MA
235
236/*
237 this function find a space for the new flow dma table
238*/
d19cf32f 239static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr);
cd1bb431
MA
240
241/*
242 this function goes over all the flow tables connected to the given table and
243 deallocate them
244*/
d19cf32f 245static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr);
cd1bb431
MA
246
247/*
248 This function handler the set flow id command
249*/
250static int sep_set_flow_id_handler(unsigned long arg);
251
252/*
253 This function returns pointer to the flow data structure
254 that conatins the given id
255*/
d19cf32f 256static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr);
cd1bb431
MA
257
258
259/*
260 this function returns the physical and virtual addresses of the static pool
261*/
262static int sep_get_static_pool_addr_handler(unsigned long arg);
263
264/*
265 this address gets the offset of the physical address from the start of
266 the mapped area
267*/
268static int sep_get_physical_mapped_offset_handler(unsigned long arg);
269
270
271/*
272 this function handles the request for get time
273*/
274static int sep_get_time_handler(unsigned long arg);
275
276/*
277 calculates time and sets it at the predefined address
278*/
d19cf32f 279static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr);
cd1bb431
MA
280
281/*
282 PATCH for configuring the DMA to single burst instead of multi-burst
283*/
284static void sep_configure_dma_burst(void);
285
286/*
287 This function locks all the physical pages of the
288 application virtual buffer and construct a basic lli
289 array, where each entry holds the physical page address
290 and the size that application data holds in this physical pages
291*/
d19cf32f 292static int sep_lock_user_pages(unsigned long app_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr);
cd1bb431
MA
293
294/*---------------------------------------------
295 FUNCTIONS
296-----------------------------------------------*/
297
298/*
299 this function locks SEP by locking the semaphore
300*/
301int sep_lock()
302{
d19cf32f 303 mutex_lock(&sep_mutex);
d19cf32f 304 return 0;
cd1bb431
MA
305}
306
307/*
308 this function unlocks SEP
309*/
310void sep_unlock()
311{
d19cf32f
AC
312 /* release mutex */
313 mutex_unlock(&sep_mutex);
cd1bb431
MA
314}
315
316/*
317 this function returns the address of the message shared area
318*/
d19cf32f 319void sep_map_shared_area(unsigned long *mappedAddr_ptr)
cd1bb431 320{
d19cf32f 321 *mappedAddr_ptr = sep_dev->shared_area_addr;
cd1bb431
MA
322}
323
324/*
325 this function returns the address of the message shared area
326*/
327void sep_send_msg_rdy_cmd()
328{
d19cf32f 329 sep_send_command_handler();
cd1bb431
MA
330}
331
332/* this functions frees all the resources that were allocated for the building
333of the LLI DMA tables */
334void sep_free_dma_resources()
335{
d19cf32f 336 sep_free_dma_table_data_handler();
cd1bb431
MA
337}
338
339/* poll(suspend), until reply from sep */
340void sep_driver_poll()
341{
d19cf32f 342 unsigned long retVal = 0;
cd1bb431
MA
343
344#ifdef SEP_DRIVER_POLLING_MODE
345
d19cf32f
AC
346 while (sep_dev->host_to_sep_send_counter != (retVal & 0x7FFFFFFF))
347 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
cd1bb431 348
d19cf32f 349 sep_dev->sep_to_host_reply_counter++;
cd1bb431 350#else
d19cf32f
AC
351 /* poll, until reply from sep */
352 wait_event(g_sep_event, (sep_dev->host_to_sep_send_counter == sep_dev->sep_to_host_reply_counter));
cd1bb431
MA
353
354#endif
355}
356
357/*----------------------------------------------------------------------
358 open function of the character driver - must only lock the mutex
359 must also release the memory data pool allocations
360------------------------------------------------------------------------*/
361static int sep_open(struct inode *inode_ptr, struct file *file_ptr)
362{
d19cf32f 363 int error;
cd1bb431 364
d19cf32f 365 dbg("SEP Driver:--------> open start\n");
cd1bb431 366
d19cf32f 367 error = 0;
cd1bb431 368
d19cf32f
AC
369 /* check the blocking mode */
370 if (sep_dev->block_mode_flag)
371 /* lock mutex */
372 mutex_lock(&sep_mutex);
373 else
374 error = mutex_trylock(&sep_mutex);
cd1bb431 375
d19cf32f
AC
376 /* check the error */
377 if (error) {
378 edbg("SEP Driver: down_interruptible failed\n");
cd1bb431 379
d19cf32f
AC
380 goto end_function;
381 }
cd1bb431 382
d19cf32f
AC
383 /* release data pool allocations */
384 sep_dev->data_pool_bytes_allocated = 0;
cd1bb431 385
f93e4bf9 386end_function:
d19cf32f 387 dbg("SEP Driver:<-------- open end\n");
d19cf32f 388 return error;
cd1bb431
MA
389}
390
391
392
393
394/*------------------------------------------------------------
395 release function
396-------------------------------------------------------------*/
397static int sep_release(struct inode *inode_ptr, struct file *file_ptr)
398{
d19cf32f 399 dbg("----------->SEP Driver: sep_release start\n");
cd1bb431 400
d19cf32f
AC
401#if 0 /*!SEP_DRIVER_POLLING_MODE */
402 /* close IMR */
403 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF);
cd1bb431 404
d19cf32f
AC
405 /* release IRQ line */
406 free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address);
cd1bb431
MA
407
408#endif
409
d19cf32f
AC
410 /* unlock the sep mutex */
411 mutex_unlock(&sep_mutex);
cd1bb431 412
d19cf32f 413 dbg("SEP Driver:<-------- sep_release end\n");
cd1bb431 414
d19cf32f 415 return 0;
cd1bb431
MA
416}
417
418
419
420
421/*---------------------------------------------------------------
422 map function - this functions maps the message shared area
423-----------------------------------------------------------------*/
d19cf32f 424static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
cd1bb431 425{
d19cf32f 426 unsigned long phys_addr;
cd1bb431 427
d19cf32f 428 dbg("-------->SEP Driver: mmap start\n");
cd1bb431 429
d19cf32f
AC
430 /* check that the size of the mapped range is as the size of the message
431 shared area */
432 if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
433 edbg("SEP Driver mmap requested size is more than allowed\n");
434 printk(KERN_WARNING "SEP Driver mmap requested size is more \
cd1bb431 435 than allowed\n");
d19cf32f
AC
436 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end);
437 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start);
438 return -EAGAIN;
439 }
440
441 edbg("SEP Driver:g_message_shared_area_addr is %08lx\n", sep_dev->message_shared_area_addr);
442
443 /* get physical address */
444 phys_addr = sep_dev->phys_shared_area_addr;
445
446 edbg("SEP Driver: phys_addr is %08lx\n", phys_addr);
447
448 if (remap_pfn_range(vma, vma->vm_start, phys_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
449 edbg("SEP Driver remap_page_range failed\n");
450 printk(KERN_WARNING "SEP Driver remap_page_range failed\n");
451 return -EAGAIN;
452 }
453
454 dbg("SEP Driver:<-------- mmap end\n");
455
456 return 0;
cd1bb431
MA
457}
458
459
460/*-----------------------------------------------
461 poll function
462*----------------------------------------------*/
d19cf32f 463static unsigned int sep_poll(struct file *filp, poll_table * wait)
cd1bb431 464{
d19cf32f 465 unsigned long count;
d19cf32f 466 unsigned int mask = 0;
f93e4bf9 467 unsigned long retVal = 0; /* flow id */
cd1bb431 468
d19cf32f 469 dbg("---------->SEP Driver poll: start\n");
cd1bb431
MA
470
471
472#if SEP_DRIVER_POLLING_MODE
473
d19cf32f
AC
474 while (sep_dev->host_to_sep_send_counter != (retVal & 0x7FFFFFFF)) {
475 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
cd1bb431 476
d19cf32f
AC
477 for (count = 0; count < 10 * 4; count += 4)
478 edbg("Poll Debug Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + count)));
479 }
cd1bb431 480
d19cf32f 481 sep_dev->sep_to_host_reply_counter++;
cd1bb431 482#else
d19cf32f
AC
483 /* add the event to the polling wait table */
484 poll_wait(filp, &g_sep_event, wait);
cd1bb431
MA
485
486#endif
487
d19cf32f
AC
488 edbg("sep_dev->host_to_sep_send_counter is %lu\n", sep_dev->host_to_sep_send_counter);
489 edbg("sep_dev->sep_to_host_reply_counter is %lu\n", sep_dev->sep_to_host_reply_counter);
490
491 /* check if the data is ready */
492 if (sep_dev->host_to_sep_send_counter == sep_dev->sep_to_host_reply_counter) {
493 for (count = 0; count < 12 * 4; count += 4)
494 edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
495
496 for (count = 0; count < 10 * 4; count += 4)
497 edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + 0x1800 + count)));
498
499 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
500 edbg("retVal is %lu\n", retVal);
501 /* check if the this is sep reply or request */
502 if (retVal >> 31) {
503 edbg("SEP Driver: sep request in\n");
504 /* request */
505 mask |= POLLOUT | POLLWRNORM;
506 } else {
507 edbg("SEP Driver: sep reply in\n");
508 mask |= POLLIN | POLLRDNORM;
509 }
cd1bb431 510 }
d19cf32f
AC
511 dbg("SEP Driver:<-------- poll exit\n");
512 return mask;
cd1bb431
MA
513}
514
515
d19cf32f 516static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
cd1bb431 517{
f93e4bf9 518 int error = 0;
cd1bb431 519
d19cf32f 520 dbg("------------>SEP Driver: ioctl start\n");
cd1bb431 521
d19cf32f 522 edbg("SEP Driver: cmd is %x\n", cmd);
cd1bb431 523
d19cf32f
AC
524 /* check that the command is for sep device */
525 if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER)
526 error = -ENOTTY;
cd1bb431
MA
527
528 switch (cmd) {
529 case SEP_IOCSENDSEPCOMMAND:
d19cf32f
AC
530 /* send command to SEP */
531 sep_send_command_handler();
d19cf32f 532 edbg("SEP Driver: after sep_send_command_handler\n");
d19cf32f 533 break;
cd1bb431 534 case SEP_IOCSENDSEPRPLYCOMMAND:
d19cf32f
AC
535 /* send reply command to SEP */
536 sep_send_reply_command_handler();
d19cf32f 537 break;
cd1bb431 538 case SEP_IOCALLOCDATAPOLL:
d19cf32f
AC
539 /* allocate data pool */
540 error = sep_allocate_data_pool_memory_handler(arg);
d19cf32f 541 break;
cd1bb431 542 case SEP_IOCWRITEDATAPOLL:
d19cf32f
AC
543 /* write data into memory pool */
544 error = sep_write_into_data_pool_handler(arg);
d19cf32f 545 break;
cd1bb431 546 case SEP_IOCREADDATAPOLL:
d19cf32f
AC
547 /* read data from data pool into application memory */
548 error = sep_read_from_data_pool_handler(arg);
d19cf32f 549 break;
cd1bb431 550 case SEP_IOCCREATESYMDMATABLE:
d19cf32f
AC
551 /* create dma table for synhronic operation */
552 error = sep_create_sync_dma_tables_handler(arg);
d19cf32f 553 break;
cd1bb431 554 case SEP_IOCCREATEFLOWDMATABLE:
d19cf32f
AC
555 /* create flow dma tables */
556 error = sep_create_flow_dma_tables_handler(arg);
d19cf32f 557 break;
cd1bb431 558 case SEP_IOCFREEDMATABLEDATA:
d19cf32f
AC
559 /* free the pages */
560 error = sep_free_dma_table_data_handler();
d19cf32f 561 break;
cd1bb431 562 case SEP_IOCSETFLOWID:
d19cf32f
AC
563 /* set flow id */
564 error = sep_set_flow_id_handler(arg);
d19cf32f 565 break;
cd1bb431 566 case SEP_IOCADDFLOWTABLE:
d19cf32f
AC
567 /* add tables to the dynamic flow */
568 error = sep_add_flow_tables_handler(arg);
d19cf32f 569 break;
cd1bb431 570 case SEP_IOCADDFLOWMESSAGE:
d19cf32f
AC
571 /* add message of add tables to flow */
572 error = sep_add_flow_tables_message_handler(arg);
d19cf32f 573 break;
cd1bb431 574 case SEP_IOCSEPSTART:
d19cf32f
AC
575 /* start command to sep */
576 error = sep_start_handler();
577 break;
cd1bb431 578 case SEP_IOCSEPINIT:
d19cf32f
AC
579 /* init command to sep */
580 error = sep_init_handler(arg);
581 break;
cd1bb431 582 case SEP_IOCSETAPIMODE:
d19cf32f
AC
583 /* set non- blocking mode */
584 error = sep_set_api_mode_handler(arg);
d19cf32f 585 break;
cd1bb431 586 case SEP_IOCGETSTATICPOOLADDR:
cd1bb431
MA
587 /* get the physical and virtual addresses of the static pool */
588 error = sep_get_static_pool_addr_handler(arg);
cd1bb431 589 break;
cd1bb431 590 case SEP_IOCENDTRANSACTION:
d19cf32f 591 error = sep_end_transaction_handler(arg);
cd1bb431 592 break;
cd1bb431 593 case SEP_IOCREALLOCCACHERES:
d19cf32f 594 error = sep_realloc_cache_resident_handler(arg);
d19cf32f 595 break;
cd1bb431 596 case SEP_IOCGETMAPPEDADDROFFSET:
d19cf32f 597 error = sep_get_physical_mapped_offset_handler(arg);
d19cf32f 598 break;
cd1bb431 599 case SEP_IOCGETIME:
d19cf32f 600 error = sep_get_time_handler(arg);
d19cf32f 601 break;
cd1bb431 602 default:
d19cf32f
AC
603 error = -ENOTTY;
604 break;
605 }
d19cf32f 606 dbg("SEP Driver:<-------- ioctl end\n");
d19cf32f 607 return error;
cd1bb431
MA
608}
609
610
611/*
612 this function registers the driver to the file system
613*/
d19cf32f 614static int sep_register_driver_to_fs(void)
cd1bb431 615{
f93e4bf9 616 int ret_val = alloc_chrdev_region(&g_sep_device_number, 0, 1, "sep_sec_driver");
d19cf32f
AC
617 if (ret_val) {
618 edbg("sep_driver:major number allocation failed, retval is %d\n", ret_val);
619 goto end_function;
620 }
cd1bb431 621
d19cf32f
AC
622 /* set the files operations structure */
623 g_sep_fops.owner = THIS_MODULE;
624 g_sep_fops.ioctl = sep_ioctl;
625 g_sep_fops.poll = sep_poll;
626 g_sep_fops.open = sep_open;
627 g_sep_fops.release = sep_release;
628 g_sep_fops.mmap = sep_mmap;
cd1bb431 629
d19cf32f
AC
630 /* init cdev */
631 cdev_init(&g_sep_cdev, &g_sep_fops);
632 g_sep_cdev.owner = THIS_MODULE;
cd1bb431 633
d19cf32f
AC
634 /* register the driver with the kernel */
635 ret_val = cdev_add(&g_sep_cdev, g_sep_device_number, 1);
cd1bb431 636
d19cf32f
AC
637 if (ret_val) {
638 edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val);
639 goto end_function_unregister_devnum;
640 }
cd1bb431 641
d19cf32f 642 goto end_function;
cd1bb431 643
f93e4bf9 644end_function_unregister_devnum:
cd1bb431 645
d19cf32f
AC
646 /* unregister dev numbers */
647 unregister_chrdev_region(g_sep_device_number, 1);
cd1bb431 648
f93e4bf9
AC
649end_function:
650 return ret_val;
cd1bb431
MA
651}
652
653/*
654 this function unregisters driver from fs
655*/
656static void sep_unregister_driver_from_fs(void)
657{
d19cf32f 658 cdev_del(&g_sep_cdev);
d19cf32f
AC
659 /* unregister dev numbers */
660 unregister_chrdev_region(g_sep_device_number, 1);
cd1bb431
MA
661}
662
663/*--------------------------------------------------------------
664 init function
665----------------------------------------------------------------*/
666static int __init sep_init(void)
667{
f93e4bf9 668 int ret_val = 0;
d19cf32f 669 int counter;
f93e4bf9 670 int size; /* size of memory for allocation */
cd1bb431 671
d19cf32f
AC
672 dbg("SEP Driver:-------->Init start\n");
673 edbg("sep->shared_area_addr = %lx\n", (unsigned long) &sep_dev->shared_area_addr);
cd1bb431 674
f93e4bf9 675 /* transaction counter that coordinates the transactions between SEP
cd1bb431 676 and HOST */
d19cf32f 677 sep_dev->host_to_sep_send_counter = 0;
cd1bb431 678
f93e4bf9 679 /* counter for the messages from sep */
d19cf32f 680 sep_dev->sep_to_host_reply_counter = 0;
cd1bb431 681
f93e4bf9
AC
682 /* counter for the number of bytes allocated in the pool
683 for the current transaction */
d19cf32f 684 sep_dev->data_pool_bytes_allocated = 0;
cd1bb431 685
d19cf32f
AC
686 /* set the starting mode to blocking */
687 sep_dev->block_mode_flag = 1;
cd1bb431 688
d19cf32f
AC
689 ret_val = sep_register_driver_to_device();
690 if (ret_val) {
691 edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val);
692 goto end_function_unregister_from_fs;
693 }
d19cf32f
AC
694 /* calculate the total size for allocation */
695 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
696 SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;
cd1bb431 697
d19cf32f
AC
698 /* allocate the shared area */
699 if (sep_map_and_alloc_shared_area(size, &sep_dev->shared_area_addr, &sep_dev->phys_shared_area_addr)) {
700 ret_val = -ENOMEM;
701 /* allocation failed */
702 goto end_function_unmap_io_memory;
703 }
d19cf32f
AC
704 /* now set the memory regions */
705 sep_dev->message_shared_area_addr = sep_dev->shared_area_addr;
cd1bb431 706
d19cf32f 707 edbg("SEP Driver: g_message_shared_area_addr is %08lx\n", sep_dev->message_shared_area_addr);
cd1bb431
MA
708
709#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1)
d19cf32f
AC
710 /* send the new SHARED MESSAGE AREA to the SEP */
711 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep_dev->phys_shared_area_addr);
cd1bb431 712
d19cf32f 713 /* poll for SEP response */
79de99e8 714 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
d19cf32f
AC
715 while (retVal != 0xffffffff && retVal != sep_dev->phys_shared_area_addr)
716 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
cd1bb431 717
d19cf32f
AC
718 /* check the return value (register) */
719 if (retVal != sep_dev->phys_shared_area_addr) {
720 ret_val = -ENOMEM;
721 goto end_function_deallocate_message_area;
722 }
cd1bb431 723#endif
d19cf32f
AC
724 /* init the flow contextes */
725 for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++)
726 sep_dev->flows_data_array[counter].flow_id = SEP_FREE_FLOW_ID;
cd1bb431 727
d19cf32f
AC
728 sep_dev->flow_wq_ptr = create_singlethread_workqueue("sepflowwq");
729 if (sep_dev->flow_wq_ptr == 0) {
730 ret_val = -ENOMEM;
731 edbg("sep_driver:flow queue creation failed\n");
732 goto end_function_deallocate_sep_shared_area;
733 }
d19cf32f 734 edbg("SEP Driver: create flow workqueue \n");
cd1bb431 735
d19cf32f
AC
736 /* register driver to fs */
737 ret_val = sep_register_driver_to_fs();
738 if (ret_val)
739 goto end_function_deallocate_sep_shared_area;
d19cf32f
AC
740 /* load the rom code */
741 sep_load_rom_code();
d19cf32f 742 goto end_function;
f93e4bf9 743end_function_unregister_from_fs:
d19cf32f
AC
744 /* unregister from fs */
745 sep_unregister_driver_from_fs();
f93e4bf9 746end_function_deallocate_sep_shared_area:
d19cf32f
AC
747 /* de-allocate shared area */
748 sep_unmap_and_free_shared_area(size, sep_dev->shared_area_addr, sep_dev->phys_shared_area_addr);
f93e4bf9 749end_function_unmap_io_memory:
d19cf32f 750 iounmap((void *) sep_dev->reg_base_address);
d19cf32f
AC
751 /* release io memory region */
752 release_mem_region(SEP_IO_MEM_REGION_START_ADDRESS, SEP_IO_MEM_REGION_SIZE);
f93e4bf9 753end_function:
d19cf32f 754 dbg("SEP Driver:<-------- Init end\n");
d19cf32f 755 return ret_val;
cd1bb431
MA
756}
757
758
cd1bb431
MA
759/*-------------------------------------------------------------
760 exit function
761--------------------------------------------------------------*/
762static void __exit sep_exit(void)
763{
d19cf32f 764 int size;
cd1bb431 765
d19cf32f 766 dbg("SEP Driver:--------> Exit start\n");
cd1bb431 767
d19cf32f
AC
768 /* unregister from fs */
769 sep_unregister_driver_from_fs();
d19cf32f
AC
770 /* calculate the total size for de-allocation */
771 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
772 SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;
d19cf32f
AC
773 /* free shared area */
774 sep_unmap_and_free_shared_area(size, sep_dev->shared_area_addr, sep_dev->phys_shared_area_addr);
d19cf32f 775 edbg("SEP Driver: free pages SEP SHARED AREA \n");
d19cf32f 776 iounmap((void *) sep_dev->reg_base_address);
d19cf32f 777 edbg("SEP Driver: iounmap \n");
d19cf32f
AC
778 /* release io memory region */
779 release_mem_region(SEP_IO_MEM_REGION_START_ADDRESS, SEP_IO_MEM_REGION_SIZE);
d19cf32f 780 edbg("SEP Driver: release_mem_region \n");
d19cf32f 781 dbg("SEP Driver:<-------- Exit end\n");
cd1bb431
MA
782}
783
784
785/*
786 interrupt handler function
787*/
788irqreturn_t sep_inthandler(int irq, void *dev_id)
789{
d19cf32f 790 irqreturn_t int_error;
d19cf32f 791 unsigned long error;
d19cf32f 792 unsigned long reg_val;
d19cf32f 793 unsigned long flow_id;
d19cf32f 794 struct sep_flow_context_t *flow_context_ptr;
cd1bb431 795
d19cf32f 796 int_error = IRQ_HANDLED;
cd1bb431 797
d19cf32f
AC
798 /* read the IRR register to check if this is SEP interrupt */
799 reg_val = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR);
800 edbg("SEP Interrupt - reg is %08lx\n", reg_val);
cd1bb431 801
d19cf32f
AC
802 /* check if this is the flow interrupt */
803 if (0 /*reg_val & (0x1 << 11) */ ) {
804 /* read GPRO to find out the which flow is done */
805 flow_id = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR);
cd1bb431 806
d19cf32f
AC
807 /* find the contex of the flow */
808 error = sep_find_flow_context(flow_id >> 28, &flow_context_ptr);
809 if (error)
810 goto end_function_with_error;
cd1bb431 811
d19cf32f 812 INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler);
cd1bb431 813
d19cf32f
AC
814 /* queue the work */
815 queue_work(sep_dev->flow_wq_ptr, &flow_context_ptr->flow_wq);
cd1bb431 816
cd1bb431 817 } else {
d19cf32f
AC
818 /* check if this is reply interrupt from SEP */
819 if (reg_val & (0x1 << 13)) {
820 /* update the counter of reply messages */
821 sep_dev->sep_to_host_reply_counter++;
822
823 /* wake up the waiting process */
824 wake_up(&g_sep_event);
825 } else {
826 int_error = IRQ_NONE;
827 goto end_function;
828 }
cd1bb431 829 }
f93e4bf9 830end_function_with_error:
d19cf32f
AC
831 /* clear the interrupt */
832 sep_write_reg(sep_dev, HW_HOST_ICR_REG_ADDR, reg_val);
f93e4bf9 833end_function:
d19cf32f 834 return int_error;
cd1bb431
MA
835}
836
837
838/*
839 This function prepares only input DMA table for synhronic symmetric
840 operations (HASH)
841*/
d19cf32f 842int sep_prepare_input_dma_table(unsigned long app_virt_addr, unsigned long data_size, unsigned long block_size, unsigned long *lli_table_ptr, unsigned long *num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress)
cd1bb431 843{
d19cf32f
AC
844 /* pointer to the info entry of the table - the last entry */
845 struct sep_lli_entry_t *info_entry_ptr;
d19cf32f
AC
846 /* array of pointers ot page */
847 struct sep_lli_entry_t *lli_array_ptr;
d19cf32f
AC
848 /* points to the first entry to be processed in the lli_in_array */
849 unsigned long current_entry;
d19cf32f
AC
850 /* num entries in the virtual buffer */
851 unsigned long sep_lli_entries;
d19cf32f
AC
852 /* lli table pointer */
853 struct sep_lli_entry_t *in_lli_table_ptr;
d19cf32f
AC
854 /* the total data in one table */
855 unsigned long table_data_size;
d19cf32f
AC
856 /* number of entries in lli table */
857 unsigned long num_entries_in_table;
d19cf32f
AC
858 /* next table address */
859 unsigned long lli_table_alloc_addr;
d19cf32f 860 unsigned long result;
cd1bb431 861
d19cf32f 862 dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n");
cd1bb431 863
d19cf32f
AC
864 edbg("SEP Driver:data_size is %lu\n", data_size);
865 edbg("SEP Driver:block_size is %lu\n", block_size);
cd1bb431 866
d19cf32f
AC
867 /* initialize the pages pointers */
868 sep_dev->in_page_array = 0;
869 sep_dev->in_num_pages = 0;
cd1bb431 870
d19cf32f
AC
871 if (data_size == 0) {
872 /* special case - created 2 entries table with zero data */
873 in_lli_table_ptr = (struct sep_lli_entry_t *) (sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES);
874 in_lli_table_ptr->physical_address = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
875 in_lli_table_ptr->block_size = 0;
cd1bb431 876
d19cf32f
AC
877 in_lli_table_ptr++;
878 in_lli_table_ptr->physical_address = 0xFFFFFFFF;
879 in_lli_table_ptr->block_size = 0;
cd1bb431 880
d19cf32f
AC
881 *lli_table_ptr = sep_dev->phys_shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
882 *num_entries_ptr = 2;
883 *table_data_size_ptr = 0;
cd1bb431 884
d19cf32f 885 goto end_function;
cd1bb431
MA
886 }
887
d19cf32f
AC
888 /* check if the pages are in Kernel Virtual Address layout */
889 if (isKernelVirtualAddress == true)
890 /* lock the pages of the kernel buffer and translate them to pages */
891 result = sep_lock_kernel_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array);
892 else
893 /* lock the pages of the user buffer and translate them to pages */
894 result = sep_lock_user_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array);
895
896 if (result)
897 return result;
898
899 edbg("SEP Driver:output sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages);
900
901 current_entry = 0;
902 info_entry_ptr = 0;
903 sep_lli_entries = sep_dev->in_num_pages;
cd1bb431 904
d19cf32f
AC
905 /* initiate to point after the message area */
906 lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
cd1bb431 907
d19cf32f
AC
908 /* loop till all the entries in in array are not processed */
909 while (current_entry < sep_lli_entries) {
910 /* set the new input and output tables */
911 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
cd1bb431 912
d19cf32f 913 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
cd1bb431 914
d19cf32f
AC
915 /* calculate the maximum size of data for input table */
916 table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry));
cd1bb431 917
d19cf32f
AC
918 /* now calculate the table size so that it will be module block size */
919 table_data_size = (table_data_size / block_size) * block_size;
920
921 edbg("SEP Driver:output table_data_size is %lu\n", table_data_size);
922
923 /* construct input lli table */
924 sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, &current_entry, &num_entries_in_table, table_data_size);
925
926 if (info_entry_ptr == 0) {
927 /* set the output parameters to physical addresses */
928 *lli_table_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
929 *num_entries_ptr = num_entries_in_table;
930 *table_data_size_ptr = table_data_size;
931
932 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr);
933 } else {
934 /* update the info entry of the previous in table */
935 info_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
936 info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
937 }
938
939 /* save the pointer to the info entry of the current tables */
940 info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
941 }
942
943 /* print input tables */
944 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
945 sep_shared_area_phys_to_virt(*lli_table_ptr), *num_entries_ptr, *table_data_size_ptr);
946
947 /* the array of the pages */
948 kfree(lli_array_ptr);
f93e4bf9 949end_function:
d19cf32f 950 dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n");
d19cf32f 951 return 0;
cd1bb431
MA
952
953}
954
955/*
956 This function builds input and output DMA tables for synhronic
957 symmetric operations (AES, DES). It also checks that each table
958 is of the modular block size
959*/
d19cf32f
AC
960int sep_prepare_input_output_dma_table(unsigned long app_virt_in_addr,
961 unsigned long app_virt_out_addr,
962 unsigned long data_size,
963 unsigned long block_size,
964 unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress)
cd1bb431 965{
d19cf32f
AC
966 /* array of pointers of page */
967 struct sep_lli_entry_t *lli_in_array;
d19cf32f
AC
968 /* array of pointers of page */
969 struct sep_lli_entry_t *lli_out_array;
f93e4bf9 970 int result = 0;
cd1bb431 971
d19cf32f 972 dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n");
cd1bb431 973
d19cf32f
AC
974 /* initialize the pages pointers */
975 sep_dev->in_page_array = 0;
976 sep_dev->out_page_array = 0;
cd1bb431 977
d19cf32f
AC
978 /* check if the pages are in Kernel Virtual Address layout */
979 if (isKernelVirtualAddress == true) {
980 /* lock the pages of the kernel buffer and translate them to pages */
981 result = sep_lock_kernel_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array);
982 if (result) {
983 edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n");
984 goto end_function;
985 }
986 } else {
987 /* lock the pages of the user buffer and translate them to pages */
988 result = sep_lock_user_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array);
989 if (result) {
990 edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n");
991 goto end_function;
992 }
cd1bb431 993 }
d19cf32f
AC
994
995 if (isKernelVirtualAddress == true) {
996 result = sep_lock_kernel_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array);
997 if (result) {
998 edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n");
999 goto end_function_with_error1;
1000 }
1001 } else {
1002 result = sep_lock_user_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array);
1003 if (result) {
1004 edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n");
1005 goto end_function_with_error1;
1006 }
cd1bb431 1007 }
d19cf32f
AC
1008 edbg("sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages);
1009 edbg("sep_dev->out_num_pages is %lu\n", sep_dev->out_num_pages);
1010 edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
cd1bb431
MA
1011
1012
d19cf32f
AC
1013 /* call the fucntion that creates table from the lli arrays */
1014 result = sep_construct_dma_tables_from_lli(lli_in_array, sep_dev->in_num_pages, lli_out_array, sep_dev->out_num_pages, block_size, lli_table_in_ptr, lli_table_out_ptr, in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr);
1015 if (result) {
1016 edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n");
1017 goto end_function_with_error2;
1018 }
cd1bb431 1019
d19cf32f 1020 /* fall through - free the lli entry arrays */
d19cf32f
AC
1021 dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr);
1022 dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr);
1023 dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr);
f93e4bf9 1024end_function_with_error2:
d19cf32f 1025 kfree(lli_out_array);
f93e4bf9 1026end_function_with_error1:
d19cf32f 1027 kfree(lli_in_array);
f93e4bf9 1028end_function:
d19cf32f 1029 dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result);
d19cf32f 1030 return result;
cd1bb431
MA
1031
1032}
1033
1034
1035/*
1036 This function creates the input and output dma tables for
1037 symmetric operations (AES/DES) according to the block size from LLI arays
1038*/
d19cf32f
AC
1039int sep_construct_dma_tables_from_lli(struct sep_lli_entry_t *lli_in_array,
1040 unsigned long sep_in_lli_entries,
1041 struct sep_lli_entry_t *lli_out_array,
1042 unsigned long sep_out_lli_entries,
1043 unsigned long block_size, unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr)
cd1bb431 1044{
d19cf32f
AC
1045 /* points to the area where next lli table can be allocated */
1046 unsigned long lli_table_alloc_addr;
d19cf32f
AC
1047 /* input lli table */
1048 struct sep_lli_entry_t *in_lli_table_ptr;
d19cf32f
AC
1049 /* output lli table */
1050 struct sep_lli_entry_t *out_lli_table_ptr;
d19cf32f
AC
1051 /* pointer to the info entry of the table - the last entry */
1052 struct sep_lli_entry_t *info_in_entry_ptr;
d19cf32f
AC
1053 /* pointer to the info entry of the table - the last entry */
1054 struct sep_lli_entry_t *info_out_entry_ptr;
d19cf32f
AC
1055 /* points to the first entry to be processed in the lli_in_array */
1056 unsigned long current_in_entry;
d19cf32f
AC
1057 /* points to the first entry to be processed in the lli_out_array */
1058 unsigned long current_out_entry;
d19cf32f
AC
1059 /* max size of the input table */
1060 unsigned long in_table_data_size;
d19cf32f
AC
1061 /* max size of the output table */
1062 unsigned long out_table_data_size;
d19cf32f
AC
1063 /* flag te signifies if this is the first tables build from the arrays */
1064 unsigned long first_table_flag;
d19cf32f
AC
1065 /* the data size that should be in table */
1066 unsigned long table_data_size;
d19cf32f
AC
1067 /* number of etnries in the input table */
1068 unsigned long num_entries_in_table;
d19cf32f
AC
1069 /* number of etnries in the output table */
1070 unsigned long num_entries_out_table;
cd1bb431 1071
d19cf32f
AC
1072 dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n");
1073
1074 /* initiate to pint after the message area */
1075 lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
1076
1077 current_in_entry = 0;
1078 current_out_entry = 0;
1079 first_table_flag = 1;
1080 info_in_entry_ptr = 0;
1081 info_out_entry_ptr = 0;
1082
1083 /* loop till all the entries in in array are not processed */
1084 while (current_in_entry < sep_in_lli_entries) {
1085 /* set the new input and output tables */
1086 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
1087
1088 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
1089
1090 /* set the first output tables */
1091 out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
1092
1093 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
1094
1095 /* calculate the maximum size of data for input table */
1096 in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry));
1097
1098 /* calculate the maximum size of data for output table */
1099 out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry));
1100
1101 edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size);
1102 edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size);
1103
1104 /* check where the data is smallest */
1105 table_data_size = in_table_data_size;
1106 if (table_data_size > out_table_data_size)
1107 table_data_size = out_table_data_size;
1108
1109 /* now calculate the table size so that it will be module block size */
1110 table_data_size = (table_data_size / block_size) * block_size;
1111
1112 dbg("SEP Driver:table_data_size is %lu\n", table_data_size);
1113
1114 /* construct input lli table */
1115 sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, &current_in_entry, &num_entries_in_table, table_data_size);
1116
1117 /* construct output lli table */
1118 sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, &current_out_entry, &num_entries_out_table, table_data_size);
1119
1120 /* if info entry is null - this is the first table built */
1121 if (info_in_entry_ptr == 0) {
1122 /* set the output parameters to physical addresses */
1123 *lli_table_in_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
1124 *in_num_entries_ptr = num_entries_in_table;
1125 *lli_table_out_ptr = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr);
1126 *out_num_entries_ptr = num_entries_out_table;
1127 *table_data_size_ptr = table_data_size;
1128
1129 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr);
1130 edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr);
1131 } else {
1132 /* update the info entry of the previous in table */
1133 info_in_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
1134 info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
1135
1136 /* update the info entry of the previous in table */
1137 info_out_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr);
1138 info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size);
1139 }
1140
1141 /* save the pointer to the info entry of the current tables */
1142 info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
1143 info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1;
1144
1145 edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table);
1146 edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr);
1147 edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr);
cd1bb431
MA
1148 }
1149
d19cf32f
AC
1150 /* print input tables */
1151 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
1152 sep_shared_area_phys_to_virt(*lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr);
d19cf32f
AC
1153 /* print output tables */
1154 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
1155 sep_shared_area_phys_to_virt(*lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr);
d19cf32f 1156 dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n");
d19cf32f 1157 return 0;
cd1bb431
MA
1158}
1159
1160/*
1161 this function calculates the size of data that can be inserted into the lli
1162 table from this array the condition is that either the table is full
1163 (all etnries are entered), or there are no more entries in the lli array
1164*/
d19cf32f 1165unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries)
cd1bb431 1166{
f93e4bf9 1167 unsigned long table_data_size = 0;
d19cf32f 1168 unsigned long counter;
cd1bb431 1169
d19cf32f
AC
1170 /* calculate the data in the out lli table if till we fill the whole
1171 table or till the data has ended */
1172 for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++)
1173 table_data_size += lli_in_array_ptr[counter].block_size;
d19cf32f 1174 return table_data_size;
cd1bb431
MA
1175}
1176
1177/*
1178 this functions builds ont lli table from the lli_array according to
1179 the given size of data
1180*/
d19cf32f 1181static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size)
cd1bb431 1182{
d19cf32f 1183 unsigned long curr_table_data_size;
d19cf32f
AC
1184 /* counter of lli array entry */
1185 unsigned long array_counter;
cd1bb431 1186
d19cf32f
AC
1187 dbg("SEP Driver:--------> sep_build_lli_table start\n");
1188
1189 /* init currrent table data size and lli array entry counter */
1190 curr_table_data_size = 0;
1191 array_counter = 0;
1192 *num_table_entries_ptr = 1;
1193
1194 edbg("SEP Driver:table_data_size is %lu\n", table_data_size);
1195
1196 /* fill the table till table size reaches the needed amount */
1197 while (curr_table_data_size < table_data_size) {
1198 /* update the number of entries in table */
1199 (*num_table_entries_ptr)++;
1200
1201 lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address;
1202 lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size;
1203 curr_table_data_size += lli_table_ptr->block_size;
1204
1205 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
1206 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1207 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1208
1209 /* check for overflow of the table data */
1210 if (curr_table_data_size > table_data_size) {
1211 edbg("SEP Driver:curr_table_data_size > table_data_size\n");
1212
1213 /* update the size of block in the table */
1214 lli_table_ptr->block_size -= (curr_table_data_size - table_data_size);
1215
1216 /* update the physical address in the lli array */
1217 lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size;
1218
1219 /* update the block size left in the lli array */
1220 lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size);
1221 } else
1222 /* advance to the next entry in the lli_array */
1223 array_counter++;
1224
1225 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1226 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1227
1228 /* move to the next entry in table */
1229 lli_table_ptr++;
1230 }
1231
1232 /* set the info entry to default */
1233 lli_table_ptr->physical_address = 0xffffffff;
1234 lli_table_ptr->block_size = 0;
1235
1236 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
1237 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1238 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1239
d19cf32f
AC
1240 /* set the output parameter */
1241 *num_processed_entries_ptr += array_counter;
1242
1243 edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr);
d19cf32f 1244 dbg("SEP Driver:<-------- sep_build_lli_table end\n");
d19cf32f 1245 return;
cd1bb431
MA
1246}
1247
1248/*
1249 this function goes over the list of the print created tables and
1250 prints all the data
1251*/
d19cf32f 1252static void sep_debug_print_lli_tables(struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size)
cd1bb431 1253{
d19cf32f 1254 unsigned long table_count;
d19cf32f 1255 unsigned long entries_count;
cd1bb431 1256
d19cf32f 1257 dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n");
cd1bb431 1258
d19cf32f
AC
1259 table_count = 1;
1260 while ((unsigned long) lli_table_ptr != 0xffffffff) {
1261 edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size);
1262 edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries);
cd1bb431 1263
d19cf32f
AC
1264 /* print entries of the table (without info entry) */
1265 for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) {
1266 edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr);
1267 edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size);
1268 }
cd1bb431 1269
d19cf32f
AC
1270 /* point to the info entry */
1271 lli_table_ptr--;
cd1bb431 1272
d19cf32f
AC
1273 edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1274 edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
cd1bb431 1275
cd1bb431 1276
d19cf32f
AC
1277 table_data_size = lli_table_ptr->block_size & 0xffffff;
1278 num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
1279 lli_table_ptr = (struct sep_lli_entry_t *)
1280 (lli_table_ptr->physical_address);
cd1bb431 1281
d19cf32f 1282 edbg("SEP Driver:phys table_data_size is %lu num_table_entries is %lu lli_table_ptr is%lu\n", table_data_size, num_table_entries, (unsigned long) lli_table_ptr);
cd1bb431 1283
d19cf32f
AC
1284 if ((unsigned long) lli_table_ptr != 0xffffffff)
1285 lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_area_phys_to_virt((unsigned long) lli_table_ptr);
1286
1287 table_count++;
1288 }
d19cf32f 1289 dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n");
cd1bb431
MA
1290}
1291
1292
1293/*
1294 This function locks all the physical pages of the application virtual buffer
1295 and construct a basic lli array, where each entry holds the physical page
1296 address and the size that application data holds in this physical pages
1297*/
d19cf32f 1298int sep_lock_user_pages(unsigned long app_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr)
cd1bb431 1299{
f93e4bf9 1300 int error = 0;
d19cf32f
AC
1301 /* the the page of the end address of the user space buffer */
1302 unsigned long end_page;
d19cf32f
AC
1303 /* the page of the start address of the user space buffer */
1304 unsigned long start_page;
d19cf32f
AC
1305 /* the range in pages */
1306 unsigned long num_pages;
d19cf32f 1307 struct page **page_array;
d19cf32f 1308 struct sep_lli_entry_t *lli_array;
d19cf32f 1309 unsigned long count;
d19cf32f 1310 int result;
cd1bb431 1311
d19cf32f
AC
1312 dbg("SEP Driver:--------> sep_lock_user_pages start\n");
1313
d19cf32f
AC
1314 /* set start and end pages and num pages */
1315 end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
1316 start_page = app_virt_addr >> PAGE_SHIFT;
1317 num_pages = end_page - start_page + 1;
1318
1319 edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr);
1320 edbg("SEP Driver: data_size is %lu\n", data_size);
1321 edbg("SEP Driver: start_page is %lu\n", start_page);
1322 edbg("SEP Driver: end_page is %lu\n", end_page);
1323 edbg("SEP Driver: num_pages is %lu\n", num_pages);
1324
1325 /* allocate array of pages structure pointers */
1326 page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
1327 if (!page_array) {
1328 edbg("SEP Driver: kmalloc for page_array failed\n");
1329
1330 error = -ENOMEM;
1331 goto end_function;
cd1bb431 1332 }
cd1bb431 1333
d19cf32f
AC
1334 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
1335 if (!lli_array) {
1336 edbg("SEP Driver: kmalloc for lli_array failed\n");
cd1bb431 1337
d19cf32f
AC
1338 error = -ENOMEM;
1339 goto end_function_with_error1;
1340 }
cd1bb431 1341
d19cf32f
AC
1342 /* convert the application virtual address into a set of physical */
1343 down_read(&current->mm->mmap_sem);
1344 result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0);
1345 up_read(&current->mm->mmap_sem);
cd1bb431 1346
d19cf32f
AC
1347 /* check the number of pages locked - if not all then exit with error */
1348 if (result != num_pages) {
1349 dbg("SEP Driver: not all pages locked by get_user_pages\n");
cd1bb431 1350
d19cf32f
AC
1351 error = -ENOMEM;
1352 goto end_function_with_error2;
1353 }
1354
1355 /* flush the cache */
1356 for (count = 0; count < num_pages; count++)
1357 flush_dcache_page(page_array[count]);
1358
1359 /* set the start address of the first page - app data may start not at
1360 the beginning of the page */
1361 lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK));
1362
1363 /* check that not all the data is in the first page only */
1364 if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
1365 lli_array[0].block_size = data_size;
1366 else
1367 lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
1368
1369 /* debug print */
1370 dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size);
1371
1372 /* go from the second page to the prev before last */
1373 for (count = 1; count < (num_pages - 1); count++) {
1374 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
1375 lli_array[count].block_size = PAGE_SIZE;
1376
f93e4bf9 1377 edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
d19cf32f
AC
1378 }
1379
1380 /* if more then 1 pages locked - then update for the last page size needed */
1381 if (num_pages > 1) {
1382 /* update the address of the last page */
1383 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
1384
1385 /* set the size of the last page */
1386 lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK);
1387
1388 if (lli_array[count].block_size == 0) {
1389 dbg("app_virt_addr is %08lx\n", app_virt_addr);
1390 dbg("data_size is %lu\n", data_size);
1391 while (1);
1392 }
1393 edbg("lli_array[%lu].physical_address is %08lx, \
1394 lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
1395 }
1396
1397 /* set output params */
1398 *lli_array_ptr = lli_array;
1399 *num_pages_ptr = num_pages;
1400 *page_array_ptr = page_array;
d19cf32f
AC
1401 goto end_function;
1402
f93e4bf9 1403end_function_with_error2:
d19cf32f
AC
1404 /* release the cache */
1405 for (count = 0; count < num_pages; count++)
1406 page_cache_release(page_array[count]);
d19cf32f 1407 kfree(lli_array);
f93e4bf9 1408end_function_with_error1:
d19cf32f 1409 kfree(page_array);
f93e4bf9 1410end_function:
d19cf32f 1411 dbg("SEP Driver:<-------- sep_lock_user_pages end\n");
d19cf32f 1412 return 0;
cd1bb431
MA
1413}
1414
1415/*
1416 This function locks all the physical pages of the kernel virtual buffer
1417 and construct a basic lli array, where each entry holds the physical
1418 page address and the size that application data holds in this physical pages
1419*/
d19cf32f 1420int sep_lock_kernel_pages(unsigned long kernel_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr)
cd1bb431 1421{
f93e4bf9 1422 int error = 0;
d19cf32f
AC
1423 /* the the page of the end address of the user space buffer */
1424 unsigned long end_page;
d19cf32f
AC
1425 /* the page of the start address of the user space buffer */
1426 unsigned long start_page;
d19cf32f
AC
1427 /* the range in pages */
1428 unsigned long num_pages;
d19cf32f 1429 struct sep_lli_entry_t *lli_array;
d19cf32f
AC
1430 /* next kernel address to map */
1431 unsigned long next_kernel_address;
d19cf32f 1432 unsigned long count;
cd1bb431 1433
d19cf32f
AC
1434 dbg("SEP Driver:--------> sep_lock_kernel_pages start\n");
1435
d19cf32f
AC
1436 /* set start and end pages and num pages */
1437 end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT;
1438 start_page = kernel_virt_addr >> PAGE_SHIFT;
1439 num_pages = end_page - start_page + 1;
1440
1441 edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr);
1442 edbg("SEP Driver: data_size is %lu\n", data_size);
1443 edbg("SEP Driver: start_page is %lx\n", start_page);
1444 edbg("SEP Driver: end_page is %lx\n", end_page);
1445 edbg("SEP Driver: num_pages is %lu\n", num_pages);
1446
1447 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
1448 if (!lli_array) {
1449 edbg("SEP Driver: kmalloc for lli_array failed\n");
d19cf32f
AC
1450 error = -ENOMEM;
1451 goto end_function;
cd1bb431
MA
1452 }
1453
d19cf32f
AC
1454 /* set the start address of the first page - app data may start not at
1455 the beginning of the page */
1456 lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr);
cd1bb431 1457
d19cf32f
AC
1458 /* check that not all the data is in the first page only */
1459 if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size)
1460 lli_array[0].block_size = data_size;
1461 else
1462 lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK));
cd1bb431 1463
d19cf32f
AC
1464 /* debug print */
1465 dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size);
1466
1467 /* advance the address to the start of the next page */
1468 next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE;
1469
1470 /* go from the second page to the prev before last */
1471 for (count = 1; count < (num_pages - 1); count++) {
1472 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
1473 lli_array[count].block_size = PAGE_SIZE;
1474
f93e4bf9 1475 edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
d19cf32f
AC
1476 next_kernel_address += PAGE_SIZE;
1477 }
cd1bb431 1478
d19cf32f
AC
1479 /* if more then 1 pages locked - then update for the last page size needed */
1480 if (num_pages > 1) {
1481 /* update the address of the last page */
1482 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
cd1bb431 1483
d19cf32f
AC
1484 /* set the size of the last page */
1485 lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK);
cd1bb431 1486
d19cf32f
AC
1487 if (lli_array[count].block_size == 0) {
1488 dbg("app_virt_addr is %08lx\n", kernel_virt_addr);
1489 dbg("data_size is %lu\n", data_size);
1490 while (1);
1491 }
1492
f93e4bf9 1493 edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
d19cf32f 1494 }
d19cf32f
AC
1495 /* set output params */
1496 *lli_array_ptr = lli_array;
1497 *num_pages_ptr = num_pages;
1498 *page_array_ptr = 0;
f93e4bf9 1499end_function:
d19cf32f 1500 dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n");
d19cf32f 1501 return 0;
cd1bb431
MA
1502}
1503
1504/*
1505 This function releases all the application virtual buffer physical pages,
1506 that were previously locked
1507*/
d19cf32f 1508int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag)
cd1bb431 1509{
d19cf32f 1510 unsigned long count;
cd1bb431 1511
d19cf32f
AC
1512 if (dirtyFlag) {
1513 for (count = 0; count < num_pages; count++) {
1514 /* the out array was written, therefore the data was changed */
1515 if (!PageReserved(page_array_ptr[count]))
1516 SetPageDirty(page_array_ptr[count]);
1517 page_cache_release(page_array_ptr[count]);
1518 }
1519 } else {
1520 /* free in pages - the data was only read, therefore no update was done
1521 on those pages */
1522 for (count = 0; count < num_pages; count++)
1523 page_cache_release(page_array_ptr[count]);
cd1bb431 1524 }
cd1bb431 1525
d19cf32f
AC
1526 if (page_array_ptr)
1527 /* free the array */
1528 kfree(page_array_ptr);
cd1bb431 1529
d19cf32f 1530 return 0;
cd1bb431
MA
1531}
1532
1533/*
1534 This function raises interrupt to SEP that signals that is has a new
1535 command from HOST
1536*/
1537static void sep_send_command_handler()
1538{
d19cf32f 1539 unsigned long count;
cd1bb431 1540
d19cf32f 1541 dbg("SEP Driver:--------> sep_send_command_handler start\n");
d19cf32f 1542 sep_set_time(0, 0);
cd1bb431 1543
d19cf32f
AC
1544 /* flash cache */
1545 flush_cache_all();
cd1bb431 1546
d19cf32f
AC
1547 for (count = 0; count < 12 * 4; count += 4)
1548 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
cd1bb431 1549
d19cf32f
AC
1550 /* update counter */
1551 sep_dev->host_to_sep_send_counter++;
d19cf32f
AC
1552 /* send interrupt to SEP */
1553 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
d19cf32f 1554 dbg("SEP Driver:<-------- sep_send_command_handler end\n");
d19cf32f 1555 return;
cd1bb431
MA
1556}
1557
1558/*
1559 This function raises interrupt to SEPm that signals that is has a
1560 new command from HOST
1561*/
1562static void sep_send_reply_command_handler()
1563{
d19cf32f 1564 unsigned long count;
cd1bb431 1565
d19cf32f 1566 dbg("SEP Driver:--------> sep_send_reply_command_handler start\n");
cd1bb431 1567
d19cf32f
AC
1568 /* flash cache */
1569 flush_cache_all();
d19cf32f
AC
1570 for (count = 0; count < 12 * 4; count += 4)
1571 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
d19cf32f
AC
1572 /* update counter */
1573 sep_dev->host_to_sep_send_counter++;
d19cf32f
AC
1574 /* send the interrupt to SEP */
1575 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep_dev->host_to_sep_send_counter);
d19cf32f
AC
1576 /* update both counters */
1577 sep_dev->host_to_sep_send_counter++;
d19cf32f 1578 sep_dev->sep_to_host_reply_counter++;
d19cf32f 1579 dbg("SEP Driver:<-------- sep_send_reply_command_handler end\n");
cd1bb431
MA
1580}
1581
1582
1583
1584/*
1585 This function handles the allocate data pool memory request
1586 This function returns calculates the physical address of the
1587 allocated memory, and the offset of this area from the mapped address.
1588 Therefore, the FVOs in user space can calculate the exact virtual
1589 address of this allocated memory
1590*/
1591static int sep_allocate_data_pool_memory_handler(unsigned long arg)
1592{
d19cf32f 1593 int error;
d19cf32f 1594 struct sep_driver_alloc_t command_args;
cd1bb431 1595
d19cf32f 1596 dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n");
cd1bb431 1597
d19cf32f
AC
1598 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t));
1599 if (error)
1600 goto end_function;
cd1bb431 1601
d19cf32f
AC
1602 /* allocate memory */
1603 if ((sep_dev->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
1604 error = -ENOTTY;
1605 goto end_function;
1606 }
1607
1608 /* set the virtual and physical address */
1609 command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated;
1610 command_args.phys_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated;
cd1bb431 1611
d19cf32f
AC
1612 /* write the memory back to the user space */
1613 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t));
1614 if (error)
1615 goto end_function;
cd1bb431 1616
d19cf32f
AC
1617 /* set the allocation */
1618 sep_dev->data_pool_bytes_allocated += command_args.num_bytes;
cd1bb431 1619
f93e4bf9 1620end_function:
d19cf32f 1621 dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n");
d19cf32f 1622 return error;
cd1bb431
MA
1623}
1624
1625/*
1626 This function handles write into allocated data pool command
1627*/
1628static int sep_write_into_data_pool_handler(unsigned long arg)
1629{
d19cf32f 1630 int error;
d19cf32f 1631 unsigned long virt_address;
d19cf32f 1632 unsigned long app_in_address;
d19cf32f 1633 unsigned long num_bytes;
d19cf32f 1634 unsigned long data_pool_area_addr;
cd1bb431 1635
d19cf32f 1636 dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n");
cd1bb431 1637
d19cf32f
AC
1638 /* get the application address */
1639 error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address));
1640 if (error)
1641 goto end_function;
cd1bb431 1642
d19cf32f
AC
1643 /* get the virtual kernel address address */
1644 error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address));
1645 if (error)
1646 goto end_function;
cd1bb431 1647
d19cf32f
AC
1648 /* get the number of bytes */
1649 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
1650 if (error)
1651 goto end_function;
cd1bb431 1652
d19cf32f
AC
1653 /* calculate the start of the data pool */
1654 data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
cd1bb431
MA
1655
1656
d19cf32f
AC
1657 /* check that the range of the virtual kernel address is correct */
1658 if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) {
1659 error = -ENOTTY;
1660 goto end_function;
1661 }
d19cf32f
AC
1662 /* copy the application data */
1663 error = copy_from_user((void *) virt_address, (void *) app_in_address, num_bytes);
f93e4bf9 1664end_function:
d19cf32f 1665 dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n");
d19cf32f 1666 return error;
cd1bb431
MA
1667}
1668
1669/*
1670 this function handles the read from data pool command
1671*/
1672static int sep_read_from_data_pool_handler(unsigned long arg)
1673{
d19cf32f 1674 int error;
d19cf32f
AC
1675 /* virtual address of dest application buffer */
1676 unsigned long app_out_address;
d19cf32f
AC
1677 /* virtual address of the data pool */
1678 unsigned long virt_address;
d19cf32f 1679 unsigned long num_bytes;
d19cf32f 1680 unsigned long data_pool_area_addr;
cd1bb431 1681
d19cf32f 1682 dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n");
cd1bb431 1683
d19cf32f
AC
1684 /* get the application address */
1685 error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address));
1686 if (error)
1687 goto end_function;
cd1bb431 1688
d19cf32f
AC
1689 /* get the virtual kernel address address */
1690 error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address));
1691 if (error)
1692 goto end_function;
cd1bb431 1693
d19cf32f
AC
1694 /* get the number of bytes */
1695 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
1696 if (error)
1697 goto end_function;
cd1bb431 1698
d19cf32f
AC
1699 /* calculate the start of the data pool */
1700 data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
cd1bb431 1701
d19cf32f
AC
1702 /* check that the range of the virtual kernel address is correct */
1703 if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) {
1704 error = -ENOTTY;
1705 goto end_function;
1706 }
cd1bb431 1707
d19cf32f
AC
1708 /* copy the application data */
1709 error = copy_to_user((void *) app_out_address, (void *) virt_address, num_bytes);
f93e4bf9 1710end_function:
d19cf32f 1711 dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n");
d19cf32f 1712 return error;
cd1bb431
MA
1713}
1714
1715
1716/*
1717 this function handles tha request for creation of the DMA table
1718 for the synchronic symmetric operations (AES,DES)
1719*/
1720static int sep_create_sync_dma_tables_handler(unsigned long arg)
1721{
d19cf32f 1722 int error;
d19cf32f
AC
1723 /* command arguments */
1724 struct sep_driver_build_sync_table_t command_args;
cd1bb431 1725
d19cf32f 1726 dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n");
cd1bb431 1727
d19cf32f
AC
1728 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t));
1729 if (error)
1730 goto end_function;
cd1bb431 1731
d19cf32f
AC
1732 edbg("app_in_address is %08lx\n", command_args.app_in_address);
1733 edbg("app_out_address is %08lx\n", command_args.app_out_address);
1734 edbg("data_size is %lu\n", command_args.data_in_size);
1735 edbg("block_size is %lu\n", command_args.block_size);
1736
d19cf32f
AC
1737 /* check if we need to build only input table or input/output */
1738 if (command_args.app_out_address)
1739 /* prepare input and output tables */
1740 error = sep_prepare_input_output_dma_table(command_args.app_in_address,
1741 command_args.app_out_address,
1742 command_args.data_in_size,
1743 command_args.block_size,
1744 &command_args.in_table_address,
1745 &command_args.out_table_address, &command_args.in_table_num_entries, &command_args.out_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress);
1746 else
1747 /* prepare input tables */
1748 error = sep_prepare_input_dma_table(command_args.app_in_address,
1749 command_args.data_in_size, command_args.block_size, &command_args.in_table_address, &command_args.in_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress);
cd1bb431 1750
d19cf32f
AC
1751 if (error)
1752 goto end_function;
d19cf32f
AC
1753 /* copy to user */
1754 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t));
f93e4bf9 1755end_function:
d19cf32f 1756 dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n");
d19cf32f 1757 return error;
cd1bb431
MA
1758}
1759
1760/*
1761 this function handles the request for freeing dma table for synhronic actions
1762*/
1763int sep_free_dma_table_data_handler()
1764{
d19cf32f 1765 dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n");
cd1bb431 1766
d19cf32f
AC
1767 /* free input pages array */
1768 sep_free_dma_pages(sep_dev->in_page_array, sep_dev->in_num_pages, 0);
cd1bb431 1769
d19cf32f
AC
1770 /* free output pages array if needed */
1771 if (sep_dev->out_page_array)
1772 sep_free_dma_pages(sep_dev->out_page_array, sep_dev->out_num_pages, 1);
cd1bb431 1773
d19cf32f
AC
1774 /* reset all the values */
1775 sep_dev->in_page_array = 0;
1776 sep_dev->out_page_array = 0;
1777 sep_dev->in_num_pages = 0;
1778 sep_dev->out_num_pages = 0;
d19cf32f 1779 dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n");
d19cf32f 1780 return 0;
cd1bb431
MA
1781}
1782
1783/*
1784 this function handles the request to create the DMA tables for flow
1785*/
1786static int sep_create_flow_dma_tables_handler(unsigned long arg)
1787{
d19cf32f 1788 int error;
d19cf32f 1789 struct sep_driver_build_flow_table_t command_args;
d19cf32f
AC
1790 /* first table - output */
1791 struct sep_lli_entry_t first_table_data;
d19cf32f
AC
1792 /* dma table data */
1793 struct sep_lli_entry_t last_table_data;
d19cf32f
AC
1794 /* pointer to the info entry of the previuos DMA table */
1795 struct sep_lli_entry_t *prev_info_entry_ptr;
d19cf32f
AC
1796 /* pointer to the flow data strucutre */
1797 struct sep_flow_context_t *flow_context_ptr;
cd1bb431 1798
d19cf32f 1799 dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n");
cd1bb431 1800
d19cf32f
AC
1801 /* init variables */
1802 prev_info_entry_ptr = 0;
1803 first_table_data.physical_address = 0xffffffff;
cd1bb431 1804
d19cf32f
AC
1805 /* find the free structure for flow data */
1806 error = sep_find_flow_context(SEP_FREE_FLOW_ID, &flow_context_ptr);
1807 if (error)
1808 goto end_function;
cd1bb431 1809
d19cf32f
AC
1810 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t));
1811 if (error)
1812 goto end_function;
cd1bb431 1813
d19cf32f
AC
1814 /* create flow tables */
1815 error = sep_prepare_flow_dma_tables(command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress);
1816 if (error)
1817 goto end_function_with_error;
cd1bb431 1818
d19cf32f
AC
1819 /* check if flow is static */
1820 if (!command_args.flow_type)
1821 /* point the info entry of the last to the info entry of the first */
1822 last_table_data = first_table_data;
cd1bb431 1823
d19cf32f
AC
1824 /* set output params */
1825 command_args.first_table_addr = first_table_data.physical_address;
1826 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1827 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
cd1bb431 1828
d19cf32f
AC
1829 /* send the parameters to user application */
1830 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t));
1831 if (error)
1832 goto end_function_with_error;
cd1bb431 1833
d19cf32f
AC
1834 /* all the flow created - update the flow entry with temp id */
1835 flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID;
cd1bb431 1836
d19cf32f
AC
1837 /* set the processing tables data in the context */
1838 if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG)
1839 flow_context_ptr->input_tables_in_process = first_table_data;
1840 else
1841 flow_context_ptr->output_tables_in_process = first_table_data;
cd1bb431 1842
d19cf32f 1843 goto end_function;
cd1bb431 1844
f93e4bf9 1845end_function_with_error:
d19cf32f
AC
1846 /* free the allocated tables */
1847 sep_deallocated_flow_tables(&first_table_data);
f93e4bf9 1848end_function:
d19cf32f 1849 dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n");
d19cf32f 1850 return error;
cd1bb431
MA
1851}
1852
1853/*
1854 this functio n handles add tables to flow
1855*/
1856static int sep_add_flow_tables_handler(unsigned long arg)
1857{
d19cf32f 1858 int error;
d19cf32f 1859 unsigned long num_entries;
d19cf32f 1860 struct sep_driver_add_flow_table_t command_args;
d19cf32f 1861 struct sep_flow_context_t *flow_context_ptr;
d19cf32f
AC
1862 /* first dma table data */
1863 struct sep_lli_entry_t first_table_data;
d19cf32f
AC
1864 /* last dma table data */
1865 struct sep_lli_entry_t last_table_data;
d19cf32f
AC
1866 /* pointer to the info entry of the current DMA table */
1867 struct sep_lli_entry_t *info_entry_ptr;
cd1bb431 1868
d19cf32f 1869 dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n");
cd1bb431 1870
d19cf32f
AC
1871 /* get input parameters */
1872 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t));
1873 if (error)
1874 goto end_function;
cd1bb431 1875
d19cf32f
AC
1876 /* find the flow structure for the flow id */
1877 error = sep_find_flow_context(command_args.flow_id, &flow_context_ptr);
1878 if (error)
1879 goto end_function;
cd1bb431 1880
d19cf32f
AC
1881 /* prepare the flow dma tables */
1882 error = sep_prepare_flow_dma_tables(command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress);
1883 if (error)
1884 goto end_function_with_error;
cd1bb431 1885
d19cf32f
AC
1886 /* now check if there is already an existing add table for this flow */
1887 if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) {
1888 /* this buffer was for input buffers */
1889 if (flow_context_ptr->input_tables_flag) {
1890 /* add table already exists - add the new tables to the end
1891 of the previous */
1892 num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
1893
1894 info_entry_ptr = (struct sep_lli_entry_t *)
1895 (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
1896
1897 /* connect to list of tables */
1898 *info_entry_ptr = first_table_data;
1899
1900 /* set the first table data */
1901 first_table_data = flow_context_ptr->first_input_table;
1902 } else {
1903 /* set the input flag */
1904 flow_context_ptr->input_tables_flag = 1;
1905
1906 /* set the first table data */
1907 flow_context_ptr->first_input_table = first_table_data;
1908 }
1909 /* set the last table data */
1910 flow_context_ptr->last_input_table = last_table_data;
1911 } else { /* this is output tables */
1912
1913 /* this buffer was for input buffers */
1914 if (flow_context_ptr->output_tables_flag) {
1915 /* add table already exists - add the new tables to
1916 the end of the previous */
1917 num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
1918
1919 info_entry_ptr = (struct sep_lli_entry_t *)
1920 (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
1921
1922 /* connect to list of tables */
1923 *info_entry_ptr = first_table_data;
1924
1925 /* set the first table data */
1926 first_table_data = flow_context_ptr->first_output_table;
1927 } else {
1928 /* set the input flag */
1929 flow_context_ptr->output_tables_flag = 1;
1930
1931 /* set the first table data */
1932 flow_context_ptr->first_output_table = first_table_data;
1933 }
1934 /* set the last table data */
1935 flow_context_ptr->last_output_table = last_table_data;
cd1bb431 1936 }
cd1bb431 1937
d19cf32f
AC
1938 /* set output params */
1939 command_args.first_table_addr = first_table_data.physical_address;
1940 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1941 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
cd1bb431 1942
d19cf32f
AC
1943 /* send the parameters to user application */
1944 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t));
f93e4bf9 1945end_function_with_error:
d19cf32f
AC
1946 /* free the allocated tables */
1947 sep_deallocated_flow_tables(&first_table_data);
f93e4bf9 1948end_function:
d19cf32f 1949 dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n");
d19cf32f 1950 return error;
cd1bb431
MA
1951}
1952
1953/*
1954 this function add the flow add message to the specific flow
1955*/
1956static int sep_add_flow_tables_message_handler(unsigned long arg)
1957{
d19cf32f 1958 int error;
d19cf32f 1959 struct sep_driver_add_message_t command_args;
d19cf32f 1960 struct sep_flow_context_t *flow_context_ptr;
cd1bb431 1961
d19cf32f 1962 dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n");
cd1bb431 1963
d19cf32f
AC
1964 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t));
1965 if (error)
1966 goto end_function;
cd1bb431 1967
d19cf32f
AC
1968 /* check input */
1969 if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) {
1970 error = -ENOMEM;
1971 goto end_function;
1972 }
cd1bb431 1973
d19cf32f
AC
1974 /* find the flow context */
1975 error = sep_find_flow_context(command_args.flow_id, &flow_context_ptr);
1976 if (error)
1977 goto end_function;
cd1bb431 1978
d19cf32f
AC
1979 /* copy the message into context */
1980 flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes;
d19cf32f 1981 error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes);
f93e4bf9 1982end_function:
d19cf32f 1983 dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n");
d19cf32f 1984 return error;
cd1bb431
MA
1985}
1986
1987
1988/*
1989 this function returns the physical and virtual addresses of the static pool
1990*/
1991static int sep_get_static_pool_addr_handler(unsigned long arg)
1992{
d19cf32f 1993 int error;
d19cf32f 1994 struct sep_driver_static_pool_addr_t command_args;
cd1bb431 1995
d19cf32f 1996 dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n");
cd1bb431 1997
d19cf32f
AC
1998 /*prepare the output parameters in the struct */
1999 command_args.physical_static_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
2000 command_args.virtual_static_address = sep_dev->shared_area_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
cd1bb431 2001
d19cf32f 2002 edbg("SEP Driver:physical_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address);
cd1bb431 2003
d19cf32f
AC
2004 /* send the parameters to user application */
2005 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t));
d19cf32f 2006 dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n");
d19cf32f 2007 return error;
cd1bb431
MA
2008}
2009
2010/*
2011 this address gets the offset of the physical address from the start
2012 of the mapped area
2013*/
2014static int sep_get_physical_mapped_offset_handler(unsigned long arg)
2015{
d19cf32f 2016 int error;
d19cf32f 2017 struct sep_driver_get_mapped_offset_t command_args;
cd1bb431 2018
d19cf32f 2019 dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n");
cd1bb431 2020
d19cf32f
AC
2021 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t));
2022 if (error)
2023 goto end_function;
cd1bb431 2024
d19cf32f
AC
2025 if (command_args.physical_address < sep_dev->phys_shared_area_addr) {
2026 error = -ENOTTY;
2027 goto end_function;
2028 }
cd1bb431 2029
d19cf32f
AC
2030 /*prepare the output parameters in the struct */
2031 command_args.offset = command_args.physical_address - sep_dev->phys_shared_area_addr;
cd1bb431 2032
d19cf32f 2033 edbg("SEP Driver:physical_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset);
cd1bb431 2034
d19cf32f
AC
2035 /* send the parameters to user application */
2036 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t));
f93e4bf9 2037end_function:
d19cf32f 2038 dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n");
d19cf32f 2039 return error;
cd1bb431
MA
2040}
2041
2042
2043/*
2044 ?
2045*/
2046static int sep_start_handler(void)
2047{
d19cf32f 2048 unsigned long reg_val;
f93e4bf9 2049 unsigned long error = 0;
cd1bb431 2050
d19cf32f 2051 dbg("SEP Driver:--------> sep_start_handler start\n");
cd1bb431 2052
d19cf32f 2053 /* wait in polling for message from SEP */
f93e4bf9 2054 do
d19cf32f 2055 reg_val = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
f93e4bf9 2056 while (!reg_val);
cd1bb431 2057
d19cf32f 2058 /* check the value */
43e8c4a3 2059 if (reg_val == 0x1)
d19cf32f
AC
2060 /* fatal error - read erro status from GPRO */
2061 error = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
f93e4bf9 2062end_function:
d19cf32f 2063 dbg("SEP Driver:<-------- sep_start_handler end\n");
d19cf32f 2064 return error;
cd1bb431
MA
2065}
2066
2067/*
2068 this function handles the request for SEP initialization
2069*/
2070static int sep_init_handler(unsigned long arg)
2071{
d19cf32f 2072 unsigned long message_word;
d19cf32f 2073 unsigned long *message_ptr;
d19cf32f 2074 struct sep_driver_init_t command_args;
d19cf32f 2075 unsigned long counter;
d19cf32f 2076 unsigned long error;
d19cf32f 2077 unsigned long reg_val;
cd1bb431 2078
d19cf32f 2079 dbg("SEP Driver:--------> sep_init_handler start\n");
d19cf32f 2080 error = 0;
cd1bb431 2081
d19cf32f 2082 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t));
cd1bb431 2083
d19cf32f 2084 dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user \n");
cd1bb431 2085
d19cf32f
AC
2086 if (error)
2087 goto end_function;
cd1bb431 2088
d19cf32f
AC
2089 /* PATCH - configure the DMA to single -burst instead of multi-burst */
2090 /*sep_configure_dma_burst(); */
cd1bb431 2091
d19cf32f 2092 dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n");
cd1bb431 2093
d19cf32f 2094 message_ptr = (unsigned long *) command_args.message_addr;
cd1bb431 2095
d19cf32f
AC
2096 /* set the base address of the SRAM */
2097 sep_write_reg(sep_dev, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS);
cd1bb431 2098
d19cf32f
AC
2099 for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) {
2100 get_user(message_word, message_ptr);
d19cf32f
AC
2101 /* write data to SRAM */
2102 sep_write_reg(sep_dev, HW_SRAM_DATA_REG_ADDR, message_word);
d19cf32f 2103 edbg("SEP Driver:message_word is %lu\n", message_word);
cd1bb431 2104 /* wait for write complete */
d19cf32f
AC
2105 sep_wait_sram_write(sep_dev);
2106 }
d19cf32f 2107 dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n");
d19cf32f
AC
2108 /* signal SEP */
2109 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1);
cd1bb431 2110
f93e4bf9 2111 do
d19cf32f 2112 reg_val = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
f93e4bf9 2113 while (!(reg_val & 0xFFFFFFFD));
cd1bb431 2114
d19cf32f 2115 dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n");
cd1bb431 2116
d19cf32f
AC
2117 /* check the value */
2118 if (reg_val == 0x1) {
2119 edbg("SEP Driver:init failed\n");
cd1bb431 2120
d19cf32f
AC
2121 error = sep_read_reg(sep_dev, 0x8060);
2122 edbg("SEP Driver:sw monitor is %lu\n", error);
cd1bb431 2123
d19cf32f
AC
2124 /* fatal error - read erro status from GPRO */
2125 error = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
2126 edbg("SEP Driver:error is %lu\n", error);
d19cf32f 2127 }
f93e4bf9 2128end_function:
d19cf32f 2129 dbg("SEP Driver:<-------- sep_init_handler end\n");
d19cf32f 2130 return error;
cd1bb431
MA
2131
2132}
2133
2134/*
2135 this function handles the request cache and resident reallocation
2136*/
2137static int sep_realloc_cache_resident_handler(unsigned long arg)
2138{
d19cf32f 2139 int error;
d19cf32f 2140 unsigned long phys_cache_address;
d19cf32f 2141 unsigned long phys_resident_address;
d19cf32f 2142 struct sep_driver_realloc_cache_resident_t command_args;
cd1bb431 2143
d19cf32f
AC
2144 /* copy the data */
2145 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_realloc_cache_resident_t));
2146 if (error)
2147 goto end_function;
cd1bb431 2148
d19cf32f
AC
2149 /* copy cache and resident to the their intended locations */
2150 error = sep_copy_cache_resident_to_area(command_args.cache_addr, command_args.cache_size_in_bytes, command_args.resident_addr, command_args.resident_size_in_bytes, &phys_cache_address, &phys_resident_address);
2151 if (error)
2152 goto end_function;
cd1bb431 2153
d19cf32f
AC
2154 /* lock the area (if needed) */
2155 sep_lock_cache_resident_area();
cd1bb431 2156
d19cf32f 2157 command_args.new_base_addr = sep_dev->phys_shared_area_addr;
cd1bb431 2158
d19cf32f
AC
2159 /* find the new base address according to the lowest address between
2160 cache, resident and shared area */
2161 if (phys_resident_address < command_args.new_base_addr)
2162 command_args.new_base_addr = phys_resident_address;
2163 if (phys_cache_address < command_args.new_base_addr)
2164 command_args.new_base_addr = phys_cache_address;
cd1bb431 2165
d19cf32f
AC
2166 /* set the return parameters */
2167 command_args.new_cache_addr = phys_cache_address;
2168 command_args.new_resident_addr = phys_resident_address;
cd1bb431 2169
d19cf32f
AC
2170 /* set the new shared area */
2171 command_args.new_shared_area_addr = sep_dev->phys_shared_area_addr;
cd1bb431 2172
d19cf32f
AC
2173 edbg("SEP Driver:command_args.new_shared_area_addr is %08lx\n", command_args.new_shared_area_addr);
2174 edbg("SEP Driver:command_args.new_base_addr is %08lx\n", command_args.new_base_addr);
2175 edbg("SEP Driver:command_args.new_resident_addr is %08lx\n", command_args.new_resident_addr);
2176 edbg("SEP Driver:command_args.new_cache_addr is %08lx\n", command_args.new_cache_addr);
cd1bb431 2177
d19cf32f
AC
2178 /* return to user */
2179 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_realloc_cache_resident_t));
f93e4bf9 2180end_function:
d19cf32f 2181 return error;
cd1bb431
MA
2182}
2183
2184/*
2185 this function handles the request for get time
2186*/
2187static int sep_get_time_handler(unsigned long arg)
2188{
d19cf32f 2189 int error;
d19cf32f 2190 struct sep_driver_get_time_t command_args;
cd1bb431 2191
d19cf32f 2192 error = sep_set_time(&command_args.time_physical_address, &command_args.time_value);
d19cf32f 2193 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_get_time_t));
d19cf32f 2194 return error;
cd1bb431
MA
2195
2196}
2197
2198/*
2199 This api handles the setting of API mode to blocking or non-blocking
2200*/
2201static int sep_set_api_mode_handler(unsigned long arg)
2202{
d19cf32f 2203 int error;
d19cf32f 2204 unsigned long mode_flag;
cd1bb431 2205
d19cf32f 2206 dbg("SEP Driver:--------> sep_set_api_mode_handler start\n");
cd1bb431 2207
d19cf32f
AC
2208 error = get_user(mode_flag, &(((struct sep_driver_set_api_mode_t *) arg)->mode));
2209 if (error)
2210 goto end_function;
cd1bb431 2211
d19cf32f
AC
2212 /* set the global flag */
2213 sep_dev->block_mode_flag = mode_flag;
f93e4bf9 2214end_function:
d19cf32f 2215 dbg("SEP Driver:<-------- sep_set_api_mode_handler end\n");
d19cf32f 2216 return error;
cd1bb431
MA
2217}
2218
2219/*
2220 This API handles the end transaction request
2221*/
2222static int sep_end_transaction_handler(unsigned long arg)
2223{
d19cf32f 2224 dbg("SEP Driver:--------> sep_end_transaction_handler start\n");
cd1bb431 2225
d19cf32f
AC
2226#if 0 /*!SEP_DRIVER_POLLING_MODE */
2227 /* close IMR */
2228 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF);
cd1bb431 2229
d19cf32f
AC
2230 /* release IRQ line */
2231 free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address);
cd1bb431 2232
d19cf32f
AC
2233 /* lock the sep mutex */
2234 mutex_unlock(&sep_mutex);
cd1bb431
MA
2235#endif
2236
d19cf32f 2237 dbg("SEP Driver:<-------- sep_end_transaction_handler end\n");
cd1bb431 2238
d19cf32f 2239 return 0;
cd1bb431
MA
2240}
2241
2242/* handler for flow done interrupt */
d19cf32f 2243static void sep_flow_done_handler(struct work_struct *work)
cd1bb431 2244{
d19cf32f 2245 struct sep_flow_context_t *flow_data_ptr;
cd1bb431 2246
d19cf32f
AC
2247 /* obtain the mutex */
2248 mutex_lock(&sep_mutex);
cd1bb431 2249
d19cf32f
AC
2250 /* get the pointer to context */
2251 flow_data_ptr = (struct sep_flow_context_t *) work;
cd1bb431 2252
d19cf32f
AC
2253 /* free all the current input tables in sep */
2254 sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process);
cd1bb431 2255
d19cf32f
AC
2256 /* free all the current tables output tables in SEP (if needed) */
2257 if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff)
2258 sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process);
cd1bb431 2259
d19cf32f
AC
2260 /* check if we have additional tables to be sent to SEP only input
2261 flag may be checked */
2262 if (flow_data_ptr->input_tables_flag) {
2263 /* copy the message to the shared RAM and signal SEP */
2264 memcpy((void *) flow_data_ptr->message, (void *) sep_dev->shared_area_addr, flow_data_ptr->message_size_in_bytes);
cd1bb431 2265
d19cf32f
AC
2266 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2);
2267 }
2268 mutex_unlock(&sep_mutex);
cd1bb431
MA
2269}
2270
2271
2272/*
2273 This function creates a list of tables for flow and returns the data for
2274 the first and last tables of the list
2275*/
2276static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers,
d19cf32f 2277 unsigned long first_buff_addr, struct sep_flow_context_t *flow_data_ptr, struct sep_lli_entry_t *first_table_data_ptr, struct sep_lli_entry_t *last_table_data_ptr, bool isKernelVirtualAddress)
cd1bb431 2278{
d19cf32f 2279 int error;
d19cf32f 2280 unsigned long virt_buff_addr;
d19cf32f 2281 unsigned long virt_buff_size;
d19cf32f 2282 struct sep_lli_entry_t table_data;
d19cf32f 2283 struct sep_lli_entry_t *info_entry_ptr;
d19cf32f 2284 struct sep_lli_entry_t *prev_info_entry_ptr;
d19cf32f 2285 unsigned long i;
cd1bb431 2286
d19cf32f
AC
2287 /* init vars */
2288 error = 0;
2289 prev_info_entry_ptr = 0;
2290
2291 /* init the first table to default */
2292 table_data.physical_address = 0xffffffff;
2293 first_table_data_ptr->physical_address = 0xffffffff;
2294 table_data.block_size = 0;
2295
2296 for (i = 0; i < num_virtual_buffers; i++) {
2297 /* get the virtual buffer address */
2298 error = get_user(virt_buff_addr, &first_buff_addr);
2299 if (error)
2300 goto end_function;
2301
2302 /* get the virtual buffer size */
2303 first_buff_addr++;
2304 error = get_user(virt_buff_size, &first_buff_addr);
2305 if (error)
2306 goto end_function;
2307
2308 /* advance the address to point to the next pair of address|size */
2309 first_buff_addr++;
2310
2311 /* now prepare the one flow LLI table from the data */
2312 error = sep_prepare_one_flow_dma_table(virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress);
2313 if (error)
2314 goto end_function;
2315
2316 if (i == 0) {
2317 /* if this is the first table - save it to return to the user
2318 application */
2319 *first_table_data_ptr = table_data;
2320
2321 /* set the pointer to info entry */
2322 prev_info_entry_ptr = info_entry_ptr;
2323 } else {
2324 /* not first table - the previous table info entry should
2325 be updated */
2326 prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size);
2327
2328 /* set the pointer to info entry */
2329 prev_info_entry_ptr = info_entry_ptr;
2330 }
cd1bb431 2331 }
cd1bb431 2332
d19cf32f
AC
2333 /* set the last table data */
2334 *last_table_data_ptr = table_data;
f93e4bf9 2335end_function:
d19cf32f 2336 return error;
cd1bb431
MA
2337}
2338
2339
2340/*
2341 This function creates one DMA table for flow and returns its data,
2342 and pointer to its info entry
2343*/
d19cf32f 2344static int sep_prepare_one_flow_dma_table(unsigned long virt_buff_addr, unsigned long virt_buff_size, struct sep_lli_entry_t *table_data, struct sep_lli_entry_t **info_entry_ptr, struct sep_flow_context_t *flow_data_ptr, bool isKernelVirtualAddress)
cd1bb431 2345{
d19cf32f 2346 int error;
d19cf32f
AC
2347 /* the range in pages */
2348 unsigned long lli_array_size;
d19cf32f 2349 struct sep_lli_entry_t *lli_array;
d19cf32f 2350 struct sep_lli_entry_t *flow_dma_table_entry_ptr;
d19cf32f 2351 unsigned long *start_dma_table_ptr;
d19cf32f
AC
2352 /* total table data counter */
2353 unsigned long dma_table_data_count;
f93e4bf9 2354 /* pointer that will keep the pointer to the pages of the virtual buffer */
d19cf32f 2355 struct page **page_array_ptr;
d19cf32f 2356 unsigned long entry_count;
cd1bb431 2357
d19cf32f
AC
2358 /* find the space for the new table */
2359 error = sep_find_free_flow_dma_table_space(&start_dma_table_ptr);
2360 if (error)
2361 goto end_function;
cd1bb431 2362
d19cf32f
AC
2363 /* check if the pages are in Kernel Virtual Address layout */
2364 if (isKernelVirtualAddress == true)
2365 /* lock kernel buffer in the memory */
2366 error = sep_lock_kernel_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
2367 else
2368 /* lock user buffer in the memory */
2369 error = sep_lock_user_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
2370
2371 if (error)
2372 goto end_function;
cd1bb431 2373
d19cf32f
AC
2374 /* set the pointer to page array at the beginning of table - this table is
2375 now considered taken */
2376 *start_dma_table_ptr = lli_array_size;
cd1bb431 2377
d19cf32f
AC
2378 /* point to the place of the pages pointers of the table */
2379 start_dma_table_ptr++;
cd1bb431 2380
d19cf32f
AC
2381 /* set the pages pointer */
2382 *start_dma_table_ptr = (unsigned long) page_array_ptr;
cd1bb431 2383
d19cf32f
AC
2384 /* set the pointer to the first entry */
2385 flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr);
cd1bb431 2386
d19cf32f
AC
2387 /* now create the entries for table */
2388 for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) {
2389 flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address;
cd1bb431 2390
d19cf32f 2391 flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size;
cd1bb431 2392
d19cf32f
AC
2393 /* set the total data of a table */
2394 dma_table_data_count += lli_array[entry_count].block_size;
cd1bb431 2395
d19cf32f
AC
2396 flow_dma_table_entry_ptr++;
2397 }
cd1bb431 2398
d19cf32f
AC
2399 /* set the physical address */
2400 table_data->physical_address = virt_to_phys(start_dma_table_ptr);
cd1bb431 2401
d19cf32f
AC
2402 /* set the num_entries and total data size */
2403 table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count);
cd1bb431 2404
d19cf32f
AC
2405 /* set the info entry */
2406 flow_dma_table_entry_ptr->physical_address = 0xffffffff;
2407 flow_dma_table_entry_ptr->block_size = 0;
cd1bb431 2408
d19cf32f
AC
2409 /* set the pointer to info entry */
2410 *info_entry_ptr = flow_dma_table_entry_ptr;
cd1bb431 2411
d19cf32f
AC
2412 /* the array of the lli entries */
2413 kfree(lli_array);
f93e4bf9 2414end_function:
d19cf32f 2415 return error;
cd1bb431
MA
2416}
2417
2418
2419/*
2420 This function returns pointer to the flow data structure
f93e4bf9 2421 that contains the given id
cd1bb431 2422*/
d19cf32f 2423static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr)
cd1bb431 2424{
d19cf32f 2425 unsigned long count;
f93e4bf9 2426 int error = 0;
d19cf32f
AC
2427
2428 /*
2429 always search for flow with id default first - in case we
2430 already started working on the flow there can be no situation
2431 when 2 flows are with default flag
2432 */
2433 for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) {
2434 if (sep_dev->flows_data_array[count].flow_id == flow_id) {
2435 *flow_data_ptr = &sep_dev->flows_data_array[count];
2436 break;
2437 }
cd1bb431 2438 }
cd1bb431 2439
d19cf32f
AC
2440 if (count == SEP_DRIVER_NUM_FLOWS)
2441 /* no flow found */
2442 error = -ENOMEM;
cd1bb431 2443
d19cf32f 2444 return error;
cd1bb431
MA
2445}
2446
2447/*
2448 this function find a space for the new flow dma table
2449*/
d19cf32f 2450static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr)
cd1bb431 2451{
f93e4bf9 2452 int error = 0;
d19cf32f
AC
2453 /* pointer to the id field of the flow dma table */
2454 unsigned long *start_table_ptr;
d19cf32f 2455 unsigned long flow_dma_area_start_addr;
d19cf32f 2456 unsigned long flow_dma_area_end_addr;
d19cf32f
AC
2457 /* maximum table size in words */
2458 unsigned long table_size_in_words;
cd1bb431 2459
d19cf32f
AC
2460 /* find the start address of the flow DMA table area */
2461 flow_dma_area_start_addr = sep_dev->shared_area_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES;
cd1bb431 2462
d19cf32f
AC
2463 /* set end address of the flow table area */
2464 flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES;
cd1bb431 2465
d19cf32f
AC
2466 /* set table size in words */
2467 table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2;
cd1bb431 2468
d19cf32f
AC
2469 /* set the pointer to the start address of DMA area */
2470 start_table_ptr = (unsigned long *) flow_dma_area_start_addr;
cd1bb431 2471
d19cf32f
AC
2472 /* find the space for the next table */
2473 while (((*start_table_ptr & 0x7FFFFFFF) != 0) && ((unsigned long) start_table_ptr < flow_dma_area_end_addr))
2474 start_table_ptr += table_size_in_words;
cd1bb431 2475
d19cf32f
AC
2476 /* check if we reached the end of floa tables area */
2477 if ((unsigned long) start_table_ptr >= flow_dma_area_end_addr)
2478 error = -1;
2479 else
2480 *table_address_ptr = start_table_ptr;
cd1bb431 2481
d19cf32f 2482 return error;
cd1bb431
MA
2483}
2484
2485/*
2486 this function goes over all the flow tables connected to the given
2487 table and deallocate them
2488*/
2489static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr)
2490{
f93e4bf9 2491 /* id pointer */
d19cf32f 2492 unsigned long *table_ptr;
d19cf32f
AC
2493 /* end address of the flow dma area */
2494 unsigned long num_entries;
d19cf32f 2495 unsigned long num_pages;
d19cf32f 2496 struct page **pages_ptr;
d19cf32f
AC
2497 /* maximum table size in words */
2498 struct sep_lli_entry_t *info_entry_ptr;
cd1bb431 2499
d19cf32f
AC
2500 /* set the pointer to the first table */
2501 table_ptr = (unsigned long *) first_table_ptr->physical_address;
cd1bb431 2502
d19cf32f
AC
2503 /* set the num of entries */
2504 num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS)
2505 & SEP_NUM_ENTRIES_MASK;
cd1bb431 2506
d19cf32f
AC
2507 /* go over all the connected tables */
2508 while (*table_ptr != 0xffffffff) {
2509 /* get number of pages */
2510 num_pages = *(table_ptr - 2);
cd1bb431 2511
d19cf32f
AC
2512 /* get the pointer to the pages */
2513 pages_ptr = (struct page **) (*(table_ptr - 1));
cd1bb431 2514
d19cf32f
AC
2515 /* free the pages */
2516 sep_free_dma_pages(pages_ptr, num_pages, 1);
cd1bb431 2517
d19cf32f
AC
2518 /* goto to the info entry */
2519 info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1);
cd1bb431 2520
d19cf32f
AC
2521 table_ptr = (unsigned long *) info_entry_ptr->physical_address;
2522 num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
2523 }
cd1bb431 2524
d19cf32f 2525 return;
cd1bb431
MA
2526}
2527
2528/*
2529 This function handler the set flow id command
2530*/
2531static int sep_set_flow_id_handler(unsigned long arg)
2532{
d19cf32f 2533 int error;
d19cf32f 2534 unsigned long flow_id;
d19cf32f 2535 struct sep_flow_context_t *flow_data_ptr;
cd1bb431 2536
d19cf32f 2537 dbg("------------>SEP Driver: sep_set_flow_id_handler start\n");
cd1bb431 2538
d19cf32f
AC
2539 error = get_user(flow_id, &(((struct sep_driver_set_flow_id_t *) arg)->flow_id));
2540 if (error)
2541 goto end_function;
cd1bb431 2542
d19cf32f
AC
2543 /* find the flow data structure that was just used for creating new flow
2544 - its id should be default */
2545 error = sep_find_flow_context(SEP_TEMP_FLOW_ID, &flow_data_ptr);
2546 if (error)
2547 goto end_function;
cd1bb431 2548
d19cf32f
AC
2549 /* set flow id */
2550 flow_data_ptr->flow_id = flow_id;
cd1bb431 2551
f93e4bf9 2552end_function:
d19cf32f 2553 dbg("SEP Driver:<-------- sep_set_flow_id_handler end\n");
d19cf32f 2554 return error;
cd1bb431
MA
2555}
2556
2557
2558/*
2559 calculates time and sets it at the predefined address
2560*/
d19cf32f 2561static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr)
cd1bb431 2562{
d19cf32f 2563 struct timeval time;
d19cf32f
AC
2564 /* address of time in the kernel */
2565 unsigned long time_addr;
cd1bb431
MA
2566
2567
d19cf32f 2568 dbg("SEP Driver:--------> sep_set_time start\n");
cd1bb431 2569
d19cf32f 2570 do_gettimeofday(&time);
cd1bb431 2571
d19cf32f
AC
2572 /* set value in the SYSTEM MEMORY offset */
2573 time_addr = sep_dev->message_shared_area_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
cd1bb431 2574
d19cf32f
AC
2575 *(unsigned long *) time_addr = SEP_TIME_VAL_TOKEN;
2576 *(unsigned long *) (time_addr + 4) = time.tv_sec;
cd1bb431 2577
d19cf32f
AC
2578 edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec);
2579 edbg("SEP Driver:time_addr is %lu\n", time_addr);
2580 edbg("SEP Driver:g_message_shared_area_addr is %lu\n", sep_dev->message_shared_area_addr);
cd1bb431 2581
d19cf32f
AC
2582 /* set the output parameters if needed */
2583 if (address_ptr)
2584 *address_ptr = sep_shared_area_virt_to_phys(time_addr);
cd1bb431 2585
d19cf32f
AC
2586 if (time_in_sec_ptr)
2587 *time_in_sec_ptr = time.tv_sec;
cd1bb431 2588
d19cf32f 2589 dbg("SEP Driver:<-------- sep_set_time end\n");
cd1bb431 2590
d19cf32f 2591 return 0;
cd1bb431
MA
2592}
2593
794f1d78
AC
2594static void sep_wait_busy(struct sep_device *dev)
2595{
2596 u32 reg;
2597
2598 do {
2599 reg = sep_read_reg(sep_dev, HW_HOST_SEP_BUSY_REG_ADDR);
2600 } while (reg);
2601}
2602
cd1bb431
MA
2603/*
2604 PATCH for configuring the DMA to single burst instead of multi-burst
2605*/
2606static void sep_configure_dma_burst(void)
2607{
cd1bb431
MA
2608#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL
2609
d19cf32f 2610 dbg("SEP Driver:<-------- sep_configure_dma_burst start \n");
cd1bb431 2611
d19cf32f
AC
2612 /* request access to registers from SEP */
2613 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
cd1bb431 2614
d19cf32f 2615 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n");
cd1bb431 2616
d19cf32f 2617 sep_wait_busy(sep_dev);
cd1bb431 2618
d19cf32f 2619 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n");
cd1bb431 2620
d19cf32f
AC
2621 /* set the DMA burst register to single burst */
2622 sep_write_reg(sep_dev, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL);
cd1bb431 2623
d19cf32f
AC
2624 /* release the sep busy */
2625 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL);
2626 sep_wait_busy(sep_dev);
cd1bb431 2627
d19cf32f 2628 dbg("SEP Driver:<-------- sep_configure_dma_burst done \n");
cd1bb431
MA
2629
2630}
2631
2632module_init(sep_init);
2633module_exit(sep_exit);
2634
2635MODULE_LICENSE("GPL");