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