| /* | |
| * 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/export.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_prot(cache_sram->base_phys, | |
| cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); | |
| if (!cache_sram->base_virt) { | |
| dev_err(&dev->dev, "%s: ioremap_prot 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"); | |
| } |