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