aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-12-08 10:57:26 +0000
committerAlan Cox <alan@linux.intel.com>2010-12-08 10:57:26 +0000
commita4c069fc2074aeeb5263c4a156ce9cfc1f83afc0 (patch)
tree387597880621439fef1f0b0409fa8dc6402f0702
parenteaf3488a9b6830a015b43fdc870c30b0ec4590fc (diff)
downloadmrst-s0i3-test-a4c069fc2074aeeb5263c4a156ce9cfc1f83afc0.tar.gz
mrst-s0i3-test-a4c069fc2074aeeb5263c4a156ce9cfc1f83afc0.tar.xz
mrst-s0i3-test-a4c069fc2074aeeb5263c4a156ce9cfc1f83afc0.zip
Signed-off-by: Mark A. Allyn <mark.a.allyn@intel.com>
-rw-r--r--drivers/staging/sep/sep_driver.c399
1 files changed, 236 insertions, 163 deletions
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
index e2a9e3fccdb..794ce113177 100644
--- a/drivers/staging/sep/sep_driver.c
+++ b/drivers/staging/sep/sep_driver.c
@@ -1385,256 +1385,329 @@ end_function:
}
/*
- 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;
-
- 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]);
- }
- } 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]);
- }
-
- if (page_array_ptr)
- /* free the array */
- kfree(page_array_ptr);
-
- 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 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 page
*/
static int sep_lock_kernel_pages(struct sep_device *sep,
- 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)
+ u32 kernel_virt_addr,
+ u32 data_size,
+ struct sep_lli_entry_t **lli_array_ptr,
+ int in_out_flag)
+
{
+ /* error */
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;
+
+ /* array of lli */
struct sep_lli_entry_t *lli_array;
- /* next kernel address to map */
- unsigned long next_kernel_address;
- unsigned long count;
- dbg("SEP Driver:--------> sep_lock_kernel_pages start\n");
+ /* map array */
+ struct sep_dma_map *map_array;
- /* 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;
+ /*------------------------
+ CODE
+ --------------------------*/
- 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);
+ dev_dbg(&sep->pdev->dev,
+ "sep_lock_kernel_pages start\n");
+
+ dev_dbg(&sep->pdev->dev,
+ "kernel_virt_addr is %08x\n", kernel_virt_addr);
+ dev_dbg(&sep->pdev->dev,
+ "data_size is %x\n", data_size);
- lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
+ lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * 1, GFP_ATOMIC);
if (!lli_array) {
- edbg("SEP Driver: kmalloc for lli_array failed\n");
+
+ dev_warn(&sep->pdev->dev, "kmalloc for lli_array failed\n");
error = -ENOMEM;
goto end_function;
}
- /* 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);
-
- /* 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));
+ map_array = kmalloc(sizeof(struct sep_dma_map) * 1, GFP_ATOMIC);
+ if (!map_array) {
+ dev_warn(&sep->pdev->dev, "kmalloc for map_array failed\n");
+ error = -ENOMEM;
+ goto end_function_with_error;
+ }
- /* 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);
+ map_array[0].dma_addr =
+ dma_map_single(&sep->pdev->dev, (void *)kernel_virt_addr,
+ data_size, DMA_BIDIRECTIONAL);
+ map_array[0].size = data_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;
+ /* set the start address of the first page - app data may start not at
+ the beginning of the page */
+ lli_array[0].bus_address = (u32)map_array[0].dma_addr;
+ lli_array[0].block_size = map_array[0].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;
+ /* debug print */
+ dev_dbg(&sep->pdev->dev,
+ "lli_array[0].bus_address is %08x,"
+ " lli_array[0].block_size is %x\n",
+ lli_array[0].bus_address,
+ lli_array[0].block_size);
+
+ /* set the output parameters */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = 1;
+ } else {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = 1;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1;
}
- /* 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);
+ goto end_function;
- /* set the size of the last page */
- lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK);
+end_function_with_error:
- 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);
- }
+ kfree(lli_array);
- 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;
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_lock_kernel_pages end\n");
+
+ return error;
}
/*
- 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 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(struct sep_device *sep,
- 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)
+ u32 app_virt_addr,
+ u32 data_size,
+ struct sep_lli_entry_t **lli_array_ptr,
+ int in_out_flag)
+
{
- int error = 0;
+ /* error */
+ int error;
+
/* the the page of the end address of the user space buffer */
- unsigned long end_page;
+ u32 end_page;
+
/* the page of the start address of the user space buffer */
- unsigned long start_page;
+ u32 start_page;
+
/* the range in pages */
- unsigned long num_pages;
+ u32 num_pages;
+
+ /* array of pointers ot page */
struct page **page_array;
+
+ /* array of lli */
struct sep_lli_entry_t *lli_array;
- unsigned long count;
+
+ /* map array */
+ struct sep_dma_map *map_array;
+
+ /* direction of the DMA mapping for locked pages */
+ enum dma_data_direction dir;
+
+ /* count */
+ u32 count;
+
+ /* result */
int result;
- dbg("SEP Driver:--------> sep_lock_user_pages start\n");
+ /*------------------------
+ CODE
+ --------------------------*/
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_lock_user_pages start\n");
+
+ error = 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;
- 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);
+ dev_dbg(&sep->pdev->dev,
+ "app_virt_addr is %08x\n", app_virt_addr);
+ dev_dbg(&sep->pdev->dev,
+ "data_size is %x\n", data_size);
+ dev_dbg(&sep->pdev->dev,
+ "start_page is %x\n", start_page);
+ dev_dbg(&sep->pdev->dev,
+ "end_page is %x\n", end_page);
+ dev_dbg(&sep->pdev->dev,
+ "num_pages is %x\n", num_pages);
+
+ dev_dbg(&sep->pdev->dev,
+ "starting page_array malloc\n");
/* 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");
+ dev_warn(&sep->pdev->dev,
+ "kmalloc for page_array failed\n");
error = -ENOMEM;
goto end_function;
}
- lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC);
+ map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC);
+ if (!map_array) {
+ dev_warn(&sep->pdev->dev,
+ "kmalloc for map_array failed\n");
+ error = -ENOMEM;
+ 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");
+ dev_warn(&sep->pdev->dev,
+ "kmalloc for lli_array failed\n");
error = -ENOMEM;
- goto end_function_with_error1;
+ goto end_function_with_error2;
}
+ dev_dbg(&sep->pdev->dev,
+ "starting get_user_pages\n");
+
/* convert the application virtual address into a set of physical */
down_read(&current->mm->mmap_sem);
- result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0);
+ result = get_user_pages(current, current->mm, app_virt_addr,
+ num_pages,
+ ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1),
+ 0, page_array, 0);
+
up_read(&current->mm->mmap_sem);
/* 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");
+ dev_warn(&sep->pdev->dev,
+ "not all pages locked by get_user_pages\n");
error = -ENOMEM;
- goto end_function_with_error2;
+ goto end_function_with_error3;
}
- /* flush the cache */
- for (count = 0; count < num_pages; count++)
- flush_dcache_page(page_array[count]);
-
- /* 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));
+ dev_dbg(&sep->pdev->dev,
+ "get_user_pages succeeded\n");
- /* 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;
+ /* set direction */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG)
+ dir = DMA_TO_DEVICE;
else
- lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
+ dir = DMA_FROM_DEVICE;
- /* 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);
+ /* fill the array using page array data and map the pages - this action
+ will also flush the cache as needed */
+ for (count = 0; count < num_pages; count++) {
+ /* fill the map array */
+ map_array[count].dma_addr =
+ dma_map_page(&sep->pdev->dev, page_array[count],
+ 0, PAGE_SIZE, /*dir*/DMA_BIDIRECTIONAL);
- /* 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]);
+ map_array[count].size = PAGE_SIZE;
+
+ /* fill the lli array entry */
+ lli_array[count].bus_address = (u32)map_array[count].dma_addr;
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);
+ dev_warn(&sep->pdev->dev,
+ "lli_array[%x].bus_address is %08x, \
+ lli_array[%x].block_size is %x\n",
+ count, lli_array[count].bus_address,
+ count, lli_array[count].block_size);
}
- /* if more then 1 pages locked - then update for the last page size needed */
+ /* check the offset for the first page -
+ data may start not at the beginning of the page */
+ lli_array[0].bus_address =
+ lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK));
+
+ /* 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));
+
+ dev_dbg(&sep->pdev->dev,
+ "lli_array[0].bus_address is %08x, \
+ lli_array[0].block_size is %x\n",
+ lli_array[count].bus_address,
+ lli_array[count].block_size);
+
+ /* check the size of the last page */
if (num_pages > 1) {
- /* update the address of the last page */
- lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]);
- /* set the size of the last page */
- lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK);
+ lli_array[num_pages - 1].block_size =
+ (app_virt_addr + data_size) & (~PAGE_MASK);
- 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);
+ dev_warn(&sep->pdev->dev,
+ "lli_array[%x].bus_address is %08x, \
+ lli_array[%x].block_size is %x\n",
+ num_pages - 1, lli_array[count].bus_address,
+ num_pages - 1,
+ lli_array[count].block_size);
+ }
+
+ /* set output params acording to the in_out flag */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages =
+ num_pages;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array =
+ page_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_array =
+ map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries =
+ num_pages;
+ } else {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages =
+ num_pages;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_page_array =
+ page_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_array =
+ map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries =
+ num_pages;
}
- /* 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]);
+end_function_with_error3:
+
+ /* free lli array */
kfree(lli_array);
+
+end_function_with_error2:
+
+ kfree(map_array);
+
end_function_with_error1:
+
+ /* free page array */
kfree(page_array);
+
end_function:
- dbg("SEP Driver:<-------- sep_lock_user_pages end\n");
- return 0;
-}
+ dev_dbg(&sep->pdev->dev,
+ "sep_lock_user_pages end\n");
+
+ return error;
+}
/*
this function calculates the size of data that can be inserted into the lli