Input: sprd_eic_keys: remove event log
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / sipc / smem.c
1 /*
2  * Copyright (C) 2012 Spreadtrum Communications Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/genalloc.h>
17 #include <linux/mm.h>
18 #include <linux/debugfs.h>
19 #include <linux/seq_file.h>
20 #include <linux/slab.h>
21 #include <linux/list.h>
22 #include <linux/sched.h>
23
24 #include <linux/sipc.h>
25
26 struct smem_pool {
27         struct list_head        smem_head;
28         spinlock_t              lock;
29
30         uint32_t                addr;
31         uint32_t                size;
32         atomic_t                used;
33
34         struct gen_pool         *gen;
35 };
36
37 struct smem_record {
38         struct list_head smem_list;
39         struct task_struct *task;
40         uint32_t size;
41         uint32_t addr;
42 };
43
44 static struct smem_pool         mem_pool;
45
46 int smem_init(uint32_t addr, uint32_t size)
47 {
48         struct smem_pool *spool = &mem_pool;
49
50         spool->addr = addr;
51         spool->size = PAGE_ALIGN(size);
52         atomic_set(&spool->used, 0);
53         spin_lock_init(&spool->lock);
54         INIT_LIST_HEAD(&spool->smem_head);
55
56         /* allocator block size is times of pages */
57         spool->gen = gen_pool_create(PAGE_SHIFT, -1);
58         if (!spool->gen) {
59                 printk(KERN_ERR "Failed to create smem gen pool!\n");
60                 return -1;
61         }
62
63         if (gen_pool_add(spool->gen, spool->addr, spool->size, -1) != 0) {
64                 printk(KERN_ERR "Failed to add smem gen pool!\n");
65                 return -1;
66         }
67
68         return 0;
69 }
70
71 /* ****************************************************************** */
72
73 uint32_t smem_alloc(uint32_t size)
74 {
75         struct smem_pool *spool = &mem_pool;
76         struct smem_record *recd;
77         unsigned long flags;
78         uint32_t addr;
79
80         recd = kzalloc(sizeof(struct smem_record), GFP_KERNEL);
81         if (!recd) {
82                 printk(KERN_ERR "failed to alloc smem record\n");
83                 addr = 0;
84                 goto error;
85         }
86
87         size = PAGE_ALIGN(size);
88         addr = gen_pool_alloc(spool->gen, size);
89         if (!addr) {
90                 printk(KERN_ERR "failed to alloc smem from gen pool\n");
91                 kfree(recd);
92                 goto error;
93         }
94
95         /* record smem alloc info */
96         atomic_add(size, &spool->used);
97         recd->size = size;
98         recd->task = current;
99         recd->addr = addr;
100         spin_lock_irqsave(&spool->lock, flags);
101         list_add_tail(&recd->smem_list, &spool->smem_head);
102         spin_unlock_irqrestore(&spool->lock, flags);
103
104 error:
105         return addr;
106 }
107
108 void smem_free(uint32_t addr, uint32_t size)
109 {
110         struct smem_pool *spool = &mem_pool;
111         struct smem_record *recd, *next;
112         unsigned long flags;
113
114         size = PAGE_ALIGN(size);
115         atomic_sub(size, &spool->used);
116         gen_pool_free(spool->gen, addr, size);
117         /* delete record node from list */
118         spin_lock_irqsave(&spool->lock, flags);
119         list_for_each_entry_safe(recd, next, &spool->smem_head, smem_list) {
120                 if (recd->addr == addr) {
121                         list_del(&recd->smem_list);
122                         kfree(recd);
123                         break;
124                 }
125         }
126         spin_unlock_irqrestore(&spool->lock, flags);
127 }
128
129 #ifdef CONFIG_DEBUG_FS
130 static int smem_debug_show(struct seq_file *m, void *private)
131 {
132         struct smem_pool *spool = &mem_pool;
133         struct smem_record *recd;
134         uint32_t fsize;
135         unsigned long flags;
136
137         fsize = gen_pool_avail(spool->gen);
138
139         seq_printf(m, "smem pool infomation:\n");
140         seq_printf(m, "phys_addr=0x%x, total=0x%x, used=0x%x, free=0x%x\n",
141                 spool->addr, spool->size, spool->used, fsize);
142         seq_printf(m, "smem record list:\n");
143
144         spin_lock_irqsave(&spool->lock, flags);
145         list_for_each_entry(recd, &spool->smem_head, smem_list) {
146                 seq_printf(m, "task %s: pid=%u, addr=0x%x, size=0x%x\n",
147                         recd->task->comm, recd->task->pid, recd->addr, recd->size);
148         }
149         spin_unlock_irqrestore(&spool->lock, flags);
150         return 0;
151 }
152
153 static int smem_debug_open(struct inode *inode, struct file *file)
154 {
155         return single_open(file, smem_debug_show, inode->i_private);
156 }
157
158 static const struct file_operations smem_debug_fops = {
159         .open = smem_debug_open,
160         .read = seq_read,
161         .llseek = seq_lseek,
162         .release = single_release,
163 };
164
165 int smem_init_debugfs(void *root)
166 {
167         if (!root)
168                 return -ENXIO;
169         debugfs_create_file("smem", S_IRUGO, (struct dentry *)root, NULL, &smem_debug_fops);
170         return 0;
171 }
172
173 #endif //endof CONFIG_DEBUG_FS
174
175 EXPORT_SYMBOL(smem_alloc);
176 EXPORT_SYMBOL(smem_free);
177
178 MODULE_AUTHOR("Chen Gaopeng");
179 MODULE_DESCRIPTION("SIPC/SMEM driver");
180 MODULE_LICENSE("GPL");