blob: 4d3b1630ef5b3ede8bbf92bef4d22c02e8678f09 [file] [log] [blame]
Mark Allyncd1bb432009-08-06 20:43:59 +01001/*
2 *
Alan Cox51faa9d2009-08-14 15:40:45 +01003 * sep_driver.c - Security Processor Driver main group of functions
Mark Allyncd1bb432009-08-06 20:43:59 +01004 *
5 * Copyright(c) 2009 Intel Corporation. All rights reserved.
6 * Copyright(c) 2009 Discretix. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * CONTACTS:
23 *
24 * Mark Allyn mark.a.allyn@intel.com
25 *
26 * CHANGES:
27 *
28 * 2009.06.26 Initial publish
29 *
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/fs.h>
35#include <linux/cdev.h>
36#include <linux/kdev_t.h>
37#include <linux/mutex.h>
38#include <linux/mm.h>
39#include <linux/poll.h>
40#include <linux/wait.h>
Alan Cox0097a692009-08-07 19:23:19 +010041#include <linux/pci.h>
42#include <linux/firmware.h>
Mark Allyncd1bb432009-08-06 20:43:59 +010043#include <asm/ioctl.h>
44#include <linux/ioport.h>
45#include <asm/io.h>
46#include <linux/interrupt.h>
47#include <linux/pagemap.h>
48#include <asm/cacheflush.h>
49#include "sep_driver_hw_defs.h"
50#include "sep_driver_config.h"
51#include "sep_driver_api.h"
Alan Coxf5e39802009-08-06 20:45:07 +010052#include "sep_dev.h"
Mark Allyncd1bb432009-08-06 20:43:59 +010053
Alan Cox0097a692009-08-07 19:23:19 +010054#if SEP_DRIVER_ARM_DEBUG_MODE
55
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
62
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
Alan Coxca605bb2009-08-07 19:24:36 +010071static void sep_load_rom_code(struct sep_device *sep)
Alan Cox0097a692009-08-07 19:23:19 +010072{
73 /* Index variables */
74 unsigned long i, k, j;
Alan Cox904290c2009-08-07 19:24:18 +010075 u32 reg;
76 u32 error;
77 u32 warning;
Alan Cox0097a692009-08-07 19:23:19 +010078
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);
Alan Coxca605bb2009-08-07 19:24:36 +010085 edbg("SEP Driver: sep->reg_addr is %p\n", sep->reg_addr);
Alan Cox0097a692009-08-07 19:23:19 +010086 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 */
Alan Coxca605bb2009-08-07 19:24:36 +010090 sep_write_reg(sep, SEP_ROM_BANK_register_offset, i);
Alan Cox0097a692009-08-07 19:23:19 +010091
92 for (j = 0; j < CRYS_SEP_ROM_length / 4; j++) {
Alan Coxca605bb2009-08-07 19:24:36 +010093 sep_write_reg(sep, CRYS_SEP_ROM_start_address_offset + 4 * j, CRYS_SEP_ROM[i * 0x1000 + j]);
Alan Cox0097a692009-08-07 19:23:19 +010094
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 */
Alan Coxca605bb2009-08-07 19:24:36 +0100105 sep_write_reg(sep, HW_HOST_SEP_SW_RST_REG_ADDR, 0x1);
Alan Cox0097a692009-08-07 19:23:19 +0100106
107 /* poll for SEP ROM boot finish */
Alan Coxdabe6e62009-08-07 19:24:58 +0100108 do
Alan Coxca605bb2009-08-07 19:24:36 +0100109 reg = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
Alan Coxdabe6e62009-08-07 19:24:58 +0100110 while (!reg);
Alan Cox0097a692009-08-07 19:23:19 +0100111
112 edbg("SEP Driver: ROM polling ended\n");
113
Alan Cox904290c2009-08-07 19:24:18 +0100114 switch (reg) {
Alan Cox0097a692009-08-07 19:23:19 +0100115 case 0x1:
116 /* fatal error - read erro status from GPRO */
Alan Coxca605bb2009-08-07 19:24:36 +0100117 error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
Alan Cox0097a692009-08-07 19:23:19 +0100118 edbg("SEP Driver: ROM polling case 1\n");
119 break;
Alan Coxdabe6e62009-08-07 19:24:58 +0100120 case 0x4:
121 /* Cold boot ended successfully */
122 case 0x8:
123 /* Warmboot ended successfully */
124 case 0x10:
125 /* ColdWarm boot ended successfully */
126 error = 0;
Alan Cox0097a692009-08-07 19:23:19 +0100127 case 0x2:
128 /* Boot First Phase ended */
Alan Coxca605bb2009-08-07 19:24:36 +0100129 warning = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
Alan Cox0097a692009-08-07 19:23:19 +0100130 case 0x20:
Alan Coxdabe6e62009-08-07 19:24:58 +0100131 edbg("SEP Driver: ROM polling case %d\n", reg);
Alan Cox0097a692009-08-07 19:23:19 +0100132 break;
133 }
134
135}
136
137#else
Alan Coxca605bb2009-08-07 19:24:36 +0100138static void sep_load_rom_code(struct sep_device *sep) { }
Alan Cox0097a692009-08-07 19:23:19 +0100139#endif /* SEP_DRIVER_ARM_DEBUG_MODE */
140
141
142
Mark Allyncd1bb432009-08-06 20:43:59 +0100143/*----------------------------------------
144 DEFINES
145-----------------------------------------*/
146
Alan Cox0097a692009-08-07 19:23:19 +0100147#define BASE_ADDRESS_FOR_SYSTEM 0xfffc0000
148#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000
Mark Allyncd1bb432009-08-06 20:43:59 +0100149
150/*--------------------------------------------
151 GLOBAL variables
152--------------------------------------------*/
153
154/* debug messages level */
Alan Cox51faa9d2009-08-14 15:40:45 +0100155static int debug;
156module_param(debug, int , 0);
157MODULE_PARM_DESC(debug, "Flag to enable SEP debug messages");
Mark Allyncd1bb432009-08-06 20:43:59 +0100158
Alan Cox0097a692009-08-07 19:23:19 +0100159/* Keep this a single static object for now to keep the conversion easy */
160
161static struct sep_device sep_instance;
Alan Coxb10b4832009-08-07 19:23:26 +0100162static struct sep_device *sep_dev = &sep_instance;
Alan Cox0097a692009-08-07 19:23:19 +0100163
Mark Allyncd1bb432009-08-06 20:43:59 +0100164/*
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 */
Alan Cox904290c2009-08-07 19:24:18 +0100171static DECLARE_WAIT_QUEUE_HEAD(sep_event);
Mark Allyncd1bb432009-08-06 20:43:59 +0100172
Alan Cox6f13ea32009-08-14 15:41:50 +0100173/**
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 */
Alan Cox0097a692009-08-07 19:23:19 +0100180
Alan Cox6f13ea32009-08-14 15:41:50 +0100181static int sep_load_firmware(struct sep_device *sep)
182{
183 const struct firmware *fw;
Alan Cox0097a692009-08-07 19:23:19 +0100184 char *cache_name = "cache.image.bin";
185 char *res_name = "resident.image.bin";
Alan Cox0097a692009-08-07 19:23:19 +0100186 int error;
187
Alan Coxca605bb2009-08-07 19:24:36 +0100188 edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr);
Alan Cox51faa9d2009-08-14 15:40:45 +0100189 edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus);
Alan Cox0097a692009-08-07 19:23:19 +0100190
Alan Cox6f13ea32009-08-14 15:41:50 +0100191 sep->rar_region_addr = sep->rar_addr;
Alan Coxca605bb2009-08-07 19:24:36 +0100192 sep->cache_bus = sep->rar_bus;
193 sep->cache_addr = sep->rar_addr;
Alan Cox0097a692009-08-07 19:23:19 +0100194
195 /* load cache */
Alan Coxca605bb2009-08-07 19:24:36 +0100196 error = request_firmware(&fw, cache_name, &sep->pdev->dev);
Alan Cox0097a692009-08-07 19:23:19 +0100197 if (error) {
198 edbg("SEP Driver:cant request cache fw\n");
Alan Cox6f13ea32009-08-14 15:41:50 +0100199 return error;
Alan Cox0097a692009-08-07 19:23:19 +0100200 }
Alan Cox6f13ea32009-08-14 15:41:50 +0100201 edbg("SEP Driver:cache %08Zx@%p\n", fw->size, (void *) fw->data);
Alan Cox0097a692009-08-07 19:23:19 +0100202
Alan Cox6f13ea32009-08-14 15:41:50 +0100203 memcpy(sep->cache_addr, (void *)fw->data, fw->size);
Alan Cox790cf1b2009-08-07 19:25:16 +0100204 sep->cache_size = fw->size;
Alan Cox0097a692009-08-07 19:23:19 +0100205 release_firmware(fw);
206
Alan Coxca605bb2009-08-07 19:24:36 +0100207 sep->resident_bus = sep->cache_bus + sep->cache_size;
208 sep->resident_addr = sep->cache_addr + sep->cache_size;
Alan Cox0097a692009-08-07 19:23:19 +0100209
210 /* load resident */
Alan Coxca605bb2009-08-07 19:24:36 +0100211 error = request_firmware(&fw, res_name, &sep->pdev->dev);
Alan Cox0097a692009-08-07 19:23:19 +0100212 if (error) {
213 edbg("SEP Driver:cant request res fw\n");
Alan Cox6f13ea32009-08-14 15:41:50 +0100214 return error;
Alan Cox0097a692009-08-07 19:23:19 +0100215 }
Alan Cox6f13ea32009-08-14 15:41:50 +0100216 edbg("sep: res %08Zx@%p\n", fw->size, (void *)fw->data);
Alan Cox0097a692009-08-07 19:23:19 +0100217
Alan Cox6f13ea32009-08-14 15:41:50 +0100218 memcpy(sep->resident_addr, (void *) fw->data, fw->size);
Alan Coxca605bb2009-08-07 19:24:36 +0100219 sep->resident_size = fw->size;
Alan Cox0097a692009-08-07 19:23:19 +0100220 release_firmware(fw);
221
Alan Cox6f13ea32009-08-14 15:41:50 +0100222 edbg("sep: resident v %p b %08llx cache v %p b %08llx\n",
223 sep->resident_addr, (unsigned long long)sep->resident_bus,
224 sep->cache_addr, (unsigned long long)sep->cache_bus);
225 return 0;
Alan Cox0097a692009-08-07 19:23:19 +0100226}
227
Alan Coxad6b9ab2009-08-07 19:25:43 +0100228/**
229 * sep_map_and_alloc_shared_area - allocate shared block
230 * @sep: security processor
231 * @size: size of shared area
232 *
233 * Allocate a shared buffer in host memory that can be used by both the
234 * kernel and also the hardware interface via DMA.
235 */
236
Alan Coxca605bb2009-08-07 19:24:36 +0100237static int sep_map_and_alloc_shared_area(struct sep_device *sep,
Alan Coxad6b9ab2009-08-07 19:25:43 +0100238 unsigned long size)
Alan Cox0097a692009-08-07 19:23:19 +0100239{
Alan Coxca605bb2009-08-07 19:24:36 +0100240 /* shared_addr = ioremap_nocache(0xda00000,shared_area_size); */
Alan Coxc7b75562009-08-14 15:40:32 +0100241 sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, size,
Alan Coxad6b9ab2009-08-07 19:25:43 +0100242 &sep->shared_bus, GFP_KERNEL);
243
Alan Coxca605bb2009-08-07 19:24:36 +0100244 if (!sep->shared_addr) {
Alan Coxad6b9ab2009-08-07 19:25:43 +0100245 edbg("sep_driver :shared memory dma_alloc_coherent failed\n");
246 return -ENOMEM;
Alan Cox0097a692009-08-07 19:23:19 +0100247 }
Alan Cox790cf1b2009-08-07 19:25:16 +0100248 sep->shared_area = sep->shared_addr;
Alan Cox51faa9d2009-08-14 15:40:45 +0100249 /* set the bus address of the shared area */
Alan Cox8c7ff812009-08-07 19:24:43 +0100250 sep->shared_area_bus = sep->shared_bus;
Alan Cox51faa9d2009-08-14 15:40:45 +0100251 edbg("sep: shared_area %ld bytes @%p (bus %08llx)\n",
Alan Coxad6b9ab2009-08-07 19:25:43 +0100252 size, sep->shared_addr, (unsigned long long)sep->shared_bus);
Alan Cox0097a692009-08-07 19:23:19 +0100253 return 0;
254}
255
Alan Coxad6b9ab2009-08-07 19:25:43 +0100256/**
257 * sep_unmap_and_free_shared_area - free shared block
258 * @sep: security processor
259 *
260 * Free the shared area allocated to the security processor. The
261 * processor must have finished with this and any final posted
262 * writes cleared before we do so.
263 */
Alan Cox8c7ff812009-08-07 19:24:43 +0100264static void sep_unmap_and_free_shared_area(struct sep_device *sep, int size)
Alan Cox0097a692009-08-07 19:23:19 +0100265{
Alan Coxad6b9ab2009-08-07 19:25:43 +0100266 dma_free_coherent(&sep->pdev->dev, size,
267 sep->shared_area, sep->shared_area_bus);
Alan Cox0097a692009-08-07 19:23:19 +0100268}
269
Alan Coxad6b9ab2009-08-07 19:25:43 +0100270/**
271 * sep_shared_area_virt_to_bus - convert bus/virt addresses
272 *
Alan Cox51faa9d2009-08-14 15:40:45 +0100273 * Returns the bus address inside the shared area according
Alan Coxad6b9ab2009-08-07 19:25:43 +0100274 * to the virtual address.
275 */
276
277static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep,
Alan Cox790cf1b2009-08-07 19:25:16 +0100278 void *virt_address)
Alan Cox0097a692009-08-07 19:23:19 +0100279{
Alan Coxad6b9ab2009-08-07 19:25:43 +0100280 dma_addr_t pa = sep->shared_bus + (virt_address - sep->shared_addr);
Alan Cox51faa9d2009-08-14 15:40:45 +0100281 edbg("sep: virt to bus b %08llx v %p\n", pa, virt_address);
Alan Coxad6b9ab2009-08-07 19:25:43 +0100282 return pa;
Alan Cox0097a692009-08-07 19:23:19 +0100283}
284
Alan Coxad6b9ab2009-08-07 19:25:43 +0100285/**
286 * sep_shared_area_bus_to_virt - convert bus/virt addresses
287 *
288 * Returns virtual address inside the shared area according
289 * to the bus address.
290 */
291
292static void *sep_shared_area_bus_to_virt(struct sep_device *sep,
293 dma_addr_t bus_address)
Alan Cox0097a692009-08-07 19:23:19 +0100294{
Alan Coxad6b9ab2009-08-07 19:25:43 +0100295 return sep->shared_addr + (bus_address - sep->shared_bus);
Alan Cox0097a692009-08-07 19:23:19 +0100296}
297
298
Mark Allyncd1bb432009-08-06 20:43:59 +0100299/*----------------------------------------------------------------------
300 open function of the character driver - must only lock the mutex
301 must also release the memory data pool allocations
302------------------------------------------------------------------------*/
Alan Cox577092a2009-08-07 19:24:08 +0100303static int sep_open(struct inode *inode, struct file *filp)
Mark Allyncd1bb432009-08-06 20:43:59 +0100304{
Alan Cox577092a2009-08-07 19:24:08 +0100305 int error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100306
Alan Coxd19cf322009-08-06 20:45:57 +0100307 dbg("SEP Driver:--------> open start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100308
Alan Coxd19cf322009-08-06 20:45:57 +0100309 /* check the blocking mode */
Alan Cox577092a2009-08-07 19:24:08 +0100310 if (filp->f_flags & O_NDELAY)
311 error = mutex_trylock(&sep_mutex);
312 else
Alan Coxd19cf322009-08-06 20:45:57 +0100313 /* lock mutex */
314 mutex_lock(&sep_mutex);
Mark Allyncd1bb432009-08-06 20:43:59 +0100315
Alan Coxd19cf322009-08-06 20:45:57 +0100316 /* check the error */
317 if (error) {
318 edbg("SEP Driver: down_interruptible failed\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100319 goto end_function;
320 }
Alan Coxca605bb2009-08-07 19:24:36 +0100321 /* Bind to the device, we only have one which makes it easy */
322 filp->private_data = sep_dev;
323 if (sep_dev == NULL)
324 return -ENODEV;
Mark Allyncd1bb432009-08-06 20:43:59 +0100325
Alan Coxd19cf322009-08-06 20:45:57 +0100326 /* release data pool allocations */
327 sep_dev->data_pool_bytes_allocated = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100328
Alan Coxca605bb2009-08-07 19:24:36 +0100329
Alan Coxf93e4bf2009-08-06 20:46:08 +0100330end_function:
Alan Coxd19cf322009-08-06 20:45:57 +0100331 dbg("SEP Driver:<-------- open end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100332 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100333}
334
335
336
337
338/*------------------------------------------------------------
339 release function
340-------------------------------------------------------------*/
Alan Coxca605bb2009-08-07 19:24:36 +0100341static int sep_release(struct inode *inode_ptr, struct file *filp)
Mark Allyncd1bb432009-08-06 20:43:59 +0100342{
Alan Coxca605bb2009-08-07 19:24:36 +0100343 struct sep_driver *sep = filp->private_data;
Alan Coxd19cf322009-08-06 20:45:57 +0100344 dbg("----------->SEP Driver: sep_release start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100345
Alan Coxd19cf322009-08-06 20:45:57 +0100346#if 0 /*!SEP_DRIVER_POLLING_MODE */
347 /* close IMR */
Alan Coxca605bb2009-08-07 19:24:36 +0100348 sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF);
Alan Coxd19cf322009-08-06 20:45:57 +0100349 /* release IRQ line */
Alan Coxca605bb2009-08-07 19:24:36 +0100350 free_irq(SEP_DIRVER_IRQ_NUM, sep);
Mark Allyncd1bb432009-08-06 20:43:59 +0100351
352#endif
Alan Coxd19cf322009-08-06 20:45:57 +0100353 /* unlock the sep mutex */
354 mutex_unlock(&sep_mutex);
Alan Coxd19cf322009-08-06 20:45:57 +0100355 dbg("SEP Driver:<-------- sep_release end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100356 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100357}
358
359
360
361
362/*---------------------------------------------------------------
363 map function - this functions maps the message shared area
364-----------------------------------------------------------------*/
Alan Coxd19cf322009-08-06 20:45:57 +0100365static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
Mark Allyncd1bb432009-08-06 20:43:59 +0100366{
Alan Cox51faa9d2009-08-14 15:40:45 +0100367 dma_addr_t bus_addr;
Alan Coxca605bb2009-08-07 19:24:36 +0100368 struct sep_device *sep = filp->private_data;
Mark Allyncd1bb432009-08-06 20:43:59 +0100369
Alan Coxd19cf322009-08-06 20:45:57 +0100370 dbg("-------->SEP Driver: mmap start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100371
Alan Coxd19cf322009-08-06 20:45:57 +0100372 /* check that the size of the mapped range is as the size of the message
373 shared area */
374 if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
375 edbg("SEP Driver mmap requested size is more than allowed\n");
376 printk(KERN_WARNING "SEP Driver mmap requested size is more \
Mark Allyncd1bb432009-08-06 20:43:59 +0100377 than allowed\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100378 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end);
379 printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start);
380 return -EAGAIN;
381 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100382
Alan Cox790cf1b2009-08-07 19:25:16 +0100383 edbg("SEP Driver:sep->message_shared_area_addr is %p\n", sep->message_shared_area_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100384
Alan Cox51faa9d2009-08-14 15:40:45 +0100385 /* get bus address */
386 bus_addr = sep->shared_area_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +0100387
Alan Cox51faa9d2009-08-14 15:40:45 +0100388 edbg("SEP Driver: phys_addr is %08llx\n", (unsigned long long)bus_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100389
Alan Cox51faa9d2009-08-14 15:40:45 +0100390 if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
Alan Coxd19cf322009-08-06 20:45:57 +0100391 edbg("SEP Driver remap_page_range failed\n");
392 printk(KERN_WARNING "SEP Driver remap_page_range failed\n");
393 return -EAGAIN;
394 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100395
Alan Coxd19cf322009-08-06 20:45:57 +0100396 dbg("SEP Driver:<-------- mmap end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100397
Alan Coxd19cf322009-08-06 20:45:57 +0100398 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100399}
400
401
402/*-----------------------------------------------
403 poll function
404*----------------------------------------------*/
Alan Coxd19cf322009-08-06 20:45:57 +0100405static unsigned int sep_poll(struct file *filp, poll_table * wait)
Mark Allyncd1bb432009-08-06 20:43:59 +0100406{
Alan Coxd19cf322009-08-06 20:45:57 +0100407 unsigned long count;
Alan Coxd19cf322009-08-06 20:45:57 +0100408 unsigned int mask = 0;
Alan Cox51faa9d2009-08-14 15:40:45 +0100409 unsigned long retval = 0; /* flow id */
Alan Coxca605bb2009-08-07 19:24:36 +0100410 struct sep_device *sep = filp->private_data;
Mark Allyncd1bb432009-08-06 20:43:59 +0100411
Alan Coxd19cf322009-08-06 20:45:57 +0100412 dbg("---------->SEP Driver poll: start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100413
414
415#if SEP_DRIVER_POLLING_MODE
416
Alan Cox51faa9d2009-08-14 15:40:45 +0100417 while (sep->send_ct != (retval & 0x7FFFFFFF)) {
418 retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
Mark Allyncd1bb432009-08-06 20:43:59 +0100419
Alan Coxd19cf322009-08-06 20:45:57 +0100420 for (count = 0; count < 10 * 4; count += 4)
Alan Coxca605bb2009-08-07 19:24:36 +0100421 edbg("Poll Debug Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_area + SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + count)));
Alan Coxd19cf322009-08-06 20:45:57 +0100422 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100423
Alan Coxca605bb2009-08-07 19:24:36 +0100424 sep->reply_ct++;
Mark Allyncd1bb432009-08-06 20:43:59 +0100425#else
Alan Coxd19cf322009-08-06 20:45:57 +0100426 /* add the event to the polling wait table */
Alan Cox904290c2009-08-07 19:24:18 +0100427 poll_wait(filp, &sep_event, wait);
Mark Allyncd1bb432009-08-06 20:43:59 +0100428
429#endif
430
Alan Coxca605bb2009-08-07 19:24:36 +0100431 edbg("sep->send_ct is %lu\n", sep->send_ct);
432 edbg("sep->reply_ct is %lu\n", sep->reply_ct);
Mark Allyncd1bb432009-08-06 20:43:59 +0100433
Alan Coxd19cf322009-08-06 20:45:57 +0100434 /* check if the data is ready */
Alan Coxca605bb2009-08-07 19:24:36 +0100435 if (sep->send_ct == sep->reply_ct) {
Alan Coxd19cf322009-08-06 20:45:57 +0100436 for (count = 0; count < 12 * 4; count += 4)
Alan Coxca605bb2009-08-07 19:24:36 +0100437 edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_area + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +0100438
Alan Coxd19cf322009-08-06 20:45:57 +0100439 for (count = 0; count < 10 * 4; count += 4)
Alan Coxca605bb2009-08-07 19:24:36 +0100440 edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_area + 0x1800 + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +0100441
Alan Cox51faa9d2009-08-14 15:40:45 +0100442 retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
443 edbg("retval is %lu\n", retval);
Alan Coxd19cf322009-08-06 20:45:57 +0100444 /* check if the this is sep reply or request */
Alan Cox51faa9d2009-08-14 15:40:45 +0100445 if (retval >> 31) {
Alan Coxd19cf322009-08-06 20:45:57 +0100446 edbg("SEP Driver: sep request in\n");
447 /* request */
448 mask |= POLLOUT | POLLWRNORM;
449 } else {
450 edbg("SEP Driver: sep reply in\n");
451 mask |= POLLIN | POLLRDNORM;
452 }
Mark Allyncd1bb432009-08-06 20:43:59 +0100453 }
Alan Coxd19cf322009-08-06 20:45:57 +0100454 dbg("SEP Driver:<-------- poll exit\n");
455 return mask;
Mark Allyncd1bb432009-08-06 20:43:59 +0100456}
457
Mark Allyncd1bb432009-08-06 20:43:59 +0100458/*
Alan Cox0a18d7b2009-08-07 19:23:50 +0100459 calculates time and sets it at the predefined address
Mark Allyncd1bb432009-08-06 20:43:59 +0100460*/
Alan Coxca605bb2009-08-07 19:24:36 +0100461static int sep_set_time(struct sep_device *sep, unsigned long *address_ptr, unsigned long *time_in_sec_ptr)
Mark Allyncd1bb432009-08-06 20:43:59 +0100462{
Alan Cox0a18d7b2009-08-07 19:23:50 +0100463 struct timeval time;
464 /* address of time in the kernel */
Alan Cox790cf1b2009-08-07 19:25:16 +0100465 u32 *time_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +0100466
Mark Allyncd1bb432009-08-06 20:43:59 +0100467
Alan Cox0a18d7b2009-08-07 19:23:50 +0100468 dbg("SEP Driver:--------> sep_set_time start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100469
Alan Cox0a18d7b2009-08-07 19:23:50 +0100470 do_gettimeofday(&time);
Mark Allyncd1bb432009-08-06 20:43:59 +0100471
Alan Cox0a18d7b2009-08-07 19:23:50 +0100472 /* set value in the SYSTEM MEMORY offset */
Alan Coxca605bb2009-08-07 19:24:36 +0100473 time_addr = sep->message_shared_area_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +0100474
Alan Cox790cf1b2009-08-07 19:25:16 +0100475 time_addr[0] = SEP_TIME_VAL_TOKEN;
476 time_addr[1] = time.tv_sec;
Mark Allyncd1bb432009-08-06 20:43:59 +0100477
Alan Cox0a18d7b2009-08-07 19:23:50 +0100478 edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec);
Alan Cox790cf1b2009-08-07 19:25:16 +0100479 edbg("SEP Driver:time_addr is %p\n", time_addr);
480 edbg("SEP Driver:sep->message_shared_area_addr is %p\n", sep->message_shared_area_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +0100481
Alan Cox0a18d7b2009-08-07 19:23:50 +0100482 /* set the output parameters if needed */
483 if (address_ptr)
Alan Coxad6b9ab2009-08-07 19:25:43 +0100484 *address_ptr = sep_shared_area_virt_to_bus(sep, time_addr);
Alan Coxd19cf322009-08-06 20:45:57 +0100485
Alan Cox0a18d7b2009-08-07 19:23:50 +0100486 if (time_in_sec_ptr)
487 *time_in_sec_ptr = time.tv_sec;
488
489 dbg("SEP Driver:<-------- sep_set_time end\n");
490
491 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100492}
493
Mark Allyncd1bb432009-08-06 20:43:59 +0100494/*
Alan Cox0a18d7b2009-08-07 19:23:50 +0100495 This function raises interrupt to SEP that signals that is has a new
496 command from HOST
Mark Allyncd1bb432009-08-06 20:43:59 +0100497*/
Alan Coxca605bb2009-08-07 19:24:36 +0100498static void sep_send_command_handler(struct sep_device *sep)
Mark Allyncd1bb432009-08-06 20:43:59 +0100499{
Alan Cox0a18d7b2009-08-07 19:23:50 +0100500 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +0100501
Alan Cox0a18d7b2009-08-07 19:23:50 +0100502 dbg("SEP Driver:--------> sep_send_command_handler start\n");
Alan Coxca605bb2009-08-07 19:24:36 +0100503 sep_set_time(sep, 0, 0);
Mark Allyncd1bb432009-08-06 20:43:59 +0100504
Alan Cox0a18d7b2009-08-07 19:23:50 +0100505 /* flash cache */
506 flush_cache_all();
Mark Allyncd1bb432009-08-06 20:43:59 +0100507
Alan Cox0a18d7b2009-08-07 19:23:50 +0100508 for (count = 0; count < 12 * 4; count += 4)
Alan Coxca605bb2009-08-07 19:24:36 +0100509 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_area + count)));
Mark Allyncd1bb432009-08-06 20:43:59 +0100510
Alan Cox0a18d7b2009-08-07 19:23:50 +0100511 /* update counter */
Alan Coxca605bb2009-08-07 19:24:36 +0100512 sep->send_ct++;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100513 /* send interrupt to SEP */
Alan Coxca605bb2009-08-07 19:24:36 +0100514 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
Alan Cox0a18d7b2009-08-07 19:23:50 +0100515 dbg("SEP Driver:<-------- sep_send_command_handler end\n");
516 return;
517}
Mark Allyncd1bb432009-08-06 20:43:59 +0100518
Alan Cox0a18d7b2009-08-07 19:23:50 +0100519/*
520 This function raises interrupt to SEPm that signals that is has a
521 new command from HOST
522*/
Alan Coxca605bb2009-08-07 19:24:36 +0100523static void sep_send_reply_command_handler(struct sep_device *sep)
Alan Cox0a18d7b2009-08-07 19:23:50 +0100524{
525 unsigned long count;
Mark Allyncd1bb432009-08-06 20:43:59 +0100526
Alan Cox0a18d7b2009-08-07 19:23:50 +0100527 dbg("SEP Driver:--------> sep_send_reply_command_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100528
Alan Cox0a18d7b2009-08-07 19:23:50 +0100529 /* flash cache */
530 flush_cache_all();
531 for (count = 0; count < 12 * 4; count += 4)
Alan Coxca605bb2009-08-07 19:24:36 +0100532 edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_area + count)));
Alan Cox0a18d7b2009-08-07 19:23:50 +0100533 /* update counter */
Alan Coxca605bb2009-08-07 19:24:36 +0100534 sep->send_ct++;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100535 /* send the interrupt to SEP */
Alan Coxca605bb2009-08-07 19:24:36 +0100536 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct);
Alan Cox0a18d7b2009-08-07 19:23:50 +0100537 /* update both counters */
Alan Coxca605bb2009-08-07 19:24:36 +0100538 sep->send_ct++;
539 sep->reply_ct++;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100540 dbg("SEP Driver:<-------- sep_send_reply_command_handler end\n");
541}
542
543/*
544 This function handles the allocate data pool memory request
Alan Cox51faa9d2009-08-14 15:40:45 +0100545 This function returns calculates the bus address of the
Alan Cox0a18d7b2009-08-07 19:23:50 +0100546 allocated memory, and the offset of this area from the mapped address.
547 Therefore, the FVOs in user space can calculate the exact virtual
548 address of this allocated memory
549*/
Alan Coxca605bb2009-08-07 19:24:36 +0100550static int sep_allocate_data_pool_memory_handler(struct sep_device *sep,
551 unsigned long arg)
Alan Cox0a18d7b2009-08-07 19:23:50 +0100552{
553 int error;
554 struct sep_driver_alloc_t command_args;
555
556 dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n");
557
558 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t));
559 if (error)
560 goto end_function;
561
562 /* allocate memory */
Alan Coxca605bb2009-08-07 19:24:36 +0100563 if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
Alan Cox51faa9d2009-08-14 15:40:45 +0100564 error = -ENOMEM;
Alan Coxd19cf322009-08-06 20:45:57 +0100565 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +0100566 }
567
Alan Cox51faa9d2009-08-14 15:40:45 +0100568 /* set the virtual and bus address */
Alan Coxca605bb2009-08-07 19:24:36 +0100569 command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated;
570 command_args.phys_address = sep->shared_area_bus + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated;
Mark Allyncd1bb432009-08-06 20:43:59 +0100571
Alan Cox0a18d7b2009-08-07 19:23:50 +0100572 /* write the memory back to the user space */
573 error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t));
574 if (error)
575 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +0100576
Alan Cox0a18d7b2009-08-07 19:23:50 +0100577 /* set the allocation */
Alan Coxca605bb2009-08-07 19:24:36 +0100578 sep->data_pool_bytes_allocated += command_args.num_bytes;
Mark Allyncd1bb432009-08-06 20:43:59 +0100579
Alan Coxf93e4bf2009-08-06 20:46:08 +0100580end_function:
Alan Cox0a18d7b2009-08-07 19:23:50 +0100581 dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n");
582 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +0100583}
584
585/*
Alan Cox0a18d7b2009-08-07 19:23:50 +0100586 This function handles write into allocated data pool command
Mark Allyncd1bb432009-08-06 20:43:59 +0100587*/
Alan Coxca605bb2009-08-07 19:24:36 +0100588static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +0100589{
Alan Cox0a18d7b2009-08-07 19:23:50 +0100590 int error;
Alan Cox790cf1b2009-08-07 19:25:16 +0100591 void *virt_address;
592 unsigned long va;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100593 unsigned long app_in_address;
594 unsigned long num_bytes;
Alan Cox790cf1b2009-08-07 19:25:16 +0100595 void *data_pool_area_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +0100596
Alan Cox0a18d7b2009-08-07 19:23:50 +0100597 dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100598
Alan Cox0a18d7b2009-08-07 19:23:50 +0100599 /* get the application address */
600 error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address));
601 if (error)
602 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +0100603
Alan Cox0a18d7b2009-08-07 19:23:50 +0100604 /* get the virtual kernel address address */
Alan Cox790cf1b2009-08-07 19:25:16 +0100605 error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address));
Alan Cox0a18d7b2009-08-07 19:23:50 +0100606 if (error)
607 goto end_function;
Alan Cox790cf1b2009-08-07 19:25:16 +0100608 virt_address = (void *)va;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100609
610 /* get the number of bytes */
611 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
612 if (error)
613 goto end_function;
614
615 /* calculate the start of the data pool */
Alan Coxca605bb2009-08-07 19:24:36 +0100616 data_pool_area_addr = sep->shared_area + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100617
618
619 /* check that the range of the virtual kernel address is correct */
Alan Coxca605bb2009-08-07 19:24:36 +0100620 if (virt_address < data_pool_area_addr || virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)) {
Alan Cox51faa9d2009-08-14 15:40:45 +0100621 error = -EINVAL;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100622 goto end_function;
623 }
624 /* copy the application data */
Alan Cox790cf1b2009-08-07 19:25:16 +0100625 error = copy_from_user(virt_address, (void *) app_in_address, num_bytes);
Alan Cox0a18d7b2009-08-07 19:23:50 +0100626end_function:
627 dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n");
628 return error;
629}
630
631/*
632 this function handles the read from data pool command
633*/
Alan Coxca605bb2009-08-07 19:24:36 +0100634static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long arg)
Alan Cox0a18d7b2009-08-07 19:23:50 +0100635{
636 int error;
637 /* virtual address of dest application buffer */
638 unsigned long app_out_address;
639 /* virtual address of the data pool */
Alan Cox790cf1b2009-08-07 19:25:16 +0100640 unsigned long va;
641 void *virt_address;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100642 unsigned long num_bytes;
Alan Cox790cf1b2009-08-07 19:25:16 +0100643 void *data_pool_area_addr;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100644
645 dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n");
646
647 /* get the application address */
648 error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address));
649 if (error)
650 goto end_function;
651
652 /* get the virtual kernel address address */
Alan Cox790cf1b2009-08-07 19:25:16 +0100653 error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address));
Alan Cox0a18d7b2009-08-07 19:23:50 +0100654 if (error)
655 goto end_function;
Alan Cox790cf1b2009-08-07 19:25:16 +0100656 virt_address = (void *)va;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100657
658 /* get the number of bytes */
659 error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes));
660 if (error)
661 goto end_function;
662
663 /* calculate the start of the data pool */
Alan Coxca605bb2009-08-07 19:24:36 +0100664 data_pool_area_addr = sep->shared_area + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100665
Alan Coxca605bb2009-08-07 19:24:36 +0100666 /* FIXME: These are incomplete all over the driver: what about + len
667 and when doing that also overflows */
Alan Cox0a18d7b2009-08-07 19:23:50 +0100668 /* check that the range of the virtual kernel address is correct */
Alan Coxca605bb2009-08-07 19:24:36 +0100669 if (virt_address < data_pool_area_addr || virt_address > data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
Alan Cox51faa9d2009-08-14 15:40:45 +0100670 error = -EINVAL;
Alan Cox0a18d7b2009-08-07 19:23:50 +0100671 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +0100672 }
Alan Coxd19cf322009-08-06 20:45:57 +0100673
Alan Cox0a18d7b2009-08-07 19:23:50 +0100674 /* copy the application data */
Alan Cox790cf1b2009-08-07 19:25:16 +0100675 error = copy_to_user((void *) app_out_address, virt_address, num_bytes);
Alan Cox0a18d7b2009-08-07 19:23:50 +0100676end_function:
677 dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n");
678 return error;
679}
680
681/*
682 This function releases all the application virtual buffer physical pages,
683 that were previously locked
684*/
685static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag)
686{
687 unsigned long count;
688
689 if (dirtyFlag) {
690 for (count = 0; count < num_pages; count++) {
691 /* the out array was written, therefore the data was changed */
692 if (!PageReserved(page_array_ptr[count]))
693 SetPageDirty(page_array_ptr[count]);
694 page_cache_release(page_array_ptr[count]);
Alan Coxd19cf322009-08-06 20:45:57 +0100695 }
696 } else {
Alan Cox0a18d7b2009-08-07 19:23:50 +0100697 /* free in pages - the data was only read, therefore no update was done
698 on those pages */
699 for (count = 0; count < num_pages; count++)
700 page_cache_release(page_array_ptr[count]);
Mark Allyncd1bb432009-08-06 20:43:59 +0100701 }
Alan Coxd19cf322009-08-06 20:45:57 +0100702
Alan Cox0a18d7b2009-08-07 19:23:50 +0100703 if (page_array_ptr)
704 /* free the array */
705 kfree(page_array_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +0100706
Alan Cox0a18d7b2009-08-07 19:23:50 +0100707 return 0;
708}
709
710/*
711 This function locks all the physical pages of the kernel virtual buffer
712 and construct a basic lli array, where each entry holds the physical
713 page address and the size that application data holds in this physical pages
714*/
Alan Coxca605bb2009-08-07 19:24:36 +0100715static int sep_lock_kernel_pages(struct sep_device *sep,
716 unsigned long kernel_virt_addr,
717 unsigned long data_size,
718 unsigned long *num_pages_ptr,
719 struct sep_lli_entry_t **lli_array_ptr,
720 struct page ***page_array_ptr)
Alan Cox0a18d7b2009-08-07 19:23:50 +0100721{
722 int error = 0;
723 /* the the page of the end address of the user space buffer */
724 unsigned long end_page;
725 /* the page of the start address of the user space buffer */
726 unsigned long start_page;
727 /* the range in pages */
728 unsigned long num_pages;
729 struct sep_lli_entry_t *lli_array;
730 /* next kernel address to map */
731 unsigned long next_kernel_address;
732 unsigned long count;
733
734 dbg("SEP Driver:--------> sep_lock_kernel_pages start\n");
735
736 /* set start and end pages and num pages */
737 end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT;
738 start_page = kernel_virt_addr >> PAGE_SHIFT;
739 num_pages = end_page - start_page + 1;
740
741 edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr);
742 edbg("SEP Driver: data_size is %lu\n", data_size);
743 edbg("SEP Driver: start_page is %lx\n", start_page);
744 edbg("SEP Driver: end_page is %lx\n", end_page);
745 edbg("SEP Driver: num_pages is %lu\n", num_pages);
746
747 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
748 if (!lli_array) {
749 edbg("SEP Driver: kmalloc for lli_array failed\n");
750 error = -ENOMEM;
751 goto end_function;
752 }
753
754 /* set the start address of the first page - app data may start not at
755 the beginning of the page */
756 lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr);
757
758 /* check that not all the data is in the first page only */
759 if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size)
760 lli_array[0].block_size = data_size;
761 else
762 lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK));
763
764 /* debug print */
765 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);
766
767 /* advance the address to the start of the next page */
768 next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE;
769
770 /* go from the second page to the prev before last */
771 for (count = 1; count < (num_pages - 1); count++) {
772 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
773 lli_array[count].block_size = PAGE_SIZE;
774
775 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);
776 next_kernel_address += PAGE_SIZE;
777 }
778
779 /* if more then 1 pages locked - then update for the last page size needed */
780 if (num_pages > 1) {
781 /* update the address of the last page */
782 lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address);
783
784 /* set the size of the last page */
785 lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK);
786
787 if (lli_array[count].block_size == 0) {
788 dbg("app_virt_addr is %08lx\n", kernel_virt_addr);
789 dbg("data_size is %lu\n", data_size);
790 while (1);
791 }
792
793 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);
794 }
795 /* set output params */
796 *lli_array_ptr = lli_array;
797 *num_pages_ptr = num_pages;
798 *page_array_ptr = 0;
799end_function:
800 dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n");
801 return 0;
802}
803
804/*
805 This function locks all the physical pages of the application virtual buffer
806 and construct a basic lli array, where each entry holds the physical page
807 address and the size that application data holds in this physical pages
808*/
Alan Coxca605bb2009-08-07 19:24:36 +0100809static int sep_lock_user_pages(struct sep_device *sep,
810 unsigned long app_virt_addr,
811 unsigned long data_size,
812 unsigned long *num_pages_ptr,
813 struct sep_lli_entry_t **lli_array_ptr,
814 struct page ***page_array_ptr)
Alan Cox0a18d7b2009-08-07 19:23:50 +0100815{
816 int error = 0;
817 /* the the page of the end address of the user space buffer */
818 unsigned long end_page;
819 /* the page of the start address of the user space buffer */
820 unsigned long start_page;
821 /* the range in pages */
822 unsigned long num_pages;
823 struct page **page_array;
824 struct sep_lli_entry_t *lli_array;
825 unsigned long count;
826 int result;
827
828 dbg("SEP Driver:--------> sep_lock_user_pages start\n");
829
830 /* set start and end pages and num pages */
831 end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
832 start_page = app_virt_addr >> PAGE_SHIFT;
833 num_pages = end_page - start_page + 1;
834
835 edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr);
836 edbg("SEP Driver: data_size is %lu\n", data_size);
837 edbg("SEP Driver: start_page is %lu\n", start_page);
838 edbg("SEP Driver: end_page is %lu\n", end_page);
839 edbg("SEP Driver: num_pages is %lu\n", num_pages);
840
841 /* allocate array of pages structure pointers */
842 page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
843 if (!page_array) {
844 edbg("SEP Driver: kmalloc for page_array failed\n");
845
846 error = -ENOMEM;
847 goto end_function;
848 }
849
850 lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
851 if (!lli_array) {
852 edbg("SEP Driver: kmalloc for lli_array failed\n");
853
854 error = -ENOMEM;
855 goto end_function_with_error1;
856 }
857
858 /* convert the application virtual address into a set of physical */
859 down_read(&current->mm->mmap_sem);
860 result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0);
861 up_read(&current->mm->mmap_sem);
862
863 /* check the number of pages locked - if not all then exit with error */
864 if (result != num_pages) {
865 dbg("SEP Driver: not all pages locked by get_user_pages\n");
866
867 error = -ENOMEM;
Alan Coxd19cf322009-08-06 20:45:57 +0100868 goto end_function_with_error2;
Mark Allyncd1bb432009-08-06 20:43:59 +0100869 }
Alan Coxd19cf322009-08-06 20:45:57 +0100870
Alan Cox0a18d7b2009-08-07 19:23:50 +0100871 /* flush the cache */
872 for (count = 0; count < num_pages; count++)
873 flush_dcache_page(page_array[count]);
Mark Allyncd1bb432009-08-06 20:43:59 +0100874
Alan Cox0a18d7b2009-08-07 19:23:50 +0100875 /* set the start address of the first page - app data may start not at
876 the beginning of the page */
877 lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK));
Mark Allyncd1bb432009-08-06 20:43:59 +0100878
Alan Cox0a18d7b2009-08-07 19:23:50 +0100879 /* check that not all the data is in the first page only */
880 if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
881 lli_array[0].block_size = data_size;
882 else
883 lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
Mark Allyncd1bb432009-08-06 20:43:59 +0100884
Alan Cox0a18d7b2009-08-07 19:23:50 +0100885 /* debug print */
886 dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100887
Alan Cox0a18d7b2009-08-07 19:23:50 +0100888 /* go from the second page to the prev before last */
889 for (count = 1; count < (num_pages - 1); count++) {
890 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
891 lli_array[count].block_size = PAGE_SIZE;
Mark Allyncd1bb432009-08-06 20:43:59 +0100892
Alan Cox0a18d7b2009-08-07 19:23:50 +0100893 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);
Mark Allyncd1bb432009-08-06 20:43:59 +0100894 }
895
Alan Cox0a18d7b2009-08-07 19:23:50 +0100896 /* if more then 1 pages locked - then update for the last page size needed */
897 if (num_pages > 1) {
898 /* update the address of the last page */
899 lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
900
901 /* set the size of the last page */
902 lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK);
903
904 if (lli_array[count].block_size == 0) {
905 dbg("app_virt_addr is %08lx\n", app_virt_addr);
906 dbg("data_size is %lu\n", data_size);
907 while (1);
908 }
909 edbg("lli_array[%lu].physical_address is %08lx, \
910 lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
911 }
912
913 /* set output params */
914 *lli_array_ptr = lli_array;
915 *num_pages_ptr = num_pages;
916 *page_array_ptr = page_array;
917 goto end_function;
918
919end_function_with_error2:
920 /* release the cache */
921 for (count = 0; count < num_pages; count++)
922 page_cache_release(page_array[count]);
923 kfree(lli_array);
924end_function_with_error1:
925 kfree(page_array);
926end_function:
927 dbg("SEP Driver:<-------- sep_lock_user_pages end\n");
Alan Coxd19cf322009-08-06 20:45:57 +0100928 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +0100929}
930
Alan Cox0a18d7b2009-08-07 19:23:50 +0100931
Mark Allyncd1bb432009-08-06 20:43:59 +0100932/*
933 this function calculates the size of data that can be inserted into the lli
934 table from this array the condition is that either the table is full
935 (all etnries are entered), or there are no more entries in the lli array
936*/
Alan Coxb10b4832009-08-07 19:23:26 +0100937static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries)
Mark Allyncd1bb432009-08-06 20:43:59 +0100938{
Alan Coxf93e4bf2009-08-06 20:46:08 +0100939 unsigned long table_data_size = 0;
Alan Coxd19cf322009-08-06 20:45:57 +0100940 unsigned long counter;
Mark Allyncd1bb432009-08-06 20:43:59 +0100941
Alan Coxd19cf322009-08-06 20:45:57 +0100942 /* calculate the data in the out lli table if till we fill the whole
943 table or till the data has ended */
944 for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++)
945 table_data_size += lli_in_array_ptr[counter].block_size;
Alan Coxd19cf322009-08-06 20:45:57 +0100946 return table_data_size;
Mark Allyncd1bb432009-08-06 20:43:59 +0100947}
948
949/*
950 this functions builds ont lli table from the lli_array according to
951 the given size of data
952*/
Alan Coxd19cf322009-08-06 20:45:57 +0100953static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size)
Mark Allyncd1bb432009-08-06 20:43:59 +0100954{
Alan Coxd19cf322009-08-06 20:45:57 +0100955 unsigned long curr_table_data_size;
Alan Coxd19cf322009-08-06 20:45:57 +0100956 /* counter of lli array entry */
957 unsigned long array_counter;
Mark Allyncd1bb432009-08-06 20:43:59 +0100958
Alan Coxd19cf322009-08-06 20:45:57 +0100959 dbg("SEP Driver:--------> sep_build_lli_table start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100960
Alan Coxd19cf322009-08-06 20:45:57 +0100961 /* init currrent table data size and lli array entry counter */
962 curr_table_data_size = 0;
963 array_counter = 0;
964 *num_table_entries_ptr = 1;
Mark Allyncd1bb432009-08-06 20:43:59 +0100965
Alan Coxd19cf322009-08-06 20:45:57 +0100966 edbg("SEP Driver:table_data_size is %lu\n", table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100967
Alan Coxd19cf322009-08-06 20:45:57 +0100968 /* fill the table till table size reaches the needed amount */
969 while (curr_table_data_size < table_data_size) {
970 /* update the number of entries in table */
971 (*num_table_entries_ptr)++;
Mark Allyncd1bb432009-08-06 20:43:59 +0100972
Alan Coxd19cf322009-08-06 20:45:57 +0100973 lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address;
974 lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size;
975 curr_table_data_size += lli_table_ptr->block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +0100976
Alan Coxd19cf322009-08-06 20:45:57 +0100977 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
978 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
979 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100980
Alan Coxd19cf322009-08-06 20:45:57 +0100981 /* check for overflow of the table data */
982 if (curr_table_data_size > table_data_size) {
983 edbg("SEP Driver:curr_table_data_size > table_data_size\n");
Mark Allyncd1bb432009-08-06 20:43:59 +0100984
Alan Coxd19cf322009-08-06 20:45:57 +0100985 /* update the size of block in the table */
986 lli_table_ptr->block_size -= (curr_table_data_size - table_data_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100987
Alan Coxd19cf322009-08-06 20:45:57 +0100988 /* update the physical address in the lli array */
989 lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size;
Mark Allyncd1bb432009-08-06 20:43:59 +0100990
Alan Coxd19cf322009-08-06 20:45:57 +0100991 /* update the block size left in the lli array */
992 lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size);
993 } else
994 /* advance to the next entry in the lli_array */
995 array_counter++;
Mark Allyncd1bb432009-08-06 20:43:59 +0100996
Alan Coxd19cf322009-08-06 20:45:57 +0100997 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
998 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +0100999
Alan Coxd19cf322009-08-06 20:45:57 +01001000 /* move to the next entry in table */
1001 lli_table_ptr++;
1002 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001003
Alan Coxd19cf322009-08-06 20:45:57 +01001004 /* set the info entry to default */
1005 lli_table_ptr->physical_address = 0xffffffff;
1006 lli_table_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001007
Alan Coxd19cf322009-08-06 20:45:57 +01001008 edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr);
1009 edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1010 edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001011
Alan Coxd19cf322009-08-06 20:45:57 +01001012 /* set the output parameter */
1013 *num_processed_entries_ptr += array_counter;
Mark Allyncd1bb432009-08-06 20:43:59 +01001014
Alan Coxd19cf322009-08-06 20:45:57 +01001015 edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01001016 dbg("SEP Driver:<-------- sep_build_lli_table end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001017 return;
Mark Allyncd1bb432009-08-06 20:43:59 +01001018}
1019
1020/*
1021 this function goes over the list of the print created tables and
1022 prints all the data
1023*/
Alan Coxca605bb2009-08-07 19:24:36 +01001024static 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)
Mark Allyncd1bb432009-08-06 20:43:59 +01001025{
Alan Coxd19cf322009-08-06 20:45:57 +01001026 unsigned long table_count;
Alan Coxd19cf322009-08-06 20:45:57 +01001027 unsigned long entries_count;
Mark Allyncd1bb432009-08-06 20:43:59 +01001028
Alan Coxd19cf322009-08-06 20:45:57 +01001029 dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001030
Alan Coxd19cf322009-08-06 20:45:57 +01001031 table_count = 1;
1032 while ((unsigned long) lli_table_ptr != 0xffffffff) {
1033 edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size);
1034 edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries);
Mark Allyncd1bb432009-08-06 20:43:59 +01001035
Alan Coxd19cf322009-08-06 20:45:57 +01001036 /* print entries of the table (without info entry) */
1037 for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) {
1038 edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr);
1039 edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size);
1040 }
1041
1042 /* point to the info entry */
1043 lli_table_ptr--;
1044
1045 edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size);
1046 edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address);
1047
1048
1049 table_data_size = lli_table_ptr->block_size & 0xffffff;
1050 num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
1051 lli_table_ptr = (struct sep_lli_entry_t *)
1052 (lli_table_ptr->physical_address);
1053
1054 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);
1055
1056 if ((unsigned long) lli_table_ptr != 0xffffffff)
Alan Coxad6b9ab2009-08-07 19:25:43 +01001057 lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_area_bus_to_virt(sep, (unsigned long) lli_table_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01001058
1059 table_count++;
Mark Allyncd1bb432009-08-06 20:43:59 +01001060 }
Alan Coxd19cf322009-08-06 20:45:57 +01001061 dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001062}
1063
1064
1065/*
Alan Cox0a18d7b2009-08-07 19:23:50 +01001066 This function prepares only input DMA table for synhronic symmetric
1067 operations (HASH)
Mark Allyncd1bb432009-08-06 20:43:59 +01001068*/
Alan Coxca605bb2009-08-07 19:24:36 +01001069static int sep_prepare_input_dma_table(struct sep_device *sep,
1070 unsigned long app_virt_addr,
1071 unsigned long data_size,
1072 unsigned long block_size,
1073 unsigned long *lli_table_ptr,
1074 unsigned long *num_entries_ptr,
1075 unsigned long *table_data_size_ptr,
1076 bool isKernelVirtualAddress)
Mark Allyncd1bb432009-08-06 20:43:59 +01001077{
Alan Cox0a18d7b2009-08-07 19:23:50 +01001078 /* pointer to the info entry of the table - the last entry */
1079 struct sep_lli_entry_t *info_entry_ptr;
1080 /* array of pointers ot page */
1081 struct sep_lli_entry_t *lli_array_ptr;
1082 /* points to the first entry to be processed in the lli_in_array */
1083 unsigned long current_entry;
1084 /* num entries in the virtual buffer */
1085 unsigned long sep_lli_entries;
1086 /* lli table pointer */
1087 struct sep_lli_entry_t *in_lli_table_ptr;
1088 /* the total data in one table */
1089 unsigned long table_data_size;
1090 /* number of entries in lli table */
1091 unsigned long num_entries_in_table;
1092 /* next table address */
Alan Cox790cf1b2009-08-07 19:25:16 +01001093 void *lli_table_alloc_addr;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001094 unsigned long result;
Mark Allyncd1bb432009-08-06 20:43:59 +01001095
Alan Cox0a18d7b2009-08-07 19:23:50 +01001096 dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001097
Alan Cox0a18d7b2009-08-07 19:23:50 +01001098 edbg("SEP Driver:data_size is %lu\n", data_size);
1099 edbg("SEP Driver:block_size is %lu\n", block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001100
Alan Cox0a18d7b2009-08-07 19:23:50 +01001101 /* initialize the pages pointers */
Alan Coxca605bb2009-08-07 19:24:36 +01001102 sep->in_page_array = 0;
1103 sep->in_num_pages = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001104
Alan Cox0a18d7b2009-08-07 19:23:50 +01001105 if (data_size == 0) {
1106 /* special case - created 2 entries table with zero data */
Alan Coxca605bb2009-08-07 19:24:36 +01001107 in_lli_table_ptr = (struct sep_lli_entry_t *) (sep->shared_area + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES);
Alan Cox790cf1b2009-08-07 19:25:16 +01001108 /* FIXME: Should the entry below not be for _bus */
1109 in_lli_table_ptr->physical_address = (unsigned long)sep->shared_area + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001110 in_lli_table_ptr->block_size = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001111
Alan Cox0a18d7b2009-08-07 19:23:50 +01001112 in_lli_table_ptr++;
1113 in_lli_table_ptr->physical_address = 0xFFFFFFFF;
1114 in_lli_table_ptr->block_size = 0;
1115
Alan Coxca605bb2009-08-07 19:24:36 +01001116 *lli_table_ptr = sep->shared_area_bus + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001117 *num_entries_ptr = 2;
1118 *table_data_size_ptr = 0;
1119
Alan Coxd19cf322009-08-06 20:45:57 +01001120 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001121 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001122
Alan Cox0a18d7b2009-08-07 19:23:50 +01001123 /* check if the pages are in Kernel Virtual Address layout */
1124 if (isKernelVirtualAddress == true)
1125 /* lock the pages of the kernel buffer and translate them to pages */
Alan Coxca605bb2009-08-07 19:24:36 +01001126 result = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001127 else
1128 /* lock the pages of the user buffer and translate them to pages */
Alan Coxca605bb2009-08-07 19:24:36 +01001129 result = sep_lock_user_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array);
Mark Allyncd1bb432009-08-06 20:43:59 +01001130
Alan Cox0a18d7b2009-08-07 19:23:50 +01001131 if (result)
1132 return result;
1133
Alan Coxca605bb2009-08-07 19:24:36 +01001134 edbg("SEP Driver:output sep->in_num_pages is %lu\n", sep->in_num_pages);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001135
1136 current_entry = 0;
1137 info_entry_ptr = 0;
Alan Coxca605bb2009-08-07 19:24:36 +01001138 sep_lli_entries = sep->in_num_pages;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001139
1140 /* initiate to point after the message area */
Alan Coxca605bb2009-08-07 19:24:36 +01001141 lli_table_alloc_addr = sep->shared_area + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001142
1143 /* loop till all the entries in in array are not processed */
1144 while (current_entry < sep_lli_entries) {
1145 /* set the new input and output tables */
1146 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
1147
1148 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
1149
1150 /* calculate the maximum size of data for input table */
1151 table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry));
1152
1153 /* now calculate the table size so that it will be module block size */
1154 table_data_size = (table_data_size / block_size) * block_size;
1155
1156 edbg("SEP Driver:output table_data_size is %lu\n", table_data_size);
1157
1158 /* construct input lli table */
1159 sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, &current_entry, &num_entries_in_table, table_data_size);
1160
1161 if (info_entry_ptr == 0) {
1162 /* set the output parameters to physical addresses */
Alan Coxad6b9ab2009-08-07 19:25:43 +01001163 *lli_table_ptr = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001164 *num_entries_ptr = num_entries_in_table;
1165 *table_data_size_ptr = table_data_size;
1166
1167 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr);
1168 } else {
1169 /* update the info entry of the previous in table */
Alan Coxad6b9ab2009-08-07 19:25:43 +01001170 info_entry_ptr->physical_address = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001171 info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
1172 }
1173
1174 /* save the pointer to the info entry of the current tables */
1175 info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
Alan Coxd19cf322009-08-06 20:45:57 +01001176 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001177
Alan Cox0a18d7b2009-08-07 19:23:50 +01001178 /* print input tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001179 sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *)
Alan Coxad6b9ab2009-08-07 19:25:43 +01001180 sep_shared_area_bus_to_virt(sep, *lli_table_ptr), *num_entries_ptr, *table_data_size_ptr);
Mark Allyncd1bb432009-08-06 20:43:59 +01001181
Alan Cox0a18d7b2009-08-07 19:23:50 +01001182 /* the array of the pages */
1183 kfree(lli_array_ptr);
1184end_function:
1185 dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n");
1186 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001187
Alan Cox0a18d7b2009-08-07 19:23:50 +01001188}
1189
1190/*
1191 This function creates the input and output dma tables for
1192 symmetric operations (AES/DES) according to the block size from LLI arays
1193*/
Alan Coxca605bb2009-08-07 19:24:36 +01001194static int sep_construct_dma_tables_from_lli(struct sep_device *sep,
1195 struct sep_lli_entry_t *lli_in_array,
Alan Cox0a18d7b2009-08-07 19:23:50 +01001196 unsigned long sep_in_lli_entries,
1197 struct sep_lli_entry_t *lli_out_array,
1198 unsigned long sep_out_lli_entries,
1199 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)
1200{
Alan Cox790cf1b2009-08-07 19:25:16 +01001201 /* points to the area where next lli table can be allocated: keep void *
1202 as there is pointer scaling to fix otherwise */
1203 void *lli_table_alloc_addr;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001204 /* input lli table */
1205 struct sep_lli_entry_t *in_lli_table_ptr;
1206 /* output lli table */
1207 struct sep_lli_entry_t *out_lli_table_ptr;
1208 /* pointer to the info entry of the table - the last entry */
1209 struct sep_lli_entry_t *info_in_entry_ptr;
1210 /* pointer to the info entry of the table - the last entry */
1211 struct sep_lli_entry_t *info_out_entry_ptr;
1212 /* points to the first entry to be processed in the lli_in_array */
1213 unsigned long current_in_entry;
1214 /* points to the first entry to be processed in the lli_out_array */
1215 unsigned long current_out_entry;
1216 /* max size of the input table */
1217 unsigned long in_table_data_size;
1218 /* max size of the output table */
1219 unsigned long out_table_data_size;
1220 /* flag te signifies if this is the first tables build from the arrays */
1221 unsigned long first_table_flag;
1222 /* the data size that should be in table */
1223 unsigned long table_data_size;
1224 /* number of etnries in the input table */
1225 unsigned long num_entries_in_table;
1226 /* number of etnries in the output table */
1227 unsigned long num_entries_out_table;
1228
1229 dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n");
1230
1231 /* initiate to pint after the message area */
Alan Coxca605bb2009-08-07 19:24:36 +01001232 lli_table_alloc_addr = sep->shared_area + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001233
1234 current_in_entry = 0;
1235 current_out_entry = 0;
1236 first_table_flag = 1;
1237 info_in_entry_ptr = 0;
1238 info_out_entry_ptr = 0;
1239
1240 /* loop till all the entries in in array are not processed */
1241 while (current_in_entry < sep_in_lli_entries) {
1242 /* set the new input and output tables */
1243 in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
1244
1245 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
1246
1247 /* set the first output tables */
1248 out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr;
1249
1250 lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
1251
1252 /* calculate the maximum size of data for input table */
1253 in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry));
1254
1255 /* calculate the maximum size of data for output table */
1256 out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry));
1257
1258 edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size);
1259 edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size);
1260
1261 /* check where the data is smallest */
1262 table_data_size = in_table_data_size;
1263 if (table_data_size > out_table_data_size)
1264 table_data_size = out_table_data_size;
1265
1266 /* now calculate the table size so that it will be module block size */
1267 table_data_size = (table_data_size / block_size) * block_size;
1268
1269 dbg("SEP Driver:table_data_size is %lu\n", table_data_size);
1270
1271 /* construct input lli table */
1272 sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, &current_in_entry, &num_entries_in_table, table_data_size);
1273
1274 /* construct output lli table */
1275 sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, &current_out_entry, &num_entries_out_table, table_data_size);
1276
1277 /* if info entry is null - this is the first table built */
1278 if (info_in_entry_ptr == 0) {
1279 /* set the output parameters to physical addresses */
Alan Coxad6b9ab2009-08-07 19:25:43 +01001280 *lli_table_in_ptr = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001281 *in_num_entries_ptr = num_entries_in_table;
Alan Coxad6b9ab2009-08-07 19:25:43 +01001282 *lli_table_out_ptr = sep_shared_area_virt_to_bus(sep, out_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001283 *out_num_entries_ptr = num_entries_out_table;
1284 *table_data_size_ptr = table_data_size;
1285
1286 edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr);
1287 edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr);
1288 } else {
1289 /* update the info entry of the previous in table */
Alan Coxad6b9ab2009-08-07 19:25:43 +01001290 info_in_entry_ptr->physical_address = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001291 info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size);
1292
1293 /* update the info entry of the previous in table */
Alan Coxad6b9ab2009-08-07 19:25:43 +01001294 info_out_entry_ptr->physical_address = sep_shared_area_virt_to_bus(sep, out_lli_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001295 info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size);
1296 }
1297
1298 /* save the pointer to the info entry of the current tables */
1299 info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
1300 info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1;
1301
1302 edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table);
1303 edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr);
1304 edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr);
1305 }
1306
1307 /* print input tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001308 sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *)
Alan Coxad6b9ab2009-08-07 19:25:43 +01001309 sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001310 /* print output tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001311 sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *)
Alan Coxad6b9ab2009-08-07 19:25:43 +01001312 sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001313 dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n");
1314 return 0;
1315}
1316
1317
1318/*
1319 This function builds input and output DMA tables for synhronic
1320 symmetric operations (AES, DES). It also checks that each table
1321 is of the modular block size
1322*/
Alan Coxca605bb2009-08-07 19:24:36 +01001323static int sep_prepare_input_output_dma_table(struct sep_device *sep,
1324 unsigned long app_virt_in_addr,
Alan Cox0a18d7b2009-08-07 19:23:50 +01001325 unsigned long app_virt_out_addr,
1326 unsigned long data_size,
1327 unsigned long block_size,
1328 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)
1329{
1330 /* array of pointers of page */
1331 struct sep_lli_entry_t *lli_in_array;
1332 /* array of pointers of page */
1333 struct sep_lli_entry_t *lli_out_array;
1334 int result = 0;
1335
1336 dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n");
1337
1338 /* initialize the pages pointers */
Alan Coxca605bb2009-08-07 19:24:36 +01001339 sep->in_page_array = 0;
1340 sep->out_page_array = 0;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001341
1342 /* check if the pages are in Kernel Virtual Address layout */
1343 if (isKernelVirtualAddress == true) {
1344 /* lock the pages of the kernel buffer and translate them to pages */
Alan Coxca605bb2009-08-07 19:24:36 +01001345 result = sep_lock_kernel_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001346 if (result) {
1347 edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n");
1348 goto end_function;
1349 }
1350 } else {
1351 /* lock the pages of the user buffer and translate them to pages */
Alan Coxca605bb2009-08-07 19:24:36 +01001352 result = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001353 if (result) {
1354 edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n");
1355 goto end_function;
1356 }
1357 }
1358
1359 if (isKernelVirtualAddress == true) {
Alan Coxca605bb2009-08-07 19:24:36 +01001360 result = sep_lock_kernel_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001361 if (result) {
1362 edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n");
1363 goto end_function_with_error1;
1364 }
1365 } else {
Alan Coxca605bb2009-08-07 19:24:36 +01001366 result = sep_lock_user_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001367 if (result) {
1368 edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n");
1369 goto end_function_with_error1;
1370 }
1371 }
Alan Coxca605bb2009-08-07 19:24:36 +01001372 edbg("sep->in_num_pages is %lu\n", sep->in_num_pages);
1373 edbg("sep->out_num_pages is %lu\n", sep->out_num_pages);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001374 edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
1375
1376
1377 /* call the fucntion that creates table from the lli arrays */
Alan Coxca605bb2009-08-07 19:24:36 +01001378 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);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001379 if (result) {
1380 edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001381 goto end_function_with_error2;
1382 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001383
Alan Cox0a18d7b2009-08-07 19:23:50 +01001384 /* fall through - free the lli entry arrays */
1385 dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr);
1386 dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr);
1387 dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001388end_function_with_error2:
Alan Cox0a18d7b2009-08-07 19:23:50 +01001389 kfree(lli_out_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001390end_function_with_error1:
Alan Cox0a18d7b2009-08-07 19:23:50 +01001391 kfree(lli_in_array);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001392end_function:
Alan Cox0a18d7b2009-08-07 19:23:50 +01001393 dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result);
1394 return result;
1395
Mark Allyncd1bb432009-08-06 20:43:59 +01001396}
1397
1398/*
Mark Allyncd1bb432009-08-06 20:43:59 +01001399 this function handles tha request for creation of the DMA table
1400 for the synchronic symmetric operations (AES,DES)
1401*/
Alan Coxca605bb2009-08-07 19:24:36 +01001402static int sep_create_sync_dma_tables_handler(struct sep_device *sep,
1403 unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001404{
Alan Coxd19cf322009-08-06 20:45:57 +01001405 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001406 /* command arguments */
1407 struct sep_driver_build_sync_table_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01001408
Alan Coxd19cf322009-08-06 20:45:57 +01001409 dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001410
Alan Coxd19cf322009-08-06 20:45:57 +01001411 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t));
1412 if (error)
1413 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001414
Alan Coxd19cf322009-08-06 20:45:57 +01001415 edbg("app_in_address is %08lx\n", command_args.app_in_address);
1416 edbg("app_out_address is %08lx\n", command_args.app_out_address);
1417 edbg("data_size is %lu\n", command_args.data_in_size);
1418 edbg("block_size is %lu\n", command_args.block_size);
Mark Allyncd1bb432009-08-06 20:43:59 +01001419
Alan Coxd19cf322009-08-06 20:45:57 +01001420 /* check if we need to build only input table or input/output */
1421 if (command_args.app_out_address)
1422 /* prepare input and output tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001423 error = sep_prepare_input_output_dma_table(sep,
1424 command_args.app_in_address,
Alan Coxd19cf322009-08-06 20:45:57 +01001425 command_args.app_out_address,
1426 command_args.data_in_size,
1427 command_args.block_size,
1428 &command_args.in_table_address,
1429 &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);
1430 else
1431 /* prepare input tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001432 error = sep_prepare_input_dma_table(sep,
1433 command_args.app_in_address,
Alan Coxd19cf322009-08-06 20:45:57 +01001434 command_args.data_in_size, command_args.block_size, &command_args.in_table_address, &command_args.in_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress);
Mark Allyncd1bb432009-08-06 20:43:59 +01001435
Alan Coxd19cf322009-08-06 20:45:57 +01001436 if (error)
1437 goto end_function;
Alan Coxd19cf322009-08-06 20:45:57 +01001438 /* copy to user */
Alan Cox51faa9d2009-08-14 15:40:45 +01001439 if (copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t)))
1440 error = -EFAULT;
Alan Coxf93e4bf2009-08-06 20:46:08 +01001441end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001442 dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001443 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001444}
1445
1446/*
1447 this function handles the request for freeing dma table for synhronic actions
1448*/
Alan Coxca605bb2009-08-07 19:24:36 +01001449static int sep_free_dma_table_data_handler(struct sep_device *sep)
Mark Allyncd1bb432009-08-06 20:43:59 +01001450{
Alan Coxd19cf322009-08-06 20:45:57 +01001451 dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001452
Alan Coxd19cf322009-08-06 20:45:57 +01001453 /* free input pages array */
Alan Coxca605bb2009-08-07 19:24:36 +01001454 sep_free_dma_pages(sep->in_page_array, sep->in_num_pages, 0);
Mark Allyncd1bb432009-08-06 20:43:59 +01001455
Alan Coxd19cf322009-08-06 20:45:57 +01001456 /* free output pages array if needed */
Alan Coxca605bb2009-08-07 19:24:36 +01001457 if (sep->out_page_array)
1458 sep_free_dma_pages(sep->out_page_array, sep->out_num_pages, 1);
Mark Allyncd1bb432009-08-06 20:43:59 +01001459
Alan Coxd19cf322009-08-06 20:45:57 +01001460 /* reset all the values */
Alan Coxca605bb2009-08-07 19:24:36 +01001461 sep->in_page_array = 0;
1462 sep->out_page_array = 0;
1463 sep->in_num_pages = 0;
1464 sep->out_num_pages = 0;
Alan Coxd19cf322009-08-06 20:45:57 +01001465 dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001466 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01001467}
1468
1469/*
Alan Cox0a18d7b2009-08-07 19:23:50 +01001470 this function find a space for the new flow dma table
1471*/
Alan Coxca605bb2009-08-07 19:24:36 +01001472static int sep_find_free_flow_dma_table_space(struct sep_device *sep,
1473 unsigned long **table_address_ptr)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001474{
1475 int error = 0;
1476 /* pointer to the id field of the flow dma table */
1477 unsigned long *start_table_ptr;
Alan Cox790cf1b2009-08-07 19:25:16 +01001478 /* Do not make start_addr unsigned long * unless fixing the offset
1479 computations ! */
1480 void *flow_dma_area_start_addr;
1481 unsigned long *flow_dma_area_end_addr;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001482 /* maximum table size in words */
1483 unsigned long table_size_in_words;
1484
1485 /* find the start address of the flow DMA table area */
Alan Coxca605bb2009-08-07 19:24:36 +01001486 flow_dma_area_start_addr = sep->shared_area + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001487
1488 /* set end address of the flow table area */
1489 flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES;
1490
1491 /* set table size in words */
1492 table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2;
1493
1494 /* set the pointer to the start address of DMA area */
Alan Cox790cf1b2009-08-07 19:25:16 +01001495 start_table_ptr = flow_dma_area_start_addr;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001496
1497 /* find the space for the next table */
Alan Cox790cf1b2009-08-07 19:25:16 +01001498 while (((*start_table_ptr & 0x7FFFFFFF) != 0) && start_table_ptr < flow_dma_area_end_addr)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001499 start_table_ptr += table_size_in_words;
1500
1501 /* check if we reached the end of floa tables area */
Alan Cox790cf1b2009-08-07 19:25:16 +01001502 if (start_table_ptr >= flow_dma_area_end_addr)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001503 error = -1;
1504 else
1505 *table_address_ptr = start_table_ptr;
1506
1507 return error;
1508}
1509
Alan Cox0a18d7b2009-08-07 19:23:50 +01001510/*
1511 This function creates one DMA table for flow and returns its data,
1512 and pointer to its info entry
1513*/
Alan Coxca605bb2009-08-07 19:24:36 +01001514static int sep_prepare_one_flow_dma_table(struct sep_device *sep,
1515 unsigned long virt_buff_addr,
1516 unsigned long virt_buff_size,
1517 struct sep_lli_entry_t *table_data,
1518 struct sep_lli_entry_t **info_entry_ptr,
1519 struct sep_flow_context_t *flow_data_ptr,
1520 bool isKernelVirtualAddress)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001521{
1522 int error;
1523 /* the range in pages */
1524 unsigned long lli_array_size;
1525 struct sep_lli_entry_t *lli_array;
1526 struct sep_lli_entry_t *flow_dma_table_entry_ptr;
1527 unsigned long *start_dma_table_ptr;
1528 /* total table data counter */
1529 unsigned long dma_table_data_count;
1530 /* pointer that will keep the pointer to the pages of the virtual buffer */
1531 struct page **page_array_ptr;
1532 unsigned long entry_count;
1533
1534 /* find the space for the new table */
Alan Coxca605bb2009-08-07 19:24:36 +01001535 error = sep_find_free_flow_dma_table_space(sep, &start_dma_table_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001536 if (error)
1537 goto end_function;
1538
1539 /* check if the pages are in Kernel Virtual Address layout */
1540 if (isKernelVirtualAddress == true)
1541 /* lock kernel buffer in the memory */
Alan Coxca605bb2009-08-07 19:24:36 +01001542 error = sep_lock_kernel_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001543 else
1544 /* lock user buffer in the memory */
Alan Coxca605bb2009-08-07 19:24:36 +01001545 error = sep_lock_user_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001546
1547 if (error)
1548 goto end_function;
1549
1550 /* set the pointer to page array at the beginning of table - this table is
1551 now considered taken */
1552 *start_dma_table_ptr = lli_array_size;
1553
1554 /* point to the place of the pages pointers of the table */
1555 start_dma_table_ptr++;
1556
1557 /* set the pages pointer */
1558 *start_dma_table_ptr = (unsigned long) page_array_ptr;
1559
1560 /* set the pointer to the first entry */
1561 flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr);
1562
1563 /* now create the entries for table */
1564 for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) {
1565 flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address;
1566
1567 flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size;
1568
1569 /* set the total data of a table */
1570 dma_table_data_count += lli_array[entry_count].block_size;
1571
1572 flow_dma_table_entry_ptr++;
1573 }
1574
1575 /* set the physical address */
1576 table_data->physical_address = virt_to_phys(start_dma_table_ptr);
1577
1578 /* set the num_entries and total data size */
1579 table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count);
1580
1581 /* set the info entry */
1582 flow_dma_table_entry_ptr->physical_address = 0xffffffff;
1583 flow_dma_table_entry_ptr->block_size = 0;
1584
1585 /* set the pointer to info entry */
1586 *info_entry_ptr = flow_dma_table_entry_ptr;
1587
1588 /* the array of the lli entries */
1589 kfree(lli_array);
1590end_function:
1591 return error;
1592}
1593
1594
1595
1596/*
1597 This function creates a list of tables for flow and returns the data for
1598 the first and last tables of the list
1599*/
Alan Coxca605bb2009-08-07 19:24:36 +01001600static int sep_prepare_flow_dma_tables(struct sep_device *sep,
1601 unsigned long num_virtual_buffers,
1602 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)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001603{
1604 int error;
1605 unsigned long virt_buff_addr;
1606 unsigned long virt_buff_size;
1607 struct sep_lli_entry_t table_data;
1608 struct sep_lli_entry_t *info_entry_ptr;
1609 struct sep_lli_entry_t *prev_info_entry_ptr;
1610 unsigned long i;
1611
1612 /* init vars */
1613 error = 0;
1614 prev_info_entry_ptr = 0;
1615
1616 /* init the first table to default */
1617 table_data.physical_address = 0xffffffff;
1618 first_table_data_ptr->physical_address = 0xffffffff;
1619 table_data.block_size = 0;
1620
1621 for (i = 0; i < num_virtual_buffers; i++) {
1622 /* get the virtual buffer address */
1623 error = get_user(virt_buff_addr, &first_buff_addr);
1624 if (error)
1625 goto end_function;
1626
1627 /* get the virtual buffer size */
1628 first_buff_addr++;
1629 error = get_user(virt_buff_size, &first_buff_addr);
1630 if (error)
1631 goto end_function;
1632
1633 /* advance the address to point to the next pair of address|size */
1634 first_buff_addr++;
1635
1636 /* now prepare the one flow LLI table from the data */
Alan Coxca605bb2009-08-07 19:24:36 +01001637 error = sep_prepare_one_flow_dma_table(sep, virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress);
Alan Cox0a18d7b2009-08-07 19:23:50 +01001638 if (error)
1639 goto end_function;
1640
1641 if (i == 0) {
1642 /* if this is the first table - save it to return to the user
1643 application */
1644 *first_table_data_ptr = table_data;
1645
1646 /* set the pointer to info entry */
1647 prev_info_entry_ptr = info_entry_ptr;
1648 } else {
1649 /* not first table - the previous table info entry should
1650 be updated */
1651 prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size);
1652
1653 /* set the pointer to info entry */
1654 prev_info_entry_ptr = info_entry_ptr;
1655 }
1656 }
1657
1658 /* set the last table data */
1659 *last_table_data_ptr = table_data;
1660end_function:
1661 return error;
1662}
1663
1664/*
1665 this function goes over all the flow tables connected to the given
1666 table and deallocate them
1667*/
1668static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr)
1669{
1670 /* id pointer */
1671 unsigned long *table_ptr;
1672 /* end address of the flow dma area */
1673 unsigned long num_entries;
1674 unsigned long num_pages;
1675 struct page **pages_ptr;
1676 /* maximum table size in words */
1677 struct sep_lli_entry_t *info_entry_ptr;
1678
1679 /* set the pointer to the first table */
1680 table_ptr = (unsigned long *) first_table_ptr->physical_address;
1681
1682 /* set the num of entries */
1683 num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS)
1684 & SEP_NUM_ENTRIES_MASK;
1685
1686 /* go over all the connected tables */
1687 while (*table_ptr != 0xffffffff) {
1688 /* get number of pages */
1689 num_pages = *(table_ptr - 2);
1690
1691 /* get the pointer to the pages */
1692 pages_ptr = (struct page **) (*(table_ptr - 1));
1693
1694 /* free the pages */
1695 sep_free_dma_pages(pages_ptr, num_pages, 1);
1696
1697 /* goto to the info entry */
1698 info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1);
1699
1700 table_ptr = (unsigned long *) info_entry_ptr->physical_address;
1701 num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
1702 }
1703
1704 return;
1705}
1706
Alan Cox3cacf722009-08-07 19:24:51 +01001707/**
1708 * sep_find_flow_context - find a flow
1709 * @sep: the SEP we are working with
1710 * @flow_id: flow identifier
1711 *
1712 * Returns a pointer the matching flow, or NULL if the flow does not
1713 * exist.
1714 */
Alan Coxca605bb2009-08-07 19:24:36 +01001715
Alan Cox3cacf722009-08-07 19:24:51 +01001716static struct sep_flow_context_t *sep_find_flow_context(struct sep_device *sep,
1717 unsigned long flow_id)
Alan Cox0a18d7b2009-08-07 19:23:50 +01001718{
Alan Cox3cacf722009-08-07 19:24:51 +01001719 int count;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001720 /*
Alan Cox3cacf722009-08-07 19:24:51 +01001721 * always search for flow with id default first - in case we
1722 * already started working on the flow there can be no situation
1723 * when 2 flows are with default flag
Alan Cox0a18d7b2009-08-07 19:23:50 +01001724 */
1725 for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) {
Alan Cox3cacf722009-08-07 19:24:51 +01001726 if (sep->flows[count].flow_id == flow_id)
1727 return &sep->flows[count];
Alan Cox0a18d7b2009-08-07 19:23:50 +01001728 }
Alan Cox3cacf722009-08-07 19:24:51 +01001729 return NULL;
Alan Cox0a18d7b2009-08-07 19:23:50 +01001730}
1731
1732
1733/*
Mark Allyncd1bb432009-08-06 20:43:59 +01001734 this function handles the request to create the DMA tables for flow
1735*/
Alan Coxca605bb2009-08-07 19:24:36 +01001736static int sep_create_flow_dma_tables_handler(struct sep_device *sep,
1737 unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001738{
Alan Coxd19cf322009-08-06 20:45:57 +01001739 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001740 struct sep_driver_build_flow_table_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001741 /* first table - output */
1742 struct sep_lli_entry_t first_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001743 /* dma table data */
1744 struct sep_lli_entry_t last_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001745 /* pointer to the info entry of the previuos DMA table */
1746 struct sep_lli_entry_t *prev_info_entry_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001747 /* pointer to the flow data strucutre */
1748 struct sep_flow_context_t *flow_context_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001749
Alan Coxd19cf322009-08-06 20:45:57 +01001750 dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001751
Alan Coxd19cf322009-08-06 20:45:57 +01001752 /* init variables */
1753 prev_info_entry_ptr = 0;
1754 first_table_data.physical_address = 0xffffffff;
Mark Allyncd1bb432009-08-06 20:43:59 +01001755
Alan Coxd19cf322009-08-06 20:45:57 +01001756 /* find the free structure for flow data */
Alan Cox3cacf722009-08-07 19:24:51 +01001757 flow_context_ptr = sep_find_flow_context(sep, SEP_FREE_FLOW_ID);
1758 if (flow_context_ptr == NULL)
Alan Coxd19cf322009-08-06 20:45:57 +01001759 goto end_function;
1760
1761 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t));
1762 if (error)
1763 goto end_function;
1764
1765 /* create flow tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001766 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);
Alan Coxd19cf322009-08-06 20:45:57 +01001767 if (error)
1768 goto end_function_with_error;
1769
1770 /* check if flow is static */
1771 if (!command_args.flow_type)
1772 /* point the info entry of the last to the info entry of the first */
1773 last_table_data = first_table_data;
1774
1775 /* set output params */
1776 command_args.first_table_addr = first_table_data.physical_address;
1777 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1778 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
1779
1780 /* send the parameters to user application */
1781 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t));
1782 if (error)
1783 goto end_function_with_error;
1784
1785 /* all the flow created - update the flow entry with temp id */
1786 flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID;
1787
1788 /* set the processing tables data in the context */
1789 if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG)
1790 flow_context_ptr->input_tables_in_process = first_table_data;
1791 else
1792 flow_context_ptr->output_tables_in_process = first_table_data;
1793
Mark Allyncd1bb432009-08-06 20:43:59 +01001794 goto end_function;
1795
Alan Coxf93e4bf2009-08-06 20:46:08 +01001796end_function_with_error:
Alan Coxd19cf322009-08-06 20:45:57 +01001797 /* free the allocated tables */
1798 sep_deallocated_flow_tables(&first_table_data);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001799end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001800 dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001801 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001802}
1803
1804/*
Alan Coxca605bb2009-08-07 19:24:36 +01001805 this function handles add tables to flow
Mark Allyncd1bb432009-08-06 20:43:59 +01001806*/
Alan Coxca605bb2009-08-07 19:24:36 +01001807static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001808{
Alan Coxd19cf322009-08-06 20:45:57 +01001809 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001810 unsigned long num_entries;
Alan Coxd19cf322009-08-06 20:45:57 +01001811 struct sep_driver_add_flow_table_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001812 struct sep_flow_context_t *flow_context_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01001813 /* first dma table data */
1814 struct sep_lli_entry_t first_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001815 /* last dma table data */
1816 struct sep_lli_entry_t last_table_data;
Alan Coxd19cf322009-08-06 20:45:57 +01001817 /* pointer to the info entry of the current DMA table */
1818 struct sep_lli_entry_t *info_entry_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001819
Alan Coxd19cf322009-08-06 20:45:57 +01001820 dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001821
Alan Coxd19cf322009-08-06 20:45:57 +01001822 /* get input parameters */
1823 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t));
1824 if (error)
1825 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001826
Alan Coxd19cf322009-08-06 20:45:57 +01001827 /* find the flow structure for the flow id */
Alan Cox3cacf722009-08-07 19:24:51 +01001828 flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id);
1829 if (flow_context_ptr == NULL)
Alan Coxd19cf322009-08-06 20:45:57 +01001830 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001831
Alan Coxd19cf322009-08-06 20:45:57 +01001832 /* prepare the flow dma tables */
Alan Coxca605bb2009-08-07 19:24:36 +01001833 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);
Alan Coxd19cf322009-08-06 20:45:57 +01001834 if (error)
1835 goto end_function_with_error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001836
Alan Coxd19cf322009-08-06 20:45:57 +01001837 /* now check if there is already an existing add table for this flow */
1838 if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) {
1839 /* this buffer was for input buffers */
1840 if (flow_context_ptr->input_tables_flag) {
1841 /* add table already exists - add the new tables to the end
1842 of the previous */
1843 num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
Mark Allyncd1bb432009-08-06 20:43:59 +01001844
Alan Coxd19cf322009-08-06 20:45:57 +01001845 info_entry_ptr = (struct sep_lli_entry_t *)
1846 (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
Mark Allyncd1bb432009-08-06 20:43:59 +01001847
Alan Coxd19cf322009-08-06 20:45:57 +01001848 /* connect to list of tables */
1849 *info_entry_ptr = first_table_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01001850
Alan Coxd19cf322009-08-06 20:45:57 +01001851 /* set the first table data */
1852 first_table_data = flow_context_ptr->first_input_table;
1853 } else {
1854 /* set the input flag */
1855 flow_context_ptr->input_tables_flag = 1;
Mark Allyncd1bb432009-08-06 20:43:59 +01001856
Alan Coxd19cf322009-08-06 20:45:57 +01001857 /* set the first table data */
1858 flow_context_ptr->first_input_table = first_table_data;
1859 }
1860 /* set the last table data */
1861 flow_context_ptr->last_input_table = last_table_data;
1862 } else { /* this is output tables */
1863
1864 /* this buffer was for input buffers */
1865 if (flow_context_ptr->output_tables_flag) {
1866 /* add table already exists - add the new tables to
1867 the end of the previous */
1868 num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK;
1869
1870 info_entry_ptr = (struct sep_lli_entry_t *)
1871 (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1)));
1872
1873 /* connect to list of tables */
1874 *info_entry_ptr = first_table_data;
1875
1876 /* set the first table data */
1877 first_table_data = flow_context_ptr->first_output_table;
1878 } else {
1879 /* set the input flag */
1880 flow_context_ptr->output_tables_flag = 1;
1881
1882 /* set the first table data */
1883 flow_context_ptr->first_output_table = first_table_data;
1884 }
1885 /* set the last table data */
1886 flow_context_ptr->last_output_table = last_table_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01001887 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001888
Alan Coxd19cf322009-08-06 20:45:57 +01001889 /* set output params */
1890 command_args.first_table_addr = first_table_data.physical_address;
1891 command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK);
1892 command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK);
Mark Allyncd1bb432009-08-06 20:43:59 +01001893
Alan Coxd19cf322009-08-06 20:45:57 +01001894 /* send the parameters to user application */
1895 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01001896end_function_with_error:
Alan Coxd19cf322009-08-06 20:45:57 +01001897 /* free the allocated tables */
1898 sep_deallocated_flow_tables(&first_table_data);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001899end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001900 dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001901 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001902}
1903
1904/*
1905 this function add the flow add message to the specific flow
1906*/
Alan Coxca605bb2009-08-07 19:24:36 +01001907static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001908{
Alan Coxd19cf322009-08-06 20:45:57 +01001909 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001910 struct sep_driver_add_message_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01001911 struct sep_flow_context_t *flow_context_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01001912
Alan Coxd19cf322009-08-06 20:45:57 +01001913 dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001914
Alan Coxd19cf322009-08-06 20:45:57 +01001915 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t));
1916 if (error)
1917 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001918
Alan Coxd19cf322009-08-06 20:45:57 +01001919 /* check input */
1920 if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) {
1921 error = -ENOMEM;
1922 goto end_function;
1923 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001924
Alan Coxd19cf322009-08-06 20:45:57 +01001925 /* find the flow context */
Alan Cox3cacf722009-08-07 19:24:51 +01001926 flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id);
1927 if (flow_context_ptr == NULL)
Alan Coxd19cf322009-08-06 20:45:57 +01001928 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001929
Alan Coxd19cf322009-08-06 20:45:57 +01001930 /* copy the message into context */
1931 flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes;
Alan Coxd19cf322009-08-06 20:45:57 +01001932 error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes);
Alan Coxf93e4bf2009-08-06 20:46:08 +01001933end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001934 dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001935 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001936}
1937
1938
1939/*
Alan Cox51faa9d2009-08-14 15:40:45 +01001940 this function returns the bus and virtual addresses of the static pool
Mark Allyncd1bb432009-08-06 20:43:59 +01001941*/
Alan Coxca605bb2009-08-07 19:24:36 +01001942static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001943{
Alan Coxd19cf322009-08-06 20:45:57 +01001944 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001945 struct sep_driver_static_pool_addr_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01001946
Alan Coxd19cf322009-08-06 20:45:57 +01001947 dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001948
Alan Coxd19cf322009-08-06 20:45:57 +01001949 /*prepare the output parameters in the struct */
Alan Coxca605bb2009-08-07 19:24:36 +01001950 command_args.physical_static_address = sep->shared_area_bus + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
Alan Cox790cf1b2009-08-07 19:25:16 +01001951 command_args.virtual_static_address = (unsigned long)sep->shared_area + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
Mark Allyncd1bb432009-08-06 20:43:59 +01001952
Alan Cox51faa9d2009-08-14 15:40:45 +01001953 edbg("SEP Driver:bus_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address);
Mark Allyncd1bb432009-08-06 20:43:59 +01001954
Alan Coxd19cf322009-08-06 20:45:57 +01001955 /* send the parameters to user application */
1956 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t));
Alan Coxd19cf322009-08-06 20:45:57 +01001957 dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001958 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001959}
1960
1961/*
1962 this address gets the offset of the physical address from the start
1963 of the mapped area
1964*/
Alan Coxca605bb2009-08-07 19:24:36 +01001965static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01001966{
Alan Coxd19cf322009-08-06 20:45:57 +01001967 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01001968 struct sep_driver_get_mapped_offset_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01001969
Alan Coxd19cf322009-08-06 20:45:57 +01001970 dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01001971
Alan Coxd19cf322009-08-06 20:45:57 +01001972 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t));
1973 if (error)
1974 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01001975
Alan Coxca605bb2009-08-07 19:24:36 +01001976 if (command_args.physical_address < sep->shared_area_bus) {
Alan Cox51faa9d2009-08-14 15:40:45 +01001977 error = -EINVAL;
Alan Coxd19cf322009-08-06 20:45:57 +01001978 goto end_function;
1979 }
Mark Allyncd1bb432009-08-06 20:43:59 +01001980
Alan Coxd19cf322009-08-06 20:45:57 +01001981 /*prepare the output parameters in the struct */
Alan Coxca605bb2009-08-07 19:24:36 +01001982 command_args.offset = command_args.physical_address - sep->shared_area_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +01001983
Alan Cox51faa9d2009-08-14 15:40:45 +01001984 edbg("SEP Driver:bus_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset);
Mark Allyncd1bb432009-08-06 20:43:59 +01001985
Alan Coxd19cf322009-08-06 20:45:57 +01001986 /* send the parameters to user application */
1987 error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t));
Alan Coxf93e4bf2009-08-06 20:46:08 +01001988end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01001989 dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01001990 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01001991}
1992
1993
1994/*
1995 ?
1996*/
Alan Coxca605bb2009-08-07 19:24:36 +01001997static int sep_start_handler(struct sep_device *sep)
Mark Allyncd1bb432009-08-06 20:43:59 +01001998{
Alan Coxd19cf322009-08-06 20:45:57 +01001999 unsigned long reg_val;
Alan Coxf93e4bf2009-08-06 20:46:08 +01002000 unsigned long error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002001
Alan Coxd19cf322009-08-06 20:45:57 +01002002 dbg("SEP Driver:--------> sep_start_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002003
Alan Coxd19cf322009-08-06 20:45:57 +01002004 /* wait in polling for message from SEP */
Alan Coxf93e4bf2009-08-06 20:46:08 +01002005 do
Alan Coxca605bb2009-08-07 19:24:36 +01002006 reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002007 while (!reg_val);
Mark Allyncd1bb432009-08-06 20:43:59 +01002008
Alan Coxd19cf322009-08-06 20:45:57 +01002009 /* check the value */
Alan Cox43e8c4a2009-08-06 20:46:22 +01002010 if (reg_val == 0x1)
Alan Coxca605bb2009-08-07 19:24:36 +01002011 /* fatal error - read error status from GPRO */
2012 error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
Alan Coxd19cf322009-08-06 20:45:57 +01002013 dbg("SEP Driver:<-------- sep_start_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002014 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002015}
2016
2017/*
2018 this function handles the request for SEP initialization
2019*/
Alan Coxca605bb2009-08-07 19:24:36 +01002020static int sep_init_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002021{
Alan Coxd19cf322009-08-06 20:45:57 +01002022 unsigned long message_word;
Alan Coxd19cf322009-08-06 20:45:57 +01002023 unsigned long *message_ptr;
Alan Coxd19cf322009-08-06 20:45:57 +01002024 struct sep_driver_init_t command_args;
Alan Coxd19cf322009-08-06 20:45:57 +01002025 unsigned long counter;
Alan Coxd19cf322009-08-06 20:45:57 +01002026 unsigned long error;
Alan Coxd19cf322009-08-06 20:45:57 +01002027 unsigned long reg_val;
Mark Allyncd1bb432009-08-06 20:43:59 +01002028
Alan Coxd19cf322009-08-06 20:45:57 +01002029 dbg("SEP Driver:--------> sep_init_handler start\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002030 error = 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002031
Alan Coxd19cf322009-08-06 20:45:57 +01002032 error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t));
Mark Allyncd1bb432009-08-06 20:43:59 +01002033
Alan Coxd19cf322009-08-06 20:45:57 +01002034 dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002035
Alan Coxd19cf322009-08-06 20:45:57 +01002036 if (error)
2037 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002038
Alan Coxd19cf322009-08-06 20:45:57 +01002039 /* PATCH - configure the DMA to single -burst instead of multi-burst */
2040 /*sep_configure_dma_burst(); */
Mark Allyncd1bb432009-08-06 20:43:59 +01002041
Alan Coxd19cf322009-08-06 20:45:57 +01002042 dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002043
Alan Coxd19cf322009-08-06 20:45:57 +01002044 message_ptr = (unsigned long *) command_args.message_addr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002045
Alan Coxd19cf322009-08-06 20:45:57 +01002046 /* set the base address of the SRAM */
Alan Coxca605bb2009-08-07 19:24:36 +01002047 sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS);
Mark Allyncd1bb432009-08-06 20:43:59 +01002048
Alan Coxd19cf322009-08-06 20:45:57 +01002049 for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) {
2050 get_user(message_word, message_ptr);
Alan Coxd19cf322009-08-06 20:45:57 +01002051 /* write data to SRAM */
Alan Coxca605bb2009-08-07 19:24:36 +01002052 sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, message_word);
Alan Coxd19cf322009-08-06 20:45:57 +01002053 edbg("SEP Driver:message_word is %lu\n", message_word);
Mark Allyncd1bb432009-08-06 20:43:59 +01002054 /* wait for write complete */
Alan Coxca605bb2009-08-07 19:24:36 +01002055 sep_wait_sram_write(sep);
Alan Coxd19cf322009-08-06 20:45:57 +01002056 }
Alan Coxd19cf322009-08-06 20:45:57 +01002057 dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002058 /* signal SEP */
Alan Coxca605bb2009-08-07 19:24:36 +01002059 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1);
Mark Allyncd1bb432009-08-06 20:43:59 +01002060
Alan Coxf93e4bf2009-08-06 20:46:08 +01002061 do
Alan Coxca605bb2009-08-07 19:24:36 +01002062 reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
Alan Coxf93e4bf2009-08-06 20:46:08 +01002063 while (!(reg_val & 0xFFFFFFFD));
Mark Allyncd1bb432009-08-06 20:43:59 +01002064
Alan Coxd19cf322009-08-06 20:45:57 +01002065 dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002066
Alan Coxd19cf322009-08-06 20:45:57 +01002067 /* check the value */
2068 if (reg_val == 0x1) {
2069 edbg("SEP Driver:init failed\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002070
Alan Coxca605bb2009-08-07 19:24:36 +01002071 error = sep_read_reg(sep, 0x8060);
Alan Coxd19cf322009-08-06 20:45:57 +01002072 edbg("SEP Driver:sw monitor is %lu\n", error);
Mark Allyncd1bb432009-08-06 20:43:59 +01002073
Alan Coxd19cf322009-08-06 20:45:57 +01002074 /* fatal error - read erro status from GPRO */
Alan Coxca605bb2009-08-07 19:24:36 +01002075 error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
Alan Coxd19cf322009-08-06 20:45:57 +01002076 edbg("SEP Driver:error is %lu\n", error);
Alan Coxd19cf322009-08-06 20:45:57 +01002077 }
Alan Coxf93e4bf2009-08-06 20:46:08 +01002078end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002079 dbg("SEP Driver:<-------- sep_init_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002080 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002081
2082}
2083
2084/*
2085 this function handles the request cache and resident reallocation
2086*/
Alan Coxca605bb2009-08-07 19:24:36 +01002087static int sep_realloc_cache_resident_handler(struct sep_device *sep,
2088 unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002089{
Alan Coxd19cf322009-08-06 20:45:57 +01002090 struct sep_driver_realloc_cache_resident_t command_args;
Alan Cox6f13ea32009-08-14 15:41:50 +01002091 int error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002092
Alan Coxd19cf322009-08-06 20:45:57 +01002093 /* copy cache and resident to the their intended locations */
Alan Cox6f13ea32009-08-14 15:41:50 +01002094 error = sep_load_firmware(sep);
Alan Coxd19cf322009-08-06 20:45:57 +01002095 if (error)
Alan Cox6f13ea32009-08-14 15:41:50 +01002096 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002097
Alan Coxca605bb2009-08-07 19:24:36 +01002098 command_args.new_base_addr = sep->shared_area_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +01002099
Alan Coxd19cf322009-08-06 20:45:57 +01002100 /* find the new base address according to the lowest address between
2101 cache, resident and shared area */
Alan Cox6f13ea32009-08-14 15:41:50 +01002102 if (sep->resident_bus < command_args.new_base_addr)
2103 command_args.new_base_addr = sep->resident_bus;
2104 if (sep->cache_bus < command_args.new_base_addr)
2105 command_args.new_base_addr = sep->cache_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +01002106
Alan Coxd19cf322009-08-06 20:45:57 +01002107 /* set the return parameters */
Alan Cox6f13ea32009-08-14 15:41:50 +01002108 command_args.new_cache_addr = sep->cache_bus;
2109 command_args.new_resident_addr = sep->resident_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +01002110
Alan Coxd19cf322009-08-06 20:45:57 +01002111 /* set the new shared area */
Alan Coxca605bb2009-08-07 19:24:36 +01002112 command_args.new_shared_area_addr = sep->shared_area_bus;
Mark Allyncd1bb432009-08-06 20:43:59 +01002113
Alan Cox6f13ea32009-08-14 15:41:50 +01002114 edbg("SEP Driver:command_args.new_shared_area is %08llx\n", command_args.new_shared_area_addr);
2115 edbg("SEP Driver:command_args.new_base_addr is %08llx\n", command_args.new_base_addr);
2116 edbg("SEP Driver:command_args.new_resident_addr is %08llx\n", command_args.new_resident_addr);
2117 edbg("SEP Driver:command_args.new_cache_addr is %08llx\n", command_args.new_cache_addr);
Mark Allyncd1bb432009-08-06 20:43:59 +01002118
Alan Coxd19cf322009-08-06 20:45:57 +01002119 /* return to user */
Alan Cox6f13ea32009-08-14 15:41:50 +01002120 if (copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_realloc_cache_resident_t)))
2121 return -EFAULT;
2122 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002123}
2124
2125/*
2126 this function handles the request for get time
2127*/
Alan Coxca605bb2009-08-07 19:24:36 +01002128static int sep_get_time_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002129{
Alan Coxd19cf322009-08-06 20:45:57 +01002130 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002131 struct sep_driver_get_time_t command_args;
Mark Allyncd1bb432009-08-06 20:43:59 +01002132
Alan Coxca605bb2009-08-07 19:24:36 +01002133 error = sep_set_time(sep, &command_args.time_physical_address, &command_args.time_value);
Alan Cox7913c212009-08-07 19:24:00 +01002134 if (error == 0)
2135 error = copy_to_user((void __user *)arg,
2136 &command_args, sizeof(struct sep_driver_get_time_t));
Alan Coxd19cf322009-08-06 20:45:57 +01002137 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002138
2139}
2140
2141/*
Mark Allyncd1bb432009-08-06 20:43:59 +01002142 This API handles the end transaction request
2143*/
Alan Coxca605bb2009-08-07 19:24:36 +01002144static int sep_end_transaction_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002145{
Alan Coxd19cf322009-08-06 20:45:57 +01002146 dbg("SEP Driver:--------> sep_end_transaction_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002147
Alan Coxd19cf322009-08-06 20:45:57 +01002148#if 0 /*!SEP_DRIVER_POLLING_MODE */
2149 /* close IMR */
Alan Coxca605bb2009-08-07 19:24:36 +01002150 sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF);
Mark Allyncd1bb432009-08-06 20:43:59 +01002151
Alan Coxd19cf322009-08-06 20:45:57 +01002152 /* release IRQ line */
Alan Coxca605bb2009-08-07 19:24:36 +01002153 free_irq(SEP_DIRVER_IRQ_NUM, sep);
Mark Allyncd1bb432009-08-06 20:43:59 +01002154
Alan Coxd19cf322009-08-06 20:45:57 +01002155 /* lock the sep mutex */
2156 mutex_unlock(&sep_mutex);
Mark Allyncd1bb432009-08-06 20:43:59 +01002157#endif
2158
Alan Coxd19cf322009-08-06 20:45:57 +01002159 dbg("SEP Driver:<-------- sep_end_transaction_handler end\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002160
Alan Coxd19cf322009-08-06 20:45:57 +01002161 return 0;
Mark Allyncd1bb432009-08-06 20:43:59 +01002162}
2163
Mark Allyncd1bb432009-08-06 20:43:59 +01002164
Mark Allyncd1bb432009-08-06 20:43:59 +01002165/*
2166 This function handler the set flow id command
2167*/
Alan Coxca605bb2009-08-07 19:24:36 +01002168static int sep_set_flow_id_handler(struct sep_device *sep, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002169{
Alan Coxd19cf322009-08-06 20:45:57 +01002170 int error;
Alan Coxd19cf322009-08-06 20:45:57 +01002171 unsigned long flow_id;
Alan Coxd19cf322009-08-06 20:45:57 +01002172 struct sep_flow_context_t *flow_data_ptr;
Mark Allyncd1bb432009-08-06 20:43:59 +01002173
Alan Coxd19cf322009-08-06 20:45:57 +01002174 dbg("------------>SEP Driver: sep_set_flow_id_handler start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002175
Alan Coxd19cf322009-08-06 20:45:57 +01002176 error = get_user(flow_id, &(((struct sep_driver_set_flow_id_t *) arg)->flow_id));
2177 if (error)
2178 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002179
Alan Coxd19cf322009-08-06 20:45:57 +01002180 /* find the flow data structure that was just used for creating new flow
2181 - its id should be default */
Alan Cox3cacf722009-08-07 19:24:51 +01002182 flow_data_ptr = sep_find_flow_context(sep, SEP_TEMP_FLOW_ID);
2183 if (flow_data_ptr == NULL)
Alan Coxd19cf322009-08-06 20:45:57 +01002184 goto end_function;
Mark Allyncd1bb432009-08-06 20:43:59 +01002185
Alan Coxd19cf322009-08-06 20:45:57 +01002186 /* set flow id */
2187 flow_data_ptr->flow_id = flow_id;
Mark Allyncd1bb432009-08-06 20:43:59 +01002188
Alan Coxf93e4bf2009-08-06 20:46:08 +01002189end_function:
Alan Coxd19cf322009-08-06 20:45:57 +01002190 dbg("SEP Driver:<-------- sep_set_flow_id_handler end\n");
Alan Coxd19cf322009-08-06 20:45:57 +01002191 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002192}
2193
2194
Alan Cox0a18d7b2009-08-07 19:23:50 +01002195
2196
2197
2198static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
Mark Allyncd1bb432009-08-06 20:43:59 +01002199{
Alan Cox0a18d7b2009-08-07 19:23:50 +01002200 int error = 0;
Alan Coxca605bb2009-08-07 19:24:36 +01002201 struct sep_device *sep = filp->private_data;
Mark Allyncd1bb432009-08-06 20:43:59 +01002202
Alan Cox0a18d7b2009-08-07 19:23:50 +01002203 dbg("------------>SEP Driver: ioctl start\n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002204
Alan Cox0a18d7b2009-08-07 19:23:50 +01002205 edbg("SEP Driver: cmd is %x\n", cmd);
Mark Allyncd1bb432009-08-06 20:43:59 +01002206
Alan Cox0a18d7b2009-08-07 19:23:50 +01002207 switch (cmd) {
2208 case SEP_IOCSENDSEPCOMMAND:
2209 /* send command to SEP */
Alan Coxca605bb2009-08-07 19:24:36 +01002210 sep_send_command_handler(sep);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002211 edbg("SEP Driver: after sep_send_command_handler\n");
2212 break;
2213 case SEP_IOCSENDSEPRPLYCOMMAND:
2214 /* send reply command to SEP */
Alan Coxca605bb2009-08-07 19:24:36 +01002215 sep_send_reply_command_handler(sep);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002216 break;
2217 case SEP_IOCALLOCDATAPOLL:
2218 /* allocate data pool */
Alan Coxca605bb2009-08-07 19:24:36 +01002219 error = sep_allocate_data_pool_memory_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002220 break;
2221 case SEP_IOCWRITEDATAPOLL:
2222 /* write data into memory pool */
Alan Coxca605bb2009-08-07 19:24:36 +01002223 error = sep_write_into_data_pool_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002224 break;
2225 case SEP_IOCREADDATAPOLL:
2226 /* read data from data pool into application memory */
Alan Coxca605bb2009-08-07 19:24:36 +01002227 error = sep_read_from_data_pool_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002228 break;
2229 case SEP_IOCCREATESYMDMATABLE:
2230 /* create dma table for synhronic operation */
Alan Coxca605bb2009-08-07 19:24:36 +01002231 error = sep_create_sync_dma_tables_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002232 break;
2233 case SEP_IOCCREATEFLOWDMATABLE:
2234 /* create flow dma tables */
Alan Coxca605bb2009-08-07 19:24:36 +01002235 error = sep_create_flow_dma_tables_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002236 break;
2237 case SEP_IOCFREEDMATABLEDATA:
2238 /* free the pages */
Alan Coxca605bb2009-08-07 19:24:36 +01002239 error = sep_free_dma_table_data_handler(sep);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002240 break;
2241 case SEP_IOCSETFLOWID:
2242 /* set flow id */
Alan Coxca605bb2009-08-07 19:24:36 +01002243 error = sep_set_flow_id_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002244 break;
2245 case SEP_IOCADDFLOWTABLE:
2246 /* add tables to the dynamic flow */
Alan Coxca605bb2009-08-07 19:24:36 +01002247 error = sep_add_flow_tables_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002248 break;
2249 case SEP_IOCADDFLOWMESSAGE:
2250 /* add message of add tables to flow */
Alan Coxca605bb2009-08-07 19:24:36 +01002251 error = sep_add_flow_tables_message_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002252 break;
2253 case SEP_IOCSEPSTART:
2254 /* start command to sep */
Alan Coxca605bb2009-08-07 19:24:36 +01002255 error = sep_start_handler(sep);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002256 break;
2257 case SEP_IOCSEPINIT:
2258 /* init command to sep */
Alan Coxca605bb2009-08-07 19:24:36 +01002259 error = sep_init_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002260 break;
Alan Cox0a18d7b2009-08-07 19:23:50 +01002261 case SEP_IOCGETSTATICPOOLADDR:
2262 /* get the physical and virtual addresses of the static pool */
Alan Coxca605bb2009-08-07 19:24:36 +01002263 error = sep_get_static_pool_addr_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002264 break;
2265 case SEP_IOCENDTRANSACTION:
Alan Coxca605bb2009-08-07 19:24:36 +01002266 error = sep_end_transaction_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002267 break;
2268 case SEP_IOCREALLOCCACHERES:
Alan Coxca605bb2009-08-07 19:24:36 +01002269 error = sep_realloc_cache_resident_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002270 break;
2271 case SEP_IOCGETMAPPEDADDROFFSET:
Alan Coxca605bb2009-08-07 19:24:36 +01002272 error = sep_get_physical_mapped_offset_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002273 break;
2274 case SEP_IOCGETIME:
Alan Coxca605bb2009-08-07 19:24:36 +01002275 error = sep_get_time_handler(sep, arg);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002276 break;
2277 default:
2278 error = -ENOTTY;
2279 break;
2280 }
2281 dbg("SEP Driver:<-------- ioctl end\n");
2282 return error;
Mark Allyncd1bb432009-08-06 20:43:59 +01002283}
2284
Alan Cox0a18d7b2009-08-07 19:23:50 +01002285
2286
2287#if !SEP_DRIVER_POLLING_MODE
2288
2289/* handler for flow done interrupt */
2290
2291static void sep_flow_done_handler(struct work_struct *work)
2292{
2293 struct sep_flow_context_t *flow_data_ptr;
2294
2295 /* obtain the mutex */
2296 mutex_lock(&sep_mutex);
2297
2298 /* get the pointer to context */
2299 flow_data_ptr = (struct sep_flow_context_t *) work;
2300
2301 /* free all the current input tables in sep */
2302 sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process);
2303
2304 /* free all the current tables output tables in SEP (if needed) */
2305 if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff)
2306 sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process);
2307
2308 /* check if we have additional tables to be sent to SEP only input
2309 flag may be checked */
2310 if (flow_data_ptr->input_tables_flag) {
2311 /* copy the message to the shared RAM and signal SEP */
Alan Coxca605bb2009-08-07 19:24:36 +01002312 memcpy((void *) flow_data_ptr->message, (void *) sep->shared_area, flow_data_ptr->message_size_in_bytes);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002313
Alan Coxca605bb2009-08-07 19:24:36 +01002314 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002315 }
2316 mutex_unlock(&sep_mutex);
2317}
2318/*
2319 interrupt handler function
2320*/
2321static irqreturn_t sep_inthandler(int irq, void *dev_id)
2322{
2323 irqreturn_t int_error;
Alan Cox0a18d7b2009-08-07 19:23:50 +01002324 unsigned long reg_val;
2325 unsigned long flow_id;
2326 struct sep_flow_context_t *flow_context_ptr;
Alan Coxca605bb2009-08-07 19:24:36 +01002327 struct sep_device *sep = dev_id;
Alan Cox0a18d7b2009-08-07 19:23:50 +01002328
2329 int_error = IRQ_HANDLED;
2330
2331 /* read the IRR register to check if this is SEP interrupt */
Alan Coxca605bb2009-08-07 19:24:36 +01002332 reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002333 edbg("SEP Interrupt - reg is %08lx\n", reg_val);
2334
2335 /* check if this is the flow interrupt */
2336 if (0 /*reg_val & (0x1 << 11) */ ) {
2337 /* read GPRO to find out the which flow is done */
Alan Coxca605bb2009-08-07 19:24:36 +01002338 flow_id = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002339
2340 /* find the contex of the flow */
Alan Cox3cacf722009-08-07 19:24:51 +01002341 flow_context_ptr = sep_find_flow_context(sep, flow_id >> 28);
2342 if (flow_context_ptr == NULL)
Alan Cox0a18d7b2009-08-07 19:23:50 +01002343 goto end_function_with_error;
2344
Alan Cox0a18d7b2009-08-07 19:23:50 +01002345 /* queue the work */
Alan Cox3cacf722009-08-07 19:24:51 +01002346 INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler);
Alan Coxca605bb2009-08-07 19:24:36 +01002347 queue_work(sep->flow_wq, &flow_context_ptr->flow_wq);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002348
2349 } else {
2350 /* check if this is reply interrupt from SEP */
2351 if (reg_val & (0x1 << 13)) {
2352 /* update the counter of reply messages */
Alan Coxca605bb2009-08-07 19:24:36 +01002353 sep->reply_ct++;
Alan Cox0a18d7b2009-08-07 19:23:50 +01002354 /* wake up the waiting process */
Alan Cox904290c2009-08-07 19:24:18 +01002355 wake_up(&sep_event);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002356 } else {
2357 int_error = IRQ_NONE;
2358 goto end_function;
2359 }
2360 }
2361end_function_with_error:
2362 /* clear the interrupt */
Alan Coxca605bb2009-08-07 19:24:36 +01002363 sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val);
Alan Cox0a18d7b2009-08-07 19:23:50 +01002364end_function:
2365 return int_error;
2366}
2367
2368#endif
2369
2370
2371
Alan Cox8c7ff812009-08-07 19:24:43 +01002372#if 0
Alan Cox0a18d7b2009-08-07 19:23:50 +01002373
Alan Coxca605bb2009-08-07 19:24:36 +01002374static void sep_wait_busy(struct sep_device *sep)
Alan Cox794f1d72009-08-06 20:45:35 +01002375{
2376 u32 reg;
2377
2378 do {
Alan Coxca605bb2009-08-07 19:24:36 +01002379 reg = sep_read_reg(sep, HW_HOST_SEP_BUSY_REG_ADDR);
Alan Cox794f1d72009-08-06 20:45:35 +01002380 } while (reg);
2381}
2382
Mark Allyncd1bb432009-08-06 20:43:59 +01002383/*
2384 PATCH for configuring the DMA to single burst instead of multi-burst
2385*/
Alan Coxca605bb2009-08-07 19:24:36 +01002386static void sep_configure_dma_burst(struct sep_device *sep)
Mark Allyncd1bb432009-08-06 20:43:59 +01002387{
Mark Allyncd1bb432009-08-06 20:43:59 +01002388#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL
2389
Alan Coxd19cf322009-08-06 20:45:57 +01002390 dbg("SEP Driver:<-------- sep_configure_dma_burst start \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002391
Alan Coxd19cf322009-08-06 20:45:57 +01002392 /* request access to registers from SEP */
Alan Coxca605bb2009-08-07 19:24:36 +01002393 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
Mark Allyncd1bb432009-08-06 20:43:59 +01002394
Alan Coxd19cf322009-08-06 20:45:57 +01002395 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002396
Alan Coxca605bb2009-08-07 19:24:36 +01002397 sep_wait_busy(sep);
Mark Allyncd1bb432009-08-06 20:43:59 +01002398
Alan Coxd19cf322009-08-06 20:45:57 +01002399 dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002400
Alan Coxd19cf322009-08-06 20:45:57 +01002401 /* set the DMA burst register to single burst */
Alan Coxca605bb2009-08-07 19:24:36 +01002402 sep_write_reg(sep, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL);
Mark Allyncd1bb432009-08-06 20:43:59 +01002403
Alan Coxd19cf322009-08-06 20:45:57 +01002404 /* release the sep busy */
Alan Coxca605bb2009-08-07 19:24:36 +01002405 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL);
2406 sep_wait_busy(sep);
Mark Allyncd1bb432009-08-06 20:43:59 +01002407
Alan Coxd19cf322009-08-06 20:45:57 +01002408 dbg("SEP Driver:<-------- sep_configure_dma_burst done \n");
Mark Allyncd1bb432009-08-06 20:43:59 +01002409
2410}
2411
Alan Cox8c7ff812009-08-07 19:24:43 +01002412#endif
2413
Alan Cox0097a692009-08-07 19:23:19 +01002414/*
Alan Coxca605bb2009-08-07 19:24:36 +01002415 Function that is activaed on the succesful probe of the SEP device
Alan Cox0097a692009-08-07 19:23:19 +01002416*/
2417static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2418{
2419 int error = 0;
Alan Coxca605bb2009-08-07 19:24:36 +01002420 struct sep_device *sep;
2421 int counter;
2422 int size; /* size of memory for allocation */
Alan Cox0097a692009-08-07 19:23:19 +01002423
2424 edbg("Sep pci probe starting\n");
Alan Coxca605bb2009-08-07 19:24:36 +01002425 if (sep_dev != NULL) {
2426 dev_warn(&pdev->dev, "only one SEP supported.\n");
2427 return -EBUSY;
2428 }
Alan Cox0097a692009-08-07 19:23:19 +01002429
2430 /* enable the device */
2431 error = pci_enable_device(pdev);
2432 if (error) {
2433 edbg("error enabling pci device\n");
2434 goto end_function;
2435 }
2436
2437 /* set the pci dev pointer */
Alan Coxca605bb2009-08-07 19:24:36 +01002438 sep_dev = &sep_instance;
2439 sep = &sep_instance;
2440
2441 edbg("sep->shared_area = %lx\n", (unsigned long) &sep->shared_area);
2442 /* transaction counter that coordinates the transactions between SEP
2443 and HOST */
2444 sep->send_ct = 0;
2445 /* counter for the messages from sep */
2446 sep->reply_ct = 0;
2447 /* counter for the number of bytes allocated in the pool
2448 for the current transaction */
2449 sep->data_pool_bytes_allocated = 0;
2450
2451 /* calculate the total size for allocation */
2452 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
2453 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;
2454
2455 /* allocate the shared area */
Alan Cox8c7ff812009-08-07 19:24:43 +01002456 if (sep_map_and_alloc_shared_area(sep, size)) {
Alan Coxca605bb2009-08-07 19:24:36 +01002457 error = -ENOMEM;
2458 /* allocation failed */
2459 goto end_function_error;
2460 }
2461 /* now set the memory regions */
2462 sep->message_shared_area_addr = sep->shared_area;
2463
Alan Cox790cf1b2009-08-07 19:25:16 +01002464 edbg("SEP Driver: sep->message_shared_area_addr is %p\n", sep->message_shared_area_addr);
Alan Coxca605bb2009-08-07 19:24:36 +01002465
2466#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1)
2467 /* send the new SHARED MESSAGE AREA to the SEP */
2468 sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_area_bus);
2469
2470 /* poll for SEP response */
Alan Cox51faa9d2009-08-14 15:40:45 +01002471 retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
2472 while (retval != 0xffffffff && retval != sep->shared_area_bus)
2473 retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
Alan Coxca605bb2009-08-07 19:24:36 +01002474
2475 /* check the return value (register) */
Alan Cox51faa9d2009-08-14 15:40:45 +01002476 if (retval != sep->shared_area_bus) {
Alan Coxca605bb2009-08-07 19:24:36 +01002477 error = -ENOMEM;
2478 goto end_function_deallocate_sep_shared_area;
2479 }
2480#endif
2481 /* init the flow contextes */
2482 for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++)
2483 sep->flows[counter].flow_id = SEP_FREE_FLOW_ID;
2484
2485 sep->flow_wq = create_singlethread_workqueue("sepflowwq");
2486 if (sep->flow_wq == NULL) {
2487 error = -ENOMEM;
2488 edbg("sep_driver:flow queue creation failed\n");
2489 goto end_function_deallocate_sep_shared_area;
2490 }
2491 edbg("SEP Driver: create flow workqueue \n");
2492 /* load the rom code */
2493 sep_load_rom_code(sep);
2494
2495 sep->pdev = pci_dev_get(pdev);
Alan Cox0097a692009-08-07 19:23:19 +01002496
2497 /* get the io memory start address */
Alan Coxca605bb2009-08-07 19:24:36 +01002498 sep->io_bus = pci_resource_start(pdev, 0);
2499 if (!sep->io_bus) {
Alan Cox0097a692009-08-07 19:23:19 +01002500 edbg("SEP Driver error pci resource start\n");
Alan Coxca605bb2009-08-07 19:24:36 +01002501 goto end_function_deallocate_sep_shared_area;
Alan Cox0097a692009-08-07 19:23:19 +01002502 }
2503
2504 /* get the io memory end address */
Alan Coxca605bb2009-08-07 19:24:36 +01002505 sep->io_end_bus = pci_resource_end(pdev, 0);
2506 if (!sep->io_end_bus) {
Alan Cox0097a692009-08-07 19:23:19 +01002507 edbg("SEP Driver error pci resource end\n");
Alan Coxca605bb2009-08-07 19:24:36 +01002508 goto end_function_deallocate_sep_shared_area;
Alan Cox0097a692009-08-07 19:23:19 +01002509 }
2510
Alan Coxca605bb2009-08-07 19:24:36 +01002511 sep->io_memory_size = sep->io_end_bus - sep->io_bus + 1;
Alan Cox0097a692009-08-07 19:23:19 +01002512
Alan Coxca605bb2009-08-07 19:24:36 +01002513 edbg("SEP Driver:io_bus is %08lx\n", sep->io_bus);
Alan Cox0097a692009-08-07 19:23:19 +01002514
Alan Coxca605bb2009-08-07 19:24:36 +01002515 edbg("SEP Driver:io_memory_end_phyaical_address is %08lx\n", sep->io_end_bus);
Alan Cox0097a692009-08-07 19:23:19 +01002516
Alan Coxca605bb2009-08-07 19:24:36 +01002517 edbg("SEP Driver:io_memory_size is %08lx\n", sep->io_memory_size);
Alan Cox0097a692009-08-07 19:23:19 +01002518
Alan Coxca605bb2009-08-07 19:24:36 +01002519 sep->io_addr = ioremap_nocache(sep->io_bus, sep->io_memory_size);
2520 if (!sep->io_addr) {
Alan Cox0097a692009-08-07 19:23:19 +01002521 edbg("SEP Driver error ioremap of io memory\n");
Alan Coxca605bb2009-08-07 19:24:36 +01002522 goto end_function_deallocate_sep_shared_area;
Alan Cox0097a692009-08-07 19:23:19 +01002523 }
2524
Alan Coxca605bb2009-08-07 19:24:36 +01002525 edbg("SEP Driver:io_addr is %p\n", sep->io_addr);
Alan Cox0097a692009-08-07 19:23:19 +01002526
Alan Coxca605bb2009-08-07 19:24:36 +01002527 sep->reg_addr = (void __iomem *) sep->io_addr;
Alan Cox0097a692009-08-07 19:23:19 +01002528
2529 /* set up system base address and shared memory location */
2530
Alan Cox6f13ea32009-08-14 15:41:50 +01002531 sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev,
2532 2 * SEP_RAR_IO_MEM_REGION_SIZE,
2533 &sep->rar_bus, GFP_KERNEL);
Alan Cox0097a692009-08-07 19:23:19 +01002534
Alan Coxca605bb2009-08-07 19:24:36 +01002535 if (!sep->rar_addr) {
Alan Cox6f13ea32009-08-14 15:41:50 +01002536 edbg("SEP Driver:can't allocate rar\n");
Alan Coxca605bb2009-08-07 19:24:36 +01002537 goto end_function_uniomap;
Alan Cox0097a692009-08-07 19:23:19 +01002538 }
Alan Cox0097a692009-08-07 19:23:19 +01002539
Alan Cox51faa9d2009-08-14 15:40:45 +01002540 edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus);
Alan Coxca605bb2009-08-07 19:24:36 +01002541 edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr);
Alan Cox0097a692009-08-07 19:23:19 +01002542
2543#if !SEP_DRIVER_POLLING_MODE
2544
2545 edbg("SEP Driver: about to write IMR and ICR REG_ADDR\n");
2546
2547 /* clear ICR register */
Alan Coxca605bb2009-08-07 19:24:36 +01002548 sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
Alan Cox0097a692009-08-07 19:23:19 +01002549
2550 /* set the IMR register - open only GPR 2 */
Alan Coxca605bb2009-08-07 19:24:36 +01002551 sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
Alan Cox0097a692009-08-07 19:23:19 +01002552
Alan Cox0097a692009-08-07 19:23:19 +01002553 edbg("SEP Driver: about to call request_irq\n");
2554 /* get the interrupt line */
Alan Coxca605bb2009-08-07 19:24:36 +01002555 error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep);
Alan Cox0097a692009-08-07 19:23:19 +01002556 if (error)
Alan Coxca605bb2009-08-07 19:24:36 +01002557 goto end_function_free_res;
Alan Cox0097a692009-08-07 19:23:19 +01002558
2559 goto end_function;
2560 edbg("SEP Driver: about to write IMR REG_ADDR");
2561
2562 /* set the IMR register - open only GPR 2 */
Alan Coxca605bb2009-08-07 19:24:36 +01002563 sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
Alan Cox0097a692009-08-07 19:23:19 +01002564
Alan Coxca605bb2009-08-07 19:24:36 +01002565end_function_free_res:
Alan Cox6f13ea32009-08-14 15:41:50 +01002566 dma_free_coherent(&sep->pdev->dev, 2 * SEP_RAR_IO_MEM_REGION_SIZE,
2567 sep->rar_addr, sep->rar_bus);
Alan Cox0097a692009-08-07 19:23:19 +01002568#endif /* SEP_DRIVER_POLLING_MODE */
Alan Coxca605bb2009-08-07 19:24:36 +01002569end_function_uniomap:
2570 iounmap(sep->io_addr);
2571end_function_deallocate_sep_shared_area:
2572 /* de-allocate shared area */
Alan Cox8c7ff812009-08-07 19:24:43 +01002573 sep_unmap_and_free_shared_area(sep, size);
Alan Coxca605bb2009-08-07 19:24:36 +01002574end_function_error:
2575 sep_dev = NULL;
Alan Cox0097a692009-08-07 19:23:19 +01002576end_function:
2577 return error;
2578}
2579
2580static struct pci_device_id sep_pci_id_tbl[] = {
2581 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)},
2582 {0}
2583};
2584
2585MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl);
2586
2587/* field for registering driver to PCI device */
2588static struct pci_driver sep_pci_driver = {
2589 .name = "sep_sec_driver",
2590 .id_table = sep_pci_id_tbl,
2591 .probe = sep_probe
Alan Coxca605bb2009-08-07 19:24:36 +01002592 /* FIXME: remove handler */
Alan Cox0097a692009-08-07 19:23:19 +01002593};
2594
Alan Cox2f826142009-08-07 19:23:04 +01002595/* major and minor device numbers */
2596static dev_t sep_devno;
2597
2598/* the files operations structure of the driver */
2599static struct file_operations sep_file_operations = {
2600 .owner = THIS_MODULE,
2601 .ioctl = sep_ioctl,
2602 .poll = sep_poll,
2603 .open = sep_open,
2604 .release = sep_release,
2605 .mmap = sep_mmap,
2606};
2607
2608
2609/* cdev struct of the driver */
2610static struct cdev sep_cdev;
2611
Alan Coxa2171b62009-08-07 19:22:57 +01002612/*
2613 this function registers the driver to the file system
2614*/
2615static int sep_register_driver_to_fs(void)
2616{
Alan Cox2f826142009-08-07 19:23:04 +01002617 int ret_val = alloc_chrdev_region(&sep_devno, 0, 1, "sep_sec_driver");
Alan Coxa2171b62009-08-07 19:22:57 +01002618 if (ret_val) {
2619 edbg("sep_driver:major number allocation failed, retval is %d\n", ret_val);
2620 goto end_function;
2621 }
2622
Alan Coxa2171b62009-08-07 19:22:57 +01002623 /* init cdev */
Alan Cox2f826142009-08-07 19:23:04 +01002624 cdev_init(&sep_cdev, &sep_file_operations);
2625 sep_cdev.owner = THIS_MODULE;
Alan Coxa2171b62009-08-07 19:22:57 +01002626
2627 /* register the driver with the kernel */
Alan Cox2f826142009-08-07 19:23:04 +01002628 ret_val = cdev_add(&sep_cdev, sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002629
2630 if (ret_val) {
2631 edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val);
2632 goto end_function_unregister_devnum;
2633 }
2634
2635 goto end_function;
2636
2637end_function_unregister_devnum:
2638
2639 /* unregister dev numbers */
Alan Cox2f826142009-08-07 19:23:04 +01002640 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002641
2642end_function:
2643 return ret_val;
2644}
2645
Alan Coxa2171b62009-08-07 19:22:57 +01002646
2647/*--------------------------------------------------------------
2648 init function
2649----------------------------------------------------------------*/
2650static int __init sep_init(void)
2651{
2652 int ret_val = 0;
Alan Coxa2171b62009-08-07 19:22:57 +01002653 dbg("SEP Driver:-------->Init start\n");
Alan Cox91410062009-08-07 19:23:41 +01002654 /* FIXME: Probe can occur before we are ready to survive a probe */
2655 ret_val = pci_register_driver(&sep_pci_driver);
Alan Coxa2171b62009-08-07 19:22:57 +01002656 if (ret_val) {
2657 edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val);
2658 goto end_function_unregister_from_fs;
2659 }
Alan Coxa2171b62009-08-07 19:22:57 +01002660 /* register driver to fs */
2661 ret_val = sep_register_driver_to_fs();
2662 if (ret_val)
Alan Coxca605bb2009-08-07 19:24:36 +01002663 goto end_function_unregister_pci;
Alan Coxa2171b62009-08-07 19:22:57 +01002664 goto end_function;
Alan Coxca605bb2009-08-07 19:24:36 +01002665end_function_unregister_pci:
2666 pci_unregister_driver(&sep_pci_driver);
Alan Coxa2171b62009-08-07 19:22:57 +01002667end_function_unregister_from_fs:
2668 /* unregister from fs */
Alan Cox91410062009-08-07 19:23:41 +01002669 cdev_del(&sep_cdev);
2670 /* unregister dev numbers */
2671 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002672end_function:
2673 dbg("SEP Driver:<-------- Init end\n");
2674 return ret_val;
2675}
2676
2677
2678/*-------------------------------------------------------------
2679 exit function
2680--------------------------------------------------------------*/
2681static void __exit sep_exit(void)
2682{
2683 int size;
2684
2685 dbg("SEP Driver:--------> Exit start\n");
2686
2687 /* unregister from fs */
Alan Cox91410062009-08-07 19:23:41 +01002688 cdev_del(&sep_cdev);
2689 /* unregister dev numbers */
2690 unregister_chrdev_region(sep_devno, 1);
Alan Coxa2171b62009-08-07 19:22:57 +01002691 /* calculate the total size for de-allocation */
2692 size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
2693 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;
Alan Coxca605bb2009-08-07 19:24:36 +01002694 /* FIXME: We need to do this in the unload for the device */
Alan Coxa2171b62009-08-07 19:22:57 +01002695 /* free shared area */
Alan Coxca605bb2009-08-07 19:24:36 +01002696 if (sep_dev) {
Alan Cox8c7ff812009-08-07 19:24:43 +01002697 sep_unmap_and_free_shared_area(sep_dev, size);
Alan Coxca605bb2009-08-07 19:24:36 +01002698 edbg("SEP Driver: free pages SEP SHARED AREA \n");
2699 iounmap((void *) sep_dev->reg_addr);
2700 edbg("SEP Driver: iounmap \n");
2701 }
Alan Coxa2171b62009-08-07 19:22:57 +01002702 edbg("SEP Driver: release_mem_region \n");
2703 dbg("SEP Driver:<-------- Exit end\n");
2704}
2705
2706
Mark Allyncd1bb432009-08-06 20:43:59 +01002707module_init(sep_init);
2708module_exit(sep_exit);
2709
2710MODULE_LICENSE("GPL");