blob: 23bc8a81105edb4c44b1e8ca3fc4959320aae0bd [file] [log] [blame]
Mark Allyncd1bb432009-08-06 20:43:59 +01001/*
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>
Alan Cox0097a692009-08-07 19:23:19 +010041#include <linux/pci.h>
42#include <linux/firmware.h>
Mark Allyncd1bb432009-08-06 20:43:59 +010043#include <asm/ioctl.h>
44#include <linux/ioport.h>
45#include <asm/io.h>
46#include <linux/interrupt.h>
47#include <linux/pagemap.h>
48#include <asm/cacheflush.h>
49#include "sep_driver_hw_defs.h"
50#include "sep_driver_config.h"
51#include "sep_driver_api.h"
52#include "sep_driver_ext_api.h"
Alan Coxf5e39802009-08-06 20:45:07 +010053#include "sep_dev.h"
Mark Allyncd1bb432009-08-06 20:43:59 +010054
Alan Cox0097a692009-08-07 19:23:19 +010055#if SEP_DRIVER_ARM_DEBUG_MODE
56
57#define CRYS_SEP_ROM_length 0x4000
58#define CRYS_SEP_ROM_start_address 0x8000C000UL
59#define CRYS_SEP_ROM_start_address_offset 0xC000UL
60#define SEP_ROM_BANK_register 0x80008420UL
61#define SEP_ROM_BANK_register_offset 0x8420UL
62#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0x82000000
63
64/*
65 * THESE 2 definitions are specific to the board - must be
66 * defined during integration
67 */
68#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0xFF0D0000
69
70/* 2M size */
71
Alan Coxb10b4832009-08-07 19:23:26 +010072static void sep_load_rom_code(void)
Alan Cox0097a692009-08-07 19:23:19 +010073{
74 /* Index variables */
75 unsigned long i, k, j;
76 unsigned long regVal;
77 unsigned long Error;
78 unsigned long warning;
79
80 /* Loading ROM from SEP_ROM_image.h file */
81 k = sizeof(CRYS_SEP_ROM);
82
83 edbg("SEP Driver: DX_CC_TST_SepRomLoader start\n");
84
85 edbg("SEP Driver: k is %lu\n", k);
86 edbg("SEP Driver: sep_dev->reg_base_address is %p\n", sep_dev->reg_base_address);
87 edbg("SEP Driver: CRYS_SEP_ROM_start_address_offset is %p\n", CRYS_SEP_ROM_start_address_offset);
88
89 for (i = 0; i < 4; i++) {
90 /* write bank */
91 sep_write_reg(sep_dev, SEP_ROM_BANK_register_offset, i);
92
93 for (j = 0; j < CRYS_SEP_ROM_length / 4; j++) {
94 sep_write_reg(sep_dev, CRYS_SEP_ROM_start_address_offset + 4 * j, CRYS_SEP_ROM[i * 0x1000 + j]);
95
96 k = k - 4;
97
98 if (k == 0) {
99 j = CRYS_SEP_ROM_length;
100 i = 4;
101 }
102 }
103 }
104
105 /* reset the SEP */
106 sep_write_reg(sep_dev, HW_HOST_SEP_SW_RST_REG_ADDR, 0x1);
107
108 /* poll for SEP ROM boot finish */
109 do {
110 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
111 } while (!regVal);
112
113 edbg("SEP Driver: ROM polling ended\n");
114
115 switch (regVal) {
116 case 0x1:
117 /* fatal error - read erro status from GPRO */
118 Error = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
119 edbg("SEP Driver: ROM polling case 1\n");
120 break;
121 case 0x2:
122 /* Boot First Phase ended */
123 warning = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
124 edbg("SEP Driver: ROM polling case 2\n");
125 break;
126 case 0x4:
127 /* Cold boot ended successfully */
128 warning = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
129 edbg("SEP Driver: ROM polling case 4\n");
130 Error = 0;
131 break;
132 case 0x8:
133 /* Warmboot ended successfully */
134 warning = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
135 edbg("SEP Driver: ROM polling case 8\n");
136 Error = 0;
137 break;
138 case 0x10:
139 /* ColdWarm boot ended successfully */
140 warning = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
141 edbg("SEP Driver: ROM polling case 16\n");
142 Error = 0;
143 break;
144 case 0x20:
145 edbg("SEP Driver: ROM polling case 32\n");
146 break;
147 }
148
149}
150
151#else
Alan Coxb10b4832009-08-07 19:23:26 +0100152static void sep_load_rom_code(void) { }
Alan Cox0097a692009-08-07 19:23:19 +0100153#endif /* SEP_DRIVER_ARM_DEBUG_MODE */
154
155
156
Mark Allyncd1bb432009-08-06 20:43:59 +0100157/*----------------------------------------
158 DEFINES
159-----------------------------------------*/
160
Alan Coxb10b4832009-08-07 19:23:26 +0100161#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
Alan Cox0097a692009-08-07 19:23:19 +0100162#define BASE_ADDRESS_FOR_SYSTEM 0xfffc0000
163#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000
Mark Allyncd1bb432009-08-06 20:43:59 +0100164
165/*--------------------------------------------
166 GLOBAL variables
167--------------------------------------------*/
168
169/* debug messages level */
170INT_MODULE_PARM(sepDebug, 0x0);
171MODULE_PARM_DESC(sepDebug, "Flag to enable SEP debug messages");
172
Alan Cox0097a692009-08-07 19:23:19 +0100173/* Keep this a single static object for now to keep the conversion easy */
174
175static struct sep_device sep_instance;
Alan Coxb10b4832009-08-07 19:23:26 +0100176static struct sep_device *sep_dev = &sep_instance;
Alan Cox0097a692009-08-07 19:23:19 +0100177
Mark Allyncd1bb432009-08-06 20:43:59 +0100178/*
179 mutex for the access to the internals of the sep driver
180*/
181static DEFINE_MUTEX(sep_mutex);
182
183
184/* wait queue head (event) of the driver */
Alan Coxf5e39802009-08-06 20:45:07 +0100185static DECLARE_WAIT_QUEUE_HEAD(g_sep_event);
Mark Allyncd1bb432009-08-06 20:43:59 +0100186
187
Mark Allyncd1bb432009-08-06 20:43:59 +0100188
189/*------------------------------------------------
190 PROTOTYPES
191---------------------------------------------------*/
192
193/*
Mark Allyncd1bb432009-08-06 20:43:59 +0100194 this function registers the driver to the file system
195*/
Alan Coxd19cf322009-08-06 20:45:57 +0100196static int sep_register_driver_to_fs(void);
Mark Allyncd1bb432009-08-06 20:43:59 +0100197
198/*
Mark Allyncd1bb432009-08-06 20:43:59 +0100199 this function calculates the size of data that can be inserted into the lli
200 table from this array the condition is that either the table is full
201 (all etnries are entered), or there are no more entries in the lli array
202*/
Alan Coxd19cf322009-08-06 20:45:57 +0100203static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries);
Mark Allyncd1bb432009-08-06 20:43:59 +0100204/*
205 this functions builds ont lli table from the lli_array according to the
206 given size of data
207*/
Alan Coxd19cf322009-08-06 20:45:57 +0100208static 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100209
210/*
211 this function goes over the list of the print created tables and prints
212 all the data
213*/
Alan Coxd19cf322009-08-06 20:45:57 +0100214static void sep_debug_print_lli_tables(struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100215
216
217
218/*
219 This function raises interrupt to SEPm that signals that is has a new
220 command from HOST
221*/
222static void sep_send_command_handler(void);
223
224
225/*
226 This function raises interrupt to SEP that signals that is has a
227 new reply from HOST
228*/
229static void sep_send_reply_command_handler(void);
230
231/*
232 This function handles the allocate data pool memory request
233 This function returns calculates the physical address of the allocated memory
234 and the offset of this area from the mapped address. Therefore, the FVOs in
235 user space can calculate the exact virtual address of this allocated memory
236*/
237static int sep_allocate_data_pool_memory_handler(unsigned long arg);
238
239
240/*
241 This function handles write into allocated data pool command
242*/
243static int sep_write_into_data_pool_handler(unsigned long arg);
244
245/*
246 this function handles the read from data pool command
247*/
248static int sep_read_from_data_pool_handler(unsigned long arg);
249
250/*
251 this function handles tha request for creation of the DMA table
252 for the synchronic symmetric operations (AES,DES)
253*/
254static int sep_create_sync_dma_tables_handler(unsigned long arg);
255
256/*
257 this function handles the request to create the DMA tables for flow
258*/
259static int sep_create_flow_dma_tables_handler(unsigned long arg);
260
261/*
262 This API handles the end transaction request
263*/
264static int sep_end_transaction_handler(unsigned long arg);
265
266
267/*
268 this function handles add tables to flow
269*/
270static int sep_add_flow_tables_handler(unsigned long arg);
271
272/*
273 this function add the flow add message to the specific flow
274*/
275static int sep_add_flow_tables_message_handler(unsigned long arg);
276
277/*
278 this function handles the request for SEP start
279*/
280static int sep_start_handler(void);
281
282/*
283 this function handles the request for SEP initialization
284*/
285static int sep_init_handler(unsigned long arg);
286
287/*
288 this function handles the request cache and resident reallocation
289*/
290static int sep_realloc_cache_resident_handler(unsigned long arg);
291
292
293/*
294 This api handles the setting of API mode to blocking or non-blocking
295*/
296static int sep_set_api_mode_handler(unsigned long arg);
297
Mark Allyncd1bb432009-08-06 20:43:59 +0100298/*
299 This function locks all the physical pages of the kernel virtual buffer
300 and construct a basic lli array, where each entry holds the physical
301 page address and the size that application data holds in this physical pages
302*/
Alan Coxd19cf322009-08-06 20:45:57 +0100303static 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100304
305/*
306 This function creates one DMA table for flow and returns its data,
307 and pointer to its info entry
308*/
Alan Coxd19cf322009-08-06 20:45:57 +0100309static 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100310
311/*
312 This function creates a list of tables for flow and returns the data for the
313 first and last tables of the list
314*/
Alan Coxd19cf322009-08-06 20:45:57 +0100315static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers,
316 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100317
318/*
319 this function find a space for the new flow dma table
320*/
Alan Coxd19cf322009-08-06 20:45:57 +0100321static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100322
323/*
324 this function goes over all the flow tables connected to the given table and
325 deallocate them
326*/
Alan Coxd19cf322009-08-06 20:45:57 +0100327static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100328
329/*
330 This function handler the set flow id command
331*/
332static int sep_set_flow_id_handler(unsigned long arg);
333
334/*
335 This function returns pointer to the flow data structure
336 that conatins the given id
337*/
Alan Coxd19cf322009-08-06 20:45:57 +0100338static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100339
340
341/*
342 this function returns the physical and virtual addresses of the static pool
343*/
344static int sep_get_static_pool_addr_handler(unsigned long arg);
345
346/*
347 this address gets the offset of the physical address from the start of
348 the mapped area
349*/
350static int sep_get_physical_mapped_offset_handler(unsigned long arg);
351
352
353/*
354 this function handles the request for get time
355*/
356static int sep_get_time_handler(unsigned long arg);
357
358/*
359 calculates time and sets it at the predefined address
360*/
Alan Coxd19cf322009-08-06 20:45:57 +0100361static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100362
363/*
364 PATCH for configuring the DMA to single burst instead of multi-burst
365*/
366static void sep_configure_dma_burst(void);
367
368/*
369 This function locks all the physical pages of the
370 application virtual buffer and construct a basic lli
371 array, where each entry holds the physical page address
372 and the size that application data holds in this physical pages
373*/
Alan Coxd19cf322009-08-06 20:45:57 +0100374static 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100375
376/*---------------------------------------------
377 FUNCTIONS
378-----------------------------------------------*/
379
380/*
Alan Cox0097a692009-08-07 19:23:19 +0100381 This functions copies the cache and resident from their source location into
382 destination memory, which is external to Linux VM and is given as
383 physical address
384*/
Alan Coxb10b4832009-08-07 19:23:26 +0100385static int sep_copy_cache_resident_to_area(unsigned long src_cache_addr, unsigned long cache_size_in_bytes, unsigned long src_resident_addr, unsigned long resident_size_in_bytes, unsigned long *dst_new_cache_addr_ptr, unsigned long *dst_new_resident_addr_ptr)
Alan Cox0097a692009-08-07 19:23:19 +0100386{
387 unsigned long resident_addr;
388 unsigned long cache_addr;
389 const struct firmware *fw;
390
391 char *cache_name = "cache.image.bin";
392 char *res_name = "resident.image.bin";
393
394 /* error */
395 int error;
396
397 /*--------------------------------
398 CODE
399 -------------------------------------*/
400 error = 0;
401
402 edbg("SEP Driver:rar_virtual is %p\n", sep_dev->rar_virtual_address);
403 edbg("SEP Driver:rar_physical is %08lx\n", sep_dev->rar_physical_address);
404
405 sep_dev->rar_region_addr = (unsigned long) sep_dev->rar_virtual_address;
406
407 sep_dev->cache_physical_address = sep_dev->rar_physical_address;
408 sep_dev->cache_virtual_address = sep_dev->rar_virtual_address;
409
410 /* load cache */
411 error = request_firmware(&fw, cache_name, &sep_dev->sep_pci_dev_ptr->dev);
412 if (error) {
413 edbg("SEP Driver:cant request cache fw\n");
414 goto end_function;
415 }
416
417 edbg("SEP Driver:cache data loc is %p\n", (void *) fw->data);
418 edbg("SEP Driver:cache data size is %08Zx\n", fw->size);
419
420 memcpy((void *) sep_dev->cache_virtual_address, (void *) fw->data, fw->size);
421
422 sep_dev->cache_size = fw->size;
423
424 cache_addr = (unsigned long) sep_dev->cache_virtual_address;
425
426 release_firmware(fw);
427
428 sep_dev->resident_physical_address = sep_dev->cache_physical_address + sep_dev->cache_size;
429 sep_dev->resident_virtual_address = sep_dev->cache_virtual_address + sep_dev->cache_size;
430
431 /* load resident */
432 error = request_firmware(&fw, res_name, &sep_dev->sep_pci_dev_ptr->dev);
433 if (error) {
434 edbg("SEP Driver:cant request res fw\n");
435 goto end_function;
436 }
437
438 edbg("SEP Driver:res data loc is %p\n", (void *) fw->data);
439 edbg("SEP Driver:res data size is %08Zx\n", fw->size);
440
441 memcpy((void *) sep_dev->resident_virtual_address, (void *) fw->data, fw->size);
442
443 sep_dev->resident_size = fw->size;
444
445 release_firmware(fw);
446
447 resident_addr = (unsigned long) sep_dev->resident_virtual_address;
448
449 edbg("SEP Driver:resident_addr (physical )is %08lx\n", sep_dev->resident_physical_address);
450 edbg("SEP Driver:cache_addr (physical) is %08lx\n", sep_dev->cache_physical_address);
451
452 edbg("SEP Driver:resident_addr (logical )is %08lx\n", resident_addr);
453 edbg("SEP Driver:cache_addr (logical) is %08lx\n", cache_addr);
454
455 edbg("SEP Driver:resident_size is %08lx\n", sep_dev->resident_size);
456 edbg("SEP Driver:cache_size is %08lx\n", sep_dev->cache_size);
457
458
459
460 /* physical addresses */
461 *dst_new_cache_addr_ptr = sep_dev->cache_physical_address;
462 *dst_new_resident_addr_ptr = sep_dev->resident_physical_address;
463end_function:
464 return error;
465}
466
467/*
468 This functions maps and allocates the
469 shared area on the external RAM (device)
470 The input is shared_area_size - the size of the memory to
471 allocate. The outputs
472 are kernel_shared_area_addr_ptr - the kerenl
473 address of the mapped and allocated
474 shared area, and phys_shared_area_addr_ptr
475 - the physical address of the shared area
476*/
Alan Coxb10b4832009-08-07 19:23:26 +0100477static int sep_map_and_alloc_shared_area(unsigned long shared_area_size, unsigned long *kernel_shared_area_addr_ptr, unsigned long *phys_shared_area_addr_ptr)
Alan Cox0097a692009-08-07 19:23:19 +0100478{
479 // shared_virtual_address = ioremap_nocache(0xda00000,shared_area_size);
480 sep_dev->shared_virtual_address = kmalloc(shared_area_size, GFP_KERNEL);
481 if (!sep_dev->shared_virtual_address) {
482 edbg("sep_driver:shared memory kmalloc failed\n");
483 return -1;
484 }
485 /* FIXME */
486 sep_dev->shared_physical_address = __pa(sep_dev->shared_virtual_address);
487 /* shared_physical_address = 0xda00000; */
488 *kernel_shared_area_addr_ptr = (unsigned long) sep_dev->shared_virtual_address;
489 /* set the physical address of the shared area */
490 *phys_shared_area_addr_ptr = sep_dev->shared_physical_address;
491 edbg("SEP Driver:shared_virtual_address is %p\n", sep_dev->shared_virtual_address);
492 edbg("SEP Driver:shared_region_size is %08lx\n", shared_area_size);
493 edbg("SEP Driver:shared_physical_addr is %08lx\n", *phys_shared_area_addr_ptr);
494
495 return 0;
496}
497
498/*
499 This functions unmaps and deallocates the shared area
500 on the external RAM (device)
501 The input is shared_area_size - the size of the memory to deallocate,kernel_
502 shared_area_addr_ptr - the kernel address of the mapped and allocated
503 shared area,phys_shared_area_addr_ptr - the physical address of
504 the shared area
505*/
Alan Coxb10b4832009-08-07 19:23:26 +0100506static void sep_unmap_and_free_shared_area(unsigned long shared_area_size, unsigned long kernel_shared_area_addr, unsigned long phys_shared_area_addr)
Alan Cox0097a692009-08-07 19:23:19 +0100507{
508 kfree((void *) kernel_shared_area_addr);
509}
510
511/*
512 This functions returns the physical address inside shared area according
513 to the virtual address. It can be either on the externa RAM device
514 (ioremapped), or on the system RAM
515 This implementation is for the external RAM
516*/
Alan Coxb10b4832009-08-07 19:23:26 +0100517static unsigned long sep_shared_area_virt_to_phys(unsigned long virt_address)
Alan Cox0097a692009-08-07 19:23:19 +0100518{
519 edbg("SEP Driver:sh virt to phys v %08lx\n", virt_address);
520 edbg("SEP Driver:sh virt to phys p %08lx\n", sep_dev->shared_physical_address + (virt_address - (unsigned long) sep_dev->shared_virtual_address));
521
522 return (unsigned long) sep_dev->shared_physical_address + (virt_address - (unsigned long) sep_dev->shared_virtual_address);
523}
524
525/*
526 This functions returns the virtual address inside shared area
527 according to the physical address. It can be either on the
528 externa RAM device (ioremapped), or on the system RAM This implementation
529 is for the external RAM
530*/
Alan Coxb10b4832009-08-07 19:23:26 +0100531static unsigned long sep_shared_area_phys_to_virt(unsigned long phys_address)
Alan Cox0097a692009-08-07 19:23:19 +0100532{
533 return (unsigned long) sep_dev->shared_virtual_address + (phys_address - sep_dev->shared_physical_address);
534}
535
536
Mark Allyncd1bb432009-08-06 20:43:59 +0100537/*----------------------------------------------------------------------
538 open function of the character driver - must only lock the mutex
539 must also release the memory data pool allocations
540------------------------------------------------------------------------*/
541static int sep_open(struct inode *inode_ptr, struct file *file_ptr)
542{
Alan Coxd19cf322009-08-06 20:45:57 +0100543 int error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100544
Alan Coxd19cf322009-08-06 20:45:57 +0100545 dbg("SEP Driver:--------> open start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100546
Alan Coxd19cf322009-08-06 20:45:57 +0100547 error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100548
Alan Coxd19cf322009-08-06 20:45:57 +0100549 /* check the blocking mode */
550 if (sep_dev->block_mode_flag)
551 /* lock mutex */
552 mutex_lock(&sep_mutex);
553 else
554 error = mutex_trylock(&sep_mutex);
Mark Allyncd1bb432009-08-06 20:43:59 +0100555
Alan Coxd19cf322009-08-06 20:45:57 +0100556 /* check the error */
557 if (error) {
558 edbg("SEP Driver: down_interruptible failed\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100559
Alan Coxd19cf322009-08-06 20:45:57 +0100560 goto end_function;
561 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100562
Alan Coxd19cf322009-08-06 20:45:57 +0100563 /* release data pool allocations */
564 sep_dev->data_pool_bytes_allocated = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100565
Alan Coxf93e4bf2009-08-06 20:46:08 +0100566end_function:
Alan Coxd19cf322009-08-06 20:45:57 +0100567 dbg("SEP Driver:<-------- open end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100568 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100569}
570
571
572
573
574/*------------------------------------------------------------
575 release function
576-------------------------------------------------------------*/
577static int sep_release(struct inode *inode_ptr, struct file *file_ptr)
578{
Alan Coxd19cf322009-08-06 20:45:57 +0100579 dbg("----------->SEP Driver: sep_release start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100580
Alan Coxd19cf322009-08-06 20:45:57 +0100581#if 0 /*!SEP_DRIVER_POLLING_MODE */
582 /* close IMR */
583 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF);
Mark Allyncd1bb432009-08-06 20:43:59 +0100584
Alan Coxd19cf322009-08-06 20:45:57 +0100585 /* release IRQ line */
586 free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address);
Mark Allyncd1bb432009-08-06 20:43:59 +0100587
588#endif
589
Alan Coxd19cf322009-08-06 20:45:57 +0100590 /* unlock the sep mutex */
591 mutex_unlock(&sep_mutex);
Mark Allyncd1bb432009-08-06 20:43:59 +0100592
Alan Coxd19cf322009-08-06 20:45:57 +0100593 dbg("SEP Driver:<-------- sep_release end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100594
Alan Coxd19cf322009-08-06 20:45:57 +0100595 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100596}
597
598
599
600
601/*---------------------------------------------------------------
602 map function - this functions maps the message shared area
603-----------------------------------------------------------------*/
Alan Coxd19cf322009-08-06 20:45:57 +0100604static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
Mark Allyncd1bb432009-08-06 20:43:59 +0100605{
Alan Coxd19cf322009-08-06 20:45:57 +0100606 unsigned long phys_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +0100607
Alan Coxd19cf322009-08-06 20:45:57 +0100608 dbg("-------->SEP Driver: mmap start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100609
Alan Coxd19cf322009-08-06 20:45:57 +0100610 /* check that the size of the mapped range is as the size of the message
611 shared area */
612 if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
613 edbg("SEP Driver mmap requested size is more than allowed\n");
614 printk(KERN_WARNING "SEP Driver mmap requested size is more \
Mark Allyncd1bb432009-08-06 20:43:59 +0100615 than allowed\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100616 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end);
617 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start);
618 return -EAGAIN;
619 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100620
Alan Coxd19cf322009-08-06 20:45:57 +0100621 edbg("SEP Driver:g_message_shared_area_addr is %08lx\n", sep_dev->message_shared_area_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100622
Alan Coxd19cf322009-08-06 20:45:57 +0100623 /* get physical address */
624 phys_addr = sep_dev->phys_shared_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +0100625
Alan Coxd19cf322009-08-06 20:45:57 +0100626 edbg("SEP Driver: phys_addr is %08lx\n", phys_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100627
Alan Coxd19cf322009-08-06 20:45:57 +0100628 if (remap_pfn_range(vma, vma->vm_start, phys_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
629 edbg("SEP Driver remap_page_range failed\n");
630 printk(KERN_WARNING "SEP Driver remap_page_range failed\n");
631 return -EAGAIN;
632 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100633
Alan Coxd19cf322009-08-06 20:45:57 +0100634 dbg("SEP Driver:<-------- mmap end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100635
Alan Coxd19cf322009-08-06 20:45:57 +0100636 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100637}
638
639
640/*-----------------------------------------------
641 poll function
642*----------------------------------------------*/
Alan Coxd19cf322009-08-06 20:45:57 +0100643static unsigned int sep_poll(struct file *filp, poll_table * wait)
Mark Allyncd1bb432009-08-06 20:43:59 +0100644{
Alan Coxd19cf322009-08-06 20:45:57 +0100645 unsigned long count;
Alan Coxd19cf322009-08-06 20:45:57 +0100646 unsigned int mask = 0;
Alan Coxf93e4bf2009-08-06 20:46:08 +0100647 unsigned long retVal = 0; /* flow id */
Mark Allyncd1bb432009-08-06 20:43:59 +0100648
Alan Coxd19cf322009-08-06 20:45:57 +0100649 dbg("---------->SEP Driver poll: start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100650
651
652#if SEP_DRIVER_POLLING_MODE
653
Alan Coxd19cf322009-08-06 20:45:57 +0100654 while (sep_dev->host_to_sep_send_counter != (retVal & 0x7FFFFFFF)) {
655 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
Mark Allyncd1bb432009-08-06 20:43:59 +0100656
Alan Coxd19cf322009-08-06 20:45:57 +0100657 for (count = 0; count < 10 * 4; count += 4)
658 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)));
659 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100660
Alan Coxd19cf322009-08-06 20:45:57 +0100661 sep_dev->sep_to_host_reply_counter++;
Mark Allyncd1bb432009-08-06 20:43:59 +0100662#else
Alan Coxd19cf322009-08-06 20:45:57 +0100663 /* add the event to the polling wait table */
664 poll_wait(filp, &g_sep_event, wait);
Mark Allyncd1bb432009-08-06 20:43:59 +0100665
666#endif
667
Alan Coxd19cf322009-08-06 20:45:57 +0100668 edbg("sep_dev->host_to_sep_send_counter is %lu\n", sep_dev->host_to_sep_send_counter);
669 edbg("sep_dev->sep_to_host_reply_counter is %lu\n", sep_dev->sep_to_host_reply_counter);
Mark Allyncd1bb432009-08-06 20:43:59 +0100670
Alan Coxd19cf322009-08-06 20:45:57 +0100671 /* check if the data is ready */
672 if (sep_dev->host_to_sep_send_counter == sep_dev->sep_to_host_reply_counter) {
673 for (count = 0; count < 12 * 4; count += 4)
674 edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +0100675
Alan Coxd19cf322009-08-06 20:45:57 +0100676 for (count = 0; count < 10 * 4; count += 4)
677 edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + 0x1800 + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +0100678
Alan Coxd19cf322009-08-06 20:45:57 +0100679 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
680 edbg("retVal is %lu\n", retVal);
681 /* check if the this is sep reply or request */
682 if (retVal >> 31) {
683 edbg("SEP Driver: sep request in\n");
684 /* request */
685 mask |= POLLOUT | POLLWRNORM;
686 } else {
687 edbg("SEP Driver: sep reply in\n");
688 mask |= POLLIN | POLLRDNORM;
689 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100690 }
Alan Coxd19cf322009-08-06 20:45:57 +0100691 dbg("SEP Driver:<-------- poll exit\n");
692 return mask;
Mark Allyncd1bb432009-08-06 20:43:59 +0100693}
694
695
Alan Coxd19cf322009-08-06 20:45:57 +0100696static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +0100697{
Alan Coxf93e4bf2009-08-06 20:46:08 +0100698 int error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100699
Alan Coxd19cf322009-08-06 20:45:57 +0100700 dbg("------------>SEP Driver: ioctl start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100701
Alan Coxd19cf322009-08-06 20:45:57 +0100702 edbg("SEP Driver: cmd is %x\n", cmd);
Mark Allyncd1bb432009-08-06 20:43:59 +0100703
Alan Coxd19cf322009-08-06 20:45:57 +0100704 /* check that the command is for sep device */
705 if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER)
706 error = -ENOTTY;
Mark Allyncd1bb432009-08-06 20:43:59 +0100707
708 switch (cmd) {
709 case SEP_IOCSENDSEPCOMMAND:
Alan Coxd19cf322009-08-06 20:45:57 +0100710 /* send command to SEP */
711 sep_send_command_handler();
Alan Coxd19cf322009-08-06 20:45:57 +0100712 edbg("SEP Driver: after sep_send_command_handler\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100713 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100714 case SEP_IOCSENDSEPRPLYCOMMAND:
Alan Coxd19cf322009-08-06 20:45:57 +0100715 /* send reply command to SEP */
716 sep_send_reply_command_handler();
Alan Coxd19cf322009-08-06 20:45:57 +0100717 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100718 case SEP_IOCALLOCDATAPOLL:
Alan Coxd19cf322009-08-06 20:45:57 +0100719 /* allocate data pool */
720 error = sep_allocate_data_pool_memory_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100721 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100722 case SEP_IOCWRITEDATAPOLL:
Alan Coxd19cf322009-08-06 20:45:57 +0100723 /* write data into memory pool */
724 error = sep_write_into_data_pool_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100725 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100726 case SEP_IOCREADDATAPOLL:
Alan Coxd19cf322009-08-06 20:45:57 +0100727 /* read data from data pool into application memory */
728 error = sep_read_from_data_pool_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100729 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100730 case SEP_IOCCREATESYMDMATABLE:
Alan Coxd19cf322009-08-06 20:45:57 +0100731 /* create dma table for synhronic operation */
732 error = sep_create_sync_dma_tables_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100733 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100734 case SEP_IOCCREATEFLOWDMATABLE:
Alan Coxd19cf322009-08-06 20:45:57 +0100735 /* create flow dma tables */
736 error = sep_create_flow_dma_tables_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100737 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100738 case SEP_IOCFREEDMATABLEDATA:
Alan Coxd19cf322009-08-06 20:45:57 +0100739 /* free the pages */
740 error = sep_free_dma_table_data_handler();
Alan Coxd19cf322009-08-06 20:45:57 +0100741 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100742 case SEP_IOCSETFLOWID:
Alan Coxd19cf322009-08-06 20:45:57 +0100743 /* set flow id */
744 error = sep_set_flow_id_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100745 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100746 case SEP_IOCADDFLOWTABLE:
Alan Coxd19cf322009-08-06 20:45:57 +0100747 /* add tables to the dynamic flow */
748 error = sep_add_flow_tables_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100749 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100750 case SEP_IOCADDFLOWMESSAGE:
Alan Coxd19cf322009-08-06 20:45:57 +0100751 /* add message of add tables to flow */
752 error = sep_add_flow_tables_message_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100753 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100754 case SEP_IOCSEPSTART:
Alan Coxd19cf322009-08-06 20:45:57 +0100755 /* start command to sep */
756 error = sep_start_handler();
757 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100758 case SEP_IOCSEPINIT:
Alan Coxd19cf322009-08-06 20:45:57 +0100759 /* init command to sep */
760 error = sep_init_handler(arg);
761 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100762 case SEP_IOCSETAPIMODE:
Alan Coxd19cf322009-08-06 20:45:57 +0100763 /* set non- blocking mode */
764 error = sep_set_api_mode_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100765 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100766 case SEP_IOCGETSTATICPOOLADDR:
Mark Allyncd1bb432009-08-06 20:43:59 +0100767 /* get the physical and virtual addresses of the static pool */
768 error = sep_get_static_pool_addr_handler(arg);
Mark Allyncd1bb432009-08-06 20:43:59 +0100769 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100770 case SEP_IOCENDTRANSACTION:
Alan Coxd19cf322009-08-06 20:45:57 +0100771 error = sep_end_transaction_handler(arg);
Mark Allyncd1bb432009-08-06 20:43:59 +0100772 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100773 case SEP_IOCREALLOCCACHERES:
Alan Coxd19cf322009-08-06 20:45:57 +0100774 error = sep_realloc_cache_resident_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100775 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100776 case SEP_IOCGETMAPPEDADDROFFSET:
Alan Coxd19cf322009-08-06 20:45:57 +0100777 error = sep_get_physical_mapped_offset_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100778 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100779 case SEP_IOCGETIME:
Alan Coxd19cf322009-08-06 20:45:57 +0100780 error = sep_get_time_handler(arg);
Alan Coxd19cf322009-08-06 20:45:57 +0100781 break;
Mark Allyncd1bb432009-08-06 20:43:59 +0100782 default:
Alan Coxd19cf322009-08-06 20:45:57 +0100783 error = -ENOTTY;
784 break;
785 }
Alan Coxd19cf322009-08-06 20:45:57 +0100786 dbg("SEP Driver:<-------- ioctl end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100787 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100788}
789
790
Mark Allyncd1bb432009-08-06 20:43:59 +0100791
Alan Coxb6368032009-08-07 19:23:34 +0100792#if !SEP_DRIVER_POLLING_MODE
793
794/* handler for flow done interrupt */
795
796static void sep_flow_done_handler(struct work_struct *work)
797{
798 struct sep_flow_context_t *flow_data_ptr;
799
800 /* obtain the mutex */
801 mutex_lock(&sep_mutex);
802
803 /* get the pointer to context */
804 flow_data_ptr = (struct sep_flow_context_t *) work;
805
806 /* free all the current input tables in sep */
807 sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process);
808
809 /* free all the current tables output tables in SEP (if needed) */
810 if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff)
811 sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process);
812
813 /* check if we have additional tables to be sent to SEP only input
814 flag may be checked */
815 if (flow_data_ptr->input_tables_flag) {
816 /* copy the message to the shared RAM and signal SEP */
817 memcpy((void *) flow_data_ptr->message, (void *) sep_dev->shared_area_addr, flow_data_ptr->message_size_in_bytes);
818
819 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2);
820 }
821 mutex_unlock(&sep_mutex);
822}
Mark Allyncd1bb432009-08-06 20:43:59 +0100823/*
824 interrupt handler function
825*/
Alan Coxb10b4832009-08-07 19:23:26 +0100826static irqreturn_t sep_inthandler(int irq, void *dev_id)
Mark Allyncd1bb432009-08-06 20:43:59 +0100827{
Alan Coxd19cf322009-08-06 20:45:57 +0100828 irqreturn_t int_error;
Alan Coxd19cf322009-08-06 20:45:57 +0100829 unsigned long error;
Alan Coxd19cf322009-08-06 20:45:57 +0100830 unsigned long reg_val;
Alan Coxd19cf322009-08-06 20:45:57 +0100831 unsigned long flow_id;
Alan Coxd19cf322009-08-06 20:45:57 +0100832 struct sep_flow_context_t *flow_context_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +0100833
Alan Coxd19cf322009-08-06 20:45:57 +0100834 int_error = IRQ_HANDLED;
Mark Allyncd1bb432009-08-06 20:43:59 +0100835
Alan Coxd19cf322009-08-06 20:45:57 +0100836 /* read the IRR register to check if this is SEP interrupt */
837 reg_val = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR);
838 edbg("SEP Interrupt - reg is %08lx\n", reg_val);
Mark Allyncd1bb432009-08-06 20:43:59 +0100839
Alan Coxd19cf322009-08-06 20:45:57 +0100840 /* check if this is the flow interrupt */
841 if (0 /*reg_val & (0x1 << 11) */ ) {
842 /* read GPRO to find out the which flow is done */
843 flow_id = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR);
Mark Allyncd1bb432009-08-06 20:43:59 +0100844
Alan Coxd19cf322009-08-06 20:45:57 +0100845 /* find the contex of the flow */
846 error = sep_find_flow_context(flow_id >> 28, &flow_context_ptr);
847 if (error)
848 goto end_function_with_error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100849
Alan Coxd19cf322009-08-06 20:45:57 +0100850 INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler);
Mark Allyncd1bb432009-08-06 20:43:59 +0100851
Alan Coxd19cf322009-08-06 20:45:57 +0100852 /* queue the work */
853 queue_work(sep_dev->flow_wq_ptr, &flow_context_ptr->flow_wq);
Mark Allyncd1bb432009-08-06 20:43:59 +0100854
Mark Allyncd1bb432009-08-06 20:43:59 +0100855 } else {
Alan Coxd19cf322009-08-06 20:45:57 +0100856 /* check if this is reply interrupt from SEP */
857 if (reg_val & (0x1 << 13)) {
858 /* update the counter of reply messages */
859 sep_dev->sep_to_host_reply_counter++;
860
861 /* wake up the waiting process */
862 wake_up(&g_sep_event);
863 } else {
864 int_error = IRQ_NONE;
865 goto end_function;
866 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100867 }
Alan Coxf93e4bf2009-08-06 20:46:08 +0100868end_function_with_error:
Alan Coxd19cf322009-08-06 20:45:57 +0100869 /* clear the interrupt */
870 sep_write_reg(sep_dev, HW_HOST_ICR_REG_ADDR, reg_val);
Alan Coxf93e4bf2009-08-06 20:46:08 +0100871end_function:
Alan Coxd19cf322009-08-06 20:45:57 +0100872 return int_error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100873}
874
Alan Coxb6368032009-08-07 19:23:34 +0100875#endif
Mark Allyncd1bb432009-08-06 20:43:59 +0100876
877/*
878 This function prepares only input DMA table for synhronic symmetric
879 operations (HASH)
880*/
Alan Coxb10b4832009-08-07 19:23:26 +0100881static int 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)
Mark Allyncd1bb432009-08-06 20:43:59 +0100882{
Alan Coxd19cf322009-08-06 20:45:57 +0100883 /* pointer to the info entry of the table - the last entry */
884 struct sep_lli_entry_t *info_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +0100885 /* array of pointers ot page */
886 struct sep_lli_entry_t *lli_array_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +0100887 /* points to the first entry to be processed in the lli_in_array */
888 unsigned long current_entry;
Alan Coxd19cf322009-08-06 20:45:57 +0100889 /* num entries in the virtual buffer */
890 unsigned long sep_lli_entries;
Alan Coxd19cf322009-08-06 20:45:57 +0100891 /* lli table pointer */
892 struct sep_lli_entry_t *in_lli_table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +0100893 /* the total data in one table */
894 unsigned long table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +0100895 /* number of entries in lli table */
896 unsigned long num_entries_in_table;
Alan Coxd19cf322009-08-06 20:45:57 +0100897 /* next table address */
898 unsigned long lli_table_alloc_addr;
Alan Coxd19cf322009-08-06 20:45:57 +0100899 unsigned long result;
Mark Allyncd1bb432009-08-06 20:43:59 +0100900
Alan Coxd19cf322009-08-06 20:45:57 +0100901 dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100902
Alan Coxd19cf322009-08-06 20:45:57 +0100903 edbg("SEP Driver:data_size is %lu\n", data_size);
904 edbg("SEP Driver:block_size is %lu\n", block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100905
Alan Coxd19cf322009-08-06 20:45:57 +0100906 /* initialize the pages pointers */
907 sep_dev->in_page_array = 0;
908 sep_dev->in_num_pages = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100909
Alan Coxd19cf322009-08-06 20:45:57 +0100910 if (data_size == 0) {
911 /* special case - created 2 entries table with zero data */
912 in_lli_table_ptr = (struct sep_lli_entry_t *) (sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES);
913 in_lli_table_ptr->physical_address = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
914 in_lli_table_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100915
Alan Coxd19cf322009-08-06 20:45:57 +0100916 in_lli_table_ptr++;
917 in_lli_table_ptr->physical_address = 0xFFFFFFFF;
918 in_lli_table_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100919
Alan Coxd19cf322009-08-06 20:45:57 +0100920 *lli_table_ptr = sep_dev->phys_shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
921 *num_entries_ptr = 2;
922 *table_data_size_ptr = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100923
Alan Coxd19cf322009-08-06 20:45:57 +0100924 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +0100925 }
926
Alan Coxd19cf322009-08-06 20:45:57 +0100927 /* check if the pages are in Kernel Virtual Address layout */
928 if (isKernelVirtualAddress == true)
929 /* lock the pages of the kernel buffer and translate them to pages */
930 result = sep_lock_kernel_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array);
931 else
932 /* lock the pages of the user buffer and translate them to pages */
933 result = sep_lock_user_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array);
Mark Allyncd1bb432009-08-06 20:43:59 +0100934
Alan Coxd19cf322009-08-06 20:45:57 +0100935 if (result)
936 return result;
Mark Allyncd1bb432009-08-06 20:43:59 +0100937
Alan Coxd19cf322009-08-06 20:45:57 +0100938 edbg("SEP Driver:output sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages);
Mark Allyncd1bb432009-08-06 20:43:59 +0100939
Alan Coxd19cf322009-08-06 20:45:57 +0100940 current_entry = 0;
941 info_entry_ptr = 0;
942 sep_lli_entries = sep_dev->in_num_pages;
Mark Allyncd1bb432009-08-06 20:43:59 +0100943
Alan Coxd19cf322009-08-06 20:45:57 +0100944 /* initiate to point after the message area */
945 lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +0100946
Alan Coxd19cf322009-08-06 20:45:57 +0100947 /* loop till all the entries in in array are not processed */
948 while (current_entry < sep_lli_entries) {
949 /* set the new input and output tables */
950 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
951
952 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
953
954 /* calculate the maximum size of data for input table */
955 table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry));
956
957 /* now calculate the table size so that it will be module block size */
958 table_data_size = (table_data_size / block_size) * block_size;
959
960 edbg("SEP Driver:output table_data_size is %lu\n", table_data_size);
961
962 /* construct input lli table */
963 sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, &current_entry, &num_entries_in_table, table_data_size);
964
965 if (info_entry_ptr == 0) {
966 /* set the output parameters to physical addresses */
967 *lli_table_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
968 *num_entries_ptr = num_entries_in_table;
969 *table_data_size_ptr = table_data_size;
970
971 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr);
972 } else {
973 /* update the info entry of the previous in table */
974 info_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
975 info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
976 }
977
978 /* save the pointer to the info entry of the current tables */
979 info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
980 }
981
982 /* print input tables */
983 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
984 sep_shared_area_phys_to_virt(*lli_table_ptr), *num_entries_ptr, *table_data_size_ptr);
985
986 /* the array of the pages */
987 kfree(lli_array_ptr);
Alan Coxf93e4bf2009-08-06 20:46:08 +0100988end_function:
Alan Coxd19cf322009-08-06 20:45:57 +0100989 dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100990 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100991
992}
993
994/*
995 This function builds input and output DMA tables for synhronic
996 symmetric operations (AES, DES). It also checks that each table
997 is of the modular block size
998*/
Alan Coxb10b4832009-08-07 19:23:26 +0100999static int sep_prepare_input_output_dma_table(unsigned long app_virt_in_addr,
Alan Coxd19cf322009-08-06 20:45:57 +01001000 unsigned long app_virt_out_addr,
1001 unsigned long data_size,
1002 unsigned long block_size,
1003 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001004{
Alan Coxd19cf322009-08-06 20:45:57 +01001005 /* array of pointers of page */
1006 struct sep_lli_entry_t *lli_in_array;
Alan Coxd19cf322009-08-06 20:45:57 +01001007 /* array of pointers of page */
1008 struct sep_lli_entry_t *lli_out_array;
Alan Coxf93e4bf2009-08-06 20:46:08 +01001009 int result = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001010
Alan Coxd19cf322009-08-06 20:45:57 +01001011 dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001012
Alan Coxd19cf322009-08-06 20:45:57 +01001013 /* initialize the pages pointers */
1014 sep_dev->in_page_array = 0;
1015 sep_dev->out_page_array = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001016
Alan Coxd19cf322009-08-06 20:45:57 +01001017 /* check if the pages are in Kernel Virtual Address layout */
1018 if (isKernelVirtualAddress == true) {
1019 /* lock the pages of the kernel buffer and translate them to pages */
1020 result = sep_lock_kernel_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array);
1021 if (result) {
1022 edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n");
1023 goto end_function;
1024 }
1025 } else {
1026 /* lock the pages of the user buffer and translate them to pages */
1027 result = sep_lock_user_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array);
1028 if (result) {
1029 edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n");
1030 goto end_function;
1031 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001032 }
Alan Coxd19cf322009-08-06 20:45:57 +01001033
1034 if (isKernelVirtualAddress == true) {
1035 result = sep_lock_kernel_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array);
1036 if (result) {
1037 edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n");
1038 goto end_function_with_error1;
1039 }
1040 } else {
1041 result = sep_lock_user_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array);
1042 if (result) {
1043 edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n");
1044 goto end_function_with_error1;
1045 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001046 }
Alan Coxd19cf322009-08-06 20:45:57 +01001047 edbg("sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages);
1048 edbg("sep_dev->out_num_pages is %lu\n", sep_dev->out_num_pages);
1049 edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
1050
1051
1052 /* call the fucntion that creates table from the lli arrays */
1053 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);
Mark Allyncd1bb432009-08-06 20:43:59 +01001054 if (result) {
Alan Coxd19cf322009-08-06 20:45:57 +01001055 edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n");
1056 goto end_function_with_error2;
Mark Allyncd1bb432009-08-06 20:43:59 +01001057 }
Alan Coxd19cf322009-08-06 20:45:57 +01001058
1059 /* fall through - free the lli entry arrays */
Alan Coxd19cf322009-08-06 20:45:57 +01001060 dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr);
1061 dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr);
1062 dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001063end_function_with_error2:
Alan Coxd19cf322009-08-06 20:45:57 +01001064 kfree(lli_out_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001065end_function_with_error1:
Alan Coxd19cf322009-08-06 20:45:57 +01001066 kfree(lli_in_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001067end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001068 dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result);
Alan Coxd19cf322009-08-06 20:45:57 +01001069 return result;
Mark Allyncd1bb432009-08-06 20:43:59 +01001070
1071}
1072
1073
1074/*
1075 This function creates the input and output dma tables for
1076 symmetric operations (AES/DES) according to the block size from LLI arays
1077*/
Alan Coxb10b4832009-08-07 19:23:26 +01001078static int sep_construct_dma_tables_from_lli(struct sep_lli_entry_t *lli_in_array,
Alan Coxd19cf322009-08-06 20:45:57 +01001079 unsigned long sep_in_lli_entries,
1080 struct sep_lli_entry_t *lli_out_array,
1081 unsigned long sep_out_lli_entries,
1082 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001083{
Alan Coxd19cf322009-08-06 20:45:57 +01001084 /* points to the area where next lli table can be allocated */
1085 unsigned long lli_table_alloc_addr;
Alan Coxd19cf322009-08-06 20:45:57 +01001086 /* input lli table */
1087 struct sep_lli_entry_t *in_lli_table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001088 /* output lli table */
1089 struct sep_lli_entry_t *out_lli_table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001090 /* pointer to the info entry of the table - the last entry */
1091 struct sep_lli_entry_t *info_in_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001092 /* pointer to the info entry of the table - the last entry */
1093 struct sep_lli_entry_t *info_out_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001094 /* points to the first entry to be processed in the lli_in_array */
1095 unsigned long current_in_entry;
Alan Coxd19cf322009-08-06 20:45:57 +01001096 /* points to the first entry to be processed in the lli_out_array */
1097 unsigned long current_out_entry;
Alan Coxd19cf322009-08-06 20:45:57 +01001098 /* max size of the input table */
1099 unsigned long in_table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +01001100 /* max size of the output table */
1101 unsigned long out_table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +01001102 /* flag te signifies if this is the first tables build from the arrays */
1103 unsigned long first_table_flag;
Alan Coxd19cf322009-08-06 20:45:57 +01001104 /* the data size that should be in table */
1105 unsigned long table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +01001106 /* number of etnries in the input table */
1107 unsigned long num_entries_in_table;
Alan Coxd19cf322009-08-06 20:45:57 +01001108 /* number of etnries in the output table */
1109 unsigned long num_entries_out_table;
Mark Allyncd1bb432009-08-06 20:43:59 +01001110
Alan Coxd19cf322009-08-06 20:45:57 +01001111 dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001112
Alan Coxd19cf322009-08-06 20:45:57 +01001113 /* initiate to pint after the message area */
1114 lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01001115
Alan Coxd19cf322009-08-06 20:45:57 +01001116 current_in_entry = 0;
1117 current_out_entry = 0;
1118 first_table_flag = 1;
1119 info_in_entry_ptr = 0;
1120 info_out_entry_ptr = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001121
Alan Coxd19cf322009-08-06 20:45:57 +01001122 /* loop till all the entries in in array are not processed */
1123 while (current_in_entry < sep_in_lli_entries) {
1124 /* set the new input and output tables */
1125 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001126
Alan Coxd19cf322009-08-06 20:45:57 +01001127 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
Mark Allyncd1bb432009-08-06 20:43:59 +01001128
Alan Coxd19cf322009-08-06 20:45:57 +01001129 /* set the first output tables */
1130 out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001131
Alan Coxd19cf322009-08-06 20:45:57 +01001132 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
Mark Allyncd1bb432009-08-06 20:43:59 +01001133
Alan Coxd19cf322009-08-06 20:45:57 +01001134 /* calculate the maximum size of data for input table */
1135 in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry));
Mark Allyncd1bb432009-08-06 20:43:59 +01001136
Alan Coxd19cf322009-08-06 20:45:57 +01001137 /* calculate the maximum size of data for output table */
1138 out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry));
Mark Allyncd1bb432009-08-06 20:43:59 +01001139
Alan Coxd19cf322009-08-06 20:45:57 +01001140 edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size);
1141 edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001142
Alan Coxd19cf322009-08-06 20:45:57 +01001143 /* check where the data is smallest */
1144 table_data_size = in_table_data_size;
1145 if (table_data_size > out_table_data_size)
1146 table_data_size = out_table_data_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001147
Alan Coxd19cf322009-08-06 20:45:57 +01001148 /* now calculate the table size so that it will be module block size */
1149 table_data_size = (table_data_size / block_size) * block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001150
Alan Coxd19cf322009-08-06 20:45:57 +01001151 dbg("SEP Driver:table_data_size is %lu\n", table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001152
Alan Coxd19cf322009-08-06 20:45:57 +01001153 /* construct input lli table */
1154 sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, &current_in_entry, &num_entries_in_table, table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001155
Alan Coxd19cf322009-08-06 20:45:57 +01001156 /* construct output lli table */
1157 sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, &current_out_entry, &num_entries_out_table, table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001158
Alan Coxd19cf322009-08-06 20:45:57 +01001159 /* if info entry is null - this is the first table built */
1160 if (info_in_entry_ptr == 0) {
1161 /* set the output parameters to physical addresses */
1162 *lli_table_in_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
1163 *in_num_entries_ptr = num_entries_in_table;
1164 *lli_table_out_ptr = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr);
1165 *out_num_entries_ptr = num_entries_out_table;
1166 *table_data_size_ptr = table_data_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001167
Alan Coxd19cf322009-08-06 20:45:57 +01001168 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr);
1169 edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr);
1170 } else {
1171 /* update the info entry of the previous in table */
1172 info_in_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr);
1173 info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001174
Alan Coxd19cf322009-08-06 20:45:57 +01001175 /* update the info entry of the previous in table */
1176 info_out_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr);
1177 info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size);
1178 }
1179
1180 /* save the pointer to the info entry of the current tables */
1181 info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
1182 info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1;
1183
1184 edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table);
1185 edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr);
1186 edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01001187 }
1188
Alan Coxd19cf322009-08-06 20:45:57 +01001189 /* print input tables */
1190 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
1191 sep_shared_area_phys_to_virt(*lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01001192 /* print output tables */
1193 sep_debug_print_lli_tables((struct sep_lli_entry_t *)
1194 sep_shared_area_phys_to_virt(*lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01001195 dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001196 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001197}
1198
1199/*
1200 this function calculates the size of data that can be inserted into the lli
1201 table from this array the condition is that either the table is full
1202 (all etnries are entered), or there are no more entries in the lli array
1203*/
Alan Coxb10b4832009-08-07 19:23:26 +01001204static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries)
Mark Allyncd1bb432009-08-06 20:43:59 +01001205{
Alan Coxf93e4bf2009-08-06 20:46:08 +01001206 unsigned long table_data_size = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01001207 unsigned long counter;
Mark Allyncd1bb432009-08-06 20:43:59 +01001208
Alan Coxd19cf322009-08-06 20:45:57 +01001209 /* calculate the data in the out lli table if till we fill the whole
1210 table or till the data has ended */
1211 for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++)
1212 table_data_size += lli_in_array_ptr[counter].block_size;
Alan Coxd19cf322009-08-06 20:45:57 +01001213 return table_data_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001214}
1215
1216/*
1217 this functions builds ont lli table from the lli_array according to
1218 the given size of data
1219*/
Alan Coxd19cf322009-08-06 20:45:57 +01001220static 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001221{
Alan Coxd19cf322009-08-06 20:45:57 +01001222 unsigned long curr_table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +01001223 /* counter of lli array entry */
1224 unsigned long array_counter;
Mark Allyncd1bb432009-08-06 20:43:59 +01001225
Alan Coxd19cf322009-08-06 20:45:57 +01001226 dbg("SEP Driver:--------> sep_build_lli_table start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001227
Alan Coxd19cf322009-08-06 20:45:57 +01001228 /* init currrent table data size and lli array entry counter */
1229 curr_table_data_size = 0;
1230 array_counter = 0;
1231 *num_table_entries_ptr = 1;
Mark Allyncd1bb432009-08-06 20:43:59 +01001232
Alan Coxd19cf322009-08-06 20:45:57 +01001233 edbg("SEP Driver:table_data_size is %lu\n", table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001234
Alan Coxd19cf322009-08-06 20:45:57 +01001235 /* fill the table till table size reaches the needed amount */
1236 while (curr_table_data_size < table_data_size) {
1237 /* update the number of entries in table */
1238 (*num_table_entries_ptr)++;
Mark Allyncd1bb432009-08-06 20:43:59 +01001239
Alan Coxd19cf322009-08-06 20:45:57 +01001240 lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address;
1241 lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size;
1242 curr_table_data_size += lli_table_ptr->block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001243
Alan Coxd19cf322009-08-06 20:45:57 +01001244 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
1245 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1246 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001247
Alan Coxd19cf322009-08-06 20:45:57 +01001248 /* check for overflow of the table data */
1249 if (curr_table_data_size > table_data_size) {
1250 edbg("SEP Driver:curr_table_data_size > table_data_size\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001251
Alan Coxd19cf322009-08-06 20:45:57 +01001252 /* update the size of block in the table */
1253 lli_table_ptr->block_size -= (curr_table_data_size - table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001254
Alan Coxd19cf322009-08-06 20:45:57 +01001255 /* update the physical address in the lli array */
1256 lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01001257
Alan Coxd19cf322009-08-06 20:45:57 +01001258 /* update the block size left in the lli array */
1259 lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size);
1260 } else
1261 /* advance to the next entry in the lli_array */
1262 array_counter++;
Mark Allyncd1bb432009-08-06 20:43:59 +01001263
Alan Coxd19cf322009-08-06 20:45:57 +01001264 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1265 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001266
Alan Coxd19cf322009-08-06 20:45:57 +01001267 /* move to the next entry in table */
1268 lli_table_ptr++;
1269 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001270
Alan Coxd19cf322009-08-06 20:45:57 +01001271 /* set the info entry to default */
1272 lli_table_ptr->physical_address = 0xffffffff;
1273 lli_table_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001274
Alan Coxd19cf322009-08-06 20:45:57 +01001275 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
1276 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1277 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001278
Alan Coxd19cf322009-08-06 20:45:57 +01001279 /* set the output parameter */
1280 *num_processed_entries_ptr += array_counter;
Mark Allyncd1bb432009-08-06 20:43:59 +01001281
Alan Coxd19cf322009-08-06 20:45:57 +01001282 edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01001283 dbg("SEP Driver:<-------- sep_build_lli_table end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001284 return;
Mark Allyncd1bb432009-08-06 20:43:59 +01001285}
1286
1287/*
1288 this function goes over the list of the print created tables and
1289 prints all the data
1290*/
Alan Coxd19cf322009-08-06 20:45:57 +01001291static void sep_debug_print_lli_tables(struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size)
Mark Allyncd1bb432009-08-06 20:43:59 +01001292{
Alan Coxd19cf322009-08-06 20:45:57 +01001293 unsigned long table_count;
Alan Coxd19cf322009-08-06 20:45:57 +01001294 unsigned long entries_count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001295
Alan Coxd19cf322009-08-06 20:45:57 +01001296 dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001297
Alan Coxd19cf322009-08-06 20:45:57 +01001298 table_count = 1;
1299 while ((unsigned long) lli_table_ptr != 0xffffffff) {
1300 edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size);
1301 edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries);
Mark Allyncd1bb432009-08-06 20:43:59 +01001302
Alan Coxd19cf322009-08-06 20:45:57 +01001303 /* print entries of the table (without info entry) */
1304 for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) {
1305 edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr);
1306 edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size);
1307 }
1308
1309 /* point to the info entry */
1310 lli_table_ptr--;
1311
1312 edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1313 edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1314
1315
1316 table_data_size = lli_table_ptr->block_size & 0xffffff;
1317 num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
1318 lli_table_ptr = (struct sep_lli_entry_t *)
1319 (lli_table_ptr->physical_address);
1320
1321 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);
1322
1323 if ((unsigned long) lli_table_ptr != 0xffffffff)
1324 lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_area_phys_to_virt((unsigned long) lli_table_ptr);
1325
1326 table_count++;
Mark Allyncd1bb432009-08-06 20:43:59 +01001327 }
Alan Coxd19cf322009-08-06 20:45:57 +01001328 dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001329}
1330
1331
1332/*
1333 This function locks all the physical pages of the application virtual buffer
1334 and construct a basic lli array, where each entry holds the physical page
1335 address and the size that application data holds in this physical pages
1336*/
Alan Coxb10b4832009-08-07 19:23:26 +01001337static 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001338{
Alan Coxf93e4bf2009-08-06 20:46:08 +01001339 int error = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01001340 /* the the page of the end address of the user space buffer */
1341 unsigned long end_page;
Alan Coxd19cf322009-08-06 20:45:57 +01001342 /* the page of the start address of the user space buffer */
1343 unsigned long start_page;
Alan Coxd19cf322009-08-06 20:45:57 +01001344 /* the range in pages */
1345 unsigned long num_pages;
Alan Coxd19cf322009-08-06 20:45:57 +01001346 struct page **page_array;
Alan Coxd19cf322009-08-06 20:45:57 +01001347 struct sep_lli_entry_t *lli_array;
Alan Coxd19cf322009-08-06 20:45:57 +01001348 unsigned long count;
Alan Coxd19cf322009-08-06 20:45:57 +01001349 int result;
Mark Allyncd1bb432009-08-06 20:43:59 +01001350
Alan Coxd19cf322009-08-06 20:45:57 +01001351 dbg("SEP Driver:--------> sep_lock_user_pages start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001352
Alan Coxd19cf322009-08-06 20:45:57 +01001353 /* set start and end pages and num pages */
1354 end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
1355 start_page = app_virt_addr >> PAGE_SHIFT;
1356 num_pages = end_page - start_page + 1;
Mark Allyncd1bb432009-08-06 20:43:59 +01001357
Alan Coxd19cf322009-08-06 20:45:57 +01001358 edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr);
1359 edbg("SEP Driver: data_size is %lu\n", data_size);
1360 edbg("SEP Driver: start_page is %lu\n", start_page);
1361 edbg("SEP Driver: end_page is %lu\n", end_page);
1362 edbg("SEP Driver: num_pages is %lu\n", num_pages);
Mark Allyncd1bb432009-08-06 20:43:59 +01001363
Alan Coxd19cf322009-08-06 20:45:57 +01001364 /* allocate array of pages structure pointers */
1365 page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
1366 if (!page_array) {
1367 edbg("SEP Driver: kmalloc for page_array failed\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001368
Alan Coxd19cf322009-08-06 20:45:57 +01001369 error = -ENOMEM;
1370 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001371 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001372
Alan Coxd19cf322009-08-06 20:45:57 +01001373 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
1374 if (!lli_array) {
1375 edbg("SEP Driver: kmalloc for lli_array failed\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001376
Alan Coxd19cf322009-08-06 20:45:57 +01001377 error = -ENOMEM;
1378 goto end_function_with_error1;
1379 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001380
Alan Coxd19cf322009-08-06 20:45:57 +01001381 /* convert the application virtual address into a set of physical */
1382 down_read(&current->mm->mmap_sem);
1383 result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0);
1384 up_read(&current->mm->mmap_sem);
Mark Allyncd1bb432009-08-06 20:43:59 +01001385
Alan Coxd19cf322009-08-06 20:45:57 +01001386 /* check the number of pages locked - if not all then exit with error */
1387 if (result != num_pages) {
1388 dbg("SEP Driver: not all pages locked by get_user_pages\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001389
Alan Coxd19cf322009-08-06 20:45:57 +01001390 error = -ENOMEM;
1391 goto end_function_with_error2;
1392 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001393
Alan Coxd19cf322009-08-06 20:45:57 +01001394 /* flush the cache */
1395 for (count = 0; count < num_pages; count++)
1396 flush_dcache_page(page_array[count]);
Mark Allyncd1bb432009-08-06 20:43:59 +01001397
Alan Coxd19cf322009-08-06 20:45:57 +01001398 /* set the start address of the first page - app data may start not at
1399 the beginning of the page */
1400 lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK));
Mark Allyncd1bb432009-08-06 20:43:59 +01001401
Alan Coxd19cf322009-08-06 20:45:57 +01001402 /* check that not all the data is in the first page only */
1403 if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
1404 lli_array[0].block_size = data_size;
1405 else
1406 lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
Mark Allyncd1bb432009-08-06 20:43:59 +01001407
Alan Coxd19cf322009-08-06 20:45:57 +01001408 /* debug print */
1409 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);
Mark Allyncd1bb432009-08-06 20:43:59 +01001410
Alan Coxd19cf322009-08-06 20:45:57 +01001411 /* go from the second page to the prev before last */
1412 for (count = 1; count < (num_pages - 1); count++) {
1413 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
1414 lli_array[count].block_size = PAGE_SIZE;
1415
Alan Coxf93e4bf2009-08-06 20:46:08 +01001416 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);
Alan Coxd19cf322009-08-06 20:45:57 +01001417 }
1418
1419 /* if more then 1 pages locked - then update for the last page size needed */
1420 if (num_pages > 1) {
1421 /* update the address of the last page */
1422 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
1423
1424 /* set the size of the last page */
1425 lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK);
1426
1427 if (lli_array[count].block_size == 0) {
1428 dbg("app_virt_addr is %08lx\n", app_virt_addr);
1429 dbg("data_size is %lu\n", data_size);
1430 while (1);
1431 }
1432 edbg("lli_array[%lu].physical_address is %08lx, \
1433 lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
1434 }
1435
1436 /* set output params */
1437 *lli_array_ptr = lli_array;
1438 *num_pages_ptr = num_pages;
1439 *page_array_ptr = page_array;
Alan Coxd19cf322009-08-06 20:45:57 +01001440 goto end_function;
1441
Alan Coxf93e4bf2009-08-06 20:46:08 +01001442end_function_with_error2:
Alan Coxd19cf322009-08-06 20:45:57 +01001443 /* release the cache */
1444 for (count = 0; count < num_pages; count++)
1445 page_cache_release(page_array[count]);
Alan Coxd19cf322009-08-06 20:45:57 +01001446 kfree(lli_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001447end_function_with_error1:
Alan Coxd19cf322009-08-06 20:45:57 +01001448 kfree(page_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001449end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001450 dbg("SEP Driver:<-------- sep_lock_user_pages end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001451 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001452}
1453
1454/*
1455 This function locks all the physical pages of the kernel virtual buffer
1456 and construct a basic lli array, where each entry holds the physical
1457 page address and the size that application data holds in this physical pages
1458*/
Alan Coxb10b4832009-08-07 19:23:26 +01001459static 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001460{
Alan Coxf93e4bf2009-08-06 20:46:08 +01001461 int error = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01001462 /* the the page of the end address of the user space buffer */
1463 unsigned long end_page;
Alan Coxd19cf322009-08-06 20:45:57 +01001464 /* the page of the start address of the user space buffer */
1465 unsigned long start_page;
Alan Coxd19cf322009-08-06 20:45:57 +01001466 /* the range in pages */
1467 unsigned long num_pages;
Alan Coxd19cf322009-08-06 20:45:57 +01001468 struct sep_lli_entry_t *lli_array;
Alan Coxd19cf322009-08-06 20:45:57 +01001469 /* next kernel address to map */
1470 unsigned long next_kernel_address;
Alan Coxd19cf322009-08-06 20:45:57 +01001471 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001472
Alan Coxd19cf322009-08-06 20:45:57 +01001473 dbg("SEP Driver:--------> sep_lock_kernel_pages start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001474
Alan Coxd19cf322009-08-06 20:45:57 +01001475 /* set start and end pages and num pages */
1476 end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT;
1477 start_page = kernel_virt_addr >> PAGE_SHIFT;
1478 num_pages = end_page - start_page + 1;
Mark Allyncd1bb432009-08-06 20:43:59 +01001479
Alan Coxd19cf322009-08-06 20:45:57 +01001480 edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr);
1481 edbg("SEP Driver: data_size is %lu\n", data_size);
1482 edbg("SEP Driver: start_page is %lx\n", start_page);
1483 edbg("SEP Driver: end_page is %lx\n", end_page);
1484 edbg("SEP Driver: num_pages is %lu\n", num_pages);
Mark Allyncd1bb432009-08-06 20:43:59 +01001485
Alan Coxd19cf322009-08-06 20:45:57 +01001486 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
1487 if (!lli_array) {
1488 edbg("SEP Driver: kmalloc for lli_array failed\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001489 error = -ENOMEM;
1490 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001491 }
1492
Alan Coxd19cf322009-08-06 20:45:57 +01001493 /* set the start address of the first page - app data may start not at
1494 the beginning of the page */
1495 lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +01001496
Alan Coxd19cf322009-08-06 20:45:57 +01001497 /* check that not all the data is in the first page only */
1498 if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size)
1499 lli_array[0].block_size = data_size;
1500 else
1501 lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK));
1502
1503 /* debug print */
1504 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);
1505
1506 /* advance the address to the start of the next page */
1507 next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE;
1508
1509 /* go from the second page to the prev before last */
1510 for (count = 1; count < (num_pages - 1); count++) {
1511 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
1512 lli_array[count].block_size = PAGE_SIZE;
1513
Alan Coxf93e4bf2009-08-06 20:46:08 +01001514 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);
Alan Coxd19cf322009-08-06 20:45:57 +01001515 next_kernel_address += PAGE_SIZE;
1516 }
1517
1518 /* if more then 1 pages locked - then update for the last page size needed */
1519 if (num_pages > 1) {
1520 /* update the address of the last page */
1521 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
1522
1523 /* set the size of the last page */
1524 lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK);
1525
1526 if (lli_array[count].block_size == 0) {
1527 dbg("app_virt_addr is %08lx\n", kernel_virt_addr);
1528 dbg("data_size is %lu\n", data_size);
1529 while (1);
1530 }
1531
Alan Coxf93e4bf2009-08-06 20:46:08 +01001532 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);
Alan Coxd19cf322009-08-06 20:45:57 +01001533 }
Alan Coxd19cf322009-08-06 20:45:57 +01001534 /* set output params */
1535 *lli_array_ptr = lli_array;
1536 *num_pages_ptr = num_pages;
1537 *page_array_ptr = 0;
Alan Coxf93e4bf2009-08-06 20:46:08 +01001538end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001539 dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001540 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001541}
1542
1543/*
1544 This function releases all the application virtual buffer physical pages,
1545 that were previously locked
1546*/
Alan Coxb10b4832009-08-07 19:23:26 +01001547static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag)
Mark Allyncd1bb432009-08-06 20:43:59 +01001548{
Alan Coxd19cf322009-08-06 20:45:57 +01001549 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001550
Alan Coxd19cf322009-08-06 20:45:57 +01001551 if (dirtyFlag) {
1552 for (count = 0; count < num_pages; count++) {
1553 /* the out array was written, therefore the data was changed */
1554 if (!PageReserved(page_array_ptr[count]))
1555 SetPageDirty(page_array_ptr[count]);
1556 page_cache_release(page_array_ptr[count]);
1557 }
1558 } else {
1559 /* free in pages - the data was only read, therefore no update was done
1560 on those pages */
1561 for (count = 0; count < num_pages; count++)
1562 page_cache_release(page_array_ptr[count]);
Mark Allyncd1bb432009-08-06 20:43:59 +01001563 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001564
Alan Coxd19cf322009-08-06 20:45:57 +01001565 if (page_array_ptr)
1566 /* free the array */
1567 kfree(page_array_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01001568
Alan Coxd19cf322009-08-06 20:45:57 +01001569 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001570}
1571
1572/*
1573 This function raises interrupt to SEP that signals that is has a new
1574 command from HOST
1575*/
Alan Coxb10b4832009-08-07 19:23:26 +01001576static void sep_send_command_handler(void)
Mark Allyncd1bb432009-08-06 20:43:59 +01001577{
Alan Coxd19cf322009-08-06 20:45:57 +01001578 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001579
Alan Coxd19cf322009-08-06 20:45:57 +01001580 dbg("SEP Driver:--------> sep_send_command_handler start\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001581 sep_set_time(0, 0);
Mark Allyncd1bb432009-08-06 20:43:59 +01001582
Alan Coxd19cf322009-08-06 20:45:57 +01001583 /* flash cache */
1584 flush_cache_all();
Mark Allyncd1bb432009-08-06 20:43:59 +01001585
Alan Coxd19cf322009-08-06 20:45:57 +01001586 for (count = 0; count < 12 * 4; count += 4)
1587 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +01001588
Alan Coxd19cf322009-08-06 20:45:57 +01001589 /* update counter */
1590 sep_dev->host_to_sep_send_counter++;
Alan Coxd19cf322009-08-06 20:45:57 +01001591 /* send interrupt to SEP */
1592 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
Alan Coxd19cf322009-08-06 20:45:57 +01001593 dbg("SEP Driver:<-------- sep_send_command_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001594 return;
Mark Allyncd1bb432009-08-06 20:43:59 +01001595}
1596
1597/*
1598 This function raises interrupt to SEPm that signals that is has a
1599 new command from HOST
1600*/
Alan Coxb10b4832009-08-07 19:23:26 +01001601static void sep_send_reply_command_handler(void)
Mark Allyncd1bb432009-08-06 20:43:59 +01001602{
Alan Coxd19cf322009-08-06 20:45:57 +01001603 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001604
Alan Coxd19cf322009-08-06 20:45:57 +01001605 dbg("SEP Driver:--------> sep_send_reply_command_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001606
Alan Coxd19cf322009-08-06 20:45:57 +01001607 /* flash cache */
1608 flush_cache_all();
Alan Coxd19cf322009-08-06 20:45:57 +01001609 for (count = 0; count < 12 * 4; count += 4)
1610 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count)));
Alan Coxd19cf322009-08-06 20:45:57 +01001611 /* update counter */
1612 sep_dev->host_to_sep_send_counter++;
Alan Coxd19cf322009-08-06 20:45:57 +01001613 /* send the interrupt to SEP */
1614 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep_dev->host_to_sep_send_counter);
Alan Coxd19cf322009-08-06 20:45:57 +01001615 /* update both counters */
1616 sep_dev->host_to_sep_send_counter++;
Alan Coxd19cf322009-08-06 20:45:57 +01001617 sep_dev->sep_to_host_reply_counter++;
Alan Coxd19cf322009-08-06 20:45:57 +01001618 dbg("SEP Driver:<-------- sep_send_reply_command_handler end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001619}
1620
1621
1622
1623/*
1624 This function handles the allocate data pool memory request
1625 This function returns calculates the physical address of the
1626 allocated memory, and the offset of this area from the mapped address.
1627 Therefore, the FVOs in user space can calculate the exact virtual
1628 address of this allocated memory
1629*/
1630static int sep_allocate_data_pool_memory_handler(unsigned long arg)
1631{
Alan Coxd19cf322009-08-06 20:45:57 +01001632 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001633 struct sep_driver_alloc_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01001634
Alan Coxd19cf322009-08-06 20:45:57 +01001635 dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001636
Alan Coxd19cf322009-08-06 20:45:57 +01001637 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t));
1638 if (error)
1639 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001640
Alan Coxd19cf322009-08-06 20:45:57 +01001641 /* allocate memory */
1642 if ((sep_dev->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
1643 error = -ENOTTY;
1644 goto end_function;
1645 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001646
Alan Coxd19cf322009-08-06 20:45:57 +01001647 /* set the virtual and physical address */
1648 command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated;
1649 command_args.phys_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated;
Mark Allyncd1bb432009-08-06 20:43:59 +01001650
Alan Coxd19cf322009-08-06 20:45:57 +01001651 /* write the memory back to the user space */
1652 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t));
1653 if (error)
1654 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001655
Alan Coxd19cf322009-08-06 20:45:57 +01001656 /* set the allocation */
1657 sep_dev->data_pool_bytes_allocated += command_args.num_bytes;
Mark Allyncd1bb432009-08-06 20:43:59 +01001658
Alan Coxf93e4bf2009-08-06 20:46:08 +01001659end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001660 dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001661 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001662}
1663
1664/*
1665 This function handles write into allocated data pool command
1666*/
1667static int sep_write_into_data_pool_handler(unsigned long arg)
1668{
Alan Coxd19cf322009-08-06 20:45:57 +01001669 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001670 unsigned long virt_address;
Alan Coxd19cf322009-08-06 20:45:57 +01001671 unsigned long app_in_address;
Alan Coxd19cf322009-08-06 20:45:57 +01001672 unsigned long num_bytes;
Alan Coxd19cf322009-08-06 20:45:57 +01001673 unsigned long data_pool_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001674
Alan Coxd19cf322009-08-06 20:45:57 +01001675 dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001676
Alan Coxd19cf322009-08-06 20:45:57 +01001677 /* get the application address */
1678 error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address));
1679 if (error)
1680 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001681
Alan Coxd19cf322009-08-06 20:45:57 +01001682 /* get the virtual kernel address address */
1683 error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address));
1684 if (error)
1685 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001686
Alan Coxd19cf322009-08-06 20:45:57 +01001687 /* get the number of bytes */
1688 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
1689 if (error)
1690 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001691
Alan Coxd19cf322009-08-06 20:45:57 +01001692 /* calculate the start of the data pool */
1693 data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01001694
1695
Alan Coxd19cf322009-08-06 20:45:57 +01001696 /* check that the range of the virtual kernel address is correct */
1697 if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) {
1698 error = -ENOTTY;
1699 goto end_function;
1700 }
Alan Coxd19cf322009-08-06 20:45:57 +01001701 /* copy the application data */
1702 error = copy_from_user((void *) virt_address, (void *) app_in_address, num_bytes);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001703end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001704 dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001705 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001706}
1707
1708/*
1709 this function handles the read from data pool command
1710*/
1711static int sep_read_from_data_pool_handler(unsigned long arg)
1712{
Alan Coxd19cf322009-08-06 20:45:57 +01001713 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001714 /* virtual address of dest application buffer */
1715 unsigned long app_out_address;
Alan Coxd19cf322009-08-06 20:45:57 +01001716 /* virtual address of the data pool */
1717 unsigned long virt_address;
Alan Coxd19cf322009-08-06 20:45:57 +01001718 unsigned long num_bytes;
Alan Coxd19cf322009-08-06 20:45:57 +01001719 unsigned long data_pool_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001720
Alan Coxd19cf322009-08-06 20:45:57 +01001721 dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001722
Alan Coxd19cf322009-08-06 20:45:57 +01001723 /* get the application address */
1724 error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address));
1725 if (error)
1726 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001727
Alan Coxd19cf322009-08-06 20:45:57 +01001728 /* get the virtual kernel address address */
1729 error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address));
1730 if (error)
1731 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001732
Alan Coxd19cf322009-08-06 20:45:57 +01001733 /* get the number of bytes */
1734 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
1735 if (error)
1736 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001737
Alan Coxd19cf322009-08-06 20:45:57 +01001738 /* calculate the start of the data pool */
1739 data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01001740
Alan Coxd19cf322009-08-06 20:45:57 +01001741 /* check that the range of the virtual kernel address is correct */
1742 if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) {
1743 error = -ENOTTY;
1744 goto end_function;
1745 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001746
Alan Coxd19cf322009-08-06 20:45:57 +01001747 /* copy the application data */
1748 error = copy_to_user((void *) app_out_address, (void *) virt_address, num_bytes);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001749end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001750 dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001751 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001752}
1753
1754
1755/*
1756 this function handles tha request for creation of the DMA table
1757 for the synchronic symmetric operations (AES,DES)
1758*/
1759static int sep_create_sync_dma_tables_handler(unsigned long arg)
1760{
Alan Coxd19cf322009-08-06 20:45:57 +01001761 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001762 /* command arguments */
1763 struct sep_driver_build_sync_table_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01001764
Alan Coxd19cf322009-08-06 20:45:57 +01001765 dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001766
Alan Coxd19cf322009-08-06 20:45:57 +01001767 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t));
1768 if (error)
1769 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001770
Alan Coxd19cf322009-08-06 20:45:57 +01001771 edbg("app_in_address is %08lx\n", command_args.app_in_address);
1772 edbg("app_out_address is %08lx\n", command_args.app_out_address);
1773 edbg("data_size is %lu\n", command_args.data_in_size);
1774 edbg("block_size is %lu\n", command_args.block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001775
Alan Coxd19cf322009-08-06 20:45:57 +01001776 /* check if we need to build only input table or input/output */
1777 if (command_args.app_out_address)
1778 /* prepare input and output tables */
1779 error = sep_prepare_input_output_dma_table(command_args.app_in_address,
1780 command_args.app_out_address,
1781 command_args.data_in_size,
1782 command_args.block_size,
1783 &command_args.in_table_address,
1784 &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);
1785 else
1786 /* prepare input tables */
1787 error = sep_prepare_input_dma_table(command_args.app_in_address,
1788 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);
Mark Allyncd1bb432009-08-06 20:43:59 +01001789
Alan Coxd19cf322009-08-06 20:45:57 +01001790 if (error)
1791 goto end_function;
Alan Coxd19cf322009-08-06 20:45:57 +01001792 /* copy to user */
1793 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01001794end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001795 dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001796 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001797}
1798
1799/*
1800 this function handles the request for freeing dma table for synhronic actions
1801*/
Alan Coxb10b4832009-08-07 19:23:26 +01001802static int sep_free_dma_table_data_handler(void)
Mark Allyncd1bb432009-08-06 20:43:59 +01001803{
Alan Coxd19cf322009-08-06 20:45:57 +01001804 dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001805
Alan Coxd19cf322009-08-06 20:45:57 +01001806 /* free input pages array */
1807 sep_free_dma_pages(sep_dev->in_page_array, sep_dev->in_num_pages, 0);
Mark Allyncd1bb432009-08-06 20:43:59 +01001808
Alan Coxd19cf322009-08-06 20:45:57 +01001809 /* free output pages array if needed */
1810 if (sep_dev->out_page_array)
1811 sep_free_dma_pages(sep_dev->out_page_array, sep_dev->out_num_pages, 1);
Mark Allyncd1bb432009-08-06 20:43:59 +01001812
Alan Coxd19cf322009-08-06 20:45:57 +01001813 /* reset all the values */
1814 sep_dev->in_page_array = 0;
1815 sep_dev->out_page_array = 0;
1816 sep_dev->in_num_pages = 0;
1817 sep_dev->out_num_pages = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01001818 dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001819 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001820}
1821
1822/*
1823 this function handles the request to create the DMA tables for flow
1824*/
1825static int sep_create_flow_dma_tables_handler(unsigned long arg)
1826{
Alan Coxd19cf322009-08-06 20:45:57 +01001827 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001828 struct sep_driver_build_flow_table_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001829 /* first table - output */
1830 struct sep_lli_entry_t first_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001831 /* dma table data */
1832 struct sep_lli_entry_t last_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001833 /* pointer to the info entry of the previuos DMA table */
1834 struct sep_lli_entry_t *prev_info_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001835 /* pointer to the flow data strucutre */
1836 struct sep_flow_context_t *flow_context_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001837
Alan Coxd19cf322009-08-06 20:45:57 +01001838 dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001839
Alan Coxd19cf322009-08-06 20:45:57 +01001840 /* init variables */
1841 prev_info_entry_ptr = 0;
1842 first_table_data.physical_address = 0xffffffff;
Mark Allyncd1bb432009-08-06 20:43:59 +01001843
Alan Coxd19cf322009-08-06 20:45:57 +01001844 /* find the free structure for flow data */
1845 error = sep_find_flow_context(SEP_FREE_FLOW_ID, &flow_context_ptr);
1846 if (error)
1847 goto end_function;
1848
1849 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t));
1850 if (error)
1851 goto end_function;
1852
1853 /* create flow tables */
1854 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);
1855 if (error)
1856 goto end_function_with_error;
1857
1858 /* check if flow is static */
1859 if (!command_args.flow_type)
1860 /* point the info entry of the last to the info entry of the first */
1861 last_table_data = first_table_data;
1862
1863 /* set output params */
1864 command_args.first_table_addr = first_table_data.physical_address;
1865 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1866 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
1867
1868 /* send the parameters to user application */
1869 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t));
1870 if (error)
1871 goto end_function_with_error;
1872
1873 /* all the flow created - update the flow entry with temp id */
1874 flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID;
1875
1876 /* set the processing tables data in the context */
1877 if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG)
1878 flow_context_ptr->input_tables_in_process = first_table_data;
1879 else
1880 flow_context_ptr->output_tables_in_process = first_table_data;
1881
Mark Allyncd1bb432009-08-06 20:43:59 +01001882 goto end_function;
1883
Alan Coxf93e4bf2009-08-06 20:46:08 +01001884end_function_with_error:
Alan Coxd19cf322009-08-06 20:45:57 +01001885 /* free the allocated tables */
1886 sep_deallocated_flow_tables(&first_table_data);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001887end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001888 dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001889 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001890}
1891
1892/*
Alan Coxb10b4832009-08-07 19:23:26 +01001893 this functio nhandles add tables to flow
Mark Allyncd1bb432009-08-06 20:43:59 +01001894*/
1895static int sep_add_flow_tables_handler(unsigned long arg)
1896{
Alan Coxd19cf322009-08-06 20:45:57 +01001897 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001898 unsigned long num_entries;
Alan Coxd19cf322009-08-06 20:45:57 +01001899 struct sep_driver_add_flow_table_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001900 struct sep_flow_context_t *flow_context_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001901 /* first dma table data */
1902 struct sep_lli_entry_t first_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001903 /* last dma table data */
1904 struct sep_lli_entry_t last_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001905 /* pointer to the info entry of the current DMA table */
1906 struct sep_lli_entry_t *info_entry_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001907
Alan Coxd19cf322009-08-06 20:45:57 +01001908 dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001909
Alan Coxd19cf322009-08-06 20:45:57 +01001910 /* get input parameters */
1911 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t));
1912 if (error)
1913 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001914
Alan Coxd19cf322009-08-06 20:45:57 +01001915 /* find the flow structure for the flow id */
1916 error = sep_find_flow_context(command_args.flow_id, &flow_context_ptr);
1917 if (error)
1918 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001919
Alan Coxd19cf322009-08-06 20:45:57 +01001920 /* prepare the flow dma tables */
1921 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);
1922 if (error)
1923 goto end_function_with_error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001924
Alan Coxd19cf322009-08-06 20:45:57 +01001925 /* now check if there is already an existing add table for this flow */
1926 if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) {
1927 /* this buffer was for input buffers */
1928 if (flow_context_ptr->input_tables_flag) {
1929 /* add table already exists - add the new tables to the end
1930 of the previous */
1931 num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
Mark Allyncd1bb432009-08-06 20:43:59 +01001932
Alan Coxd19cf322009-08-06 20:45:57 +01001933 info_entry_ptr = (struct sep_lli_entry_t *)
1934 (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
Mark Allyncd1bb432009-08-06 20:43:59 +01001935
Alan Coxd19cf322009-08-06 20:45:57 +01001936 /* connect to list of tables */
1937 *info_entry_ptr = first_table_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01001938
Alan Coxd19cf322009-08-06 20:45:57 +01001939 /* set the first table data */
1940 first_table_data = flow_context_ptr->first_input_table;
1941 } else {
1942 /* set the input flag */
1943 flow_context_ptr->input_tables_flag = 1;
Mark Allyncd1bb432009-08-06 20:43:59 +01001944
Alan Coxd19cf322009-08-06 20:45:57 +01001945 /* set the first table data */
1946 flow_context_ptr->first_input_table = first_table_data;
1947 }
1948 /* set the last table data */
1949 flow_context_ptr->last_input_table = last_table_data;
1950 } else { /* this is output tables */
1951
1952 /* this buffer was for input buffers */
1953 if (flow_context_ptr->output_tables_flag) {
1954 /* add table already exists - add the new tables to
1955 the end of the previous */
1956 num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
1957
1958 info_entry_ptr = (struct sep_lli_entry_t *)
1959 (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
1960
1961 /* connect to list of tables */
1962 *info_entry_ptr = first_table_data;
1963
1964 /* set the first table data */
1965 first_table_data = flow_context_ptr->first_output_table;
1966 } else {
1967 /* set the input flag */
1968 flow_context_ptr->output_tables_flag = 1;
1969
1970 /* set the first table data */
1971 flow_context_ptr->first_output_table = first_table_data;
1972 }
1973 /* set the last table data */
1974 flow_context_ptr->last_output_table = last_table_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01001975 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001976
Alan Coxd19cf322009-08-06 20:45:57 +01001977 /* set output params */
1978 command_args.first_table_addr = first_table_data.physical_address;
1979 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1980 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
Mark Allyncd1bb432009-08-06 20:43:59 +01001981
Alan Coxd19cf322009-08-06 20:45:57 +01001982 /* send the parameters to user application */
1983 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01001984end_function_with_error:
Alan Coxd19cf322009-08-06 20:45:57 +01001985 /* free the allocated tables */
1986 sep_deallocated_flow_tables(&first_table_data);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001987end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001988 dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001989 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001990}
1991
1992/*
1993 this function add the flow add message to the specific flow
1994*/
1995static int sep_add_flow_tables_message_handler(unsigned long arg)
1996{
Alan Coxd19cf322009-08-06 20:45:57 +01001997 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001998 struct sep_driver_add_message_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001999 struct sep_flow_context_t *flow_context_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002000
Alan Coxd19cf322009-08-06 20:45:57 +01002001 dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002002
Alan Coxd19cf322009-08-06 20:45:57 +01002003 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t));
2004 if (error)
2005 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002006
Alan Coxd19cf322009-08-06 20:45:57 +01002007 /* check input */
2008 if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) {
2009 error = -ENOMEM;
2010 goto end_function;
2011 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002012
Alan Coxd19cf322009-08-06 20:45:57 +01002013 /* find the flow context */
2014 error = sep_find_flow_context(command_args.flow_id, &flow_context_ptr);
2015 if (error)
2016 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002017
Alan Coxd19cf322009-08-06 20:45:57 +01002018 /* copy the message into context */
2019 flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes;
Alan Coxd19cf322009-08-06 20:45:57 +01002020 error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002021end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002022 dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002023 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002024}
2025
2026
2027/*
2028 this function returns the physical and virtual addresses of the static pool
2029*/
2030static int sep_get_static_pool_addr_handler(unsigned long arg)
2031{
Alan Coxd19cf322009-08-06 20:45:57 +01002032 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002033 struct sep_driver_static_pool_addr_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01002034
Alan Coxd19cf322009-08-06 20:45:57 +01002035 dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002036
Alan Coxd19cf322009-08-06 20:45:57 +01002037 /*prepare the output parameters in the struct */
2038 command_args.physical_static_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
2039 command_args.virtual_static_address = sep_dev->shared_area_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01002040
Alan Coxd19cf322009-08-06 20:45:57 +01002041 edbg("SEP Driver:physical_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address);
Mark Allyncd1bb432009-08-06 20:43:59 +01002042
Alan Coxd19cf322009-08-06 20:45:57 +01002043 /* send the parameters to user application */
2044 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t));
Alan Coxd19cf322009-08-06 20:45:57 +01002045 dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002046 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002047}
2048
2049/*
2050 this address gets the offset of the physical address from the start
2051 of the mapped area
2052*/
2053static int sep_get_physical_mapped_offset_handler(unsigned long arg)
2054{
Alan Coxd19cf322009-08-06 20:45:57 +01002055 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002056 struct sep_driver_get_mapped_offset_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01002057
Alan Coxd19cf322009-08-06 20:45:57 +01002058 dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002059
Alan Coxd19cf322009-08-06 20:45:57 +01002060 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t));
2061 if (error)
2062 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002063
Alan Coxd19cf322009-08-06 20:45:57 +01002064 if (command_args.physical_address < sep_dev->phys_shared_area_addr) {
2065 error = -ENOTTY;
2066 goto end_function;
2067 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002068
Alan Coxd19cf322009-08-06 20:45:57 +01002069 /*prepare the output parameters in the struct */
2070 command_args.offset = command_args.physical_address - sep_dev->phys_shared_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002071
Alan Coxd19cf322009-08-06 20:45:57 +01002072 edbg("SEP Driver:physical_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset);
Mark Allyncd1bb432009-08-06 20:43:59 +01002073
Alan Coxd19cf322009-08-06 20:45:57 +01002074 /* send the parameters to user application */
2075 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01002076end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002077 dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002078 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002079}
2080
2081
2082/*
2083 ?
2084*/
2085static int sep_start_handler(void)
2086{
Alan Coxd19cf322009-08-06 20:45:57 +01002087 unsigned long reg_val;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002088 unsigned long error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002089
Alan Coxd19cf322009-08-06 20:45:57 +01002090 dbg("SEP Driver:--------> sep_start_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002091
Alan Coxd19cf322009-08-06 20:45:57 +01002092 /* wait in polling for message from SEP */
Alan Coxf93e4bf2009-08-06 20:46:08 +01002093 do
Alan Coxd19cf322009-08-06 20:45:57 +01002094 reg_val = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002095 while (!reg_val);
Mark Allyncd1bb432009-08-06 20:43:59 +01002096
Alan Coxd19cf322009-08-06 20:45:57 +01002097 /* check the value */
Alan Cox43e8c4a2009-08-06 20:46:22 +01002098 if (reg_val == 0x1)
Alan Coxd19cf322009-08-06 20:45:57 +01002099 /* fatal error - read erro status from GPRO */
2100 error = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
Alan Coxd19cf322009-08-06 20:45:57 +01002101 dbg("SEP Driver:<-------- sep_start_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002102 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002103}
2104
2105/*
2106 this function handles the request for SEP initialization
2107*/
2108static int sep_init_handler(unsigned long arg)
2109{
Alan Coxd19cf322009-08-06 20:45:57 +01002110 unsigned long message_word;
Alan Coxd19cf322009-08-06 20:45:57 +01002111 unsigned long *message_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002112 struct sep_driver_init_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01002113 unsigned long counter;
Alan Coxd19cf322009-08-06 20:45:57 +01002114 unsigned long error;
Alan Coxd19cf322009-08-06 20:45:57 +01002115 unsigned long reg_val;
Mark Allyncd1bb432009-08-06 20:43:59 +01002116
Alan Coxd19cf322009-08-06 20:45:57 +01002117 dbg("SEP Driver:--------> sep_init_handler start\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002118 error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002119
Alan Coxd19cf322009-08-06 20:45:57 +01002120 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t));
Mark Allyncd1bb432009-08-06 20:43:59 +01002121
Alan Coxd19cf322009-08-06 20:45:57 +01002122 dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002123
Alan Coxd19cf322009-08-06 20:45:57 +01002124 if (error)
2125 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002126
Alan Coxd19cf322009-08-06 20:45:57 +01002127 /* PATCH - configure the DMA to single -burst instead of multi-burst */
2128 /*sep_configure_dma_burst(); */
Mark Allyncd1bb432009-08-06 20:43:59 +01002129
Alan Coxd19cf322009-08-06 20:45:57 +01002130 dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002131
Alan Coxd19cf322009-08-06 20:45:57 +01002132 message_ptr = (unsigned long *) command_args.message_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002133
Alan Coxd19cf322009-08-06 20:45:57 +01002134 /* set the base address of the SRAM */
2135 sep_write_reg(sep_dev, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS);
Mark Allyncd1bb432009-08-06 20:43:59 +01002136
Alan Coxd19cf322009-08-06 20:45:57 +01002137 for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) {
2138 get_user(message_word, message_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01002139 /* write data to SRAM */
2140 sep_write_reg(sep_dev, HW_SRAM_DATA_REG_ADDR, message_word);
Alan Coxd19cf322009-08-06 20:45:57 +01002141 edbg("SEP Driver:message_word is %lu\n", message_word);
Mark Allyncd1bb432009-08-06 20:43:59 +01002142 /* wait for write complete */
Alan Coxd19cf322009-08-06 20:45:57 +01002143 sep_wait_sram_write(sep_dev);
2144 }
Alan Coxd19cf322009-08-06 20:45:57 +01002145 dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002146 /* signal SEP */
2147 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1);
Mark Allyncd1bb432009-08-06 20:43:59 +01002148
Alan Coxf93e4bf2009-08-06 20:46:08 +01002149 do
Alan Coxd19cf322009-08-06 20:45:57 +01002150 reg_val = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002151 while (!(reg_val & 0xFFFFFFFD));
Mark Allyncd1bb432009-08-06 20:43:59 +01002152
Alan Coxd19cf322009-08-06 20:45:57 +01002153 dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002154
Alan Coxd19cf322009-08-06 20:45:57 +01002155 /* check the value */
2156 if (reg_val == 0x1) {
2157 edbg("SEP Driver:init failed\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002158
Alan Coxd19cf322009-08-06 20:45:57 +01002159 error = sep_read_reg(sep_dev, 0x8060);
2160 edbg("SEP Driver:sw monitor is %lu\n", error);
Mark Allyncd1bb432009-08-06 20:43:59 +01002161
Alan Coxd19cf322009-08-06 20:45:57 +01002162 /* fatal error - read erro status from GPRO */
2163 error = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
2164 edbg("SEP Driver:error is %lu\n", error);
Alan Coxd19cf322009-08-06 20:45:57 +01002165 }
Alan Coxf93e4bf2009-08-06 20:46:08 +01002166end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002167 dbg("SEP Driver:<-------- sep_init_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002168 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002169
2170}
2171
2172/*
2173 this function handles the request cache and resident reallocation
2174*/
2175static int sep_realloc_cache_resident_handler(unsigned long arg)
2176{
Alan Coxd19cf322009-08-06 20:45:57 +01002177 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002178 unsigned long phys_cache_address;
Alan Coxd19cf322009-08-06 20:45:57 +01002179 unsigned long phys_resident_address;
Alan Coxd19cf322009-08-06 20:45:57 +01002180 struct sep_driver_realloc_cache_resident_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01002181
Alan Coxd19cf322009-08-06 20:45:57 +01002182 /* copy the data */
2183 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_realloc_cache_resident_t));
2184 if (error)
2185 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002186
Alan Coxd19cf322009-08-06 20:45:57 +01002187 /* copy cache and resident to the their intended locations */
2188 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);
2189 if (error)
2190 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002191
Alan Coxd19cf322009-08-06 20:45:57 +01002192 command_args.new_base_addr = sep_dev->phys_shared_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002193
Alan Coxd19cf322009-08-06 20:45:57 +01002194 /* find the new base address according to the lowest address between
2195 cache, resident and shared area */
2196 if (phys_resident_address < command_args.new_base_addr)
2197 command_args.new_base_addr = phys_resident_address;
2198 if (phys_cache_address < command_args.new_base_addr)
2199 command_args.new_base_addr = phys_cache_address;
Mark Allyncd1bb432009-08-06 20:43:59 +01002200
Alan Coxd19cf322009-08-06 20:45:57 +01002201 /* set the return parameters */
2202 command_args.new_cache_addr = phys_cache_address;
2203 command_args.new_resident_addr = phys_resident_address;
Mark Allyncd1bb432009-08-06 20:43:59 +01002204
Alan Coxd19cf322009-08-06 20:45:57 +01002205 /* set the new shared area */
2206 command_args.new_shared_area_addr = sep_dev->phys_shared_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002207
Alan Coxd19cf322009-08-06 20:45:57 +01002208 edbg("SEP Driver:command_args.new_shared_area_addr is %08lx\n", command_args.new_shared_area_addr);
2209 edbg("SEP Driver:command_args.new_base_addr is %08lx\n", command_args.new_base_addr);
2210 edbg("SEP Driver:command_args.new_resident_addr is %08lx\n", command_args.new_resident_addr);
2211 edbg("SEP Driver:command_args.new_cache_addr is %08lx\n", command_args.new_cache_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002212
Alan Coxd19cf322009-08-06 20:45:57 +01002213 /* return to user */
2214 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_realloc_cache_resident_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01002215end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002216 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002217}
2218
2219/*
2220 this function handles the request for get time
2221*/
2222static int sep_get_time_handler(unsigned long arg)
2223{
Alan Coxd19cf322009-08-06 20:45:57 +01002224 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002225 struct sep_driver_get_time_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01002226
Alan Coxd19cf322009-08-06 20:45:57 +01002227 error = sep_set_time(&command_args.time_physical_address, &command_args.time_value);
Alan Coxd19cf322009-08-06 20:45:57 +01002228 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_get_time_t));
Alan Coxd19cf322009-08-06 20:45:57 +01002229 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002230
2231}
2232
2233/*
2234 This api handles the setting of API mode to blocking or non-blocking
2235*/
2236static int sep_set_api_mode_handler(unsigned long arg)
2237{
Alan Coxd19cf322009-08-06 20:45:57 +01002238 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002239 unsigned long mode_flag;
Mark Allyncd1bb432009-08-06 20:43:59 +01002240
Alan Coxd19cf322009-08-06 20:45:57 +01002241 dbg("SEP Driver:--------> sep_set_api_mode_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002242
Alan Coxd19cf322009-08-06 20:45:57 +01002243 error = get_user(mode_flag, &(((struct sep_driver_set_api_mode_t *) arg)->mode));
2244 if (error)
2245 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002246
Alan Coxd19cf322009-08-06 20:45:57 +01002247 /* set the global flag */
2248 sep_dev->block_mode_flag = mode_flag;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002249end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002250 dbg("SEP Driver:<-------- sep_set_api_mode_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002251 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002252}
2253
2254/*
2255 This API handles the end transaction request
2256*/
2257static int sep_end_transaction_handler(unsigned long arg)
2258{
Alan Coxd19cf322009-08-06 20:45:57 +01002259 dbg("SEP Driver:--------> sep_end_transaction_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002260
Alan Coxd19cf322009-08-06 20:45:57 +01002261#if 0 /*!SEP_DRIVER_POLLING_MODE */
2262 /* close IMR */
2263 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF);
Mark Allyncd1bb432009-08-06 20:43:59 +01002264
Alan Coxd19cf322009-08-06 20:45:57 +01002265 /* release IRQ line */
2266 free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address);
Mark Allyncd1bb432009-08-06 20:43:59 +01002267
Alan Coxd19cf322009-08-06 20:45:57 +01002268 /* lock the sep mutex */
2269 mutex_unlock(&sep_mutex);
Mark Allyncd1bb432009-08-06 20:43:59 +01002270#endif
2271
Alan Coxd19cf322009-08-06 20:45:57 +01002272 dbg("SEP Driver:<-------- sep_end_transaction_handler end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002273
Alan Coxd19cf322009-08-06 20:45:57 +01002274 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002275}
2276
Mark Allyncd1bb432009-08-06 20:43:59 +01002277
2278
2279/*
2280 This function creates a list of tables for flow and returns the data for
2281 the first and last tables of the list
2282*/
2283static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers,
Alan Coxd19cf322009-08-06 20:45:57 +01002284 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01002285{
Alan Coxd19cf322009-08-06 20:45:57 +01002286 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002287 unsigned long virt_buff_addr;
Alan Coxd19cf322009-08-06 20:45:57 +01002288 unsigned long virt_buff_size;
Alan Coxd19cf322009-08-06 20:45:57 +01002289 struct sep_lli_entry_t table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01002290 struct sep_lli_entry_t *info_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002291 struct sep_lli_entry_t *prev_info_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002292 unsigned long i;
Mark Allyncd1bb432009-08-06 20:43:59 +01002293
Alan Coxd19cf322009-08-06 20:45:57 +01002294 /* init vars */
2295 error = 0;
2296 prev_info_entry_ptr = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002297
Alan Coxd19cf322009-08-06 20:45:57 +01002298 /* init the first table to default */
2299 table_data.physical_address = 0xffffffff;
2300 first_table_data_ptr->physical_address = 0xffffffff;
2301 table_data.block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002302
Alan Coxd19cf322009-08-06 20:45:57 +01002303 for (i = 0; i < num_virtual_buffers; i++) {
2304 /* get the virtual buffer address */
2305 error = get_user(virt_buff_addr, &first_buff_addr);
2306 if (error)
2307 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002308
Alan Coxd19cf322009-08-06 20:45:57 +01002309 /* get the virtual buffer size */
2310 first_buff_addr++;
2311 error = get_user(virt_buff_size, &first_buff_addr);
2312 if (error)
2313 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002314
Alan Coxd19cf322009-08-06 20:45:57 +01002315 /* advance the address to point to the next pair of address|size */
2316 first_buff_addr++;
Mark Allyncd1bb432009-08-06 20:43:59 +01002317
Alan Coxd19cf322009-08-06 20:45:57 +01002318 /* now prepare the one flow LLI table from the data */
2319 error = sep_prepare_one_flow_dma_table(virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress);
2320 if (error)
2321 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002322
Alan Coxd19cf322009-08-06 20:45:57 +01002323 if (i == 0) {
2324 /* if this is the first table - save it to return to the user
2325 application */
2326 *first_table_data_ptr = table_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01002327
Alan Coxd19cf322009-08-06 20:45:57 +01002328 /* set the pointer to info entry */
2329 prev_info_entry_ptr = info_entry_ptr;
2330 } else {
2331 /* not first table - the previous table info entry should
2332 be updated */
2333 prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01002334
Alan Coxd19cf322009-08-06 20:45:57 +01002335 /* set the pointer to info entry */
2336 prev_info_entry_ptr = info_entry_ptr;
2337 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002338 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002339
Alan Coxd19cf322009-08-06 20:45:57 +01002340 /* set the last table data */
2341 *last_table_data_ptr = table_data;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002342end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002343 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002344}
2345
2346
2347/*
2348 This function creates one DMA table for flow and returns its data,
2349 and pointer to its info entry
2350*/
Alan Coxd19cf322009-08-06 20:45:57 +01002351static 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01002352{
Alan Coxd19cf322009-08-06 20:45:57 +01002353 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002354 /* the range in pages */
2355 unsigned long lli_array_size;
Alan Coxd19cf322009-08-06 20:45:57 +01002356 struct sep_lli_entry_t *lli_array;
Alan Coxd19cf322009-08-06 20:45:57 +01002357 struct sep_lli_entry_t *flow_dma_table_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002358 unsigned long *start_dma_table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002359 /* total table data counter */
2360 unsigned long dma_table_data_count;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002361 /* pointer that will keep the pointer to the pages of the virtual buffer */
Alan Coxd19cf322009-08-06 20:45:57 +01002362 struct page **page_array_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002363 unsigned long entry_count;
Mark Allyncd1bb432009-08-06 20:43:59 +01002364
Alan Coxd19cf322009-08-06 20:45:57 +01002365 /* find the space for the new table */
2366 error = sep_find_free_flow_dma_table_space(&start_dma_table_ptr);
2367 if (error)
2368 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002369
Alan Coxd19cf322009-08-06 20:45:57 +01002370 /* check if the pages are in Kernel Virtual Address layout */
2371 if (isKernelVirtualAddress == true)
2372 /* lock kernel buffer in the memory */
2373 error = sep_lock_kernel_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
2374 else
2375 /* lock user buffer in the memory */
2376 error = sep_lock_user_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002377
Alan Coxd19cf322009-08-06 20:45:57 +01002378 if (error)
2379 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002380
Alan Coxd19cf322009-08-06 20:45:57 +01002381 /* set the pointer to page array at the beginning of table - this table is
2382 now considered taken */
2383 *start_dma_table_ptr = lli_array_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01002384
Alan Coxd19cf322009-08-06 20:45:57 +01002385 /* point to the place of the pages pointers of the table */
2386 start_dma_table_ptr++;
Mark Allyncd1bb432009-08-06 20:43:59 +01002387
Alan Coxd19cf322009-08-06 20:45:57 +01002388 /* set the pages pointer */
2389 *start_dma_table_ptr = (unsigned long) page_array_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002390
Alan Coxd19cf322009-08-06 20:45:57 +01002391 /* set the pointer to the first entry */
2392 flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002393
Alan Coxd19cf322009-08-06 20:45:57 +01002394 /* now create the entries for table */
2395 for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) {
2396 flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address;
Mark Allyncd1bb432009-08-06 20:43:59 +01002397
Alan Coxd19cf322009-08-06 20:45:57 +01002398 flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01002399
Alan Coxd19cf322009-08-06 20:45:57 +01002400 /* set the total data of a table */
2401 dma_table_data_count += lli_array[entry_count].block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +01002402
Alan Coxd19cf322009-08-06 20:45:57 +01002403 flow_dma_table_entry_ptr++;
2404 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002405
Alan Coxd19cf322009-08-06 20:45:57 +01002406 /* set the physical address */
2407 table_data->physical_address = virt_to_phys(start_dma_table_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002408
Alan Coxd19cf322009-08-06 20:45:57 +01002409 /* set the num_entries and total data size */
2410 table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count);
Mark Allyncd1bb432009-08-06 20:43:59 +01002411
Alan Coxd19cf322009-08-06 20:45:57 +01002412 /* set the info entry */
2413 flow_dma_table_entry_ptr->physical_address = 0xffffffff;
2414 flow_dma_table_entry_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002415
Alan Coxd19cf322009-08-06 20:45:57 +01002416 /* set the pointer to info entry */
2417 *info_entry_ptr = flow_dma_table_entry_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002418
Alan Coxd19cf322009-08-06 20:45:57 +01002419 /* the array of the lli entries */
2420 kfree(lli_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002421end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002422 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002423}
2424
2425
2426/*
2427 This function returns pointer to the flow data structure
Alan Coxf93e4bf2009-08-06 20:46:08 +01002428 that contains the given id
Mark Allyncd1bb432009-08-06 20:43:59 +01002429*/
Alan Coxd19cf322009-08-06 20:45:57 +01002430static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr)
Mark Allyncd1bb432009-08-06 20:43:59 +01002431{
Alan Coxd19cf322009-08-06 20:45:57 +01002432 unsigned long count;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002433 int error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002434
Alan Coxd19cf322009-08-06 20:45:57 +01002435 /*
2436 always search for flow with id default first - in case we
2437 already started working on the flow there can be no situation
2438 when 2 flows are with default flag
2439 */
2440 for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) {
2441 if (sep_dev->flows_data_array[count].flow_id == flow_id) {
2442 *flow_data_ptr = &sep_dev->flows_data_array[count];
2443 break;
2444 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002445 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002446
Alan Coxd19cf322009-08-06 20:45:57 +01002447 if (count == SEP_DRIVER_NUM_FLOWS)
2448 /* no flow found */
2449 error = -ENOMEM;
Mark Allyncd1bb432009-08-06 20:43:59 +01002450
Alan Coxd19cf322009-08-06 20:45:57 +01002451 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002452}
2453
2454/*
2455 this function find a space for the new flow dma table
2456*/
Alan Coxd19cf322009-08-06 20:45:57 +01002457static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr)
Mark Allyncd1bb432009-08-06 20:43:59 +01002458{
Alan Coxf93e4bf2009-08-06 20:46:08 +01002459 int error = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01002460 /* pointer to the id field of the flow dma table */
2461 unsigned long *start_table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002462 unsigned long flow_dma_area_start_addr;
Alan Coxd19cf322009-08-06 20:45:57 +01002463 unsigned long flow_dma_area_end_addr;
Alan Coxd19cf322009-08-06 20:45:57 +01002464 /* maximum table size in words */
2465 unsigned long table_size_in_words;
Mark Allyncd1bb432009-08-06 20:43:59 +01002466
Alan Coxd19cf322009-08-06 20:45:57 +01002467 /* find the start address of the flow DMA table area */
2468 flow_dma_area_start_addr = sep_dev->shared_area_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01002469
Alan Coxd19cf322009-08-06 20:45:57 +01002470 /* set end address of the flow table area */
2471 flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01002472
Alan Coxd19cf322009-08-06 20:45:57 +01002473 /* set table size in words */
2474 table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2;
Mark Allyncd1bb432009-08-06 20:43:59 +01002475
Alan Coxd19cf322009-08-06 20:45:57 +01002476 /* set the pointer to the start address of DMA area */
2477 start_table_ptr = (unsigned long *) flow_dma_area_start_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002478
Alan Coxd19cf322009-08-06 20:45:57 +01002479 /* find the space for the next table */
2480 while (((*start_table_ptr & 0x7FFFFFFF) != 0) && ((unsigned long) start_table_ptr < flow_dma_area_end_addr))
2481 start_table_ptr += table_size_in_words;
Mark Allyncd1bb432009-08-06 20:43:59 +01002482
Alan Coxd19cf322009-08-06 20:45:57 +01002483 /* check if we reached the end of floa tables area */
2484 if ((unsigned long) start_table_ptr >= flow_dma_area_end_addr)
2485 error = -1;
2486 else
2487 *table_address_ptr = start_table_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002488
Alan Coxd19cf322009-08-06 20:45:57 +01002489 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002490}
2491
2492/*
2493 this function goes over all the flow tables connected to the given
2494 table and deallocate them
2495*/
2496static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr)
2497{
Alan Coxf93e4bf2009-08-06 20:46:08 +01002498 /* id pointer */
Alan Coxd19cf322009-08-06 20:45:57 +01002499 unsigned long *table_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002500 /* end address of the flow dma area */
2501 unsigned long num_entries;
Alan Coxd19cf322009-08-06 20:45:57 +01002502 unsigned long num_pages;
Alan Coxd19cf322009-08-06 20:45:57 +01002503 struct page **pages_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002504 /* maximum table size in words */
2505 struct sep_lli_entry_t *info_entry_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002506
Alan Coxd19cf322009-08-06 20:45:57 +01002507 /* set the pointer to the first table */
2508 table_ptr = (unsigned long *) first_table_ptr->physical_address;
Mark Allyncd1bb432009-08-06 20:43:59 +01002509
Alan Coxd19cf322009-08-06 20:45:57 +01002510 /* set the num of entries */
2511 num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS)
2512 & SEP_NUM_ENTRIES_MASK;
Mark Allyncd1bb432009-08-06 20:43:59 +01002513
Alan Coxd19cf322009-08-06 20:45:57 +01002514 /* go over all the connected tables */
2515 while (*table_ptr != 0xffffffff) {
2516 /* get number of pages */
2517 num_pages = *(table_ptr - 2);
Mark Allyncd1bb432009-08-06 20:43:59 +01002518
Alan Coxd19cf322009-08-06 20:45:57 +01002519 /* get the pointer to the pages */
2520 pages_ptr = (struct page **) (*(table_ptr - 1));
Mark Allyncd1bb432009-08-06 20:43:59 +01002521
Alan Coxd19cf322009-08-06 20:45:57 +01002522 /* free the pages */
2523 sep_free_dma_pages(pages_ptr, num_pages, 1);
Mark Allyncd1bb432009-08-06 20:43:59 +01002524
Alan Coxd19cf322009-08-06 20:45:57 +01002525 /* goto to the info entry */
2526 info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1);
Mark Allyncd1bb432009-08-06 20:43:59 +01002527
Alan Coxd19cf322009-08-06 20:45:57 +01002528 table_ptr = (unsigned long *) info_entry_ptr->physical_address;
2529 num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
2530 }
Mark Allyncd1bb432009-08-06 20:43:59 +01002531
Alan Coxd19cf322009-08-06 20:45:57 +01002532 return;
Mark Allyncd1bb432009-08-06 20:43:59 +01002533}
2534
2535/*
2536 This function handler the set flow id command
2537*/
2538static int sep_set_flow_id_handler(unsigned long arg)
2539{
Alan Coxd19cf322009-08-06 20:45:57 +01002540 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002541 unsigned long flow_id;
Alan Coxd19cf322009-08-06 20:45:57 +01002542 struct sep_flow_context_t *flow_data_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002543
Alan Coxd19cf322009-08-06 20:45:57 +01002544 dbg("------------>SEP Driver: sep_set_flow_id_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002545
Alan Coxd19cf322009-08-06 20:45:57 +01002546 error = get_user(flow_id, &(((struct sep_driver_set_flow_id_t *) arg)->flow_id));
2547 if (error)
2548 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002549
Alan Coxd19cf322009-08-06 20:45:57 +01002550 /* find the flow data structure that was just used for creating new flow
2551 - its id should be default */
2552 error = sep_find_flow_context(SEP_TEMP_FLOW_ID, &flow_data_ptr);
2553 if (error)
2554 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002555
Alan Coxd19cf322009-08-06 20:45:57 +01002556 /* set flow id */
2557 flow_data_ptr->flow_id = flow_id;
Mark Allyncd1bb432009-08-06 20:43:59 +01002558
Alan Coxf93e4bf2009-08-06 20:46:08 +01002559end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002560 dbg("SEP Driver:<-------- sep_set_flow_id_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002561 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002562}
2563
2564
2565/*
2566 calculates time and sets it at the predefined address
2567*/
Alan Coxd19cf322009-08-06 20:45:57 +01002568static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr)
Mark Allyncd1bb432009-08-06 20:43:59 +01002569{
Alan Coxd19cf322009-08-06 20:45:57 +01002570 struct timeval time;
Alan Coxd19cf322009-08-06 20:45:57 +01002571 /* address of time in the kernel */
2572 unsigned long time_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002573
2574
Alan Coxd19cf322009-08-06 20:45:57 +01002575 dbg("SEP Driver:--------> sep_set_time start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002576
Alan Coxd19cf322009-08-06 20:45:57 +01002577 do_gettimeofday(&time);
Mark Allyncd1bb432009-08-06 20:43:59 +01002578
Alan Coxd19cf322009-08-06 20:45:57 +01002579 /* set value in the SYSTEM MEMORY offset */
2580 time_addr = sep_dev->message_shared_area_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01002581
Alan Coxd19cf322009-08-06 20:45:57 +01002582 *(unsigned long *) time_addr = SEP_TIME_VAL_TOKEN;
2583 *(unsigned long *) (time_addr + 4) = time.tv_sec;
Mark Allyncd1bb432009-08-06 20:43:59 +01002584
Alan Coxd19cf322009-08-06 20:45:57 +01002585 edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec);
2586 edbg("SEP Driver:time_addr is %lu\n", time_addr);
2587 edbg("SEP Driver:g_message_shared_area_addr is %lu\n", sep_dev->message_shared_area_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002588
Alan Coxd19cf322009-08-06 20:45:57 +01002589 /* set the output parameters if needed */
2590 if (address_ptr)
2591 *address_ptr = sep_shared_area_virt_to_phys(time_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002592
Alan Coxd19cf322009-08-06 20:45:57 +01002593 if (time_in_sec_ptr)
2594 *time_in_sec_ptr = time.tv_sec;
Mark Allyncd1bb432009-08-06 20:43:59 +01002595
Alan Coxd19cf322009-08-06 20:45:57 +01002596 dbg("SEP Driver:<-------- sep_set_time end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002597
Alan Coxd19cf322009-08-06 20:45:57 +01002598 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002599}
2600
Alan Cox794f1d72009-08-06 20:45:35 +01002601static void sep_wait_busy(struct sep_device *dev)
2602{
2603 u32 reg;
2604
2605 do {
2606 reg = sep_read_reg(sep_dev, HW_HOST_SEP_BUSY_REG_ADDR);
2607 } while (reg);
2608}
2609
Mark Allyncd1bb432009-08-06 20:43:59 +01002610/*
2611 PATCH for configuring the DMA to single burst instead of multi-burst
2612*/
2613static void sep_configure_dma_burst(void)
2614{
Mark Allyncd1bb432009-08-06 20:43:59 +01002615#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL
2616
Alan Coxd19cf322009-08-06 20:45:57 +01002617 dbg("SEP Driver:<-------- sep_configure_dma_burst start \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002618
Alan Coxd19cf322009-08-06 20:45:57 +01002619 /* request access to registers from SEP */
2620 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
Mark Allyncd1bb432009-08-06 20:43:59 +01002621
Alan Coxd19cf322009-08-06 20:45:57 +01002622 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002623
Alan Coxd19cf322009-08-06 20:45:57 +01002624 sep_wait_busy(sep_dev);
Mark Allyncd1bb432009-08-06 20:43:59 +01002625
Alan Coxd19cf322009-08-06 20:45:57 +01002626 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002627
Alan Coxd19cf322009-08-06 20:45:57 +01002628 /* set the DMA burst register to single burst */
2629 sep_write_reg(sep_dev, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL);
Mark Allyncd1bb432009-08-06 20:43:59 +01002630
Alan Coxd19cf322009-08-06 20:45:57 +01002631 /* release the sep busy */
2632 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL);
2633 sep_wait_busy(sep_dev);
Mark Allyncd1bb432009-08-06 20:43:59 +01002634
Alan Coxd19cf322009-08-06 20:45:57 +01002635 dbg("SEP Driver:<-------- sep_configure_dma_burst done \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002636
2637}
2638
Alan Cox0097a692009-08-07 19:23:19 +01002639/*
2640 function that is activaed on the succesfull probe of the SEP device
2641*/
2642static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2643{
2644 int error = 0;
2645
2646 edbg("Sep pci probe starting\n");
2647
2648 /* enable the device */
2649 error = pci_enable_device(pdev);
2650 if (error) {
2651 edbg("error enabling pci device\n");
2652 goto end_function;
2653 }
2654
2655 /* set the pci dev pointer */
2656 sep_dev->sep_pci_dev_ptr = pdev;
2657
2658 /* get the io memory start address */
2659 sep_dev->io_memory_start_physical_address = pci_resource_start(pdev, 0);
2660 if (!sep_dev->io_memory_start_physical_address) {
2661 edbg("SEP Driver error pci resource start\n");
2662 goto end_function;
2663 }
2664
2665 /* get the io memory end address */
2666 sep_dev->io_memory_end_physical_address = pci_resource_end(pdev, 0);
2667 if (!sep_dev->io_memory_end_physical_address) {
2668 edbg("SEP Driver error pci resource end\n");
2669 goto end_function;
2670 }
2671
2672 sep_dev->io_memory_size = sep_dev->io_memory_end_physical_address - sep_dev->io_memory_start_physical_address + 1;
2673
2674 edbg("SEP Driver:io_memory_start_physical_address is %08lx\n", sep_dev->io_memory_start_physical_address);
2675
2676 edbg("SEP Driver:io_memory_end_phyaical_address is %08lx\n", sep_dev->io_memory_end_physical_address);
2677
2678 edbg("SEP Driver:io_memory_size is %08lx\n", sep_dev->io_memory_size);
2679
2680 sep_dev->io_memory_start_virtual_address = ioremap_nocache(sep_dev->io_memory_start_physical_address, sep_dev->io_memory_size);
2681 if (!sep_dev->io_memory_start_virtual_address) {
2682 edbg("SEP Driver error ioremap of io memory\n");
2683 goto end_function;
2684 }
2685
2686 edbg("SEP Driver:io_memory_start_virtual_address is %p\n", sep_dev->io_memory_start_virtual_address);
2687
2688 sep_dev->reg_base_address = (void __iomem *) sep_dev->io_memory_start_virtual_address;
2689
2690
2691 /* set up system base address and shared memory location */
2692
2693 sep_dev->rar_virtual_address = kmalloc(2 * SEP_RAR_IO_MEM_REGION_SIZE, GFP_KERNEL);
2694
2695 if (!sep_dev->rar_virtual_address) {
2696 edbg("SEP Driver:cant kmalloc rar\n");
2697 goto end_function;
2698 }
2699 /* FIXME */
2700 sep_dev->rar_physical_address = __pa(sep_dev->rar_virtual_address);
2701
2702 edbg("SEP Driver:rar_physical is %08lx\n", sep_dev->rar_physical_address);
2703 edbg("SEP Driver:rar_virtual is %p\n", sep_dev->rar_virtual_address);
2704
2705#if !SEP_DRIVER_POLLING_MODE
2706
2707 edbg("SEP Driver: about to write IMR and ICR REG_ADDR\n");
2708
2709 /* clear ICR register */
2710 sep_write_reg(sep_dev, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
2711
2712 /* set the IMR register - open only GPR 2 */
2713 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
2714
2715 /* figure out our irq */
2716 /* FIXME: */
2717 error = pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, (u8 *) & sep_dev->sep_irq);
2718
2719 edbg("SEP Driver: my irq is %d\n", sep_irq);
2720
2721 edbg("SEP Driver: about to call request_irq\n");
2722 /* get the interrupt line */
2723 error = request_irq(sep_irq, sep_inthandler, IRQF_SHARED, "sep_driver", &sep_dev->reg_base_address);
2724 if (error)
2725 goto end_function;
2726
2727 goto end_function;
2728 edbg("SEP Driver: about to write IMR REG_ADDR");
2729
2730 /* set the IMR register - open only GPR 2 */
2731 sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
2732
2733#endif /* SEP_DRIVER_POLLING_MODE */
2734end_function:
2735 return error;
2736}
2737
2738static struct pci_device_id sep_pci_id_tbl[] = {
2739 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)},
2740 {0}
2741};
2742
2743MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl);
2744
2745/* field for registering driver to PCI device */
2746static struct pci_driver sep_pci_driver = {
2747 .name = "sep_sec_driver",
2748 .id_table = sep_pci_id_tbl,
2749 .probe = sep_probe
2750};
2751
Alan Cox2f826142009-08-07 19:23:04 +01002752/* major and minor device numbers */
2753static dev_t sep_devno;
2754
2755/* the files operations structure of the driver */
2756static struct file_operations sep_file_operations = {
2757 .owner = THIS_MODULE,
2758 .ioctl = sep_ioctl,
2759 .poll = sep_poll,
2760 .open = sep_open,
2761 .release = sep_release,
2762 .mmap = sep_mmap,
2763};
2764
2765
2766/* cdev struct of the driver */
2767static struct cdev sep_cdev;
2768
Alan Coxa2171b62009-08-07 19:22:57 +01002769/*
2770 this function registers the driver to the file system
2771*/
2772static int sep_register_driver_to_fs(void)
2773{
Alan Cox2f826142009-08-07 19:23:04 +01002774 int ret_val = alloc_chrdev_region(&sep_devno, 0, 1, "sep_sec_driver");
Alan Coxa2171b62009-08-07 19:22:57 +01002775 if (ret_val) {
2776 edbg("sep_driver:major number allocation failed, retval is %d\n", ret_val);
2777 goto end_function;
2778 }
2779
Alan Coxa2171b62009-08-07 19:22:57 +01002780 /* init cdev */
Alan Cox2f826142009-08-07 19:23:04 +01002781 cdev_init(&sep_cdev, &sep_file_operations);
2782 sep_cdev.owner = THIS_MODULE;
Alan Coxa2171b62009-08-07 19:22:57 +01002783
2784 /* register the driver with the kernel */
Alan Cox2f826142009-08-07 19:23:04 +01002785 ret_val = cdev_add(&sep_cdev, sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002786
2787 if (ret_val) {
2788 edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val);
2789 goto end_function_unregister_devnum;
2790 }
2791
2792 goto end_function;
2793
2794end_function_unregister_devnum:
2795
2796 /* unregister dev numbers */
Alan Cox2f826142009-08-07 19:23:04 +01002797 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002798
2799end_function:
2800 return ret_val;
2801}
2802
Alan Coxa2171b62009-08-07 19:22:57 +01002803
2804/*--------------------------------------------------------------
2805 init function
2806----------------------------------------------------------------*/
2807static int __init sep_init(void)
2808{
2809 int ret_val = 0;
2810 int counter;
2811 int size; /* size of memory for allocation */
2812
2813 dbg("SEP Driver:-------->Init start\n");
2814 edbg("sep->shared_area_addr = %lx\n", (unsigned long) &sep_dev->shared_area_addr);
2815
2816 /* transaction counter that coordinates the transactions between SEP
2817 and HOST */
2818 sep_dev->host_to_sep_send_counter = 0;
2819
2820 /* counter for the messages from sep */
2821 sep_dev->sep_to_host_reply_counter = 0;
2822
2823 /* counter for the number of bytes allocated in the pool
2824 for the current transaction */
2825 sep_dev->data_pool_bytes_allocated = 0;
2826
2827 /* set the starting mode to blocking */
2828 sep_dev->block_mode_flag = 1;
2829
Alan Cox91410062009-08-07 19:23:41 +01002830 /* FIXME: Probe can occur before we are ready to survive a probe */
2831 ret_val = pci_register_driver(&sep_pci_driver);
Alan Coxa2171b62009-08-07 19:22:57 +01002832 if (ret_val) {
2833 edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val);
2834 goto end_function_unregister_from_fs;
2835 }
2836 /* calculate the total size for allocation */
2837 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
2838 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;
2839
2840 /* allocate the shared area */
2841 if (sep_map_and_alloc_shared_area(size, &sep_dev->shared_area_addr, &sep_dev->phys_shared_area_addr)) {
2842 ret_val = -ENOMEM;
2843 /* allocation failed */
2844 goto end_function_unmap_io_memory;
2845 }
2846 /* now set the memory regions */
2847 sep_dev->message_shared_area_addr = sep_dev->shared_area_addr;
2848
2849 edbg("SEP Driver: g_message_shared_area_addr is %08lx\n", sep_dev->message_shared_area_addr);
2850
2851#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1)
2852 /* send the new SHARED MESSAGE AREA to the SEP */
2853 sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep_dev->phys_shared_area_addr);
2854
2855 /* poll for SEP response */
2856 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
2857 while (retVal != 0xffffffff && retVal != sep_dev->phys_shared_area_addr)
2858 retVal = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
2859
2860 /* check the return value (register) */
2861 if (retVal != sep_dev->phys_shared_area_addr) {
2862 ret_val = -ENOMEM;
2863 goto end_function_deallocate_message_area;
2864 }
2865#endif
2866 /* init the flow contextes */
2867 for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++)
2868 sep_dev->flows_data_array[counter].flow_id = SEP_FREE_FLOW_ID;
2869
2870 sep_dev->flow_wq_ptr = create_singlethread_workqueue("sepflowwq");
2871 if (sep_dev->flow_wq_ptr == 0) {
2872 ret_val = -ENOMEM;
2873 edbg("sep_driver:flow queue creation failed\n");
2874 goto end_function_deallocate_sep_shared_area;
2875 }
2876 edbg("SEP Driver: create flow workqueue \n");
2877
2878 /* register driver to fs */
2879 ret_val = sep_register_driver_to_fs();
2880 if (ret_val)
2881 goto end_function_deallocate_sep_shared_area;
2882 /* load the rom code */
2883 sep_load_rom_code();
2884 goto end_function;
2885end_function_unregister_from_fs:
2886 /* unregister from fs */
Alan Cox91410062009-08-07 19:23:41 +01002887 cdev_del(&sep_cdev);
2888 /* unregister dev numbers */
2889 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002890end_function_deallocate_sep_shared_area:
2891 /* de-allocate shared area */
2892 sep_unmap_and_free_shared_area(size, sep_dev->shared_area_addr, sep_dev->phys_shared_area_addr);
2893end_function_unmap_io_memory:
2894 iounmap((void *) sep_dev->reg_base_address);
2895 /* release io memory region */
2896 release_mem_region(SEP_IO_MEM_REGION_START_ADDRESS, SEP_IO_MEM_REGION_SIZE);
2897end_function:
2898 dbg("SEP Driver:<-------- Init end\n");
2899 return ret_val;
2900}
2901
2902
2903/*-------------------------------------------------------------
2904 exit function
2905--------------------------------------------------------------*/
2906static void __exit sep_exit(void)
2907{
2908 int size;
2909
2910 dbg("SEP Driver:--------> Exit start\n");
2911
2912 /* unregister from fs */
Alan Cox91410062009-08-07 19:23:41 +01002913 cdev_del(&sep_cdev);
2914 /* unregister dev numbers */
2915 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002916 /* calculate the total size for de-allocation */
2917 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
2918 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;
2919 /* free shared area */
2920 sep_unmap_and_free_shared_area(size, sep_dev->shared_area_addr, sep_dev->phys_shared_area_addr);
2921 edbg("SEP Driver: free pages SEP SHARED AREA \n");
2922 iounmap((void *) sep_dev->reg_base_address);
2923 edbg("SEP Driver: iounmap \n");
2924 /* release io memory region */
2925 release_mem_region(SEP_IO_MEM_REGION_START_ADDRESS, SEP_IO_MEM_REGION_SIZE);
2926 edbg("SEP Driver: release_mem_region \n");
2927 dbg("SEP Driver:<-------- Exit end\n");
2928}
2929
2930
Mark Allyncd1bb432009-08-06 20:43:59 +01002931module_init(sep_init);
2932module_exit(sep_exit);
2933
2934MODULE_LICENSE("GPL");