/* Copyright 2013 Freescale Semiconductor, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Freescale Semiconductor nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * * ALTERNATIVELY, this software may be distributed under the terms of the * GNU General Public License ("GPL") as published by the Free Software * Foundation, either version 2 of that License or (at your option) any * later version. * * This software is provided by Freescale Semiconductor "as is" and any * express or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose are * disclaimed. In no event shall Freescale Semiconductor be liable for any * direct, indirect, incidental, special, exemplary, or consequential damages * (including, but not limited to, procurement of substitute goods or services; * loss of use, data, or profits; or business interruption) however caused and * on any theory of liability, whether in contract, strict liability, or tort * (including negligence or otherwise) arising in any way out of the use of * this software, even if advised of the possibility of such damage. */ #include #include #include #include #include "flib/dce_defs.h" #define DRV_VERSION "0.1" MODULE_AUTHOR("Jeffrey Ladouceur"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("FSL DCE device usage"); MODULE_VERSION(DRV_VERSION); static struct kmem_cache *slab_scr_64b; static struct kmem_cache *slab_scr_128b; static struct kmem_cache *slab_compress_history; static struct kmem_cache *slab_decompress_history; static struct kmem_cache *slab_pending_output; static struct kmem_cache *slab_decomp_ctxt; /* * DCE hw dma memory requirements for stateful mode * compression: * scr: 64B size, 64B aligned * history: 4096B size, 64B aligned * pending_output: 8202B, 64B aligned optimal, recycle mode only. * * decompression: * scr: 128B size, 64B aligned * history: 32768b, 64b aligned * pending_output: 8256b, 64b aligned optimal, recycle mode only * decomp_ctx: 256b, 64b aligned optimal */ /* Hack to support "dce_map()". The point of this is that dma_map_single() now * requires a non-NULL device, so the idea is that address mapping must be * device-sensitive. Now the PAMU IO-MMU already takes care of this, as can be * seen by the device-tree structure generated by the hypervisor (each portal * node has sub-nodes for each h/w end-point it provides access to, and each * sub-node has its own LIODN configuration). So we just need to map cpu * pointers to (guest-)physical address and the PAMU takes care of the rest, so * this doesn't need to be portal-sensitive nor device-sensitive. */ static struct platform_device *pdev; static int dce_sys_init(void) { int ret = -ENOMEM; slab_scr_64b = kmem_cache_create("fsl_dce_scr_64b", sizeof(struct scf_64b), /* 64 byte size */ DCE_SCR_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_scr_64b) goto end; slab_scr_128b = kmem_cache_create("fsl_dce_scr_128b", sizeof(struct scf_128b), /* 128 byte size */ DCE_SCR_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_scr_128b) goto end; slab_compress_history = kmem_cache_create("fsl_dce_compress_history", DCE_COMP_HISTORY_SIZE, DCE_COMP_HISTORY_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_compress_history) goto end; slab_decompress_history = kmem_cache_create( "fsl_dce_decompress_history", DCE_DECOMP_HISTORY_SIZE, DCE_DECOMP_HISTORY_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_decompress_history) goto end; slab_pending_output = kmem_cache_create("fsl_dce_pending_output", DCE_PENDING_OUTPUT_SIZE, /* 8256 size */ DCE_PENDING_OUTPUT_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_pending_output) goto end; slab_decomp_ctxt = kmem_cache_create("fsl_dce_decomp_ctxt", DCE_DECOMP_CTXT_SIZE, /* 256 bytes */ DCE_DECOMP_CTXT_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!slab_decomp_ctxt) goto end; pdev = platform_device_alloc("dce", -1); if (!pdev) goto end; if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40))) goto end; if (platform_device_add(pdev)) goto end; pr_info("dce_sys_init done!\n"); return 0; end: if (pdev) { platform_device_put(pdev); pdev = NULL; } if (slab_scr_64b) { kmem_cache_destroy(slab_scr_64b); slab_scr_64b = NULL; } if (slab_scr_128b) { kmem_cache_destroy(slab_scr_128b); slab_scr_128b = NULL; } if (slab_compress_history) { kmem_cache_destroy(slab_compress_history); slab_compress_history = NULL; } if (slab_decompress_history) { kmem_cache_destroy(slab_decompress_history); slab_decompress_history = NULL; } if (slab_pending_output) { kmem_cache_destroy(slab_pending_output); slab_pending_output = NULL; } if (slab_decomp_ctxt) { kmem_cache_destroy(slab_decomp_ctxt); slab_decomp_ctxt = NULL; } pr_err("DCE: dce_sys_init failed\n"); return ret; } static void dce_sys_exit(void) { platform_device_del(pdev); platform_device_put(pdev); pdev = NULL; kmem_cache_destroy(slab_scr_64b); kmem_cache_destroy(slab_scr_128b); kmem_cache_destroy(slab_compress_history); kmem_cache_destroy(slab_decompress_history); kmem_cache_destroy(slab_pending_output); kmem_cache_destroy(slab_decomp_ctxt); } module_init(dce_sys_init); module_exit(dce_sys_exit); /**************************/ /* system level functions */ /**************************/ struct fsl_dce_hw_scr_64b *fsl_dce_hw_scr_64b_new(void) { return kmem_cache_zalloc(slab_scr_64b, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_scr_64b_new); void fsl_dce_hw_scr_64b_free(struct fsl_dce_hw_scr_64b *p) { kmem_cache_free(slab_scr_64b, p); } EXPORT_SYMBOL(fsl_dce_hw_scr_64b_free); struct fsl_dce_hw_scr_128b *fsl_dce_hw_scr_128b_new(void) { return kmem_cache_zalloc(slab_scr_128b, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_scr_128b_new); void fsl_dce_hw_scr_128b_free(struct fsl_dce_hw_scr_128b *p) { kmem_cache_free(slab_scr_128b, p); } EXPORT_SYMBOL(fsl_dce_hw_scr_128b_free); struct fsl_dce_hw_compress_history *fsl_dce_hw_compress_history_new(void) { return kmem_cache_zalloc(slab_compress_history, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_compress_history_new); void fsl_dce_hw_compress_history_free(struct fsl_dce_hw_compress_history *p) { kmem_cache_free(slab_compress_history, p); } EXPORT_SYMBOL(fsl_dce_hw_compress_history_free); struct fsl_dce_hw_decompress_history *fsl_dce_hw_decompress_history_new(void) { return kmem_cache_zalloc(slab_decompress_history, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_decompress_history_new); void fsl_dce_hw_decompress_history_free(struct fsl_dce_hw_decompress_history *p) { kmem_cache_free(slab_decompress_history, p); } EXPORT_SYMBOL(fsl_dce_hw_decompress_history_free); struct fsl_dce_hw_pending_output *fsl_dce_hw_pending_output_new(void) { return kmem_cache_zalloc(slab_pending_output, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_pending_output_new); void fsl_dce_hw_pending_output_free(struct fsl_dce_hw_pending_output *p) { kmem_cache_free(slab_pending_output, p); } EXPORT_SYMBOL(fsl_dce_hw_pending_output_free); struct fsl_dce_hw_decomp_ctxt *fsl_dce_hw_decomp_ctxt_new(void) { return kmem_cache_zalloc(slab_decomp_ctxt, GFP_KERNEL); } EXPORT_SYMBOL(fsl_dce_hw_decomp_ctxt_new); void fsl_dce_hw_decomp_ctxt_free(struct fsl_dce_hw_decomp_ctxt *p) { kmem_cache_free(slab_decomp_ctxt, p); } EXPORT_SYMBOL(fsl_dce_hw_decomp_ctxt_free); dma_addr_t fsl_dce_map(void *ptr) { return dma_map_single(&pdev->dev, ptr, 1, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(fsl_dce_map); void fsl_dce_unmap(dma_addr_t handle) { dma_unmap_single(&pdev->dev, handle, 1, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(fsl_dce_unmap); struct device *fsl_dce_get_device(void) { if (!pdev) return NULL; return &pdev->dev; } EXPORT_SYMBOL(fsl_dce_get_device); int fsl_dce_map_error(dma_addr_t dma_addr) { return dma_mapping_error(&pdev->dev, dma_addr); } EXPORT_SYMBOL(fsl_dce_map_error);