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