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