1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright 2009-2010 Freescale Semiconductor, Inc. 4 * 5 * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM 6 * 7 * Author: Vivek Mahajan <vivek.mahajan@freescale.com> 8 * 9 * This file is derived from the original work done 10 * by Sylvain Munaut for the Bestcomm SRAM allocator. 11 */ 12 13#include <linux/kernel.h> 14#include <linux/export.h> 15#include <linux/slab.h> 16#include <linux/err.h> 17#include <linux/of_platform.h> 18#include <linux/pgtable.h> 19#include <asm/fsl_85xx_cache_sram.h> 20 21#include "fsl_85xx_cache_ctlr.h" 22 23struct mpc85xx_cache_sram *cache_sram; 24 25void *mpc85xx_cache_sram_alloc(unsigned int size, 26 phys_addr_t *phys, unsigned int align) 27{ 28 unsigned long offset; 29 unsigned long flags; 30 31 if (unlikely(cache_sram == NULL)) 32 return NULL; 33 34 if (!size || (size > cache_sram->size) || (align > cache_sram->size)) { 35 pr_err("%s(): size(=%x) or align(=%x) zero or too big\n", 36 __func__, size, align); 37 return NULL; 38 } 39 40 if ((align & (align - 1)) || align <= 1) { 41 pr_err("%s(): align(=%x) must be power of two and >1\n", 42 __func__, align); 43 return NULL; 44 } 45 46 spin_lock_irqsave(&cache_sram->lock, flags); 47 offset = rh_alloc_align(cache_sram->rh, size, align, NULL); 48 spin_unlock_irqrestore(&cache_sram->lock, flags); 49 50 if (IS_ERR_VALUE(offset)) 51 return NULL; 52 53 *phys = cache_sram->base_phys + offset; 54 55 return (unsigned char *)cache_sram->base_virt + offset; 56} 57EXPORT_SYMBOL(mpc85xx_cache_sram_alloc); 58 59void mpc85xx_cache_sram_free(void *ptr) 60{ 61 unsigned long flags; 62 BUG_ON(!ptr); 63 64 spin_lock_irqsave(&cache_sram->lock, flags); 65 rh_free(cache_sram->rh, ptr - cache_sram->base_virt); 66 spin_unlock_irqrestore(&cache_sram->lock, flags); 67} 68EXPORT_SYMBOL(mpc85xx_cache_sram_free); 69 70int __init instantiate_cache_sram(struct platform_device *dev, 71 struct sram_parameters sram_params) 72{ 73 int ret = 0; 74 75 if (cache_sram) { 76 dev_err(&dev->dev, "Already initialized cache-sram\n"); 77 return -EBUSY; 78 } 79 80 cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL); 81 if (!cache_sram) { 82 dev_err(&dev->dev, "Out of memory for cache_sram structure\n"); 83 return -ENOMEM; 84 } 85 86 cache_sram->base_phys = sram_params.sram_offset; 87 cache_sram->size = sram_params.sram_size; 88 89 if (!request_mem_region(cache_sram->base_phys, cache_sram->size, 90 "fsl_85xx_cache_sram")) { 91 dev_err(&dev->dev, "%pOF: request memory failed\n", 92 dev->dev.of_node); 93 ret = -ENXIO; 94 goto out_free; 95 } 96 97 cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys, 98 cache_sram->size); 99 if (!cache_sram->base_virt) { 100 dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n", 101 dev->dev.of_node); 102 ret = -ENOMEM; 103 goto out_release; 104 } 105 106 cache_sram->rh = rh_create(sizeof(unsigned int)); 107 if (IS_ERR(cache_sram->rh)) { 108 dev_err(&dev->dev, "%pOF: Unable to create remote heap\n", 109 dev->dev.of_node); 110 ret = PTR_ERR(cache_sram->rh); 111 goto out_unmap; 112 } 113 114 rh_attach_region(cache_sram->rh, 0, cache_sram->size); 115 spin_lock_init(&cache_sram->lock); 116 117 dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n", 118 (unsigned long long)cache_sram->base_phys, cache_sram->size); 119 120 return 0; 121 122out_unmap: 123 iounmap(cache_sram->base_virt); 124 125out_release: 126 release_mem_region(cache_sram->base_phys, cache_sram->size); 127 128out_free: 129 kfree(cache_sram); 130 return ret; 131} 132 133void remove_cache_sram(struct platform_device *dev) 134{ 135 BUG_ON(!cache_sram); 136 137 rh_detach_region(cache_sram->rh, 0, cache_sram->size); 138 rh_destroy(cache_sram->rh); 139 140 iounmap(cache_sram->base_virt); 141 release_mem_region(cache_sram->base_phys, cache_sram->size); 142 143 kfree(cache_sram); 144 cache_sram = NULL; 145 146 dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n"); 147} 148