/* * Copyright 2009-2010 Freescale Semiconductor, Inc. * * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM * * Author: Vivek Mahajan * * 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 #include #include #include #include #include #include #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"); }