Version:  2.0.40 2.2.26 2.4.37 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4

Linux/drivers/misc/sram.c

  1 /*
  2  * Generic on-chip SRAM allocation driver
  3  *
  4  * Copyright (C) 2012 Philipp Zabel, Pengutronix
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License
  8  * as published by the Free Software Foundation; either version 2
  9  * of the License, or (at your option) any later version.
 10  * This program is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  * GNU General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU General Public License
 16  * along with this program; if not, write to the Free Software
 17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 18  * MA 02110-1301, USA.
 19  */
 20 
 21 #include <linux/clk.h>
 22 #include <linux/genalloc.h>
 23 #include <linux/io.h>
 24 #include <linux/list_sort.h>
 25 #include <linux/of_address.h>
 26 #include <linux/platform_device.h>
 27 #include <linux/slab.h>
 28 
 29 #define SRAM_GRANULARITY        32
 30 
 31 struct sram_partition {
 32         void __iomem *base;
 33 
 34         struct gen_pool *pool;
 35         struct bin_attribute battr;
 36         struct mutex lock;
 37 };
 38 
 39 struct sram_dev {
 40         struct device *dev;
 41         void __iomem *virt_base;
 42 
 43         struct gen_pool *pool;
 44         struct clk *clk;
 45 
 46         struct sram_partition *partition;
 47         u32 partitions;
 48 };
 49 
 50 struct sram_reserve {
 51         struct list_head list;
 52         u32 start;
 53         u32 size;
 54         bool export;
 55         bool pool;
 56         const char *label;
 57 };
 58 
 59 static ssize_t sram_read(struct file *filp, struct kobject *kobj,
 60                          struct bin_attribute *attr,
 61                          char *buf, loff_t pos, size_t count)
 62 {
 63         struct sram_partition *part;
 64 
 65         part = container_of(attr, struct sram_partition, battr);
 66 
 67         mutex_lock(&part->lock);
 68         memcpy_fromio(buf, part->base + pos, count);
 69         mutex_unlock(&part->lock);
 70 
 71         return count;
 72 }
 73 
 74 static ssize_t sram_write(struct file *filp, struct kobject *kobj,
 75                           struct bin_attribute *attr,
 76                           char *buf, loff_t pos, size_t count)
 77 {
 78         struct sram_partition *part;
 79 
 80         part = container_of(attr, struct sram_partition, battr);
 81 
 82         mutex_lock(&part->lock);
 83         memcpy_toio(part->base + pos, buf, count);
 84         mutex_unlock(&part->lock);
 85 
 86         return count;
 87 }
 88 
 89 static int sram_add_pool(struct sram_dev *sram, struct sram_reserve *block,
 90                          phys_addr_t start, struct sram_partition *part)
 91 {
 92         int ret;
 93 
 94         part->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
 95                                           NUMA_NO_NODE, block->label);
 96         if (IS_ERR(part->pool))
 97                 return PTR_ERR(part->pool);
 98 
 99         ret = gen_pool_add_virt(part->pool, (unsigned long)part->base, start,
100                                 block->size, NUMA_NO_NODE);
101         if (ret < 0) {
102                 dev_err(sram->dev, "failed to register subpool: %d\n", ret);
103                 return ret;
104         }
105 
106         return 0;
107 }
108 
109 static int sram_add_export(struct sram_dev *sram, struct sram_reserve *block,
110                            phys_addr_t start, struct sram_partition *part)
111 {
112         sysfs_bin_attr_init(&part->battr);
113         part->battr.attr.name = devm_kasprintf(sram->dev, GFP_KERNEL,
114                                                "%llx.sram",
115                                                (unsigned long long)start);
116         if (!part->battr.attr.name)
117                 return -ENOMEM;
118 
119         part->battr.attr.mode = S_IRUSR | S_IWUSR;
120         part->battr.read = sram_read;
121         part->battr.write = sram_write;
122         part->battr.size = block->size;
123 
124         return device_create_bin_file(sram->dev, &part->battr);
125 }
126 
127 static int sram_add_partition(struct sram_dev *sram, struct sram_reserve *block,
128                               phys_addr_t start)
129 {
130         int ret;
131         struct sram_partition *part = &sram->partition[sram->partitions];
132 
133         mutex_init(&part->lock);
134         part->base = sram->virt_base + block->start;
135 
136         if (block->pool) {
137                 ret = sram_add_pool(sram, block, start, part);
138                 if (ret)
139                         return ret;
140         }
141         if (block->export) {
142                 ret = sram_add_export(sram, block, start, part);
143                 if (ret)
144                         return ret;
145         }
146         sram->partitions++;
147 
148         return 0;
149 }
150 
151 static void sram_free_partitions(struct sram_dev *sram)
152 {
153         struct sram_partition *part;
154 
155         if (!sram->partitions)
156                 return;
157 
158         part = &sram->partition[sram->partitions - 1];
159         for (; sram->partitions; sram->partitions--, part--) {
160                 if (part->battr.size)
161                         device_remove_bin_file(sram->dev, &part->battr);
162 
163                 if (part->pool &&
164                     gen_pool_avail(part->pool) < gen_pool_size(part->pool))
165                         dev_err(sram->dev, "removed pool while SRAM allocated\n");
166         }
167 }
168 
169 static int sram_reserve_cmp(void *priv, struct list_head *a,
170                                         struct list_head *b)
171 {
172         struct sram_reserve *ra = list_entry(a, struct sram_reserve, list);
173         struct sram_reserve *rb = list_entry(b, struct sram_reserve, list);
174 
175         return ra->start - rb->start;
176 }
177 
178 static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
179 {
180         struct device_node *np = sram->dev->of_node, *child;
181         unsigned long size, cur_start, cur_size;
182         struct sram_reserve *rblocks, *block;
183         struct list_head reserve_list;
184         unsigned int nblocks, exports = 0;
185         const char *label;
186         int ret = 0;
187 
188         INIT_LIST_HEAD(&reserve_list);
189 
190         size = resource_size(res);
191 
192         /*
193          * We need an additional block to mark the end of the memory region
194          * after the reserved blocks from the dt are processed.
195          */
196         nblocks = (np) ? of_get_available_child_count(np) + 1 : 1;
197         rblocks = kzalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL);
198         if (!rblocks)
199                 return -ENOMEM;
200 
201         block = &rblocks[0];
202         for_each_available_child_of_node(np, child) {
203                 struct resource child_res;
204 
205                 ret = of_address_to_resource(child, 0, &child_res);
206                 if (ret < 0) {
207                         dev_err(sram->dev,
208                                 "could not get address for node %s\n",
209                                 child->full_name);
210                         goto err_chunks;
211                 }
212 
213                 if (child_res.start < res->start || child_res.end > res->end) {
214                         dev_err(sram->dev,
215                                 "reserved block %s outside the sram area\n",
216                                 child->full_name);
217                         ret = -EINVAL;
218                         goto err_chunks;
219                 }
220 
221                 block->start = child_res.start - res->start;
222                 block->size = resource_size(&child_res);
223                 list_add_tail(&block->list, &reserve_list);
224 
225                 if (of_find_property(child, "export", NULL))
226                         block->export = true;
227 
228                 if (of_find_property(child, "pool", NULL))
229                         block->pool = true;
230 
231                 if ((block->export || block->pool) && block->size) {
232                         exports++;
233 
234                         label = NULL;
235                         ret = of_property_read_string(child, "label", &label);
236                         if (ret && ret != -EINVAL) {
237                                 dev_err(sram->dev,
238                                         "%s has invalid label name\n",
239                                         child->full_name);
240                                 goto err_chunks;
241                         }
242                         if (!label)
243                                 label = child->name;
244 
245                         block->label = devm_kstrdup(sram->dev,
246                                                     label, GFP_KERNEL);
247                         if (!block->label)
248                                 goto err_chunks;
249 
250                         dev_dbg(sram->dev, "found %sblock '%s' 0x%x-0x%x\n",
251                                 block->export ? "exported " : "", block->label,
252                                 block->start, block->start + block->size);
253                 } else {
254                         dev_dbg(sram->dev, "found reserved block 0x%x-0x%x\n",
255                                 block->start, block->start + block->size);
256                 }
257 
258                 block++;
259         }
260         child = NULL;
261 
262         /* the last chunk marks the end of the region */
263         rblocks[nblocks - 1].start = size;
264         rblocks[nblocks - 1].size = 0;
265         list_add_tail(&rblocks[nblocks - 1].list, &reserve_list);
266 
267         list_sort(NULL, &reserve_list, sram_reserve_cmp);
268 
269         if (exports) {
270                 sram->partition = devm_kzalloc(sram->dev,
271                                        exports * sizeof(*sram->partition),
272                                        GFP_KERNEL);
273                 if (!sram->partition) {
274                         ret = -ENOMEM;
275                         goto err_chunks;
276                 }
277         }
278 
279         cur_start = 0;
280         list_for_each_entry(block, &reserve_list, list) {
281                 /* can only happen if sections overlap */
282                 if (block->start < cur_start) {
283                         dev_err(sram->dev,
284                                 "block at 0x%x starts after current offset 0x%lx\n",
285                                 block->start, cur_start);
286                         ret = -EINVAL;
287                         sram_free_partitions(sram);
288                         goto err_chunks;
289                 }
290 
291                 if ((block->export || block->pool) && block->size) {
292                         ret = sram_add_partition(sram, block,
293                                                  res->start + block->start);
294                         if (ret) {
295                                 sram_free_partitions(sram);
296                                 goto err_chunks;
297                         }
298                 }
299 
300                 /* current start is in a reserved block, so continue after it */
301                 if (block->start == cur_start) {
302                         cur_start = block->start + block->size;
303                         continue;
304                 }
305 
306                 /*
307                  * allocate the space between the current starting
308                  * address and the following reserved block, or the
309                  * end of the region.
310                  */
311                 cur_size = block->start - cur_start;
312 
313                 dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n",
314                         cur_start, cur_start + cur_size);
315 
316                 ret = gen_pool_add_virt(sram->pool,
317                                 (unsigned long)sram->virt_base + cur_start,
318                                 res->start + cur_start, cur_size, -1);
319                 if (ret < 0) {
320                         sram_free_partitions(sram);
321                         goto err_chunks;
322                 }
323 
324                 /* next allocation after this reserved block */
325                 cur_start = block->start + block->size;
326         }
327 
328  err_chunks:
329         if (child)
330                 of_node_put(child);
331 
332         kfree(rblocks);
333 
334         return ret;
335 }
336 
337 static int sram_probe(struct platform_device *pdev)
338 {
339         struct sram_dev *sram;
340         struct resource *res;
341         size_t size;
342         int ret;
343 
344         sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
345         if (!sram)
346                 return -ENOMEM;
347 
348         sram->dev = &pdev->dev;
349 
350         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
351         if (!res) {
352                 dev_err(sram->dev, "found no memory resource\n");
353                 return -EINVAL;
354         }
355 
356         size = resource_size(res);
357 
358         if (!devm_request_mem_region(sram->dev, res->start, size, pdev->name)) {
359                 dev_err(sram->dev, "could not request region for resource\n");
360                 return -EBUSY;
361         }
362 
363         sram->virt_base = devm_ioremap_wc(sram->dev, res->start, size);
364         if (IS_ERR(sram->virt_base))
365                 return PTR_ERR(sram->virt_base);
366 
367         sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
368                                           NUMA_NO_NODE, NULL);
369         if (IS_ERR(sram->pool))
370                 return PTR_ERR(sram->pool);
371 
372         ret = sram_reserve_regions(sram, res);
373         if (ret)
374                 return ret;
375 
376         sram->clk = devm_clk_get(sram->dev, NULL);
377         if (IS_ERR(sram->clk))
378                 sram->clk = NULL;
379         else
380                 clk_prepare_enable(sram->clk);
381 
382         platform_set_drvdata(pdev, sram);
383 
384         dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n",
385                 gen_pool_size(sram->pool) / 1024, sram->virt_base);
386 
387         return 0;
388 }
389 
390 static int sram_remove(struct platform_device *pdev)
391 {
392         struct sram_dev *sram = platform_get_drvdata(pdev);
393 
394         sram_free_partitions(sram);
395 
396         if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
397                 dev_err(sram->dev, "removed while SRAM allocated\n");
398 
399         if (sram->clk)
400                 clk_disable_unprepare(sram->clk);
401 
402         return 0;
403 }
404 
405 #ifdef CONFIG_OF
406 static const struct of_device_id sram_dt_ids[] = {
407         { .compatible = "mmio-sram" },
408         {}
409 };
410 #endif
411 
412 static struct platform_driver sram_driver = {
413         .driver = {
414                 .name = "sram",
415                 .of_match_table = of_match_ptr(sram_dt_ids),
416         },
417         .probe = sram_probe,
418         .remove = sram_remove,
419 };
420 
421 static int __init sram_init(void)
422 {
423         return platform_driver_register(&sram_driver);
424 }
425 
426 postcore_initcall(sram_init);
427 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us