diff options
Diffstat (limited to 'drivers/char/diag/diagmem.c')
| -rw-r--r-- | drivers/char/diag/diagmem.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c new file mode 100644 index 000000000000..3d9fceddb893 --- /dev/null +++ b/drivers/char/diag/diagmem.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2008-2014, 2016, The Linux Foundation. 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 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mempool.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/kmemleak.h> +#include <linux/ratelimit.h> +#include <asm/atomic.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/kmemleak.h> + +#include "diagchar.h" +#include "diagmem.h" + +struct diag_mempool_t diag_mempools[NUM_MEMORY_POOLS] = { + { + .id = POOL_TYPE_COPY, + .name = "POOL_COPY", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_HDLC, + .name = "POOL_HDLC", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_USER, + .name = "POOL_USER", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MUX_APPS, + .name = "POOL_MUX_APPS", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_DCI, + .name = "POOL_DCI", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, +#ifdef CONFIG_DIAGFWD_BRIDGE_CODE + { + .id = POOL_TYPE_MDM, + .name = "POOL_MDM", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM2, + .name = "POOL_MDM2", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM_DCI, + .name = "POOL_MDM_DCI", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM2_DCI, + .name = "POOL_MDM2_DCI", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM_MUX, + .name = "POOL_MDM_MUX", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM2_MUX, + .name = "POOL_MDM2_MUX", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM_DCI_WRITE, + .name = "POOL_MDM_DCI_WRITE", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_MDM2_DCI_WRITE, + .name = "POOL_MDM2_DCI_WRITE", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + }, + { + .id = POOL_TYPE_QSC_MUX, + .name = "POOL_QSC_MUX", + .pool = NULL, + .itemsize = 0, + .poolsize = 0, + .count = 0 + } +#endif +}; + +void diagmem_setsize(int pool_idx, int itemsize, int poolsize) +{ + if (pool_idx < 0 || pool_idx >= NUM_MEMORY_POOLS) { + pr_err("diag: Invalid pool index %d in %s\n", pool_idx, + __func__); + return; + } + + diag_mempools[pool_idx].itemsize = itemsize; + diag_mempools[pool_idx].poolsize = poolsize; + pr_debug("diag: Mempool %s sizes: itemsize %d poolsize %d\n", + diag_mempools[pool_idx].name, diag_mempools[pool_idx].itemsize, + diag_mempools[pool_idx].poolsize); +} + +void *diagmem_alloc(struct diagchar_dev *driver, int size, int pool_type) +{ + void *buf = NULL; + int i = 0; + unsigned long flags; + struct diag_mempool_t *mempool = NULL; + + if (!driver) + return NULL; + + for (i = 0; i < NUM_MEMORY_POOLS; i++) { + mempool = &diag_mempools[i]; + if (pool_type != mempool->id) + continue; + if (!mempool->pool) { + pr_err_ratelimited("diag: %s mempool is not initialized yet\n", + mempool->name); + break; + } + if (size == 0 || size > mempool->itemsize) { + pr_err_ratelimited("diag: cannot alloc from mempool %s, invalid size: %d\n", + mempool->name, size); + break; + } + spin_lock_irqsave(&mempool->lock, flags); + if (mempool->count < mempool->poolsize) { + atomic_add(1, (atomic_t *)&mempool->count); + buf = mempool_alloc(mempool->pool, GFP_ATOMIC); + kmemleak_not_leak(buf); + } + spin_unlock_irqrestore(&mempool->lock, flags); + if (!buf) { + pr_debug_ratelimited("diag: Unable to allocate buffer from memory pool %s, size: %d/%d count: %d/%d\n", + mempool->name, + size, mempool->itemsize, + mempool->count, + mempool->poolsize); + } + break; + } + + return buf; +} + +void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type) +{ + int i = 0; + unsigned long flags; + struct diag_mempool_t *mempool = NULL; + + if (!driver || !buf) + return; + + for (i = 0; i < NUM_MEMORY_POOLS; i++) { + mempool = &diag_mempools[i]; + if (pool_type != mempool->id) + continue; + if (!mempool->pool) { + pr_err_ratelimited("diag: %s mempool is not initialized yet\n", + mempool->name); + break; + } + spin_lock_irqsave(&mempool->lock, flags); + if (mempool->count > 0) { + mempool_free(buf, mempool->pool); + atomic_add(-1, (atomic_t *)&mempool->count); + } else { + pr_err_ratelimited("diag: Attempting to free items from %s mempool which is already empty\n", + mempool->name); + } + spin_unlock_irqrestore(&mempool->lock, flags); + break; + } +} + +void diagmem_init(struct diagchar_dev *driver, int index) +{ + struct diag_mempool_t *mempool = NULL; + if (!driver) + return; + + if (index < 0 || index >= NUM_MEMORY_POOLS) { + pr_err("diag: In %s, Invalid index %d\n", __func__, index); + return; + } + + mempool = &diag_mempools[index]; + if (mempool->pool) { + pr_debug("diag: mempool %s is already initialized\n", + mempool->name); + return; + } + if (mempool->itemsize <= 0 || mempool->poolsize <= 0) { + pr_err("diag: Unable to initialize %s mempool, itemsize: %d poolsize: %d\n", + mempool->name, mempool->itemsize, + mempool->poolsize); + return; + } + + mempool->pool = mempool_create_kmalloc_pool(mempool->poolsize, + mempool->itemsize); + if (!mempool->pool) + pr_err("diag: cannot allocate %s mempool\n", mempool->name); + else + kmemleak_not_leak(mempool->pool); + + spin_lock_init(&mempool->lock); +} + +void diagmem_exit(struct diagchar_dev *driver, int index) +{ + unsigned long flags; + struct diag_mempool_t *mempool = NULL; + + if (!driver) + return; + + if (index < 0 || index >= NUM_MEMORY_POOLS) { + pr_err("diag: In %s, Invalid index %d\n", __func__, index); + return; + } + + mempool = &diag_mempools[index]; + spin_lock_irqsave(&mempool->lock, flags); + if (mempool->count == 0 && mempool->pool != NULL) { + mempool_destroy(mempool->pool); + mempool->pool = NULL; + } else { + pr_err("diag: Unable to destory %s pool, count: %d\n", + mempool->name, mempool->count); + } + spin_unlock_irqrestore(&mempool->lock, flags); +} + |
