|  | // SPDX-License-Identifier: GPL-2.0-or-later | 
|  | /* | 
|  | * Copyright 2009-2010 Freescale Semiconductor, Inc. | 
|  | * | 
|  | * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM | 
|  | * | 
|  | * Author: Vivek Mahajan <[email protected]> | 
|  | * | 
|  | * This file is derived from the original work done | 
|  | * by Sylvain Munaut for the Bestcomm SRAM allocator. | 
|  | */ | 
|  |  | 
|  | #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, "%pOF: request memory failed\n", | 
|  | dev->dev.of_node); | 
|  | ret = -ENXIO; | 
|  | goto out_free; | 
|  | } | 
|  |  | 
|  | cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys, | 
|  | cache_sram->size); | 
|  | if (!cache_sram->base_virt) { | 
|  | dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n", | 
|  | dev->dev.of_node); | 
|  | ret = -ENOMEM; | 
|  | goto out_release; | 
|  | } | 
|  |  | 
|  | cache_sram->rh = rh_create(sizeof(unsigned int)); | 
|  | if (IS_ERR(cache_sram->rh)) { | 
|  | dev_err(&dev->dev, "%pOF: Unable to create remote heap\n", | 
|  | dev->dev.of_node); | 
|  | 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"); | 
|  | } |