From alan@lxorguk.ukuu.org.uk Wed Aug 12 13:20:11 2009 From: Alan Cox Date: Fri, 07 Aug 2009 19:23:50 +0100 Subject: Staging: sep: forward declaration removal time To: greg@kroah.com, mark.a.allyn@intel.com Message-ID: <20090807182347.19360.47452.stgit@localhost.localdomain> From: Alan Cox Exterminate! Exterminate! Exterminate! Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 2297 ++++++++++++++----------------- drivers/staging/sep/sep_driver_api.h | 42 drivers/staging/sep/sep_driver_ext_api.h | 84 - 3 files changed, 1055 insertions(+), 1368 deletions(-) --- a/drivers/staging/sep/sep_driver_api.h +++ b/drivers/staging/sep/sep_driver_api.h @@ -451,46 +451,4 @@ struct sep_flow_context_t { }; -/* - This function releases all the application virtual - buffer physical pages, that were previously locked -*/ -static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag); - -/* - This function creates the input and output dma tables for - symmetric operations (AES/DES) according to the block size - from LLI arays -*/ -static int sep_construct_dma_tables_from_lli(struct sep_lli_entry_t *lli_in_array, - unsigned long sep_in_lli_entries, - struct sep_lli_entry_t *lli_out_array, - unsigned long sep_out_lli_entries, - 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); - -/* - This function builds input and output DMA tables for synhronic symmetric - operations (AES, DES) It also checks that each table is of the modular - block size -*/ -static int sep_prepare_input_output_dma_table(unsigned long app_virt_in_addr, - unsigned long app_virt_out_addr, - unsigned long data_size, - 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, bool isKernelVirtualAddress); - -/* - This function prepares only input DMA table for synhronic symmetric - operations (HASH) -*/ -static int sep_prepare_input_dma_table(unsigned long app_virt_addr, unsigned long data_size, unsigned long block_size, unsigned long *lli_table_ptr, unsigned long *num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress); - - -/* - this function handles the request for freeing dma table for - synhronic actions -*/ -static int sep_free_dma_table_data_handler(void); - - #endif --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -184,199 +184,6 @@ static DEFINE_MUTEX(sep_mutex); /* wait queue head (event) of the driver */ static DECLARE_WAIT_QUEUE_HEAD(g_sep_event); - - -/*------------------------------------------------ - PROTOTYPES ----------------------------------------------------*/ - -/* - this function registers the driver to the file system -*/ -static int sep_register_driver_to_fs(void); - -/* - this function calculates the size of data that can be inserted into the lli - table from this array the condition is that either the table is full - (all etnries are entered), or there are no more entries in the lli array -*/ -static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries); -/* - this functions builds ont lli table from the lli_array according to the - given size of data -*/ -static 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); - -/* - this function goes over the list of the print created tables and prints - all the data -*/ -static void sep_debug_print_lli_tables(struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size); - - - -/* - This function raises interrupt to SEPm that signals that is has a new - command from HOST -*/ -static void sep_send_command_handler(void); - - -/* - This function raises interrupt to SEP that signals that is has a - new reply from HOST -*/ -static void sep_send_reply_command_handler(void); - -/* - This function handles the allocate data pool memory request - This function returns calculates the physical address of the allocated memory - and the offset of this area from the mapped address. Therefore, the FVOs in - user space can calculate the exact virtual address of this allocated memory -*/ -static int sep_allocate_data_pool_memory_handler(unsigned long arg); - - -/* - This function handles write into allocated data pool command -*/ -static int sep_write_into_data_pool_handler(unsigned long arg); - -/* - this function handles the read from data pool command -*/ -static int sep_read_from_data_pool_handler(unsigned long arg); - -/* - this function handles tha request for creation of the DMA table - for the synchronic symmetric operations (AES,DES) -*/ -static int sep_create_sync_dma_tables_handler(unsigned long arg); - -/* - this function handles the request to create the DMA tables for flow -*/ -static int sep_create_flow_dma_tables_handler(unsigned long arg); - -/* - This API handles the end transaction request -*/ -static int sep_end_transaction_handler(unsigned long arg); - - -/* - this function handles add tables to flow -*/ -static int sep_add_flow_tables_handler(unsigned long arg); - -/* - this function add the flow add message to the specific flow -*/ -static int sep_add_flow_tables_message_handler(unsigned long arg); - -/* - this function handles the request for SEP start -*/ -static int sep_start_handler(void); - -/* - this function handles the request for SEP initialization -*/ -static int sep_init_handler(unsigned long arg); - -/* - this function handles the request cache and resident reallocation -*/ -static int sep_realloc_cache_resident_handler(unsigned long arg); - - -/* - This api handles the setting of API mode to blocking or non-blocking -*/ -static int sep_set_api_mode_handler(unsigned long arg); - -/* - This function locks all the physical pages of the kernel virtual buffer - and construct a basic lli array, where each entry holds the physical - page address and the size that application data holds in this physical pages -*/ -static int sep_lock_kernel_pages(unsigned long kernel_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr); - -/* - This function creates one DMA table for flow and returns its data, - and pointer to its info entry -*/ -static int sep_prepare_one_flow_dma_table(unsigned long virt_buff_addr, unsigned long virt_buff_size, struct sep_lli_entry_t *table_data, struct sep_lli_entry_t **info_entry_ptr, struct sep_flow_context_t *flow_data_ptr, bool isKernelVirtualAddress); - -/* - This function creates a list of tables for flow and returns the data for the - first and last tables of the list -*/ -static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers, - 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); - -/* - this function find a space for the new flow dma table -*/ -static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr); - -/* - this function goes over all the flow tables connected to the given table and - deallocate them -*/ -static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr); - -/* - This function handler the set flow id command -*/ -static int sep_set_flow_id_handler(unsigned long arg); - -/* - This function returns pointer to the flow data structure - that conatins the given id -*/ -static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr); - - -/* - this function returns the physical and virtual addresses of the static pool -*/ -static int sep_get_static_pool_addr_handler(unsigned long arg); - -/* - this address gets the offset of the physical address from the start of - the mapped area -*/ -static int sep_get_physical_mapped_offset_handler(unsigned long arg); - - -/* - this function handles the request for get time -*/ -static int sep_get_time_handler(unsigned long arg); - -/* - calculates time and sets it at the predefined address -*/ -static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr); - -/* - PATCH for configuring the DMA to single burst instead of multi-burst -*/ -static void sep_configure_dma_burst(void); - -/* - This function locks all the physical pages of the - application virtual buffer and construct a basic lli - array, where each entry holds the physical page address - and the size that application data holds in this physical pages -*/ -static int sep_lock_user_pages(unsigned long app_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr); - -/*--------------------------------------------- - FUNCTIONS ------------------------------------------------*/ - /* This functions copies the cache and resident from their source location into destination memory, which is external to Linux VM and is given as @@ -692,510 +499,463 @@ static unsigned int sep_poll(struct file return mask; } - -static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +/* + calculates time and sets it at the predefined address +*/ +static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr) { - int error = 0; - - dbg("------------>SEP Driver: ioctl start\n"); + struct timeval time; + /* address of time in the kernel */ + unsigned long time_addr; - edbg("SEP Driver: cmd is %x\n", cmd); - /* check that the command is for sep device */ - if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) - error = -ENOTTY; + dbg("SEP Driver:--------> sep_set_time start\n"); - switch (cmd) { - case SEP_IOCSENDSEPCOMMAND: - /* send command to SEP */ - sep_send_command_handler(); - edbg("SEP Driver: after sep_send_command_handler\n"); - break; - case SEP_IOCSENDSEPRPLYCOMMAND: - /* send reply command to SEP */ - sep_send_reply_command_handler(); - break; - case SEP_IOCALLOCDATAPOLL: - /* allocate data pool */ - error = sep_allocate_data_pool_memory_handler(arg); - break; - case SEP_IOCWRITEDATAPOLL: - /* write data into memory pool */ - error = sep_write_into_data_pool_handler(arg); - break; - case SEP_IOCREADDATAPOLL: - /* read data from data pool into application memory */ - error = sep_read_from_data_pool_handler(arg); - break; - case SEP_IOCCREATESYMDMATABLE: - /* create dma table for synhronic operation */ - error = sep_create_sync_dma_tables_handler(arg); - break; - case SEP_IOCCREATEFLOWDMATABLE: - /* create flow dma tables */ - error = sep_create_flow_dma_tables_handler(arg); - break; - case SEP_IOCFREEDMATABLEDATA: - /* free the pages */ - error = sep_free_dma_table_data_handler(); - break; - case SEP_IOCSETFLOWID: - /* set flow id */ - error = sep_set_flow_id_handler(arg); - break; - case SEP_IOCADDFLOWTABLE: - /* add tables to the dynamic flow */ - error = sep_add_flow_tables_handler(arg); - break; - case SEP_IOCADDFLOWMESSAGE: - /* add message of add tables to flow */ - error = sep_add_flow_tables_message_handler(arg); - break; - case SEP_IOCSEPSTART: - /* start command to sep */ - error = sep_start_handler(); - break; - case SEP_IOCSEPINIT: - /* init command to sep */ - error = sep_init_handler(arg); - break; - case SEP_IOCSETAPIMODE: - /* set non- blocking mode */ - error = sep_set_api_mode_handler(arg); - break; - case SEP_IOCGETSTATICPOOLADDR: - /* get the physical and virtual addresses of the static pool */ - error = sep_get_static_pool_addr_handler(arg); - break; - case SEP_IOCENDTRANSACTION: - error = sep_end_transaction_handler(arg); - break; - case SEP_IOCREALLOCCACHERES: - error = sep_realloc_cache_resident_handler(arg); - break; - case SEP_IOCGETMAPPEDADDROFFSET: - error = sep_get_physical_mapped_offset_handler(arg); - break; - case SEP_IOCGETIME: - error = sep_get_time_handler(arg); - break; - default: - error = -ENOTTY; - break; - } - dbg("SEP Driver:<-------- ioctl end\n"); - return error; -} + do_gettimeofday(&time); + /* set value in the SYSTEM MEMORY offset */ + time_addr = sep_dev->message_shared_area_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; + *(unsigned long *) time_addr = SEP_TIME_VAL_TOKEN; + *(unsigned long *) (time_addr + 4) = time.tv_sec; -#if !SEP_DRIVER_POLLING_MODE + edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec); + edbg("SEP Driver:time_addr is %lu\n", time_addr); + edbg("SEP Driver:g_message_shared_area_addr is %lu\n", sep_dev->message_shared_area_addr); -/* handler for flow done interrupt */ + /* set the output parameters if needed */ + if (address_ptr) + *address_ptr = sep_shared_area_virt_to_phys(time_addr); -static void sep_flow_done_handler(struct work_struct *work) -{ - struct sep_flow_context_t *flow_data_ptr; + if (time_in_sec_ptr) + *time_in_sec_ptr = time.tv_sec; - /* obtain the mutex */ - mutex_lock(&sep_mutex); + dbg("SEP Driver:<-------- sep_set_time end\n"); - /* get the pointer to context */ - flow_data_ptr = (struct sep_flow_context_t *) work; + return 0; +} - /* free all the current input tables in sep */ - sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process); +/* + This function raises interrupt to SEP that signals that is has a new + command from HOST +*/ +static void sep_send_command_handler(void) +{ + unsigned long count; - /* free all the current tables output tables in SEP (if needed) */ - if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff) - sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process); + dbg("SEP Driver:--------> sep_send_command_handler start\n"); + sep_set_time(0, 0); - /* check if we have additional tables to be sent to SEP only input - flag may be checked */ - if (flow_data_ptr->input_tables_flag) { - /* copy the message to the shared RAM and signal SEP */ - memcpy((void *) flow_data_ptr->message, (void *) sep_dev->shared_area_addr, flow_data_ptr->message_size_in_bytes); + /* flash cache */ + flush_cache_all(); - sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2); - } - mutex_unlock(&sep_mutex); + for (count = 0; count < 12 * 4; count += 4) + edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count))); + + /* update counter */ + sep_dev->host_to_sep_send_counter++; + /* send interrupt to SEP */ + sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); + dbg("SEP Driver:<-------- sep_send_command_handler end\n"); + return; } + /* - interrupt handler function + This function raises interrupt to SEPm that signals that is has a + new command from HOST */ -static irqreturn_t sep_inthandler(int irq, void *dev_id) +static void sep_send_reply_command_handler(void) { - irqreturn_t int_error; - unsigned long error; - unsigned long reg_val; - unsigned long flow_id; - struct sep_flow_context_t *flow_context_ptr; + unsigned long count; - int_error = IRQ_HANDLED; + dbg("SEP Driver:--------> sep_send_reply_command_handler start\n"); - /* read the IRR register to check if this is SEP interrupt */ - reg_val = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR); - edbg("SEP Interrupt - reg is %08lx\n", reg_val); + /* flash cache */ + flush_cache_all(); + for (count = 0; count < 12 * 4; count += 4) + edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count))); + /* update counter */ + sep_dev->host_to_sep_send_counter++; + /* send the interrupt to SEP */ + sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep_dev->host_to_sep_send_counter); + /* update both counters */ + sep_dev->host_to_sep_send_counter++; + sep_dev->sep_to_host_reply_counter++; + dbg("SEP Driver:<-------- sep_send_reply_command_handler end\n"); +} - /* check if this is the flow interrupt */ - if (0 /*reg_val & (0x1 << 11) */ ) { - /* read GPRO to find out the which flow is done */ - flow_id = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR); +/* + This function handles the allocate data pool memory request + This function returns calculates the physical address of the + allocated memory, and the offset of this area from the mapped address. + Therefore, the FVOs in user space can calculate the exact virtual + address of this allocated memory +*/ +static int sep_allocate_data_pool_memory_handler(unsigned long arg) +{ + int error; + struct sep_driver_alloc_t command_args; - /* find the contex of the flow */ - error = sep_find_flow_context(flow_id >> 28, &flow_context_ptr); - if (error) - goto end_function_with_error; + dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); - INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler); + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); + if (error) + goto end_function; - /* queue the work */ - queue_work(sep_dev->flow_wq_ptr, &flow_context_ptr->flow_wq); + /* allocate memory */ + if ((sep_dev->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { + error = -ENOTTY; + goto end_function; + } - } else { - /* check if this is reply interrupt from SEP */ - if (reg_val & (0x1 << 13)) { - /* update the counter of reply messages */ - sep_dev->sep_to_host_reply_counter++; + /* set the virtual and physical address */ + command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated; + command_args.phys_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated; + + /* write the memory back to the user space */ + error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); + if (error) + goto end_function; + + /* set the allocation */ + sep_dev->data_pool_bytes_allocated += command_args.num_bytes; - /* wake up the waiting process */ - wake_up(&g_sep_event); - } else { - int_error = IRQ_NONE; - goto end_function; - } - } -end_function_with_error: - /* clear the interrupt */ - sep_write_reg(sep_dev, HW_HOST_ICR_REG_ADDR, reg_val); end_function: - return int_error; + dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n"); + return error; } -#endif - /* - This function prepares only input DMA table for synhronic symmetric - operations (HASH) + This function handles write into allocated data pool command */ -static int sep_prepare_input_dma_table(unsigned long app_virt_addr, unsigned long data_size, unsigned long block_size, unsigned long *lli_table_ptr, unsigned long *num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress) +static int sep_write_into_data_pool_handler(unsigned long arg) { - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_entry_ptr; - /* array of pointers ot page */ - struct sep_lli_entry_t *lli_array_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_entry; - /* num entries in the virtual buffer */ - unsigned long sep_lli_entries; - /* lli table pointer */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* the total data in one table */ - unsigned long table_data_size; - /* number of entries in lli table */ - unsigned long num_entries_in_table; - /* next table address */ - unsigned long lli_table_alloc_addr; - unsigned long result; + int error; + unsigned long virt_address; + unsigned long app_in_address; + unsigned long num_bytes; + unsigned long data_pool_area_addr; - dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n"); + dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n"); - edbg("SEP Driver:data_size is %lu\n", data_size); - edbg("SEP Driver:block_size is %lu\n", block_size); + /* get the application address */ + error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address)); + if (error) + goto end_function; - /* initialize the pages pointers */ - sep_dev->in_page_array = 0; - sep_dev->in_num_pages = 0; + /* get the virtual kernel address address */ + error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address)); + if (error) + goto end_function; - if (data_size == 0) { - /* special case - created 2 entries table with zero data */ - in_lli_table_ptr = (struct sep_lli_entry_t *) (sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES); - in_lli_table_ptr->physical_address = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - in_lli_table_ptr->block_size = 0; + /* get the number of bytes */ + error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); + if (error) + goto end_function; - in_lli_table_ptr++; - in_lli_table_ptr->physical_address = 0xFFFFFFFF; - in_lli_table_ptr->block_size = 0; + /* calculate the start of the data pool */ + data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - *lli_table_ptr = sep_dev->phys_shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - *num_entries_ptr = 2; - *table_data_size_ptr = 0; + /* check that the range of the virtual kernel address is correct */ + if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) { + error = -ENOTTY; goto end_function; } + /* copy the application data */ + error = copy_from_user((void *) virt_address, (void *) app_in_address, num_bytes); +end_function: + dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); + return error; +} - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array); - else - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array); - - if (result) - return result; - - edbg("SEP Driver:output sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages); - - current_entry = 0; - info_entry_ptr = 0; - sep_lli_entries = sep_dev->in_num_pages; +/* + this function handles the read from data pool command +*/ +static int sep_read_from_data_pool_handler(unsigned long arg) +{ + int error; + /* virtual address of dest application buffer */ + unsigned long app_out_address; + /* virtual address of the data pool */ + unsigned long virt_address; + unsigned long num_bytes; + unsigned long data_pool_area_addr; - /* initiate to point after the message area */ - lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n"); - /* loop till all the entries in in array are not processed */ - while (current_entry < sep_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + /* get the application address */ + error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address)); + if (error) + goto end_function; - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + /* get the virtual kernel address address */ + error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address)); + if (error) + goto end_function; - /* calculate the maximum size of data for input table */ - table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry)); + /* get the number of bytes */ + error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); + if (error) + goto end_function; - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; + /* calculate the start of the data pool */ + data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - edbg("SEP Driver:output table_data_size is %lu\n", table_data_size); + /* check that the range of the virtual kernel address is correct */ + if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) { + error = -ENOTTY; + goto end_function; + } - /* construct input lli table */ - sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); + /* copy the application data */ + error = copy_to_user((void *) app_out_address, (void *) virt_address, num_bytes); +end_function: + dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); + return error; +} - if (info_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); - *num_entries_ptr = num_entries_in_table; - *table_data_size_ptr = table_data_size; +/* + This function releases all the application virtual buffer physical pages, + that were previously locked +*/ +static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag) +{ + unsigned long count; - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr); - } else { - /* update the info entry of the previous in table */ - info_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); - info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); + if (dirtyFlag) { + for (count = 0; count < num_pages; count++) { + /* the out array was written, therefore the data was changed */ + if (!PageReserved(page_array_ptr[count])) + SetPageDirty(page_array_ptr[count]); + page_cache_release(page_array_ptr[count]); } - - /* save the pointer to the info entry of the current tables */ - info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; + } else { + /* free in pages - the data was only read, therefore no update was done + on those pages */ + for (count = 0; count < num_pages; count++) + page_cache_release(page_array_ptr[count]); } - /* print input tables */ - sep_debug_print_lli_tables((struct sep_lli_entry_t *) - sep_shared_area_phys_to_virt(*lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); + if (page_array_ptr) + /* free the array */ + kfree(page_array_ptr); - /* the array of the pages */ - kfree(lli_array_ptr); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n"); return 0; - } /* - This function builds input and output DMA tables for synhronic - symmetric operations (AES, DES). It also checks that each table - is of the modular block size + This function locks all the physical pages of the kernel virtual buffer + and construct a basic lli array, where each entry holds the physical + page address and the size that application data holds in this physical pages */ -static int sep_prepare_input_output_dma_table(unsigned long app_virt_in_addr, - unsigned long app_virt_out_addr, - unsigned long data_size, - 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, bool isKernelVirtualAddress) +static int sep_lock_kernel_pages(unsigned long kernel_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr) { - /* array of pointers of page */ - struct sep_lli_entry_t *lli_in_array; - /* array of pointers of page */ - struct sep_lli_entry_t *lli_out_array; - int result = 0; + int error = 0; + /* the the page of the end address of the user space buffer */ + unsigned long end_page; + /* the page of the start address of the user space buffer */ + unsigned long start_page; + /* the range in pages */ + unsigned long num_pages; + struct sep_lli_entry_t *lli_array; + /* next kernel address to map */ + unsigned long next_kernel_address; + unsigned long count; - dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n"); + dbg("SEP Driver:--------> sep_lock_kernel_pages start\n"); - /* initialize the pages pointers */ - sep_dev->in_page_array = 0; - sep_dev->out_page_array = 0; + /* set start and end pages and num pages */ + end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT; + start_page = kernel_virt_addr >> PAGE_SHIFT; + num_pages = end_page - start_page + 1; - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) { - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n"); - goto end_function; - } - } else { - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n"); - goto end_function; - } - } + edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr); + edbg("SEP Driver: data_size is %lu\n", data_size); + edbg("SEP Driver: start_page is %lx\n", start_page); + edbg("SEP Driver: end_page is %lx\n", end_page); + edbg("SEP Driver: num_pages is %lu\n", num_pages); - if (isKernelVirtualAddress == true) { - result = sep_lock_kernel_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } - } else { - result = sep_lock_user_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } + lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); + if (!lli_array) { + edbg("SEP Driver: kmalloc for lli_array failed\n"); + error = -ENOMEM; + goto end_function; } - edbg("sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages); - edbg("sep_dev->out_num_pages is %lu\n", sep_dev->out_num_pages); - edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + /* set the start address of the first page - app data may start not at + the beginning of the page */ + lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr); - /* call the fucntion that creates table from the lli arrays */ - result = sep_construct_dma_tables_from_lli(lli_in_array, sep_dev->in_num_pages, lli_out_array, sep_dev->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); - if (result) { - edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n"); - goto end_function_with_error2; + /* check that not all the data is in the first page only */ + if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size) + lli_array[0].block_size = data_size; + else + lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK)); + + /* debug print */ + 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); + + /* advance the address to the start of the next page */ + next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE; + + /* go from the second page to the prev before last */ + for (count = 1; count < (num_pages - 1); count++) { + lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); + lli_array[count].block_size = PAGE_SIZE; + + 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); + next_kernel_address += PAGE_SIZE; } - /* fall through - free the lli entry arrays */ - dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr); - dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr); - dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr); -end_function_with_error2: - kfree(lli_out_array); -end_function_with_error1: - kfree(lli_in_array); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result); - return result; + /* if more then 1 pages locked - then update for the last page size needed */ + if (num_pages > 1) { + /* update the address of the last page */ + lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); -} + /* set the size of the last page */ + lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK); + if (lli_array[count].block_size == 0) { + dbg("app_virt_addr is %08lx\n", kernel_virt_addr); + dbg("data_size is %lu\n", data_size); + while (1); + } -/* - This function creates the input and output dma tables for - symmetric operations (AES/DES) according to the block size from LLI arays + 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); + } + /* set output params */ + *lli_array_ptr = lli_array; + *num_pages_ptr = num_pages; + *page_array_ptr = 0; +end_function: + dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n"); + return 0; +} + +/* + This function locks all the physical pages of the application virtual buffer + and construct a basic lli array, where each entry holds the physical page + address and the size that application data holds in this physical pages */ -static int sep_construct_dma_tables_from_lli(struct sep_lli_entry_t *lli_in_array, - unsigned long sep_in_lli_entries, - struct sep_lli_entry_t *lli_out_array, - unsigned long sep_out_lli_entries, - 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) +static int sep_lock_user_pages(unsigned long app_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr) { - /* points to the area where next lli table can be allocated */ - unsigned long lli_table_alloc_addr; - /* input lli table */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* output lli table */ - struct sep_lli_entry_t *out_lli_table_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_in_entry_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_out_entry_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_in_entry; - /* points to the first entry to be processed in the lli_out_array */ - unsigned long current_out_entry; - /* max size of the input table */ - unsigned long in_table_data_size; - /* max size of the output table */ - unsigned long out_table_data_size; - /* flag te signifies if this is the first tables build from the arrays */ - unsigned long first_table_flag; - /* the data size that should be in table */ - unsigned long table_data_size; - /* number of etnries in the input table */ - unsigned long num_entries_in_table; - /* number of etnries in the output table */ - unsigned long num_entries_out_table; - - dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n"); + int error = 0; + /* the the page of the end address of the user space buffer */ + unsigned long end_page; + /* the page of the start address of the user space buffer */ + unsigned long start_page; + /* the range in pages */ + unsigned long num_pages; + struct page **page_array; + struct sep_lli_entry_t *lli_array; + unsigned long count; + int result; - /* initiate to pint after the message area */ - lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + dbg("SEP Driver:--------> sep_lock_user_pages start\n"); - current_in_entry = 0; - current_out_entry = 0; - first_table_flag = 1; - info_in_entry_ptr = 0; - info_out_entry_ptr = 0; + /* set start and end pages and num pages */ + end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; + start_page = app_virt_addr >> PAGE_SHIFT; + num_pages = end_page - start_page + 1; - /* loop till all the entries in in array are not processed */ - while (current_in_entry < sep_in_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr); + edbg("SEP Driver: data_size is %lu\n", data_size); + edbg("SEP Driver: start_page is %lu\n", start_page); + edbg("SEP Driver: end_page is %lu\n", end_page); + edbg("SEP Driver: num_pages is %lu\n", num_pages); - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + /* allocate array of pages structure pointers */ + page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); + if (!page_array) { + edbg("SEP Driver: kmalloc for page_array failed\n"); - /* set the first output tables */ - out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; + error = -ENOMEM; + goto end_function; + } - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); + if (!lli_array) { + edbg("SEP Driver: kmalloc for lli_array failed\n"); - /* calculate the maximum size of data for input table */ - in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry)); + error = -ENOMEM; + goto end_function_with_error1; + } - /* calculate the maximum size of data for output table */ - out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry)); + /* convert the application virtual address into a set of physical */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0); + up_read(¤t->mm->mmap_sem); - edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size); - edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size); + /* check the number of pages locked - if not all then exit with error */ + if (result != num_pages) { + dbg("SEP Driver: not all pages locked by get_user_pages\n"); - /* check where the data is smallest */ - table_data_size = in_table_data_size; - if (table_data_size > out_table_data_size) - table_data_size = out_table_data_size; + error = -ENOMEM; + goto end_function_with_error2; + } - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; + /* flush the cache */ + for (count = 0; count < num_pages; count++) + flush_dcache_page(page_array[count]); - dbg("SEP Driver:table_data_size is %lu\n", table_data_size); + /* set the start address of the first page - app data may start not at + the beginning of the page */ + lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK)); - /* construct input lli table */ - sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); + /* check that not all the data is in the first page only */ + if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) + lli_array[0].block_size = data_size; + else + lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); - /* construct output lli table */ - sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); + /* debug print */ + 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); - /* if info entry is null - this is the first table built */ - if (info_in_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_in_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); - *in_num_entries_ptr = num_entries_in_table; - *lli_table_out_ptr = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr); - *out_num_entries_ptr = num_entries_out_table; - *table_data_size_ptr = table_data_size; + /* go from the second page to the prev before last */ + for (count = 1; count < (num_pages - 1); count++) { + lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); + lli_array[count].block_size = PAGE_SIZE; - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr); - edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr); - } else { - /* update the info entry of the previous in table */ - info_in_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); - info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); + 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); + } - /* update the info entry of the previous in table */ - info_out_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr); - info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size); - } + /* if more then 1 pages locked - then update for the last page size needed */ + if (num_pages > 1) { + /* update the address of the last page */ + lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - /* save the pointer to the info entry of the current tables */ - info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1; + /* set the size of the last page */ + lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); - edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table); - edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr); - edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr); + if (lli_array[count].block_size == 0) { + dbg("app_virt_addr is %08lx\n", app_virt_addr); + dbg("data_size is %lu\n", data_size); + while (1); + } + 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); } - /* print input tables */ - sep_debug_print_lli_tables((struct sep_lli_entry_t *) - sep_shared_area_phys_to_virt(*lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); - /* print output tables */ - sep_debug_print_lli_tables((struct sep_lli_entry_t *) - sep_shared_area_phys_to_virt(*lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr); - dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n"); + /* set output params */ + *lli_array_ptr = lli_array; + *num_pages_ptr = num_pages; + *page_array_ptr = page_array; + goto end_function; + +end_function_with_error2: + /* release the cache */ + for (count = 0; count < num_pages; count++) + page_cache_release(page_array[count]); + kfree(lli_array); +end_function_with_error1: + kfree(page_array); +end_function: + dbg("SEP Driver:<-------- sep_lock_user_pages end\n"); return 0; } + /* this function calculates the size of data that can be inserted into the lli table from this array the condition is that either the table is full @@ -1330,495 +1090,653 @@ static void sep_debug_print_lli_tables(s /* - This function locks all the physical pages of the application virtual buffer - and construct a basic lli array, where each entry holds the physical page - address and the size that application data holds in this physical pages + This function prepares only input DMA table for synhronic symmetric + operations (HASH) */ -static int sep_lock_user_pages(unsigned long app_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr) +static int sep_prepare_input_dma_table(unsigned long app_virt_addr, unsigned long data_size, unsigned long block_size, unsigned long *lli_table_ptr, unsigned long *num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress) { - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct page **page_array; - struct sep_lli_entry_t *lli_array; - unsigned long count; - int result; + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_entry_ptr; + /* array of pointers ot page */ + struct sep_lli_entry_t *lli_array_ptr; + /* points to the first entry to be processed in the lli_in_array */ + unsigned long current_entry; + /* num entries in the virtual buffer */ + unsigned long sep_lli_entries; + /* lli table pointer */ + struct sep_lli_entry_t *in_lli_table_ptr; + /* the total data in one table */ + unsigned long table_data_size; + /* number of entries in lli table */ + unsigned long num_entries_in_table; + /* next table address */ + unsigned long lli_table_alloc_addr; + unsigned long result; - dbg("SEP Driver:--------> sep_lock_user_pages start\n"); + dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n"); - /* set start and end pages and num pages */ - end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = app_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; + edbg("SEP Driver:data_size is %lu\n", data_size); + edbg("SEP Driver:block_size is %lu\n", block_size); - edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lu\n", start_page); - edbg("SEP Driver: end_page is %lu\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); + /* initialize the pages pointers */ + sep_dev->in_page_array = 0; + sep_dev->in_num_pages = 0; - /* allocate array of pages structure pointers */ - page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); - if (!page_array) { - edbg("SEP Driver: kmalloc for page_array failed\n"); + if (data_size == 0) { + /* special case - created 2 entries table with zero data */ + in_lli_table_ptr = (struct sep_lli_entry_t *) (sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES); + in_lli_table_ptr->physical_address = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + in_lli_table_ptr->block_size = 0; + + in_lli_table_ptr++; + in_lli_table_ptr->physical_address = 0xFFFFFFFF; + in_lli_table_ptr->block_size = 0; + + *lli_table_ptr = sep_dev->phys_shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; + *num_entries_ptr = 2; + *table_data_size_ptr = 0; - error = -ENOMEM; goto end_function; } - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - - error = -ENOMEM; - goto end_function_with_error1; - } + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) + /* lock the pages of the kernel buffer and translate them to pages */ + result = sep_lock_kernel_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array); + else + /* lock the pages of the user buffer and translate them to pages */ + result = sep_lock_user_pages(app_virt_addr, data_size, &sep_dev->in_num_pages, &lli_array_ptr, &sep_dev->in_page_array); - /* convert the application virtual address into a set of physical */ - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0); - up_read(¤t->mm->mmap_sem); + if (result) + return result; - /* check the number of pages locked - if not all then exit with error */ - if (result != num_pages) { - dbg("SEP Driver: not all pages locked by get_user_pages\n"); + edbg("SEP Driver:output sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages); - error = -ENOMEM; - goto end_function_with_error2; - } + current_entry = 0; + info_entry_ptr = 0; + sep_lli_entries = sep_dev->in_num_pages; - /* flush the cache */ - for (count = 0; count < num_pages; count++) - flush_dcache_page(page_array[count]); + /* initiate to point after the message area */ + lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK)); + /* loop till all the entries in in array are not processed */ + while (current_entry < sep_lli_entries) { + /* set the new input and output tables */ + in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* debug print */ - 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); + /* calculate the maximum size of data for input table */ + table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry)); - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - lli_array[count].block_size = PAGE_SIZE; + /* now calculate the table size so that it will be module block size */ + table_data_size = (table_data_size / block_size) * block_size; - 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); - } + edbg("SEP Driver:output table_data_size is %lu\n", table_data_size); - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); + /* construct input lli table */ + sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); - /* set the size of the last page */ - lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); + if (info_entry_ptr == 0) { + /* set the output parameters to physical addresses */ + *lli_table_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); + *num_entries_ptr = num_entries_in_table; + *table_data_size_ptr = table_data_size; - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", app_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); + edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr); + } else { + /* update the info entry of the previous in table */ + info_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); + info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); } - 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); + + /* save the pointer to the info entry of the current tables */ + info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; } - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = page_array; - goto end_function; + /* print input tables */ + sep_debug_print_lli_tables((struct sep_lli_entry_t *) + sep_shared_area_phys_to_virt(*lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); -end_function_with_error2: - /* release the cache */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array[count]); - kfree(lli_array); -end_function_with_error1: - kfree(page_array); + /* the array of the pages */ + kfree(lli_array_ptr); end_function: - dbg("SEP Driver:<-------- sep_lock_user_pages end\n"); + dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n"); return 0; + } /* - This function locks all the physical pages of the kernel virtual buffer - and construct a basic lli array, where each entry holds the physical - page address and the size that application data holds in this physical pages + This function creates the input and output dma tables for + symmetric operations (AES/DES) according to the block size from LLI arays */ -static int sep_lock_kernel_pages(unsigned long kernel_virt_addr, unsigned long data_size, unsigned long *num_pages_ptr, struct sep_lli_entry_t **lli_array_ptr, struct page ***page_array_ptr) +static int sep_construct_dma_tables_from_lli(struct sep_lli_entry_t *lli_in_array, + unsigned long sep_in_lli_entries, + struct sep_lli_entry_t *lli_out_array, + unsigned long sep_out_lli_entries, + 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) { - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct sep_lli_entry_t *lli_array; - /* next kernel address to map */ - unsigned long next_kernel_address; - unsigned long count; + /* points to the area where next lli table can be allocated */ + unsigned long lli_table_alloc_addr; + /* input lli table */ + struct sep_lli_entry_t *in_lli_table_ptr; + /* output lli table */ + struct sep_lli_entry_t *out_lli_table_ptr; + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_in_entry_ptr; + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry_t *info_out_entry_ptr; + /* points to the first entry to be processed in the lli_in_array */ + unsigned long current_in_entry; + /* points to the first entry to be processed in the lli_out_array */ + unsigned long current_out_entry; + /* max size of the input table */ + unsigned long in_table_data_size; + /* max size of the output table */ + unsigned long out_table_data_size; + /* flag te signifies if this is the first tables build from the arrays */ + unsigned long first_table_flag; + /* the data size that should be in table */ + unsigned long table_data_size; + /* number of etnries in the input table */ + unsigned long num_entries_in_table; + /* number of etnries in the output table */ + unsigned long num_entries_out_table; - dbg("SEP Driver:--------> sep_lock_kernel_pages start\n"); + dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n"); - /* set start and end pages and num pages */ - end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = kernel_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; + /* initiate to pint after the message area */ + lli_table_alloc_addr = sep_dev->shared_area_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lx\n", start_page); - edbg("SEP Driver: end_page is %lx\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); + current_in_entry = 0; + current_out_entry = 0; + first_table_flag = 1; + info_in_entry_ptr = 0; + info_out_entry_ptr = 0; - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - error = -ENOMEM; - goto end_function; - } + /* loop till all the entries in in array are not processed */ + while (current_in_entry < sep_in_lli_entries) { + /* set the new input and output tables */ + in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr); + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK)); + /* set the first output tables */ + out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - /* debug print */ - 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); + lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* advance the address to the start of the next page */ - next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE; + /* calculate the maximum size of data for input table */ + in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry)); - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); - lli_array[count].block_size = PAGE_SIZE; + /* calculate the maximum size of data for output table */ + out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry)); - 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); - next_kernel_address += PAGE_SIZE; - } + edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size); + edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size); - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); + /* check where the data is smallest */ + table_data_size = in_table_data_size; + if (table_data_size > out_table_data_size) + table_data_size = out_table_data_size; - /* set the size of the last page */ - lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK); + /* now calculate the table size so that it will be module block size */ + table_data_size = (table_data_size / block_size) * block_size; - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", kernel_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); + dbg("SEP Driver:table_data_size is %lu\n", table_data_size); + + /* construct input lli table */ + sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); + + /* construct output lli table */ + sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); + + /* if info entry is null - this is the first table built */ + if (info_in_entry_ptr == 0) { + /* set the output parameters to physical addresses */ + *lli_table_in_ptr = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); + *in_num_entries_ptr = num_entries_in_table; + *lli_table_out_ptr = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr); + *out_num_entries_ptr = num_entries_out_table; + *table_data_size_ptr = table_data_size; + + edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr); + edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr); + } else { + /* update the info entry of the previous in table */ + info_in_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) in_lli_table_ptr); + info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); + + /* update the info entry of the previous in table */ + info_out_entry_ptr->physical_address = sep_shared_area_virt_to_phys((unsigned long) out_lli_table_ptr); + info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size); } - 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); + /* save the pointer to the info entry of the current tables */ + info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; + info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1; + + edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table); + edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr); + edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr); } - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = 0; -end_function: - dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n"); + + /* print input tables */ + sep_debug_print_lli_tables((struct sep_lli_entry_t *) + sep_shared_area_phys_to_virt(*lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); + /* print output tables */ + sep_debug_print_lli_tables((struct sep_lli_entry_t *) + sep_shared_area_phys_to_virt(*lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr); + dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n"); return 0; } + /* - This function releases all the application virtual buffer physical pages, - that were previously locked + This function builds input and output DMA tables for synhronic + symmetric operations (AES, DES). It also checks that each table + is of the modular block size */ -static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag) +static int sep_prepare_input_output_dma_table(unsigned long app_virt_in_addr, + unsigned long app_virt_out_addr, + unsigned long data_size, + 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, bool isKernelVirtualAddress) { - unsigned long count; + /* array of pointers of page */ + struct sep_lli_entry_t *lli_in_array; + /* array of pointers of page */ + struct sep_lli_entry_t *lli_out_array; + int result = 0; - if (dirtyFlag) { - for (count = 0; count < num_pages; count++) { - /* the out array was written, therefore the data was changed */ - if (!PageReserved(page_array_ptr[count])) - SetPageDirty(page_array_ptr[count]); - page_cache_release(page_array_ptr[count]); + dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n"); + + /* initialize the pages pointers */ + sep_dev->in_page_array = 0; + sep_dev->out_page_array = 0; + + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) { + /* lock the pages of the kernel buffer and translate them to pages */ + result = sep_lock_kernel_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array); + if (result) { + edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n"); + goto end_function; } } else { - /* free in pages - the data was only read, therefore no update was done - on those pages */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array_ptr[count]); + /* lock the pages of the user buffer and translate them to pages */ + result = sep_lock_user_pages(app_virt_in_addr, data_size, &sep_dev->in_num_pages, &lli_in_array, &sep_dev->in_page_array); + if (result) { + edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n"); + goto end_function; + } } - if (page_array_ptr) - /* free the array */ - kfree(page_array_ptr); + if (isKernelVirtualAddress == true) { + result = sep_lock_kernel_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array); + if (result) { + edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n"); + goto end_function_with_error1; + } + } else { + result = sep_lock_user_pages(app_virt_out_addr, data_size, &sep_dev->out_num_pages, &lli_out_array, &sep_dev->out_page_array); + if (result) { + edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n"); + goto end_function_with_error1; + } + } + edbg("sep_dev->in_num_pages is %lu\n", sep_dev->in_num_pages); + edbg("sep_dev->out_num_pages is %lu\n", sep_dev->out_num_pages); + edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + + + /* call the fucntion that creates table from the lli arrays */ + result = sep_construct_dma_tables_from_lli(lli_in_array, sep_dev->in_num_pages, lli_out_array, sep_dev->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); + if (result) { + edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n"); + goto end_function_with_error2; + } + + /* fall through - free the lli entry arrays */ + dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr); + dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr); + dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr); +end_function_with_error2: + kfree(lli_out_array); +end_function_with_error1: + kfree(lli_in_array); +end_function: + dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result); + return result; - return 0; } /* - This function raises interrupt to SEP that signals that is has a new - command from HOST + this function handles tha request for creation of the DMA table + for the synchronic symmetric operations (AES,DES) */ -static void sep_send_command_handler(void) +static int sep_create_sync_dma_tables_handler(unsigned long arg) { - unsigned long count; + int error; + /* command arguments */ + struct sep_driver_build_sync_table_t command_args; - dbg("SEP Driver:--------> sep_send_command_handler start\n"); - sep_set_time(0, 0); + dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); - /* flash cache */ - flush_cache_all(); + error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); + if (error) + goto end_function; - for (count = 0; count < 12 * 4; count += 4) - edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count))); + edbg("app_in_address is %08lx\n", command_args.app_in_address); + edbg("app_out_address is %08lx\n", command_args.app_out_address); + edbg("data_size is %lu\n", command_args.data_in_size); + edbg("block_size is %lu\n", command_args.block_size); - /* update counter */ - sep_dev->host_to_sep_send_counter++; - /* send interrupt to SEP */ - sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); - dbg("SEP Driver:<-------- sep_send_command_handler end\n"); - return; + /* check if we need to build only input table or input/output */ + if (command_args.app_out_address) + /* prepare input and output tables */ + error = sep_prepare_input_output_dma_table(command_args.app_in_address, + command_args.app_out_address, + command_args.data_in_size, + command_args.block_size, + &command_args.in_table_address, + &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); + else + /* prepare input tables */ + error = sep_prepare_input_dma_table(command_args.app_in_address, + 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); + + if (error) + goto end_function; + /* copy to user */ + error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t)); +end_function: + dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n"); + return error; } /* - This function raises interrupt to SEPm that signals that is has a - new command from HOST + this function handles the request for freeing dma table for synhronic actions */ -static void sep_send_reply_command_handler(void) +static int sep_free_dma_table_data_handler(void) { - unsigned long count; - - dbg("SEP Driver:--------> sep_send_reply_command_handler start\n"); + dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n"); - /* flash cache */ - flush_cache_all(); - for (count = 0; count < 12 * 4; count += 4) - edbg("Word %lu of the message is %lu\n", count, *((unsigned long *) (sep_dev->shared_area_addr + count))); - /* update counter */ - sep_dev->host_to_sep_send_counter++; - /* send the interrupt to SEP */ - sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep_dev->host_to_sep_send_counter); - /* update both counters */ - sep_dev->host_to_sep_send_counter++; - sep_dev->sep_to_host_reply_counter++; - dbg("SEP Driver:<-------- sep_send_reply_command_handler end\n"); -} + /* free input pages array */ + sep_free_dma_pages(sep_dev->in_page_array, sep_dev->in_num_pages, 0); + /* free output pages array if needed */ + if (sep_dev->out_page_array) + sep_free_dma_pages(sep_dev->out_page_array, sep_dev->out_num_pages, 1); + /* reset all the values */ + sep_dev->in_page_array = 0; + sep_dev->out_page_array = 0; + sep_dev->in_num_pages = 0; + sep_dev->out_num_pages = 0; + dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n"); + return 0; +} /* - This function handles the allocate data pool memory request - This function returns calculates the physical address of the - allocated memory, and the offset of this area from the mapped address. - Therefore, the FVOs in user space can calculate the exact virtual - address of this allocated memory + this function find a space for the new flow dma table */ -static int sep_allocate_data_pool_memory_handler(unsigned long arg) +static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr) { - int error; - struct sep_driver_alloc_t command_args; + int error = 0; + /* pointer to the id field of the flow dma table */ + unsigned long *start_table_ptr; + unsigned long flow_dma_area_start_addr; + unsigned long flow_dma_area_end_addr; + /* maximum table size in words */ + unsigned long table_size_in_words; - dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); + /* find the start address of the flow DMA table area */ + flow_dma_area_start_addr = sep_dev->shared_area_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES; - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); - if (error) - goto end_function; + /* set end address of the flow table area */ + flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES; - /* allocate memory */ - if ((sep_dev->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { - error = -ENOTTY; - goto end_function; - } + /* set table size in words */ + table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2; - /* set the virtual and physical address */ - command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated; - command_args.phys_address = sep_dev->phys_shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep_dev->data_pool_bytes_allocated; + /* set the pointer to the start address of DMA area */ + start_table_ptr = (unsigned long *) flow_dma_area_start_addr; - /* write the memory back to the user space */ - error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); - if (error) - goto end_function; + /* find the space for the next table */ + while (((*start_table_ptr & 0x7FFFFFFF) != 0) && ((unsigned long) start_table_ptr < flow_dma_area_end_addr)) + start_table_ptr += table_size_in_words; - /* set the allocation */ - sep_dev->data_pool_bytes_allocated += command_args.num_bytes; + /* check if we reached the end of floa tables area */ + if ((unsigned long) start_table_ptr >= flow_dma_area_end_addr) + error = -1; + else + *table_address_ptr = start_table_ptr; -end_function: - dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n"); return error; } + + /* - This function handles write into allocated data pool command + This function creates one DMA table for flow and returns its data, + and pointer to its info entry */ -static int sep_write_into_data_pool_handler(unsigned long arg) +static int sep_prepare_one_flow_dma_table(unsigned long virt_buff_addr, unsigned long virt_buff_size, struct sep_lli_entry_t *table_data, struct sep_lli_entry_t **info_entry_ptr, struct sep_flow_context_t *flow_data_ptr, bool isKernelVirtualAddress) { int error; - unsigned long virt_address; - unsigned long app_in_address; - unsigned long num_bytes; - unsigned long data_pool_area_addr; - - dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n"); + /* the range in pages */ + unsigned long lli_array_size; + struct sep_lli_entry_t *lli_array; + struct sep_lli_entry_t *flow_dma_table_entry_ptr; + unsigned long *start_dma_table_ptr; + /* total table data counter */ + unsigned long dma_table_data_count; + /* pointer that will keep the pointer to the pages of the virtual buffer */ + struct page **page_array_ptr; + unsigned long entry_count; - /* get the application address */ - error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address)); + /* find the space for the new table */ + error = sep_find_free_flow_dma_table_space(&start_dma_table_ptr); if (error) goto end_function; - /* get the virtual kernel address address */ - error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; + /* check if the pages are in Kernel Virtual Address layout */ + if (isKernelVirtualAddress == true) + /* lock kernel buffer in the memory */ + error = sep_lock_kernel_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); + else + /* lock user buffer in the memory */ + error = sep_lock_user_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); if (error) goto end_function; - /* calculate the start of the data pool */ - data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; + /* set the pointer to page array at the beginning of table - this table is + now considered taken */ + *start_dma_table_ptr = lli_array_size; + /* point to the place of the pages pointers of the table */ + start_dma_table_ptr++; - /* check that the range of the virtual kernel address is correct */ - if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) { - error = -ENOTTY; - goto end_function; + /* set the pages pointer */ + *start_dma_table_ptr = (unsigned long) page_array_ptr; + + /* set the pointer to the first entry */ + flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr); + + /* now create the entries for table */ + for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) { + flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address; + + flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size; + + /* set the total data of a table */ + dma_table_data_count += lli_array[entry_count].block_size; + + flow_dma_table_entry_ptr++; } - /* copy the application data */ - error = copy_from_user((void *) virt_address, (void *) app_in_address, num_bytes); + + /* set the physical address */ + table_data->physical_address = virt_to_phys(start_dma_table_ptr); + + /* set the num_entries and total data size */ + table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count); + + /* set the info entry */ + flow_dma_table_entry_ptr->physical_address = 0xffffffff; + flow_dma_table_entry_ptr->block_size = 0; + + /* set the pointer to info entry */ + *info_entry_ptr = flow_dma_table_entry_ptr; + + /* the array of the lli entries */ + kfree(lli_array); end_function: - dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); return error; } + + /* - this function handles the read from data pool command + This function creates a list of tables for flow and returns the data for + the first and last tables of the list */ -static int sep_read_from_data_pool_handler(unsigned long arg) +static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers, + 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) { int error; - /* virtual address of dest application buffer */ - unsigned long app_out_address; - /* virtual address of the data pool */ - unsigned long virt_address; - unsigned long num_bytes; - unsigned long data_pool_area_addr; + unsigned long virt_buff_addr; + unsigned long virt_buff_size; + struct sep_lli_entry_t table_data; + struct sep_lli_entry_t *info_entry_ptr; + struct sep_lli_entry_t *prev_info_entry_ptr; + unsigned long i; - dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n"); + /* init vars */ + error = 0; + prev_info_entry_ptr = 0; - /* get the application address */ - error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address)); - if (error) - goto end_function; + /* init the first table to default */ + table_data.physical_address = 0xffffffff; + first_table_data_ptr->physical_address = 0xffffffff; + table_data.block_size = 0; - /* get the virtual kernel address address */ - error = get_user(virt_address, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; + for (i = 0; i < num_virtual_buffers; i++) { + /* get the virtual buffer address */ + error = get_user(virt_buff_addr, &first_buff_addr); + if (error) + goto end_function; - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); - if (error) - goto end_function; + /* get the virtual buffer size */ + first_buff_addr++; + error = get_user(virt_buff_size, &first_buff_addr); + if (error) + goto end_function; - /* calculate the start of the data pool */ - data_pool_area_addr = sep_dev->shared_area_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; + /* advance the address to point to the next pair of address|size */ + first_buff_addr++; - /* check that the range of the virtual kernel address is correct */ - if ((virt_address < data_pool_area_addr) || (virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES))) { - error = -ENOTTY; - goto end_function; + /* now prepare the one flow LLI table from the data */ + error = sep_prepare_one_flow_dma_table(virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress); + if (error) + goto end_function; + + if (i == 0) { + /* if this is the first table - save it to return to the user + application */ + *first_table_data_ptr = table_data; + + /* set the pointer to info entry */ + prev_info_entry_ptr = info_entry_ptr; + } else { + /* not first table - the previous table info entry should + be updated */ + prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size); + + /* set the pointer to info entry */ + prev_info_entry_ptr = info_entry_ptr; + } } - /* copy the application data */ - error = copy_to_user((void *) app_out_address, (void *) virt_address, num_bytes); + /* set the last table data */ + *last_table_data_ptr = table_data; end_function: - dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); return error; } - /* - this function handles tha request for creation of the DMA table - for the synchronic symmetric operations (AES,DES) + this function goes over all the flow tables connected to the given + table and deallocate them */ -static int sep_create_sync_dma_tables_handler(unsigned long arg) +static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr) { - int error; - /* command arguments */ - struct sep_driver_build_sync_table_t command_args; + /* id pointer */ + unsigned long *table_ptr; + /* end address of the flow dma area */ + unsigned long num_entries; + unsigned long num_pages; + struct page **pages_ptr; + /* maximum table size in words */ + struct sep_lli_entry_t *info_entry_ptr; - dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); + /* set the pointer to the first table */ + table_ptr = (unsigned long *) first_table_ptr->physical_address; - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); - if (error) - goto end_function; + /* set the num of entries */ + num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) + & SEP_NUM_ENTRIES_MASK; - edbg("app_in_address is %08lx\n", command_args.app_in_address); - edbg("app_out_address is %08lx\n", command_args.app_out_address); - edbg("data_size is %lu\n", command_args.data_in_size); - edbg("block_size is %lu\n", command_args.block_size); + /* go over all the connected tables */ + while (*table_ptr != 0xffffffff) { + /* get number of pages */ + num_pages = *(table_ptr - 2); - /* check if we need to build only input table or input/output */ - if (command_args.app_out_address) - /* prepare input and output tables */ - error = sep_prepare_input_output_dma_table(command_args.app_in_address, - command_args.app_out_address, - command_args.data_in_size, - command_args.block_size, - &command_args.in_table_address, - &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); - else - /* prepare input tables */ - error = sep_prepare_input_dma_table(command_args.app_in_address, - 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); + /* get the pointer to the pages */ + pages_ptr = (struct page **) (*(table_ptr - 1)); - if (error) - goto end_function; - /* copy to user */ - error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t)); -end_function: - dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n"); - return error; + /* free the pages */ + sep_free_dma_pages(pages_ptr, num_pages, 1); + + /* goto to the info entry */ + info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1); + + table_ptr = (unsigned long *) info_entry_ptr->physical_address; + num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; + } + + return; } /* - this function handles the request for freeing dma table for synhronic actions + This function returns pointer to the flow data structure + that contains the given id */ -static int sep_free_dma_table_data_handler(void) +static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr) { - dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n"); + unsigned long count; + int error = 0; - /* free input pages array */ - sep_free_dma_pages(sep_dev->in_page_array, sep_dev->in_num_pages, 0); + /* + always search for flow with id default first - in case we + already started working on the flow there can be no situation + when 2 flows are with default flag + */ + for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) { + if (sep_dev->flows_data_array[count].flow_id == flow_id) { + *flow_data_ptr = &sep_dev->flows_data_array[count]; + break; + } + } - /* free output pages array if needed */ - if (sep_dev->out_page_array) - sep_free_dma_pages(sep_dev->out_page_array, sep_dev->out_num_pages, 1); + if (count == SEP_DRIVER_NUM_FLOWS) + /* no flow found */ + error = -ENOMEM; - /* reset all the values */ - sep_dev->in_page_array = 0; - sep_dev->out_page_array = 0; - sep_dev->in_num_pages = 0; - sep_dev->out_num_pages = 0; - dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n"); - return 0; + return error; } + /* this function handles the request to create the DMA tables for flow */ @@ -2238,300 +2156,43 @@ static int sep_set_api_mode_handler(unsi int error; unsigned long mode_flag; - dbg("SEP Driver:--------> sep_set_api_mode_handler start\n"); - - error = get_user(mode_flag, &(((struct sep_driver_set_api_mode_t *) arg)->mode)); - if (error) - goto end_function; - - /* set the global flag */ - sep_dev->block_mode_flag = mode_flag; -end_function: - dbg("SEP Driver:<-------- sep_set_api_mode_handler end\n"); - return error; -} - -/* - This API handles the end transaction request -*/ -static int sep_end_transaction_handler(unsigned long arg) -{ - dbg("SEP Driver:--------> sep_end_transaction_handler start\n"); - -#if 0 /*!SEP_DRIVER_POLLING_MODE */ - /* close IMR */ - sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF); - - /* release IRQ line */ - free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address); - - /* lock the sep mutex */ - mutex_unlock(&sep_mutex); -#endif - - dbg("SEP Driver:<-------- sep_end_transaction_handler end\n"); - - return 0; -} - - - -/* - This function creates a list of tables for flow and returns the data for - the first and last tables of the list -*/ -static int sep_prepare_flow_dma_tables(unsigned long num_virtual_buffers, - 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) -{ - int error; - unsigned long virt_buff_addr; - unsigned long virt_buff_size; - struct sep_lli_entry_t table_data; - struct sep_lli_entry_t *info_entry_ptr; - struct sep_lli_entry_t *prev_info_entry_ptr; - unsigned long i; - - /* init vars */ - error = 0; - prev_info_entry_ptr = 0; - - /* init the first table to default */ - table_data.physical_address = 0xffffffff; - first_table_data_ptr->physical_address = 0xffffffff; - table_data.block_size = 0; - - for (i = 0; i < num_virtual_buffers; i++) { - /* get the virtual buffer address */ - error = get_user(virt_buff_addr, &first_buff_addr); - if (error) - goto end_function; - - /* get the virtual buffer size */ - first_buff_addr++; - error = get_user(virt_buff_size, &first_buff_addr); - if (error) - goto end_function; - - /* advance the address to point to the next pair of address|size */ - first_buff_addr++; - - /* now prepare the one flow LLI table from the data */ - error = sep_prepare_one_flow_dma_table(virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress); - if (error) - goto end_function; - - if (i == 0) { - /* if this is the first table - save it to return to the user - application */ - *first_table_data_ptr = table_data; - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } else { - /* not first table - the previous table info entry should - be updated */ - prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size); - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } - } - - /* set the last table data */ - *last_table_data_ptr = table_data; -end_function: - return error; -} - - -/* - This function creates one DMA table for flow and returns its data, - and pointer to its info entry -*/ -static int sep_prepare_one_flow_dma_table(unsigned long virt_buff_addr, unsigned long virt_buff_size, struct sep_lli_entry_t *table_data, struct sep_lli_entry_t **info_entry_ptr, struct sep_flow_context_t *flow_data_ptr, bool isKernelVirtualAddress) -{ - int error; - /* the range in pages */ - unsigned long lli_array_size; - struct sep_lli_entry_t *lli_array; - struct sep_lli_entry_t *flow_dma_table_entry_ptr; - unsigned long *start_dma_table_ptr; - /* total table data counter */ - unsigned long dma_table_data_count; - /* pointer that will keep the pointer to the pages of the virtual buffer */ - struct page **page_array_ptr; - unsigned long entry_count; - - /* find the space for the new table */ - error = sep_find_free_flow_dma_table_space(&start_dma_table_ptr); - if (error) - goto end_function; - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock kernel buffer in the memory */ - error = sep_lock_kernel_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - else - /* lock user buffer in the memory */ - error = sep_lock_user_pages(virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - - if (error) - goto end_function; - - /* set the pointer to page array at the beginning of table - this table is - now considered taken */ - *start_dma_table_ptr = lli_array_size; - - /* point to the place of the pages pointers of the table */ - start_dma_table_ptr++; - - /* set the pages pointer */ - *start_dma_table_ptr = (unsigned long) page_array_ptr; - - /* set the pointer to the first entry */ - flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr); - - /* now create the entries for table */ - for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) { - flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address; - - flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size; - - /* set the total data of a table */ - dma_table_data_count += lli_array[entry_count].block_size; - - flow_dma_table_entry_ptr++; - } - - /* set the physical address */ - table_data->physical_address = virt_to_phys(start_dma_table_ptr); - - /* set the num_entries and total data size */ - table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count); - - /* set the info entry */ - flow_dma_table_entry_ptr->physical_address = 0xffffffff; - flow_dma_table_entry_ptr->block_size = 0; - - /* set the pointer to info entry */ - *info_entry_ptr = flow_dma_table_entry_ptr; - - /* the array of the lli entries */ - kfree(lli_array); -end_function: - return error; -} - - -/* - This function returns pointer to the flow data structure - that contains the given id -*/ -static int sep_find_flow_context(unsigned long flow_id, struct sep_flow_context_t **flow_data_ptr) -{ - unsigned long count; - int error = 0; - - /* - always search for flow with id default first - in case we - already started working on the flow there can be no situation - when 2 flows are with default flag - */ - for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) { - if (sep_dev->flows_data_array[count].flow_id == flow_id) { - *flow_data_ptr = &sep_dev->flows_data_array[count]; - break; - } - } - - if (count == SEP_DRIVER_NUM_FLOWS) - /* no flow found */ - error = -ENOMEM; - - return error; -} - -/* - this function find a space for the new flow dma table -*/ -static int sep_find_free_flow_dma_table_space(unsigned long **table_address_ptr) -{ - int error = 0; - /* pointer to the id field of the flow dma table */ - unsigned long *start_table_ptr; - unsigned long flow_dma_area_start_addr; - unsigned long flow_dma_area_end_addr; - /* maximum table size in words */ - unsigned long table_size_in_words; - - /* find the start address of the flow DMA table area */ - flow_dma_area_start_addr = sep_dev->shared_area_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - /* set end address of the flow table area */ - flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES; - - /* set table size in words */ - table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2; - - /* set the pointer to the start address of DMA area */ - start_table_ptr = (unsigned long *) flow_dma_area_start_addr; - - /* find the space for the next table */ - while (((*start_table_ptr & 0x7FFFFFFF) != 0) && ((unsigned long) start_table_ptr < flow_dma_area_end_addr)) - start_table_ptr += table_size_in_words; + dbg("SEP Driver:--------> sep_set_api_mode_handler start\n"); - /* check if we reached the end of floa tables area */ - if ((unsigned long) start_table_ptr >= flow_dma_area_end_addr) - error = -1; - else - *table_address_ptr = start_table_ptr; + error = get_user(mode_flag, &(((struct sep_driver_set_api_mode_t *) arg)->mode)); + if (error) + goto end_function; + /* set the global flag */ + sep_dev->block_mode_flag = mode_flag; +end_function: + dbg("SEP Driver:<-------- sep_set_api_mode_handler end\n"); return error; } /* - this function goes over all the flow tables connected to the given - table and deallocate them + This API handles the end transaction request */ -static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr) +static int sep_end_transaction_handler(unsigned long arg) { - /* id pointer */ - unsigned long *table_ptr; - /* end address of the flow dma area */ - unsigned long num_entries; - unsigned long num_pages; - struct page **pages_ptr; - /* maximum table size in words */ - struct sep_lli_entry_t *info_entry_ptr; - - /* set the pointer to the first table */ - table_ptr = (unsigned long *) first_table_ptr->physical_address; - - /* set the num of entries */ - num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) - & SEP_NUM_ENTRIES_MASK; - - /* go over all the connected tables */ - while (*table_ptr != 0xffffffff) { - /* get number of pages */ - num_pages = *(table_ptr - 2); + dbg("SEP Driver:--------> sep_end_transaction_handler start\n"); - /* get the pointer to the pages */ - pages_ptr = (struct page **) (*(table_ptr - 1)); +#if 0 /*!SEP_DRIVER_POLLING_MODE */ + /* close IMR */ + sep_write_reg(sep_dev, HW_HOST_IMR_REG_ADDR, 0x7FFF); - /* free the pages */ - sep_free_dma_pages(pages_ptr, num_pages, 1); + /* release IRQ line */ + free_irq(SEP_DIRVER_IRQ_NUM, &sep_dev->reg_base_address); - /* goto to the info entry */ - info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1); + /* lock the sep mutex */ + mutex_unlock(&sep_mutex); +#endif - table_ptr = (unsigned long *) info_entry_ptr->physical_address; - num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - } + dbg("SEP Driver:<-------- sep_end_transaction_handler end\n"); - return; + return 0; } + /* This function handler the set flow id command */ @@ -2562,41 +2223,193 @@ end_function: } + + + +static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int error = 0; + + dbg("------------>SEP Driver: ioctl start\n"); + + edbg("SEP Driver: cmd is %x\n", cmd); + + /* check that the command is for sep device */ + if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) + error = -ENOTTY; + + switch (cmd) { + case SEP_IOCSENDSEPCOMMAND: + /* send command to SEP */ + sep_send_command_handler(); + edbg("SEP Driver: after sep_send_command_handler\n"); + break; + case SEP_IOCSENDSEPRPLYCOMMAND: + /* send reply command to SEP */ + sep_send_reply_command_handler(); + break; + case SEP_IOCALLOCDATAPOLL: + /* allocate data pool */ + error = sep_allocate_data_pool_memory_handler(arg); + break; + case SEP_IOCWRITEDATAPOLL: + /* write data into memory pool */ + error = sep_write_into_data_pool_handler(arg); + break; + case SEP_IOCREADDATAPOLL: + /* read data from data pool into application memory */ + error = sep_read_from_data_pool_handler(arg); + break; + case SEP_IOCCREATESYMDMATABLE: + /* create dma table for synhronic operation */ + error = sep_create_sync_dma_tables_handler(arg); + break; + case SEP_IOCCREATEFLOWDMATABLE: + /* create flow dma tables */ + error = sep_create_flow_dma_tables_handler(arg); + break; + case SEP_IOCFREEDMATABLEDATA: + /* free the pages */ + error = sep_free_dma_table_data_handler(); + break; + case SEP_IOCSETFLOWID: + /* set flow id */ + error = sep_set_flow_id_handler(arg); + break; + case SEP_IOCADDFLOWTABLE: + /* add tables to the dynamic flow */ + error = sep_add_flow_tables_handler(arg); + break; + case SEP_IOCADDFLOWMESSAGE: + /* add message of add tables to flow */ + error = sep_add_flow_tables_message_handler(arg); + break; + case SEP_IOCSEPSTART: + /* start command to sep */ + error = sep_start_handler(); + break; + case SEP_IOCSEPINIT: + /* init command to sep */ + error = sep_init_handler(arg); + break; + case SEP_IOCSETAPIMODE: + /* set non- blocking mode */ + error = sep_set_api_mode_handler(arg); + break; + case SEP_IOCGETSTATICPOOLADDR: + /* get the physical and virtual addresses of the static pool */ + error = sep_get_static_pool_addr_handler(arg); + break; + case SEP_IOCENDTRANSACTION: + error = sep_end_transaction_handler(arg); + break; + case SEP_IOCREALLOCCACHERES: + error = sep_realloc_cache_resident_handler(arg); + break; + case SEP_IOCGETMAPPEDADDROFFSET: + error = sep_get_physical_mapped_offset_handler(arg); + break; + case SEP_IOCGETIME: + error = sep_get_time_handler(arg); + break; + default: + error = -ENOTTY; + break; + } + dbg("SEP Driver:<-------- ioctl end\n"); + return error; +} + + + +#if !SEP_DRIVER_POLLING_MODE + +/* handler for flow done interrupt */ + +static void sep_flow_done_handler(struct work_struct *work) +{ + struct sep_flow_context_t *flow_data_ptr; + + /* obtain the mutex */ + mutex_lock(&sep_mutex); + + /* get the pointer to context */ + flow_data_ptr = (struct sep_flow_context_t *) work; + + /* free all the current input tables in sep */ + sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process); + + /* free all the current tables output tables in SEP (if needed) */ + if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff) + sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process); + + /* check if we have additional tables to be sent to SEP only input + flag may be checked */ + if (flow_data_ptr->input_tables_flag) { + /* copy the message to the shared RAM and signal SEP */ + memcpy((void *) flow_data_ptr->message, (void *) sep_dev->shared_area_addr, flow_data_ptr->message_size_in_bytes); + + sep_write_reg(sep_dev, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2); + } + mutex_unlock(&sep_mutex); +} /* - calculates time and sets it at the predefined address + interrupt handler function */ -static int sep_set_time(unsigned long *address_ptr, unsigned long *time_in_sec_ptr) +static irqreturn_t sep_inthandler(int irq, void *dev_id) { - struct timeval time; - /* address of time in the kernel */ - unsigned long time_addr; + irqreturn_t int_error; + unsigned long error; + unsigned long reg_val; + unsigned long flow_id; + struct sep_flow_context_t *flow_context_ptr; + int_error = IRQ_HANDLED; - dbg("SEP Driver:--------> sep_set_time start\n"); + /* read the IRR register to check if this is SEP interrupt */ + reg_val = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR); + edbg("SEP Interrupt - reg is %08lx\n", reg_val); - do_gettimeofday(&time); + /* check if this is the flow interrupt */ + if (0 /*reg_val & (0x1 << 11) */ ) { + /* read GPRO to find out the which flow is done */ + flow_id = sep_read_reg(sep_dev, HW_HOST_IRR_REG_ADDR); - /* set value in the SYSTEM MEMORY offset */ - time_addr = sep_dev->message_shared_area_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; + /* find the contex of the flow */ + error = sep_find_flow_context(flow_id >> 28, &flow_context_ptr); + if (error) + goto end_function_with_error; - *(unsigned long *) time_addr = SEP_TIME_VAL_TOKEN; - *(unsigned long *) (time_addr + 4) = time.tv_sec; + INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler); - edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec); - edbg("SEP Driver:time_addr is %lu\n", time_addr); - edbg("SEP Driver:g_message_shared_area_addr is %lu\n", sep_dev->message_shared_area_addr); + /* queue the work */ + queue_work(sep_dev->flow_wq_ptr, &flow_context_ptr->flow_wq); + + } else { + /* check if this is reply interrupt from SEP */ + if (reg_val & (0x1 << 13)) { + /* update the counter of reply messages */ + sep_dev->sep_to_host_reply_counter++; + + /* wake up the waiting process */ + wake_up(&g_sep_event); + } else { + int_error = IRQ_NONE; + goto end_function; + } + } +end_function_with_error: + /* clear the interrupt */ + sep_write_reg(sep_dev, HW_HOST_ICR_REG_ADDR, reg_val); +end_function: + return int_error; +} + +#endif - /* set the output parameters if needed */ - if (address_ptr) - *address_ptr = sep_shared_area_virt_to_phys(time_addr); - if (time_in_sec_ptr) - *time_in_sec_ptr = time.tv_sec; - dbg("SEP Driver:<-------- sep_set_time end\n"); - return 0; -} static void sep_wait_busy(struct sep_device *dev) { --- a/drivers/staging/sep/sep_driver_ext_api.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * sep_driver_ext_api.h - Security Processor Driver external api definitions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef __SEP_DRIVER_EXT_API_H__ -#define __SEP_DRIVER_EXT_API_H__ - - -/* shared variables */ -static int sepDebug; - -/* -this function loads the ROM code in SEP (needed only in the debug mode on FPGA) -*/ -static void sep_load_rom_code(void); - -/* -This functions copies the cache and resident from their source location into -destination memory, which is external to Linux VM and is given as physical -address -*/ -static int sep_copy_cache_resident_to_area(unsigned long src_cache_addr, unsigned long cache_size_in_bytes, unsigned long src_resident_addr, unsigned long resident_size_in_bytes, unsigned long *dst_new_cache_addr_ptr, unsigned long *dst_new_resident_addr_ptr); - -/* -This functions maps and allocates the shared area on the external -RAM (device) The input is shared_area_size - the size of the memory -to allocate. The outputs are kernel_shared_area_addr_ptr - the kerenl -address of the mapped and allocated shared area, and -phys_shared_area_addr_ptr - the physical address of the shared area -*/ -static int sep_map_and_alloc_shared_area(unsigned long shared_area_size, unsigned long *kernel_shared_area_addr_ptr, unsigned long *phys_shared_area_addr_ptr); - -/* -This functions unmaps and deallocates the shared area on the external -RAM (device) The input is shared_area_size - the size of the memory to -deallocate,kernel_shared_area_addr_ptr - the kernel address of the -mapped and allocated shared area,phys_shared_area_addr_ptr - the physical -address of the shared area -*/ -static void sep_unmap_and_free_shared_area(unsigned long shared_area_size, unsigned long kernel_shared_area_addr, unsigned long phys_shared_area_addr); - - -/* -This functions returns the physical address inside shared area according -to the virtual address. It can be either on the externa RAM device -(ioremapped), or on the system RAM -*/ -static unsigned long sep_shared_area_virt_to_phys(unsigned long virt_address); - -/* -This functions returns the vitrual address inside shared area according -to the physical address. It can be either on the externa RAM device -(ioremapped), or on the system RAM This implementation is for the external RAM -*/ -static unsigned long sep_shared_area_phys_to_virt(unsigned long phys_address); - -#endif /*__SEP_DRIVER_EXT_API_H__*/