📄 directpool.c
字号:
/*Copyright (C) 2003 Sigma Designs, Inc.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <linux/kernel.h>#include <linux/module.h>#include "directpool.h"#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/interrupt.h>#include <linux/mm.h>#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#include <asm/tango2/hardware.h>#include <asm/tango2/rmdefs.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#include <asm/tango2/rmdefs.h>#endif#include <asm/io.h>#ifndef XLAT_P2G // Subject to redefinition in kernel#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#if defined(CONFIG_TANGO2_USE_TLB_REMAP_DRAM1) || defined(CONFIG_TANGOX_USE_TLB_REMAP_DRAM1) // In Tango 2, we need to remap addresses greater than 0x20000000. For this, the kernel is currently // - subject to change - setting the TLB so that @ > 0x20000000 is remapped to 0x08000000.// Therefore for the kernel point of view GBUS address is equal to PHYSICAL address.#define XLAT_P2G(p) (p)#else// In Tango 2, we need to remap addresses greater than 0x20000000. For this, the kernel is currently // - subject to change - setting the remap register so that @ > 0x20000000 is remapped to 0x08000000// (128MB). Therefore @ becomes @ - 0x08000000 + 0x20000000" (== 0x18000000) when 0x08000000 < @ < 0x10000000.#define XLAT_P2G(p) ((((p) >= 0x08000000) && ((p) < 0x10000000)) ? (p) + 0x18000000 : (p)) #endif#else#define XLAT_P2G(p) (p)#endif#endif#if (EM86XX_CHIP < EM86XX_CHIPID_TANGO2)#define UNCACHED(p) ((unsigned long) ((p)&0x7FFFFFFF))#endif#else#include <asm/hardware.h>#endif#include <asm/irq.h>#include <asm/atomic.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#include <asm/softirq.h>#else#include <asm/pgtable.h>#endifstruct llad;#include "kernelcalls.h"#include "../../include/kdmapool.h"extern unsigned long max_dmapool_memory_size;extern unsigned long max_dmabuffer_log2_size;/* not static because shared with kllad.c */unsigned long kdmapool_usage_mask = 0;/* not static because shared with kllad.c */struct kdmapool bufferpools[MAXDMAPOOL];static struct kdmapool_address kdmapool_area[MAXAREABUFFERCOUNT];static unsigned long kdmapool_area_buffer_count;#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)static unsigned long kdmapool_mmap_mask = 0;#endif // EM86XX_CHIP#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#define MALLOC(x) (void *) kmalloc(x, GFP_KERNEL | __GFP_REPEAT)#else#define MALLOC(x) (void *) kmalloc(x, GFP_KERNEL)#endif#define FREE(x) kfree(x)#else#define MALLOC(x) vmalloc(x)#define FREE(x) vfree(x)#endif // EM86XX_CHIPstatic int kdmapool_alloc(struct kdmapool *pool){ int i, j, k; unsigned long buffersize = (1<<pool->log2_buffersize); // buffer_split is the number of buffers within 1 llad dma buffer int buffer_split = (1<<(max_dmabuffer_log2_size - pool->log2_buffersize)); for (i=0 , j=0 ; i<kdmapool_area_buffer_count ; i++) { if (j >= pool->buffercount) break; if (test_and_set_bit(0, &(kdmapool_area[i].used))) continue; for (k=0 ; ((k<buffer_split) && (j<pool->buffercount)) ; k++ , j++) { pool->buf_info[j].area_buffer_index = i; pool->buf_info[j].addr = (unsigned char *) kdmapool_area[i].addr + k*buffersize; // printk("buffer virt address : %p ", pool->buf_info[j].addr);#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) pool->buf_info[j].bus_addr = kdmapool_area[i].bus_addr + k*buffersize; // printk("bus address : 0x%08lx ", pool->buf_info[j].bus_addr);#endif // EM86XX_CHIP // printk("\n"); } } if (j<pool->buffercount) { for (k=0 ; k<j ; k += buffer_split) { i = pool->buf_info[k].area_buffer_index; clear_bit(0, &(kdmapool_area[i].used)); } return -ENOMEM; } return 0;}static void kdmapool_free(struct kdmapool *pool){ int i,j; int buffer_split = (1<<(max_dmabuffer_log2_size - pool->log2_buffersize)); for (j=0 ; j<pool->buffercount ; j += buffer_split) { i = pool->buf_info[j].area_buffer_index; clear_bit(0, &(kdmapool_area[i].used)); }}int kdmapool_init(struct llad *h){ int i; unsigned long buffersize = (1 << max_dmabuffer_log2_size); for (i=0 ; i<MAXDMAPOOL ; i++) { init_waitqueue_head(&(bufferpools[i].queue)); bufferpools[i].first_free = 0; } kdmapool_area_buffer_count = max_dmapool_memory_size / buffersize; if (kdmapool_area_buffer_count > MAXAREABUFFERCOUNT) { printk("mumpool_init: too many buffers to create this dmapool area (%lu > %d)\n", kdmapool_area_buffer_count, MAXAREABUFFERCOUNT); return -ENOMEM; } for (i=0 ; i<kdmapool_area_buffer_count ; i++) { clear_bit(0, &(kdmapool_area[i].used)); kdmapool_area[i].addr = MALLOC(buffersize); if (kdmapool_area[i].addr == NULL) { int j; for (j=0 ; j<i ; j++) { FREE(kdmapool_area[j].addr); } kdmapool_area_buffer_count = 0; printk("mumpool_init: cannot allocate dma buffers\n"); return -ENOMEM; }#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) kdmapool_area[i].bus_addr=XLAT_P2G(virt_to_phys(kdmapool_area[i].addr));#endif // EM86XX_CHIP }#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)/* Only applied for kernel 2.4.x */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) for (i=0 ; i<kdmapool_area_buffer_count ; i++) { struct page *pbeg, *pend, *page; pbeg = virt_to_page(kdmapool_area[i].addr); pend = virt_to_page((unsigned char *) kdmapool_area[i].addr + buffersize); for (page=pbeg;page<pend;page++) set_bit(PG_reserved, &((page)->flags)); }#endif#endif // EM86XX_CHIP return 0;}void kdmapool_deinit(struct llad *h){ int i; for (i=0 ; i<kdmapool_area_buffer_count ; i++) { if (test_and_clear_bit(0, &(kdmapool_area[i].used))) printk("kdmapool_deinit: an area buffer has not been released\n"); FREE(kdmapool_area[i].addr); } kdmapool_area_buffer_count = 0;}EXPORT_SYMBOL(kdmapool_check_valid);long kdmapool_check_valid(struct llad *h, unsigned long dmapool_id){ if (!test_bit(dmapool_id, &(kdmapool_usage_mask))) { printk("dmapool index %lu is not opened\n", dmapool_id); return -EINVAL; } #if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) if (!test_bit(dmapool_id, &kdmapool_mmap_mask)) { printk("dmapool index %lu is not mmaped\n", dmapool_id); return -EINVAL; }#endif // EM86XX_CHIP return 0;}EXPORT_SYMBOL(kdmapool_check_opened);long kdmapool_check_opened(struct llad *h, unsigned long dmapool_id){ if (!test_bit(dmapool_id, &(kdmapool_usage_mask))) { printk("dmapool index %lu is not opened\n", dmapool_id); return -EINVAL; } return 0;}EXPORT_SYMBOL(kdmapool_open);int kdmapool_open(struct llad *h, void *area, unsigned long buffercount, unsigned long log2_buffersize){ int dmapool_id; struct kdmapool *pool; unsigned long buffersize = (1 << log2_buffersize); int i;#ifdef _DEBUG printk("Opening DMAPOOL %lu %lu\n", buffercount, log2_buffersize);#endif if (log2_buffersize > max_dmabuffer_log2_size) { printk("kdmapool_open: buffersize too big, (%lu > %lu)\n", log2_buffersize, max_dmabuffer_log2_size); return -EINVAL; } if (log2_buffersize < PAGE_SHIFT) { printk("kdmapool_open: buffersize too small, (%u > %lu)\n", PAGE_SHIFT, log2_buffersize); return -EINVAL; } /* looks for a free entry */ for (dmapool_id=0 ; dmapool_id<MAXDMAPOOL ; dmapool_id++) { if (!test_and_set_bit(dmapool_id, &(kdmapool_usage_mask))) break; } if (dmapool_id == MAXDMAPOOL) { printk("Cannot find any free space for a new pool\n"); return -EINVAL; } pool = &(bufferpools[dmapool_id]); pool->buf_info = (struct buffer_info *) vmalloc(sizeof(struct buffer_info) * buffercount); if (pool->buf_info == NULL) { printk("Cannot allocate ref_count array (%lu entries)\n", buffercount); return -EINVAL; } pool->buffercount = buffercount; pool->buffersize = buffersize; pool->log2_buffersize = log2_buffersize; pool->area = (unsigned char *) area;#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) pool->user_addr = NULL;#endif if (area == NULL) { if (kdmapool_alloc(pool)) { pool->buffercount = 0; pool->buffersize = 0; vfree(pool->buf_info); printk("Cannot allocate dma buffers\n"); clear_bit(dmapool_id, &(kdmapool_usage_mask)); return -ENOMEM; } } else { for (i=0 ; i<buffercount ; i++) { pool->buf_info[i].addr = phys_to_virt((unsigned long) area + i*buffersize); //printk("buffer virt address : %p ", pool->buf_info[i].addr);#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) pool->buf_info[i].bus_addr = XLAT_P2G(virt_to_phys(pool->buf_info[i].addr)); //printk("bus address : 0x%08lx ", pool->buf_info[i].bus_addr);#endif // EM86XX_CHIP //printk("\n"); } } spin_lock_init(&(pool->lock)); atomic_set(&(pool->available_buffer_count), pool->buffercount); kdmapool_reset(h, dmapool_id); return dmapool_id;}EXPORT_SYMBOL(kdmapool_close);int kdmapool_close(struct llad *h, unsigned long dmapool_id){ struct kdmapool *pool; if (!test_bit(dmapool_id, &(kdmapool_usage_mask))) { printk("dmapool index %lu is not opened\n", dmapool_id); return -EINVAL; } pool = &(bufferpools[dmapool_id]); if (pool->area == NULL) { kdmapool_free(pool); } vfree(pool->buf_info);#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -