| 
									
										
										
										
											2010-10-13 17:30:56 +05:30
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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>
 | 
					
						
							| 
									
										
										
										
											2012-02-01 19:05:15 +02:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2010-10-13 17:30:56 +05:30
										 |  |  | #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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-08 21:43:47 +00:00
										 |  |  | 	cache_sram->base_virt = ioremap_prot(cache_sram->base_phys, | 
					
						
							| 
									
										
										
										
											2010-10-13 17:30:56 +05:30
										 |  |  | 				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); | 
					
						
							|  |  |  | 	if (!cache_sram->base_virt) { | 
					
						
							| 
									
										
										
										
											2011-05-08 21:43:47 +00:00
										 |  |  | 		dev_err(&dev->dev, "%s: ioremap_prot failed\n", | 
					
						
							| 
									
										
										
										
											2010-10-13 17:30:56 +05:30
										 |  |  | 				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"); | 
					
						
							|  |  |  | } |