blob: 0b5c27a5c12f79e5db4f478aab9142916429d25c [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/mempool.h>
17#include <linux/mutex.h>
18#include <asm/atomic.h>
19#include "diagchar.h"
20
21void *diagmem_alloc(struct diagchar_dev *driver, int size, int pool_type)
22{
23 void *buf = NULL;
24
25 if (pool_type == POOL_TYPE_COPY) {
26 if (driver->diagpool) {
27 mutex_lock(&driver->diagmem_mutex);
28 if (driver->count < driver->poolsize) {
29 atomic_add(1, (atomic_t *)&driver->count);
30 buf = mempool_alloc(driver->diagpool,
31 GFP_ATOMIC);
32 }
33 mutex_unlock(&driver->diagmem_mutex);
34 }
35 } else if (pool_type == POOL_TYPE_HDLC) {
36 if (driver->diag_hdlc_pool) {
37 if (driver->count_hdlc_pool < driver->poolsize_hdlc) {
38 atomic_add(1,
39 (atomic_t *)&driver->count_hdlc_pool);
40 buf = mempool_alloc(driver->diag_hdlc_pool,
41 GFP_ATOMIC);
42 }
43 }
44 } else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
45 if (driver->diag_write_struct_pool) {
46 if (driver->count_write_struct_pool <
47 driver->poolsize_write_struct) {
48 atomic_add(1,
49 (atomic_t *)&driver->count_write_struct_pool);
50 buf = mempool_alloc(
51 driver->diag_write_struct_pool, GFP_ATOMIC);
52 }
53 }
54 }
55 return buf;
56}
57
58void diagmem_exit(struct diagchar_dev *driver, int pool_type)
59{
60 if (driver->diagpool) {
61 if (driver->count == 0 && driver->ref_count == 0) {
62 mempool_destroy(driver->diagpool);
63 driver->diagpool = NULL;
64 } else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
65 printk(KERN_ALERT "Unable to destroy COPY mempool");
66 }
67
68 if (driver->diag_hdlc_pool) {
69 if (driver->count_hdlc_pool == 0 && driver->ref_count == 0) {
70 mempool_destroy(driver->diag_hdlc_pool);
71 driver->diag_hdlc_pool = NULL;
72 } else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
73 printk(KERN_ALERT "Unable to destroy HDLC mempool");
74 }
75
76 if (driver->diag_write_struct_pool) {
77 /* Free up struct pool ONLY if there are no outstanding
78 transactions(aggregation buffer) with USB */
79 if (driver->count_write_struct_pool == 0 &&
80 driver->count_hdlc_pool == 0 && driver->ref_count == 0) {
81 mempool_destroy(driver->diag_write_struct_pool);
82 driver->diag_write_struct_pool = NULL;
83 } else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
84 printk(KERN_ALERT "Unable to destroy STRUCT mempool");
85 }
86}
87
88void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
89{
90 if (pool_type == POOL_TYPE_COPY) {
91 if (driver->diagpool != NULL && driver->count > 0) {
92 mempool_free(buf, driver->diagpool);
93 atomic_add(-1, (atomic_t *)&driver->count);
94 } else
95 pr_err("diag: Attempt to free up DIAG driver "
96 "mempool memory which is already free %d", driver->count);
97 } else if (pool_type == POOL_TYPE_HDLC) {
98 if (driver->diag_hdlc_pool != NULL &&
99 driver->count_hdlc_pool > 0) {
100 mempool_free(buf, driver->diag_hdlc_pool);
101 atomic_add(-1, (atomic_t *)&driver->count_hdlc_pool);
102 } else
103 pr_err("diag: Attempt to free up DIAG driver "
104 "HDLC mempool which is already free %d ", driver->count_hdlc_pool);
105 } else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
106 if (driver->diag_write_struct_pool != NULL &&
107 driver->count_write_struct_pool > 0) {
108 mempool_free(buf, driver->diag_write_struct_pool);
109 atomic_add(-1,
110 (atomic_t *)&driver->count_write_struct_pool);
111 } else
112 pr_err("diag: Attempt to free up DIAG driver "
113 "USB structure mempool which is already free %d ",
114 driver->count_write_struct_pool);
115 }
116
117 diagmem_exit(driver, pool_type);
118}
119
120void diagmem_init(struct diagchar_dev *driver)
121{
122 mutex_init(&driver->diagmem_mutex);
123
124 if (driver->count == 0)
125 driver->diagpool = mempool_create_kmalloc_pool(
126 driver->poolsize, driver->itemsize);
127
128 if (driver->count_hdlc_pool == 0)
129 driver->diag_hdlc_pool = mempool_create_kmalloc_pool(
130 driver->poolsize_hdlc, driver->itemsize_hdlc);
131
132 if (driver->count_write_struct_pool == 0)
133 driver->diag_write_struct_pool = mempool_create_kmalloc_pool(
134 driver->poolsize_write_struct, driver->itemsize_write_struct);
135
136 if (!driver->diagpool)
137 printk(KERN_INFO "Cannot allocate diag mempool\n");
138
139 if (!driver->diag_hdlc_pool)
140 printk(KERN_INFO "Cannot allocate diag HDLC mempool\n");
141
142 if (!driver->diag_write_struct_pool)
143 printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
144}
145