linux/arch/powerpc/sysdev/bestcomm/sram.c
<<
>>
Prefs
   1/*
   2 * Simple memory allocator for on-board SRAM
   3 *
   4 *
   5 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
   6 *
   7 * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public License
  10 * version 2. This program is licensed "as is" without any warranty of any
  11 * kind, whether express or implied.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/spinlock.h>
  18#include <linux/string.h>
  19#include <linux/ioport.h>
  20#include <linux/of.h>
  21
  22#include <asm/io.h>
  23#include <asm/mmu.h>
  24
  25#include "sram.h"
  26
  27
  28/* Struct keeping our 'state' */
  29struct bcom_sram *bcom_sram = NULL;
  30EXPORT_SYMBOL_GPL(bcom_sram);   /* needed for inline functions */
  31
  32
  33/* ======================================================================== */
  34/* Public API                                                               */
  35/* ======================================================================== */
  36/* DO NOT USE in interrupts, if needed in irq handler, we should use the
  37   _irqsave version of the spin_locks */
  38
  39int bcom_sram_init(struct device_node *sram_node, char *owner)
  40{
  41        int rv;
  42        const u32 *regaddr_p;
  43        u64 regaddr64, size64;
  44        unsigned int psize;
  45
  46        /* Create our state struct */
  47        if (bcom_sram) {
  48                printk(KERN_ERR "%s: bcom_sram_init: "
  49                        "Already initialized !\n", owner);
  50                return -EBUSY;
  51        }
  52
  53        bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
  54        if (!bcom_sram) {
  55                printk(KERN_ERR "%s: bcom_sram_init: "
  56                        "Couldn't allocate internal state !\n", owner);
  57                return -ENOMEM;
  58        }
  59
  60        /* Get address and size of the sram */
  61        regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
  62        if (!regaddr_p) {
  63                printk(KERN_ERR "%s: bcom_sram_init: "
  64                        "Invalid device node !\n", owner);
  65                rv = -EINVAL;
  66                goto error_free;
  67        }
  68
  69        regaddr64 = of_translate_address(sram_node, regaddr_p);
  70
  71        bcom_sram->base_phys = (phys_addr_t) regaddr64;
  72        bcom_sram->size = (unsigned int) size64;
  73
  74        /* Request region */
  75        if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
  76                printk(KERN_ERR "%s: bcom_sram_init: "
  77                        "Couldn't request region !\n", owner);
  78                rv = -EBUSY;
  79                goto error_free;
  80        }
  81
  82        /* Map SRAM */
  83                /* sram is not really __iomem */
  84        bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
  85
  86        if (!bcom_sram->base_virt) {
  87                printk(KERN_ERR "%s: bcom_sram_init: "
  88                        "Map error SRAM zone 0x%08lx (0x%0x)!\n",
  89                        owner, (long)bcom_sram->base_phys, bcom_sram->size );
  90                rv = -ENOMEM;
  91                goto error_release;
  92        }
  93
  94        /* Create an rheap (defaults to 32 bits word alignment) */
  95        bcom_sram->rh = rh_create(4);
  96
  97        /* Attach the free zones */
  98#if 0
  99        /* Currently disabled ... for future use only */
 100        reg_addr_p = of_get_property(sram_node, "available", &psize);
 101#else
 102        regaddr_p = NULL;
 103        psize = 0;
 104#endif
 105
 106        if (!regaddr_p || !psize) {
 107                /* Attach the whole zone */
 108                rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
 109        } else {
 110                /* Attach each zone independently */
 111                while (psize >= 2 * sizeof(u32)) {
 112                        phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
 113                        rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
 114                        regaddr_p += 2;
 115                        psize -= 2 * sizeof(u32);
 116                }
 117        }
 118
 119        /* Init our spinlock */
 120        spin_lock_init(&bcom_sram->lock);
 121
 122        return 0;
 123
 124error_release:
 125        release_mem_region(bcom_sram->base_phys, bcom_sram->size);
 126error_free:
 127        kfree(bcom_sram);
 128        bcom_sram = NULL;
 129
 130        return rv;
 131}
 132EXPORT_SYMBOL_GPL(bcom_sram_init);
 133
 134void bcom_sram_cleanup(void)
 135{
 136        /* Free resources */
 137        if (bcom_sram) {
 138                rh_destroy(bcom_sram->rh);
 139                iounmap((void __iomem *)bcom_sram->base_virt);
 140                release_mem_region(bcom_sram->base_phys, bcom_sram->size);
 141                kfree(bcom_sram);
 142                bcom_sram = NULL;
 143        }
 144}
 145EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
 146
 147void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
 148{
 149        unsigned long offset;
 150
 151        spin_lock(&bcom_sram->lock);
 152        offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
 153        spin_unlock(&bcom_sram->lock);
 154
 155        if (IS_ERR_VALUE(offset))
 156                return NULL;
 157
 158        *phys = bcom_sram->base_phys + offset;
 159        return bcom_sram->base_virt + offset;
 160}
 161EXPORT_SYMBOL_GPL(bcom_sram_alloc);
 162
 163void bcom_sram_free(void *ptr)
 164{
 165        unsigned long offset;
 166
 167        if (!ptr)
 168                return;
 169
 170        offset = ptr - bcom_sram->base_virt;
 171
 172        spin_lock(&bcom_sram->lock);
 173        rh_free(bcom_sram->rh, offset);
 174        spin_unlock(&bcom_sram->lock);
 175}
 176EXPORT_SYMBOL_GPL(bcom_sram_free);
 177
 178