]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/powerpc/sysdev/fsl_85xx_cache_sram.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / arch / powerpc / sysdev / fsl_85xx_cache_sram.c
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
new file mode 100644 (file)
index 0000000..54fb192
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <asm/pgtable.h>
+#include <asm/fsl_85xx_cache_sram.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+struct mpc85xx_cache_sram *cache_sram;
+
+void *mpc85xx_cache_sram_alloc(unsigned int size,
+                               phys_addr_t *phys, unsigned int align)
+{
+       unsigned long offset;
+       unsigned long flags;
+
+       if (unlikely(cache_sram == NULL))
+               return NULL;
+
+       if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
+               pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
+                       __func__, size, align);
+               return NULL;
+       }
+
+       if ((align & (align - 1)) || align <= 1) {
+               pr_err("%s(): align(=%x) must be power of two and >1\n",
+                       __func__, align);
+               return NULL;
+       }
+
+       spin_lock_irqsave(&cache_sram->lock, flags);
+       offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
+       spin_unlock_irqrestore(&cache_sram->lock, flags);
+
+       if (IS_ERR_VALUE(offset))
+               return NULL;
+
+       *phys = cache_sram->base_phys + offset;
+
+       return (unsigned char *)cache_sram->base_virt + offset;
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
+
+void mpc85xx_cache_sram_free(void *ptr)
+{
+       unsigned long flags;
+       BUG_ON(!ptr);
+
+       spin_lock_irqsave(&cache_sram->lock, flags);
+       rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
+       spin_unlock_irqrestore(&cache_sram->lock, flags);
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_free);
+
+int __init instantiate_cache_sram(struct platform_device *dev,
+               struct sram_parameters sram_params)
+{
+       int ret = 0;
+
+       if (cache_sram) {
+               dev_err(&dev->dev, "Already initialized cache-sram\n");
+               return -EBUSY;
+       }
+
+       cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
+       if (!cache_sram) {
+               dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
+               return -ENOMEM;
+       }
+
+       cache_sram->base_phys = sram_params.sram_offset;
+       cache_sram->size = sram_params.sram_size;
+
+       if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+                                               "fsl_85xx_cache_sram")) {
+               dev_err(&dev->dev, "%s: request memory failed\n",
+                               dev->dev.of_node->full_name);
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+                               cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
+       if (!cache_sram->base_virt) {
+               dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+                               dev->dev.of_node->full_name);
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       cache_sram->rh = rh_create(sizeof(unsigned int));
+       if (IS_ERR(cache_sram->rh)) {
+               dev_err(&dev->dev, "%s: Unable to create remote heap\n",
+                               dev->dev.of_node->full_name);
+               ret = PTR_ERR(cache_sram->rh);
+               goto out_unmap;
+       }
+
+       rh_attach_region(cache_sram->rh, 0, cache_sram->size);
+       spin_lock_init(&cache_sram->lock);
+
+       dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
+               (unsigned long long)cache_sram->base_phys, cache_sram->size);
+
+       return 0;
+
+out_unmap:
+       iounmap(cache_sram->base_virt);
+
+out_release:
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+out_free:
+       kfree(cache_sram);
+       return ret;
+}
+
+void remove_cache_sram(struct platform_device *dev)
+{
+       BUG_ON(!cache_sram);
+
+       rh_detach_region(cache_sram->rh, 0, cache_sram->size);
+       rh_destroy(cache_sram->rh);
+
+       iounmap(cache_sram->base_virt);
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+       kfree(cache_sram);
+       cache_sram = NULL;
+
+       dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
+}