/* * * cppi_client.c * Description: * cppi mrpc client driver * * * GPL LICENSE SUMMARY * * Copyright(c) 2016-2019 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * Contact Information: * Intel Corporation * 2200 Mission College Blvd. * Santa Clara, CA 97052 */ #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d " fmt "\n", __func__, __LINE__ /************************************************/ /** Includes */ /************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Memory mapping utility is needed for CPPI buffer pools mapping #ifdef DEBUG #define DBG(fmt, ...) pr_err(fmt, ##__VA_ARGS__) #else #define DBG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) #endif /* driver private database */ struct cppi_private { struct platform_device *pdev; /* platform device */ struct mrpc_client *mrpc; /* mrpc client handle */ }; static struct cppi_private *this; #ifdef CONFIG_PP_SANITY_TESTS struct cppi_sanity_dma_args { Uint32 freeQMgr; Uint32 freeQNum; Uint32 freeBMgr; Uint32 freeBpool; }; #endif typedef struct { Uint32 bMgr; Uint32 bPool; } cppi_get_bpool_info_args_t; typedef struct { PAL_Result result; Cppi4BufPoolInfo bp_info; } cppi_get_bpool_info_rep_t; struct cppi_set_dma_status_args { PAL_CPPI_PP_DMA_BLOCKS_e dma_number; Uint32 to_enable; }; struct cppi_get_dma_state_rep { struct Puma7_cppi_dma_block_state dma_blocks_state[PAL_CPPI41_NUM_DMA_BLOCK]; int return_value; }; struct mrpc_cppi_get_pp_free_queue_info_according_to_q_manager_and_num_args { unsigned int qMgr; /* The queue manager number */ unsigned int qNum; /* The queue number */ }; enum { CPPI_GET_BPOOL_INFO = 0, CPPI_CONFIGURE_SANITY_DMA_CHANNELS, CPPI_GET_BPOOL_BSMON_INFO, CPPI_GET_PP_FREE_QUEUES_COUNT, CPPI_GET_PP_FREE_QUEUE_INFO, CPPI_DISABLE_INGRESS_DMA_CHANNELS, CPPI_RESTORE_INGRESS_DMA_CHANNELS, CPPI_SET_DMA_STATE, CPPI_GET_DMA_STATE, CPPI_GET_PP_FREE_QUEUE_INFO_ACCORDING_TO_Q_MANAGER_AND_NUM, CPPI_GET_PP_DESC_REGION_INFO, }; static inline int cppi_mrpc_call(__u8 procid, void *args, ssize_t args_size ) { struct cppi_private *priv = this; int ret, errcode; Uint32 rep; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return -EFAULT; } ret = mrpc_call(priv->mrpc, procid, args, args_size, &rep, sizeof(rep), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return errcode; } return be32_to_cpu(rep); } static inline cppi_get_bpool_info_rep_t cppi_mrpc_call_bpool_info(__u8 procid, void *args, ssize_t args_size ) { struct cppi_private *priv = this; int ret, errcode; cppi_get_bpool_info_rep_t rep = {0}; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); rep.result = -EFAULT; return rep; } ret = mrpc_call(priv->mrpc, procid, args, args_size, &rep, sizeof(rep), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); rep.result = errcode; return rep; } return rep; } static inline int cppi_mrpc_call_get_dma_state(__u8 procid, void *args, ssize_t args_size, struct Puma7_cppi_dma_block_state dma_state[]) { struct cppi_private *priv = this; int ret; int errcode; struct cppi_get_dma_state_rep rep; u32 i; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); rep.return_value = -EFAULT; return rep.return_value; } ret = mrpc_call(priv->mrpc, procid, args, args_size, &rep, sizeof(struct cppi_get_dma_state_rep), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); rep.return_value = errcode; return rep.return_value; } for (i = 0; i < PAL_CPPI41_NUM_DMA_BLOCK; i++) { dma_state[i].channels_bitmap = be32_to_cpu(rep.dma_blocks_state[i].channels_bitmap); } return rep.return_value; } Int32 disable_all_packet_ram_rx_dma_channels(void) { return cppi_mrpc_call(CPPI_DISABLE_INGRESS_DMA_CHANNELS, NULL, 0); } EXPORT_SYMBOL(disable_all_packet_ram_rx_dma_channels); Int32 restore_all_packet_ram_rx_dma_channels(void) { return cppi_mrpc_call(CPPI_RESTORE_INGRESS_DMA_CHANNELS, NULL, 0); } EXPORT_SYMBOL(restore_all_packet_ram_rx_dma_channels); void set_dma_status(PAL_CPPI_PP_DMA_BLOCKS_e dma_number, Uint32 to_enable) { struct cppi_set_dma_status_args args = { .dma_number = htonl(dma_number), .to_enable = htonl(to_enable) }; cppi_mrpc_call(CPPI_SET_DMA_STATE, &args, sizeof(args)); } EXPORT_SYMBOL(set_dma_status); int get_dma_state(struct Puma7_cppi_dma_block_state dma_state[PAL_CPPI41_NUM_DMA_BLOCK]) { int ret; Uint32 args; ret = cppi_mrpc_call_get_dma_state(CPPI_GET_DMA_STATE, &args, sizeof(args), dma_state); return ret; } EXPORT_SYMBOL(get_dma_state); #ifdef CONFIG_PP_SANITY_TESTS /* DMA channels configuration for sanity tool */ Int32 avalanche_cppi_init_pp_sanity_dma_channels(PAL_Handle palHandle, Cppi4Queue freeQ, Cppi4BufPool freeBuf) { struct cppi_sanity_dma_args args; args.freeQMgr = htonl(freeQ.qMgr); args.freeQNum = htonl(freeQ.qNum); args.freeBMgr = htonl(freeBuf.bMgr); args.freeBpool = htonl(freeBuf.bPool); return cppi_mrpc_call(CPPI_CONFIGURE_SANITY_DMA_CHANNELS, &args, sizeof(args)); } EXPORT_SYMBOL(avalanche_cppi_init_pp_sanity_dma_channels); #endif /* * PAL_cppi4GetBufferPoolInfo * - Get Buffer Pool info */ PAL_Result PAL_cppi4GetBufferPoolInfo(PAL_Handle hnd, Cppi4BufPool pool, Cppi4BufPoolInfo* bp_info) { cppi_get_bpool_info_args_t args; cppi_get_bpool_info_rep_t rep; PAL_Result result; args.bMgr = cpu_to_be32(pool.bMgr); args.bPool = cpu_to_be32(pool.bPool); rep = (cppi_get_bpool_info_rep_t) cppi_mrpc_call_bpool_info(CPPI_GET_BPOOL_INFO, &args, sizeof(args)); result = rep.result; if (PAL_SOK == result) { memcpy(bp_info, &rep.bp_info, sizeof(Cppi4BufPoolInfo)); bp_info->bPoolPhyAddr = be32_to_cpu(bp_info->bPoolPhyAddr); bp_info->bPoolTopPhyAddr = be32_to_cpu(bp_info->bPoolTopPhyAddr); bp_info->bPoolOffset = be32_to_cpu(bp_info->bPoolOffset); bp_info->bPoolSize = be32_to_cpu(bp_info->bPoolSize); bp_info->bufSize = be32_to_cpu(bp_info->bufSize); bp_info->numBuf = be32_to_cpu(bp_info->numBuf); pr_debug("BPOOL INFO MRPC OK: buffStart: 0x%08x, buffEnd: 0x%08x, poolOffset: 0x%08x", bp_info->bPoolPhyAddr, bp_info->bPoolTopPhyAddr, bp_info->bPoolOffset); } return result; } EXPORT_SYMBOL(PAL_cppi4GetBufferPoolInfo); /*! * Get cppi buffer pool status monitor info from ARM cppi * driver * * \param idx buffer pool index, 0 - PAL_CPPI41_BMGR_MAX_POOLS * \param info buffer pool buffer status monitor info on a * successful run * * \return PAL_Result 0 on success, error code otherwise */ PAL_Result PAL_cppi4GetBpoolBsmonInfo(u32 idx, qsmonRal_t *info) { struct cppi_private *priv = this; int ret, errcode; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return EFAULT; } if (!info) return EFAULT; idx = cpu_to_be32(idx); ret = mrpc_call(priv->mrpc, CPPI_GET_BPOOL_BSMON_INFO, &idx, sizeof(idx), info, sizeof(*info), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return EFAULT; } info->fdQueue.qMgr = be32_to_cpu(info->fdQueue.qMgr ); info->fdQueue.qNum = be32_to_cpu(info->fdQueue.qNum ); info->qsmonThread = be32_to_cpu(info->qsmonThread ); info->qsmonThreshold = be32_to_cpu(info->qsmonThreshold); info->qsmonChEn = be32_to_cpu(info->qsmonChEn ); info->ralQEnable = be32_to_cpu(info->ralQEnable ); info->direction = be32_to_cpu(info->direction ); return 0; } EXPORT_SYMBOL(PAL_cppi4GetBpoolBsmonInfo); /*! * Get number of free queues configured in CPPI driver on ARM side * * \param fqueues_count number of free queueson a successful run * * \return PAL_Result 0 on success, error code otherwise */ PAL_Result PAL_cppi4GetFreeQueuesCount(u32 *fqueues_count) { struct cppi_private *priv = this; int ret, errcode; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return EFAULT; } if (!fqueues_count) return EINVAL; ret = mrpc_call(priv->mrpc, CPPI_GET_PP_FREE_QUEUES_COUNT, &ret, sizeof(ret), fqueues_count, sizeof(*fqueues_count), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return EFAULT; } *fqueues_count = be32_to_cpu(*fqueues_count); return 0; } EXPORT_SYMBOL(PAL_cppi4GetFreeQueuesCount); /*! * Get cppi queue's status monitor info from ARM cppi driver * * \param idx buffer pool index, 0 - PAL_CPPI41_BMGR_MAX_POOLS * \param info buffer pool buffer status monitor info on a successful run * * \return PAL_Result 0 on success, error code otherwise */ PAL_Result PAL_cppi4GetPpFreeQueueInfo(u32 idx, FDqueue_t *fqueue_info) { struct cppi_private *priv = this; int ret, errcode; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return EFAULT; } if (!fqueue_info) return EINVAL; idx = cpu_to_be32(idx); ret = mrpc_call(priv->mrpc, CPPI_GET_PP_FREE_QUEUE_INFO, &idx, sizeof(idx), fqueue_info, sizeof(*fqueue_info), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return EFAULT; } fqueue_info->descCount = be16_to_cpu(fqueue_info->descCount); fqueue_info->descSize = be16_to_cpu(fqueue_info->descSize ); fqueue_info->qId = be16_to_cpu(fqueue_info->qId ); fqueue_info->allocType = be32_to_cpu(fqueue_info->allocType); return 0; } EXPORT_SYMBOL(PAL_cppi4GetPpFreeQueueInfo); /*! * Get cppi queue's status monitor info from ARM cppi driver * * \param idx buffer pool index, 0 - PAL_CPPI41_BMGR_MAX_POOLS * \param info buffer pool buffer status monitor info on a successful run * * \return PAL_Result 0 on success, error code otherwise */ int cppi_get_pp_free_queue_info_according_to_q_manager_and_num(Cppi4Queue* q, FDqueue_t *fqueue_info) { struct cppi_private *priv = this; struct mrpc_cppi_get_pp_free_queue_info_according_to_q_manager_and_num_args args; int ret; int errcode; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return EFAULT; } if (!fqueue_info) return EINVAL; args.qMgr = cpu_to_be32(q->qMgr); args.qNum = cpu_to_be32(q->qNum); ret = mrpc_call(priv->mrpc, CPPI_GET_PP_FREE_QUEUE_INFO_ACCORDING_TO_Q_MANAGER_AND_NUM, &args, sizeof(args), fqueue_info, sizeof(*fqueue_info), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return EFAULT; } fqueue_info->descCount = be16_to_cpu(fqueue_info->descCount); fqueue_info->descSize = be16_to_cpu(fqueue_info->descSize ); fqueue_info->qId = be16_to_cpu(fqueue_info->qId ); fqueue_info->allocType = be32_to_cpu(fqueue_info->allocType); return 0; } EXPORT_SYMBOL(cppi_get_pp_free_queue_info_according_to_q_manager_and_num); int PAL_cppi4GetPpDescRegionInfo(u32 idx, Cppi4DescReg *region_info) { struct cppi_private *priv = this; int ret; int errcode; if (!priv) { pr_err("ERROR: mrpc cppi not initialized"); return EFAULT; } if (!region_info) return EINVAL; idx = cpu_to_be32(idx); ret = mrpc_call(priv->mrpc, CPPI_GET_PP_DESC_REGION_INFO, &idx, sizeof(idx), region_info, sizeof(*region_info), 0, &errcode); if (ret || errcode) { pr_err("ERROR: ret=%d, errcode=%d", ret, errcode); return EFAULT; } region_info->numDesc = be32_to_cpu(region_info->numDesc); region_info->szDesc = be32_to_cpu(region_info->szDesc); return 0; } EXPORT_SYMBOL(PAL_cppi4GetPpDescRegionInfo); /* sysfs for future use */ static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct cppi_private *priv = dev_get_drvdata(dev); if (!priv) return -EINVAL; return scnprintf(buf, PAGE_SIZE, "status ok"); } static DEVICE_ATTR(status, S_IRUGO, status_show, NULL); static struct attribute *cppi_attrs[] = { &dev_attr_status.attr, NULL }; static struct attribute_group cppi_attrs_group = { .attrs = cppi_attrs, }; /** * cppi_mrpc_probe * * @param pdev platform device * * @return 0 for success, error code otherwise */ static int cppi_mrpc_probe(struct platform_device *pdev) { struct cppi_private *priv; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { pr_err("memory allocation failed"); return -ENOMEM; } dev_set_drvdata(&pdev->dev, priv); priv->pdev = pdev; ret = sysfs_create_group(&priv->pdev->dev.kobj, &cppi_attrs_group); if (ret) { pr_err("sysfs_create_group failed (ret=%d)", ret); return ret; } priv->mrpc = mrpc_client_register(MRPC_RESERVED_ID_CPPI, "cppi"); if (!priv->mrpc) { pr_err("failed to register cppi"); ret = -ENODEV; goto out_remove_group; } this = priv; return 0; out_remove_group: sysfs_remove_group(&priv->pdev->dev.kobj, &cppi_attrs_group); return ret; } /** * cppi_mrpc_remove * * This function is called when the cppi mrpc driver is * removed. * * @param pdev platform device * * @return 0 for success, error code otherwise */ static int cppi_mrpc_remove(struct platform_device *pdev) { struct cppi_private *priv = platform_get_drvdata(pdev); mrpc_client_unregister(priv->mrpc); sysfs_remove_group(&priv->pdev->dev.kobj, &cppi_attrs_group); dev_set_drvdata(&pdev->dev, NULL); this = NULL; return 0; } static struct platform_driver cppi_driver = { .driver = { .name = "cppi", }, .probe = cppi_mrpc_probe, .remove = cppi_mrpc_remove, }; static struct platform_device *cppi_device; static int __init cppi_mrpc_init(void) { int ret; ret = platform_driver_register(&cppi_driver); if (ret < 0) { pr_err("Failed to register cppi platform driver: %d\n", ret); return ret; } pr_debug("cppi platform driver is registered"); cppi_device = platform_device_register_simple("cppi", -1, NULL, 0); if (IS_ERR(cppi_device)) { pr_err("Failed to register cppi platform device\n"); platform_driver_unregister(&cppi_driver); return PTR_ERR(cppi_device); } dev_info(&cppi_device->dev, "platform device is registered\n"); return 0; } static void __exit cppi_mrpc_exit(void) { platform_device_unregister(cppi_device); platform_driver_unregister(&cppi_driver); } /******************************************************/ /** Module Declarations **/ /******************************************************/ module_init(cppi_mrpc_init); module_exit(cppi_mrpc_exit); MODULE_AUTHOR("Intel Corporation"); MODULE_AUTHOR("Yair Weiss yair.weiss@intel.com"); MODULE_DESCRIPTION("cppi mrpc client"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0");