| /* |
| * Copyright (C) 2018 Synaptics Incorporated. 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 version 2 as |
| * published by the Free Software Foundation. |
| * |
| * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND |
| * SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, |
| * INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY |
| * INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR |
| * CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE |
| * OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND |
| * BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF |
| * COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT |
| * DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY |
| * TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS. |
| */ |
| #include "diag_common.h" |
| |
| extern void *malloc(size_t size); |
| |
| #define LOCK(irq_save, fiq_save, lock) { irq_save = DisableIRQ(); fiq_save = DisableFIQ(); spin_lock(lock);} |
| #define UNLOCK(irq_save, fiq_save, lock) { spin_unlock(lock); RestoreFIQ(fiq_save); RestoreIRQ(irq_save);} |
| |
| typedef struct |
| { |
| unsigned int start; |
| unsigned int size; |
| unsigned int block_size; |
| unsigned int block_count; |
| unsigned char* map; |
| unsigned int mutex; |
| } mem_buffer_manager_t; |
| static mem_buffer_manager_t mem_buffer_manager; |
| |
| int diag_buffpool_init(unsigned int start, int size, int block_size) |
| { |
| mem_buffer_manager.start = start; |
| mem_buffer_manager.size = size; |
| mem_buffer_manager.block_size = block_size; |
| mem_buffer_manager.block_count = size/block_size; |
| mem_buffer_manager.map = (unsigned char*)malloc(ALIGN(mem_buffer_manager.block_count, 4)); |
| DIAG_ASSERT(mem_buffer_manager.map != 0); |
| memset(mem_buffer_manager.map, 0, mem_buffer_manager.block_count); |
| spin_lock_init((int*)(&mem_buffer_manager.mutex)); |
| dbg_printf(PRN_INFO, "diag_buffer_pool start:0x%08x, size:0x%08x, block size:0x%x, map addr:0x%08x\n", |
| start, size, block_size, mem_buffer_manager.map); |
| return 0; |
| } |
| |
| unsigned int diag_buffpool_alloc(int size, unsigned char tag) |
| { |
| unsigned int irq_save; |
| unsigned int fiq_save; |
| unsigned char* p = mem_buffer_manager.map; |
| unsigned char* p_end = p + mem_buffer_manager.block_count; |
| int blocks_req = (size + mem_buffer_manager.block_size - 1)/mem_buffer_manager.block_size; |
| int continue_free_count = 0; |
| int addr; |
| LOCK(irq_save, fiq_save, (int*)(&mem_buffer_manager.mutex)); |
| while(p < p_end) |
| { |
| if (*p == 0) |
| { |
| continue_free_count++; |
| if (continue_free_count >= blocks_req) |
| { |
| break; |
| } |
| } |
| else |
| { |
| continue_free_count = 0; |
| } |
| p++; |
| } |
| if (continue_free_count >= blocks_req) |
| { |
| while(continue_free_count-- > 1) |
| { |
| *p-- = tag; |
| } |
| *p = tag | 0x80; // start flag |
| addr = mem_buffer_manager.start + (p-mem_buffer_manager.map)*mem_buffer_manager.block_size; |
| } |
| else |
| { |
| addr = 0; // no buffer |
| } |
| UNLOCK(irq_save, fiq_save, (int*)(&mem_buffer_manager.mutex)); |
| if (addr == 0) |
| { |
| dbg_printf(PRN_RES, "diag_buffer_pool out of memory\n"); |
| } |
| return addr; |
| } |
| |
| unsigned int diag_buffpool_free(unsigned int addr, unsigned char tag) |
| { |
| unsigned int irq_save; |
| unsigned int fiq_save; |
| unsigned char* p; |
| unsigned char* p_end = mem_buffer_manager.map + mem_buffer_manager.block_count; |
| int count = 0; |
| if (0 != (addr & (mem_buffer_manager.block_size-1))) |
| { |
| dbg_printf(PRN_RES, " address wrong, addr:0x%08x\n", addr); |
| return -1; |
| } |
| // check |
| p = mem_buffer_manager.map + (addr - mem_buffer_manager.start)/mem_buffer_manager.block_size; |
| if (*p != (tag|0x80)) |
| { |
| dbg_printf(PRN_RES, " tag wrong, tag:0x%02x, expect:0x%02x\n", *p, (tag|0x80)); |
| return -1; |
| } |
| *p++ = 0; |
| count++; |
| LOCK(irq_save, fiq_save, (int*)(&mem_buffer_manager.mutex)); |
| while(*p == tag && p < p_end) |
| { |
| *p = 0; |
| p++; |
| count++; |
| } |
| UNLOCK(irq_save, fiq_save, (int*)(&mem_buffer_manager.mutex)); |
| return 0; |
| } |
| |