diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/src')
35 files changed, 16420 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fman/src/Makefile b/drivers/net/ethernet/freescale/fman/src/Makefile new file mode 100644 index 0000000..af5d2e7 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk +# +obj-y += system/ +obj-y += wrapper/ +obj-y += xx/ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/system/sys_ext.h b/drivers/net/ethernet/freescale/fman/src/inc/system/sys_ext.h new file mode 100644 index 0000000..20f27d2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/system/sys_ext.h @@ -0,0 +1,118 @@ +/* + * Copyright 2008-2012 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. + */ + +#ifndef __SYS_EXT_H +#define __SYS_EXT_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group sys_grp System Interfaces + + @Description Linux system programming interfaces. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group sys_gen_grp System General Interface + + @Description General definitions, structures and routines of the linux + system programming interface. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Collection Macros for Advanced Configuration Requests + @{ +*//***************************************************************************/ +#define SYS_MAX_ADV_CONFIG_ARGS 4 + /**< Maximum number of arguments in + an advanced configuration entry */ +/* @} */ + +/**************************************************************************//** + @Description System Object Advanced Configuration Entry + + This structure represents a single request for an advanced + configuration call on the initialized object. An array of such + requests may be contained in the settings structure of the + corresponding object. + + The maximum number of arguments is limited to #SYS_MAX_ADV_CONFIG_ARGS. +*//***************************************************************************/ +typedef struct t_SysObjectAdvConfigEntry +{ + void *p_Function; /**< Pointer to advanced configuration routine */ + + uintptr_t args[SYS_MAX_ADV_CONFIG_ARGS]; + /**< Array of arguments for the specified routine; + All arguments should be casted to uint32_t. */ +} t_SysObjectAdvConfigEntry; + + +/** @} */ /* end of sys_gen_grp */ +/** @} */ /* end of sys_grp */ + +#define NCSW_PARAMS(_num, _params) ADV_CONFIG_PARAMS_##_num _params + +#define ADV_CONFIG_PARAMS_1(_type) \ + , (_type)p_Entry->args[0] + +#define SET_ADV_CONFIG_ARGS_1(_arg0) \ + p_Entry->args[0] = (uintptr_t )(_arg0); \ + +#define ARGS(_num, _params) SET_ADV_CONFIG_ARGS_##_num _params + +#define ADD_ADV_CONFIG_START(_p_Entries, _maxEntries) \ + { \ + t_SysObjectAdvConfigEntry *p_Entry; \ + t_SysObjectAdvConfigEntry *p_Entrys = (_p_Entries); \ + int i=0, max = (_maxEntries); \ + +#define ADD_ADV_CONFIG_END \ + } + +#define ADV_CONFIG_CHECK_START(_p_Entry) \ + { \ + t_SysObjectAdvConfigEntry *p_Entry = _p_Entry; \ + t_Error errCode; \ + +#define ADV_CONFIG_CHECK(_handle, _func, _params) \ + if (p_Entry->p_Function == _func) \ + { \ + errCode = _func(_handle _params); \ + } else + +#endif /* __SYS_EXT_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/system/sys_io_ext.h b/drivers/net/ethernet/freescale/fman/src/inc/system/sys_io_ext.h new file mode 100644 index 0000000..d6aa9d4 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/system/sys_io_ext.h @@ -0,0 +1,46 @@ +/* + * Copyright 2008-2012 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. + */ + +#ifndef __SYS_IO_EXT_H +#define __SYS_IO_EXT_H + +#include "std_ext.h" +#include "error_ext.h" + + +t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size); +t_Error SYS_UnregisterIoMap (uint64_t virtAddr); +uint64_t SYS_PhysToVirt (uint64_t addr); +uint64_t SYS_VirtToPhys (uint64_t addr); + + +#endif /* __SYS_IO_EXT_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/types_linux.h b/drivers/net/ethernet/freescale/fman/src/inc/types_linux.h new file mode 100644 index 0000000..ac15d66 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/types_linux.h @@ -0,0 +1,200 @@ +/* + * Copyright 2008-2012 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. + */ + +#ifndef __TYPES_LINUX_H__ +#define __TYPES_LINUX_H__ + +#include <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) + #error "This kernel is probably not supported!!!" +#elif (!((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) || \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)) || \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)))) + #warning "This kernel is probably not supported!!! You may need to add some fixes." +#endif /* LINUX_VERSION_CODE */ + + +typedef float float_t; /* Single precision floating point */ +typedef double double_t; /* Double precision floating point */ + + +#define _Packed +#define _PackedType __attribute__ ((packed)) + +typedef phys_addr_t physAddress_t; + +#define UINT8_MAX 0xFF +#define UINT8_MIN 0 +#define UINT16_MAX 0xFFFF +#define UINT16_MIN 0 +#define UINT32_MAX 0xFFFFFFFF +#define UINT32_MIN 0 +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFLL +#define UINT64_MIN 0 +#define INT8_MAX 0x7F +#define INT8_MIN 0x80 +#define INT16_MAX 0x7FFF +#define INT16_MIN 0x8000 +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL +#define INT64_MIN 0x8000000000000000LL + +#define ON 1 +#define OFF 0 + +#define FALSE false +#define TRUE true + + +/************************/ +/* memory access macros */ +/************************/ +#define GET_UINT8(arg) *(volatile uint8_t *)(&(arg)) +#define GET_UINT16(arg) in_be16(&(arg))//*(volatile uint16_t*)(&(arg)) +#define GET_UINT32(arg) in_be32(&(arg))//*(volatile uint32_t*)(&(arg)) +#define GET_UINT64(arg) *(volatile uint64_t*)(&(arg)) + +#ifdef VERBOSE_WRITE +void XX_Print(char *str, ...); +#define WRITE_UINT8(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%02x\r\n", (uint32_t)&(arg), (data)); *(volatile uint8_t *)(&(arg)) = (data); } while (0) +#define WRITE_UINT16(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%04x\r\n", (uint32_t)&(arg), (data)); out_be16(&(arg), data); /* *(volatile uint16_t*)(&(arg)) = (data);*/ } while (0) +#define WRITE_UINT32(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%08x\r\n", (uint32_t)&(arg), (data)); out_be32(&(arg), data); /* *(volatile uint32_t*)(&(arg)) = (data);*/ } while (0) +#define WRITE_UINT64(arg, data) \ + do { XX_Print("ADDR: 0x%08x, VAL: 0x%016llx\r\n", (uint32_t)&(arg), (data)); *(volatile uint64_t*)(&(arg)) = (data); } while (0) + +#else /* not VERBOSE_WRITE */ +#define WRITE_UINT8(arg, data) *(volatile uint8_t *)(&(arg)) = (data) +#define WRITE_UINT16(arg, data) out_be16(&(arg), data)//*(volatile uint16_t*)(&(arg)) = (data) +#define WRITE_UINT32(arg, data) out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data) +#define WRITE_UINT64(arg, data) *(volatile uint64_t*)(&(arg)) = (data) +#endif /* not VERBOSE_WRITE */ + + +/*****************************************************************************/ +/* General stuff */ +/*****************************************************************************/ +#ifdef ARRAY_SIZE +#undef ARRAY_SIZE +#endif /* ARRAY_SIZE */ + +#ifdef MAJOR +#undef MAJOR +#endif /* MAJOR */ + +#ifdef MINOR +#undef MINOR +#endif /* MINOR */ + +#ifdef QE_SIZEOF_BD +#undef QE_SIZEOF_BD +#endif /* QE_SIZEOF_BD */ + +#ifdef BD_BUFFER_CLEAR +#undef BD_BUFFER_CLEAR +#endif /* BD_BUFFER_CLEAR */ + +#ifdef BD_BUFFER +#undef BD_BUFFER +#endif /* BD_BUFFER */ + +#ifdef BD_STATUS_AND_LENGTH_SET +#undef BD_STATUS_AND_LENGTH_SET +#endif /* BD_STATUS_AND_LENGTH_SET */ + +#ifdef BD_STATUS_AND_LENGTH +#undef BD_STATUS_AND_LENGTH +#endif /* BD_STATUS_AND_LENGTH */ + +#ifdef BD_BUFFER_ARG +#undef BD_BUFFER_ARG +#endif /* BD_BUFFER_ARG */ + +#ifdef BD_GET_NEXT +#undef BD_GET_NEXT +#endif /* BD_GET_NEXT */ + +#ifdef QE_SDEBCR_BA_MASK +#undef QE_SDEBCR_BA_MASK +#endif /* QE_SDEBCR_BA_MASK */ + +#ifdef BD_BUFFER_SET +#undef BD_BUFFER_SET +#endif /* BD_BUFFER_SET */ + +#ifdef UPGCR_PROTOCOL +#undef UPGCR_PROTOCOL +#endif /* UPGCR_PROTOCOL */ + +#ifdef UPGCR_TMS +#undef UPGCR_TMS +#endif /* UPGCR_TMS */ + +#ifdef UPGCR_RMS +#undef UPGCR_RMS +#endif /* UPGCR_RMS */ + +#ifdef UPGCR_ADDR +#undef UPGCR_ADDR +#endif /* UPGCR_ADDR */ + +#ifdef UPGCR_DIAG +#undef UPGCR_DIAG +#endif /* UPGCR_DIAG */ + +#ifdef NCSW_PARAMS +#undef NCSW_PARAMS +#endif /* NCSW_PARAMS */ + +#ifdef NO_IRQ +#undef NO_IRQ +#endif /* NO_IRQ */ + +#define PRINT_LINE XX_Print("%s:\n %s [%d]\n",__FILE__,__FUNCTION__,__LINE__); + + +#endif /* __TYPES_LINUX_H__ */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman.h b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman.h new file mode 100644 index 0000000..3efc8ce --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman.h @@ -0,0 +1,322 @@ +/* + * Copyright 2008-2012 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. + */ + +/****************************************************************************** + @File fsl_fman.h + + @Description Linux internal kernel API +*//***************************************************************************/ + +#ifndef __FSL_FMAN_H +#define __FSL_FMAN_H + +#include <linux/types.h> +#include <linux/device.h> /* struct device */ +#include <linux/fsl_qman.h> /* struct qman_fq */ +#include "dpaa_integration_ext.h" +#include "fm_port_ext.h" + +/**************************************************************************//** + @Group FM_LnxKern_grp Frame Manager Linux wrapper API + + @Description FM API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_LnxKern_ctrl_grp Control Unit + + @Description Control Unit + + Internal Kernel Control Unit API + @{ +*//***************************************************************************/ + +/*****************************************************************************/ +/* Internal Linux kernel routines */ +/*****************************************************************************/ + +/**************************************************************************//** + @Description A structure .., +*//***************************************************************************/ +struct fm; + +/**************************************************************************//** + @Description A structure .., +*//***************************************************************************/ +struct fm_port; + +typedef int (*alloc_pcd_fqids)(struct device *dev, uint32_t num, + uint8_t alignment, uint32_t *base_fqid); + +typedef int (*free_pcd_fqids)(struct device *dev, uint32_t base_fqid); + +struct fm_port_pcd_param { + alloc_pcd_fqids cba; + free_pcd_fqids cbf; + struct device *dev; +}; + +/**************************************************************************//** + @Description A structure of information about each of the external + buffer pools used by the port, +*//***************************************************************************/ +struct fm_port_pool_param { + uint8_t id; /**< External buffer pool id */ + uint16_t size; /**< External buffer pool buffer size */ +}; + +/**************************************************************************//** + @Description structure for additional port parameters +*//***************************************************************************/ +struct fm_port_params { + uint32_t errq; /**< Error Queue Id. */ + uint32_t defq; /**< For Tx and HC - Default Confirmation queue, + 0 means no Tx conf for processed frames. + For Rx and OP - default Rx queue. */ + uint8_t num_pools; /**< Number of pools use by this port */ + struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + /**< Parameters for each pool */ + uint16_t priv_data_size; /**< Area that user may save for his own + need (E.g. save the SKB) */ + bool parse_results; /**< Put the parser-results in the Rx/Tx buffer */ + bool hash_results; /**< Put the hash-results in the Rx/Tx buffer */ + bool time_stamp; /**< Put the time-stamp in the Rx/Tx buffer */ + bool frag_enable; /**< Fragmentation support, for OP only */ + uint16_t data_align; /**< value for selecting a data alignment (must be a power of 2); + if write optimization is used, must be >= 16. */ + uint8_t manip_extra_space; /**< Maximum extra size needed (insertion-size minus removal-size); + Note that this field impacts the size of the buffer-prefix + (i.e. it pushes the data offset); */ +}; + +/**************************************************************************//** + @Function fm_bind + + @Description Bind to a specific FM device. + + @Param[in] fm_dev - the OF handle of the FM device. + + @Return A handle of the FM device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +struct fm *fm_bind(struct device *fm_dev); + +/**************************************************************************//** + @Function fm_unbind + + @Description Un-bind from a specific FM device. + + @Param[in] fm - A handle of the FM device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +void fm_unbind(struct fm *fm); + +void *fm_get_handle(struct fm *fm); +void *fm_get_rtc_handle(struct fm *fm); +struct resource *fm_get_mem_region(struct fm *fm); + +/**************************************************************************//** + @Function fm_port_bind + + @Description Bind to a specific FM-port device (may be Rx or Tx port). + + @Param[in] fm_port_dev - the OF handle of the FM port device. + + @Return A handle of the FM port device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +struct fm_port *fm_port_bind(struct device *fm_port_dev); + +/**************************************************************************//** + @Function fm_port_unbind + + @Description Un-bind from a specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only after the port was created. +*//***************************************************************************/ +void fm_port_unbind(struct fm_port *port); + +/**************************************************************************//** + @Function fm_set_rx_port_params + + @Description Configure parameters for a specific Rx FM-port device. + + @Param[in] port - A handle of the FM port device. + @Param[in] params - Rx port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_set_rx_port_params(struct fm_port *port, + struct fm_port_params *params); + +/**************************************************************************//** + @Function fm_port_pcd_bind + + @Description Bind as a listener on a port PCD. + + @Param[in] port - A handle of the FM port device. + @Param[in] params - PCD port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params); + +/**************************************************************************//** + @Function fm_port_get_buff_layout_ext_params + + @Description Get data_align and manip_extra_space from the device tree + chosen node if aplied. + This function will only update these two parameters. + When this port has no such parameters in the device tree + values will be set to 0. + + @Param[in] port - A handle of the FM port device. + @Param[in] params - PCD port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params); + +/**************************************************************************//** + @Function fm_get_tx_port_channel + + @Description Get qman-channel number for this Tx port. + + @Param[in] port - A handle of the FM port device. + + @Return qman-channel number for this Tx port. + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +int fm_get_tx_port_channel(struct fm_port *port); + +/**************************************************************************//** + @Function fm_set_tx_port_params + + @Description Configure parameters for a specific Tx FM-port device + + @Param[in] port - A handle of the FM port device. + @Param[in] params - Tx port parameters + + @Cautions Allowed only after the port is binded. +*//***************************************************************************/ +void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params); + + +/**************************************************************************//** + @Function fm_mac_set_handle + + @Description Set mac handle + + @Param[in] h_lnx_wrp_fm_dev - A handle of the LnxWrp FM device. + @Param[in] h_fm_mac - A handle of the LnxWrp FM MAC device. + @Param[in] mac_id - MAC id. +*//***************************************************************************/ +void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, t_Handle h_fm_mac, + int mac_id); + +/**************************************************************************//** + @Function fm_port_enable + + @Description Enable specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only after the port is initialized. +*//***************************************************************************/ +int fm_port_enable(struct fm_port *port); + +/**************************************************************************//** + @Function fm_port_disable + + @Description Disable specific FM-port device (may be Rx or Tx port). + + @Param[in] port - A handle of the FM port device. + + @Cautions Allowed only after the port is initialized. +*//***************************************************************************/ +void fm_port_disable(struct fm_port *port); + +void *fm_port_get_handle(struct fm_port *port); + +/**************************************************************************//** + @Function fm_port_get_base_address + + @Description Get base address of this port. Useful for accessing + port-specific registers (i.e., not common ones). + + @Param[in] port - A handle of the FM port device. + + @Param[out] base_addr - The port's base addr (virtual address). +*//***************************************************************************/ +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr); + +/**************************************************************************//** + @Function fm_mutex_lock + + @Description Lock function required before any FMD/LLD call. +*//***************************************************************************/ +void fm_mutex_lock(void); + +/**************************************************************************//** + @Function fm_mutex_unlock + + @Description Unlock function required after any FMD/LLD call. +*//***************************************************************************/ +void fm_mutex_unlock(void); + +/**************************************************************************//** + @Function fm_get_max_frm + + @Description Get the maximum frame size +*//***************************************************************************/ +int fm_get_max_frm(void); + +/**************************************************************************//** + @Function fm_get_rx_extra_headroom + + @Description Get the extra headroom size +*//***************************************************************************/ +int fm_get_rx_extra_headroom(void); + +/** @} */ /* end of FM_LnxKern_ctrl_grp group */ +/** @} */ /* end of FM_LnxKern_grp group */ + + +#endif /* __FSL_FMAN_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman_test.h b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman_test.h new file mode 100644 index 0000000..0466a47 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/fsl_fman_test.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * 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. + */ + +/****************************************************************************** + @File fsl_fman_test.h + + @Description +*//***************************************************************************/ + +#ifndef __FSL_FMAN_TEST_H +#define __FSL_FMAN_TEST_H + +#include <linux/types.h> +#include <linux/smp.h> /* raw_smp_processor_id() */ + +//#define FMT_K_DBG +//#define FMT_K_DBG_RUNTIME + +#define _fmt_prk(stage, format, arg...) \ + printk(stage "fmt (cpu:%u): " format, raw_smp_processor_id(), ##arg) + +#define _fmt_inf(format, arg...) _fmt_prk(KERN_INFO, format, ##arg) +#define _fmt_wrn(format, arg...) _fmt_prk(KERN_WARNING, format, ##arg) +#define _fmt_err(format, arg...) _fmt_prk(KERN_ERR, format, ##arg) + +/* there are two macros for debugging: for runtime and generic. + * Helps when the runtime functions are not targeted for debugging, + * thus all the unnecessary information will be skipped. + */ +/* used for generic debugging */ +#if defined(FMT_K_DBG) + #define _fmt_dbg(format, arg...) \ + printk("fmt [%s:%u](cpu:%u) - " format, \ + __func__, __LINE__, raw_smp_processor_id(), ##arg) +#else +# define _fmt_dbg(arg...) +#endif + +/* used for debugging runtime functions */ +#if defined(FMT_K_DBG_RUNTIME) + #define _fmt_dbgr(format, arg...) \ + printk("fmt [%s:%u](cpu:%u) - " format, \ + __func__, __LINE__, raw_smp_processor_id(), ##arg) +#else +# define _fmt_dbgr(arg...) +#endif + +#define FMT_RX_ERR_Q 0xffffffff +#define FMT_RX_DFLT_Q 0xfffffffe +#define FMT_TX_ERR_Q 0xfffffffd +#define FMT_TX_CONF_Q 0xfffffffc + +#define FMAN_TEST_MAX_TX_FQS 8 + +#endif /* __FSL_FMAN_TEST_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_exp_sym.h b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_exp_sym.h new file mode 100644 index 0000000..4c60893 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_exp_sym.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. + * All rights reserved. + * + * 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. + */ + +/* + @File lnxwrp_exp_sym.h + @Description FMan exported routines +*/ + +#ifndef __LNXWRP_EXP_SYM_H +#define __LNXWRP_EXP_SYM_H + +#include "fm_port_ext.h" +#include "fm_pcd_ext.h" +#include "fm_mac_ext.h" + + +/* FMAN Port exported routines */ +EXPORT_SYMBOL(FM_PORT_Disable); +EXPORT_SYMBOL(FM_PORT_Enable); +EXPORT_SYMBOL(FM_PORT_SetPCD); + +/* Runtime PCD exported routines */ +EXPORT_SYMBOL(FM_PCD_Enable); +EXPORT_SYMBOL(FM_PCD_Disable); +EXPORT_SYMBOL(FM_PCD_GetCounter); +EXPORT_SYMBOL(FM_PCD_PrsLoadSw); +EXPORT_SYMBOL(FM_PCD_KgSetDfltValue); +EXPORT_SYMBOL(FM_PCD_KgSetAdditionalDataAfterParsing); +EXPORT_SYMBOL(FM_PCD_SetException); +EXPORT_SYMBOL(FM_PCD_ModifyCounter); +EXPORT_SYMBOL(FM_PCD_SetPlcrStatistics); +EXPORT_SYMBOL(FM_PCD_SetPrsStatistics); +EXPORT_SYMBOL(FM_PCD_ForceIntr); +EXPORT_SYMBOL(FM_PCD_HcTxConf); + +EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsSet); +EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsDelete); +EXPORT_SYMBOL(FM_PCD_KgSchemeSet); +EXPORT_SYMBOL(FM_PCD_KgSchemeDelete); +EXPORT_SYMBOL(FM_PCD_KgSchemeGetCounter); +EXPORT_SYMBOL(FM_PCD_KgSchemeSetCounter); +EXPORT_SYMBOL(FM_PCD_CcRootBuild); +EXPORT_SYMBOL(FM_PCD_CcRootDelete); +EXPORT_SYMBOL(FM_PCD_MatchTableSet); +EXPORT_SYMBOL(FM_PCD_MatchTableDelete); +EXPORT_SYMBOL(FM_PCD_CcRootModifyNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableModifyNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableModifyMissNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableRemoveKey); +EXPORT_SYMBOL(FM_PCD_MatchTableFindNRemoveKey); +EXPORT_SYMBOL(FM_PCD_MatchTableAddKey); +EXPORT_SYMBOL(FM_PCD_MatchTableModifyKeyAndNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKeyAndNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableModifyKey); +EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKey); +EXPORT_SYMBOL(FM_PCD_MatchTableGetIndexedHashBucket); +EXPORT_SYMBOL(FM_PCD_MatchTableGetNextEngine); +EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyCounter); +EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyStatistics); +EXPORT_SYMBOL(FM_PCD_MatchTableFindNGetKeyStatistics); +EXPORT_SYMBOL(FM_PCD_HashTableSet); +EXPORT_SYMBOL(FM_PCD_HashTableDelete); +EXPORT_SYMBOL(FM_PCD_HashTableAddKey); +EXPORT_SYMBOL(FM_PCD_HashTableRemoveKey); +EXPORT_SYMBOL(FM_PCD_HashTableModifyNextEngine); +EXPORT_SYMBOL(FM_PCD_HashTableModifyMissNextEngine); +EXPORT_SYMBOL(FM_PCD_HashTableGetMissNextEngine); +EXPORT_SYMBOL(FM_PCD_HashTableFindNGetKeyStatistics); +EXPORT_SYMBOL(FM_PCD_PlcrProfileSet); +EXPORT_SYMBOL(FM_PCD_PlcrProfileDelete); +EXPORT_SYMBOL(FM_PCD_PlcrProfileGetCounter); +EXPORT_SYMBOL(FM_PCD_PlcrProfileSetCounter); +EXPORT_SYMBOL(FM_PCD_ManipNodeSet); +EXPORT_SYMBOL(FM_PCD_ManipNodeDelete); +EXPORT_SYMBOL(FM_PCD_ManipGetStatistics); +EXPORT_SYMBOL(FM_PCD_ManipNodeReplace); +#if (DPAA_VERSION >= 11) +EXPORT_SYMBOL(FM_PCD_FrmReplicSetGroup); +EXPORT_SYMBOL(FM_PCD_FrmReplicDeleteGroup); +EXPORT_SYMBOL(FM_PCD_FrmReplicAddMember); +EXPORT_SYMBOL(FM_PCD_FrmReplicRemoveMember); +#endif /* DPAA_VERSION >= 11 */ + +#ifdef FM_CAPWAP_SUPPORT +EXPORT_SYMBOL(FM_PCD_StatisticsSetNode); +#endif /* FM_CAPWAP_SUPPORT */ + +EXPORT_SYMBOL(FM_PCD_SetAdvancedOffloadSupport); + +/* FMAN MAC exported routines */ +EXPORT_SYMBOL(FM_MAC_GetStatistics); + +EXPORT_SYMBOL(FM_GetSpecialOperationCoding); + +#endif /* __LNXWRP_EXP_SYM_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_fm_ext.h b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_fm_ext.h new file mode 100644 index 0000000..8dda657 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/wrapper/lnxwrp_fm_ext.h @@ -0,0 +1,163 @@ +/* + * Copyright 2008-2012 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. + */ + +/****************************************************************************** + @File lnxwrp_fm_ext.h + + @Description TODO +*//***************************************************************************/ + +#ifndef __LNXWRP_FM_EXT_H +#define __LNXWRP_FM_EXT_H + +#include "std_ext.h" +#include "sys_ext.h" +#include "fm_ext.h" +#include "fm_muram_ext.h" +#include "fm_pcd_ext.h" +#include "fm_port_ext.h" +#include "fm_mac_ext.h" +#include "fm_rtc_ext.h" + + +/**************************************************************************//** + @Group FM_LnxKern_grp Frame Manager Linux wrapper API + + @Description FM API functions, definitions and enums. + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_LnxKern_init_grp Initialization Unit + + @Description Initialization Unit + + Initialization Flow: + Initialization of the FM Module will be carried out by the Linux + kernel according to the following sequence: + a. Calling the initialization routine with no parameters. + b. The driver will register to the Device-Tree. + c. The Linux Device-Tree will initiate a call to the driver for + initialization. + d. The driver will read the appropriate information from the Device-Tree + e. [Optional] Calling the advance initialization routines to change + driver's defaults. + f. Initialization of the device will be automatically upon using it. + + @{ +*//***************************************************************************/ + +typedef struct t_WrpFmDevSettings +{ + t_FmParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmDevSettings; + +typedef struct t_WrpFmPcdDevSettings +{ + t_FmPcdParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmPcdDevSettings; + +typedef struct t_WrpFmPortDevSettings +{ + bool frag_enabled; + t_FmPortParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmPortDevSettings; + +typedef struct t_WrpFmMacDevSettings +{ + t_FmMacParams param; + t_SysObjectAdvConfigEntry *advConfig; +} t_WrpFmMacDevSettings; + + +/**************************************************************************//** + @Function LNXWRP_FM_Init + + @Description Initialize the FM linux wrapper. + + @Return A handle (descriptor) of the newly created FM Linux wrapper + structure. +*//***************************************************************************/ +t_Handle LNXWRP_FM_Init(void); + +/**************************************************************************//** + @Function LNXWRP_FM_Free + + @Description Free the FM linux wrapper. + + @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm); + +/**************************************************************************//** + @Function LNXWRP_FM_GetMacHandle + + @Description Get the FM-MAC LLD handle from the FM linux wrapper. + + @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. + @Param[in] fmId - Index of the FM device to get the MAC handle from. + @Param[in] macId - Index of the mac handle. + + @Return A handle of the LLD compressor. +*//***************************************************************************/ +t_Handle LNXWRP_FM_GetMacHandle(t_Handle h_LnxWrpFm, uint8_t fmId, uint8_t macId); + +#ifdef CONFIG_FSL_FMAN_TEST +t_Handle LNXWRP_FM_TEST_Init(void); +t_Error LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp); +#endif /* CONFIG_FSL_FMAN_TEST */ + +/** @} */ /* end of FM_LnxKern_init_grp group */ + + +/**************************************************************************//** + @Group FM_LnxKern_ctrl_grp Control Unit + + @Description Control Unit + + TODO + @{ +*//***************************************************************************/ + +#include "fsl_fman.h" + +/** @} */ /* end of FM_LnxKern_ctrl_grp group */ +/** @} */ /* end of FM_LnxKern_grp group */ + + +#endif /* __LNXWRP_FM_EXT_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/inc/xx/xx.h b/drivers/net/ethernet/freescale/fman/src/inc/xx/xx.h new file mode 100644 index 0000000..b183c86 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/inc/xx/xx.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008-2012 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. + */ + +#ifndef __XX_H +#define __XX_H + +#include "xx_ext.h" + +void * xx_Malloc(uint32_t n); +void xx_Free(void *p); + +void *xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t align); +void xx_FreeSmart(void *p); + +/* never used: */ +#define GetDeviceName(irq) ((char *)NULL) + +int GetDeviceIrqNum(int irq); + + +#endif /* __XX_H */ diff --git a/drivers/net/ethernet/freescale/fman/src/system/Makefile b/drivers/net/ethernet/freescale/fman/src/system/Makefile new file mode 100644 index 0000000..f1aa763 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/system/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk +# + +obj-y += sys_io.o diff --git a/drivers/net/ethernet/freescale/fman/src/system/sys_io.c b/drivers/net/ethernet/freescale/fman/src/system/sys_io.c new file mode 100644 index 0000000..c106a8b --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/system/sys_io.c @@ -0,0 +1,171 @@ +/* + * Copyright 2008-2012 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 <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#include <linux/modversions.h> +#else +#include <config/modversions.h> +#endif /* LINUX_VERSION_CODE */ +#endif /* MODVERSIONS */ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <asm/io.h> + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "list_ext.h" +#include "sys_io_ext.h" + + +#define __ERR_MODULE__ MODULE_UNKNOWN + + +typedef struct { + uint64_t virtAddr; + uint64_t physAddr; + uint32_t size; + t_List node; +} t_IoMap; +#define IOMAP_OBJECT(ptr) LIST_OBJECT(ptr, t_IoMap, node) + +LIST(mapsList); + + +static void EnqueueIoMap(t_IoMap *p_IoMap) +{ + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_IoMap->node, &mapsList); + XX_RestoreAllIntr(intFlags); +} + +static t_IoMap * FindIoMapByVirtAddr(uint64_t addr) +{ + t_IoMap *p_IoMap; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &mapsList) + { + p_IoMap = IOMAP_OBJECT(p_Pos); + if ((addr >= p_IoMap->virtAddr) && (addr < p_IoMap->virtAddr+p_IoMap->size)) + return p_IoMap; + } + + return NULL; +} + +static t_IoMap * FindIoMapByPhysAddr(uint64_t addr) +{ + t_IoMap *p_IoMap; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &mapsList) + { + p_IoMap = IOMAP_OBJECT(p_Pos); + if ((addr >= p_IoMap->physAddr) && (addr < p_IoMap->physAddr+p_IoMap->size)) + return p_IoMap; + } + + return NULL; +} + +t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size) +{ + t_IoMap *p_IoMap; + + p_IoMap = (t_IoMap*)XX_Malloc(sizeof(t_IoMap)); + if (!p_IoMap) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); + memset(p_IoMap, 0, sizeof(t_IoMap)); + + p_IoMap->virtAddr = virtAddr; + p_IoMap->physAddr = physAddr; + p_IoMap->size = size; + + INIT_LIST(&p_IoMap->node); + EnqueueIoMap(p_IoMap); + + return E_OK; +} + +t_Error SYS_UnregisterIoMap (uint64_t virtAddr) +{ + t_IoMap *p_IoMap = FindIoMapByVirtAddr(virtAddr); + if (!p_IoMap) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + LIST_Del(&p_IoMap->node); + XX_Free(p_IoMap); + + return E_OK; +} + +uint64_t SYS_PhysToVirt(uint64_t addr) +{ + t_IoMap *p_IoMap = FindIoMapByPhysAddr(addr); + if (p_IoMap) + { + /* This is optimization - put the latest in the list-head - like a cache */ + if (mapsList.p_Next != &p_IoMap->node) + { + uint32_t intFlags = XX_DisableAllIntr(); + LIST_DelAndInit(&p_IoMap->node); + LIST_Add(&p_IoMap->node, &mapsList); + XX_RestoreAllIntr(intFlags); + } + return (uint64_t)(addr - p_IoMap->physAddr + p_IoMap->virtAddr); + } + return PTR_TO_UINT(phys_to_virt((unsigned long)addr)); +} + +uint64_t SYS_VirtToPhys(uint64_t addr) +{ + t_IoMap *p_IoMap; + + if (addr == 0) + return 0; + + p_IoMap = FindIoMapByVirtAddr(addr); + if (p_IoMap) + return (uint64_t)(addr - p_IoMap->virtAddr + p_IoMap->physAddr); + return (uint64_t)virt_to_phys(UINT_TO_PTR(addr)); +} diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/Makefile b/drivers/net/ethernet/freescale/fman/src/wrapper/Makefile new file mode 100644 index 0000000..22fe2e2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/fman/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) +EXTRA_CFLAGS += -I$(NET_DPA) + +obj-y += fsl-ncsw-PFM.o +obj-$(CONFIG_FSL_FMAN_TEST) += fman_test.o + +fsl-ncsw-PFM-objs := lnxwrp_fm.o lnxwrp_fm_port.o lnxwrp_ioctls_fm.o \ + lnxwrp_sysfs.o lnxwrp_sysfs_fm.o lnxwrp_sysfs_fm_port.o \ + lnxwrp_resources.o +obj-$(CONFIG_COMPAT) += lnxwrp_ioctls_fm_compat.o diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/fman_test.c b/drivers/net/ethernet/freescale/fman/src/wrapper/fman_test.c new file mode 100644 index 0000000..81edc9a --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/fman_test.c @@ -0,0 +1,1665 @@ +/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. + * All rights reserved. + * + * 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. + */ + +/* + @File fman_test.c + @Authors Pistirica Sorin Andrei + @Description FM Linux test environment +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/of_platform.h> +#include <linux/ip.h> +#include <linux/compat.h> +#include <linux/uaccess.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/fsl_qman.h> +#include <linux/fsl_bman.h> + +/* private headers */ +#include "fm_ext.h" +#include "fsl_fman.h" +#include "fm_port_ext.h" +#if (DPAA_VERSION == 11) +#include "../../Peripherals/FM/MAC/memac.h" +#endif +#include "fm_test_ioctls.h" +#include "fsl_fman_test.h" + +#include "dpaa_eth.h" +#include "dpaa_eth-common.h" + +#define FMT_FRM_WATERMARK 0xdeadbeefdeadbeeaLL + +struct fmt_frame_s { + ioc_fmt_buff_desc_t buff; + struct list_head list; +}; + +struct fmt_fqs_s { + struct qman_fq fq_base; + bool init; + struct fmt_port_s *fmt_port_priv; +}; + +struct fmt_port_pcd_s { + int num_queues; + struct fmt_fqs_s *fmt_pcd_fqs; + uint32_t fqid_base; +}; + +/* char dev structure: fm test port */ +struct fmt_port_s { + bool valid; + uint8_t id; + ioc_fmt_port_type port_type; + ioc_diag_mode diag; + bool compat_test_type; + + /* fm ports */ + /* ! for oh ports p_tx_fm_port_dev == p_rx_fm_port_dev && + * p_tx_port == p_rx_port */ + /* t_LnxWrpFmPortDev */ + struct fm_port *p_tx_port; + /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */ + void *p_tx_fm_port_dev; + /* t_LnxWrpFmPortDev */ + struct fm_port *p_rx_port; + /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */ + void *p_rx_fm_port_dev; + + void *p_mac_dev; + uint64_t fm_phys_base_addr; + + /* read/write queue manipulation */ + spinlock_t rx_q_lock; + struct list_head rx_q; + + /* tx queuee for injecting trafic */ + int num_of_tx_fqs; + struct fmt_fqs_s p_tx_fqs[FMAN_TEST_MAX_TX_FQS]; + + /* pcd private queues manipulation */ + struct fmt_port_pcd_s fmt_port_pcd; + + /* debugging stuff */ + +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_t enqueue_to_qman_frm; + atomic_t enqueue_to_rxq; + atomic_t dequeue_from_rxq; + atomic_t not_enqueue_to_rxq_wrong_frm; +#endif + +}; + +/* The devices. */ +struct fmt_s { + int major; + struct fmt_port_s ports[IOC_FMT_MAX_NUM_OF_PORTS]; + struct class *fmt_class; +}; + +/* fm test structure */ +static struct fmt_s fm_test; + +#if (DPAA_VERSION == 11) +struct mac_priv_s { + t_Handle mac; +}; +#endif + +#define DTSEC_BASE_ADDR 0x000e0000 +#define DTSEC_MEM_RANGE 0x00002000 +#define MAC_1G_MACCFG1 0x00000100 +#define MAC_1G_LOOP_MASK 0x00000100 +static int set_1gmac_loopback( + struct fmt_port_s *fmt_port, + bool en) +{ +#if (DPAA_VERSION <= 10) + uint32_t dtsec_idx = fmt_port->id; /* dtsec for which port */ + uint32_t dtsec_idx_off = dtsec_idx * DTSEC_MEM_RANGE; + phys_addr_t maccfg1_hw; + void *maccfg1_map; + uint32_t maccfg1_val; + + /* compute the maccfg1 register address */ + maccfg1_hw = fmt_port->fm_phys_base_addr + + (phys_addr_t)(DTSEC_BASE_ADDR + + dtsec_idx_off + + MAC_1G_MACCFG1); + + /* map register */ + maccfg1_map = ioremap(maccfg1_hw, sizeof(u32)); + + /* set register */ + maccfg1_val = in_be32(maccfg1_map); + if (en) + maccfg1_val |= MAC_1G_LOOP_MASK; + else + maccfg1_val &= ~MAC_1G_LOOP_MASK; + out_be32(maccfg1_map, maccfg1_val); + + /* unmap register */ + iounmap(maccfg1_map); +#else + struct mac_device *mac_dev; + struct mac_priv_s *priv; + t_Memac *p_memac; + + if (!fmt_port) + return -EINVAL; + + mac_dev = (struct mac_device *)fmt_port->p_mac_dev; + + if (!mac_dev) + return -EINVAL; + + priv = macdev_priv(mac_dev); + + if (!priv) + return -EINVAL; + + p_memac = priv->mac; + + if (!p_memac) + return -EINVAL; + + memac_set_loopback(p_memac->p_MemMap, en); +#endif + return 0; +} + +/* TODO: re-write this function */ +static int set_10gmac_int_loopback( + struct fmt_port_s *fmt_port, + bool en) +{ +#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK +#define FM_10GMAC0_OFFSET 0x000f0000 +#define FM_10GMAC_CMD_CONF_CTRL_OFFSET 0x8 +#define CMD_CFG_LOOPBACK_EN 0x00000400 + + uint64_t base_addr, reg_addr; + uint32_t tmp_val; + + base_addr = fmt_port->fm_phys_base_addr + (FM_10GMAC0_OFFSET + + ((fmt_port->id-FM_MAX_NUM_OF_1G_RX_PORTS)*0x2000)); + + base_addr = PTR_TO_UINT(ioremap(base_addr, 0x1000)); + + reg_addr = base_addr + FM_10GMAC_CMD_CONF_CTRL_OFFSET; + tmp_val = GET_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr))); + if (en) + tmp_val |= CMD_CFG_LOOPBACK_EN; + else + tmp_val &= ~CMD_CFG_LOOPBACK_EN; + WRITE_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr)), tmp_val); + + iounmap(UINT_TO_PTR(base_addr)); + + return 0; +#else + _fmt_err("TGEC don't have internal-loopback.\n"); + return -EPERM; +#endif +} + +static int set_mac_int_loopback(struct fmt_port_s *fmt_port, bool en) +{ + int _err = 0; + + switch (fmt_port->port_type) { + + case e_IOC_FMT_PORT_T_RXTX: + /* 1G port */ + if (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS) + _err = set_1gmac_loopback(fmt_port, en); + /* 10g port */ + else if ((fmt_port->id >= FM_MAX_NUM_OF_1G_RX_PORTS) && + (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS + + FM_MAX_NUM_OF_10G_RX_PORTS)) { + + _err = set_10gmac_int_loopback(fmt_port, en); + } else + _err = -EINVAL; + break; + /* op port does not have MAC (loopback mode) */ + case e_IOC_FMT_PORT_T_OP: + + _err = 0; + break; + default: + + _err = -EPERM; + break; + } + + return _err; +} + +static void enqueue_fmt_frame( + struct fmt_port_s *fmt_port, + struct fmt_frame_s *p_fmt_frame) +{ + spinlock_t *rx_q_lock = NULL; + + rx_q_lock = &fmt_port->rx_q_lock; + + spin_lock(rx_q_lock); + list_add_tail(&p_fmt_frame->list, &fmt_port->rx_q); + spin_unlock(rx_q_lock); + +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_inc(&fmt_port->enqueue_to_rxq); +#endif +} + +static struct fmt_frame_s *dequeue_fmt_frame( + struct fmt_port_s *fmt_port) +{ + struct fmt_frame_s *p_fmt_frame = NULL; + spinlock_t *rx_q_lock = NULL; + + rx_q_lock = &fmt_port->rx_q_lock; + + spin_lock(rx_q_lock); + +#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) + + if (!list_empty(&fmt_port->rx_q)) { + p_fmt_frame = list_last_entry(&fmt_port->rx_q, + struct fmt_frame_s, + list); + list_del(&p_fmt_frame->list); + +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_inc(&fmt_port->dequeue_from_rxq); +#endif + } + + spin_unlock(rx_q_lock); + + return p_fmt_frame; +} + +/* eth-dev -to- fmt port association */ +struct fmt_port_s *match_dpa_to_fmt_port( + struct dpa_priv_s *dpa_priv) { + struct mac_device *mac_dev = dpa_priv->mac_dev; + struct fm_port *fm_port = (struct fm_port *) mac_dev; + struct fmt_port_s *fmt_port = NULL; + int i; + + _fmt_dbgr("calling...\n"); + + /* find the FM-test-port object */ + for (i = 0; i < IOC_FMT_MAX_NUM_OF_PORTS; i++) + if ((fm_test.ports[i].p_mac_dev && + mac_dev == fm_test.ports[i].p_mac_dev) || + fm_port == fm_test.ports[i].p_tx_port) { + + fmt_port = &fm_test.ports[i]; + break; + } + + _fmt_dbgr("called\n"); + return fmt_port; +} + +void dump_frame( + uint8_t *buffer, + uint32_t size) +{ +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + unsigned int i; + + for (i = 0; i < size; i++) { + if (i%16 == 0) + printk(KERN_DEBUG "\n"); + printk(KERN_DEBUG "%2x ", *(buffer+i)); + } +#endif + return; +} + +bool test_and_steal_frame(struct fmt_port_s *fmt_port, + uint32_t fqid, + uint8_t *buffer, + uint32_t size) +{ + struct fmt_frame_s *p_fmt_frame = NULL; + bool test_and_steal_frame_frame; + uint32_t data_offset; + uint32_t i; + + _fmt_dbgr("calling...\n"); + + if (!fmt_port || !fmt_port->p_rx_fm_port_dev) + return false; + + /* check watermark */ + test_and_steal_frame_frame = false; + for (i = 0; i < size; i++) { + uint64_t temp = *((uint64_t *)(buffer + i)); + + if (temp == (uint64_t) FMT_FRM_WATERMARK) { + _fmt_dbgr("watermark found!\n"); + test_and_steal_frame_frame = true; + break; + } + } + + if (!test_and_steal_frame_frame) { +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm); +#endif + _fmt_dbgr("NOT watermark found!\n"); + return false; + } + + /* do not enqueue the tx conf/err frames */ + if ((fqid == FMT_TX_CONF_Q) || (fqid == FMT_TX_ERR_Q)) + goto _test_and_steal_frame_return_true; + + _fmt_dbgr("on port %d got FMUC frame\n", fmt_port->id); + data_offset = FM_PORT_GetBufferDataOffset( + fmt_port->p_rx_fm_port_dev); + + p_fmt_frame = kmalloc(sizeof(struct fmt_frame_s), GFP_KERNEL); + + /* dump frame... no more space left on device */ + if (p_fmt_frame == NULL) { + _fmt_err("no space left on device!\n"); + goto _test_and_steal_frame_return_true; + } + + memset(p_fmt_frame, 0, sizeof(struct fmt_frame_s)); + p_fmt_frame->buff.p_data = kmalloc(size * sizeof(uint8_t), GFP_KERNEL); + + /* No more space left on device*/ + if (p_fmt_frame->buff.p_data == NULL) { + _fmt_err("no space left on device!\n"); + kfree(p_fmt_frame); + goto _test_and_steal_frame_return_true; + } + + p_fmt_frame->buff.size = size-data_offset; + p_fmt_frame->buff.qid = fqid; + + memcpy(p_fmt_frame->buff.p_data, + (uint8_t *)PTR_MOVE(buffer, data_offset), + p_fmt_frame->buff.size); + + memcpy(p_fmt_frame->buff.buff_context.fm_prs_res, + FM_PORT_GetBufferPrsResult(fmt_port->p_rx_fm_port_dev, + (char *)buffer), + 32); + + /* enqueue frame - this frame will go to us */ + enqueue_fmt_frame(fmt_port, p_fmt_frame); + +_test_and_steal_frame_return_true: + return true; +} + +static int fmt_fq_release(const struct qm_fd *fd) +{ + struct dpa_bp *_dpa_bp; + struct bm_buffer _bmb; + + if (fd->format == qm_fd_contig) { + _dpa_bp = dpa_bpid2pool(fd->bpid); + BUG_ON(IS_ERR(_dpa_bp)); + + _bmb.hi = fd->addr_hi; + _bmb.lo = fd->addr_lo; + + while (bman_release(_dpa_bp->pool, &_bmb, 1, 0)) + cpu_relax(); + + } else { + _fmt_err("frame not supported !\n"); + return -1; + } + + return 0; +} + +/* sync it w/ dpaa_eth.c: DPA_BP_HEAD */ +#define DPA_BP_HEADROOM (DPA_TX_PRIV_DATA_SIZE + \ + fm_get_rx_extra_headroom() + \ + DPA_PARSE_RESULTS_SIZE + \ + DPA_HASH_RESULTS_SIZE) +#define MAC_HEADER_LENGTH 14 +#define L2_AND_HEADROOM_OFF ((DPA_BP_HEADROOM) + (MAC_HEADER_LENGTH)) + +/* dpa ingress hooks definition */ +enum dpaa_eth_hook_result fmt_rx_default_hook( + struct sk_buff *skb, + struct net_device *net_dev, + u32 fqid) +{ + struct dpa_priv_s *dpa_priv = NULL; + struct fmt_port_s *fmt_port = NULL; + uint8_t *buffer; + uint32_t buffer_len; + + _fmt_dbgr("calling...\n"); + + dpa_priv = netdev_priv(net_dev); + fmt_port = match_dpa_to_fmt_port(dpa_priv); + + /* conversion from skb to fd: + * skb cames processed for L3, so we need to go back for + * layer 2 offset */ + buffer = (uint8_t *)(skb->data - ((int)L2_AND_HEADROOM_OFF)); + buffer_len = skb->len + ((int)L2_AND_HEADROOM_OFF); + + /* if is not out frame let dpa to handle it */ + if (test_and_steal_frame(fmt_port, + FMT_RX_DFLT_Q, + buffer, + buffer_len)) + goto _fmt_rx_default_hook_stolen; + + _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); + return DPAA_ETH_CONTINUE; + +_fmt_rx_default_hook_stolen: + dev_kfree_skb(skb); + + _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); + return DPAA_ETH_STOLEN; +} + +enum dpaa_eth_hook_result fmt_rx_error_hook( + struct net_device *net_dev, + const struct qm_fd *fd, + u32 fqid) +{ + struct dpa_priv_s *dpa_priv = NULL; + struct dpa_bp *dpa_bp = NULL; + struct fmt_port_s *fmt_port = NULL; + void *fd_virt_addr = NULL; + dma_addr_t addr = qm_fd_addr(fd); + + _fmt_dbgr("calling...\n"); + + dpa_priv = netdev_priv(net_dev); + fmt_port = match_dpa_to_fmt_port(dpa_priv); + + /* dpaa doesn't do this... we have to do it here */ + dpa_bp = dpa_bpid2pool(fd->bpid); + dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); + + fd_virt_addr = phys_to_virt(addr); + /* if is not out frame let dpa to handle it */ + if (test_and_steal_frame(fmt_port, + FMT_RX_ERR_Q, + fd_virt_addr, + fd->length20 + fd->offset)) { + goto _fmt_rx_error_hook_stolen; + } + + _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); + return DPAA_ETH_CONTINUE; + +_fmt_rx_error_hook_stolen: + /* the frame data doesn't matter, + * so, no mapping is needed */ + fmt_fq_release(fd); + + _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); + return DPAA_ETH_STOLEN; +} + +enum dpaa_eth_hook_result fmt_tx_confirm_hook( + struct net_device *net_dev, + const struct qm_fd *fd, + u32 fqid) +{ + struct dpa_priv_s *dpa_priv = NULL; + struct fmt_port_s *fmt_port = NULL; + dma_addr_t addr = qm_fd_addr(fd); + void *fd_virt_addr = NULL; + uint32_t fd_len = 0; + + _fmt_dbgr("calling...\n"); + + dpa_priv = netdev_priv(net_dev); + fmt_port = match_dpa_to_fmt_port(dpa_priv); + + fd_virt_addr = phys_to_virt(addr); + fd_len = fd->length20 + fd->offset; + + if (fd_len > fm_get_max_frm()) { + _fmt_err("tx confirm bad frame size: %u!\n", fd_len); + goto _fmt_tx_confirm_hook_continue; + } + + if (test_and_steal_frame(fmt_port, + FMT_TX_CONF_Q, + fd_virt_addr, + fd_len)) + goto _fmt_tx_confirm_hook_stolen; + +_fmt_tx_confirm_hook_continue: + _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); + return DPAA_ETH_CONTINUE; + +_fmt_tx_confirm_hook_stolen: + kfree(fd_virt_addr); + + _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); + return DPAA_ETH_STOLEN; +} + +enum dpaa_eth_hook_result fmt_tx_confirm_error_hook( + struct net_device *net_dev, + const struct qm_fd *fd, + u32 fqid) +{ + struct dpa_priv_s *dpa_priv = NULL; + struct fmt_port_s *fmt_port = NULL; + dma_addr_t addr = qm_fd_addr(fd); + void *fd_virt_addr = NULL; + uint32_t fd_len = 0; + + _fmt_dbgr("calling...\n"); + + dpa_priv = netdev_priv(net_dev); + fmt_port = match_dpa_to_fmt_port(dpa_priv); + + fd_virt_addr = phys_to_virt(addr); + fd_len = fd->length20 + fd->offset; + + if (fd_len > fm_get_max_frm()) { + _fmt_err("tx confirm err bad frame size: %u !\n", fd_len); + goto _priv_ingress_tx_err_continue; + } + + if (test_and_steal_frame(fmt_port, FMT_TX_ERR_Q, fd_virt_addr, fd_len)) + goto _priv_ingress_tx_err_stolen; + +_priv_ingress_tx_err_continue: + _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); + return DPAA_ETH_CONTINUE; + +_priv_ingress_tx_err_stolen: + kfree(fd_virt_addr); + + _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); + return DPAA_ETH_STOLEN; +} + +/* egress callbacks definition */ +enum qman_cb_dqrr_result fmt_egress_dqrr( + struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dqrr) +{ + /* this callback should never be called */ + BUG(); + return qman_cb_dqrr_consume; +} + +static void fmt_egress_error_dqrr( + struct qman_portal *p, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + uint8_t *fd_virt_addr = NULL; + + /* tx failure, on the ern callback - release buffer */ + fd_virt_addr = (uint8_t *)phys_to_virt(qm_fd_addr(&msg->ern.fd)); + kfree(fd_virt_addr); + + return; +} + +static const struct qman_fq fmt_egress_fq = { + .cb = { .dqrr = fmt_egress_dqrr, + .ern = fmt_egress_error_dqrr, + .fqs = NULL} +}; + +int fmt_fq_alloc( + struct fmt_fqs_s *fmt_fqs, + const struct qman_fq *qman_fq, + uint32_t fqid, uint32_t flags, + uint16_t channel, uint8_t wq) +{ + int _errno = 0; + + _fmt_dbg("calling...\n"); + + fmt_fqs->fq_base = *qman_fq; + + if (fqid == 0) { + flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; + flags &= ~QMAN_FQ_FLAG_NO_MODIFY; + } else + flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; + + fmt_fqs->init = !(flags & QMAN_FQ_FLAG_NO_MODIFY); + + _errno = qman_create_fq(fqid, flags, &fmt_fqs->fq_base); + if (_errno < 0) { + _fmt_err("frame queues create failed.\n"); + return -EINVAL; + } + + if (fmt_fqs->init) { + struct qm_mcc_initfq initfq; + + initfq.we_mask = QM_INITFQ_WE_DESTWQ; + initfq.fqd.dest.channel = channel; + initfq.fqd.dest.wq = wq; + + _errno = qman_init_fq(&fmt_fqs->fq_base, + QMAN_INITFQ_FLAG_SCHED, + &initfq); + if (_errno < 0) { + _fmt_err("frame queues init erorr.\n"); + qman_destroy_fq(&fmt_fqs->fq_base, 0); + return -EINVAL; + } + } + + _fmt_dbg("called.\n"); + return 0; +} + +static int fmt_fq_free(struct fmt_fqs_s *fmt_fq) +{ + int _err = 0; + + _fmt_dbg("calling...\n"); + + if (fmt_fq->init) { + _err = qman_retire_fq(&fmt_fq->fq_base, NULL); + if (unlikely(_err < 0)) + _fmt_err("qman_retire_fq(%u) = %d\n", + qman_fq_fqid(&fmt_fq->fq_base), _err); + + _err = qman_oos_fq(&fmt_fq->fq_base); + if (unlikely(_err < 0)) + _fmt_err("qman_oos_fq(%u) = %d\n", + qman_fq_fqid(&fmt_fq->fq_base), _err); + } + + qman_destroy_fq(&fmt_fq->fq_base, 0); + + _fmt_dbg("called.\n"); + return _err; +} + +/* private pcd dqrr calbacks */ +static enum qman_cb_dqrr_result fmt_pcd_dqrr( + struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + struct dpa_bp *dpa_bp = NULL; + dma_addr_t addr = qm_fd_addr(&dq->fd); + uint8_t *fd_virt_addr = NULL; + struct fmt_port_s *fmt_port; + struct fmt_port_pcd_s *fmt_port_pcd; + uint32_t relative_fqid = 0; + uint32_t fd_len = 0; + + _fmt_dbgr("calling...\n"); + + /* upcast - from pcd_alloc_fq */ + fmt_port = ((struct fmt_fqs_s *)fq)->fmt_port_priv; + if (!fmt_port) { + _fmt_err(" wrong fmt port -to- fq match.\n"); + goto _fmt_pcd_dqrr_return; + } + fmt_port_pcd = &fmt_port->fmt_port_pcd; + + relative_fqid = dq->fqid - fmt_port_pcd->fqid_base; + _fmt_dbgr("pcd dqrr got frame on relative fq:%u@base:%u\n", + relative_fqid, fmt_port_pcd->fqid_base); + + fd_len = dq->fd.length20 + dq->fd.offset; + + if (fd_len > fm_get_max_frm()) { + _fmt_err("pcd dqrr wrong frame size: %u (%u:%u)!\n", + fd_len, dq->fd.length20, dq->fd.offset); + goto _fmt_pcd_dqrr_return; + } + + dpa_bp = dpa_bpid2pool(dq->fd.bpid); + dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); + + fd_virt_addr = phys_to_virt(addr); + if (!test_and_steal_frame(fmt_port, relative_fqid, fd_virt_addr, + fd_len)) { + +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm); +#endif + _fmt_wrn("pcd dqrr unrecognized frame@fqid: %u," + " frame len: %u (dropped).\n", + dq->fqid, dq->fd.length20); + dump_frame(fd_virt_addr, fd_len); + } + +_fmt_pcd_dqrr_return: + /* no need to map again here */ + fmt_fq_release(&dq->fd); + + _fmt_dbgr("calle.\n"); + return qman_cb_dqrr_consume; +} + +static void fmt_pcd_err_dqrr( + struct qman_portal *qm, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + _fmt_err("this callback should never be called.\n"); + BUG(); + return; +} + +static void fmt_pcd_fqs_dqrr( + struct qman_portal *qm, + struct qman_fq *fq, + const struct qm_mr_entry *msg) +{ + _fmt_dbg(" fq state(0x%x)@fqid(%u.\n", msg->fq.fqs, msg->fq.fqid); + return; +} + +/* private pcd queue template */ +static const struct qman_fq pcd_fq = { + .cb = { .dqrr = fmt_pcd_dqrr, + .ern = fmt_pcd_err_dqrr, + .fqs = fmt_pcd_fqs_dqrr} +}; + +/* defined as weak in dpaa driver. */ +/* ! parameters come from IOCTL call - US */ +int dpa_alloc_pcd_fqids( + struct device *dev, + uint32_t num, uint8_t alignment, + uint32_t *base_fqid) +{ + int _err = 0, i; + struct net_device *net_dev = NULL; + struct dpa_priv_s *dpa_priv = NULL; + struct fmt_port_pcd_s *fmt_port_pcd = NULL; + struct fmt_fqs_s *fmt_fqs = NULL; + struct fmt_port_s *fmt_port = NULL; + int num_allocated = 0; + + _fmt_dbg("calling...\n"); + + net_dev = (typeof(net_dev))dev_get_drvdata(dev); + dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev); + + if (!netif_msg_probe(dpa_priv)) { + _fmt_err("dpa not probe.\n"); + _err = -ENODEV; + goto _pcd_alloc_fqs_err; + } + + fmt_port = match_dpa_to_fmt_port(dpa_priv); + if (!fmt_port) { + _fmt_err("fmt port not found."); + _err = -EINVAL; + goto _pcd_alloc_fqs_err; + } + + fmt_port_pcd = &fmt_port->fmt_port_pcd; + + num_allocated = qman_alloc_fqid_range(base_fqid, num, alignment, 0); + + if ((num_allocated <= 0) || + (num_allocated < num) || + (alignment && (*base_fqid) % alignment)) { + *base_fqid = 0; + _fmt_err("Failed to alloc pcd fqs rang.\n"); + _err = -EINVAL; + goto _pcd_alloc_fqs_err; + } + + _fmt_dbg("wanted %d fqs(align %d), got %d fqids@%u.\n", + num, alignment, num_allocated, *base_fqid); + + /* alloc pcd queues */ + fmt_port_pcd->fmt_pcd_fqs = kmalloc(num_allocated * + sizeof(struct fmt_fqs_s), + GFP_KERNEL); + fmt_port_pcd->num_queues = num_allocated; + fmt_port_pcd->fqid_base = *base_fqid; + fmt_fqs = fmt_port_pcd->fmt_pcd_fqs; + + /* alloc the pcd queues */ + for (i = 0; i < num_allocated; i++, fmt_fqs++) { + _err = fmt_fq_alloc( + fmt_fqs, + &pcd_fq, + (*base_fqid) + i, QMAN_FQ_FLAG_NO_ENQUEUE, + dpa_priv->channel, 7); + + if (_err < 0) + goto _pcd_alloc_fqs_err; + + /* upcast to identify from where the frames came from */ + fmt_fqs->fmt_port_priv = fmt_port; + } + + _fmt_dbg("called.\n"); + return _err; +_pcd_alloc_fqs_err: + if (num_allocated > 0) + qman_release_fqid_range(*base_fqid, num_allocated); + /*TODO: free fmt_pcd_fqs if are any */ + + _fmt_dbg("called(_err:%d).\n", _err); + return _err; +} + +/* defined as weak in dpaa driver. */ +int dpa_free_pcd_fqids( + struct device *dev, + uint32_t base_fqid) +{ + + int _err = 0, i; + struct net_device *net_dev = NULL; + struct dpa_priv_s *dpa_priv = NULL; + struct fmt_port_pcd_s *fmt_port_pcd = NULL; + struct fmt_fqs_s *fmt_fqs = NULL; + struct fmt_port_s *fmt_port = NULL; + int num_allocated = 0; + + _fmt_dbg("calling...\n"); + + net_dev = (typeof(net_dev))dev_get_drvdata(dev); + dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev); + + if (!netif_msg_probe(dpa_priv)) { + _fmt_err("dpa not probe.\n"); + _err = -ENODEV; + goto _pcd_free_fqs_err; + } + + fmt_port = match_dpa_to_fmt_port(dpa_priv); + if (!fmt_port) { + _fmt_err("fmt port not found."); + _err = -EINVAL; + goto _pcd_free_fqs_err; + } + + fmt_port_pcd = &fmt_port->fmt_port_pcd; + num_allocated = fmt_port_pcd->num_queues; + fmt_fqs = fmt_port_pcd->fmt_pcd_fqs; + + for (i = 0; i < num_allocated; i++, fmt_fqs++) + fmt_fq_free(fmt_fqs); + + qman_release_fqid_range(base_fqid,num_allocated); + + kfree(fmt_port_pcd->fmt_pcd_fqs); + memset(fmt_port_pcd, 0, sizeof(*fmt_port_pcd)); + + /* debugging stuff */ +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + _fmt_dbg(" portid: %u.\n", fmt_port->id); + _fmt_dbg(" frames enqueue to qman: %u.\n", + atomic_read(&fmt_port->enqueue_to_qman_frm)); + _fmt_dbg(" frames enqueue to rxq: %u.\n", + atomic_read(&fmt_port->enqueue_to_rxq)); + _fmt_dbg(" frames dequeue from rxq: %u.\n", + atomic_read(&fmt_port->dequeue_from_rxq)); + _fmt_dbg(" frames not enqueue to rxq - wrong frm: %u.\n", + atomic_read(&fmt_port->not_enqueue_to_rxq_wrong_frm)); + atomic_set(&fmt_port->enqueue_to_qman_frm, 0); + atomic_set(&fmt_port->enqueue_to_rxq, 0); + atomic_set(&fmt_port->dequeue_from_rxq, 0); + atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0); +#endif + return 0; + +_pcd_free_fqs_err: + return _err; +} + +static int fmt_port_init( + struct fmt_port_s *fmt_port, + ioc_fmt_port_param_t *p_Params) +{ + struct device_node *fm_node, *fm_port_node; + const uint32_t *uint32_prop; + int _errno = 0, lenp = 0, i; + static struct of_device_id fm_node_of_match[] = { + { .compatible = "fsl,fman", }, + { /* end of list */ }, + }; + + _fmt_dbg("calling...\n"); + + /* init send/receive tu US list */ + INIT_LIST_HEAD(&fmt_port->rx_q); + + /* check parameters */ + if (p_Params->num_tx_queues > FMAN_TEST_MAX_TX_FQS || + p_Params->fm_port_id > IOC_FMT_MAX_NUM_OF_PORTS) { + _fmt_dbg("wrong test parameters.\n"); + return -EINVAL; + } + + /* set port parameters */ + fmt_port->num_of_tx_fqs = p_Params->num_tx_queues; + fmt_port->id = p_Params->fm_port_id; + fmt_port->port_type = p_Params->fm_port_type; + fmt_port->diag = e_IOC_DIAG_MODE_NONE; + + /* init debugging stuff */ +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_set(&fmt_port->enqueue_to_qman_frm, 0); + atomic_set(&fmt_port->enqueue_to_rxq, 0); + atomic_set(&fmt_port->dequeue_from_rxq, 0); + atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0); +#endif + + /* TODO: This should be done at probe time not at runtime + * very ugly function */ + /* fill fmt port properties from dts */ + for_each_matching_node(fm_node, fm_node_of_match) { + + uint32_prop = (uint32_t *)of_get_property(fm_node, + "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + _fmt_wrn("of_get_property(%s, cell-index) invalid", + fm_node->full_name); + return -EINVAL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) { + _fmt_wrn("of_get_property(%s, cell-index) invalid", + fm_node->full_name); + return -EINVAL; + } + + if (*uint32_prop == p_Params->fm_id) { + struct resource res; + + /* Get the FM address */ + _errno = of_address_to_resource(fm_node, 0, &res); + if (unlikely(_errno < 0)) { + _fmt_wrn("of_address_to_resource() = %u.\n", _errno); + return -EINVAL; + } + + fmt_port->fm_phys_base_addr = res.start; + + for_each_child_of_node(fm_node, fm_port_node) { + struct platform_device *of_dev; + + if (!of_device_is_available(fm_port_node)) + continue; + + uint32_prop = (uint32_t *)of_get_property( + fm_port_node, + "cell-index", + &lenp); + if (uint32_prop == NULL) + continue; + + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-oh") && + (fmt_port->port_type == e_IOC_FMT_PORT_T_OP)) { + + if (*uint32_prop == fmt_port->id) { + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) { + _fmt_wrn("fm id invalid\n"); + return -EINVAL; + } + + fmt_port->p_tx_port = + fm_port_bind(&of_dev->dev); + fmt_port->p_tx_fm_port_dev = + (void *)fm_port_get_handle( + fmt_port->p_tx_port); + fmt_port->p_rx_port = + fmt_port->p_tx_port; + fmt_port->p_rx_fm_port_dev = + fmt_port->p_tx_fm_port_dev; + fmt_port->p_mac_dev = NULL; + break; + } + } else if ((*uint32_prop == fmt_port->id) && + fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) { + + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) { + _fmt_wrn("dtb fm id invalid value"); + return -EINVAL; + } + + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-tx")) { + fmt_port->p_tx_port = + fm_port_bind(&of_dev->dev); + fmt_port->p_tx_fm_port_dev = (void *) + fm_port_get_handle( + fmt_port->p_tx_port); + } else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-rx")) { + fmt_port->p_rx_port = + fm_port_bind(&of_dev->dev); + fmt_port->p_rx_fm_port_dev = (void *) + fm_port_get_handle( + fmt_port->p_rx_port); + } else if (of_device_is_compatible(fm_port_node, + "fsl,fman-1g-mac") || + of_device_is_compatible(fm_port_node, + "fsl,fman-memac")) + fmt_port->p_mac_dev = + (typeof(fmt_port->p_mac_dev)) + dev_get_drvdata(&of_dev->dev); + else + continue; + + if (fmt_port->p_tx_fm_port_dev && + fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev) + break; + } else if (((*uint32_prop + FM_MAX_NUM_OF_1G_RX_PORTS) == + fmt_port->id) && + fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) { + + of_dev = of_find_device_by_node(fm_port_node); + if (unlikely(of_dev == NULL)) { + _fmt_wrn("dtb fm id invalid value\n"); + return -EINVAL; + } + + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-tx")) { + fmt_port->p_tx_port = + fm_port_bind(&of_dev->dev); + fmt_port->p_tx_fm_port_dev = (void *) + fm_port_get_handle( + fmt_port->p_tx_port); + } else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-rx")) { + fmt_port->p_rx_port = + fm_port_bind(&of_dev->dev); + fmt_port->p_rx_fm_port_dev = (void *) + fm_port_get_handle( + fmt_port->p_rx_port); + } else if (of_device_is_compatible(fm_port_node, + "fsl,fman-10g-mac") || + of_device_is_compatible(fm_port_node, + "fsl,fman-memac")) + fmt_port->p_mac_dev = + (typeof(fmt_port->p_mac_dev)) + dev_get_drvdata(&of_dev->dev); + else + continue; + + if (fmt_port->p_tx_fm_port_dev && + fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev) + break; + } + } /* for_each_child */ + } + } /* for each matching node */ + + if (fmt_port->p_tx_fm_port_dev == 0 || + fmt_port->p_rx_fm_port_dev == 0) { + + _fmt_err("bad fm port pointers.\n"); + return -EINVAL; + } + + _fmt_dbg("alloc %u tx queues.\n", fmt_port->num_of_tx_fqs); + + /* init fman test egress dynamic frame queues */ + for (i = 0; i < fmt_port->num_of_tx_fqs; i++) { + int _errno; + _errno = fmt_fq_alloc( + &fmt_port->p_tx_fqs[i], + &fmt_egress_fq, + 0, + QMAN_FQ_FLAG_TO_DCPORTAL, + fm_get_tx_port_channel(fmt_port->p_tx_port), + i); + + if (_errno < 0) { + _fmt_err("tx queues allocation failed.\n"); + /* TODO: memory leak here if 1 queue is allocated and + * next queues are failing ... */ + return -EINVAL; + } + } + + /* port is valid and ready to use. */ + fmt_port->valid = TRUE; + + _fmt_dbg("called.\n"); + return 0; +} + +/* fm test chardev functions */ +static int fmt_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + + _fmt_dbg("calling...\n"); + + if (file->private_data != NULL) + return 0; + + /* The minor represent the port number. + * Set the port structure accordingly, thus all the operations + * will be done on this port. */ + if ((minor >= DEV_FM_TEST_PORTS_MINOR_BASE) && + (minor < DEV_FM_TEST_MAX_MINORS)) + file->private_data = &fm_test.ports[minor]; + else + return -ENXIO; + + _fmt_dbg("called.\n"); + return 0; +} + +static int fmt_close(struct inode *inode, struct file *file) +{ + struct fmt_port_s *fmt_port = NULL; + struct fmt_frame_s *fmt_frame = NULL; + + int err = 0; + + _fmt_dbg("calling...\n"); + + fmt_port = file->private_data; + if (!fmt_port) + return -ENODEV; + + /* Close the current test port by invalidating it. */ + fmt_port->valid = FALSE; + + /* clean the fmt port queue */ + while ((fmt_frame = dequeue_fmt_frame(fmt_port)) != NULL) { + if (fmt_frame && fmt_frame->buff.p_data){ + kfree(fmt_frame->buff.p_data); + kfree(fmt_frame); + } + } + + /* !!! the qman queues are cleaning from fm_ioctl... + * - very ugly */ + + _fmt_dbg("called.\n"); + return err; +} + +static int fmt_ioctls(unsigned int minor, + struct file *file, + unsigned int cmd, + unsigned long arg, + bool compat) +{ + struct fmt_port_s *fmt_port = NULL; + + _fmt_dbg("IOCTL minor:%u " + " arg:0x%08lx ioctl cmd (0x%08x):(0x%02x:0x%02x.\n", + minor, arg, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); + + fmt_port = file->private_data; + if (!fmt_port) { + _fmt_err("invalid fmt port.\n"); + return -ENODEV; + } + + /* set test type properly */ + if (compat) + fmt_port->compat_test_type = true; + else + fmt_port->compat_test_type = false; + + switch (cmd) { + case FMT_PORT_IOC_INIT: + { + ioc_fmt_port_param_t param; + + if (fmt_port->valid) { + _fmt_wrn("port is already initialized.\n"); + return -EFAULT; + } +#if defined(CONFIG_COMPAT) + if (compat) { + if (copy_from_user(¶m, + (ioc_fmt_port_param_t *)compat_ptr(arg), + sizeof(ioc_fmt_port_param_t))) + + return -EFAULT; + } else +#endif + { + if (copy_from_user(¶m, + (ioc_fmt_port_param_t *) arg, + sizeof(ioc_fmt_port_param_t))) + + return -EFAULT; + } + + return fmt_port_init(fmt_port, ¶m); + } + + case FMT_PORT_IOC_SET_DIAG_MODE: + if (get_user(fmt_port->diag, (ioc_diag_mode *)arg)) + return -EFAULT; + + if (fmt_port->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK) + return set_mac_int_loopback(fmt_port, TRUE); + else + return set_mac_int_loopback(fmt_port, FALSE); + break; + + case FMT_PORT_IOC_SET_DPAECHO_MODE: + case FMT_PORT_IOC_SET_IP_HEADER_MANIP: + default: + _fmt_wrn("ioctl unimplemented minor:%u@ioctl" + " cmd:0x%08x(type:0x%02x, nr:0x%02x.\n", + minor, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); + return -EFAULT; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long fmt_compat_ioctl( + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + + _fmt_dbg("calling...\n"); + return fmt_ioctls(minor, file, cmd, arg, true); +} +#endif + +static long fmt_ioctl( + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + unsigned int res; + + _fmt_dbg("calling...\n"); + + fm_mutex_lock(); + res = fmt_ioctls(minor, file, cmd, arg, false); + fm_mutex_unlock(); + + _fmt_dbg("called.\n"); + + return res; +} + +#ifdef CONFIG_COMPAT +void copy_compat_test_frame_buffer( + ioc_fmt_buff_desc_t *buff, + ioc_fmt_compat_buff_desc_t *compat_buff) +{ + compat_buff->qid = buff->qid; + compat_buff->p_data = ptr_to_compat(buff->p_data); + compat_buff->size = buff->size; + compat_buff->status = buff->status; + + compat_buff->buff_context.p_user_priv = + ptr_to_compat(buff->buff_context.p_user_priv); + memcpy(compat_buff->buff_context.fm_prs_res, + buff->buff_context.fm_prs_res, + FM_PRS_MAX * sizeof(uint8_t)); + memcpy(compat_buff->buff_context.fm_time_stamp, + buff->buff_context.fm_time_stamp, + FM_TIME_STAMP_MAX * sizeof(uint8_t)); +} +#endif + +ssize_t fmt_read( + struct file *file, + char __user *buf, + size_t size, + loff_t *ppos) +{ + struct fmt_port_s *fmt_port = NULL; + struct fmt_frame_s *p_fmt_frame = NULL; + ssize_t cnt = 0; + + fmt_port = file->private_data; + if (!fmt_port || !fmt_port->valid) { + _fmt_err("fmt port not valid!\n"); + return -ENODEV; + } + + p_fmt_frame = dequeue_fmt_frame(fmt_port); + if (p_fmt_frame == NULL) + return 0; + + _fmt_dbgr("calling...\n"); + +#ifdef CONFIG_COMPAT + if (fmt_port->compat_test_type){ + cnt = sizeof(ioc_fmt_compat_buff_desc_t); + } + else +#endif + { + cnt = sizeof(ioc_fmt_buff_desc_t); + } + + if (size < cnt) { + _fmt_err("illegal buffer-size!\n"); + cnt = 0; + goto _fmt_read_return; + } + + /* Copy structure */ +#ifdef CONFIG_COMPAT + if (fmt_port->compat_test_type) { + { + ioc_fmt_compat_buff_desc_t compat_buff; + copy_compat_test_frame_buffer(&p_fmt_frame->buff, + &compat_buff); + + if (copy_to_user(buf, &compat_buff, cnt)) { + _fmt_err("copy_to_user failed!\n"); + goto _fmt_read_return; + } + } + + ((ioc_fmt_compat_buff_desc_t *)buf)->p_data = + ptr_to_compat(buf+sizeof(ioc_fmt_compat_buff_desc_t)); + cnt += MIN(p_fmt_frame->buff.size, size-cnt); + } else +#endif + { + if (copy_to_user(buf, &p_fmt_frame->buff, cnt)) { + _fmt_err("copy_to_user failed!\n"); + goto _fmt_read_return; + } + + ((ioc_fmt_buff_desc_t *)buf)->p_data = + buf + sizeof(ioc_fmt_buff_desc_t); + cnt += MIN(p_fmt_frame->buff.size, size-cnt); + } + + if (size < cnt) { + _fmt_err("illegal buffer-size!\n"); + goto _fmt_read_return; + } + + /* copy frame */ +#ifdef CONFIG_COMPAT + if (fmt_port->compat_test_type) { + if (copy_to_user(buf+sizeof(ioc_fmt_compat_buff_desc_t), + p_fmt_frame->buff.p_data, cnt)) { + _fmt_err("copy_to_user failed!\n"); + goto _fmt_read_return; + } + } else +#endif + { + if (copy_to_user(buf+sizeof(ioc_fmt_buff_desc_t), + p_fmt_frame->buff.p_data, cnt)) { + _fmt_err("copy_to_user failed!\n"); + goto _fmt_read_return; + } + } + +_fmt_read_return: + kfree(p_fmt_frame->buff.p_data); + kfree(p_fmt_frame); + + _fmt_dbgr("called.\n"); + return cnt; +} + +ssize_t fmt_write( + struct file *file, + const char __user *buf, + size_t size, + loff_t *ppos) +{ + struct fmt_port_s *fmt_port = NULL; + ioc_fmt_buff_desc_t buff_desc; +#ifdef CONFIG_COMPAT + ioc_fmt_compat_buff_desc_t buff_desc_compat; +#endif + uint8_t *p_data = NULL; + uint32_t data_offset; + int _errno; + t_DpaaFD fd; + + _fmt_dbgr("calling...\n"); + + fmt_port = file->private_data; + if (!fmt_port || !fmt_port->valid) { + _fmt_err("fmt port not valid.\n"); + return -EINVAL; + } + + /* If Compat (32B UserSpace - 64B KernelSpace) */ +#ifdef CONFIG_COMPAT + if (fmt_port->compat_test_type) { + if (size < sizeof(ioc_fmt_compat_buff_desc_t)) { + _fmt_err("invalid buff_desc size.\n"); + return -EFAULT; + } + + if (copy_from_user(&buff_desc_compat, buf, + sizeof(ioc_fmt_compat_buff_desc_t))) + return -EFAULT; + + buff_desc.qid = buff_desc_compat.qid; + buff_desc.p_data = compat_ptr(buff_desc_compat.p_data); + buff_desc.size = buff_desc_compat.size; + buff_desc.status = buff_desc_compat.status; + + buff_desc.buff_context.p_user_priv = + compat_ptr(buff_desc_compat.buff_context.p_user_priv); + memcpy(buff_desc.buff_context.fm_prs_res, + buff_desc_compat.buff_context.fm_prs_res, + FM_PRS_MAX * sizeof(uint8_t)); + memcpy(buff_desc.buff_context.fm_time_stamp, + buff_desc_compat.buff_context.fm_time_stamp, + FM_TIME_STAMP_MAX * sizeof(uint8_t)); + } else +#endif + { + if (size < sizeof(ioc_fmt_buff_desc_t)) { + _fmt_err("invalid buff_desc size.\n"); + return -EFAULT; + } + + if (copy_from_user(&buff_desc, (ioc_fmt_buff_desc_t *)buf, + sizeof(ioc_fmt_buff_desc_t))) + return -EFAULT; + } + + data_offset = FM_PORT_GetBufferDataOffset(fmt_port->p_tx_fm_port_dev); + p_data = kmalloc(buff_desc.size+data_offset, GFP_KERNEL); + if (!p_data) + return -ENOMEM; + + /* If Compat (32UserSpace - 64KernelSpace) the buff_desc.p_data is ok */ + if (copy_from_user((uint8_t *)PTR_MOVE(p_data, data_offset), + buff_desc.p_data, + buff_desc.size)) { + kfree(p_data); + return -EFAULT; + } + + /* TODO: dma_map_single here (cannnot access the bpool struct) */ + + /* prepare fd */ + memset(&fd, 0, sizeof(fd)); + DPAA_FD_SET_ADDR(&fd, p_data); + DPAA_FD_SET_OFFSET(&fd, data_offset); + DPAA_FD_SET_LENGTH(&fd, buff_desc.size); + + _errno = qman_enqueue(&fmt_port->p_tx_fqs[buff_desc.qid].fq_base, + (struct qm_fd *)&fd, 0); + if (_errno) { + buff_desc.status = (uint32_t)_errno; + if (copy_to_user((ioc_fmt_buff_desc_t *)buf, &buff_desc, + sizeof(ioc_fmt_buff_desc_t))) { + kfree(p_data); + return -EFAULT; + } + } + + /* for debugging */ +#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) + atomic_inc(&fmt_port->enqueue_to_qman_frm); +#endif + _fmt_dbgr("called.\n"); + return buff_desc.size; +} + +/* fm test character device definition */ +static const struct file_operations fmt_fops = +{ + .owner = THIS_MODULE, +#ifdef CONFIG_COMPAT + .compat_ioctl = fmt_compat_ioctl, +#endif + .unlocked_ioctl = fmt_ioctl, + .open = fmt_open, + .release = fmt_close, + .read = fmt_read, + .write = fmt_write, +}; + +static int fmt_init(void) +{ + int id; + + _fmt_dbg("calling...\n"); + + /* Register to the /dev for IOCTL API */ + /* Register dynamically a new major number for the character device: */ + fm_test.major = register_chrdev(0, DEV_FM_TEST_NAME, &fmt_fops); + if (fm_test.major <= 0) { + _fmt_wrn("Failed to allocate major number for device %s.\n", + DEV_FM_TEST_NAME); + return -ENODEV; + } + + /* Creating class for FMan_test */ + fm_test.fmt_class = class_create(THIS_MODULE, DEV_FM_TEST_NAME); + if (IS_ERR(fm_test.fmt_class)) { + unregister_chrdev(fm_test.major, DEV_FM_TEST_NAME); + _fmt_wrn("Error creating %s class.\n", DEV_FM_TEST_NAME); + return -ENODEV; + } + + for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) + if (NULL == device_create(fm_test.fmt_class, NULL, + MKDEV(fm_test.major, + DEV_FM_TEST_PORTS_MINOR_BASE + id), NULL, + DEV_FM_TEST_NAME "%d", id)) { + + _fmt_err("Error creating %s device.\n", + DEV_FM_TEST_NAME); + return -ENODEV; + } + + return 0; +} + +static void fmt_free(void) +{ + int id; + + for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) + device_destroy(fm_test.fmt_class, MKDEV(fm_test.major, + DEV_FM_TEST_PORTS_MINOR_BASE + id)); + class_destroy(fm_test.fmt_class); +} + +static int __init __cold fmt_load(void) +{ + struct dpaa_eth_hooks_s priv_dpaa_eth_hooks; + + /* set dpaa hooks for default queues */ + memset(&priv_dpaa_eth_hooks, 0, sizeof(priv_dpaa_eth_hooks)); + priv_dpaa_eth_hooks.rx_default = fmt_rx_default_hook; + priv_dpaa_eth_hooks.rx_error = fmt_rx_error_hook; + priv_dpaa_eth_hooks.tx_confirm = fmt_tx_confirm_hook; + priv_dpaa_eth_hooks.tx_error = fmt_tx_confirm_error_hook; + + fsl_dpaa_eth_set_hooks(&priv_dpaa_eth_hooks); + + /* initialize the fman test environment */ + if (fmt_init() < 0) { + _fmt_err("Failed to init FM-test modul.\n"); + fmt_free(); + return -ENODEV; + } + + _fmt_inf("FSL FM test module loaded.\n"); + + return 0; +} + +static void __exit __cold fmt_unload(void) +{ + fmt_free(); + _fmt_inf("FSL FM test module unloaded.\n"); +} + +module_init(fmt_load); +module_exit(fmt_unload); diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.c new file mode 100644 index 0000000..b20f3a5 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.c @@ -0,0 +1,1308 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_fm.c + @Author Shlomi Gridish + @Description FM Linux wrapper functions. +*/ + +#include <linux/version.h> +#include <linux/slab.h> +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/of_platform.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <asm/qe.h> /* For struct qe_firmware */ +#include <sysdev/fsl_soc.h> +#include <linux/stat.h> /* For file access mask */ +#include <linux/skbuff.h> + +/* NetCommSw Headers --------------- */ +#include "std_ext.h" +#include "error_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "sys_io_ext.h" + +#include "fm_ioctls.h" + +#include "lnxwrp_fm.h" +#include "lnxwrp_resources.h" +#include "lnxwrp_sysfs_fm.h" +#include "lnxwrp_sysfs_fm_port.h" + +/* export LLD API to DPAA offload kernel module */ +#if defined(CONFIG_FSL_DPA_OFFLOAD_MODULE) +#include "lnxwrp_exp_sym.h" +#endif + +extern struct device_node *GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node, + e_FmPortType portType, + uint8_t portId); + +#define PROC_PRINT(args...) offset += sprintf(buf+offset,args) + +#define ADD_ADV_CONFIG_NO_RET(_func, _param) \ + do { \ + if (i<max){ \ + p_Entry = &p_Entrys[i]; \ + p_Entry->p_Function = _func; \ + _param \ + i++; \ + } \ + else \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ + ("Number of advanced-configuration entries exceeded"));\ + } while (0) + +/* Bootarg used to override the Kconfig FSL_FM_MAX_FRAME_SIZE value */ +#define FSL_FM_MAX_FRM_BOOTARG "fsl_fm_max_frm" + +/* Bootarg used to override FSL_FM_RX_EXTRA_HEADROOM Kconfig value */ +#define FSL_FM_RX_EXTRA_HEADROOM_BOOTARG "fsl_fm_rx_extra_headroom" + +/* Maximum value for the fsl_fm_rx_extra_headroom bootarg */ +#define FSL_FM_RX_EXTRA_HEADROOM_MAX 384 + +/* + * Max frame size, across all interfaces. + * Configurable from Kconfig or bootargs, to avoid allocating + * oversized (socket) buffers when not using jumbo frames. + * Must be large enough to accomodate the network MTU, but small enough + * to avoid wasting skb memory. + * + * Could be overridden once, at boot-time, via the + * fm_set_max_frm() callback. + */ +int fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; + +/* + * Extra headroom for Rx buffers. + * FMan is instructed to allocate, on the Rx path, this amount of + * space at the beginning of a data buffer, beside the DPA private + * data area and the IC fields. + * Does not impact Tx buffer layout. + * + * Configurable from Kconfig or bootargs. Zero by default, it's needed + * on particular forwarding scenarios that add extra headers to the + * forwarded frame. + */ +int fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; + +static t_LnxWrpFm lnxWrpFm; + +int fm_get_max_frm() +{ + return fsl_fm_max_frm; +} + +int fm_get_rx_extra_headroom() +{ + return fsl_fm_rx_extra_headroom; +} + +static int __init fm_set_max_frm(char *str) +{ + int ret = 0; + + ret = get_option(&str, &fsl_fm_max_frm); + if (ret != 1) { + /* + * This will only work if CONFIG_EARLY_PRINTK is compiled in, + * and something like "earlyprintk=serial,uart0,115200" is + * specified in the bootargs + */ + printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; " + "will use the default FSL_FM_MAX_FRAME_SIZE (%d) " + "from Kconfig.\n", FSL_FM_MAX_FRM_BOOTARG, + CONFIG_FSL_FM_MAX_FRAME_SIZE); + + fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; + return 1; + } + + /* Don't allow invalid bootargs; fallback to the Kconfig value */ + if (fsl_fm_max_frm < 64 || fsl_fm_max_frm > 9600) { + printk(KERN_WARNING "Invalid %s=%d in bootargs, valid range is " + "64-9600. Falling back to the FSL_FM_MAX_FRAME_SIZE (%d) " + "from Kconfig.\n", + FSL_FM_MAX_FRM_BOOTARG, fsl_fm_max_frm, + CONFIG_FSL_FM_MAX_FRAME_SIZE); + + fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; + return 1; + } + + printk(KERN_INFO "Using fsl_fm_max_frm=%d from bootargs\n", + fsl_fm_max_frm); + return 0; +} +early_param(FSL_FM_MAX_FRM_BOOTARG, fm_set_max_frm); + +static int __init fm_set_rx_extra_headroom(char *str) +{ + int ret; + + ret = get_option(&str, &fsl_fm_rx_extra_headroom); + + if (ret != 1) { + printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; " + "will use the default FSL_FM_RX_EXTRA_HEADROOM (%d) " + "from Kconfig.\n", FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, + CONFIG_FSL_FM_RX_EXTRA_HEADROOM); + fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; + + return 1; + } + + if (fsl_fm_rx_extra_headroom < 0 || + fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) { + printk(KERN_WARNING "Invalid value for %s=<int> prop in " + "bootargs; will use the default " + "FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n", + FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, + CONFIG_FSL_FM_RX_EXTRA_HEADROOM); + fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; + } + + printk(KERN_INFO "Using fsl_fm_rx_extra_headroom=%d from bootargs\n", + fsl_fm_rx_extra_headroom); + + return 0; +} +early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, fm_set_rx_extra_headroom); + +static irqreturn_t fm_irq(int irq, void *_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; + + if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) + return IRQ_NONE; + + FM_EventIsr(p_LnxWrpFmDev->h_Dev); + + return IRQ_HANDLED; +} + +static irqreturn_t fm_err_irq(int irq, void *_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; + + if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) + return IRQ_NONE; + + if (FM_ErrorIsr(p_LnxWrpFmDev->h_Dev) == E_OK) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +/* used to protect FMD/LLD from concurrent calls in functions fm_mutex_lock / fm_mutex_unlock */ +static struct mutex lnxwrp_mutex; + +static t_LnxWrpFmDev * CreateFmDev(uint8_t id) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + int j; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *)XX_Malloc(sizeof(t_LnxWrpFmDev)); + if (!p_LnxWrpFmDev) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + memset(p_LnxWrpFmDev, 0, sizeof(t_LnxWrpFmDev)); + p_LnxWrpFmDev->fmDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->fmDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + p_LnxWrpFmDev->fmPcdDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->fmPcdDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + p_LnxWrpFmDev->hcPort.settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->hcPort.settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++) + { + p_LnxWrpFmDev->rxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->rxPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++) + { + p_LnxWrpFmDev->txPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->txPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++) + { + p_LnxWrpFmDev->opPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); + memset(p_LnxWrpFmDev->opPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); + } + + return p_LnxWrpFmDev; +} + +static void DestroyFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + int j; + + for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++) + if (p_LnxWrpFmDev->opPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->opPorts[j].settings.advConfig); + for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++) + if (p_LnxWrpFmDev->txPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->txPorts[j].settings.advConfig); + for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++) + if (p_LnxWrpFmDev->rxPorts[j].settings.advConfig) + XX_Free(p_LnxWrpFmDev->rxPorts[j].settings.advConfig); + if (p_LnxWrpFmDev->hcPort.settings.advConfig) + XX_Free(p_LnxWrpFmDev->hcPort.settings.advConfig); + if (p_LnxWrpFmDev->fmPcdDevSettings.advConfig) + XX_Free(p_LnxWrpFmDev->fmPcdDevSettings.advConfig); + if (p_LnxWrpFmDev->fmDevSettings.advConfig) + XX_Free(p_LnxWrpFmDev->fmDevSettings.advConfig); + + XX_Free(p_LnxWrpFmDev); +} + +static t_Error FillRestFmInfo(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ +#define FM_BMI_PPIDS_OFFSET 0x00080304 +#define FM_DMA_PLR_OFFSET 0x000c2060 +#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4 +#define DMA_HIGH_LIODN_MASK 0x0FFF0000 +#define DMA_LOW_LIODN_MASK 0x00000FFF +#define DMA_LIODN_SHIFT 16 + +typedef _Packed struct { + uint32_t plr[32]; +} _PackedType t_Plr; + +typedef _Packed struct { + volatile uint32_t fmbm_ppid[63]; +} _PackedType t_Ppids; + + t_Plr *p_Plr; + t_Ppids *p_Ppids; + int i,j; + uint32_t fmRev; + + static const uint8_t phys1GRxPortId[] = {0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf}; + static const uint8_t phys10GRxPortId[] = {0x10,0x11}; + static const uint8_t physOhPortId[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7}; + static const uint8_t phys1GTxPortId[] = {0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f}; + static const uint8_t phys10GTxPortId[] = {0x30,0x31}; + + fmRev = (uint32_t)(*((volatile uint32_t *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_FPM_IP_REV_1_OFFSET))); + fmRev &= 0xffff; + + p_Plr = (t_Plr *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_DMA_PLR_OFFSET); +#ifdef MODULE + for (i=0;i<FM_MAX_NUM_OF_PARTITIONS/2;i++) + p_Plr->plr[i] = 0; +#endif /* MODULE */ + + for (i=0; i<FM_MAX_NUM_OF_PARTITIONS; i++) + { + uint16_t liodnBase = (uint16_t)((i%2) ? + (p_Plr->plr[i/2] & DMA_LOW_LIODN_MASK) : + ((p_Plr->plr[i/2] & DMA_HIGH_LIODN_MASK) >> DMA_LIODN_SHIFT)); +#ifdef FM_PARTITION_ARRAY + /* TODO: this was .liodnPerPartition[i] = liodnBase; is the index meaning the same? */ + p_LnxWrpFmDev->fmDevSettings.param.liodnBasePerPort[i] = liodnBase; +#endif /* FM_PARTITION_ARRAY */ + + if ((i >= phys1GRxPortId[0]) && + (i <= phys1GRxPortId[FM_MAX_NUM_OF_1G_RX_PORTS-1])) + { + for (j=0; j<ARRAY_SIZE(phys1GRxPortId); j++) + if (phys1GRxPortId[j] == i) + break; + ASSERT_COND(j<ARRAY_SIZE(phys1GRxPortId)); + p_LnxWrpFmDev->rxPorts[j].settings.param.liodnBase = liodnBase; + } + else if (FM_MAX_NUM_OF_10G_RX_PORTS && + (i >= phys10GRxPortId[0]) && + (i <= phys10GRxPortId[FM_MAX_NUM_OF_10G_RX_PORTS-1])) + { + for (j=0; j<ARRAY_SIZE(phys10GRxPortId); j++) + if (phys10GRxPortId[j] == i) + break; + ASSERT_COND(j<ARRAY_SIZE(phys10GRxPortId)); + p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+j].settings.param.liodnBase = liodnBase; + } + else if ((i >= physOhPortId[0]) && + (i <= physOhPortId[FM_MAX_NUM_OF_OH_PORTS-1])) + { + for (j=0; j<ARRAY_SIZE(physOhPortId); j++) + if (physOhPortId[j] == i) + break; + ASSERT_COND(j<ARRAY_SIZE(physOhPortId)); + if (j == 0) + p_LnxWrpFmDev->hcPort.settings.param.liodnBase = liodnBase; + else + p_LnxWrpFmDev->opPorts[j - 1].settings.param.liodnBase = liodnBase; + } + else if ((i >= phys1GTxPortId[0]) && + (i <= phys1GTxPortId[FM_MAX_NUM_OF_1G_TX_PORTS-1])) + { + for (j=0; j<ARRAY_SIZE(phys1GTxPortId); j++) + if (phys1GTxPortId[j] == i) + break; + ASSERT_COND(j<ARRAY_SIZE(phys1GTxPortId)); + p_LnxWrpFmDev->txPorts[j].settings.param.liodnBase = liodnBase; + } + else if (FM_MAX_NUM_OF_10G_TX_PORTS && + (i >= phys10GTxPortId[0]) && + (i <= phys10GTxPortId[FM_MAX_NUM_OF_10G_TX_PORTS-1])) + { + for (j=0; j<ARRAY_SIZE(phys10GTxPortId); j++) + if (phys10GTxPortId[j] == i) + break; + ASSERT_COND(j<ARRAY_SIZE(phys10GTxPortId)); + p_LnxWrpFmDev->txPorts[FM_MAX_NUM_OF_1G_TX_PORTS+j].settings.param.liodnBase = liodnBase; + } + } + + p_Ppids = (t_Ppids *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_BMI_PPIDS_OFFSET); + + for (i=0; i<FM_MAX_NUM_OF_1G_RX_PORTS; i++) + p_LnxWrpFmDev->rxPorts[i].settings.param.specificParams.rxParams.liodnOffset = + p_Ppids->fmbm_ppid[phys1GRxPortId[i]-1]; + + for (i=0; i<FM_MAX_NUM_OF_10G_RX_PORTS; i++) + p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+i].settings.param.specificParams.rxParams.liodnOffset = + p_Ppids->fmbm_ppid[phys10GRxPortId[i]-1]; + + return E_OK; +} + +/** + * FindFmanMicrocode - find the Fman microcode + * + * This function returns a pointer to the QE Firmware blob that holds + * the Fman microcode. We use the QE Firmware structure because Fman microcode + * is similar to QE microcode, so there's no point in defining a new layout. + * + * Current versions of U-Boot embed the Fman firmware into the device tree, + * so we check for that first. Each Fman node in the device tree contains a + * node or a pointer to node that holds the firmware. Technically, we should + * be fetching the firmware node for the current Fman, but we don't have that + * information any more, so we assume that there is only one firmware node in + * the device tree, and that all Fmen use the same firmware. + */ +static const struct qe_firmware *FindFmanMicrocode(void) +{ + static const struct qe_firmware *P4080_UCPatch; + struct device_node *np; + + if (P4080_UCPatch) + return P4080_UCPatch; + + /* The firmware should be inside the device tree. */ + np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware"); + if (np) { + P4080_UCPatch = of_get_property(np, "fsl,firmware", NULL); + of_node_put(np); + if (P4080_UCPatch) + return P4080_UCPatch; + else + REPORT_ERROR(WARNING, E_NOT_FOUND, ("firmware node is incomplete")); + } + + /* Returning NULL here forces the reuse of the IRAM content */ + return NULL; +} + +static t_LnxWrpFmDev * ReadFmDevTreeNode (struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device_node *fm_node, *dev_node; + struct of_device_id name; + struct resource res; + const uint32_t *uint32_prop; + int _errno=0, lenp; + + fm_node = of_node_get(of_dev->dev.of_node); + + uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (*uint32_prop > INTG_MAX_NUM_OF_FM) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + return NULL; + } + p_LnxWrpFmDev = CreateFmDev(*uint32_prop); + if (!p_LnxWrpFmDev) { + REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG); + return NULL; + } + p_LnxWrpFmDev->dev = &of_dev->dev; + p_LnxWrpFmDev->id = *uint32_prop; + + /* Get the FM interrupt */ + p_LnxWrpFmDev->irq = of_irq_to_resource(fm_node, 0, NULL); + if (unlikely(p_LnxWrpFmDev->irq == /*NO_IRQ*/0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); + return NULL; + } + + /* Get the FM error interrupt */ + p_LnxWrpFmDev->err_irq = of_irq_to_resource(fm_node, 1, NULL); + /* TODO - un-comment it once there will be err_irq in the DTS */ +#if 0 + if (unlikely(p_LnxWrpFmDev->err_irq == /*NO_IRQ*/0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); + return NULL; + } +#endif /* 0 */ + + /* Get the FM address */ + _errno = of_address_to_resource(fm_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmBaseAddr = 0; + p_LnxWrpFmDev->fmPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmMemSize = res.end + 1 - res.start; + + uint32_prop = (uint32_t *)of_get_property(fm_node, "clock-frequency", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, clock-frequency) failed", fm_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmDev->fmDevSettings.param.fmClkFreq = (*uint32_prop + 500000)/1000000; /* In MHz, rounded */ + + /* Get the MURAM base address and size */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("muram") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "muram"); + if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-muram"); + for_each_child_of_node(fm_node, dev_node) { + if (likely(of_match_node(&name, dev_node) != NULL)) { + _errno = of_address_to_resource(dev_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmMuramBaseAddr = 0; + p_LnxWrpFmDev->fmMuramPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmMuramMemSize = res.end + 1 - res.start; + } + } + + /* Get the RTC base address and size */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("rtc") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "rtc"); + if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-rtc"); + for_each_child_of_node(fm_node, dev_node) { + if (likely(of_match_node(&name, dev_node) != NULL)) { + _errno = of_address_to_resource(dev_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev->fmRtcBaseAddr = 0; + p_LnxWrpFmDev->fmRtcPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start; + } + } + +#if (DPAA_VERSION >= 11) + /* Get the VSP base address */ + for_each_child_of_node(fm_node, dev_node) { + if (of_device_is_compatible(dev_node, "fsl,fman-vsps")) { + _errno = of_address_to_resource(dev_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); + return NULL; + } + p_LnxWrpFmDev->fmVspBaseAddr = 0; + p_LnxWrpFmDev->fmVspPhysBaseAddr = res.start; + p_LnxWrpFmDev->fmVspMemSize = res.end + 1 - res.start; + } + } +#endif + + /* Get all PCD nodes */ + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("parser") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "parser"); + if (WARN_ON(strlen("fsl,fman-parser") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-parser"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->prsActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("keygen") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "keygen"); + if (WARN_ON(strlen("fsl,fman-keygen") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-keygen"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->kgActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("cc") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "cc"); + if (WARN_ON(strlen("fsl,fman-cc") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-cc"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->ccActive = TRUE; + + memset(&name, 0, sizeof(struct of_device_id)); + if (WARN_ON(strlen("policer") >= sizeof(name.name))) + return NULL; + strcpy(name.name, "policer"); + if (WARN_ON(strlen("fsl,fman-policer") >= sizeof(name.compatible))) + return NULL; + strcpy(name.compatible, "fsl,fman-policer"); + for_each_child_of_node(fm_node, dev_node) + if (likely(of_match_node(&name, dev_node) != NULL)) + p_LnxWrpFmDev->plcrActive = TRUE; + + if (p_LnxWrpFmDev->prsActive || p_LnxWrpFmDev->kgActive || + p_LnxWrpFmDev->ccActive || p_LnxWrpFmDev->plcrActive) + p_LnxWrpFmDev->pcdActive = TRUE; + + if (p_LnxWrpFmDev->pcdActive) + { + const char *str_prop = (char *)of_get_property(fm_node, "fsl,default-pcd", &lenp); + if (str_prop) { + if (strncmp(str_prop, "3-tuple", strlen("3-tuple")) == 0) + p_LnxWrpFmDev->defPcd = e_FM_PCD_3_TUPLE; + } + else + p_LnxWrpFmDev->defPcd = e_NO_PCD; + } + + of_node_put(fm_node); + + p_LnxWrpFmDev->hcCh = + qman_affine_channel(cpumask_first(qman_affine_cpus())); + + p_LnxWrpFmDev->active = TRUE; + + return p_LnxWrpFmDev; +} + +struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx) +{ + struct device_node *dev_node; + const uint32_t *uint32_prop; + int lenp; + + for_each_compatible_node(dev_node, NULL, "fsl,fman-extended-args") { + uint32_prop = (uint32_t *)of_get_property(dev_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + dev_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (*uint32_prop > INTG_MAX_NUM_OF_FM) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + return NULL; + } + if (fmIndx == *uint32_prop) + return dev_node; + } + + return NULL; +} + +static t_Error CheckNConfigFmAdvArgs (t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + struct device_node *dev_node; + t_Error err = E_INVALID_VALUE; + /*const uint32_t *uint32_prop;*/ + const char *str_prop; + int lenp; + + dev_node = GetFmAdvArgsDevTreeNode(p_LnxWrpFmDev->id); + if (!dev_node) /* no advance parameters for FMan */ + return E_OK; + + str_prop = (char *)of_get_property(dev_node, "dma-aid-mode", &lenp); + if (str_prop) { + if (strcmp(str_prop, "port") == 0) + err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_PORT_ID); + else if (strcmp(str_prop, "tnum") == 0) + err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_TNUM); + } + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + of_node_put(dev_node); + + return E_OK; +} + +static void LnxwrpFmDevExceptionsCb(t_Handle h_App, e_FmExceptions exception) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, ("got fm exception %d", exception)); + + /* do nothing */ + UNUSED(exception); +} + +static void LnxwrpFmDevBusErrorCb(t_Handle h_App, + e_FmPortType portType, + uint8_t portId, + uint64_t addr, + uint8_t tnum, + uint16_t liodn) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + /* do nothing */ + UNUSED(portType);UNUSED(portId);UNUSED(addr);UNUSED(tnum);UNUSED(liodn); +} + +static t_Error ConfigureFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + struct resource *dev_res; + int _errno; + + if (!p_LnxWrpFmDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); + +#ifndef MODULE + _errno = can_request_irq(p_LnxWrpFmDev->irq, 0); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); +#endif + _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, 0, "fman", p_LnxWrpFmDev); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno)); + + if (p_LnxWrpFmDev->err_irq != 0) { +#ifndef MODULE + _errno = can_request_irq(p_LnxWrpFmDev->err_irq, 0); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); +#endif + _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, fm_err_irq, IRQF_SHARED, "fman-err", p_LnxWrpFmDev); + if (unlikely(_errno < 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->err_irq, _errno)); + } + + p_LnxWrpFmDev->res = devm_request_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize, "fman"); + if (unlikely(p_LnxWrpFmDev->res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_mem_region() failed")); + + p_LnxWrpFmDev->fmBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize)); + if (unlikely(p_LnxWrpFmDev->fmBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmBaseAddr, (uint64_t)p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM memory map")); + + dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize, "fman-muram"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); + + p_LnxWrpFmDev->fmMuramBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)); + if (unlikely(p_LnxWrpFmDev->fmMuramBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map")); + + if (p_LnxWrpFmDev->fmRtcPhysBaseAddr) + { + dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-rtc"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); + + p_LnxWrpFmDev->fmRtcBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize)); + if (unlikely(p_LnxWrpFmDev->fmRtcBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + + if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map")); + } + +#if (DPAA_VERSION >= 11) + if (p_LnxWrpFmDev->fmVspPhysBaseAddr) { + dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize, "fman-vsp"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); + + p_LnxWrpFmDev->fmVspBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize)); + if (unlikely(p_LnxWrpFmDev->fmVspBaseAddr == 0)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); + } +#endif + + p_LnxWrpFmDev->fmDevSettings.param.baseAddr = p_LnxWrpFmDev->fmBaseAddr; + p_LnxWrpFmDev->fmDevSettings.param.fmId = p_LnxWrpFmDev->id; + p_LnxWrpFmDev->fmDevSettings.param.irq = NO_IRQ; + p_LnxWrpFmDev->fmDevSettings.param.errIrq = NO_IRQ; + p_LnxWrpFmDev->fmDevSettings.param.f_Exception = LnxwrpFmDevExceptionsCb; + p_LnxWrpFmDev->fmDevSettings.param.f_BusError = LnxwrpFmDevBusErrorCb; + p_LnxWrpFmDev->fmDevSettings.param.h_App = p_LnxWrpFmDev; + + return FillRestFmInfo(p_LnxWrpFmDev); +} + +static t_Error InitFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + const struct qe_firmware *fw; + + if (!p_LnxWrpFmDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); + + if ((p_LnxWrpFmDev->h_MuramDev = FM_MURAM_ConfigAndInit(p_LnxWrpFmDev->fmMuramBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)) == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM!")); + + /* Loading the fman-controller code */ + fw = FindFmanMicrocode(); + + if (!fw) { + /* this forces the reuse of the current IRAM content */ + p_LnxWrpFmDev->fmDevSettings.param.firmware.size = 0; + p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = NULL; + } else { + p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = + (void *) fw + fw->microcode[0].code_offset; + p_LnxWrpFmDev->fmDevSettings.param.firmware.size = + sizeof(u32) * fw->microcode[0].count; + DBG(INFO, ("Loading fman-controller code version %d.%d.%d", + fw->microcode[0].major, + fw->microcode[0].minor, + fw->microcode[0].revision)); + } + + p_LnxWrpFmDev->fmDevSettings.param.h_FmMuram = p_LnxWrpFmDev->h_MuramDev; + +#if (DPAA_VERSION >= 11) + if (p_LnxWrpFmDev->fmVspBaseAddr) { + p_LnxWrpFmDev->fmDevSettings.param.vspBaseAddr = p_LnxWrpFmDev->fmVspBaseAddr; + p_LnxWrpFmDev->fmDevSettings.param.partVSPBase = 0; + p_LnxWrpFmDev->fmDevSettings.param.partNumOfVSPs = FM_VSP_MAX_NUM_OF_ENTRIES; + } +#endif + + if ((p_LnxWrpFmDev->h_Dev = FM_Config(&p_LnxWrpFmDev->fmDevSettings.param)) == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM")); + + + if (FM_ConfigResetOnInit(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); + +#ifdef CONFIG_FMAN_P1023 + if (FM_ConfigDmaAidOverride(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); +#endif + + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) && defined(CONFIG_FMAN_P3040_P4080_P5020) + /* Enable 14g w/ jumbo frames following HW suggestion. */ + FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev, 128*KILOBYTE); +#elif defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) && defined(CONFIG_FMAN_P1023) + FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev, 48*KILOBYTE); +#endif +#if (DPAA_VERSION >= 11) +#define DEFAULT_TOTAL_FIFO_SIZE_FOR_FMAN_V3H 295*KILOBYTE + FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev, + DEFAULT_TOTAL_FIFO_SIZE_FOR_FMAN_V3H); +#endif /* (DPAA_VERSION >= 11) */ + + CheckNConfigFmAdvArgs(p_LnxWrpFmDev); + + if (FM_Init(p_LnxWrpFmDev->h_Dev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); + + /* TODO: Why we mask these interrupts? */ + if (p_LnxWrpFmDev->err_irq == 0) { + FM_SetException(p_LnxWrpFmDev->h_Dev, e_FM_EX_DMA_BUS_ERROR,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_READ_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SYSTEM_WRITE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_FM_WRITE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SINGLE_PORT_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_STALL_ON_TASKS , FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_SINGLE_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_DOUBLE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_SINGLE_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DOUBLE_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_LIST_RAM_ECC,FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STORAGE_PROFILE_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STATISTICS_RAM_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_DISPATCH_RAM_ECC, FALSE); + FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_IRAM_ECC,FALSE); + /* TODO: FmDisableRamsEcc assert for ramsEccOwners. + * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/ + } + + if (p_LnxWrpFmDev->fmRtcBaseAddr) + { + t_FmRtcParams fmRtcParam; + + memset(&fmRtcParam, 0, sizeof(fmRtcParam)); + fmRtcParam.h_App = p_LnxWrpFmDev; + fmRtcParam.h_Fm = p_LnxWrpFmDev->h_Dev; + fmRtcParam.baseAddress = p_LnxWrpFmDev->fmRtcBaseAddr; + + if(!(p_LnxWrpFmDev->h_RtcDev = FM_RTC_Config(&fmRtcParam))) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-RTC")); + + if (FM_RTC_ConfigPeriod(p_LnxWrpFmDev->h_RtcDev, 5) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); + + if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); + } + + return E_OK; +} + +/* TODO: to be moved back here */ +extern void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev); + +static void FreeFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + if (!p_LnxWrpFmDev->active) + return; + + FreeFmPcdDev(p_LnxWrpFmDev); + + if (p_LnxWrpFmDev->h_RtcDev) + FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev); + + if (p_LnxWrpFmDev->h_Dev) + FM_Free(p_LnxWrpFmDev->h_Dev); + + if (p_LnxWrpFmDev->h_MuramDev) + FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev); + + if (p_LnxWrpFmDev->fmRtcBaseAddr) + { + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize); + } + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize); + SYS_UnregisterIoMap(p_LnxWrpFmDev->fmBaseAddr); + devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr)); + devm_release_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize); + if (p_LnxWrpFmDev->err_irq != 0) { + devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, p_LnxWrpFmDev); + } + + devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, p_LnxWrpFmDev); +} + +/* FMan character device file operations */ +extern struct file_operations fm_fops; + +static int /*__devinit*/ fm_probe(struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + + if ((p_LnxWrpFmDev = ReadFmDevTreeNode(of_dev)) == NULL) + return -EIO; + if (ConfigureFmDev(p_LnxWrpFmDev) != E_OK) + return -EIO; + if (InitFmDev(p_LnxWrpFmDev) != E_OK) + return -EIO; + + /* IOCTL ABI checking */ + LnxWrpPCDIOCTLEnumChecking(); + LnxWrpPCDIOCTLTypeChecking(); + + Sprint (p_LnxWrpFmDev->name, "%s%d", DEV_FM_NAME, p_LnxWrpFmDev->id); + + /* Register to the /dev for IOCTL API */ + /* Register dynamically a new major number for the character device: */ + if ((p_LnxWrpFmDev->major = register_chrdev(0, p_LnxWrpFmDev->name, &fm_fops)) <= 0) { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", p_LnxWrpFmDev->name)); + return -EIO; + } + + /* Creating classes for FM */ + DBG(TRACE ,("class_create fm_class")); + p_LnxWrpFmDev->fm_class = class_create(THIS_MODULE, p_LnxWrpFmDev->name); + if (IS_ERR(p_LnxWrpFmDev->fm_class)) { + unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_class")); + return -EIO; + } + + device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE), NULL, + "fm%d", p_LnxWrpFmDev->id); + device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE), NULL, + "fm%d-pcd", p_LnxWrpFmDev->id); + dev_set_drvdata(p_LnxWrpFmDev->dev, p_LnxWrpFmDev); + + /* create sysfs entries for stats and regs */ + if ( fm_sysfs_create(p_LnxWrpFmDev->dev) !=0 ) + { + FreeFmDev(p_LnxWrpFmDev); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unable to create sysfs entry - fm!!!")); + return -EIO; + } + + DBG(TRACE, ("FM%d probed", p_LnxWrpFmDev->id)); + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) + /* Precalculate resources for FMAN based on number of + * FMan ports available + */ + if(fm_set_active_fman_ports(of_dev, p_LnxWrpFmDev)!= 0) + return -EIO; + +#if defined(CONFIG_FMAN_P3040_P4080_P5020) + /* 128K MURAM for p3,p4 and p5 */ + if(fm_precalculate_fifosizes( + p_LnxWrpFmDev, + 128*KILOBYTE) + != 0) + return -EIO; +#else + /* for all other platforms: MURAM Space for fifosize=3/4 * MURAM_SIZE*/ + if(fm_precalculate_fifosizes( + p_LnxWrpFmDev, + 48*KILOBYTE) + != 0) + return -EIO; +#endif + if(fm_precalculate_open_dma( + p_LnxWrpFmDev, + BMI_MAX_NUM_OF_DMAS, /* max open dmas:dpaa_integration_ext.h */ + FM_DEFAULT_TX10G_OPENDMA, /* default TX 10g open dmas */ + FM_DEFAULT_RX10G_OPENDMA, /* default RX 10g open dmas */ + FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */ + FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */ + != 0) + return -EIO; + if(fm_precalculate_tnums( + p_LnxWrpFmDev, + BMI_MAX_NUM_OF_TASKS) /* max TNUMS: dpa integration file. */ + != 0) + return -EIO; +#endif + + return 0; +} + +static int fm_remove(struct platform_device *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + p_LnxWrpFmDev = dev_get_drvdata(dev); + + fm_sysfs_destroy(dev); + + DBG(TRACE, ("destroy fm_class")); + device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE)); + device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE)); + class_destroy(p_LnxWrpFmDev->fm_class); + + /* Destroy chardev */ + unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); + + FreeFmDev(p_LnxWrpFmDev); + + DestroyFmDev(p_LnxWrpFmDev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id fm_match[] = { + { + .compatible = "fsl,fman" + }, + {} +}; +#ifndef MODULE +MODULE_DEVICE_TABLE(of, fm_match); +#endif /* !MODULE */ + +static struct platform_driver fm_driver = { + .driver = { + .name = "fsl-fman", + .of_match_table = fm_match, + .owner = THIS_MODULE, + }, + .probe = fm_probe, + .remove = fm_remove +}; + +t_Handle LNXWRP_FM_Init(void) +{ + memset(&lnxWrpFm, 0, sizeof(lnxWrpFm)); + mutex_init(&lnxwrp_mutex); + + /* Register to the DTB for basic FM API */ + platform_driver_register(&fm_driver); + + return &lnxWrpFm; +} + +t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm) +{ + platform_driver_unregister(&fm_driver); + mutex_destroy(&lnxwrp_mutex); + + return E_OK; +} + + +struct fm * fm_bind(struct device *fm_dev) +{ + return (struct fm *)(dev_get_drvdata(get_device(fm_dev))); +} +EXPORT_SYMBOL(fm_bind); + +void fm_unbind(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + put_device(p_LnxWrpFmDev->dev); +} +EXPORT_SYMBOL(fm_unbind); + +struct resource * fm_get_mem_region(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return p_LnxWrpFmDev->res; +} +EXPORT_SYMBOL(fm_get_mem_region); + +void * fm_get_handle(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return (void *)p_LnxWrpFmDev->h_Dev; +} +EXPORT_SYMBOL(fm_get_handle); + +void * fm_get_rtc_handle(struct fm *fm) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; + + return (void *)p_LnxWrpFmDev->h_RtcDev; +} +EXPORT_SYMBOL(fm_get_rtc_handle); + +struct fm_port * fm_port_bind (struct device *fm_port_dev) +{ + return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev))); +} +EXPORT_SYMBOL(fm_port_bind); + +void fm_port_unbind(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + put_device(p_LnxWrpFmPortDev->dev); +} +EXPORT_SYMBOL(fm_port_unbind); + +void * fm_port_get_handle(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + return (void *)p_LnxWrpFmPortDev->h_Dev; +} +EXPORT_SYMBOL(fm_port_get_handle); + +void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; + + *base_addr = p_LnxWrpFmPortDev->settings.param.baseAddr; +} +EXPORT_SYMBOL(fm_port_get_base_addr); + +void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + p_LnxWrpFmPortDev->pcd_owner_params.cba = params->cba; + p_LnxWrpFmPortDev->pcd_owner_params.cbf = params->cbf; + p_LnxWrpFmPortDev->pcd_owner_params.dev = params->dev; +} +EXPORT_SYMBOL(fm_port_pcd_bind); + +void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; + struct device_node *fm_node, *port_node; + const uint32_t *uint32_prop; + int lenp; + + params->data_align = 0; + params->manip_extra_space = 0; + + fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); + if (!fm_node) /* no advance parameters for FMan */ + return; + + port_node = GetFmPortAdvArgsDevTreeNode(fm_node, + p_LnxWrpFmPortDev->settings.param.portType, + p_LnxWrpFmPortDev->settings.param.portId); + if (!port_node) /* no advance parameters for FMan-Port */ + return; + + uint32_prop = (uint32_t *)of_get_property(port_node, "buffer-layout", &lenp); + if (uint32_prop) { + if (WARN_ON(lenp != sizeof(uint32_t)*2)) + return; + + params->manip_extra_space = (uint8_t)uint32_prop[0]; + params->data_align = (uint16_t)uint32_prop[1]; + } + + of_node_put(port_node); + of_node_put(fm_node); +} +EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params); + +int fm_get_tx_port_channel(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + return p_LnxWrpFmPortDev->txCh; +} +EXPORT_SYMBOL(fm_get_tx_port_channel); + +int fm_port_enable (struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); + + return 0; +} +EXPORT_SYMBOL(fm_port_enable); + +void fm_port_disable(struct fm_port *port) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; + + FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); +} +EXPORT_SYMBOL(fm_port_disable); + +void fm_mutex_lock(void) +{ + mutex_lock(&lnxwrp_mutex); +} +EXPORT_SYMBOL(fm_mutex_lock); + +void fm_mutex_unlock(void) +{ + mutex_unlock(&lnxwrp_mutex); +} +EXPORT_SYMBOL(fm_mutex_unlock); + +static t_Handle h_FmLnxWrp; + +static int __init __cold fm_load (void) +{ + if ((h_FmLnxWrp = LNXWRP_FM_Init()) == NULL) + { + printk("Failed to init FM wrapper!\n"); + return -ENODEV; + } + + printk(KERN_CRIT "Freescale FM module ("__DATE__ ":"__TIME__")," \ + " FMD API version %d.%d.%d\n", + FMD_API_VERSION_MAJOR, + FMD_API_VERSION_MINOR, + FMD_API_VERSION_RESPIN); + return 0; +} + +static void __exit __cold fm_unload (void) +{ + if (h_FmLnxWrp) + LNXWRP_FM_Free(h_FmLnxWrp); +} + +module_init (fm_load); +module_exit (fm_unload); diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h new file mode 100644 index 0000000..37c52c7 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h @@ -0,0 +1,275 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_fm.h + + @Author Shlomi Gridish + + @Description FM Linux wrapper functions. + +*/ + +#ifndef __LNXWRP_FM_H__ +#define __LNXWRP_FM_H__ + +#include <linux/fsl_qman.h> /* struct qman_fq */ + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "lnxwrp_fm_ext.h" + +#define __ERR_MODULE__ MODULE_FM + +#define FM_MAX_NUM_OF_ADV_SETTINGS 10 + +#define LNXWRP_FM_NUM_OF_SHARED_PROFILES 16 + +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) +#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */ +#else +#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */ +#endif +#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */ +#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */ + +#define FRAG_MANIP_SPACE 128 +#define FRAG_DATA_ALIGN 64 + +#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE +#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0 +#endif + +#ifndef CONFIG_FSL_FM_RX_EXTRA_HEADROOM +#define CONFIG_FSL_FM_RX_EXTRA_HEADROOM 0 +#endif + +typedef enum { + e_NO_PCD = 0, + e_FM_PCD_3_TUPLE +} e_LnxWrpFmPortPcdDefUseCase; + + +typedef struct t_FmTestFq { + struct qman_fq fq_base; + t_Handle h_Arg; +} t_FmTestFq; + +typedef struct { + uint8_t id; /* sw port id, see SW_PORT_ID_TO_HW_PORT_ID() in fm_common.h */ + int minor; + char name[20]; + bool active; + uint64_t phys_baseAddr; + uint64_t baseAddr; /* Port's *virtual* address */ + uint32_t memSize; + t_WrpFmPortDevSettings settings; + t_FmExtPools opExtPools; + uint8_t totalNumOfSchemes; + uint8_t schemesBase; + uint8_t numOfSchemesUsed; + uint32_t pcdBaseQ; + uint16_t pcdNumOfQs; + struct fm_port_pcd_param pcd_owner_params; + e_LnxWrpFmPortPcdDefUseCase defPcd; + t_Handle h_DefNetEnv; + t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmBufferPrefixContent buffPrefixContent; + t_Handle h_Dev; + t_Handle h_DfltVsp; + t_Handle h_LnxWrpFmDev; + uint16_t txCh; + struct device *dev; + struct device_attribute *dev_attr_stats; + struct device_attribute *dev_attr_regs; +} t_LnxWrpFmPortDev; + +typedef struct { + uint8_t id; + bool active; + uint64_t baseAddr; + uint32_t memSize; + t_WrpFmMacDevSettings settings; + t_Handle h_Dev; + t_Handle h_LnxWrpFmDev; +} t_LnxWrpFmMacDev; + +/* information about all active ports for an FMan. + * !Some ports may be disabled by u-boot, thus will not be available */ +struct fm_active_ports { + uint32_t num_oh_ports; + uint32_t num_tx_ports; + uint32_t num_rx_ports; + uint32_t num_tx25_ports; + uint32_t num_rx25_ports; + uint32_t num_tx10_ports; + uint32_t num_rx10_ports; +}; + +/* FMan resources precalculated at fm probe based + * on available FMan port. */ +struct fm_resource_settings { + /* buffers - fifo sizes */ + uint32_t tx1g_num_buffers; + uint32_t rx1g_num_buffers; + uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t tx10g_num_buffers; + uint32_t rx10g_num_buffers; + uint32_t oh_num_buffers; + uint32_t shared_ext_buffers; + + /* open DMAs */ + uint32_t tx_1g_dmas; + uint32_t rx_1g_dmas; + uint32_t tx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t rx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t tx_10g_dmas; + uint32_t rx_10g_dmas; + uint32_t oh_dmas; + uint32_t shared_ext_open_dma; + + /* Tnums */ + uint32_t tx_1g_tnums; + uint32_t rx_1g_tnums; + uint32_t tx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t rx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t tx_10g_tnums; + uint32_t rx_10g_tnums; + uint32_t oh_tnums; + uint32_t shared_ext_tnums; +}; + +typedef struct { + uint8_t id; + char name[10]; + bool active; + bool pcdActive; + bool prsActive; + bool kgActive; + bool ccActive; + bool plcrActive; + e_LnxWrpFmPortPcdDefUseCase defPcd; + uint32_t usedSchemes; + uint8_t totalNumOfSharedSchemes; + uint8_t sharedSchemesBase; + uint8_t numOfSchemesUsed; + uint8_t defNetEnvId; + uint64_t fmPhysBaseAddr; + uint64_t fmBaseAddr; + uint32_t fmMemSize; + uint64_t fmMuramPhysBaseAddr; + uint64_t fmMuramBaseAddr; + uint32_t fmMuramMemSize; + uint64_t fmRtcPhysBaseAddr; + uint64_t fmRtcBaseAddr; + uint32_t fmRtcMemSize; + uint64_t fmVspPhysBaseAddr; + uint64_t fmVspBaseAddr; + uint32_t fmVspMemSize; + int irq; + int err_irq; + t_WrpFmDevSettings fmDevSettings; + t_WrpFmPcdDevSettings fmPcdDevSettings; + t_Handle h_Dev; + uint16_t hcCh; + + t_Handle h_MuramDev; + t_Handle h_PcdDev; + t_Handle h_RtcDev; + + t_LnxWrpFmPortDev hcPort; + t_LnxWrpFmPortDev opPorts[FM_MAX_NUM_OF_OH_PORTS-1]; + t_LnxWrpFmPortDev rxPorts[FM_MAX_NUM_OF_RX_PORTS]; + t_LnxWrpFmPortDev txPorts[FM_MAX_NUM_OF_TX_PORTS]; + t_LnxWrpFmMacDev macs[FM_MAX_NUM_OF_MACS]; + struct fm_active_ports fm_active_ports_info; + struct fm_resource_settings fm_resource_settings_info; + + struct device *dev; + struct resource *res; + int major; + struct class *fm_class; + struct device_attribute *dev_attr_stats; + struct device_attribute *dev_attr_regs; + + struct device_attribute *dev_pcd_attr_stats; + struct device_attribute *dev_pcd_attr_regs; + + struct qman_fq *hc_tx_conf_fq, *hc_tx_err_fq, *hc_tx_fq; +} t_LnxWrpFmDev; + +typedef struct { + t_LnxWrpFmDev *p_FmDevs[INTG_MAX_NUM_OF_FM]; +} t_LnxWrpFm; +#define LNXWRP_FM_OBJECT(ptr) LIST_OBJECT(ptr, t_LnxWrpFm, fms[((t_LnxWrpFmDev *)ptr)->id]) + + +t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat); +t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat); + + +static __inline__ t_Error AllocSchemesForPort(t_LnxWrpFmDev *p_LnxWrpFmDev, uint8_t numSchemes, uint8_t *p_BaseSchemeNum) +{ + uint32_t schemeMask; + uint8_t i; + + if (!numSchemes) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + schemeMask = 0x80000000; + *p_BaseSchemeNum = 0xff; + + for (i=0; schemeMask && numSchemes; schemeMask>>=1, i++) + if ((p_LnxWrpFmDev->usedSchemes & schemeMask) == 0) + { + p_LnxWrpFmDev->usedSchemes |= schemeMask; + numSchemes--; + if (*p_BaseSchemeNum==0xff) + *p_BaseSchemeNum = i; + } + else if (*p_BaseSchemeNum!=0xff) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Fragmentation on schemes array!!!")); + + if (numSchemes) + RETURN_ERROR(MINOR, E_FULL, ("schemes!!!")); + return E_OK; +} + +void LnxWrpPCDIOCTLTypeChecking(void); +void LnxWrpPCDIOCTLEnumChecking(void); + +#endif /* __LNXWRP_FM_H__ */ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm_port.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm_port.c new file mode 100644 index 0000000..f9f3353 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm_port.c @@ -0,0 +1,1332 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_fm_port.c + + @Description FMD wrapper - FMan port functions. + +*/ + +#include <linux/version.h> +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/cdev.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "sprint_ext.h" +#include "fm_common.h" +#include "fm_port_ext.h" +#if (DPAA_VERSION >= 11) +#include "fm_vsp_ext.h" +#endif /* DPAA_VERSION >= 11 */ +#include "fm_ioctls.h" +#include "lnxwrp_resources.h" +#include "lnxwrp_sysfs_fm_port.h" + +extern struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx); + +/* TODO: duplicated, see lnxwrp_fm.c */ +#define ADD_ADV_CONFIG_NO_RET(_func, _param)\ +do {\ + if (i < max) {\ + p_Entry = &p_Entrys[i];\ + p_Entry->p_Function = _func;\ + _param\ + i++;\ + } else {\ + REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ + ("Number of advanced-configuration entries exceeded"));\ + } \ +} while (0) + + +static volatile int hcFrmRcv/* = 0 */; +static spinlock_t lock; + +static enum qman_cb_dqrr_result qm_tx_conf_dqrr_cb(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry + *dq) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_FmTestFq *) fq)->h_Arg; + unsigned long flags; + + FM_PCD_HcTxConf(p_LnxWrpFmDev->h_PcdDev, (t_DpaaFD *)&dq->fd); + spin_lock_irqsave(&lock, flags); + hcFrmRcv--; + spin_unlock_irqrestore(&lock, flags); + + return qman_cb_dqrr_consume; +} + +static enum qman_cb_dqrr_result qm_tx_dqrr_cb(struct qman_portal *portal, + struct qman_fq *fq, + const struct qm_dqrr_entry *dq) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + return qman_cb_dqrr_consume; +} + +static void qm_err_cb(struct qman_portal *portal, + struct qman_fq *fq, const struct qm_mr_entry *msg) +{ + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); +} + +static struct qman_fq *FqAlloc(t_LnxWrpFmDev * p_LnxWrpFmDev, + uint32_t fqid, + uint32_t flags, uint16_t channel, uint8_t wq) +{ + int _errno; + struct qman_fq *fq = NULL; + t_FmTestFq *p_FmtFq; + struct qm_mcc_initfq initfq; + + p_FmtFq = (t_FmTestFq *) XX_Malloc(sizeof(t_FmTestFq)); + if (!p_FmtFq) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!")); + return NULL; + } + + p_FmtFq->fq_base.cb.dqrr = ((flags & QMAN_FQ_FLAG_NO_ENQUEUE) + ? qm_tx_conf_dqrr_cb + : qm_tx_dqrr_cb); + p_FmtFq->fq_base.cb.ern = qm_err_cb; + /* p_FmtFq->fq_base.cb.fqs = qm_err_cb; */ + /* qm_err_cb wrongly called when the FQ is parked */ + p_FmtFq->fq_base.cb.fqs = NULL; + p_FmtFq->h_Arg = (t_Handle) p_LnxWrpFmDev; + if (fqid == 0) { + flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; + flags &= ~QMAN_FQ_FLAG_NO_MODIFY; + } else { + flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; + } + + if (qman_create_fq(fqid, flags, &p_FmtFq->fq_base)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!")); + XX_Free(p_FmtFq); + return NULL; + } + fq = &p_FmtFq->fq_base; + + if (!(flags & QMAN_FQ_FLAG_NO_MODIFY)) { + initfq.we_mask = QM_INITFQ_WE_DESTWQ; + initfq.fqd.dest.channel = channel; + initfq.fqd.dest.wq = wq; + + _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_NO_MEMORY, + ("FQ obj - qman_init_fq!!!")); + qman_destroy_fq(fq, 0); + XX_Free(p_FmtFq); + return NULL; + } + } + + DBG(TRACE, + ("fqid %d, flags 0x%08x, channel %d, wq %d", qman_fq_fqid(fq), + flags, channel, wq)); + + return fq; +} + +static void FqFree(struct qman_fq *fq) +{ + int _errno; + + _errno = qman_retire_fq(fq, NULL); + if (unlikely(_errno < 0)) + printk(KERN_WARNING "qman_retire_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); + + _errno = qman_oos_fq(fq); + if (unlikely(_errno < 0)) + printk(KERN_WARNING "qman_oos_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); + + qman_destroy_fq(fq, 0); + XX_Free((t_FmTestFq *) fq); +} + +static t_Error QmEnqueueCB(t_Handle h_Arg, void *p_Fd) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_Arg; + int _errno, timeout = 1000000; + unsigned long flags; + + ASSERT_COND(p_LnxWrpFmDev); + + spin_lock_irqsave(&lock, flags); + hcFrmRcv++; + spin_unlock_irqrestore(&lock, flags); + + _errno = qman_enqueue(p_LnxWrpFmDev->hc_tx_fq, (struct qm_fd *) p_Fd, + 0); + if (_errno) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("qman_enqueue() failed")); + + while (hcFrmRcv && --timeout) { + udelay(1); + cpu_relax(); + } + if (timeout == 0) { + dump_stack(); + RETURN_ERROR(MINOR, E_WRITE_FAILED, + ("timeout waiting for Tx confirmation")); + return E_WRITE_FAILED; + } + + return E_OK; +} + +static t_LnxWrpFmPortDev *ReadFmPortDevTreeNode(struct platform_device + *of_dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + struct device_node *fm_node, *port_node; + struct resource res; + const uint32_t *uint32_prop; + int _errno = 0, lenp; +#ifdef CONFIG_FMAN_P1023 + static unsigned char have_oh_port/* = 0 */; +#endif + + port_node = of_node_get(of_dev->dev.of_node); + + /* Get the FM node */ + fm_node = of_get_parent(port_node); + if (unlikely(fm_node == NULL)) { + REPORT_ERROR(MAJOR, E_NO_DEVICE, + ("of_get_parent() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmDev = + dev_get_drvdata(&of_find_device_by_node(fm_node)->dev); + of_node_put(fm_node); + + /* if fm_probe() failed, no point in going further with port probing */ + if (p_LnxWrpFmDev == NULL) + return NULL; + + uint32_prop = + (uint32_t *) of_get_property(port_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (of_device_is_compatible(port_node, "fsl,fman-port-oh")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_OH_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + +#ifdef CONFIG_FMAN_P1023 + /* Beware, this can be done when there is only + one FMan to be initialized */ + if (!have_oh_port) { + have_oh_port = 1; /* first OP/HC port + is used for host command */ +#else + /* Here it is hardcoded the use of the OH port 1 + (with cell-index 0) */ + if (*uint32_prop == 0) { +#endif + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + p_LnxWrpFmPortDev->id = 0; + /* + p_LnxWrpFmPortDev->id = *uint32_prop-1; + p_LnxWrpFmPortDev->id = *uint32_prop; + */ + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_OH_HOST_COMMAND; + } else { + p_LnxWrpFmPortDev = + &p_LnxWrpFmDev->opPorts[*uint32_prop - 1]; + p_LnxWrpFmPortDev->id = *uint32_prop - 1; + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_OH_OFFLINE_PARSING; + } + p_LnxWrpFmPortDev->settings.param.portId = *uint32_prop; + + uint32_prop = + (uint32_t *) of_get_property(port_node, + "fsl,qman-channel-id", + &lenp); + if (uint32_prop == NULL) { + /* + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("missing fsl,qman-channel-id")); + */ + XX_Print("FM warning: missing fsl,qman-channel-id" + " for OH port.\n"); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmPortDev->txCh = *uint32_prop; + + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + qmChannel = p_LnxWrpFmPortDev->txCh; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-tx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_1G_TX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[*uint32_prop]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_TX; + + uint32_prop = (uint32_t *) of_get_property(port_node, + "fsl,qman-channel-id", &lenp); + if (uint32_prop == NULL) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("missing fsl,qman-channel-id")); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmPortDev->txCh = *uint32_prop; + p_LnxWrpFmPortDev-> + settings.param.specificParams.nonRxParams.qmChannel = + p_LnxWrpFmPortDev->txCh; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_10G_TX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[*uint32_prop + + FM_MAX_NUM_OF_1G_TX_PORTS]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_TX_10G; + uint32_prop = (uint32_t *) of_get_property(port_node, + "fsl,qman-channel-id", &lenp); + if (uint32_prop == NULL) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("missing fsl,qman-channel-id")); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + p_LnxWrpFmPortDev->txCh = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + qmChannel = p_LnxWrpFmPortDev->txCh; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-rx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_1G_RX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[*uint32_prop]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_RX; + if (p_LnxWrpFmDev->pcdActive) + p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd; + } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) { + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_10G_RX_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[*uint32_prop + + FM_MAX_NUM_OF_1G_RX_PORTS]; + + p_LnxWrpFmPortDev->id = *uint32_prop; + p_LnxWrpFmPortDev->settings.param.portId = + p_LnxWrpFmPortDev->id; + p_LnxWrpFmPortDev->settings.param.portType = + e_FM_PORT_TYPE_RX_10G; + if (p_LnxWrpFmDev->pcdActive) + p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd; + } else { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); + return NULL; + } + + _errno = of_address_to_resource(port_node, 0, &res); + if (unlikely(_errno < 0)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_address_to_resource() = %d", _errno)); + return NULL; + } + + p_LnxWrpFmPortDev->dev = &of_dev->dev; + p_LnxWrpFmPortDev->baseAddr = 0; + p_LnxWrpFmPortDev->phys_baseAddr = res.start; + p_LnxWrpFmPortDev->memSize = res.end + 1 - res.start; + p_LnxWrpFmPortDev->settings.param.h_Fm = p_LnxWrpFmDev->h_Dev; + p_LnxWrpFmPortDev->h_LnxWrpFmDev = (t_Handle) p_LnxWrpFmDev; + + of_node_put(port_node); + + p_LnxWrpFmPortDev->active = TRUE; + +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) + /* for performance mode no OH port available. */ + if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_LnxWrpFmPortDev->active = FALSE; +#endif + + return p_LnxWrpFmPortDev; +} + +struct device_node * GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node, + e_FmPortType portType, + uint8_t portId) +{ + struct device_node *port_node; + const uint32_t *uint32_prop; + int lenp; + char *portTypeString; + + switch(portType) { + case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: + portTypeString = "fsl,fman-port-op-extended-args"; + break; + case e_FM_PORT_TYPE_TX: + portTypeString = "fsl,fman-port-1g-tx-extended-args"; + break; + case e_FM_PORT_TYPE_TX_10G: + portTypeString = "fsl,fman-port-10g-tx-extended-args"; + break; + case e_FM_PORT_TYPE_RX: + portTypeString = "fsl,fman-port-1g-rx-extended-args"; + break; + case e_FM_PORT_TYPE_RX_10G: + portTypeString = "fsl,fman-port-10g-rx-extended-args"; + break; + default: + return NULL; + } + + for_each_child_of_node(fm_node, port_node) { + uint32_prop = (uint32_t *)of_get_property(port_node, "cell-index", &lenp); + if (unlikely(uint32_prop == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + if (WARN_ON(lenp != sizeof(uint32_t))) + return NULL; + if (unlikely(*uint32_prop >= FM_MAX_NUM_OF_OH_PORTS)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("of_get_property(%s, cell-index) failed", + port_node->full_name)); + return NULL; + } + + if ((portId == *uint32_prop) && + (of_device_is_compatible(port_node, portTypeString))) { + return port_node; + } + } + + return NULL; +} + +static t_Error CheckNConfigFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + struct device_node *fm_node, *port_node; + t_Error err; + t_FmPortRsrc portRsrc; + const uint32_t *uint32_prop; + /*const char *str_prop;*/ + int lenp; + + fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); + if (!fm_node) /* no advance parameters for FMan */ + return E_OK; + + port_node = GetFmPortAdvArgsDevTreeNode(fm_node, + p_LnxWrpFmPortDev->settings.param.portType, + p_LnxWrpFmPortDev->settings.param.portId); + if (!port_node) /* no advance parameters for FMan-Port */ + return E_OK; + + uint32_prop = (uint32_t *)of_get_property(port_node, "num-tnums", &lenp); + if (uint32_prop) { + if (WARN_ON(lenp != sizeof(uint32_t)*2)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + portRsrc.num = uint32_prop[0]; + portRsrc.extra = uint32_prop[1]; + + if ((err = FM_PORT_ConfigNumOfTasks(p_LnxWrpFmPortDev->h_Dev, + &portRsrc)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + + uint32_prop = (uint32_t *)of_get_property(port_node, "num-dmas", &lenp); + if (uint32_prop) { + if (WARN_ON(lenp != sizeof(uint32_t)*2)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + portRsrc.num = uint32_prop[0]; + portRsrc.extra = uint32_prop[1]; + + if ((err = FM_PORT_ConfigNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev, + &portRsrc)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + + uint32_prop = (uint32_t *)of_get_property(port_node, "fifo_size", &lenp); + if (uint32_prop) { + if (WARN_ON(lenp != sizeof(uint32_t)*2)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + portRsrc.num = uint32_prop[0]; + portRsrc.extra = uint32_prop[1]; + + if ((err = FM_PORT_ConfigSizeOfFifo(p_LnxWrpFmPortDev->h_Dev, + &portRsrc)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + + of_node_put(port_node); + of_node_put(fm_node); + + return E_OK; +} + +static t_Error CheckNSetFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + struct device_node *fm_node, *port_node; + t_Error err; + const uint32_t *uint32_prop; + /*const char *str_prop;*/ + int lenp; + + fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); + if (!fm_node) /* no advance parameters for FMan */ + return E_OK; + + port_node = GetFmPortAdvArgsDevTreeNode(fm_node, + p_LnxWrpFmPortDev->settings.param.portType, + p_LnxWrpFmPortDev->settings.param.portId); + if (!port_node) /* no advance parameters for FMan-Port */ + return E_OK; + +#if (DPAA_VERSION >= 11) + uint32_prop = (uint32_t *)of_get_property(port_node, "vsp-window", &lenp); + if (uint32_prop) { + t_FmPortVSPAllocParams portVSPAllocParams; + t_FmVspParams fmVspParams; + t_LnxWrpFmDev *p_LnxWrpFmDev; + uint8_t portId; + + p_LnxWrpFmDev = ((t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev); + + if (WARN_ON(lenp != sizeof(uint32_t)*2)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + + if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) || + (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX_10G) || + ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + p_LnxWrpFmPortDev->settings.frag_enabled)) + return E_OK; + + memset(&portVSPAllocParams, 0, sizeof(portVSPAllocParams)); + memset(&fmVspParams, 0, sizeof(fmVspParams)); + + portVSPAllocParams.numOfProfiles = (uint8_t)uint32_prop[0]; + portVSPAllocParams.dfltRelativeId = (uint8_t)uint32_prop[1]; + + fmVspParams.h_Fm = p_LnxWrpFmDev->h_Dev; + + fmVspParams.portParams.portType = p_LnxWrpFmPortDev->settings.param.portType; + fmVspParams.portParams.portId = p_LnxWrpFmPortDev->settings.param.portId; + fmVspParams.relativeProfileId = portVSPAllocParams.dfltRelativeId; + + if (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + portId = fmVspParams.portParams.portId; + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) + portId += FM_MAX_NUM_OF_1G_RX_PORTS; + portVSPAllocParams.h_FmTxPort = + p_LnxWrpFmDev->txPorts[portId].h_Dev; + fmVspParams.liodnOffset = + p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset; + memcpy(&fmVspParams.extBufPools, + &p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools, + sizeof(t_FmExtPools)); + } + else + { + memcpy(&fmVspParams.extBufPools, + &p_LnxWrpFmPortDev->opExtPools, + sizeof(t_FmExtPools)); + } + + if ((err = FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, + &portVSPAllocParams)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* We're initializing only the default VSP that are being used by the Linux-Ethernet-driver */ + if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + !p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed) + return E_OK; + + p_LnxWrpFmPortDev->h_DfltVsp = FM_VSP_Config(&fmVspParams); + if (!p_LnxWrpFmPortDev->h_DfltVsp) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("default-VSP for port!")); + + if ((err = FM_VSP_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_DfltVsp, + &p_LnxWrpFmPortDev->buffPrefixContent)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + if ((err = FM_VSP_Init(p_LnxWrpFmPortDev->h_DfltVsp)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } +#else +UNUSED(err); UNUSED(uint32_prop); UNUSED(lenp); +#endif /* (DPAA_VERSION >= 11) */ + + of_node_put(port_node); + of_node_put(fm_node); + + return E_OK; +} + +static t_Error ConfigureFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct resource *dev_res; + + if (!p_LnxWrpFmPortDev->active) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("FM port not configured!!!")); + + dev_res = + __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize, + "fman-port-hc"); + if (unlikely(dev_res == NULL)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("__devm_request_region() failed")); + p_LnxWrpFmPortDev->baseAddr = + PTR_TO_UINT(devm_ioremap + (p_LnxWrpFmDev->dev, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize)); + if (unlikely(p_LnxWrpFmPortDev->baseAddr == 0)) + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("devm_ioremap() failed")); + + p_LnxWrpFmPortDev->settings.param.baseAddr = + p_LnxWrpFmPortDev->baseAddr; + + return E_OK; +} + +static t_Error InitFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ +#define MY_ADV_CONFIG_CHECK_END \ + RETURN_ERROR(MAJOR, E_INVALID_SELECTION,\ + ("Advanced configuration routine"));\ + if (errCode != E_OK)\ + RETURN_ERROR(MAJOR, errCode, NO_MSG);\ + } + + int i = 0; + + if (!p_LnxWrpFmPortDev->active || p_LnxWrpFmPortDev->h_Dev) + return E_INVALID_STATE; + + p_LnxWrpFmPortDev->h_Dev = + FM_PORT_Config(&p_LnxWrpFmPortDev->settings.param); + if (p_LnxWrpFmPortDev->h_Dev == NULL) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-port")); + +#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + || (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX)) { + t_Error errCode = E_OK; + errCode = + FM_PORT_ConfigDeqHighPriority(p_LnxWrpFmPortDev->h_Dev, + TRUE); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + errCode = + FM_PORT_ConfigDeqPrefetchOption(p_LnxWrpFmPortDev->h_Dev, + e_FM_PORT_DEQ_FULL_PREFETCH); + if (errCode + != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + } +#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + +#ifdef FM_BCB_ERRATA_BMI_SW001 +/* Configure BCB workaround on Rx ports, only for B4860 rev1 */ +#define SVR_SECURITY_MASK 0x00080000 +#define SVR_PERSONALITY_MASK 0x0000FF00 +#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK) +#define SVR_B4860_REV1_VALUE 0x86800010 + + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) || + (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX)) { + unsigned int svr; + + svr = mfspr(SPRN_SVR); + + if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE) + FM_PORT_ConfigBCBWorkaround(p_LnxWrpFmPortDev->h_Dev); + } +#endif /* FM_BCB_ERRATA_BMI_SW001 */ + +/* Call the driver's advanced configuration routines, if requested: + Compare the function pointer of each entry to the available routines, + and invoke the matching routine with proper casting of arguments. */ + while (p_LnxWrpFmPortDev->settings.advConfig[i].p_Function + && (i < FM_MAX_NUM_OF_ADV_SETTINGS)) { + +/* TODO: Change this MACRO */ + ADV_CONFIG_CHECK_START( + &(p_LnxWrpFmPortDev->settings.advConfig[i])) + + ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev, + FM_PORT_ConfigBufferPrefixContent, + NCSW_PARAMS(1, + (t_FmBufferPrefixContent *))) + + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + (p_LnxWrpFmPortDev->settings.frag_enabled == TRUE)) { + + ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev, + FM_PORT_ConfigExtBufPools, + NCSW_PARAMS(1, (t_FmExtPools *))) + + /* this define contains an else */ + MY_ADV_CONFIG_CHECK_END + } + + /* Advance to next advanced configuration entry */ + i++; + } + +#if defined(CONFIG_FMAN_RESOURCE_ALLOCATION_ALGORITHM) +#if (DPAA_VERSION >= 11) +#warning The resource allocation algorithm is not available for FMan v3 platforms +#else + /* even if these functions return w/ error, do not crash kernel. + Do not return anything because the container function is not + linux complient (it should return -EIO). */ + fm_config_precalculate_fifosize(p_LnxWrpFmPortDev); + fm_config_precalculate_open_dma(p_LnxWrpFmPortDev); + fm_config_precalculate_tnums(p_LnxWrpFmPortDev); +#endif +#endif + + if ((p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX) && + (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX_10G)) { + if (FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev, (FM_PORT_FRM_ERR_IPRE | + FM_PORT_FRM_ERR_IPR_NCSP | + FM_PORT_FRM_ERR_CLS_DISCARD)) !=E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + } + + if (CheckNConfigFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (FM_PORT_Init(p_LnxWrpFmPortDev->h_Dev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (CheckNSetFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + +/* FMan Fifo sizes behind the scene": + * Using the following formulae (*), under a set of simplifying assumptions (.): + * . all ports are configured in Normal Mode (rather than Independent Mode) + * . the DPAA Eth driver allocates buffers of size: + * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE + * + DPA_HASH_RESULTS_SIZE, i.e.: + * MAXFRM + 2 + 16 + sizeof(t_FmPrsResult) + 16, i.e.: + * MAXFRM + 66 + * . excessive buffer pools not accounted for + * + * * for Rx ports on P4080: + * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256) * 256 + 7 * 256 + * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + * * for Rx ports on P1023: + * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256)) * 256 + 7 * 256, + * if at least 2 bpools are configured + * . IFSZ = 8 * 256, if only a single bpool is configured + * + * * for Tx ports: + * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + * + FMBM_TFP[DPDE] * 256, i.e.: + * IFSZ = ceil(MAXFRM / 256) * 256 + 3 x 256 + FMBM_TFP[DPDE] * 256 + * + * * for OH ports on P4080: + * . IFSZ = ceil(frame_size / 256) * 256 + 1 * 256 + FMBM_PP[MXT] * 256 + * * for OH ports on P1023: + * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + FMBM_TFP[DPDE] * 256 + * * for both P4080 and P1023: + * . (conservative decisions, assuming that BMI must bring the entire + * frame, not only the frame header) + * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise, + * add up to 256 to the above + * + * . for P4080/P5020/P3041/P2040, DPDE is: + * > 0 or 1, for 1Gb ports, HW default: 0 + * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3 + * . for P1023, DPDE should be 1 + * + * . for P1023, MXT is in range (0..31) + * . for P4080, MXT is in range (0..63) + * + */ +#if 0 + if ((p_LnxWrpFmPortDev->defPcd != e_NO_PCD) && + (InitFmPort3TupleDefPcd(p_LnxWrpFmPortDev) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); +#endif + return E_OK; +} + +void fm_set_rx_port_params(struct fm_port *port, + struct fm_port_params *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; + int i; + + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.errFqid = + params->errq; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.dfltFqid = + params->defq; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools. + numOfPoolsUsed = params->num_pools; + for (i = 0; i < params->num_pools; i++) { + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. + extBufPools.extBufPool[i].id = + params->pool_param[i].id; + p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. + extBufPools.extBufPool[i].size = + params->pool_param[i].size; + } + + p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = + params->priv_data_size; + p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = + params->parse_results; + p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = + params->hash_results; + p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = + params->time_stamp; + p_LnxWrpFmPortDev->buffPrefixContent.dataAlign = + params->data_align; + p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace = + params->manip_extra_space; + + ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, + FM_MAX_NUM_OF_ADV_SETTINGS) + + ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, + ARGS(1, + (&p_LnxWrpFmPortDev-> + buffPrefixContent))); + + ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); +} +EXPORT_SYMBOL(fm_set_rx_port_params); + +/* this function is called from oh_probe as well, thus it contains oh port + * specific parameters (make sure everything is checked) */ +void fm_set_tx_port_params(struct fm_port *port, + struct fm_port_params *params) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; + + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.errFqid = + params->errq; + p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. + dfltFqid = params->defq; + + p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = + params->priv_data_size; + p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = + params->parse_results; + p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = + params->hash_results; + p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = + params->time_stamp; + p_LnxWrpFmPortDev->settings.frag_enabled = + params->frag_enable; + p_LnxWrpFmPortDev->buffPrefixContent.dataAlign = + params->data_align; + p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace = + params->manip_extra_space; + + ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, + FM_MAX_NUM_OF_ADV_SETTINGS) + + ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, + ARGS(1, + (&p_LnxWrpFmPortDev-> + buffPrefixContent))); + + /* oh port specific parameter (for fragmentation only) */ + if ((p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + params->num_pools) { + int i; + + p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed = params->num_pools; + for (i = 0; i < params->num_pools; i++) { + p_LnxWrpFmPortDev->opExtPools.extBufPool[i].id = params->pool_param[i].id; + p_LnxWrpFmPortDev->opExtPools.extBufPool[i].size = params->pool_param[i].size; + } + + if (p_LnxWrpFmPortDev->settings.frag_enabled) + ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigExtBufPools, + ARGS(1, (&p_LnxWrpFmPortDev->opExtPools))); + } + + ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); +} +EXPORT_SYMBOL(fm_set_tx_port_params); + +void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, + t_Handle h_fm_mac, + int mac_id) +{ + t_LnxWrpFmDev *p_lnx_wrp_fm_dev = (t_LnxWrpFmDev *)h_lnx_wrp_fm_dev; + + p_lnx_wrp_fm_dev->macs[mac_id].h_Dev = h_fm_mac; + p_lnx_wrp_fm_dev->macs[mac_id].h_LnxWrpFmDev = h_lnx_wrp_fm_dev; +} +EXPORT_SYMBOL(fm_mac_set_handle); + +static void LnxwrpFmPcdDevExceptionsCb(t_Handle h_App, + e_FmPcdExceptions exception) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, ("got fm-pcd exception %d", exception)); + + /* do nothing */ + UNUSED(exception); +} + +static void LnxwrpFmPcdDevIndexedExceptionsCb(t_Handle h_App, + e_FmPcdExceptions exception, + uint16_t index) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; + + ASSERT_COND(p_LnxWrpFmDev); + + DBG(INFO, + ("got fm-pcd-indexed exception %d, indx %d", exception, index)); + + /* do nothing */ + UNUSED(exception); + UNUSED(index); +} + +static t_Error InitFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + spin_lock_init(&lock); + + if (p_LnxWrpFmDev->pcdActive) { + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + t_FmPcdParams fmPcdParams; + t_Error err; + + memset(&fmPcdParams, 0, sizeof(fmPcdParams)); + fmPcdParams.h_Fm = p_LnxWrpFmDev->h_Dev; + fmPcdParams.prsSupport = p_LnxWrpFmDev->prsActive; + fmPcdParams.kgSupport = p_LnxWrpFmDev->kgActive; + fmPcdParams.plcrSupport = p_LnxWrpFmDev->plcrActive; + fmPcdParams.ccSupport = p_LnxWrpFmDev->ccActive; + fmPcdParams.numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; + +#ifndef CONFIG_GUEST_PARTITION + fmPcdParams.f_Exception = LnxwrpFmPcdDevExceptionsCb; + if (fmPcdParams.kgSupport) + fmPcdParams.f_ExceptionId = + LnxwrpFmPcdDevIndexedExceptionsCb; + fmPcdParams.h_App = p_LnxWrpFmDev; +#endif /* !CONFIG_GUEST_PARTITION */ + +#ifdef CONFIG_MULTI_PARTITION_SUPPORT + fmPcdParams.numOfSchemes = 0; + fmPcdParams.numOfClsPlanEntries = 0; + fmPcdParams.partitionId = 0; +#endif /* CONFIG_MULTI_PARTITION_SUPPORT */ + fmPcdParams.useHostCommand = TRUE; + + p_LnxWrpFmDev->hc_tx_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_TO_DCPORTAL, + p_LnxWrpFmPortDev->txCh, 0); + if (!p_LnxWrpFmDev->hc_tx_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + p_LnxWrpFmDev->hc_tx_conf_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_NO_ENQUEUE, + p_LnxWrpFmDev->hcCh, 7); + if (!p_LnxWrpFmDev->hc_tx_conf_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + p_LnxWrpFmDev->hc_tx_err_fq = + FqAlloc(p_LnxWrpFmDev, + 0, + QMAN_FQ_FLAG_NO_ENQUEUE, + p_LnxWrpFmDev->hcCh, 7); + if (!p_LnxWrpFmDev->hc_tx_err_fq) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("Frame queue allocation failed...")); + + fmPcdParams.hc.portBaseAddr = p_LnxWrpFmPortDev->baseAddr; + fmPcdParams.hc.portId = + p_LnxWrpFmPortDev->settings.param.portId; + fmPcdParams.hc.liodnBase = + p_LnxWrpFmPortDev->settings.param.liodnBase; + fmPcdParams.hc.errFqid = + qman_fq_fqid(p_LnxWrpFmDev->hc_tx_err_fq); + fmPcdParams.hc.confFqid = + qman_fq_fqid(p_LnxWrpFmDev->hc_tx_conf_fq); + fmPcdParams.hc.qmChannel = p_LnxWrpFmPortDev->txCh; + fmPcdParams.hc.f_QmEnqueue = QmEnqueueCB; + fmPcdParams.hc.h_QmArg = (t_Handle) p_LnxWrpFmDev; + + p_LnxWrpFmDev->h_PcdDev = FM_PCD_Config(&fmPcdParams); + if (!p_LnxWrpFmDev->h_PcdDev) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!")); + + err = + FM_PCD_ConfigPlcrNumOfSharedProfiles(p_LnxWrpFmDev->h_PcdDev, + LNXWRP_FM_NUM_OF_SHARED_PROFILES); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FM_PCD_Init(p_LnxWrpFmDev->h_PcdDev); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_LnxWrpFmDev->err_irq == 0) { + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, + FALSE); + FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, + e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC, + FALSE); + } + } + + return E_OK; +} + +void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + + if (p_LnxWrpFmDev->h_PcdDev) + FM_PCD_Free(p_LnxWrpFmDev->h_PcdDev); + + if (p_LnxWrpFmDev->hc_tx_err_fq) + FqFree(p_LnxWrpFmDev->hc_tx_err_fq); + + if (p_LnxWrpFmDev->hc_tx_conf_fq) + FqFree(p_LnxWrpFmDev->hc_tx_conf_fq); + + if (p_LnxWrpFmDev->hc_tx_fq) + FqFree(p_LnxWrpFmDev->hc_tx_fq); +} + +static void FreeFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + + if (!p_LnxWrpFmPortDev->active) + return; + + if (p_LnxWrpFmPortDev->h_Dev) + FM_PORT_Free(p_LnxWrpFmPortDev->h_Dev); + + devm_iounmap(p_LnxWrpFmDev->dev, + UINT_TO_PTR(p_LnxWrpFmPortDev->baseAddr)); + __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, + p_LnxWrpFmPortDev->phys_baseAddr, + p_LnxWrpFmPortDev->memSize); +} + +static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + + p_LnxWrpFmPortDev = ReadFmPortDevTreeNode(of_dev); + if (p_LnxWrpFmPortDev == NULL) + return -EIO; + /* Port can be inactive, thus will not be probed: + - in performance mode, OH ports are disabled + ... + */ + if (!p_LnxWrpFmPortDev->active) + return 0; + + if (ConfigureFmPortDev(p_LnxWrpFmPortDev) != E_OK) + return -EIO; + + dev_set_drvdata(dev, p_LnxWrpFmPortDev); + + if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_HOST_COMMAND) + InitFmPcdDev((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev); + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_RX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", + p_LnxWrpFmDev->name, + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS + + DEV_FM_RX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_TX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", + p_LnxWrpFmDev->name, + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS + + DEV_FM_TX_PORTS_MINOR_BASE; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_HOST_COMMAND) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + DEV_FM_OH_PORTS_MINOR_BASE; + p_LnxWrpFmPortDev->h_Dev = FM_PCD_GetHcDevH(p_LnxWrpFmDev->h_PcdDev); + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { + Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", + p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id + 1); + p_LnxWrpFmPortDev->minor = + p_LnxWrpFmPortDev->id + 1 + + DEV_FM_OH_PORTS_MINOR_BASE; + } + + device_create(p_LnxWrpFmDev->fm_class, NULL, + MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor), + NULL, p_LnxWrpFmPortDev->name); + + /* create sysfs entries for stats and regs */ + + if (fm_port_sysfs_create(dev) != 0) { + FreeFmPortDev(p_LnxWrpFmPortDev); + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("Unable to create sys entry - fm port!!!")); + return -EIO; + } + +#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 + FM_DisableRamsEcc(p_LnxWrpFmDev->h_Dev); +#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */ + + DBG(TRACE, ("%s probed", p_LnxWrpFmPortDev->name)); + + return 0; +} + +static int fm_port_remove(struct platform_device *of_dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + struct device *dev; + + dev = &of_dev->dev; + p_LnxWrpFmPortDev = dev_get_drvdata(dev); + + fm_port_sysfs_destroy(dev); + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + device_destroy(p_LnxWrpFmDev->fm_class, + MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor)); + + FreeFmPortDev(p_LnxWrpFmPortDev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct of_device_id fm_port_match[] = { + { + .compatible = "fsl,fman-port-oh"}, + { + .compatible = "fsl,fman-port-1g-rx"}, + { + .compatible = "fsl,fman-port-10g-rx"}, + { + .compatible = "fsl,fman-port-1g-tx"}, + { + .compatible = "fsl,fman-port-10g-tx"}, + {} +}; + +#ifndef MODULE +MODULE_DEVICE_TABLE(of, fm_port_match); +#endif /* !MODULE */ + +static struct platform_driver fm_port_driver = { + + .driver = { + .name = "fsl-fman-port", + .of_match_table = fm_port_match, + .owner = THIS_MODULE, + }, + .probe = fm_port_probe, + .remove = fm_port_remove +}; + + +t_Error LNXWRP_FM_Port_Init(void) +{ + /* Register to the DTB for basic FM port API */ + if (platform_driver_register(&fm_port_driver)) + return E_NO_DEVICE; + + return E_OK; +} + +void LNXWRP_FM_Port_Free(void) +{ + platform_driver_unregister(&fm_port_driver); +} + +static int __init __cold fm_port_load(void) +{ + if (LNXWRP_FM_Port_Init() != E_OK) { + printk(KERN_CRIT "Failed to init FM Ports wrapper!\n"); + return -ENODEV; + } + + printk(KERN_CRIT "Freescale FM Ports module (" __DATE__ ":" __TIME__ + ")\n"); + + return 0; +} + +static void __exit __cold fm_port_unload(void) +{ + LNXWRP_FM_Port_Free(); +} + +module_init(fm_port_load); +module_exit(fm_port_unload); diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm.c new file mode 100644 index 0000000..c958675 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm.c @@ -0,0 +1,4423 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_ioctls_fm.c + @Author Shlomi Gridish + @Description FM Linux wrapper functions. +*/ + +/* Linux Headers ------------------- */ +#include <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/of_platform.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <sysdev/fsl_soc.h> + +#if defined(CONFIG_COMPAT) +#include <linux/compat.h> +#endif + +#include "part_ext.h" +#include "fm_ioctls.h" +#include "fm_pcd_ioctls.h" +#include "fm_port_ioctls.h" +#include "fm_vsp_ext.h" + +#if defined(CONFIG_COMPAT) +#include "lnxwrp_ioctls_fm_compat.h" +#endif + +#include "lnxwrp_fm.h" + +#include "dpaa_eth.h" + +#define CMP_IOC_DEFINE(def) (IOC_##def != def) + +/* fm_pcd_ioctls.h === fm_pcd_ext.h assertions */ +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_GENERIC_REGS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_EXTRACT_MASKS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_DEFAULT_GROUPS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_LABELS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_SW_PRS_SIZE) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_SW_OFFSET) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_SW_PATCHES_SIZE) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_PRS_SW_TAIL_SIZE) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_SW_PRS_MAX_IMAGE_SIZE) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE) +#error Error: please synchronize IOC_ defines! +#endif + +#if DPAA_VERSION >= 11 +#if CMP_IOC_DEFINE(FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES) +#error Error: please synchronize IOC_ defines! +#endif +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_TREES) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_GROUPS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_UNITS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_KEYS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_SIZE_OF_KEY) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(FM_PCD_LAST_KEY_INDEX) +#error Error: please synchronize IOC_ defines! +#endif + +/* net_ioctls.h === net_ext.h assertions */ +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_PID) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_COMPRESSED) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPoE_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ETH_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv4_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv6_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ICMP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IGMP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_TCP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_DCCP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPHC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv2_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_VLAN_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_NLPID_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SNAP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS) +#warning Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ARP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_RFC2684_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_GRE_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MINENCAP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MACSEC_ALL_FIELDS) +#error Error: please synchronize IOC_ defines! +#endif + +/* fm_ioctls.h === fm_ext.h assertions */ +#if CMP_IOC_DEFINE(FM_MAX_NUM_OF_VALID_PORTS) +#error Error: please synchronize IOC_ defines! +#endif + +void LnxWrpPCDIOCTLTypeChecking(void) +{ + /* fm_ext.h == fm_ioctls.h */ + ASSERT_COND(sizeof(ioc_fm_port_bandwidth_params) == sizeof(t_FmPortsBandwidthParams)); + ASSERT_COND(sizeof(ioc_fm_revision_info_t) == sizeof(t_FmRevisionInfo)); + + /* fm_pcd_ext.h == fm_pcd_ioctls.h */ + /*ioc_fm_pcd_counters_params_t : NOT USED */ + /*ioc_fm_pcd_exception_params_t : private */ + ASSERT_COND(sizeof(ioc_fm_pcd_prs_label_params_t) == sizeof(t_FmPcdPrsLabelParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_prs_sw_params_t) == sizeof(t_FmPcdPrsSwParams)); + /*ioc_fm_pcd_kg_dflt_value_params_t : private */ + ASSERT_COND(sizeof(ioc_fm_pcd_hdr_protocol_opt_u) == sizeof(u_FmPcdHdrProtocolOpt)); + ASSERT_COND(sizeof(ioc_fm_pcd_fields_u) == sizeof(t_FmPcdFields)); + ASSERT_COND(sizeof(ioc_fm_pcd_from_hdr_t) == sizeof(t_FmPcdFromHdr)); + ASSERT_COND(sizeof(ioc_fm_pcd_from_field_t) == sizeof(t_FmPcdFromField)); + ASSERT_COND(sizeof(ioc_fm_pcd_distinction_unit_t) == sizeof(t_FmPcdDistinctionUnit)); +#if !defined(CONFIG_COMPAT) + /* different alignment */ + ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_extract_entry_t) == sizeof(t_FmPcdExtractEntry)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_mask_t) == sizeof(t_FmPcdKgExtractMask)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_dflt_t) == sizeof(t_FmPcdKgExtractDflt)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t) == sizeof(t_FmPcdKgKeyExtractAndHashParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_extracted_or_params_t) == sizeof(t_FmPcdKgExtractedOrParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_counter_t) == sizeof(t_FmPcdKgSchemeCounter)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_plcr_profile_t) == sizeof(t_FmPcdKgPlcrProfile)); +#if (DPAA_VERSION >= 11) + ASSERT_COND(sizeof(ioc_fm_pcd_kg_storage_profile_t) == sizeof(t_FmPcdKgStorageProfile)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_kg_cc_t) == sizeof(t_FmPcdKgCc)); +#if !defined(CONFIG_COMPAT) + /* different alignment */ + ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_params_t) == sizeof(t_FmPcdKgSchemeParams) + sizeof(void *)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_cc_params_t) == sizeof(t_FmPcdCcNextCcParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_plcr_params_t) == sizeof(t_FmPcdCcNextPlcrParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_enqueue_params_t) == sizeof(t_FmPcdCcNextEnqueueParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_kg_params_t) == sizeof(t_FmPcdCcNextKgParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams)); + ASSERT_COND(sizeof(ioc_keys_params_t) == sizeof(t_KeysParams)); +#if !defined(CONFIG_COMPAT) + /* different alignment */ + ASSERT_COND(sizeof(ioc_fm_pcd_cc_node_params_t) == sizeof(t_FmPcdCcNodeParams) + sizeof(void *)); + ASSERT_COND(sizeof(ioc_fm_pcd_hash_table_params_t) == sizeof(t_FmPcdHashTableParams) + sizeof(void *)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_cc_grp_params_t) == sizeof(t_FmPcdCcGrpParams)); +#if !defined(CONFIG_COMPAT) + /* different alignment */ + ASSERT_COND(sizeof(ioc_fm_pcd_cc_tree_params_t) == sizeof(t_FmPcdCcTreeParams) + sizeof(void *)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_plcr_byte_rate_mode_param_t) == sizeof(t_FmPcdPlcrByteRateModeParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t) == sizeof(t_FmPcdPlcrNonPassthroughAlgParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_plcr_next_engine_params_u) == sizeof(u_FmPcdPlcrNextEngineParams)); + /*ioc_fm_pcd_port_params_t : private */ + ASSERT_COND(sizeof(ioc_fm_pcd_plcr_profile_params_t) == sizeof(t_FmPcdPlcrProfileParams) + sizeof(void *)); + /*ioc_fm_pcd_cc_tree_modify_next_engine_params_t : private */ + +#ifdef FM_CAPWAP_SUPPORT +#error TODO: unsupported feature +/* + ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipHdrInsrtByTemplateParams)); + ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapFragmentationParams)); + ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapReassemblyParams)); + ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipFragOrReasmParams)); + ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipHdrRmvByHdrParams)); +*/ +#endif + + /*ioc_fm_pcd_cc_node_modify_next_engine_params_t : private */ + /*ioc_fm_pcd_cc_node_remove_key_params_t : private */ + /*ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t : private */ + /*ioc_fm_pcd_cc_node_modify_key_params_t : private */ + /*ioc_fm_manip_hdr_info_t : private */ + /*ioc_fm_pcd_hash_table_set_t : private */ + ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_params_t) == sizeof(t_FmPcdManipFragIpParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_params_t) == sizeof(t_FmPcdManipReassemIpParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_ipsec_params_t) == sizeof(t_FmPcdManipSpecialOffloadIPSecParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_params_t) == sizeof(t_FmPcdManipSpecialOffloadParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_generic_params_t) == sizeof(t_FmPcdManipHdrRmvGenericParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_generic_params_t) == sizeof(t_FmPcdManipHdrInsrtGenericParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_params_t) == sizeof(t_FmPcdManipHdrInsrtParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_params_t) == sizeof(t_FmPcdManipHdrRmvParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_params_t) == sizeof(t_FmPcdManipHdrParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_params_t) == sizeof(t_FmPcdManipReassemParams)); +#if !defined(CONFIG_COMPAT) + /* different alignment */ + ASSERT_COND(sizeof(ioc_fm_pcd_manip_params_t) == sizeof(t_FmPcdManipParams) + sizeof(void *)); +#endif + ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_stats_t) == sizeof(t_FmPcdManipReassemIpStats)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_stats_t) == sizeof(t_FmPcdManipFragIpStats)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_stats_t) == sizeof(t_FmPcdManipReassemStats)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_stats_t) == sizeof(t_FmPcdManipFragStats)); + ASSERT_COND(sizeof(ioc_fm_pcd_manip_stats_t) == sizeof(t_FmPcdManipStats)); +#if DPAA_VERSION >= 11 + ASSERT_COND(sizeof(ioc_fm_pcd_frm_replic_group_params_t) == sizeof(t_FmPcdFrmReplicGroupParams) + sizeof(void *)); +#endif + + /* fm_port_ext.h == fm_port_ioctls.h */ + ASSERT_COND(sizeof(ioc_fm_port_rate_limit_t) == sizeof(t_FmPortRateLimit)); + ASSERT_COND(sizeof(ioc_fm_port_pcd_params_t) == sizeof(t_FmPortPcdParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_select_t) == sizeof(t_FmPcdKgSchemeSelect)); + ASSERT_COND(sizeof(ioc_fm_pcd_port_schemes_params_t) == sizeof(t_FmPcdPortSchemesParams)); + ASSERT_COND(sizeof(ioc_fm_pcd_prs_start_t) == sizeof(t_FmPcdPrsStart)); + + return; +} + +#define ASSERT_IOC_NET_ENUM(def) ASSERT_COND((unsigned long)e_IOC_NET_##def == (unsigned long)def) + +void LnxWrpPCDIOCTLEnumChecking(void) +{ + /* net_ext.h == net_ioctls.h : sampling checks */ + ASSERT_IOC_NET_ENUM(HEADER_TYPE_MACSEC); + ASSERT_IOC_NET_ENUM(HEADER_TYPE_PPP); + ASSERT_IOC_NET_ENUM(MAX_HEADER_TYPE_COUNT); + + /* fm_ext.h == fm_ioctls.h */ + ASSERT_COND((unsigned long)e_IOC_FM_PORT_TYPE_DUMMY == (unsigned long)e_FM_PORT_TYPE_DUMMY); + ASSERT_COND((unsigned long)e_IOC_EX_MURAM_ECC == (unsigned long)e_FM_EX_MURAM_ECC); + ASSERT_COND((unsigned long)e_IOC_FM_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_COUNTERS_DEQ_CONFIRM); + + /* fm_pcd_ext.h == fm_pcd_ioctls.h */ + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES == (unsigned long)e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC == (unsigned long)e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS == (unsigned long)e_FM_PCD_PRS); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FULL_FIELD == (unsigned long)e_FM_PCD_EXTRACT_FULL_FIELD); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID == (unsigned long)e_FM_PCD_EXTRACT_FROM_FLOW_ID); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO == (unsigned long)e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_DFLT_ILLEGAL == (unsigned long)e_FM_PCD_KG_DFLT_ILLEGAL); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA == (unsigned long)e_FM_PCD_KG_GENERIC_NOT_FROM_DATA); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_HDR_INDEX_LAST == (unsigned long)e_FM_PCD_HDR_INDEX_LAST); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_SHARED == (unsigned long)e_FM_PCD_PLCR_SHARED); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_RFC_4115 == (unsigned long)e_FM_PCD_PLCR_RFC_4115); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_COLOR_AWARE == (unsigned long)e_FM_PCD_PLCR_COLOR_AWARE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_OVERRIDE == (unsigned long)e_FM_PCD_PLCR_OVERRIDE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_FULL_FRM_LEN); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PACKET_MODE == (unsigned long)e_FM_PCD_PLCR_PACKET_MODE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_DROP_FRAME == (unsigned long)e_FM_PCD_DROP_FRAME); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER == (unsigned long)e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP == (unsigned long)e_FM_PCD_ACTION_INDEXED_LOOKUP); + ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR); +#if !defined(FM_CAPWAP_SUPPORT) + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_GENERIC == (unsigned long)e_FM_PCD_MANIP_INSRT_GENERIC); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_GENERIC == (unsigned long)e_FM_PCD_MANIP_RMV_GENERIC); +#else + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE == (unsigned long)e_FM_PCD_MANIP_INSRT_BY_TEMPLATE); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START); +#endif + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG == (unsigned long)e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH == (unsigned long)e_FM_PCD_MANIP_EIGHT_WAYS_HASH); + +#ifdef FM_CAPWAP_SUPPORT + ASSERT_COND((unsigned long)e_IOC_FM_PCD_STATS_PER_FLOWID == (unsigned long)e_FM_PCD_STATS_PER_FLOWID); +#endif + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_CC_STATS_MODE_FRAME == (unsigned long)e_FM_PCD_CC_STATS_MODE_FRAME); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG == (unsigned long)e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG); + ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC); + + /* fm_port_ext.h == fm_port_ioctls.h */ +#if !defined(FM_CAPWAP_SUPPORT) + ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR); +#else + ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR); +#endif + ASSERT_COND((unsigned long)e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_PORT_COUNTERS_DEQ_CONFIRM); + ASSERT_COND((unsigned long)e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 == (unsigned long)e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8); + + return; +} + +static t_Error LnxwrpFmPcdIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_OK; + +/* +Status: PCD API to fmlib (file: drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h): + + FM_PCD_PrsLoadSw + FM_PCD_SetAdvancedOffloadSupport + FM_PCD_Enable + FM_PCD_Disable + FM_PCD_ForceIntr + FM_PCD_SetException + FM_PCD_KgSetAdditionalDataAfterParsing + FM_PCD_KgSetDfltValue + FM_PCD_NetEnvCharacteristicsSet + FM_PCD_NetEnvCharacteristicsDelete + FM_PCD_KgSchemeSet + FM_PCD_KgSchemeDelete + FM_PCD_MatchTableSet + FM_PCD_MatchTableDelete + FM_PCD_CcRootBuild + FM_PCD_CcRootDelete + FM_PCD_PlcrProfileSet + FM_PCD_PlcrProfileDelete + FM_PCD_CcRootModifyNextEngine + FM_PCD_MatchTableModifyNextEngine + FM_PCD_MatchTableModifyMissNextEngine + FM_PCD_MatchTableRemoveKey + FM_PCD_MatchTableAddKey + FM_PCD_MatchTableModifyKeyAndNextEngine + FM_PCD_HashTableSet + FM_PCD_HashTableDelete + FM_PCD_HashTableAddKey + FM_PCD_HashTableRemoveKey + FM_PCD_MatchTableModifyKey + FM_PCD_ManipNodeReplace + FM_PCD_ManipNodeSet + FM_PCD_ManipNodeDelete + +Status: not exported, should be thru sysfs + FM_PCD_KgSchemeGetCounter + FM_PCD_KgSchemeSetCounter + FM_PCD_PlcrProfileGetCounter + FM_PCD_PlcrProfileSetCounter + +Status: not exported + FM_PCD_MatchTableFindNRemoveKey + FM_PCD_MatchTableFindNModifyNextEngine + FM_PCD_MatchTableFindNModifyKeyAndNextEngine + FM_PCD_MatchTableFindNModifyKey + FM_PCD_MatchTableGetIndexedHashBucket + FM_PCD_MatchTableGetNextEngine + FM_PCD_MatchTableGetKeyCounter + +Status: not exported, would be nice to have + FM_PCD_HashTableModifyNextEngine + FM_PCD_HashTableModifyMissNextEngine + FM_PCD_HashTableGetMissNextEngine + FM_PCD_ManipGetStatistics + +Status: not exported +#if DPAA_VERSION >= 11 + + FM_VSP_GetStatistics -- it's not available yet +#endif + +Status: feature not supported +#ifdef FM_CAPWAP_SUPPORT +#error unsupported feature + FM_PCD_StatisticsSetNode +#endif + + */ + _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n", + cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 20); + + switch (cmd) + { +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PRS_LOAD_SW_COMPAT: +#endif + case FM_PCD_IOC_PRS_LOAD_SW: + { + ioc_fm_pcd_prs_sw_params_t *param; + uint8_t *p_code; + + param = (ioc_fm_pcd_prs_sw_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_sw_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_prs_sw_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_prs_sw_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_prs_sw_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_prs_sw_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_prs_sw_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_prs_sw_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_prs_sw_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_fm_pcd_prs_sw(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_prs_sw_params_t *)arg, + sizeof(ioc_fm_pcd_prs_sw_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (!param->p_code || !param->size) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + p_code = (uint8_t *) XX_Malloc(param->size); + if (!p_code) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(p_code, 0, param->size); + if (copy_from_user(p_code, param->p_code, param->size)) + { + XX_Free(p_code); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->p_code = p_code; + + err = FM_PCD_PrsLoadSw(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPrsSwParams*)param); + + XX_Free(p_code); + XX_Free(param); + break; + } + + case FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT: + err = FM_PCD_SetAdvancedOffloadSupport(p_LnxWrpFmDev->h_PcdDev); + break; + + case FM_PCD_IOC_ENABLE: + err = FM_PCD_Enable(p_LnxWrpFmDev->h_PcdDev); + break; + + case FM_PCD_IOC_DISABLE: + err = FM_PCD_Disable(p_LnxWrpFmDev->h_PcdDev); + break; + + case FM_PCD_IOC_FORCE_INTR: + { + int exception; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(exception, (int *) compat_ptr(arg))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + { + if (get_user(exception, (int *)arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_ForceIntr(p_LnxWrpFmDev->h_PcdDev, (e_FmPcdExceptions)exception); + break; + } + + case FM_PCD_IOC_SET_EXCEPTION: + { + ioc_fm_pcd_exception_params_t *param; + + param = (ioc_fm_pcd_exception_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_exception_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_exception_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_exception_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)arg, + sizeof(ioc_fm_pcd_exception_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, param->exception, param->enable); + + XX_Free(param); + break; + } + + case FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING: + { + uint8_t payloadOffset; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(payloadOffset, (uint8_t*) compat_ptr(arg))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + { + if (get_user(payloadOffset, (uint8_t*) arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_KgSetAdditionalDataAfterParsing(p_LnxWrpFmDev->h_PcdDev, payloadOffset); + break; + } + + case FM_PCD_IOC_KG_SET_DFLT_VALUE: + { + ioc_fm_pcd_kg_dflt_value_params_t *param; + + param = (ioc_fm_pcd_kg_dflt_value_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_kg_dflt_value_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_kg_dflt_value_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)arg, + sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_KgSetDfltValue(p_LnxWrpFmDev->h_PcdDev, param->valueId, param->value); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT: +#endif + case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET: + { + ioc_fm_pcd_net_env_params_t *param; + + param = (ioc_fm_pcd_net_env_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_net_env_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_net_env_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_net_env_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_net_env_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t)); + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_net_env_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_US_TO_K); + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_net_env_params_t *) arg, + sizeof(ioc_fm_pcd_net_env_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + param->id = FM_PCD_NetEnvCharacteristicsSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdNetEnvParams*)param); + + if (!param->id) + { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_net_env_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_net_env_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t)); + compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_K_TO_US); + + if (copy_to_user((ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_net_env_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_net_env_params_t *)arg, + param, + sizeof(ioc_fm_pcd_net_env_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT: +#endif + case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_NetEnvCharacteristicsDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_KG_SCHEME_SET_COMPAT: +#endif + case FM_PCD_IOC_KG_SCHEME_SET: + { + ioc_fm_pcd_kg_scheme_params_t *param; + + param = (ioc_fm_pcd_kg_scheme_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_params_t *)arg, + sizeof(ioc_fm_pcd_kg_scheme_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + param->id = FM_PCD_KgSchemeSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdKgSchemeParams*)param); + + if (!param->id) + { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); + compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_K_TO_US); + if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_kg_scheme_params_t *)arg, + param, + sizeof(ioc_fm_pcd_kg_scheme_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT: +#endif + case FM_PCD_IOC_KG_SCHEME_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_KgSchemeDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_SET_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_SET: + { + ioc_fm_pcd_cc_node_params_t *param; + uint8_t *keys; + uint8_t *masks; + int i,k; + + param = (ioc_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + + keys = (uint8_t *) (param + 1); + masks = keys + IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_params_t *)arg, sizeof(ioc_fm_pcd_cc_node_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + ASSERT_COND(param->keys_params.num_of_keys <= IOC_FM_PCD_MAX_NUM_OF_KEYS); + ASSERT_COND(param->keys_params.key_size <= IOC_FM_PCD_MAX_SIZE_OF_KEY); + + /* support for indexed lookup */ + if( !(param->extract_cc_params.type == e_IOC_FM_PCD_EXTRACT_NON_HDR && + param->extract_cc_params.extract_params.extract_non_hdr.src == e_IOC_FM_PCD_EXTRACT_FROM_HASH && + param->extract_cc_params.extract_params.extract_non_hdr.action == e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP)) + { + for (i=0, k=0; + i < param->keys_params.num_of_keys; + i++, k += IOC_FM_PCD_MAX_SIZE_OF_KEY) + { + if (param->keys_params.key_params[i].p_key && + param->keys_params.key_size) + { + if (copy_from_user(&keys[k], + param->keys_params.key_params[i].p_key, + param->keys_params.key_size)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->keys_params.key_params[i].p_key = &keys[k]; + } + + if (param->keys_params.key_params[i].p_mask) + { + if (copy_from_user(&masks[k], + param->keys_params.key_params[i].p_mask, + param->keys_params.key_size)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->keys_params.key_params[i].p_mask = &masks[k]; + } + } + } + + param->id = FM_PCD_MatchTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcNodeParams*)param); + + if (!param->id) { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_params_t *compat_param; + compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + + 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); + compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_K_TO_US); + + if (copy_to_user((ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_cc_node_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_cc_node_params_t *)arg, + param, + sizeof(ioc_fm_pcd_cc_node_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_MatchTableDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_ROOT_BUILD_COMPAT: +#endif + case FM_PCD_IOC_CC_ROOT_BUILD: + { + ioc_fm_pcd_cc_tree_params_t *param; + + param = (ioc_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_cc_tree_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_tree_params_t *)arg, + sizeof(ioc_fm_pcd_cc_tree_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + param->id = FM_PCD_CcRootBuild(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcTreeParams*)param); + + if (!param->id) { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); + + compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_K_TO_US); + + if (copy_to_user((ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_cc_tree_params_t *)arg, + param, + sizeof(ioc_fm_pcd_cc_tree_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_ROOT_DELETE_COMPAT: +#endif + case FM_PCD_IOC_CC_ROOT_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_CcRootDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT: +#endif + case FM_PCD_IOC_PLCR_PROFILE_SET: + { + ioc_fm_pcd_plcr_profile_params_t *param; + + param = (ioc_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_plcr_profile_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t)); + if (copy_from_user(compat_param, ( + ioc_compat_fm_pcd_plcr_profile_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_plcr_profile_params_t *)arg, + sizeof(ioc_fm_pcd_plcr_profile_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (!param->modify && + (((t_FmPcdPlcrProfileParams*)param)->id.newParams.profileType != e_FM_PCD_PLCR_SHARED)) + { + t_Handle h_Port; + ioc_fm_pcd_port_params_t *port_params; + + port_params = (ioc_fm_pcd_port_params_t*) XX_Malloc(sizeof(ioc_fm_pcd_port_params_t)); + if (!port_params) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(port_params, 0, sizeof(ioc_fm_pcd_port_params_t)); + if (copy_from_user(port_params, (ioc_fm_pcd_port_params_t*)((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort, + sizeof(ioc_fm_pcd_port_params_t))) + { + XX_Free(port_params); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + switch(port_params->port_type) + { + case (e_IOC_FM_PORT_TYPE_RX): + if (port_params->port_id < FM_MAX_NUM_OF_1G_RX_PORTS) { + h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev; + break; + } + goto invalid_port_id; + + case (e_IOC_FM_PORT_TYPE_RX_10G): + if (port_params->port_id < FM_MAX_NUM_OF_10G_RX_PORTS) { + h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id + FM_MAX_NUM_OF_1G_RX_PORTS].h_Dev; + break; + } + goto invalid_port_id; + + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + if (port_params->port_id && port_params->port_id < FM_MAX_NUM_OF_OH_PORTS) { + h_Port = p_LnxWrpFmDev->opPorts[port_params->port_id - 1].h_Dev; + break; + } + goto invalid_port_id; + + default: +invalid_port_id: + XX_Free(port_params); + XX_Free(param); + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + + ((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort = h_Port; + XX_Free(port_params); + } + + param->id = FM_PCD_PlcrProfileSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPlcrProfileParams*)param); + + if (!param->id) { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); + compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_K_TO_US); + if (copy_to_user((ioc_compat_fm_pcd_plcr_profile_params_t *) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_plcr_profile_params_t *)arg, + param, + sizeof(ioc_fm_pcd_plcr_profile_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT: +#endif + case FM_PCD_IOC_PLCR_PROFILE_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_PlcrProfileDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE: + { + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param; + + param = (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)); + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_fm_pcd_cc_tree_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_CcRootModifyNextEngine(param->id, + param->grp_indx, + param->indx, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; + + param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_MatchTableModifyNextEngine(param->id, + param->key_indx, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; + + param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) arg, + sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_MatchTableModifyMissNextEngine(param->id, + (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY: + { + ioc_fm_pcd_cc_node_remove_key_params_t *param; + + param = (ioc_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_remove_key_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_remove_key_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->id = compat_ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_remove_key_params_t *) arg, + sizeof(ioc_fm_pcd_cc_node_remove_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_MatchTableRemoveKey(param->id, param->key_indx); + + XX_Free(param); + break; + } +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_ADD_KEY: + { + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; + + param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (param->key_size) + { + int size = 0; + + if (param->key_params.p_key) size += param->key_size; + if (param->key_params.p_mask) size += param->key_size; + + if (size) + { + uint8_t *p_tmp; + + p_tmp = (uint8_t*) XX_Malloc(size); + if (!p_tmp) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); + } + + if (param->key_params.p_key) + { + if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size)) + { + XX_Free(p_tmp); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->key_params.p_key = p_tmp; + } + + if (param->key_params.p_mask) + { + p_tmp += param->key_size; + if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size)) + { + XX_Free(p_tmp - param->key_size); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->key_params.p_mask = p_tmp; + } + } + } + + err = FM_PCD_MatchTableAddKey( + param->id, + param->key_indx, + param->key_size, + (t_FmPcdCcKeyParams*)¶m->key_params); + + if (param->key_params.p_key) + XX_Free(param->key_params.p_key); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE: + { + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; + + param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PCD_MatchTableModifyKeyAndNextEngine(param->id, + param->key_indx, + param->key_size, + (t_FmPcdCcKeyParams*)(¶m->key_params)); + + XX_Free(param); + break; + } +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_HASH_TABLE_SET_COMPAT: +#endif + case FM_PCD_IOC_HASH_TABLE_SET: + { + ioc_fm_pcd_hash_table_params_t *param; + + param = (ioc_fm_pcd_hash_table_params_t*) XX_Malloc( + sizeof(ioc_fm_pcd_hash_table_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_hash_table_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_hash_table_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc( + sizeof(ioc_compat_fm_pcd_hash_table_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_hash_table_params_t*)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_hash_table_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_hash_table_params_t *)arg, + sizeof(ioc_fm_pcd_hash_table_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + param->id = FM_PCD_HashTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdHashTableParams *) param); + + if (!param->id) + { + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_hash_table_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc( + sizeof(ioc_compat_fm_pcd_hash_table_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t)); + compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_K_TO_US); + if (copy_to_user((ioc_compat_fm_pcd_hash_table_params_t*) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_hash_table_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_hash_table_params_t *)arg, + param, + sizeof(ioc_fm_pcd_hash_table_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT: +#endif + case FM_PCD_IOC_HASH_TABLE_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0, sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + id.obj = compat_pcd_id2ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_HashTableDelete(id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT: +#endif + case FM_PCD_IOC_HASH_TABLE_ADD_KEY: + { + ioc_fm_pcd_hash_table_add_key_params_t *param = NULL; + + param = (ioc_fm_pcd_hash_table_add_key_params_t*) XX_Malloc( + sizeof(ioc_fm_pcd_hash_table_add_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_hash_table_add_key_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_hash_table_add_key_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_hash_table_add_key_params_t*) XX_Malloc( + sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_hash_table_add_key_params_t*) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + if (compat_param->key_size) + { + param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl); + param->key_size = compat_param->key_size; + + compat_copy_fm_pcd_cc_key(&compat_param->key_params, ¶m->key_params, COMPAT_US_TO_K); + } + else + { + XX_Free(compat_param); + err = E_INVALID_VALUE; + break; + } + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_hash_table_add_key_params_t*) arg, + sizeof(ioc_fm_pcd_hash_table_add_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (param->key_size) + { + int size = 0; + + if (param->key_params.p_key) size += param->key_size; + if (param->key_params.p_mask) size += param->key_size; + + if (size) + { + uint8_t *p_tmp; + + p_tmp = (uint8_t*) XX_Malloc(size); + if (!p_tmp) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); + } + + if (param->key_params.p_key) + { + if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size)) + { + XX_Free(p_tmp); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->key_params.p_key = p_tmp; + } + + if (param->key_params.p_mask) + { + p_tmp += param->key_size; + if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size)) + { + XX_Free(p_tmp - param->key_size); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->key_params.p_mask = p_tmp; + } + } + } + + err = FM_PCD_HashTableAddKey( + param->p_hash_tbl, + param->key_size, + (t_FmPcdCcKeyParams*)¶m->key_params); + + if (param->key_params.p_key) + XX_Free(param->key_params.p_key); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT: +#endif + case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY: + { + ioc_fm_pcd_hash_table_remove_key_params_t *param = NULL; + + param = (ioc_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc( + sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_hash_table_remove_key_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc( + sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl); + param->key_size = compat_param->key_size; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_hash_table_remove_key_params_t*)arg, + sizeof(ioc_fm_pcd_hash_table_remove_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (param->key_size) + { + uint8_t *p_key; + + p_key = (uint8_t*) XX_Malloc(param->key_size); + if (!p_key) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + if (param->p_key && copy_from_user(p_key, param->p_key, param->key_size)) + { + XX_Free(p_key); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + param->p_key = p_key; + } + + err = FM_PCD_HashTableRemoveKey( + param->p_hash_tbl, + param->key_size, + param->p_key); + + if (param->p_key) + XX_Free(param->p_key); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT: +#endif + case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY: + { + ioc_fm_pcd_cc_node_modify_key_params_t *param; + + param = (ioc_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)); + if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_key_params_t *)compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_cc_node_modify_key(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_params_t *)arg, + sizeof(ioc_fm_pcd_cc_node_modify_key_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (param->key_size) + { + int size = 0; + + if (param->p_key) size += param->key_size; + if (param->p_mask) size += param->key_size; + + if (size) + { + uint8_t *p_tmp; + + p_tmp = (uint8_t*) XX_Malloc(size); + if (!p_tmp) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); + } + + if (param->p_key) + { + if (copy_from_user(p_tmp, param->p_key, param->key_size)) + { + XX_Free(p_tmp); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->p_key = p_tmp; + } + + if (param->p_mask) + { + p_tmp += param->key_size; + if (copy_from_user(p_tmp, param->p_mask, param->key_size)) + { + XX_Free(p_tmp - param->key_size); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->p_mask = p_tmp; + } + } + } + + err = FM_PCD_MatchTableModifyKey(param->id, + param->key_indx, + param->key_size, + param->p_key, + param->p_mask); + + if (param->p_key) + XX_Free(param->p_key); + else if (param->p_mask) + XX_Free(param->p_mask); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MANIP_NODE_SET_COMPAT: +#endif + case FM_PCD_IOC_MANIP_NODE_SET: + { + ioc_fm_pcd_manip_params_t *param; + uint8_t *p_data = NULL; + uint8_t size; + + param = (ioc_fm_pcd_manip_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_manip_params_t)); + + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_manip_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_manip_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_manip_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_manip_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_manip_params_t *)arg, + sizeof(ioc_fm_pcd_manip_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (param->type == e_IOC_FM_PCD_MANIP_HDR) + { + size = param->u.hdr.insrt_params.u.generic.size; + p_data = (uint8_t *) XX_Malloc(size); + if (!p_data ) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, NO_MSG); + } + + if (param->u.hdr.insrt_params.u.generic.p_data && + copy_from_user(p_data, + param->u.hdr.insrt_params.u.generic.p_data, size)) + { + XX_Free(p_data); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + param->u.hdr.insrt_params.u.generic.p_data = p_data; + } + + if (param->id) + { + /* Security Hole: the user can pass any piece of garbage + in 'param->id', and that will go straight through to the LLD, + no checks being done by the wrapper! */ + err = FM_PCD_ManipNodeReplace( + (t_Handle) param->id, + (t_FmPcdManipParams*) param); + if (err) + { + if (p_data) + XX_Free(p_data); + XX_Free(param); + break; + } + } + else + { + param->id = FM_PCD_ManipNodeSet( + p_LnxWrpFmDev->h_PcdDev, + (t_FmPcdManipParams*) param); + if (!param->id) + { + if (p_data) + XX_Free(p_data); + XX_Free(param); + err = E_INVALID_VALUE; + /* Since the LLD has no errno-style error reporting, + we're left here with no other option than to report + a generic E_INVALID_VALUE */ + break; + } + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_manip_params_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_manip_params_t)); + if (!compat_param) + { + if (p_data) + XX_Free(p_data); + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t)); + + compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_K_TO_US); + + if (copy_to_user((ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg), + compat_param, + sizeof(ioc_compat_fm_pcd_manip_params_t))) + err = E_READ_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user((ioc_fm_pcd_manip_params_t *)arg, + param, sizeof(ioc_fm_pcd_manip_params_t))) + err = E_READ_FAILED; + } + + if (p_data) + XX_Free(p_data); + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT: +#endif + case FM_PCD_IOC_MANIP_NODE_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0, sizeof(ioc_fm_obj_t)); +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PCD_ManipNodeDelete(id.obj); + break; + } + +#if (DPAA_VERSION >= 11) +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT: +#endif + case FM_PCD_IOC_FRM_REPLIC_GROUP_SET: + { + ioc_fm_pcd_frm_replic_group_params_t *param; + + param = (ioc_fm_pcd_frm_replic_group_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_frm_replic_group_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_frm_replic_group_params_t + *compat_param; + + compat_param = + (ioc_compat_fm_pcd_frm_replic_group_params_t *) + XX_Malloc(sizeof(*compat_param)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, + ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(*compat_param)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_frm_replic_group_params_t *) + compat_ptr(arg), + sizeof(*compat_param))) { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_frm_replic_group_params(compat_param, + param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, + (ioc_fm_pcd_frm_replic_group_params_t *)arg, + sizeof(ioc_fm_pcd_frm_replic_group_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); + } + } + + param->id = FM_PCD_FrmReplicSetGroup(p_LnxWrpFmDev->h_PcdDev, + (t_FmPcdFrmReplicGroupParams*)param); + + if (!param->id) { + XX_Free(param); + err = E_INVALID_VALUE; + /* + * Since the LLD has no errno-style error reporting, + * we're left here with no other option than to report + * a generic E_INVALID_VALUE + */ + break; + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_frm_replic_group_params_t + *compat_param; + + compat_param = + (ioc_compat_fm_pcd_frm_replic_group_params_t *) + XX_Malloc(sizeof(*compat_param)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, + ("IOCTL FM PCD")); + } + + memset(compat_param, 0, sizeof(*compat_param)); + compat_copy_fm_pcd_frm_replic_group_params(compat_param, + param, COMPAT_K_TO_US); + if (copy_to_user( + (ioc_compat_fm_pcd_frm_replic_group_params_t *) + compat_ptr(arg), + compat_param, + sizeof(*compat_param))) + err = E_WRITE_FAILED; + + XX_Free(compat_param); + } + else +#endif + { + if (copy_to_user( + (ioc_fm_pcd_frm_replic_group_params_t *)arg, + param, + sizeof(ioc_fm_pcd_frm_replic_group_params_t))) + err = E_WRITE_FAILED; + } + + XX_Free(param); + break; + } + break; + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT: +#endif + case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE: + { + ioc_fm_obj_t id; + + memset(&id, 0, sizeof(ioc_fm_obj_t)); +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, + (ioc_compat_fm_obj_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_obj_t))) + break; + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, + sizeof(ioc_fm_obj_t))) + break; + } + + return FM_PCD_FrmReplicDeleteGroup(id.obj); + } + break; + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT: +#endif + case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD: + { + ioc_fm_pcd_frm_replic_member_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_frm_replic_member_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_pcd_frm_replic_member_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + return FM_PCD_FrmReplicAddMember(param.member.h_replic_group, + param.member.member_index, + (t_FmPcdCcNextEngineParams*)¶m.next_engine_params); + } + break; + +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT: +#endif + case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE: + { + ioc_fm_pcd_frm_replic_member_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_frm_replic_member_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_pcd_frm_replic_member(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + return FM_PCD_FrmReplicRemoveMember(param.h_replic_group, param.member_index); + } + break; + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_CONFIG_COMPAT: +#endif + case FM_IOC_VSP_CONFIG: + { + ioc_fm_vsp_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_vsp_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_vsp_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + param.p_fm = p_LnxWrpFmDev->h_Dev; + param.id = FM_VSP_Config((t_FmVspParams *)¶m); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_vsp_params_t compat_param; + + memset(&compat_param, 0, sizeof(compat_param)); + compat_copy_fm_vsp_params(&compat_param, ¶m, COMPAT_K_TO_US); + + if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + if (copy_to_user((void *)arg, ¶m, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_INIT_COMPAT: +#endif + case FM_IOC_VSP_INIT: + { + ioc_fm_obj_t id; + + memset(&id, 0, sizeof(ioc_fm_obj_t)); +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, + (ioc_compat_fm_obj_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_obj_t))) + break; + id.obj = compat_pcd_id2ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, + sizeof(ioc_fm_obj_t))) + break; + } + + return FM_VSP_Init(id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_FREE_COMPAT: +#endif + case FM_IOC_VSP_FREE: + { + ioc_fm_obj_t id; + + memset(&id, 0, sizeof(ioc_fm_obj_t)); +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, + (ioc_compat_fm_obj_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_obj_t))) + break; + compat_obj_delete(&compat_id, &id); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, + sizeof(ioc_fm_obj_t))) + break; + } + + return FM_VSP_Free(id.obj); + } + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT: +#endif + case FM_IOC_VSP_CONFIG_POOL_DEPLETION: + { + ioc_fm_buf_pool_depletion_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_buf_pool_depletion_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_buf_pool_depletion_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (FM_VSP_ConfigPoolDepletion(param.p_fm_vsp, + (t_FmBufPoolDepletion *)¶m.fm_buf_pool_depletion)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + break; + } + + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT: +#endif + case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT: + { + ioc_fm_buffer_prefix_content_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_buffer_prefix_content_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_buffer_prefix_content_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (FM_VSP_ConfigBufferPrefixContent(param.p_fm_vsp, + (t_FmBufferPrefixContent *)¶m.fm_buffer_prefix_content)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + break; + } + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_CONFIG_NO_SG_COMPAT: +#endif + case FM_IOC_VSP_CONFIG_NO_SG: + { + ioc_fm_vsp_config_no_sg_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_vsp_config_no_sg_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_vsp_config_no_sg_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (FM_VSP_ConfigNoScatherGather(param.p_fm_vsp, param.no_sg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + break; + } + +#if defined(CONFIG_COMPAT) + case FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT: +#endif + case FM_IOC_VSP_GET_BUFFER_PRS_RESULT: + { + ioc_fm_vsp_prs_result_params_t param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_vsp_prs_result_params_t compat_param; + + if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_vsp_prs_result_params(&compat_param, ¶m, COMPAT_US_TO_K); + } + else +#endif + if (copy_from_user(¶m, (void *)arg, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + /* this call just adds the parse results offset to p_data */ + param.p_data = FM_VSP_GetBufferPrsResult(param.p_fm_vsp, param.p_data); + + if (!param.p_data) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_vsp_prs_result_params_t compat_param; + + memset(&compat_param, 0, sizeof(compat_param)); + compat_copy_fm_vsp_prs_result_params(&compat_param, ¶m, COMPAT_K_TO_US); + + if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + if (copy_to_user((void *)arg, ¶m, sizeof(param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + break; + } +#endif /* (DPAA_VERSION >= 11) */ + +#ifdef FM_CAPWAP_SUPPORT +#warning "feature not supported!" +#if defined(CONFIG_COMPAT) + case FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT: +#endif + case FM_PCD_IOC_STATISTICS_SET_NODE: + { +/* ioc_fm_pcd_stats_params_t param; + ... + param->id = FM_PCD_StatisticsSetNode(p_LnxWrpFmDev->h_PcdDev, + (t_FmPcdStatsParams *)¶m); +*/ + err = E_NOT_SUPPORTED; + break; + } +#endif /* FM_CAPWAP_SUPPORT */ + + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr: %d.\n", + cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); + } + + if (err) + RETURN_ERROR(MINOR, err, ("IOCTL FM PCD")); + + return E_OK; +} + +void FM_Get_Api_Version(ioc_fm_api_version_t *p_version) +{ + p_version->version.major = FMD_API_VERSION_MAJOR; + p_version->version.minor = FMD_API_VERSION_MINOR; + p_version->version.respin = FMD_API_VERSION_RESPIN; + p_version->version.reserved = 0; +} + +t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_OK; + + switch (cmd) + { + case FM_IOC_SET_PORTS_BANDWIDTH: + { + ioc_fm_port_bandwidth_params *param; + + param = (ioc_fm_port_bandwidth_params*) XX_Malloc(sizeof(ioc_fm_port_bandwidth_params)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_port_bandwidth_params)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)compat_ptr(arg), sizeof(ioc_fm_port_bandwidth_params))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)arg, sizeof(ioc_fm_port_bandwidth_params))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_SetPortsBandwidth(p_LnxWrpFmDev->h_Dev, (t_FmPortsBandwidthParams*) param); + + XX_Free(param); + break; + } + + case FM_IOC_GET_REVISION: + { + ioc_fm_revision_info_t *param; + + param = (ioc_fm_revision_info_t *) XX_Malloc(sizeof(ioc_fm_revision_info_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + FM_GetRevision(p_LnxWrpFmDev->h_Dev, (t_FmRevisionInfo*)param); + /* This one never returns anything other than E_OK */ + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_revision_info_t *)compat_ptr(arg), + param, + sizeof(ioc_fm_revision_info_t))) + RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); + } + else +#endif + { + if (copy_to_user((ioc_fm_revision_info_t *)arg, + param, + sizeof(ioc_fm_revision_info_t))) + RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); + } + + XX_Free(param); + break; + } + + case FM_IOC_SET_COUNTER: + { + ioc_fm_counters_params_t *param; + + param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_counters_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_ModifyCounter(p_LnxWrpFmDev->h_Dev, param->cnt, param->val); + + XX_Free(param); + break; + } + + case FM_IOC_GET_COUNTER: + { + ioc_fm_counters_params_t *param; + + param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); + + memset(param, 0, sizeof(ioc_fm_counters_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + param->val = FM_GetCounter(p_LnxWrpFmDev->h_Dev, param->cnt); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_counters_params_t *)compat_ptr(arg), param, sizeof(ioc_fm_counters_params_t))) + err = E_READ_FAILED; + } + else +#endif + { + if (copy_to_user((ioc_fm_counters_params_t *)arg, param, sizeof(ioc_fm_counters_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + + case FM_IOC_FORCE_INTR: + { + ioc_fm_exceptions param; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(param, (ioc_fm_exceptions*) compat_ptr(arg))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + { + if (get_user(param, (ioc_fm_exceptions*)arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_ForceIntr(p_LnxWrpFmDev->h_Dev, (e_FmExceptions)param); + break; + } + + case FM_IOC_GET_API_VERSION: + { + ioc_fm_api_version_t version; + + FM_Get_Api_Version(&version); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user( + (ioc_fm_api_version_t *)compat_ptr(arg), + &version, sizeof(version))) + err = E_READ_FAILED; + } + else +#endif + { + if (copy_to_user((ioc_fm_api_version_t *)arg, + &version, sizeof(version))) + err = E_READ_FAILED; + } + } + break; + + case FM_IOC_CTRL_MON_START: + { + FM_CtrlMonStart(p_LnxWrpFmDev->h_Dev); + } + break; + + case FM_IOC_CTRL_MON_STOP: + { + FM_CtrlMonStop(p_LnxWrpFmDev->h_Dev); + } + break; + +#if defined(CONFIG_COMPAT) + case FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT: +#endif + case FM_IOC_CTRL_MON_GET_COUNTERS: + { + ioc_fm_ctrl_mon_counters_params_t param; + t_FmCtrlMon mon; + +#if defined(CONFIG_COMPAT) + ioc_compat_fm_ctrl_mon_counters_params_t compat_param; + + if (compat) + { + if (copy_from_user(&compat_param, (void *)compat_ptr(arg), + sizeof(compat_param))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + param.fm_ctrl_index = compat_param.fm_ctrl_index; + param.p_mon = (fm_ctrl_mon_t *)compat_ptr(compat_param.p_mon); + } + else +#endif + { + if (copy_from_user(¶m, (void *)arg, sizeof(ioc_fm_counters_params_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + if (FM_CtrlMonGetCounters(p_LnxWrpFmDev->h_Dev, param.fm_ctrl_index, &mon)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (copy_to_user(param.p_mon, &mon, sizeof(t_FmCtrlMon))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + break; + + default: + return LnxwrpFmPcdIOCTL(p_LnxWrpFmDev, cmd, arg, compat); + } + + if (err) + RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM")); + + return E_OK; +} + +t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat) +{ + t_Error err = E_OK; + + _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n", + cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 50); + + switch (cmd) + { + case FM_PORT_IOC_DISABLE: + FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); + /* deliberately ignoring error codes here */ + return E_OK; + + case FM_PORT_IOC_ENABLE: + FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); + /* deliberately ignoring error codes here */ + return E_OK; + + case FM_PORT_IOC_SET_ERRORS_ROUTE: + { + ioc_fm_port_frame_err_select_t errs; + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(errs, (ioc_fm_port_frame_err_select_t*)compat_ptr(arg))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + { + if (get_user(errs, (ioc_fm_port_frame_err_select_t*)arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PORT_SetErrorsRoute(p_LnxWrpFmPortDev->h_Dev, (fmPortFrameErrSelect_t)errs); + break; + } + + case FM_PORT_IOC_SET_RATE_LIMIT: + { + ioc_fm_port_rate_limit_t *param; + + param = (ioc_fm_port_rate_limit_t *) XX_Malloc(sizeof(ioc_fm_port_rate_limit_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_port_rate_limit_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)compat_ptr(arg), sizeof(ioc_fm_port_rate_limit_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)arg, sizeof(ioc_fm_port_rate_limit_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, (t_FmPortRateLimit *)param); + + XX_Free(param); + break; + } + + case FM_PORT_IOC_REMOVE_RATE_LIMIT: + FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev); + /* deliberately ignoring error codes here */ + return E_OK; + + case FM_PORT_IOC_ALLOC_PCD_FQIDS: + { + ioc_fm_port_pcd_fqids_params_t *param; + + if (!p_LnxWrpFmPortDev->pcd_owner_params.cba) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); + + param = (ioc_fm_port_pcd_fqids_params_t *) XX_Malloc(sizeof(ioc_fm_port_pcd_fqids_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_port_pcd_fqids_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), + sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)arg, + sizeof(ioc_fm_port_pcd_fqids_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (p_LnxWrpFmPortDev->pcd_owner_params.cba(p_LnxWrpFmPortDev->pcd_owner_params.dev, + param->num_fqids, + param->alignment, + ¶m->base_fqid)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("can't allocate fqids for PCD!!!")); + } + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), + param, sizeof(ioc_fm_port_pcd_fqids_params_t))) + err = E_READ_FAILED; + } + else +#endif + { + if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)arg, + param, sizeof(ioc_fm_port_pcd_fqids_params_t))) + err = E_READ_FAILED; + } + + XX_Free(param); + break; + } + + case FM_PORT_IOC_FREE_PCD_FQIDS: + { + uint32_t base_fqid; + + if (!p_LnxWrpFmPortDev->pcd_owner_params.cbf) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (get_user(base_fqid, (uint32_t*) compat_ptr(arg))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + else +#endif + { + if (get_user(base_fqid, (uint32_t*)arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + if (p_LnxWrpFmPortDev->pcd_owner_params.cbf(p_LnxWrpFmPortDev->pcd_owner_params.dev, base_fqid)) + err = E_WRITE_FAILED; + + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_SET_PCD_COMPAT: +#endif + case FM_PORT_IOC_SET_PCD: + { + ioc_fm_port_pcd_params_t *port_pcd_params; + ioc_fm_port_pcd_prs_params_t *port_pcd_prs_params; + ioc_fm_port_pcd_cc_params_t *port_pcd_cc_params; + ioc_fm_port_pcd_kg_params_t *port_pcd_kg_params; + ioc_fm_port_pcd_plcr_params_t *port_pcd_plcr_params; + + port_pcd_params = (ioc_fm_port_pcd_params_t *) XX_Malloc( + sizeof(ioc_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_fm_port_pcd_cc_params_t) + + sizeof(ioc_fm_port_pcd_kg_params_t) + + sizeof(ioc_fm_port_pcd_plcr_params_t)); + if (!port_pcd_params) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(port_pcd_params, 0, + sizeof(ioc_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_fm_port_pcd_cc_params_t) + + sizeof(ioc_fm_port_pcd_kg_params_t) + + sizeof(ioc_fm_port_pcd_plcr_params_t)); + + port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (port_pcd_params + 1); + port_pcd_cc_params = (ioc_fm_port_pcd_cc_params_t *) (port_pcd_prs_params + 1); + port_pcd_kg_params = (ioc_fm_port_pcd_kg_params_t *) (port_pcd_cc_params + 1); + port_pcd_plcr_params = (ioc_fm_port_pcd_plcr_params_t *) (port_pcd_kg_params + 1); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_port_pcd_params_t *compat_port_pcd_params; + ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params; + ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params; + ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params; + ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params; + + compat_port_pcd_params = (ioc_compat_fm_port_pcd_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_compat_fm_port_pcd_cc_params_t) + + sizeof(ioc_compat_fm_port_pcd_kg_params_t) + + sizeof(ioc_compat_fm_port_pcd_plcr_params_t)); + if (!compat_port_pcd_params) + { + XX_Free(port_pcd_params); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + } + + memset(compat_port_pcd_params, 0, + sizeof(ioc_compat_fm_port_pcd_params_t) + + sizeof(ioc_fm_port_pcd_prs_params_t) + + sizeof(ioc_compat_fm_port_pcd_cc_params_t) + + sizeof(ioc_compat_fm_port_pcd_kg_params_t) + + sizeof(ioc_compat_fm_port_pcd_plcr_params_t)); + same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_port_pcd_params + 1); + compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1); + compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1); + compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1); + + if (copy_from_user(compat_port_pcd_params, + (ioc_compat_fm_port_pcd_params_t*) compat_ptr(arg), + sizeof(ioc_compat_fm_port_pcd_params_t))) + err = E_WRITE_FAILED; + + while (!err) /* pseudo-while */ + { + /* set pointers from where to copy from: */ + port_pcd_params->p_prs_params = compat_ptr(compat_port_pcd_params->p_prs_params); /* same structure */ + port_pcd_params->p_cc_params = compat_ptr(compat_port_pcd_params->p_cc_params); + port_pcd_params->p_kg_params = compat_ptr(compat_port_pcd_params->p_kg_params); + port_pcd_params->p_plcr_params = compat_ptr(compat_port_pcd_params->p_plcr_params); + port_pcd_params->p_ip_reassembly_manip = compat_ptr(compat_port_pcd_params->p_ip_reassembly_manip); + + /* the prs member is the same, no compat structure...memcpy only */ + if (port_pcd_params->p_prs_params) + { + if (copy_from_user(same_port_pcd_prs_params, + port_pcd_params->p_prs_params, + sizeof(ioc_fm_port_pcd_prs_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + memcpy(port_pcd_prs_params, same_port_pcd_prs_params, sizeof(ioc_fm_port_pcd_prs_params_t)); + port_pcd_params->p_prs_params = port_pcd_prs_params; + } + + if (port_pcd_params->p_cc_params) + { + if (copy_from_user(compat_port_pcd_cc_params, + port_pcd_params->p_cc_params, + sizeof(ioc_compat_fm_port_pcd_cc_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_cc_params = port_pcd_cc_params; + } + + if (port_pcd_params->p_kg_params) + { + if (copy_from_user(compat_port_pcd_kg_params, + port_pcd_params->p_kg_params, + sizeof(ioc_compat_fm_port_pcd_kg_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_kg_params = port_pcd_kg_params; + } + + if (port_pcd_params->p_plcr_params) + { + if (copy_from_user(compat_port_pcd_plcr_params, + port_pcd_params->p_plcr_params, + sizeof(ioc_compat_fm_port_pcd_plcr_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_plcr_params = port_pcd_plcr_params; + } + + break; /* pseudo-while: always run once! */ + } + + if (!err) + compat_copy_fm_port_pcd(compat_port_pcd_params, port_pcd_params, COMPAT_US_TO_K); + + XX_Free(compat_port_pcd_params); + } + else +#endif + { + if (copy_from_user(port_pcd_params, + (ioc_fm_port_pcd_params_t*) arg, + sizeof(ioc_fm_port_pcd_params_t))) + err = E_WRITE_FAILED; + + while (!err) /* pseudo-while */ + { + if (port_pcd_params->p_prs_params) + { + if (copy_from_user(port_pcd_prs_params, + port_pcd_params->p_prs_params, + sizeof(ioc_fm_port_pcd_prs_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_prs_params = port_pcd_prs_params; + } + + if (port_pcd_params->p_cc_params) + { + if (copy_from_user(port_pcd_cc_params, + port_pcd_params->p_cc_params, + sizeof(ioc_fm_port_pcd_cc_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_cc_params = port_pcd_cc_params; + } + + if (port_pcd_params->p_kg_params) + { + if (copy_from_user(port_pcd_kg_params, + port_pcd_params->p_kg_params, + sizeof(ioc_fm_port_pcd_kg_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_kg_params = port_pcd_kg_params; + } + + if (port_pcd_params->p_plcr_params) + { + if (copy_from_user(port_pcd_plcr_params, + port_pcd_params->p_plcr_params, + sizeof(ioc_fm_port_pcd_plcr_params_t))) + { + err = E_WRITE_FAILED; + break; /* from pseudo-while */ + } + + port_pcd_params->p_plcr_params = port_pcd_plcr_params; + } + + break; /* pseudo-while: always run once! */ + } + } + + if (!err) + err = FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, (t_FmPortPcdParams*) port_pcd_params); + + XX_Free(port_pcd_params); + break; + } + + case FM_PORT_IOC_DELETE_PCD: + err = FM_PORT_DeletePCD(p_LnxWrpFmPortDev->h_Dev); + break; + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME: + { + ioc_fm_pcd_kg_scheme_select_t *param; + + param = (ioc_fm_pcd_kg_scheme_select_t *) XX_Malloc( + sizeof(ioc_fm_pcd_kg_scheme_select_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_select_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param; + + compat_param = (ioc_compat_fm_pcd_kg_scheme_select_t *) XX_Malloc( + sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_pcd_kg_scheme_select_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_kg_scheme_select_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_kg_scheme_select(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_select_t *)arg, + sizeof(ioc_fm_pcd_kg_scheme_select_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgModifyInitialScheme(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdKgSchemeSelect *)param); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT: +#endif + case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + id.obj = compat_ptr(compat_id.obj); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PORT_PcdPlcrModifyInitialProfile(p_LnxWrpFmPortDev->h_Dev, id.obj); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_BIND_SCHEMES: + { + ioc_fm_pcd_port_schemes_params_t *param; + + param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_port_schemes_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_port_schemes_params_t compat_param; + + if (copy_from_user(&compat_param, + (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, + sizeof(ioc_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgBindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); + + XX_Free(param); + break; + } + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT: +#endif + case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES: + { + ioc_fm_pcd_port_schemes_params_t *param; + + param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( + sizeof(ioc_fm_pcd_port_schemes_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_pcd_port_schemes_params_t compat_param; + + if (copy_from_user(&compat_param, + (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, + sizeof(ioc_fm_pcd_port_schemes_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdKgUnbindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); + + XX_Free(param); + break; + } + + case FM_PORT_IOC_PCD_PRS_MODIFY_START_OFFSET: + { + ioc_fm_pcd_prs_start_t *param; + + param = (ioc_fm_pcd_prs_start_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_start_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_pcd_prs_start_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_pcd_prs_start_t *)compat_ptr(arg), + sizeof(ioc_fm_pcd_prs_start_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_pcd_prs_start_t *)arg, + sizeof(ioc_fm_pcd_prs_start_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = FM_PORT_PcdPrsModifyStartOffset(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPrsStart *)param); + + XX_Free(param); + break; + } + + case FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES: + { + uint16_t num; + if (get_user(num, (uint16_t*) arg)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + err = FM_PORT_PcdPlcrAllocProfiles(p_LnxWrpFmPortDev->h_Dev, num); + break; + } + + case FM_PORT_IOC_PCD_PLCR_FREE_PROFILES: + err = FM_PORT_PcdPlcrFreeProfiles(p_LnxWrpFmPortDev->h_Dev); + break; + + case FM_PORT_IOC_DETACH_PCD: + err = FM_PORT_DetachPCD(p_LnxWrpFmPortDev->h_Dev); + break; + + case FM_PORT_IOC_ATTACH_PCD: + err = FM_PORT_AttachPCD(p_LnxWrpFmPortDev->h_Dev); + break; + +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT: +#endif + case FM_PORT_IOC_PCD_CC_MODIFY_TREE: + { + ioc_fm_obj_t id; + + memset(&id, 0 , sizeof(ioc_fm_obj_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_obj_t compat_id; + + if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + compat_copy_fm_port_pcd_modify_tree(&compat_id, &id, COMPAT_US_TO_K); + } + else +#endif + { + if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + err = FM_PORT_PcdCcModifyTree(p_LnxWrpFmPortDev->h_Dev, id.obj); + break; + } + + case FM_PORT_IOC_ADD_CONGESTION_GRPS: + case FM_PORT_IOC_REMOVE_CONGESTION_GRPS: + { + ioc_fm_port_congestion_groups_t *param; + + param = (ioc_fm_port_congestion_groups_t*) XX_Malloc(sizeof(ioc_fm_port_congestion_groups_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_port_congestion_groups_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (t_FmPortCongestionGrps*) compat_ptr(arg), + sizeof(t_FmPortCongestionGrps))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(param, (t_FmPortCongestionGrps*) arg, + sizeof(t_FmPortCongestionGrps))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + err = (cmd == FM_PORT_IOC_ADD_CONGESTION_GRPS) + ? FM_PORT_AddCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param) + : FM_PORT_RemoveCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param) + ; + + XX_Free(param); + break; + } + + case FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR: + case FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR: + { + ioc_fm_port_mac_addr_params_t *param; + + param = (ioc_fm_port_mac_addr_params_t*) XX_Malloc( + sizeof(ioc_fm_port_mac_addr_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_port_mac_addr_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) compat_ptr(arg), + sizeof(ioc_fm_port_mac_addr_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) arg, + sizeof(ioc_fm_port_mac_addr_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + if (p_LnxWrpFmPortDev->pcd_owner_params.dev) + { + struct net_device *net_dev = dev_get_drvdata(p_LnxWrpFmPortDev->pcd_owner_params.dev); + + if (net_dev) + { + struct dpa_priv_s *priv = netdev_priv(net_dev); + + if (priv) + { + struct mac_device *mac_dev = priv->mac_dev; + + if (mac_dev) + { + void *mac_handle = mac_dev->get_mac_handle(mac_dev); + + err = (cmd == FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR) + ? FM_MAC_AddHashMacAddr((t_Handle) mac_handle, (t_EnetAddr*) param) + : FM_MAC_RemoveHashMacAddr((t_Handle) mac_handle, (t_EnetAddr*) param) + ; + } + else + { + err = E_NOT_AVAILABLE; + REPORT_ERROR(MINOR, err, ("Attempt to add/remove hash MAC addr. to/from MAC-less port!")); + } + } + else + /* Not possible, set err nevertheless: */ + err = E_NOT_AVAILABLE; + } + else + { + err = E_NOT_AVAILABLE; + REPORT_ERROR(MINOR, err, ("No net device (and no MAC!) associated to this port!")); + } + } + else + { + err = E_NOT_AVAILABLE; + REPORT_ERROR(MINOR, err, ("Port not initialized or other error!?!?")); + } + + XX_Free(param); + break; + } + + case FM_PORT_IOC_SET_TX_PAUSE_FRAMES: + { + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; + ioc_fm_port_tx_pause_frames_params_t param; + int mac_id = p_LnxWrpFmPortDev->id; + + if(&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev) + mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */ + + if (copy_from_user(¶m, (ioc_fm_port_tx_pause_frames_params_t *)arg, + sizeof(ioc_fm_port_tx_pause_frames_params_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (p_LnxWrpFmDev && p_LnxWrpFmDev->macs[mac_id].h_Dev) + { + FM_MAC_SetTxPauseFrames(p_LnxWrpFmDev->macs[mac_id].h_Dev, + param.priority, + param.pause_time, + param.thresh_time); + } + else + { + err = E_NOT_AVAILABLE; + REPORT_ERROR(MINOR, err, ("Port not initialized or other error!")); + } + + break; + } + + case FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT: + { + ioc_fm_buffer_prefix_content_t *param; + + param = (ioc_fm_buffer_prefix_content_t*) XX_Malloc(sizeof(ioc_fm_buffer_prefix_content_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_buffer_prefix_content_t)); + + if (copy_from_user(param, (ioc_fm_buffer_prefix_content_t*) arg, + sizeof(ioc_fm_buffer_prefix_content_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + if (FM_PORT_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_Dev, + (t_FmBufferPrefixContent *)param)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + XX_Free(param); + break; + } + +#if (DPAA_VERSION >= 11) +#if defined(CONFIG_COMPAT) + case FM_PORT_IOC_VSP_ALLOC_COMPAT: +#endif + case FM_PORT_IOC_VSP_ALLOC: + { + ioc_fm_port_vsp_alloc_params_t *param; + t_LnxWrpFmDev *p_LnxWrpFmDev; + t_LnxWrpFmPortDev *p_LnxWrpFmTxPortDev; + + param = (ioc_fm_port_vsp_alloc_params_t *) XX_Malloc( + sizeof(ioc_fm_port_vsp_alloc_params_t)); + if (!param) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + + memset(param, 0, sizeof(ioc_fm_port_vsp_alloc_params_t)); + +#if defined(CONFIG_COMPAT) + if (compat) + { + ioc_compat_fm_port_vsp_alloc_params_t *compat_param; + + compat_param = (ioc_compat_fm_port_vsp_alloc_params_t *) XX_Malloc( + sizeof(ioc_compat_fm_port_vsp_alloc_params_t)); + if (!compat_param) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); + } + + memset(compat_param, 0, sizeof(ioc_compat_fm_port_vsp_alloc_params_t)); + if (copy_from_user(compat_param, + (ioc_compat_fm_port_vsp_alloc_params_t *) compat_ptr(arg), + sizeof(ioc_compat_fm_port_vsp_alloc_params_t))) + { + XX_Free(compat_param); + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + compat_copy_fm_port_vsp_alloc_params(compat_param, param, COMPAT_US_TO_K); + + XX_Free(compat_param); + } + else +#endif + { + if (copy_from_user(param, (ioc_fm_port_vsp_alloc_params_t *)arg, + sizeof(ioc_fm_port_vsp_alloc_params_t))) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + } + + /* Userspace may not have the Tx port t_handle when issuing the IOCTL */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX || + p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) + { + /* Determine the Tx port t_Handle from the Rx port id */ + p_LnxWrpFmDev = p_LnxWrpFmPortDev->h_LnxWrpFmDev; + p_LnxWrpFmTxPortDev = &p_LnxWrpFmDev->txPorts[p_LnxWrpFmPortDev->id]; + param->p_fm_tx_port = p_LnxWrpFmTxPortDev->h_Dev; + } + + if (FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, (t_FmPortVSPAllocParams *)param)) + { + XX_Free(param); + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + } + + XX_Free(param); + break; + } +#endif /* (DPAA_VERSION >= 11) */ + + case FM_PORT_IOC_GET_MAC_STATISTICS: + { + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; + ioc_fm_port_mac_statistics_t param; + int mac_id = p_LnxWrpFmPortDev->id; + + if (!p_LnxWrpFmDev) + RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!")); + + if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev && + &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev) + mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */ + + if (!p_LnxWrpFmDev->macs[mac_id].h_Dev) + RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!")); + + if (FM_MAC_GetStatistics(p_LnxWrpFmDev->macs[mac_id].h_Dev, + (t_FmMacStatistics *)¶m)) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + if (copy_to_user((ioc_fm_port_mac_statistics_t *)arg, ¶m, + sizeof(ioc_fm_port_mac_statistics_t))) + RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); + + break; + } + + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr:0x%02x.\n", + cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); + } + + if (err) + RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM PORT")); + + return E_OK; +} + +/*****************************************************************************/ +/* API routines for the FM Linux Device */ +/*****************************************************************************/ + +static int fm_open(struct inode *inode, struct file *file) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; + unsigned int major = imajor(inode); + unsigned int minor = iminor(inode); + struct device_node *fm_node; + static struct of_device_id fm_node_of_match[] = { + { .compatible = "fsl,fman", }, + { /* end of list */ }, + }; + + DBG(TRACE, ("Opening minor - %d - ", minor)); + + if (file->private_data != NULL) + return 0; + + /* Get all the FM nodes */ + for_each_matching_node(fm_node, fm_node_of_match) { + struct platform_device *of_dev; + + of_dev = of_find_device_by_node(fm_node); + if (unlikely(of_dev == NULL)) { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); + return -ENXIO; + } + + p_LnxWrpFmDev = (t_LnxWrpFmDev *)fm_bind(&of_dev->dev); + if (p_LnxWrpFmDev->major == major) + break; + fm_unbind((struct fm *)p_LnxWrpFmDev); + p_LnxWrpFmDev = NULL; + } + + if (!p_LnxWrpFmDev) + return -ENODEV; + + if (minor == DEV_FM_MINOR_BASE) + file->private_data = p_LnxWrpFmDev; + else if (minor == DEV_FM_PCD_MINOR_BASE) + file->private_data = p_LnxWrpFmDev; + else { + if (minor == DEV_FM_OH_PORTS_MINOR_BASE) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; + else if ((minor > DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->opPorts[minor-DEV_FM_OH_PORTS_MINOR_BASE-1]; + else if ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[minor-DEV_FM_RX_PORTS_MINOR_BASE]; + else if ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)) + p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[minor-DEV_FM_TX_PORTS_MINOR_BASE]; + else + return -EINVAL; + + /* if trying to open port, check if it initialized */ + if (!p_LnxWrpFmPortDev->h_Dev) + return -ENODEV; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)fm_port_bind(p_LnxWrpFmPortDev->dev); + file->private_data = p_LnxWrpFmPortDev; + fm_unbind((struct fm *)p_LnxWrpFmDev); + } + + if (file->private_data == NULL) + return -ENXIO; + + return 0; +} + +static int fm_close(struct inode *inode, struct file *file) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev; + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + unsigned int minor = iminor(inode); + int err = 0; + + DBG(TRACE, ("Closing minor - %d - ", minor)); + + if ((minor == DEV_FM_MINOR_BASE) || + (minor == DEV_FM_PCD_MINOR_BASE)) + { + p_LnxWrpFmDev = (t_LnxWrpFmDev*)file->private_data; + if (!p_LnxWrpFmDev) + return -ENODEV; + fm_unbind((struct fm *)p_LnxWrpFmDev); + } + else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) + { + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)file->private_data; + if (!p_LnxWrpFmPortDev) + return -ENODEV; + fm_port_unbind((struct fm_port *)p_LnxWrpFmPortDev); + } + + return err; +} + +static int fm_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat) +{ + DBG(TRACE, ("IOCTL minor - %u, cmd - 0x%08x, arg - 0x%08lx \n", minor, cmd, arg)); + + if ((minor == DEV_FM_MINOR_BASE) || + (minor == DEV_FM_PCD_MINOR_BASE)) + { + t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_LnxWrpFmDev*)file->private_data); + if (!p_LnxWrpFmDev) + return -ENODEV; + if (LnxwrpFmIOCTL(p_LnxWrpFmDev, cmd, arg, compat)) + return -EFAULT; + } + else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || + ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) + { + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = ((t_LnxWrpFmPortDev*)file->private_data); + if (!p_LnxWrpFmPortDev) + return -ENODEV; + if (LnxwrpFmPortIOCTL(p_LnxWrpFmPortDev, cmd, arg, compat)) + return -EFAULT; + } + else + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("minor")); + return -ENODEV; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long fm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + long res; + + fm_mutex_lock(); + res = fm_ioctls(minor, file, cmd, arg, true); + fm_mutex_unlock(); + + return res; +} +#endif + +static long fm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(file->f_path.dentry->d_inode); + long res; + + fm_mutex_lock(); + res = fm_ioctls(minor, file, cmd, arg, false); + fm_mutex_unlock(); + + return res; +} + +/* Globals for FM character device */ +struct file_operations fm_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = fm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fm_compat_ioctl, +#endif + .open = fm_open, + .release = fm_close, +}; diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.c new file mode 100644 index 0000000..c307473 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.c @@ -0,0 +1,1223 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_fm_compat_ioctls.c + + @Description FM PCD compat functions + +*/ + +#if !defined(CONFIG_COMPAT) +#error "missing COMPAT layer..." +#endif + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <sysdev/fsl_soc.h> + +#include "part_ext.h" +#include "fm_ioctls.h" +#include "fm_pcd_ioctls.h" +#include "fm_port_ioctls.h" +#include "lnxwrp_ioctls_fm_compat.h" + +#if defined(FM_COMPAT_DBG) +static void hex_dump(void * p_addr, unsigned int size) +{ + int i; + + for(i=0; i<size; i+=16) + { + printk("%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", p_addr + i, + *(unsigned int *)(p_addr + i), + *(unsigned int *)(p_addr + i + 4), + *(unsigned int *)(p_addr + i + 8), + *(unsigned int *)(p_addr + i +12) + ); + } +} +#endif + +/* maping kernel pointers w/ UserSpace id's { */ +struct map_node { + void *ptr; + u8 node_type; +}; + +static struct map_node compat_ptr2id_array[COMPAT_PTR2ID_ARRAY_MAX] = {{NULL},{FM_MAP_TYPE_UNSPEC}}; + +void compat_del_ptr2id(void *p, enum fm_map_node_type node_type) +{ + compat_uptr_t k; + + _fm_cpt_dbg(COMPAT_GENERIC, "delete (%p)\n", p); + + for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) + if(compat_ptr2id_array[k].ptr == p){ + compat_ptr2id_array[k].ptr = NULL; + compat_ptr2id_array[k].node_type = FM_MAP_TYPE_UNSPEC; + } +} +EXPORT_SYMBOL(compat_del_ptr2id); + +compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type node_type) +{ + compat_uptr_t k; + + _fm_cpt_dbg(COMPAT_GENERIC, " (%p) do ->\n", p); + + if(!p) + return 0; + + for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) + if(compat_ptr2id_array[k].ptr == NULL) + { + compat_ptr2id_array[k].ptr = p; + compat_ptr2id_array[k].node_type = node_type; + _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x \n", k | COMPAT_PTR2ID_WATERMARK); + return k | COMPAT_PTR2ID_WATERMARK; + } + + printk(KERN_WARNING "FMan map list full! No more PCD space on kernel!\n"); + return 0; +} +EXPORT_SYMBOL(compat_add_ptr2id); + +compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type node_type) +{ + compat_uptr_t k; + + _fm_cpt_dbg(COMPAT_GENERIC, " (%p) get -> \n", p); + + for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) + if(compat_ptr2id_array[k].ptr == p && + compat_ptr2id_array[k].node_type == node_type) { + + _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x\n", k | COMPAT_PTR2ID_WATERMARK); + return k | COMPAT_PTR2ID_WATERMARK; + } + + return 0; +} +EXPORT_SYMBOL(compat_get_ptr2id); + +void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type node_type) +{ + + _fm_cpt_dbg(COMPAT_GENERIC, " (0x%08x) get -> \n", comp); + + if((COMPAT_PTR2ID_WM_MASK & comp) != COMPAT_PTR2ID_WATERMARK) { + _fm_cpt_dbg(COMPAT_GENERIC, "Error, invalid watermark (0x%08x)!\n\n", comp); + dump_stack(); + return compat_ptr(comp); + } + + comp &= ~COMPAT_PTR2ID_WM_MASK; + + if(((0 < comp) && (comp < COMPAT_PTR2ID_ARRAY_MAX) && (compat_ptr2id_array[comp].ptr != NULL) + && compat_ptr2id_array[comp].node_type == node_type)) { + _fm_cpt_dbg(COMPAT_GENERIC, "%p\n", compat_ptr2id_array[comp].ptr); + return compat_ptr2id_array[comp].ptr; + } + return NULL; +} +EXPORT_SYMBOL(compat_get_id2ptr); +/* } maping kernel pointers w/ UserSpace id's */ + +void compat_obj_delete( + ioc_compat_fm_obj_t *compat_id, + ioc_fm_obj_t *id) +{ + id->obj = compat_pcd_id2ptr(compat_id->obj); + compat_del_ptr2id(id->obj, FM_MAP_TYPE_PCD_NODE); +} + +static inline void compat_copy_fm_pcd_plcr_next_engine( + ioc_compat_fm_pcd_plcr_next_engine_params_u *compat_param, + ioc_fm_pcd_plcr_next_engine_params_u *param, + ioc_fm_pcd_engine next_engine, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + switch (next_engine) + { + case e_IOC_FM_PCD_PLCR: + if (compat == COMPAT_US_TO_K) + param->p_profile = compat_pcd_id2ptr(compat_param->p_profile); + else + compat_param->p_profile = compat_pcd_ptr2id(param->p_profile); + break; + case e_IOC_FM_PCD_KG: + if (compat == COMPAT_US_TO_K) + param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme); + else + compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme); + break; + default: + if (compat == COMPAT_US_TO_K) + param->action = compat_param->action; + else + compat_param->action = param->action; + break; + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_pcd_plcr_profile( + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, + ioc_fm_pcd_plcr_profile_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->modify = compat_param->modify; + + /* profile_select */ + if (!compat_param->modify) + { + param->profile_select.new_params.profile_type = + compat_param->profile_select.new_params.profile_type; + param->profile_select.new_params.p_fm_port = + compat_ptr(compat_param->profile_select.new_params.p_fm_port); + param->profile_select.new_params.relative_profile_id = + compat_param->profile_select.new_params.relative_profile_id; + } + else + param->profile_select.p_profile = + compat_pcd_id2ptr(compat_param->profile_select.p_profile); + + param->alg_selection = compat_param->alg_selection; + param->color_mode = compat_param->color_mode; + + /* both parameters in the union has the same size, so memcpy works */ + memcpy(¶m->color, &compat_param->color, sizeof(param->color)); + + memcpy(¶m->non_passthrough_alg_param, + &compat_param->non_passthrough_alg_param, + sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); + + param->next_engine_on_green = compat_param->next_engine_on_green; + param->next_engine_on_yellow = compat_param->next_engine_on_yellow; + param->next_engine_on_red = compat_param->next_engine_on_red; + + param->trap_profile_on_flow_A = compat_param->trap_profile_on_flow_A; + param->trap_profile_on_flow_B = compat_param->trap_profile_on_flow_B; + param->trap_profile_on_flow_C = compat_param->trap_profile_on_flow_C; + } + else + { + compat_param->modify = param->modify; + + /* profile_select */ + if (!param->modify) + { + compat_param->profile_select.new_params.profile_type = + param->profile_select.new_params.profile_type; + compat_param->profile_select.new_params.p_fm_port = + ptr_to_compat(param->profile_select.new_params.p_fm_port); + compat_param->profile_select.new_params.relative_profile_id = + param->profile_select.new_params.relative_profile_id; + } + else + compat_param->profile_select.p_profile = + compat_pcd_ptr2id(param->profile_select.p_profile); + + compat_param->alg_selection = param->alg_selection; + compat_param->color_mode = param->color_mode; + + /* both parameters in the union has the same size, so memcpy works */ + memcpy(&compat_param->color, ¶m->color, sizeof(compat_param->color)); + + memcpy(&compat_param->non_passthrough_alg_param, + ¶m->non_passthrough_alg_param, + sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); + + compat_param->next_engine_on_green = param->next_engine_on_green; + compat_param->next_engine_on_yellow = param->next_engine_on_yellow; + compat_param->next_engine_on_red = param->next_engine_on_red; + + compat_param->trap_profile_on_flow_A = param->trap_profile_on_flow_A; + compat_param->trap_profile_on_flow_B = param->trap_profile_on_flow_B; + compat_param->trap_profile_on_flow_C = param->trap_profile_on_flow_C; + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_green, + ¶m->params_on_green, param->next_engine_on_green, compat); + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_yellow, + ¶m->params_on_yellow, param->next_engine_on_yellow, compat); + + compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_red, + ¶m->params_on_red, param->next_engine_on_red, compat); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +static inline void compat_copy_fm_pcd_cc_next_kg( + ioc_compat_fm_pcd_cc_next_kg_params_t *compat_param, + ioc_fm_pcd_cc_next_kg_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->new_fqid = compat_param->new_fqid; + param->override_fqid = compat_param->override_fqid; + param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme); + } + else + { + compat_param->new_fqid = param->new_fqid; + compat_param->override_fqid = param->override_fqid; + compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme); + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +static inline void compat_copy_fm_pcd_cc_next_cc( + ioc_compat_fm_pcd_cc_next_cc_params_t *compat_param, + ioc_fm_pcd_cc_next_cc_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + param->cc_node_id = compat_pcd_id2ptr(compat_param->cc_node_id); + else + compat_param->cc_node_id = compat_pcd_ptr2id(param->cc_node_id); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +static inline void compat_copy_fm_pcd_cc_next_engine( + ioc_compat_fm_pcd_cc_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_next_engine_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->next_engine = compat_param->next_engine; + if (param->next_engine != e_IOC_FM_PCD_INVALID ) + _fm_cpt_dbg(compat, " param->next_engine = %i \n", param->next_engine); + + switch (param->next_engine) + { +#if DPAA_VERSION >= 11 + case e_IOC_FM_PCD_FR: + param->params.fr_params.frm_replic_id = compat_pcd_id2ptr(compat_param->params.fr_params.frm_replic_id); + break; +#endif /* DPAA_VERSION >= 11 */ + case e_IOC_FM_PCD_CC: + compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); + break; + case e_IOC_FM_PCD_KG: + param->manip_id = compat_pcd_id2ptr(compat_param->manip_id); + compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); + break; + case e_IOC_FM_PCD_DONE: + case e_IOC_FM_PCD_PLCR: + param->manip_id = compat_pcd_id2ptr(compat_param->manip_id); + default: + memcpy(¶m->params, &compat_param->params, sizeof(param->params)); + } + param->statistics_en = compat_param->statistics_en; + } + else + { + compat_param->next_engine = param->next_engine; + + switch (compat_param->next_engine) + { +#if DPAA_VERSION >= 11 + case e_IOC_FM_PCD_FR: + compat_param->params.fr_params.frm_replic_id = compat_pcd_ptr2id(param->params.fr_params.frm_replic_id); + break; +#endif /* DPAA_VERSION >= 11 */ + case e_IOC_FM_PCD_CC: + compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); + break; + case e_IOC_FM_PCD_KG: + compat_param->manip_id = compat_pcd_ptr2id(param->manip_id); + compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); + break; + case e_IOC_FM_PCD_DONE: + case e_IOC_FM_PCD_PLCR: + compat_param->manip_id = compat_pcd_ptr2id(param->manip_id); + default: + memcpy(&compat_param->params, ¶m->params, sizeof(compat_param->params)); + } + compat_param->statistics_en = param->statistics_en; + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_pcd_cc_key( + ioc_compat_fm_pcd_cc_key_params_t *compat_param, + ioc_fm_pcd_cc_key_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->p_key = compat_ptr(compat_param->p_key); + param->p_mask = compat_ptr(compat_param->p_mask); + } + else + { + compat_param->p_key = ptr_to_compat(param->p_key); + compat_param->p_mask = ptr_to_compat(param->p_mask); + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->id = compat_pcd_id2ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_size; + compat_copy_fm_pcd_cc_key( + &compat_param->key_params, + ¶m->key_params, + compat); + } + else + { + compat_param->id = compat_pcd_ptr2id(param->id); + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_size; + compat_copy_fm_pcd_cc_key( + &compat_param->key_params, + ¶m->key_params, + compat); + } +} + +void compat_copy_fm_pcd_cc_node_modify_next_engine( + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->id = compat_pcd_id2ptr(compat_param->id); + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_size; + } + else + { + compat_param->id = compat_pcd_ptr2id(param->id); + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_size; + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_fm_pcd_cc_tree_modify_next_engine( + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->id = compat_pcd_id2ptr(compat_param->id); + param->grp_indx = compat_param->grp_indx; + param->indx = compat_param->indx; + } + else + { + compat_param->id = compat_pcd_ptr2id(param->id); + compat_param->grp_indx = param->grp_indx; + compat_param->indx = param->indx; + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params, + ¶m->cc_next_engine_params, + compat); +} + +void compat_copy_fm_pcd_hash_table( + ioc_compat_fm_pcd_hash_table_params_t *compat_param, + ioc_fm_pcd_hash_table_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param-> max_num_of_keys = compat_param->max_num_of_keys; + param->statistics_mode = compat_param->statistics_mode; + param->hash_res_mask = compat_param->hash_res_mask; + param->hash_shift = compat_param->hash_shift; + param->match_key_size = compat_param->match_key_size; + param->id = compat_pcd_id2ptr(compat_param->id); + } + else + { + compat_param-> max_num_of_keys = param->max_num_of_keys; + compat_param->statistics_mode = param->statistics_mode; + compat_param->hash_res_mask = param->hash_res_mask; + compat_param->hash_shift = param->hash_shift; + compat_param->match_key_size = param->match_key_size; + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params_for_miss, + ¶m->cc_next_engine_params_for_miss, + compat); +} + +void compat_copy_fm_pcd_cc_grp( + ioc_compat_fm_pcd_cc_grp_params_t *compat_param, + ioc_fm_pcd_cc_grp_params_t *param, + uint8_t compat) +{ + int k; + + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->num_of_distinction_units = compat_param->num_of_distinction_units; + memcpy(param->unit_ids, compat_param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); + } + else + { + compat_param->num_of_distinction_units = param->num_of_distinction_units; + memcpy(compat_param->unit_ids, param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); + } + + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP; k++) + compat_copy_fm_pcd_cc_next_engine( + &compat_param->next_engine_per_entries_in_grp[k], + ¶m->next_engine_per_entries_in_grp[k], + compat); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_pcd_cc_tree( + ioc_compat_fm_pcd_cc_tree_params_t *compat_param, + ioc_fm_pcd_cc_tree_params_t *param, + uint8_t compat) +{ + int k; + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id); + param->num_of_groups = compat_param->num_of_groups; + } + else + { + compat_param->net_env_id = compat_pcd_ptr2id(param->net_env_id); + compat_param->num_of_groups = param->num_of_groups; + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } + + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++) + compat_copy_fm_pcd_cc_grp( + &compat_param->fm_pcd_cc_group_params[k], + ¶m->fm_pcd_cc_group_params[k], + compat); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_fm_pcd_prs_sw( + ioc_compat_fm_pcd_prs_sw_params_t *compat_param, + ioc_fm_pcd_prs_sw_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->override = compat_param->override; + param->size = compat_param->size; + param->base = compat_param->base; + param->p_code = compat_ptr(compat_param->p_code); + memcpy(param->sw_prs_data_params,compat_param->sw_prs_data_params,IOC_FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t)); + param->num_of_labels = compat_param->num_of_labels; + memcpy(param->labels_table,compat_param->labels_table,IOC_FM_PCD_PRS_NUM_OF_LABELS*sizeof(ioc_fm_pcd_prs_label_params_t)); + } +} + +void compat_copy_fm_pcd_kg_scheme( + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, + ioc_fm_pcd_kg_scheme_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg(compat," {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->modify = compat_param->modify; + + /* scm_id */ + if (compat_param->modify) + { + param->scm_id.scheme_id = compat_pcd_id2ptr(compat_param->scm_id.scheme_id); + _fm_cpt_dbg(compat," param->scm_id.scheme_id = %p \n", param->scm_id.scheme_id); + } + else + param->scm_id.relative_scheme_id = compat_param->scm_id.relative_scheme_id; + + param->always_direct = compat_param->always_direct; + /* net_env_params */ + param->net_env_params.net_env_id = compat_pcd_id2ptr(compat_param->net_env_params.net_env_id); + param->net_env_params.num_of_distinction_units = compat_param->net_env_params.num_of_distinction_units; + memcpy(param->net_env_params.unit_ids, + compat_param->net_env_params.unit_ids, + IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + + param->use_hash = compat_param->use_hash; + memcpy(¶m->key_extract_and_hash_params, + &compat_param->key_extract_and_hash_params, + sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); + param->bypass_fqid_generation = compat_param->bypass_fqid_generation; + param->base_fqid = compat_param->base_fqid; +#if DPAA_VERSION >= 11 + param->override_storage_profile = + compat_param->override_storage_profile; + param->storage_profile = compat_param->storage_profile; +#endif /* DPAA_VERSION >= 11 */ + param->num_of_used_extracted_ors = compat_param->num_of_used_extracted_ors; + memcpy(param->extracted_ors, + compat_param->extracted_ors, + IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); + param->next_engine = compat_param->next_engine; + + /* kg_next_engine_params */ + if (param->next_engine == e_IOC_FM_PCD_CC) + { + param->kg_next_engine_params.cc.tree_id = compat_pcd_id2ptr(compat_param->kg_next_engine_params.cc.tree_id); + param->kg_next_engine_params.cc.grp_id = compat_param->kg_next_engine_params.cc.grp_id; + param->kg_next_engine_params.cc.plcr_next = compat_param->kg_next_engine_params.cc.plcr_next; + param->kg_next_engine_params.cc.bypass_plcr_profile_generation + = compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation; + memcpy(¶m->kg_next_engine_params.cc.plcr_profile, + &compat_param->kg_next_engine_params.cc.plcr_profile, + sizeof(ioc_fm_pcd_kg_plcr_profile_t)); + } + else + memcpy(¶m->kg_next_engine_params, + &compat_param->kg_next_engine_params, + sizeof(param->kg_next_engine_params)); + + memcpy(¶m->scheme_counter, + &compat_param->scheme_counter, + sizeof(ioc_fm_pcd_kg_scheme_counter_t)); + } + else + { + compat_param->modify = param->modify; + + /* scm_id */ + if (param->modify) + compat_param->scm_id.scheme_id = compat_pcd_ptr2id(param->scm_id.scheme_id); + else + compat_param->scm_id.relative_scheme_id = param->scm_id.relative_scheme_id; + + compat_param->always_direct = param->always_direct; + + /* net_env_params */ + compat_param->net_env_params.net_env_id = compat_pcd_ptr2id(param->net_env_params.net_env_id); + compat_param->net_env_params.num_of_distinction_units = param->net_env_params.num_of_distinction_units; + memcpy(compat_param->net_env_params.unit_ids, param->net_env_params.unit_ids, IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + + compat_param->use_hash = param->use_hash; + memcpy(&compat_param->key_extract_and_hash_params, ¶m->key_extract_and_hash_params, sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); + compat_param->bypass_fqid_generation = param->bypass_fqid_generation; + compat_param->base_fqid = param->base_fqid; +#if DPAA_VERSION >= 11 + compat_param->override_storage_profile = + param->override_storage_profile; + compat_param->storage_profile = param->storage_profile; +#endif /* DPAA_VERSION >= 11 */ + compat_param->num_of_used_extracted_ors = param->num_of_used_extracted_ors; + memcpy(compat_param->extracted_ors, param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); + compat_param->next_engine = param->next_engine; + + /* kg_next_engine_params */ + if (compat_param->next_engine == e_IOC_FM_PCD_CC) + { + compat_param->kg_next_engine_params.cc.tree_id = compat_pcd_ptr2id(param->kg_next_engine_params.cc.tree_id); + compat_param->kg_next_engine_params.cc.grp_id = param->kg_next_engine_params.cc.grp_id; + compat_param->kg_next_engine_params.cc.plcr_next = param->kg_next_engine_params.cc.plcr_next; + compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation + = param->kg_next_engine_params.cc.bypass_plcr_profile_generation; + memcpy(&compat_param->kg_next_engine_params.cc.plcr_profile, + ¶m->kg_next_engine_params.cc.plcr_profile, + sizeof(ioc_fm_pcd_kg_plcr_profile_t)); + } + else + memcpy(¶m->kg_next_engine_params, &compat_param->kg_next_engine_params, sizeof(compat_param->kg_next_engine_params)); + + memcpy(&compat_param->scheme_counter, ¶m->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t)); + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } + + _fm_cpt_dbg(compat," ...->}\n"); +} + +void compat_copy_fm_pcd_kg_scheme_select( + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, + ioc_fm_pcd_kg_scheme_select_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->direct = compat_param->direct; + if (param->direct) + param->scheme_id = compat_pcd_id2ptr(compat_param->scheme_id); + } +} + +void compat_copy_fm_pcd_kg_schemes_params( + ioc_compat_fm_pcd_port_schemes_params_t *compat_param, + ioc_fm_pcd_port_schemes_params_t *param, + uint8_t compat) +{ + int k; + + if (compat == COMPAT_US_TO_K) { + param->num_of_schemes = compat_param->num_of_schemes; + for(k=0; k < compat_param->num_of_schemes; k++) + param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]); + } +} + +void compat_copy_fm_port_pcd_cc( + ioc_compat_fm_port_pcd_cc_params_t *compat_cc_params , + ioc_fm_port_pcd_cc_params_t *p_cc_params, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K){ + p_cc_params->cc_tree_id = compat_pcd_id2ptr(compat_cc_params->cc_tree_id); + } +} + +void compat_copy_fm_port_pcd_kg( + ioc_compat_fm_port_pcd_kg_params_t *compat_param, + ioc_fm_port_pcd_kg_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K){ + uint8_t k; + + param->num_of_schemes = compat_param->num_of_schemes; + for(k=0; k<compat_param->num_of_schemes; k++) + param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]); + + param->direct_scheme = compat_param->direct_scheme; + if (param->direct_scheme) + param->direct_scheme_id = compat_pcd_id2ptr(compat_param->direct_scheme_id); + } +} + +void compat_copy_fm_port_pcd( + ioc_compat_fm_port_pcd_params_t *compat_param, + ioc_fm_port_pcd_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params; + ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params; + ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params; + ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params; + + same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_param + 1); + compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1); + compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1); + compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1); + + _fm_cpt_dbg(compat,"\n param->p_prs_params=%p \n", param->p_prs_params); + _fm_cpt_dbg(compat," param->p_cc_params=%p \n", param->p_cc_params); + _fm_cpt_dbg(compat," param->p_kg_params=%p \n", param->p_kg_params); + _fm_cpt_dbg(compat," param->p_plcr_params=%p \n", param->p_plcr_params); + _fm_cpt_dbg(compat," param->p_ip_reassembly_manip=%p \n", param->p_ip_reassembly_manip); + + param->pcd_support = compat_param->pcd_support; + param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id); + + if (param->p_cc_params) + compat_copy_fm_port_pcd_cc(compat_port_pcd_cc_params, param->p_cc_params, COMPAT_US_TO_K); + if (param->p_kg_params) + compat_copy_fm_port_pcd_kg(compat_port_pcd_kg_params, param->p_kg_params, COMPAT_US_TO_K); + if (param->p_plcr_params) + param->p_plcr_params->plcr_profile_id = compat_pcd_id2ptr(compat_port_pcd_plcr_params->plcr_profile_id); + param->p_ip_reassembly_manip = compat_pcd_id2ptr(compat_param->p_ip_reassembly_manip); + } +} + +void compat_copy_fm_port_pcd_modify_tree( + ioc_compat_fm_obj_t *compat_id, + ioc_fm_obj_t *id, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + id->obj = compat_pcd_id2ptr(compat_id->obj); +} + +#if (DPAA_VERSION >= 11) +void compat_copy_fm_port_vsp_alloc_params( + ioc_compat_fm_port_vsp_alloc_params_t *compat_param, + ioc_fm_port_vsp_alloc_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + _fm_cpt_dbg(compat," param->p_fm_tx_port=%p \n", param->p_fm_tx_port); + + param->dflt_relative_id = compat_param->dflt_relative_id; + param->num_of_profiles = compat_param->num_of_profiles; + param->p_fm_tx_port = compat_pcd_id2ptr(compat_param->p_fm_tx_port); + } +} +#endif /* (DPAA_VERSION >= 11) */ + +void compat_copy_fm_pcd_net_env( + ioc_compat_fm_pcd_net_env_params_t *compat_param, + ioc_fm_pcd_net_env_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->num_of_distinction_units = compat_param->num_of_distinction_units; + memcpy(param->units, compat_param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + param->id = NULL; /* to avoid passing garbage to the kernel */ + } + else + { + compat_param->num_of_distinction_units = param->num_of_distinction_units; + memcpy(compat_param->units, param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } +} + +void compat_copy_fm_pcd_cc_node_modify_key( + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) + { + param->key_indx = compat_param->key_indx; + param->key_size = compat_param->key_size; + param->p_key = (uint8_t *)compat_ptr(compat_param->p_key); + _fm_cpt_dbg(compat," param->p_key = %p \n", param->p_key); + param->p_mask = (uint8_t *)compat_ptr(compat_param->p_mask); + _fm_cpt_dbg(compat," param->p_mask = %p\n", param->p_mask); + param->id = compat_pcd_id2ptr(compat_param->id); + _fm_cpt_dbg(compat," param->id = %p \n", param->id); + } + else + { + compat_param->key_indx = param->key_indx; + compat_param->key_size = param->key_size; + compat_param->p_key = ptr_to_compat((void *)param->p_key); + compat_param->p_mask = ptr_to_compat((void *)param->p_mask); + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } +} + +void compat_copy_keys( + ioc_compat_keys_params_t *compat_param, + ioc_keys_params_t *param, + uint8_t compat) +{ + int k = 0; + + _fm_cpt_dbg(compat," {->...\n"); + + if (compat == COMPAT_US_TO_K) { + param->max_num_of_keys = compat_param->max_num_of_keys; + param->mask_support = compat_param->mask_support; + param->statistics_mode = compat_param->statistics_mode; + param->num_of_keys = compat_param->num_of_keys; + param->key_size = compat_param->key_size; +#if (DPAA_VERSION >= 11) + memcpy(¶m->frame_length_ranges, + &compat_param->frame_length_ranges, + sizeof(param->frame_length_ranges[0] * + IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR)); +#endif /* (DPAA_VERSION >= 11) */ + } + else { + compat_param->max_num_of_keys = param->max_num_of_keys; + compat_param->mask_support = param->mask_support; + compat_param->statistics_mode = param->statistics_mode; + compat_param->num_of_keys = param->num_of_keys; + compat_param->key_size = param->key_size; +#if (DPAA_VERSION >= 11) + memcpy(&compat_param->frame_length_ranges, + ¶m->frame_length_ranges, + sizeof(compat_param->frame_length_ranges[0] * + IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR)); +#endif /* (DPAA_VERSION >= 11) */ + } + + for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_KEYS; k++) + compat_copy_fm_pcd_cc_key( + &compat_param->key_params[k], + ¶m->key_params[k], + compat); + + compat_copy_fm_pcd_cc_next_engine( + &compat_param->cc_next_engine_params_for_miss, + ¶m->cc_next_engine_params_for_miss, + compat); + + _fm_cpt_dbg(compat," ...->}\n"); +} + +void compat_copy_fm_pcd_cc_node( + ioc_compat_fm_pcd_cc_node_params_t *compat_param, + ioc_fm_pcd_cc_node_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg(compat," {->...\n"); + + if (compat == COMPAT_US_TO_K) + memcpy(¶m->extract_cc_params, &compat_param->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t)); + + else + { + compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); + + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + _fm_cpt_dbg(compat," param->id = %p \n", param->id); + } + + compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); + + _fm_cpt_dbg(compat," ...->}\n"); +} + +void compat_fm_pcd_manip_set_node( + ioc_compat_fm_pcd_manip_params_t *compat_param, + ioc_fm_pcd_manip_params_t *param, + uint8_t compat) +{ + if (compat == COMPAT_US_TO_K) { + param->type = compat_param->type; + switch (param->type) { + case e_IOC_FM_PCD_MANIP_HDR: + param->u.hdr.rmv = compat_param->u.hdr.rmv; + memcpy(¶m->u.hdr.rmv_params, + &compat_param->u.hdr.rmv_params, + sizeof(param->u.hdr.rmv_params)); + + param->u.hdr.insrt = compat_param->u.hdr.insrt; + param->u.hdr.insrt_params.type = + compat_param->u.hdr.insrt_params.type; + switch (compat_param->u.hdr.insrt_params.type) + { + case e_IOC_FM_PCD_MANIP_INSRT_GENERIC: + param->u.hdr.insrt_params.u.generic.offset = + compat_param->u.hdr.insrt_params.u.generic.offset; + param->u.hdr.insrt_params.u.generic.size = + compat_param->u.hdr.insrt_params.u.generic.size; + param->u.hdr.insrt_params.u.generic.replace = + compat_param->u.hdr.insrt_params.u.generic.replace; + param->u.hdr.insrt_params.u.generic.p_data = + compat_ptr(compat_param->u.hdr.insrt_params.u.generic.p_data); + break; + case e_IOC_FM_PCD_MANIP_INSRT_BY_HDR: + param->u.hdr.insrt_params.u.by_hdr.type = + compat_param->u.hdr.insrt_params.u.by_hdr.type; + param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2 = + compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2; + param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update = + compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update; + param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size = + compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size; + param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data = + compat_ptr(compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data); + break; + default: + _fm_cpt_err("Unsupported type: %d", compat_param->u.hdr.insrt_params.type); + } + + param->u.hdr.field_update = compat_param->u.hdr.field_update; + memcpy(¶m->u.hdr.field_update_params, + &compat_param->u.hdr.field_update_params, + sizeof(param->u.hdr.field_update_params)); + + param->u.hdr.custom = compat_param->u.hdr.custom; + memcpy(¶m->u.hdr.custom_params, + &compat_param->u.hdr.custom_params, + sizeof(param->u.hdr.custom_params)); + + param->u.hdr.dont_parse_after_manip = + compat_param->u.hdr.dont_parse_after_manip; + break; + case e_IOC_FM_PCD_MANIP_REASSEM: + memcpy(¶m->u.reassem, &compat_param->u.reassem, sizeof(param->u.reassem)); + break; + case e_IOC_FM_PCD_MANIP_FRAG: + memcpy(¶m->u.frag, &compat_param->u.frag, sizeof(param->u.frag)); + break; + case e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD: + param->u.special_offload = compat_param->u.special_offload; + break; + } + + param->p_next_manip = compat_pcd_id2ptr(compat_param->p_next_manip); + param->id = compat_pcd_id2ptr(compat_param->id); + } + else { + compat_param->type = param->type; + memcpy(&compat_param->u, ¶m->u, sizeof(compat_param->u)); + + if (param->type == e_IOC_FM_PCD_MANIP_HDR && + param->u.hdr.insrt_params.type == e_IOC_FM_PCD_MANIP_INSRT_GENERIC) + compat_param->u.hdr.insrt_params.u.generic.p_data = + ptr_to_compat(param->u.hdr.insrt_params.u.generic.p_data); + + compat_param->p_next_manip = compat_pcd_ptr2id(param->id); + /* ... should be one that was added previously by the very call to + compat_add_ptr2id() below: */ + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } +} + +#if (DPAA_VERSION >= 11) +void compat_copy_fm_pcd_frm_replic_group_params( + ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param, + ioc_fm_pcd_frm_replic_group_params_t *param, + uint8_t compat) +{ + int k; + + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->max_num_of_entries = compat_param->max_num_of_entries; + param->num_of_entries = compat_param->num_of_entries; + param->id = compat_pcd_id2ptr(compat_param->id); + } + else + { + compat_param->max_num_of_entries = param->max_num_of_entries; + compat_param->num_of_entries = param->num_of_entries; + compat_param->id = compat_add_ptr2id(param->id, + FM_MAP_TYPE_PCD_NODE); + } + + for (k=0; k < IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES; k++) + compat_copy_fm_pcd_cc_next_engine( + &compat_param->next_engine_params[k], + ¶m->next_engine_params[k], + compat); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_pcd_frm_replic_member( + ioc_compat_fm_pcd_frm_replic_member_t *compat_param, + ioc_fm_pcd_frm_replic_member_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->h_replic_group = compat_pcd_id2ptr(compat_param->h_replic_group); + param->member_index = compat_param->member_index; + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_pcd_frm_replic_member_params( + ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param, + ioc_fm_pcd_frm_replic_member_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + compat_copy_fm_pcd_frm_replic_member(&compat_param->member, + ¶m->member, compat); + + compat_copy_fm_pcd_cc_next_engine(&compat_param->next_engine_params, + ¶m->next_engine_params, compat); + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_vsp_params( + ioc_compat_fm_vsp_params_t *compat_param, + ioc_fm_vsp_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->p_fm = compat_pcd_id2ptr(compat_param->p_fm); + memcpy(¶m->ext_buf_pools, &compat_param->ext_buf_pools, sizeof(ioc_fm_ext_pools)); + param->liodn_offset = compat_param->liodn_offset; + param->portParams.port_id = compat_param->portParams.port_id; + param->portParams.port_type = compat_param->portParams.port_type; + param->relative_profile_id = compat_param->relative_profile_id; + param->id = compat_pcd_id2ptr(compat_param->id); + } + else + { + compat_param->p_fm = compat_pcd_ptr2id(param->p_fm); + memcpy(&compat_param->ext_buf_pools, ¶m->ext_buf_pools, sizeof(ioc_fm_ext_pools)); + compat_param->liodn_offset = param->liodn_offset; + compat_param->portParams.port_id = param->portParams.port_id; + compat_param->portParams.port_type = param->portParams.port_type; + compat_param->relative_profile_id = param->relative_profile_id; + compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_buf_pool_depletion_params( + ioc_compat_fm_buf_pool_depletion_params_t *compat_param, + ioc_fm_buf_pool_depletion_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); + memcpy(¶m->fm_buf_pool_depletion, + &compat_param->fm_buf_pool_depletion, + sizeof(ioc_fm_buf_pool_depletion_t)); + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_buffer_prefix_content_params( + ioc_compat_fm_buffer_prefix_content_params_t *compat_param, + ioc_fm_buffer_prefix_content_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); + memcpy(¶m->fm_buffer_prefix_content, + &compat_param->fm_buffer_prefix_content, + sizeof(ioc_fm_buffer_prefix_content_t)); + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_vsp_config_no_sg_params( + ioc_compat_fm_vsp_config_no_sg_params_t *compat_param, + ioc_fm_vsp_config_no_sg_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); + param->no_sg = compat_param->no_sg; + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} + +void compat_copy_fm_vsp_prs_result_params( + ioc_compat_fm_vsp_prs_result_params_t *compat_param, + ioc_fm_vsp_prs_result_params_t *param, + uint8_t compat) +{ + _fm_cpt_dbg (compat, " {->...\n"); + + if (compat == COMPAT_US_TO_K) + { + param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); + /* p_data is an user-space pointer that needs to remain unmodified */ + param->p_data = (void *)(unsigned long long)compat_param->p_data; + } + else + { + compat_param->p_fm_vsp = compat_pcd_ptr2id(param->p_fm_vsp); + /* p_data is an user-space pointer that needs to remain unmodified */ + compat_param->p_data = (compat_uptr_t)((unsigned long long)param->p_data & 0xFFFFFFFF); + } + + _fm_cpt_dbg (compat, " ...->}\n"); +} +#endif /* (DPAA_VERSION >= 11) */ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.h new file mode 100644 index 0000000..e8e6677 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_ioctls_fm_compat.h @@ -0,0 +1,679 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_ioctls_fm_compat.h + + @Description FM PCD compat structures definition. + +*/ + +#ifndef __FM_COMPAT_IOCTLS_H +#define __FM_COMPAT_IOCTLS_H + +#include <linux/compat.h> + +#define COMPAT_K_TO_US 0 /* copy from Kernel to User */ +#define COMPAT_US_TO_K 1 /* copy from User to Kernel */ +#define COMPAT_GENERIC 2 + +#define COMPAT_COPY_K2US(dest, src, type) compat_copy_##type(src, dest, 0) +#define COMPAT_COPY_US2K(dest, src, type) compat_copy_##type(dest, src, 1) + +/* mapping kernel pointers w/ UserSpace id's { */ +/* Because compat_ptr(ptr_to_compat(X)) != X, this way we cannot exchange pointers + back and forth (US - KS). compat_ptr is a cast and pointers are broken. */ +#define COMPAT_PTR2ID_ARRAY_MAX (256+1) /* first location is not used */ +#define COMPAT_PTR2ID_WATERMARK 0xface0000 +#define COMPAT_PTR2ID_WM_MASK 0xffff0000 + +/* define it for debug trace */ +/*#define FM_COMPAT_DBG*/ + +#define _fm_cpt_prk(stage, format, arg...) \ + printk(stage "fm_cpt (cpu:%u): " format, raw_smp_processor_id(), ##arg) + +#define _fm_cpt_inf(format, arg...) _fm_cpt_prk(KERN_INFO, format, ##arg) +#define _fm_cpt_wrn(format, arg...) _fm_cpt_prk(KERN_WARNING, format, ##arg) +#define _fm_cpt_err(format, arg...) _fm_cpt_prk(KERN_ERR, format, ##arg) + +/* used for compat IOCTL debugging */ +#if defined(FM_COMPAT_DBG) + #define _fm_cpt_dbg(from, format, arg...) \ + do{ \ + if (from == COMPAT_US_TO_K) \ + printk("fm_cpt to KS [%s:%u](cpu:%u) - " format, \ + __func__, __LINE__, raw_smp_processor_id(), ##arg); \ + else if (from == COMPAT_K_TO_US) \ + printk("fm_cpt to US [%s:%u](cpu:%u) - " format, \ + __func__, __LINE__, raw_smp_processor_id(), ##arg); \ + else \ + printk("fm_cpt [%s:%u](cpu:%u) - " format, \ + __func__, __LINE__, raw_smp_processor_id(), ##arg); \ + }while(0) +#else +# define _fm_cpt_dbg(arg...) +#endif + +/*TODO: per FMan module: + * + * Parser: FM_MAP_TYPE_PARSER_NODE, + * Kg: FM_MAP_TYPE_KG_NODE, + * Policer: FM_MAP_TYPE_POLICER_NODE + * Manip: FM_MAP_TYPE_MANIP_NODE + **/ +enum fm_map_node_type { + FM_MAP_TYPE_UNSPEC = 0, + FM_MAP_TYPE_PCD_NODE, + + /* add types here, update the policy */ + + __FM_MAP_TYPE_AFTER_LAST, + FM_MAP_TYPE_MAX = __FM_MAP_TYPE_AFTER_LAST - 1 +}; + +void compat_del_ptr2id(void *p, enum fm_map_node_type); +compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type); +compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type); +void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type); + +static inline compat_uptr_t compat_pcd_ptr2id(void *ptr) { + return (ptr)? compat_get_ptr2id(ptr, FM_MAP_TYPE_PCD_NODE) + : (compat_uptr_t) 0; +} + +static inline void *compat_pcd_id2ptr(compat_uptr_t id) { + return (id) ? compat_get_id2ptr(id, FM_MAP_TYPE_PCD_NODE) + : NULL; +} + +/* other similar inlines may be added as new nodes are added + to enum fm_map_node_type above... */ +/* } mapping kernel pointers w/ UserSpace id's */ + +/* pcd compat structures { */ +typedef struct ioc_compat_fm_pcd_cc_node_remove_key_params_t { + compat_uptr_t id; + uint16_t key_indx; +} ioc_compat_fm_pcd_cc_node_remove_key_params_t; + +typedef union ioc_compat_fm_pcd_plcr_next_engine_params_u { + ioc_fm_pcd_done_action action; + compat_uptr_t p_profile; + compat_uptr_t p_direct_scheme; +} ioc_compat_fm_pcd_plcr_next_engine_params_u; + +typedef struct ioc_compat_fm_pcd_plcr_profile_params_t { + bool modify; + union { + struct { + ioc_fm_pcd_profile_type_selection profile_type; + compat_uptr_t p_fm_port; + uint16_t relative_profile_id; + } new_params; + compat_uptr_t p_profile; + } profile_select; + ioc_fm_pcd_plcr_algorithm_selection alg_selection; + ioc_fm_pcd_plcr_color_mode color_mode; + + union { + ioc_fm_pcd_plcr_color dflt_color; + ioc_fm_pcd_plcr_color override; + } color; + + ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param; + + ioc_fm_pcd_engine next_engine_on_green; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_green; + + ioc_fm_pcd_engine next_engine_on_yellow; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_yellow; + + ioc_fm_pcd_engine next_engine_on_red; + ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_red; + + bool trap_profile_on_flow_A; + bool trap_profile_on_flow_B; + bool trap_profile_on_flow_C; + compat_uptr_t id; +} ioc_compat_fm_pcd_plcr_profile_params_t; + +typedef struct ioc_compat_fm_obj_t { + compat_uptr_t obj; +} ioc_compat_fm_obj_t; + +typedef struct ioc_compat_fm_pcd_kg_scheme_select_t { + bool direct; + compat_uptr_t scheme_id; +} ioc_compat_fm_pcd_kg_scheme_select_t; + +typedef struct ioc_compat_fm_pcd_port_schemes_params_t { + uint8_t num_of_schemes; + compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; +} ioc_compat_fm_pcd_port_schemes_params_t; + +#if (DPAA_VERSION >= 11) +typedef struct ioc_compat_fm_port_vsp_alloc_params_t { + uint8_t num_of_profiles; /**< Number of Virtual Storage Profiles */ + uint8_t dflt_relative_id; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port + The same default Virtual-Storage-Profile-id will be for coupled Tx port + if relevant function called for Rx port */ + compat_uptr_t p_fm_tx_port; /**< Handle to coupled Tx Port; not relevant for OP port. */ +}ioc_compat_fm_port_vsp_alloc_params_t; +#endif /* (DPAA_VERSION >= 11) */ + +typedef struct ioc_compat_fm_pcd_net_env_params_t { + uint8_t num_of_distinction_units; + ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* same structure*/ + compat_uptr_t id; +} ioc_compat_fm_pcd_net_env_params_t; + +typedef struct ioc_compat_fm_pcd_prs_sw_params_t { + bool override; + uint32_t size; + uint16_t base; + compat_uptr_t p_code; + uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t num_of_labels; + ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS]; +} ioc_compat_fm_pcd_prs_sw_params_t; + +typedef struct ioc_compat_fm_pcd_cc_next_kg_params_t { + bool override_fqid; + uint32_t new_fqid; +#if DPAA_VERSION >= 11 + uint8_t new_relative_storage_profile_id; +#endif + compat_uptr_t p_direct_scheme; +} ioc_compat_fm_pcd_cc_next_kg_params_t; + +typedef struct ioc_compat_fm_pcd_cc_next_cc_params_t { + compat_uptr_t cc_node_id; +} ioc_compat_fm_pcd_cc_next_cc_params_t; + +#if DPAA_VERSION >= 11 +typedef struct ioc_compat_fm_pcd_cc_next_fr_params_t { + compat_uptr_t frm_replic_id; +} ioc_compat_fm_pcd_cc_next_fr_params_t; +#endif /* DPAA_VERSION >= 11 */ + +typedef struct ioc_compat_fm_pcd_cc_next_engine_params_t { + ioc_fm_pcd_engine next_engine; + union { + ioc_compat_fm_pcd_cc_next_cc_params_t cc_params; /**< compat structure*/ + ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< same structure*/ + ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< same structure*/ + ioc_compat_fm_pcd_cc_next_kg_params_t kg_params; /**< compat structure*/ +#if DPAA_VERSION >= 11 + ioc_compat_fm_pcd_cc_next_fr_params_t fr_params; /**< compat structure*/ +#endif /* DPAA_VERSION >= 11 */ + } params; + compat_uptr_t manip_id; + bool statistics_en; +} ioc_compat_fm_pcd_cc_next_engine_params_t; + +typedef struct ioc_compat_fm_pcd_cc_grp_params_t { + uint8_t num_of_distinction_units; + uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS]; + ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; +} ioc_compat_fm_pcd_cc_grp_params_t; + +typedef struct ioc_compat_fm_pcd_cc_tree_params_t { + compat_uptr_t net_env_id; + uint8_t num_of_groups; + ioc_compat_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS]; + compat_uptr_t id; +} ioc_compat_fm_pcd_cc_tree_params_t; + +typedef struct ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t { + compat_uptr_t id; + uint8_t grp_indx; + uint8_t indx; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; +} ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t; + +typedef struct ioc_compat_fm_pcd_cc_key_params_t { + compat_uptr_t p_key; + compat_uptr_t p_mask; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; /**< compat structure*/ +} ioc_compat_fm_pcd_cc_key_params_t; + +typedef struct ioc_compat_keys_params_t { + uint16_t max_num_of_keys; + bool mask_support; + ioc_fm_pcd_cc_stats_mode statistics_mode; +#if (DPAA_VERSION >= 11) + uint16_t frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; +#endif /* (DPAA_VERSION >= 11) */ + uint16_t num_of_keys; + uint8_t key_size; + ioc_compat_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; /**< compat structure*/ + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; /**< compat structure*/ +} ioc_compat_keys_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_params_t { + ioc_fm_pcd_extract_entry_t extract_cc_params; /**< same structure*/ + ioc_compat_keys_params_t keys_params; /**< compat structure*/ + compat_uptr_t id; +} ioc_compat_fm_pcd_cc_node_params_t; + +/**************************************************************************//** + @Description Parameters for defining a hash table +*//***************************************************************************/ +typedef struct ioc_compat_fm_pcd_hash_table_params_t { + uint16_t max_num_of_keys; + ioc_fm_pcd_cc_stats_mode statistics_mode; + uint16_t hash_res_mask; + uint8_t hash_shift; + uint8_t match_key_size; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; + compat_uptr_t id; +} ioc_compat_fm_pcd_hash_table_params_t; + +typedef struct ioc_compat_fm_pcd_hash_table_add_key_params_t { + compat_uptr_t p_hash_tbl; + uint8_t key_size; + ioc_compat_fm_pcd_cc_key_params_t key_params; +} ioc_compat_fm_pcd_hash_table_add_key_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_key_params_t { + compat_uptr_t id; + uint16_t key_indx; + uint8_t key_size; + compat_uptr_t p_key; + compat_uptr_t p_mask; +} ioc_compat_fm_pcd_cc_node_modify_key_params_t; + +typedef struct ioc_compat_fm_pcd_hash_table_remove_key_params_t { + compat_uptr_t p_hash_tbl; + uint8_t key_size; + compat_uptr_t p_key; +} ioc_compat_fm_pcd_hash_table_remove_key_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t { + compat_uptr_t id; + uint16_t key_indx; + uint8_t key_size; + ioc_compat_fm_pcd_cc_key_params_t key_params; +} ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t; + +typedef struct ioc_compat_fm_port_pcd_plcr_params_t { + compat_uptr_t plcr_profile_id; +} ioc_compat_fm_port_pcd_plcr_params_t; + +typedef struct ioc_compat_fm_port_pcd_cc_params_t { + compat_uptr_t cc_tree_id; +} ioc_compat_fm_port_pcd_cc_params_t; + +typedef struct ioc_compat_fm_port_pcd_kg_params_t { + uint8_t num_of_schemes; + compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; + bool direct_scheme; + compat_uptr_t direct_scheme_id; +} ioc_compat_fm_port_pcd_kg_params_t; + +typedef struct ioc_compat_fm_port_pcd_params_t { + ioc_fm_port_pcd_support pcd_support; + compat_uptr_t net_env_id; + compat_uptr_t p_prs_params; + compat_uptr_t p_cc_params; + compat_uptr_t p_kg_params; + compat_uptr_t p_plcr_params; + compat_uptr_t p_ip_reassembly_manip; +} ioc_compat_fm_port_pcd_params_t; + +typedef struct ioc_compat_fm_pcd_kg_cc_t { + compat_uptr_t tree_id; + uint8_t grp_id; + bool plcr_next; + bool bypass_plcr_profile_generation; + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; +} ioc_compat_fm_pcd_kg_cc_t; + +typedef struct ioc_compat_fm_pcd_kg_scheme_params_t { + bool modify; + union { + uint8_t relative_scheme_id; + compat_uptr_t scheme_id; + } scm_id; + bool always_direct; + struct { + compat_uptr_t net_env_id; + uint8_t num_of_distinction_units; + uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + } net_env_params; + bool use_hash; + ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params; + bool bypass_fqid_generation; + uint32_t base_fqid; + uint8_t num_of_used_extracted_ors; + ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS]; +#if DPAA_VERSION >= 11 + bool override_storage_profile; + ioc_fm_pcd_kg_storage_profile_t storage_profile; +#endif /* DPAA_VERSION >= 11 */ + ioc_fm_pcd_engine next_engine; + union{ + ioc_fm_pcd_done_action done_action; + ioc_fm_pcd_kg_plcr_profile_t plcr_profile; + ioc_compat_fm_pcd_kg_cc_t cc; + } kg_next_engine_params; + ioc_fm_pcd_kg_scheme_counter_t scheme_counter; + compat_uptr_t id; +} ioc_compat_fm_pcd_kg_scheme_params_t; + +typedef struct ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t { + compat_uptr_t id; + uint16_t key_indx; + uint8_t key_size; + ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; +} ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t; + +typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t { + uint8_t offset; + uint8_t size; + bool replace; + compat_uptr_t p_data; +} ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t; + +typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t { + ioc_fm_pcd_manip_hdr_insrt_specific_l2 specific_l2; + bool update; + uint8_t size; + compat_uptr_t p_data; +} ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t; + +typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t { + ioc_fm_pcd_manip_hdr_insrt_by_hdr_type type; + union { + ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t specific_l2_params; + } u; +} ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t; + +typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_params_t { + ioc_fm_pcd_manip_hdr_insrt_type type; + union { + ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t by_hdr; + ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t generic; +#ifdef FM_CAPWAP_SUPPORT +#error CAPWAP not supported! + ioc_fm_pcd_manip_hdr_insrt_by_template_params_t by_template; +#endif /* FM_CAPWAP_SUPPORT */ + } u; +} ioc_compat_fm_pcd_manip_hdr_insrt_params_t; + +typedef struct ioc_compat_fm_pcd_manip_hdr_params_t { + bool rmv; + ioc_fm_pcd_manip_hdr_rmv_params_t rmv_params; + bool insrt; + ioc_compat_fm_pcd_manip_hdr_insrt_params_t insrt_params; + bool field_update; + ioc_fm_pcd_manip_hdr_field_update_params_t field_update_params; + bool custom; + ioc_fm_pcd_manip_hdr_custom_params_t custom_params; + bool dont_parse_after_manip; +} ioc_compat_fm_pcd_manip_hdr_params_t; + +typedef struct ioc_compat_fm_pcd_manip_params_t { + ioc_fm_pcd_manip_type type; + union { + ioc_compat_fm_pcd_manip_hdr_params_t hdr; + ioc_fm_pcd_manip_reassem_params_t reassem; + ioc_fm_pcd_manip_frag_params_t frag; + ioc_fm_pcd_manip_special_offload_params_t special_offload; + } u; + compat_uptr_t p_next_manip; +#ifdef FM_CAPWAP_SUPPORT +#error "FM_CAPWAP_SUPPORT feature not supported!" + bool frag_or_reasm; + ioc_fm_pcd_manip_frag_or_reasm_params_t frag_or_reasm_params; +#endif /* FM_CAPWAP_SUPPORT */ + compat_uptr_t id; +} ioc_compat_fm_pcd_manip_params_t; + +#if (DPAA_VERSION >= 11) +typedef struct ioc_compat_fm_pcd_frm_replic_group_params_t { + uint8_t max_num_of_entries; + uint8_t num_of_entries; + ioc_compat_fm_pcd_cc_next_engine_params_t + next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES]; + compat_uptr_t id; +} ioc_compat_fm_pcd_frm_replic_group_params_t; + +typedef struct ioc_compat_fm_pcd_frm_replic_member_t { + compat_uptr_t h_replic_group; + uint16_t member_index; +} ioc_compat_fm_pcd_frm_replic_member_t; + +typedef struct ioc_compat_fm_pcd_frm_replic_member_params_t { + ioc_compat_fm_pcd_frm_replic_member_t member; + ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_params; +} ioc_compat_fm_pcd_frm_replic_member_params_t; + +typedef struct ioc_compat_fm_vsp_params_t { + compat_uptr_t p_fm; /**< A handle to the FM object this VSP related to */ + ioc_fm_ext_pools ext_buf_pools; /**< Which external buffer pools are used + (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. + parameter associated with Rx / OP port */ + uint16_t liodn_offset; /**< VSP's LIODN offset */ + struct { + ioc_fm_port_type port_type; /**< Port type */ + uint8_t port_id; /**< Port Id - relative to type */ + } portParams; + uint8_t relative_profile_id; /**< VSP Id - relative to VSP's range + defined in relevant FM object */ + compat_uptr_t id; /**< return value */ +} ioc_compat_fm_vsp_params_t; + +typedef struct ioc_compat_fm_buf_pool_depletion_params_t { + compat_uptr_t p_fm_vsp; + ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion; +} ioc_compat_fm_buf_pool_depletion_params_t; + +typedef struct ioc_compat_fm_buffer_prefix_content_params_t { + compat_uptr_t p_fm_vsp; + ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content; +} ioc_compat_fm_buffer_prefix_content_params_t; + +typedef struct ioc_compat_fm_vsp_config_no_sg_params_t { + compat_uptr_t p_fm_vsp; + bool no_sg; +} ioc_compat_fm_vsp_config_no_sg_params_t; + +typedef struct ioc_compat_fm_vsp_prs_result_params_t { + compat_uptr_t p_fm_vsp; + compat_uptr_t p_data; +} ioc_compat_fm_vsp_prs_result_params_t; +#endif /* (DPAA_VERSION >= 11) */ + +typedef struct ioc_compat_fm_ctrl_mon_counters_params_t { + uint8_t fm_ctrl_index; + compat_uptr_t p_mon; +} ioc_compat_fm_ctrl_mon_counters_params_t; + +/* } pcd compat structures */ + +void compat_obj_delete( + ioc_compat_fm_obj_t *compat_id, + ioc_fm_obj_t *id); + +/* pcd compat functions { */ +void compat_copy_fm_pcd_plcr_profile( + ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, + ioc_fm_pcd_plcr_profile_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_key( + ioc_compat_fm_pcd_cc_key_params_t *compat_param, + ioc_fm_pcd_cc_key_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( + ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_next_engine( + ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, + uint8_t compat); + +void compat_fm_pcd_cc_tree_modify_next_engine( + ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, + ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_hash_table( + ioc_compat_fm_pcd_hash_table_params_t *compat_param, + ioc_fm_pcd_hash_table_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_grp( + ioc_compat_fm_pcd_cc_grp_params_t *compat_param, + ioc_fm_pcd_cc_grp_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_tree( + ioc_compat_fm_pcd_cc_tree_params_t *compat_param, + ioc_fm_pcd_cc_tree_params_t *param, + uint8_t compat); + +void compat_fm_pcd_prs_sw( + ioc_compat_fm_pcd_prs_sw_params_t *compat_param, + ioc_fm_pcd_prs_sw_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_scheme( + ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, + ioc_fm_pcd_kg_scheme_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_scheme_select( + ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, + ioc_fm_pcd_kg_scheme_select_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_kg_schemes_params( + ioc_compat_fm_pcd_port_schemes_params_t *compat_param, + ioc_fm_pcd_port_schemes_params_t *param, + uint8_t compat); + +void compat_copy_fm_port_pcd_kg( + ioc_compat_fm_port_pcd_kg_params_t *compat_param, + ioc_fm_port_pcd_kg_params_t *param, + uint8_t compat); + +void compat_copy_fm_port_pcd( + ioc_compat_fm_port_pcd_params_t *compat_param, + ioc_fm_port_pcd_params_t *param, + uint8_t compat); + +#if (DPAA_VERSION >= 11) +void compat_copy_fm_port_vsp_alloc_params( + ioc_compat_fm_port_vsp_alloc_params_t *compat_param, + ioc_fm_port_vsp_alloc_params_t *param, + uint8_t compat); +#endif /* (DPAA_VERSION >= 11) */ + +void compat_copy_fm_pcd_net_env( + ioc_compat_fm_pcd_net_env_params_t *compat_param, + ioc_fm_pcd_net_env_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node_modify_key( + ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, + ioc_fm_pcd_cc_node_modify_key_params_t *param, + uint8_t compat); + +void compat_copy_keys( + ioc_compat_keys_params_t *compat_param, + ioc_keys_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_cc_node( + ioc_compat_fm_pcd_cc_node_params_t *compat_param, + ioc_fm_pcd_cc_node_params_t *param, + uint8_t compat); + +void compat_fm_pcd_manip_set_node( + ioc_compat_fm_pcd_manip_params_t *compat_param, + ioc_fm_pcd_manip_params_t *param, + uint8_t compat); + +void compat_copy_fm_port_pcd_modify_tree( + ioc_compat_fm_obj_t *compat_id, + ioc_fm_obj_t *id, + uint8_t compat); + +#if (DPAA_VERSION >= 11) +void compat_copy_fm_pcd_frm_replic_group_params( + ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param, + ioc_fm_pcd_frm_replic_group_params_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_frm_replic_member( + ioc_compat_fm_pcd_frm_replic_member_t *compat_param, + ioc_fm_pcd_frm_replic_member_t *param, + uint8_t compat); + +void compat_copy_fm_pcd_frm_replic_member_params( + ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param, + ioc_fm_pcd_frm_replic_member_params_t *param, + uint8_t compat); + +void compat_copy_fm_vsp_params( + ioc_compat_fm_vsp_params_t *compat_param, + ioc_fm_vsp_params_t *param, + uint8_t compat); + +void compat_copy_fm_buf_pool_depletion_params( + ioc_compat_fm_buf_pool_depletion_params_t *compat_param, + ioc_fm_buf_pool_depletion_params_t *param, + uint8_t compat); + +void compat_copy_fm_buffer_prefix_content_params( + ioc_compat_fm_buffer_prefix_content_params_t *compat_param, + ioc_fm_buffer_prefix_content_params_t *param, + uint8_t compat); + +void compat_copy_fm_vsp_config_no_sg_params( + ioc_compat_fm_vsp_config_no_sg_params_t *compat_param, + ioc_fm_vsp_config_no_sg_params_t *param, + uint8_t compat); + +void compat_copy_fm_vsp_prs_result_params( + ioc_compat_fm_vsp_prs_result_params_t *compat_param, + ioc_fm_vsp_prs_result_params_t *param, + uint8_t compat); +#endif /* (DPAA_VERSION >= 11) */ +/* } pcd compat functions */ +#endif diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.c new file mode 100644 index 0000000..2686aa2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.c @@ -0,0 +1,1196 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_resources.c + + @Description FMD wrapper resource allocation functions. + +*/ +#if !defined(FMAN_RESOURCES_UNIT_TEST) + +#include <linux/version.h> +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/skbuff.h> + +#endif /*#if !defined(FMAN_RESOURCES_UNIT_TEST)*/ + +#include "lnxwrp_resources.h" + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +static struct device_node *match_mac_to_dpaa_port(struct device_node + *enet_mac_node) +{ + struct device_node *dpaa_node = NULL; + struct device_node *dpaa_itf = NULL; + + /* find DPAA node starting from root */ + dpaa_node = of_find_compatible_node(NULL, NULL, "fsl,dpaa"); + if (dpaa_node) { + /* for all dpaa ports check which one refers this mac node. */ + for_each_child_of_node(dpaa_node, dpaa_itf) { + struct device_node *by_handle_enet_mac_node = NULL; + const phandle *phandle_prop = NULL; + int lenp = 0; + + phandle_prop = + (typeof(phandle_prop)) + of_get_property(dpaa_itf, "fsl,fman-mac", + &lenp); + if (phandle_prop == NULL) + continue; + + if (WARN_ON(lenp != sizeof(phandle))) + return NULL; + + by_handle_enet_mac_node = + of_find_node_by_phandle(*phandle_prop); + if (unlikely(by_handle_enet_mac_node == NULL)) + return NULL; + + /* check */ + if (by_handle_enet_mac_node == enet_mac_node) { + of_node_put(by_handle_enet_mac_node); + return dpaa_itf; + } + + of_node_put(by_handle_enet_mac_node); + } + of_node_put(dpaa_node); + } + + return NULL; +} + +static struct device_node *match_fman_port_to_mac(struct device_node *fm_node, + struct device_node + *fm_port_node) +{ + struct device_node *fm_node_idx = NULL; + + /* for all enet nodes (macs) check which one refers this FMan port. */ + for_each_child_of_node(fm_node, fm_node_idx) { + if (of_device_is_compatible(fm_node_idx, "fsl,fman-1g-mac") || + of_device_is_compatible(fm_node_idx, "fsl,fman-10g-mac") || + of_device_is_compatible(fm_node_idx, "fsl,fman-memac")) { + struct device_node *fman_port_node_rx = NULL; + struct device_node *fman_port_node_tx = NULL; + /* RX is first */ + fman_port_node_rx = of_parse_phandle(fm_node_idx, + "fsl,port-handles", 0); + if (unlikely(fman_port_node_rx == NULL)) + continue; + /* TX is second */ + fman_port_node_tx = of_parse_phandle(fm_node_idx, + "fsl,port-handles", 1); + if (unlikely(fman_port_node_tx == NULL)) { + of_node_put(fman_port_node_rx); + continue; + } + + /* check */ + if (fman_port_node_rx == fm_port_node + || fman_port_node_tx == fm_port_node) { + of_node_put(fman_port_node_rx); + of_node_put(fman_port_node_tx); + return fm_node_idx; + } + + of_node_put(fman_port_node_rx); + of_node_put(fman_port_node_tx); + } + } + + return NULL; +} + +static bool is_fman_port_active(struct device_node *fm_node, + struct device_node *fm_port_node) +{ + struct device_node *enet_mac_node = NULL; + struct device_node *itf_node = NULL; + + /* Which MAC node refers to this FMan port. */ + enet_mac_node = match_fman_port_to_mac(fm_node, fm_port_node); + + if (unlikely(enet_mac_node == NULL)) + return false; + + /* Which dpaa port node refers this MAC node. */ + itf_node = match_mac_to_dpaa_port(enet_mac_node); + of_node_put(enet_mac_node); + + if (unlikely(!itf_node)) + return false; + + /* check if itf (DPAA ports) is available. + * if available, means that the FMan port is + * also available - return true + */ + if (!of_device_is_available(itf_node)) { + of_node_put(itf_node); + return false; + } + of_node_put(itf_node); + + return true; +} + +int fm_set_active_fman_ports(struct platform_device *of_dev, + t_LnxWrpFmDev *p_LnxWrpFmDev) +{ + struct device_node *fm_node = NULL; + struct device_node *fm_port_node = NULL; + + memset(&p_LnxWrpFmDev->fm_active_ports_info, 0, + sizeof(struct fm_active_ports)); + + /* get FMan node */ + fm_node = of_dev->dev.of_node; + + /* for all ports which belong to this FMan, check if they are active. + * If active, set their parameters. */ + for_each_child_of_node(fm_node, fm_port_node) { + + if (!of_device_is_available(fm_port_node)) + continue; + + /* OH FMan ports */ + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-oh")) { + p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports++; + continue; + } + + if (!is_fman_port_active(fm_node, fm_port_node)) + continue; + + /* 10g TX FMan ports */ + if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-tx")) + p_LnxWrpFmDev->fm_active_ports_info.num_tx10_ports++; + + /* 10g RX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-10g-rx")) + p_LnxWrpFmDev->fm_active_ports_info.num_rx10_ports++; + + /* 1G TX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-tx")) + p_LnxWrpFmDev->fm_active_ports_info.num_tx_ports++; + + /* 1G RX FMan ports */ + else if (of_device_is_compatible(fm_port_node, + "fsl,fman-port-1g-rx")) + p_LnxWrpFmDev->fm_active_ports_info.num_rx_ports++; + } + + /* If performance is needed no oh port is probed + * except the one used for host command. */ +#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) + if (p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports) + p_LnxWrpFmDev->fm_active_ports_info.num_oh_ports = 1; + + printk(KERN_WARNING "FMAN(%u)-Performance mode - no OH support...\n", + p_LnxWrpFmDev->id); +#endif + + return 0; +} +#endif /*!defined(FMAN_RESOURCES_UNIT_TEST)*/ + +/* BPOOL size is constant and equal w/ DPA_BP_SIZE */ +static uint32_t get_largest_buf_size(uint32_t max_rx_frame_size, uint32_t buf_size) +{ + uint32_t priv_data_size = 16; /* DPA_PRIV_DATA_SIZE */ + uint32_t hash_results_size = 16; /* DPA_HASH_RESULTS_SIZE */ + uint32_t parse_results_size = + sizeof(t_FmPrsResult); /* DPA_PARSE_RESULTS_SIZE */ + uint32_t bp_head = priv_data_size + hash_results_size + + parse_results_size + + fm_get_rx_extra_headroom(); /* DPA_BP_HEAD */ + uint32_t bp_size = bp_head + max_rx_frame_size + + NET_IP_ALIGN; /* DPA_BP_SIZE */ + +#ifndef CONFIG_DPAA_ETH_SG_SUPPORT + return CEIL_DIV(bp_size, buf_size); +#else + bp_size = CEIL_DIV(bp_size, 16); /* frame split in 16 frags */ + + return max((uint32_t)16, CEIL_DIV(bp_size, buf_size)); +#endif /* CONFIG_DPAA_ETH_SG_SUPPORT */ +} + +/* Calculate the fifosize based on MURAM allocation, number of ports, dpde + value and s/g software support (! Kernel does not suport s/g). + + Algorithm summary: + - Calculate the the minimum fifosize required for every type of port + (TX,RX for 1G, 2.5G and 10G). + - Set TX the minimum fifosize required. + - Distribute the remaining buffers (after all TX were set) to RX ports + based on: + 1G RX = Remaining_buffers * 1/(1+2.5+10) + 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10) + 10G RX = Remaining_buffers * 10/(1+2.5+10) + - if the RX is smaller than the minimum required, then set the minimum + required + - In the end distribuite the leftovers if there are any (due to + unprecise calculus) or if over allocation cat some buffers from all RX + ports w/o pass over minimum required treshold, but if there must be + pass the treshold in order to cat the over allocation ,then this + configuration can not be set - KERN_ALERT. +*/ +int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev, int muram_fifo_size) +{ + + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int oh_buff = 0; + int tx_1g_bufs = 0, rx_1g_bufs = 0; + int tx_2g5_bufs = 0, rx_2g5_bufs = 0; + int tx_10g_bufs = 0, rx_10g_bufs = 0; + int err = 0; + + /* throughput parameters: divide it by 10 when used */ + int gb1g = 10, gb2g5 = 25, gb10g = 100, gb_sum = 0; + + /* buffers parameters */ + int buf_size = 0x100; /* Buffer unit size */ + int total_no_buffers = 0; /* Calculus based on MURAM size for + fifos and buf. unit size */ + + int shared_ext_buff = 0; /* External buffers allocated - LLD + boundaries:DEFAULT_PORT_extraSizeOfFifo */ + + int min_tx_1g_2g5_bufs = 0; /* minimum TX1g buffers required + (see refman.) */ + int min_tx_10g_bufs = 0; /* minimum TX10g buffers required + (see refman.) */ + int min_rx_bufs = 0; /* minimum RX buffers required (see refman.) */ + + /* Buffer sizes calculus */ + int max_frame_size = fm_get_max_frm(); + int remaining_bufs = 0; + int rx_1g_bufs_ceil = 0, rx_2g5_bufs_ceil = 0, rx_10g_bufs_ceil = 0; + int rx_2g5_max_bufs = 0, rx_10g_max_bufs = 0; + int rx_1g_used = 0, rx_1g_2g5_used = 0, rx_1g_10g_used =0, + rx_2g5_used = 0, rx_2g5_10g_used = 0, rx_1g_2g5_10g_used = 0; + + /* overflow checking */ + int tot_rx_buffs, tot_tx_buffs, tot_oh_buffs, tot_used_buffs, + leftovers = 0; + int overflow = 0; + bool loop = false; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + ASSERT_COND(max_frame_size != 0); + ASSERT_COND(muram_fifo_size != 0); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* throughput calculus */ + gb_sum = gb1g * num_1g_ports + gb2g5 * num_2g5_ports + + gb10g * num_10g_ports; /* divide it by 10 */ + + /* Base buffer calculus */ + oh_buff = 8; + total_no_buffers = muram_fifo_size / buf_size; + + min_tx_1g_2g5_bufs = CEIL_DIV(max_frame_size, buf_size) + + DPDE_1G + 3 + 1; /* +1 to handle Jumbo Frames */ + min_tx_10g_bufs = CEIL_DIV(max_frame_size, buf_size) + + DPDE_10G + 3 + 1; /* +1 to handle Jumbo Frames */ + + { +/* + * On P1023RDS FM_FIFO_ALLOCATION_ALG is enabled allowing a smaller Rx FIFO + * on hardware major rev 4. If the Rx FIFO is smaller than the size of the + * buffer in the buffer pool SG frames will be received + */ +#if defined(FM_FIFO_ALLOCATION_ALG) && \ + !defined(FMAN_RESOURCES_UNIT_TEST) && \ + defined(CONFIG_DPAA_ETH_SG_SUPPORT) + uint8_t fm_rev_major = 0; + fm_rev_major = (uint8_t) ((* + ((volatile uint32_t *) + UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr + + 0x000c30c4)) & 0xff00) >> 8); + + if (fm_rev_major == 4) + min_rx_bufs = 8; + else +#endif + min_rx_bufs = get_largest_buf_size(max_frame_size, + buf_size) + 7; + } + +#ifdef CONFIG_FMAN_P1023 + shared_ext_buff = 0; +#else + /* changing these might reduce performance */ + shared_ext_buff = num_10g_ports ? 32 : 16; /* LLD boundaries: + DEFAULT_PORT_extraNumOfFifoBufs */ +#endif + + /* TX ports will have minimum required buffers + Calculus of the remaining buffers for all RX ports */ + tx_1g_bufs = num_1g_ports ? min_tx_1g_2g5_bufs : 0; + tx_2g5_bufs = num_2g5_ports ? min_tx_1g_2g5_bufs : 0; + tx_10g_bufs = num_10g_ports ? min_tx_10g_bufs : 0; + + remaining_bufs = total_no_buffers - + oh_buff * num_oh_ports - + num_1g_ports * min_tx_1g_2g5_bufs - + num_2g5_ports * min_tx_1g_2g5_bufs - + num_10g_ports * min_tx_10g_bufs - shared_ext_buff; + + if (remaining_bufs < 0) { + printk(KERN_ALERT + "\nThis configuration will not work due to low number of" + " buffers (%u buffers)...\n", + total_no_buffers); + err = -1; + goto precalculated_fifosize_out; + } + + /* Per port buffer size calculus + . for TX ports give always minimum required + . for RX ports give whatever left scaled per port type */ + /* ------------------------------------------------------- */ + if (num_1g_ports) { + rx_1g_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb1g) / 10), + (gb_sum / 10)) : 0; + rx_1g_bufs = MAX(min_rx_bufs, rx_1g_bufs_ceil); + rx_1g_used = rx_1g_bufs - rx_1g_bufs_ceil; /* always >= 0 */ + /* distribute to 2.5g and 10g ports */ + rx_1g_2g5_used = + (num_2g5_ports + + num_10g_ports) ? CEIL_DIV(rx_1g_used * num_1g_ports * + num_2g5_ports, + num_2g5_ports + + num_10g_ports) : 0; + rx_1g_10g_used = + (num_2g5_ports + + num_10g_ports) ? CEIL_DIV(rx_1g_used * num_1g_ports * + num_10g_ports, + num_2g5_ports + + num_10g_ports) : 0; + } + + if (num_2g5_ports) { + rx_2g5_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb2g5) / 10), + (gb_sum / 10)) : 0; + rx_2g5_max_bufs = MAX(min_rx_bufs, rx_2g5_bufs_ceil); + rx_2g5_bufs = + MAX(min_rx_bufs, rx_2g5_max_bufs - rx_1g_2g5_used); + rx_2g5_used = rx_2g5_bufs - rx_2g5_bufs_ceil; /* always >= 0 */ + /* distribute to 10g ports */ + rx_2g5_10g_used = + num_10g_ports ? CEIL_DIV(rx_2g5_used * num_2g5_ports, + num_10g_ports) : 0; + } + + if (num_10g_ports) { + rx_10g_bufs_ceil = + (gb_sum / + 10) ? CEIL_DIV(((remaining_bufs * gb10g) / 10), + (gb_sum / 10)) : 0; + rx_10g_max_bufs = MAX(min_rx_bufs, rx_10g_bufs_ceil); + /* keep count of all distribution */ + rx_1g_2g5_10g_used = rx_1g_10g_used + rx_2g5_10g_used; + rx_10g_bufs = + MAX(min_rx_bufs, + rx_10g_max_bufs - rx_1g_2g5_10g_used); + } + + /* overflow-leftover calculus */ + tot_rx_buffs = rx_1g_bufs * num_1g_ports + + rx_2g5_bufs * num_2g5_ports + rx_10g_bufs * num_10g_ports; + tot_tx_buffs = tx_1g_bufs * num_1g_ports + + tx_2g5_bufs * num_2g5_ports + tx_10g_bufs * num_10g_ports; + tot_oh_buffs = oh_buff * num_oh_ports; + tot_used_buffs = + tot_oh_buffs + tot_tx_buffs + tot_rx_buffs + shared_ext_buff; + + overflow = tot_used_buffs - total_no_buffers; + /* used more than available */ + if (overflow > 0) { + loop = true; + while (overflow > 0 && loop) { + loop = false; + if (overflow && num_10g_ports + && rx_10g_bufs > min_rx_bufs) { + rx_10g_bufs--; + overflow -= num_10g_ports; + loop = true; + } + if (overflow && num_2g5_ports + && rx_2g5_bufs > min_rx_bufs) { + rx_2g5_bufs--; + overflow -= num_2g5_ports; + loop = true; + } + if (overflow && num_1g_ports + && rx_1g_bufs > min_rx_bufs) { + rx_1g_bufs--; + overflow -= num_1g_ports; + loop = true; + } + } + + if (overflow > 0) { + printk(KERN_ALERT + "This configuration will not work due to over" + " buffer allocation (%d buffers)...\n", + overflow); + err = -1; + goto precalculated_fifosize_out; + } + } + /* left a few buffers */ + else if (overflow < 0) { + leftovers = total_no_buffers - tot_used_buffs; + loop = true; + while (leftovers > 0 && loop) { + loop = false; + if (leftovers && num_1g_ports) { + rx_1g_bufs++; + leftovers -= num_1g_ports; + loop = true; + } + + if (leftovers && num_2g5_ports) { + rx_2g5_bufs++; + leftovers -= num_2g5_ports; + loop = true; + } + + if (leftovers && num_10g_ports) { + rx_10g_bufs++; + leftovers -= num_10g_ports; + loop = true; + } + } + } + + /* set fifosizes for this FMan ports */ + fm_resource_settings_info->tx1g_num_buffers = tx_1g_bufs; + fm_resource_settings_info->rx1g_num_buffers = rx_1g_bufs; + fm_resource_settings_info->tx2g5_num_buffers = tx_2g5_bufs; + fm_resource_settings_info->rx2g5_num_buffers = rx_2g5_bufs; + fm_resource_settings_info->tx10g_num_buffers = tx_10g_bufs; + fm_resource_settings_info->rx10g_num_buffers = rx_10g_bufs; + fm_resource_settings_info->oh_num_buffers = oh_buff; + fm_resource_settings_info->shared_ext_buffers = shared_ext_buff; + +precalculated_fifosize_out: + printk(KERN_INFO " FMAN(%u) Fifo size settings:\n", + p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total buffers available(%u - 256B/buffer)\n", + total_no_buffers); + printk(KERN_INFO " - Total throughput(%uGbps)\n", (gb_sum / 10)); + printk(KERN_INFO " - Max frame size(%uB)\n", max_frame_size); + if (num_1g_ports) { + printk(KERN_INFO + " - 1G ports TX %u(%u bufs set (min: %u))\n", + num_1g_ports, tx_1g_bufs, min_tx_1g_2g5_bufs); + printk(KERN_INFO + " - 1G ports RX %u(%u bufs set (min: %u))\n", + num_1g_ports, rx_1g_bufs, min_rx_bufs); + } + if (num_2g5_ports) { + printk(KERN_INFO + " - 2.5G ports TX %u(%u bufs set (min: %u))\n", + num_2g5_ports, tx_2g5_bufs, min_tx_1g_2g5_bufs); + printk(KERN_INFO + " - 2.5G ports RX %u(%u bufs set (min: %u))\n", + num_2g5_ports, rx_2g5_bufs, min_rx_bufs); + } + if (num_10g_ports) { + printk(KERN_INFO + " - 10G ports TX %u(%u bufs set (min: %u))\n", + num_10g_ports, tx_10g_bufs, min_tx_10g_bufs); + printk(KERN_INFO + " - 10G ports RX %u(%u bufs set (min: %u))\n", + num_10g_ports, rx_10g_bufs, min_rx_bufs); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_buff); + printk(KERN_INFO " - Shared extra buffers(%u)\n", shared_ext_buff); + + return err; +} + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + struct fm_active_ports *fm_active_ports_info = NULL; + t_FmPortRsrc portRsrc; + t_Error errCode; + uint32_t buf_size = 0x100; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + + memset(&portRsrc, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) { + portRsrc.num = + fm_resource_settings_info->tx1g_num_buffers * buf_size; + portRsrc.extra = 0; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) { + portRsrc.num = + fm_resource_settings_info->rx1g_num_buffers * buf_size; + portRsrc.extra = + fm_resource_settings_info->shared_ext_buffers * + buf_size; + } +/* IF 2.5G PORT */ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) { + portRsrc.num = + fm_resource_settings_info->tx10g_num_buffers * + buf_size; + portRsrc.extra = 0; + } else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) { + portRsrc.num = + fm_resource_settings_info->rx10g_num_buffers * + buf_size; + portRsrc.extra = + fm_resource_settings_info->shared_ext_buffers * + buf_size; + } else { /* IF OH PORT */ + portRsrc.num = + fm_resource_settings_info->oh_num_buffers * buf_size; + portRsrc.extra = 0; + } + + errCode = FM_PORT_ConfigSizeOfFifo(p_LnxWrpFmPortDev->h_Dev, &portRsrc); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetSizeOfFifo failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} +#endif /*if !defined(FMAN_RESOURCES_UNIT_TEST)*/ + +/* Compute FMan open DMA based on total number of open DMAs and + * number of available FMan ports. + * + * By default 10g ports are set to input parameters. The other ports + * tries to keep the proportion rx=2tx open DMAs or thresholds. + * + * If leftovers, then those will be set as shared. + * + * If after computing overflow appears, then it decrements open DMA + * for all ports w/o cross the thresholds. If the thresholds are meet + * and is still overflow, then it returns error. + */ +int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev, + int max_fm_open_dma, + int default_tx_10g_dmas, + int default_rx_10g_dmas, + int min_tx_10g_treshold, int min_rx_10g_treshold) +{ + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int tx_1g_dmas = 0, rx_1g_dmas = 0; + int tx_2g5_dmas = 0, rx_2g5_dmas = 0; + int tx_10g_dmas = 0, rx_10g_dmas = 0; + int oh_dmas = 0; + int shared_ext_open_dma = 0; + int err = 0; + + /* open dma calculus */ + int remaing_dmas = 0; + int rx_tx_raport = + FM_OPENDMA_RX_TX_RAPORT; /* RX = FM_OPENDMA_RX_TX_RAPORT *TX */ + int min_tx_1_2g5_treshold = 1; + int min_rx_1_2g5_treshold = 1; + int max_open_dma_treshold = 16; /* LLD: MAX_NUM_OF_DMAS */ + int max_ext_open_dma_treshold = 8; /* LLD: MAX_NUM_OF_EXTRA_DMAS */ + + int open_dmas_computed = 0; + int weighted_remaining_ports = 0; + int overflow = 0; + bool re_loop = false; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + ASSERT_COND(min_tx_10g_treshold <= max_open_dma_treshold); + ASSERT_COND(min_tx_10g_treshold <= max_open_dma_treshold); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* compute open DMAs per port */ + /* ------------------------------------------------------- */ + if (num_10g_ports) { + tx_10g_dmas = default_tx_10g_dmas; /* per 10G TX port */ + rx_10g_dmas = default_rx_10g_dmas; /* per 10G RX port */ + } + if (num_oh_ports) + oh_dmas = 1; /* per OH port */ + + /* should this be null? or LLD: + DEFAULT_PORT_extraNumOfOpenDmas:10g-8,else 1 */ + shared_ext_open_dma = 0; + + /* based on total number of ports set open DMAs for all other ports */ + remaing_dmas = max_fm_open_dma - + (oh_dmas * num_oh_ports) - + (tx_10g_dmas * num_10g_ports + rx_10g_dmas * num_10g_ports) - + shared_ext_open_dma; + + if (remaing_dmas < 0) { + printk(KERN_ALERT + "This configuration will not work due to low number" + " of open dmas (%u open dmas)...\n", + max_fm_open_dma); + err = -1; + goto precalculated_open_dma_out; + } + + weighted_remaining_ports = + /*tx */ num_1g_ports * rx_tx_raport + /*rx */ num_1g_ports + + /*tx */ num_2g5_ports * rx_tx_raport + /*rx */ num_2g5_ports; + + /* compute the other ports */ + if (num_1g_ports) { + tx_1g_dmas = + MAX(MIN + (ROUND_DIV + (remaing_dmas, weighted_remaining_ports), + max_open_dma_treshold), min_tx_1_2g5_treshold); + rx_1g_dmas = + MAX(MIN + (ROUND_DIV + ((remaing_dmas * rx_tx_raport), + weighted_remaining_ports), + max_open_dma_treshold), min_rx_1_2g5_treshold); + } + if (num_2g5_ports) { + tx_2g5_dmas = + MAX(MIN + (CEIL_DIV(remaing_dmas, weighted_remaining_ports), + max_open_dma_treshold), min_tx_1_2g5_treshold); + rx_2g5_dmas = + MAX(MIN + (CEIL_DIV + ((remaing_dmas * rx_tx_raport), + weighted_remaining_ports), + max_open_dma_treshold), min_rx_1_2g5_treshold); + + } + + /* Check if these settings is not exceding treshold */ + open_dmas_computed = num_1g_ports * tx_1g_dmas + + num_1g_ports * rx_1g_dmas + + num_2g5_ports * tx_2g5_dmas + + num_2g5_ports * rx_2g5_dmas + + num_10g_ports * tx_10g_dmas + + num_10g_ports * rx_10g_dmas + + num_oh_ports * oh_dmas + shared_ext_open_dma; + + /* overflow-leftover calculus */ + overflow = open_dmas_computed - max_fm_open_dma; + re_loop = true; + while (overflow > 0 && re_loop == true) { + re_loop = false; + if (num_1g_ports && overflow + && rx_1g_dmas > min_rx_1_2g5_treshold) { + rx_1g_dmas--; + overflow -= num_1g_ports; + re_loop = true; + } + if (num_2g5_ports && overflow + && rx_2g5_dmas > min_rx_1_2g5_treshold) { + rx_2g5_dmas--; + overflow -= num_2g5_ports; + re_loop = true; + } + if (num_10g_ports && overflow + && rx_10g_dmas > min_rx_10g_treshold) { + rx_10g_dmas--; + overflow -= num_10g_ports; + re_loop = true; + } + + if (num_1g_ports && overflow + && tx_1g_dmas > min_tx_1_2g5_treshold) { + tx_1g_dmas--; + overflow -= num_1g_ports; + re_loop = true; + } + if (num_2g5_ports && overflow + && tx_2g5_dmas > min_tx_1_2g5_treshold) { + tx_2g5_dmas--; + overflow -= num_2g5_ports; + re_loop = true; + } + if (num_10g_ports && overflow + && tx_10g_dmas > min_tx_10g_treshold) { + tx_10g_dmas--; + overflow -= num_10g_ports; + re_loop = true; + } + } + + if (overflow > 0) { + printk(KERN_ALERT + "This configuration will not work due to over open dma" + " allocation (%d open dmas)...\n", + overflow); + err = -1; + goto precalculated_open_dma_out; + } + + /* could remain leftovers... e.g. overflow=1, + 2ports => leftover=1 => shared=1 */ + open_dmas_computed = num_1g_ports * tx_1g_dmas + + num_1g_ports * rx_1g_dmas + + num_2g5_ports * tx_2g5_dmas + + num_2g5_ports * rx_2g5_dmas + + num_10g_ports * tx_10g_dmas + + num_10g_ports * rx_10g_dmas + + num_oh_ports * oh_dmas + shared_ext_open_dma; + + if (max_fm_open_dma - open_dmas_computed > 0) + shared_ext_open_dma = + MIN(shared_ext_open_dma + max_fm_open_dma - + open_dmas_computed, max_ext_open_dma_treshold); + + /* set open dmas */ + fm_resource_settings_info->tx_1g_dmas = tx_1g_dmas; + fm_resource_settings_info->rx_1g_dmas = rx_1g_dmas; + fm_resource_settings_info->tx_2g5_dmas = tx_2g5_dmas; + fm_resource_settings_info->rx_2g5_dmas = rx_2g5_dmas; + fm_resource_settings_info->tx_10g_dmas = tx_10g_dmas; + fm_resource_settings_info->rx_10g_dmas = rx_10g_dmas; + fm_resource_settings_info->oh_dmas = oh_dmas; + fm_resource_settings_info->shared_ext_open_dma = shared_ext_open_dma; + +precalculated_open_dma_out: + printk(KERN_INFO " FMAN(%u) open dma settings:\n", + p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total open dma available(%u)\n", + max_fm_open_dma); + if (num_1g_ports) { + printk(KERN_INFO " - 1G ports TX %u(%u)\n", num_1g_ports, + tx_1g_dmas); + printk(KERN_INFO " - 1G ports RX %u(%u)\n", num_1g_ports, + rx_1g_dmas); + } + if (num_2g5_ports) { + printk(KERN_INFO " - 2.5G ports TX %u(%u)\n", num_2g5_ports, + tx_2g5_dmas); + printk(KERN_INFO " - 2.5G ports RX %u(%u)\n", num_2g5_ports, + tx_2g5_dmas); + } + if (num_10g_ports) { + printk(KERN_INFO " - 10G ports TX %u(%u)\n", num_10g_ports, + tx_10g_dmas); + printk(KERN_INFO " - 10G ports RX %u(%u)\n", num_10g_ports, + rx_10g_dmas); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_dmas); + printk(KERN_INFO " - Shared extra open dma(%u)\n", + shared_ext_open_dma ? shared_ext_open_dma : 0); + + return err; +} + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + t_FmPortRsrc numOfOpenDmas; + t_Error errCode; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + + memset(&numOfOpenDmas, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) + numOfOpenDmas.num = fm_resource_settings_info->tx_1g_dmas; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) + numOfOpenDmas.num = fm_resource_settings_info->rx_1g_dmas; +/* IF 2.5G PORT*/ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + numOfOpenDmas.num = fm_resource_settings_info->tx_10g_dmas; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) + numOfOpenDmas.num = fm_resource_settings_info->rx_10g_dmas; +/* IF OH PORT */ + else + numOfOpenDmas.num = fm_resource_settings_info->oh_dmas; + + numOfOpenDmas.extra = fm_resource_settings_info->shared_ext_open_dma; + + errCode = FM_PORT_ConfigNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev, + &numOfOpenDmas); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetNumOfOpenDmas failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} +#endif /*if !defined(FMAN_RESOURCES_UNIT_TEST)*/ + +/* Compute FMan tnums based on available tnums and number of ports. + Set defaults (minim tresholds) and then distribute leftovers.*/ +int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums) +{ + /* input parameters */ + struct fm_active_ports *fm_active_ports_info = NULL; + int num_1g_ports = 0; + int num_2g5_ports = 0; + int num_10g_ports = 0; + int num_oh_ports = 0; + + /* output parameters */ + struct fm_resource_settings *fm_resource_settings_info = NULL; + int tx_1g_tnums = 0, rx_1g_tnums = 0; + int tx_2g5_tnums = 0, rx_2g5_tnums = 0; + int tx_10g_tnums = 0, rx_10g_tnums = 0; + int oh_tnums = 0; + int shared_ext_tnums = 0; + int err = 0; + + /* open dma calculus */ + int default_and_treshold_rx_tx_10g_tnums = 16; /* DPDE_10g */ + int default_and_treshold_rx_tx_1g_2g5_tnums = 4; /* DPDE_1g */ + int default_and_treshold_oh_tnums = 2; /* Hell knows why */ + int max_tnums_treshold = 64; /* LLD: MAX_NUM_OF_TASKS */ + int max_ext_tnums_treshold = 8; /* LLD: MAX_NUM_OF_EXTRA_TASKS */ + int remaing_tnums = 0; + int tnums_computed = 0; + int leftovers = 0; + bool re_loop = true; + + /* check input parameters correctness */ + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + ASSERT_COND(fm_active_ports_info != NULL); + ASSERT_COND(fm_resource_settings_info != NULL); + ASSERT_COND(fm_active_ports_info->num_tx_ports == + fm_active_ports_info->num_rx_ports); + ASSERT_COND(fm_active_ports_info->num_tx25_ports == + fm_active_ports_info->num_tx25_ports); + ASSERT_COND(fm_active_ports_info->num_tx10_ports == + fm_active_ports_info->num_tx10_ports); + + /* set input parameters */ + num_1g_ports = fm_active_ports_info->num_tx_ports; + num_2g5_ports = fm_active_ports_info->num_tx25_ports; + num_10g_ports = fm_active_ports_info->num_tx10_ports; + num_oh_ports = fm_active_ports_info->num_oh_ports; + + /* compute FMan TNUMs per port */ + /* ------------------------------------------------------- */ + if (num_1g_ports) { + tx_1g_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + rx_1g_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + } + if (num_2g5_ports) { + tx_2g5_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + rx_2g5_tnums = default_and_treshold_rx_tx_1g_2g5_tnums; + } + if (num_10g_ports) { + tx_10g_tnums = default_and_treshold_rx_tx_10g_tnums; + rx_10g_tnums = default_and_treshold_rx_tx_10g_tnums; + } + if (num_oh_ports) + oh_tnums = default_and_treshold_oh_tnums; + + shared_ext_tnums = num_10g_ports ? + max_ext_tnums_treshold : 2; /* DEFAULT_PORT_extraNumOfTasks */ + + /* based on total number of ports set open DMAs for all other ports */ + remaing_tnums = max_fm_tnums - + (oh_tnums * num_oh_ports) - + (tx_1g_tnums * num_1g_ports + rx_1g_tnums * num_1g_ports) - + (tx_2g5_tnums * num_2g5_ports + rx_2g5_tnums * num_2g5_ports) - + (tx_10g_tnums * num_10g_ports + rx_10g_tnums * num_10g_ports) - + shared_ext_tnums; + + if (remaing_tnums < 0) { + printk(KERN_ALERT + "This configuration will not work due to low number" + " of tnums (%u tnums) and number of total ports" + " available...\n", + max_fm_tnums); + err = -1; + goto precalculated_tnums_out; + } + + leftovers = remaing_tnums; + re_loop = true; + while (leftovers > 0 && re_loop == true) { + re_loop = false; + if (num_10g_ports && (leftovers - (int) num_10g_ports) >= 0 + && (rx_10g_tnums < max_tnums_treshold)) { + rx_10g_tnums++; + leftovers -= num_10g_ports; + re_loop = true; + } + + if (num_10g_ports && (leftovers - (int) num_10g_ports) >= 0 + && (tx_10g_tnums < max_tnums_treshold)) { + tx_10g_tnums++; + leftovers -= num_10g_ports; + re_loop = true; + } + + if (num_2g5_ports && (leftovers - (int) num_2g5_ports) >= 0 + && (rx_2g5_tnums < max_tnums_treshold)) { + rx_2g5_tnums++; + leftovers -= num_2g5_ports; + re_loop = true; + } + + if (num_2g5_ports && (leftovers - (int) num_2g5_ports) >= 0 + && (tx_2g5_tnums < max_tnums_treshold)) { + tx_2g5_tnums++; + leftovers -= num_2g5_ports; + re_loop = true; + } + + if (num_1g_ports && (leftovers - (int) num_1g_ports) >= 0 + && (rx_1g_tnums < max_tnums_treshold)) { + rx_1g_tnums++; + leftovers -= num_1g_ports; + re_loop = true; + } + + if (num_1g_ports && (leftovers - (int) num_1g_ports) >= 0 + && (tx_1g_tnums < max_tnums_treshold)) { + tx_1g_tnums++; + leftovers -= num_1g_ports; + re_loop = true; + } + } + + tnums_computed = + num_1g_ports * tx_1g_tnums + + num_1g_ports * rx_1g_tnums + + num_2g5_ports * tx_2g5_tnums + + num_2g5_ports * rx_2g5_tnums + + num_10g_ports * tx_10g_tnums + + num_10g_ports * rx_10g_tnums + + num_oh_ports * oh_tnums + + shared_ext_tnums; + + if (leftovers > 0) + shared_ext_tnums = + MIN(shared_ext_tnums + max_fm_tnums - tnums_computed, + max_ext_tnums_treshold); + + ASSERT_COND((oh_tnums * num_oh_ports) + + (tx_1g_tnums * num_1g_ports + rx_1g_tnums * num_1g_ports) + + (tx_2g5_tnums * num_2g5_ports + + rx_2g5_tnums * num_2g5_ports) + + (tx_10g_tnums * num_10g_ports + + rx_10g_tnums * num_10g_ports) + shared_ext_tnums <= + max_fm_tnums); + + /* set computed tnums */ + fm_resource_settings_info->tx_1g_tnums = tx_1g_tnums; + fm_resource_settings_info->rx_1g_tnums = rx_1g_tnums; + fm_resource_settings_info->tx_2g5_tnums = tx_2g5_tnums; + fm_resource_settings_info->rx_2g5_tnums = rx_2g5_tnums; + fm_resource_settings_info->tx_10g_tnums = tx_10g_tnums; + fm_resource_settings_info->rx_10g_tnums = rx_10g_tnums; + fm_resource_settings_info->oh_tnums = oh_tnums; + fm_resource_settings_info->shared_ext_tnums = shared_ext_tnums; + +precalculated_tnums_out: + printk(KERN_INFO " FMAN(%u) Tnums settings:\n", p_LnxWrpFmDev->id); + printk(KERN_INFO " - Total Tnums available(%u)\n", max_fm_tnums); + if (num_1g_ports) { + printk(KERN_INFO " - 1G ports TX %u(%u)\n", num_1g_ports, + tx_1g_tnums); + printk(KERN_INFO " - 1G ports RX %u(%u)\n", num_1g_ports, + rx_1g_tnums); + } + if (num_2g5_ports) { + printk(KERN_INFO " - 2.5G ports TX %u(%u)\n", num_2g5_ports, + tx_2g5_tnums); + printk(KERN_INFO " - 2.5G ports RX %u(%u)\n", num_2g5_ports, + rx_2g5_tnums); + } + if (num_10g_ports) { + printk(KERN_INFO " - 10G ports TX %u(%u)\n", num_10g_ports, + tx_10g_tnums); + printk(KERN_INFO " - 10G ports RX %u(%u)\n", num_10g_ports, + rx_10g_tnums); + } + if (num_oh_ports) + printk(KERN_INFO " - OH-HC ports %u(%u)\n", num_oh_ports, + oh_tnums); + printk(KERN_INFO " - Shared extra tnums(%u)\n", shared_ext_tnums); + + return err; +} + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = + (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + struct fm_resource_settings *fm_resource_settings_info = NULL; + t_FmPortRsrc numOfTask; + t_Error errCode; + + ASSERT_COND(p_LnxWrpFmDev != NULL); + fm_resource_settings_info = &p_LnxWrpFmDev->fm_resource_settings_info; + + memset(&numOfTask, 0, sizeof(t_FmPortRsrc)); + +/* IF 1G PORT */ + if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) + numOfTask.num = fm_resource_settings_info->tx_1g_tnums; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX) + numOfTask.num = fm_resource_settings_info->rx_1g_tnums; +/* IF 2.5G PORT*/ + /* TODO: Not supported by LLD yet. */ + +/* IF 10G PORT */ + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_TX_10G) + numOfTask.num = fm_resource_settings_info->tx_10g_tnums; + else if (p_LnxWrpFmPortDev->settings.param.portType == + e_FM_PORT_TYPE_RX_10G) + numOfTask.num = fm_resource_settings_info->rx_10g_tnums; +/* IF OH PORT */ + else + numOfTask.num = fm_resource_settings_info->oh_dmas; + + numOfTask.extra = fm_resource_settings_info->shared_ext_tnums; + + errCode = FM_PORT_ConfigNumOfTasks(p_LnxWrpFmPortDev->h_Dev, &numOfTask); + if (errCode != E_OK) { + printk(KERN_WARNING + "FM_PORT_SetNumOfTasks failed (errCode:0x%2x)", + errCode); + return -EIO; + } + + return 0; +} +#endif /*if !defined(FMAN_RESOURCES_UNIT_TEST)*/ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.h new file mode 100644 index 0000000..1b72e1d --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources.h @@ -0,0 +1,121 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_resources.h + + @Description FMD wrapper resource allocation functions. + +*/ + +#ifndef LNXWRP_RESOURCES_H_ +#define LNXWRP_RESOURCES_H_ + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +#include "lnxwrp_fm.h" +#else +#include "lnxwrp_resources_ut.h" +#endif + +#define ROUND(X) ((2*(X)+1)/2) +#define CEIL(X) ((X)+1) +/* #define ROUND_DIV(X, Y) (((X)+(Y)/2)/(Y)) */ +#define ROUND_DIV(X, Y) ((2*(X)+(Y))/(2*(Y))) +#define CEIL_DIV(X, Y) (((X)+(Y)-1)/(Y)) + +/* used for resource calculus */ +#define DPDE_1G 2 /* DQDP 1g - from LLD: + DEFAULT_PORT_txFifoDeqPipelineDepth_1G */ +#define DPDE_10G 8 /* DQDP 10g - from LLD: + DEFAULT_PORT_txFifoDeqPipelineDepth_10G */ + +int fm_set_active_fman_ports(struct platform_device *of_dev, + t_LnxWrpFmDev *p_LnxWrpFmDev); + +/* Calculate the fifosize based on MURAM allocation, number of ports, dpde + * value and s/g software support (! Kernel does not suport s/g). + * + * Algorithm summary: + * - Calculate the the minimum fifosize required for every type of port + * (TX,RX for 1G, 2.5G and 10G). + * - Set TX the minimum fifosize required. + * - Distribute the remaining buffers (after all TX were set) to RX ports + * based on: + * 1G RX = Remaining_buffers * 1/(1+2.5+10) + * 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10) + * 10G RX = Remaining_buffers * 10/(1+2.5+10) + * - if the RX is smaller than the minimum required, then set the minimum + * required + * - In the end distribuite the leftovers if there are any (due to + * unprecise calculus) or if over allocation cat some buffers from all RX + * ports w/o pass over minimum required treshold, but if there must be + * pass the treshold in order to cat the over allocation ,then this + * configuration can not be set - KERN_ALERT. +*/ +int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev, + int muram_fifo_size); + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); +#endif + +/* Compute FMan open DMA based on total number of open DMAs and + * number of available fman ports. + * + * By default 10g ports are set to input parameters. The other ports + * tries to keep the proportion rx=2tx open dmas or tresholds. + * + * If leftovers, then those will be set as shared. + * + * If after computing overflow appears, then it decrements open dma + * for all ports w/o cross the tresholds. If the tresholds are meet + * and is still overflow, then it returns error. +*/ +int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev, + int max_fm_open_dma, + int default_tx_10g_dmas, + int default_rx_10g_dmas, + int min_tx_10g_treshold, int min_rx_10g_treshold); + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); +#endif + +/* Compute FMan tnums based on available tnums and number of ports. + * Set defaults (minim tresholds) and then distribute leftovers.*/ +int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums); + +#if !defined(FMAN_RESOURCES_UNIT_TEST) +int fm_config_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); +#endif + +#endif /* LNXWRP_RESOURCES_H_ */ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.c new file mode 100644 index 0000000..6c06a5a --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.c @@ -0,0 +1,191 @@ +/* Copyright (c) 2012 Freescale Semiconductor, Inc. + * All rights reserved. + * + * 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 "lnxwrp_resources.h" +#include "lnxwrp_resources_ut.h" + +#define KILOBYTE 0x400 /* 1024 */ + +typedef enum e_board_type { + e_p3041, + e_p4080, + e_p5020, + e_p1023 +} e_board_type; + +uint8_t board_type; +uint32_t muram_size = 0; +uint32_t dmas_num = 0; +uint32_t task_num = 0; +uint32_t frame_size = 0; +uint32_t oh_num = 0; +uint32_t num_ports_1g = 0; +uint32_t num_ports_10g = 0; +uint32_t num_ports_2g5 = 0; +uint32_t fsl_fman_phy_maxfrm = 0; +uint32_t dpa_rx_extra_headroom = 0; + +void show_help(void){ + printf(" help: \n"); + printf(" -b <board_type> -f <max_fram_size(mtu)> -o <num_oh_ports> -g1" + " <num_1g_ports> -g10 <num_10g_ports> -g25 <num_2g5_ports>\n"); + printf(" Maxim num of DMAS availbale: P3/P4/P5:32 , P1023:16 \n"); + printf(" Maxim num of TNUMs availbale: P3/P4/P5:128, P1023:32 \n"); + printf(" Muram size: P3/P4/P5:160K, P1023:64K \n"); + printf(" Number of ports:\n"); + printf(" P3/P5: 5p 1g, 1p 10g, 7p oh \n"); + printf(" P4 : 4p 1g, 1p 10g, 7p oh \n"); + printf(" P1 : 2p 1g, 0p 10g, 4p oh \n"); + printf(" MTU: Default:1522, Jumbo:9600 \n"); +} + +int fm_set_param(t_LnxWrpFmDev *p_LnxWrpFmDev) { + struct fm_active_ports *fm_active_ports_info = NULL; + fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; + + switch(board_type){ + case e_p3041: + case e_p5020: + muram_size = 160*KILOBYTE; + dmas_num = 32; + task_num = 128; + if ((num_ports_1g+num_ports_2g5) > 5 || num_ports_10g > 1 || oh_num > 7) + goto err_fm_set_param; + break; + case e_p4080: + muram_size = 160*KILOBYTE; + dmas_num = 32; + task_num = 128; + if ((num_ports_1g+num_ports_2g5) > 4 || num_ports_10g > 1 || oh_num > 7) + goto err_fm_set_param; + break; + case e_p1023: + muram_size = 64*KILOBYTE; + dmas_num = 16; + task_num = 128; + if ((num_ports_1g+num_ports_2g5) > 2 || oh_num > 4) + goto err_fm_set_param; + break; + default: + goto err_fm_set_param; + break; + } + + p_LnxWrpFmDev->id = 0; + fsl_fman_phy_maxfrm = frame_size; + dpa_rx_extra_headroom = 0; /* ATTENTION: can be != 0 */ + fm_active_ports_info->num_oh_ports = oh_num; + fm_active_ports_info->num_tx_ports = num_ports_1g; + fm_active_ports_info->num_rx_ports = num_ports_1g; + fm_active_ports_info->num_tx25_ports = num_ports_2g5; + fm_active_ports_info->num_rx25_ports = num_ports_2g5; + fm_active_ports_info->num_tx10_ports = num_ports_10g; + fm_active_ports_info->num_rx10_ports = num_ports_10g; + + return 0; + +err_fm_set_param: + printf(" ERR: To many ports!!! \n"); + return -1; +} + +int main (int argc, char *argv[]){ + t_LnxWrpFmDev LnxWrpFmDev; + t_LnxWrpFmDev *p_LnxWrpFmDev = &LnxWrpFmDev; + int tokens_cnt = 1; + + char *token = NULL; + + while(tokens_cnt < argc) + { + token = argv[tokens_cnt++]; + if (strcmp(token, "-b") == 0){ + if(strcmp(argv[tokens_cnt],"p3") == 0) + board_type = e_p3041; + else if(strcmp(argv[tokens_cnt],"p4") == 0) + board_type = e_p4080; + else if(strcmp(argv[tokens_cnt],"p5") == 0) + board_type = e_p5020; + else if(strcmp(argv[tokens_cnt],"p1") == 0) + board_type = e_p1023; + else + show_help(); + tokens_cnt++; + } + else if(strcmp(token, "-d") == 0){ + dmas_num = atoi(argv[tokens_cnt++]); + } + else if(strcmp(token, "-t") == 0) + task_num = atoi(argv[tokens_cnt++]); + else if(strcmp(token, "-f") == 0) + frame_size = atoi(argv[tokens_cnt++]); + else if(strcmp(token, "-o") == 0) + oh_num = atoi(argv[tokens_cnt++]); + else if(strcmp(token, "-g1") == 0) + num_ports_1g = atoi(argv[tokens_cnt++]); + else if(strcmp(token, "-g10") == 0) + num_ports_10g = atoi(argv[tokens_cnt++]); + else if(strcmp(token, "-g25") == 0) + num_ports_2g5 = atoi(argv[tokens_cnt++]); + else { + show_help(); + return -1; + } + } + + if(fm_set_param(p_LnxWrpFmDev) < 0){ + show_help(); + return -1; + } + + if(fm_precalculate_fifosizes( + p_LnxWrpFmDev, + 128*KILOBYTE) + != 0) + return -1; + if(fm_precalculate_open_dma( + p_LnxWrpFmDev, + dmas_num, /* max open dmas:dpaa_integration_ext.h */ + FM_DEFAULT_TX10G_OPENDMA, /* default TX 10g open dmas */ + FM_DEFAULT_RX10G_OPENDMA, /* default RX 10g open dmas */ + FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */ + FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */ + != 0) + return -1; + if(fm_precalculate_tnums( + p_LnxWrpFmDev, + task_num) /* max TNUMS: dpa integration file. */ + != 0) + return -1; + + return 0; +} diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.h new file mode 100644 index 0000000..063946e --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.h @@ -0,0 +1,144 @@ +/* Copyright (c) 2012 Freescale Semiconductor, Inc + * All rights reserved. + * + * 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. + */ + +#ifndef FM_RESS_TEST_H_ +#define FM_RESS_TEST_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +#define _Packed +#define _PackedType __attribute__ ((packed)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define KERN_ALERT "" +#define KERN_INFO "" +#define ASSERT_COND assert +#define printk printf +#define NET_IP_ALIGN 0 +#define FM_FIFO_ALLOCATION_OLD_ALG + +#if defined(CONFIG_FMAN_DISABLE_OH_AND_DISTRIBUTE_RESOURCES) +#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */ +#else +#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */ +#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */ +#endif +#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */ +#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */ + +/* information about all active ports for an FMan. + * !Some ports may be disabled by u-boot, thus will not be available */ +struct fm_active_ports { + uint32_t num_oh_ports; + uint32_t num_tx_ports; + uint32_t num_rx_ports; + uint32_t num_tx25_ports; + uint32_t num_rx25_ports; + uint32_t num_tx10_ports; + uint32_t num_rx10_ports; +}; + +/* FMan resources precalculated at fm probe based + * on available FMan port. */ +struct fm_resource_settings { + /* buffers - fifo sizes */ + uint32_t tx1g_num_buffers; + uint32_t rx1g_num_buffers; + uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */ + uint32_t tx10g_num_buffers; + uint32_t rx10g_num_buffers; + uint32_t oh_num_buffers; + uint32_t shared_ext_buffers; + + + /* open DMAs */ + uint32_t tx_1g_dmas; + uint32_t rx_1g_dmas; + uint32_t tx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t rx_2g5_dmas; /* Not supported yet by LLD */ + uint32_t tx_10g_dmas; + uint32_t rx_10g_dmas; + uint32_t oh_dmas; + uint32_t shared_ext_open_dma; + + /* Tnums */ + uint32_t tx_1g_tnums; + uint32_t rx_1g_tnums; + uint32_t tx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t rx_2g5_tnums; /* Not supported yet by LLD */ + uint32_t tx_10g_tnums; + uint32_t rx_10g_tnums; + uint32_t oh_tnums; + uint32_t shared_ext_tnums; +}; + +typedef struct { + uint8_t id; + struct fm_active_ports fm_active_ports_info; + struct fm_resource_settings fm_resource_settings_info; +} t_LnxWrpFmDev; + +typedef struct { + uint8_t id; +} t_LnxWrpFmPortDev; + +typedef _Packed struct t_FmPrsResult { + volatile uint8_t lpid; /**< Logical port id */ + volatile uint8_t shimr; /**< Shim header result */ + volatile uint16_t l2r; /**< Layer 2 result */ + volatile uint16_t l3r; /**< Layer 3 result */ + volatile uint8_t l4r; /**< Layer 4 result */ + volatile uint8_t cplan; /**< Classification plan id */ + volatile uint16_t nxthdr; /**< Next Header */ + volatile uint16_t cksum; /**< Checksum */ + volatile uint32_t lcv; /**< LCV */ + volatile uint8_t shim_off[3]; /**< Shim offset */ + volatile uint8_t eth_off; /**< ETH offset */ + volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */ + volatile uint8_t vlan_off[2]; /**< VLAN offset */ + volatile uint8_t etype_off; /**< ETYPE offset */ + volatile uint8_t pppoe_off; /**< PPP offset */ + volatile uint8_t mpls_off[2]; /**< MPLS offset */ + volatile uint8_t ip_off[2]; /**< IP offset */ + volatile uint8_t gre_off; /**< GRE offset */ + volatile uint8_t l4_off; /**< Layer 4 offset */ + volatile uint8_t nxthdr_off; /**< Parser end point */ +} _PackedType t_FmPrsResult; + +#endif diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.make b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.make new file mode 100644 index 0000000..58009cd --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_resources_ut.make @@ -0,0 +1,28 @@ +CC=gcc + +LNXWRP_RESS_UT=lnxwrp_resources_ut +OBJ=lnxwrp_resources + +INC_PATH= +LIB_PATH= + +INC=$(addprefix -I,$(INC_PATH)) +LIB=$(addprefix -L,$(LIB_PATH)) + +CFLAGS= -gdwarf-2 -g -O0 -Wall +XFLAGS= -DFMAN_RESOURCES_UNIT_TEST + +all: $(LNXWRP_RESS_UT) + +$(LNXWRP_RESS_UT):$(addsuffix .o,$(OBJ)) $(LNXWRP_RESS_UT).o + $(CC) -o $(LNXWRP_RESS_UT) $(LNXWRP_RESS_UT).o $(addsuffix .o,$(OBJ)) + +%.o: %.c + @(echo " (CC) $@") + @($(CC) $(INC) $(CFLAGS) $(XFLAGS) -o $(@) -c $<) + +.PHONY: clean + +clean: + rm -f *.o + rm -f $(LNXWRP_RESS_UT) diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.c new file mode 100644 index 0000000..3f122b5 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.c @@ -0,0 +1,60 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs.c + + @Description FM wrapper sysfs related functions. + +*/ + +#include <linux/types.h> +#include "lnxwrp_sysfs.h" + +uint8_t fm_find_statistic_counter_by_name(const char *attr_name, + const struct SysfsStats_t *sysfs_stats, + uint8_t *offset) +{ + int i = 0; + + while (sysfs_stats[i].statisticName != NULL) { + if (strcmp(sysfs_stats[i].statisticName, attr_name) == 0) { + if (offset != NULL) + *offset = i; + return sysfs_stats[i].statisticCounter; + } + + i++; + } + WARN(1, "FMD: Should never get here!"); + return 0; +} diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.h new file mode 100644 index 0000000..67cb2b0 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs.h @@ -0,0 +1,67 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs.h + + @Description FM sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_H_ +#define LNXWRP_SYSFS_H_ + +/* Linux Headers ------------------- */ +#include <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/sysfs.h> + +struct SysfsStats_t { + const char *statisticName; + uint8_t statisticCounter; +}; + +uint8_t fm_find_statistic_counter_by_name(const char *attr_name, + const struct SysfsStats_t *sysfs_stats, + uint8_t *offset); + +#endif /* LNXWRP_SYSFS_H_ */ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.c new file mode 100644 index 0000000..2cfc0b9 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.c @@ -0,0 +1,573 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs_fm.c + + @Description FM sysfs related functions. + +*/ + +#include "lnxwrp_sysfs.h" +#include "lnxwrp_fm.h" + +enum e_FmDmaMatchStatistics { + e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY, + e_FM_DMA_COUNTERS_BUS_ERROR, + e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, + e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, + e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR +}; + +static const struct SysfsStats_t fmSysfsStats[] = { + /* FM statistics */ + { + .statisticName = "enq_total_frame", + .statisticCounter = e_FM_COUNTERS_ENQ_TOTAL_FRAME, + }, + { + .statisticName = "deq_total_frame", + .statisticCounter = e_FM_COUNTERS_DEQ_TOTAL_FRAME, + }, + { + .statisticName = "deq_0", + .statisticCounter = e_FM_COUNTERS_DEQ_0, + }, + { + .statisticName = "deq_1", + .statisticCounter = e_FM_COUNTERS_DEQ_1, + }, + { + .statisticName = "deq_2", + .statisticCounter = e_FM_COUNTERS_DEQ_2, + }, + { + .statisticName = "deq_3", + .statisticCounter = e_FM_COUNTERS_DEQ_3, + }, + { + .statisticName = "deq_from_default", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_DEFAULT, + }, + { + .statisticName = "deq_from_context", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_CONTEXT, + }, + { + .statisticName = "deq_from_fd", + .statisticCounter = e_FM_COUNTERS_DEQ_FROM_FD, + }, + { + .statisticName = "deq_confirm", + .statisticCounter = e_FM_COUNTERS_DEQ_CONFIRM, + }, + /* FM:DMA statistics */ + { + .statisticName = "cmq_not_empty", + .statisticCounter = e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY, + }, + { + .statisticName = "bus_error", + .statisticCounter = e_FM_DMA_COUNTERS_BUS_ERROR, + }, + { + .statisticName = "read_buf_ecc_error", + .statisticCounter = e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, + }, + { + .statisticName = "write_buf_ecc_sys_error", + .statisticCounter = e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, + }, + { + .statisticName = "write_buf_ecc_fm_error", + .statisticCounter = e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR, + }, + /* FM:PCD statistics */ + { + .statisticName = "pcd_kg_total", + .statisticCounter = e_FM_PCD_KG_COUNTERS_TOTAL, + }, + { + .statisticName = "pcd_plcr_yellow", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_YELLOW, + }, + { + .statisticName = "pcd_plcr_red", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RED, + }, + { + .statisticName = "pcd_plcr_recolored_to_red", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, + }, + { + .statisticName = "pcd_plcr_recolored_to_yellow", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, + }, + { + .statisticName = "pcd_plcr_total", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_TOTAL, + }, + { + .statisticName = "pcd_plcr_length_mismatch", + .statisticCounter = e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, + }, + { + .statisticName = "pcd_prs_parse_dispatch", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, + }, + { + .statisticName = "pcd_prs_l2_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l3_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l4_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_shim_parse_result_returned", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, + }, + { + .statisticName = "pcd_prs_l2_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_l3_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_l4_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_shim_parse_result_returned_with_err", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, + }, + { + .statisticName = "pcd_prs_soft_prs_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, + }, + { + .statisticName = "pcd_prs_soft_prs_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_hard_prs_cycle_incl_stall_cycles", + .statisticCounter = + e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_read_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_read_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_write_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, + }, + { + .statisticName = "pcd_prs_muram_write_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, + }, + { + .statisticName = "pcd_prs_fpm_command_stall_cycles", + .statisticCounter = e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES, + }, + {} +}; + +/* Fm stats and regs dumps via sysfs */ +static ssize_t show_fm_dma_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + t_FmDmaStatus fmDmaStatus; + unsigned long flags = 0; + unsigned n = 0; + uint8_t counter_value = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + counter = fm_find_statistic_counter_by_name( + attr->attr.name, + fmSysfsStats, NULL); + + local_irq_save(flags); + + memset(&fmDmaStatus, 0, sizeof(fmDmaStatus)); + FM_GetDmaStatus(p_LnxWrpFmDev->h_Dev, &fmDmaStatus); + + switch (counter) { + case e_FM_DMA_COUNTERS_CMQ_NOT_EMPTY: + counter_value = fmDmaStatus.cmqNotEmpty; + break; + case e_FM_DMA_COUNTERS_BUS_ERROR: + counter_value = fmDmaStatus.busError; + break; + case e_FM_DMA_COUNTERS_READ_BUF_ECC_ERROR: + counter_value = fmDmaStatus.readBufEccError; + break; + case e_FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR: + counter_value = fmDmaStatus.writeBufEccSysError; + break; + case e_FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR: + counter_value = fmDmaStatus.writeBufEccFmError; + break; + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + break; + }; + + n = snprintf(buf, PAGE_SIZE, "\tFM %u counter: %c\n", + p_LnxWrpFmDev->id, counter_value ? 'T' : 'F'); + + local_irq_restore(flags); + + return n; +} + +static ssize_t show_fm_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + unsigned long flags = 0; + unsigned n = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + counter = fm_find_statistic_counter_by_name( + attr->attr.name, + fmSysfsStats, NULL); + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", + p_LnxWrpFmDev->id, + FM_GetCounter(p_LnxWrpFmDev->h_Dev, + (e_FmCounters) counter)); + + local_irq_restore(flags); + + return n; +} + +static ssize_t show_fm_pcd_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + unsigned long flags = 0; + unsigned n = 0, counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev || + !p_LnxWrpFmDev->h_PcdDev) + return -EIO; + + counter = fm_find_statistic_counter_by_name( + attr->attr.name, + fmSysfsStats, NULL); + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", + p_LnxWrpFmDev->id, + FM_PCD_GetCounter(p_LnxWrpFmDev->h_PcdDev, + (e_FmPcdCounters) counter)); + + local_irq_restore(flags); + + return n; +} + +/* FM */ +static DEVICE_ATTR(enq_total_frame, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_total_frame, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_0, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_1, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_2, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_3, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_default, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_context, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_from_fd, S_IRUGO, show_fm_stats, NULL); +static DEVICE_ATTR(deq_confirm, S_IRUGO, show_fm_stats, NULL); +/* FM:DMA */ +static DEVICE_ATTR(cmq_not_empty, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(bus_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(read_buf_ecc_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(write_buf_ecc_sys_error, S_IRUGO, show_fm_dma_stats, NULL); +static DEVICE_ATTR(write_buf_ecc_fm_error, S_IRUGO, show_fm_dma_stats, NULL); +/* FM:PCD */ +static DEVICE_ATTR(pcd_kg_total, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_yellow, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_red, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_recolored_to_red, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_plcr_recolored_to_yellow, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_plcr_total, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_plcr_length_mismatch, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_parse_dispatch, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l2_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l3_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l4_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_shim_parse_result_returned, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l2_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l3_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_l4_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_shim_parse_result_returned_with_err, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_soft_prs_cycles, S_IRUGO, show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_soft_prs_stall_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_hard_prs_cycle_incl_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_muram_read_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_muram_read_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_muram_write_cycles, S_IRUGO, show_fm_pcd_stats, + NULL); +static DEVICE_ATTR(pcd_prs_muram_write_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); +static DEVICE_ATTR(pcd_prs_fpm_command_stall_cycles, S_IRUGO, + show_fm_pcd_stats, NULL); + +static struct attribute *fm_dev_stats_attributes[] = { + &dev_attr_enq_total_frame.attr, + &dev_attr_deq_total_frame.attr, + &dev_attr_deq_0.attr, + &dev_attr_deq_1.attr, + &dev_attr_deq_2.attr, + &dev_attr_deq_3.attr, + &dev_attr_deq_from_default.attr, + &dev_attr_deq_from_context.attr, + &dev_attr_deq_from_fd.attr, + &dev_attr_deq_confirm.attr, + &dev_attr_cmq_not_empty.attr, + &dev_attr_bus_error.attr, + &dev_attr_read_buf_ecc_error.attr, + &dev_attr_write_buf_ecc_sys_error.attr, + &dev_attr_write_buf_ecc_fm_error.attr, + &dev_attr_pcd_kg_total.attr, + &dev_attr_pcd_plcr_yellow.attr, + &dev_attr_pcd_plcr_red.attr, + &dev_attr_pcd_plcr_recolored_to_red.attr, + &dev_attr_pcd_plcr_recolored_to_yellow.attr, + &dev_attr_pcd_plcr_total.attr, + &dev_attr_pcd_plcr_length_mismatch.attr, + &dev_attr_pcd_prs_parse_dispatch.attr, + &dev_attr_pcd_prs_l2_parse_result_returned.attr, + &dev_attr_pcd_prs_l3_parse_result_returned.attr, + &dev_attr_pcd_prs_l4_parse_result_returned.attr, + &dev_attr_pcd_prs_shim_parse_result_returned.attr, + &dev_attr_pcd_prs_l2_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_l3_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_l4_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_shim_parse_result_returned_with_err.attr, + &dev_attr_pcd_prs_soft_prs_cycles.attr, + &dev_attr_pcd_prs_soft_prs_stall_cycles.attr, + &dev_attr_pcd_prs_hard_prs_cycle_incl_stall_cycles.attr, + &dev_attr_pcd_prs_muram_read_cycles.attr, + &dev_attr_pcd_prs_muram_read_stall_cycles.attr, + &dev_attr_pcd_prs_muram_write_cycles.attr, + &dev_attr_pcd_prs_muram_write_stall_cycles.attr, + &dev_attr_pcd_prs_fpm_command_stall_cycles.attr, + NULL +}; + +static const struct attribute_group fm_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_dev_stats_attributes +}; + +static ssize_t show_fm_regs(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + local_irq_save(flags); + + n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n"); + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + else + FM_DumpRegs(p_LnxWrpFmDev->h_Dev); + + local_irq_restore(flags); +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + return n; +} + +static ssize_t show_pcd_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n"); + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_PcdDev) + return -EIO; + else + FM_PCD_DumpRegs(p_LnxWrpFmDev->h_PcdDev); + + local_irq_restore(flags); +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); + +#endif /* (defined(DEBUG_ERRORS) && ... */ + + return n; +} + +static DEVICE_ATTR(fm_regs, S_IRUGO, show_fm_regs, NULL); +static DEVICE_ATTR(fm_pcd_regs, S_IRUGO, show_pcd_regs, NULL); + +int fm_sysfs_create(struct device *dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + + if (dev == NULL) + return -EIO; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + + /* store to remove them when module is disabled */ + p_LnxWrpFmDev->dev_attr_regs = &dev_attr_fm_regs; + p_LnxWrpFmDev->dev_pcd_attr_regs = &dev_attr_fm_pcd_regs; + + /* Create sysfs statistics group for FM module */ + if (sysfs_create_group(&dev->kobj, &fm_dev_stats_attr_grp) != 0) + return -EIO; + + /* Registers dump entry - in future will be moved to debugfs */ + if (device_create_file(dev, &dev_attr_fm_regs) != 0 || + device_create_file(dev, &dev_attr_fm_pcd_regs) != 0) + return -EIO; + + return 0; +} + +void fm_sysfs_destroy(struct device *dev) +{ + t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; + + if (WARN_ON(dev == NULL)) + return; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return; + + sysfs_remove_group(&dev->kobj, &fm_dev_stats_attr_grp); + device_remove_file(dev, p_LnxWrpFmDev->dev_attr_regs); + device_remove_file(dev, p_LnxWrpFmDev->dev_pcd_attr_regs); +} diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.h new file mode 100644 index 0000000..8aff850 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs_fm.h + + @Description FM sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_FM_H_ +#define LNXWRP_SYSFS_FM_H_ + +#include "lnxwrp_sysfs.h" + +int fm_sysfs_create(struct device *dev); +void fm_sysfs_destroy(struct device *dev); + +#endif /* LNXWRP_SYSFS_FM_H_ */ diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c new file mode 100644 index 0000000..97dacb7 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c @@ -0,0 +1,365 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs_fm_port.c + + @Description FM port sysfs related functions. + +*/ + +#include "lnxwrp_sysfs.h" +#include "lnxwrp_fm.h" + +static const struct SysfsStats_t portSysfsStats[] = { + /* RX/TX/OH common statistics */ + { + .statisticName = "port_frame", + .statisticCounter = e_FM_PORT_COUNTERS_FRAME, + }, + { + .statisticName = "port_discard_frame", + .statisticCounter = e_FM_PORT_COUNTERS_DISCARD_FRAME, + }, + { + .statisticName = "port_dealloc_buf", + .statisticCounter = e_FM_PORT_COUNTERS_DEALLOC_BUF, + }, + { + .statisticName = "port_enq_total", + .statisticCounter = e_FM_PORT_COUNTERS_ENQ_TOTAL, + }, + /* TX/OH */ + { + .statisticName = "port_length_err", + .statisticCounter = e_FM_PORT_COUNTERS_LENGTH_ERR, + }, + { + .statisticName = "port_unsupprted_format", + .statisticCounter = e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, + }, + { + .statisticName = "port_deq_total", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_TOTAL, + }, + { + .statisticName = "port_deq_from_default", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, + }, + { + .statisticName = "port_deq_confirm", + .statisticCounter = e_FM_PORT_COUNTERS_DEQ_CONFIRM, + }, + /* RX/OH */ + { + .statisticName = "port_rx_bad_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_BAD_FRAME, + }, + { + .statisticName = "port_rx_large_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_LARGE_FRAME, + }, + { + .statisticName = "port_rx_out_of_buffers_discard", + .statisticCounter = e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, + }, + { + .statisticName = "port_rx_filter_frame", + .statisticCounter = e_FM_PORT_COUNTERS_RX_FILTER_FRAME, + }, + /* TODO: Particular statistics for OH ports */ + {} +}; + +static ssize_t show_fm_port_stats(struct device *dev, + struct device_attribute *attr, char *buf) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + t_LnxWrpFmDev *p_LnxWrpFmDev; + unsigned long flags; + int n = 0; + uint8_t counter = 0; + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return -EINVAL; + + p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; + if (WARN_ON(p_LnxWrpFmDev == NULL)) + return -EINVAL; + + if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) + return -EIO; + + if (!p_LnxWrpFmPortDev->h_Dev) { + n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); + return n; + } + + counter = fm_find_statistic_counter_by_name( + attr->attr.name, + portSysfsStats, NULL); + + if (counter == e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR) { + uint32_t fmRev = 0; + fmRev = 0xffff & ioread32(UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr + + 0x000c30c4)); + + if (fmRev == 0x0100) { + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "counter not available for revision 1\n"); + local_irq_restore(flags); + } + return n; + } + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, "\tFM %d Port %d counter: %d\n", + p_LnxWrpFmDev->id, + p_LnxWrpFmPortDev->id, + FM_PORT_GetCounter(p_LnxWrpFmPortDev->h_Dev, + (e_FmPortCounters) counter)); + local_irq_restore(flags); + + return n; +} + +/* FM PORT RX/TX/OH statistics */ +static DEVICE_ATTR(port_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_discard_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_dealloc_buf, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_enq_total, S_IRUGO, show_fm_port_stats, NULL); +/* FM PORT TX/OH statistics */ +static DEVICE_ATTR(port_length_err, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_unsupprted_format, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_total, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_from_default, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_deq_confirm, S_IRUGO, show_fm_port_stats, NULL); +/* FM PORT RX/OH statistics */ +static DEVICE_ATTR(port_rx_bad_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_large_frame, S_IRUGO, show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_out_of_buffers_discard, S_IRUGO, + show_fm_port_stats, NULL); +static DEVICE_ATTR(port_rx_filter_frame, S_IRUGO, show_fm_port_stats, NULL); + +/* FM PORT TX statistics */ +static struct attribute *fm_tx_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + &dev_attr_port_length_err.attr, + &dev_attr_port_unsupprted_format.attr, + &dev_attr_port_deq_total.attr, + &dev_attr_port_deq_from_default.attr, + &dev_attr_port_deq_confirm.attr, + NULL +}; + +static const struct attribute_group fm_tx_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_tx_port_dev_stats_attributes +}; + +/* FM PORT RX statistics */ +static struct attribute *fm_rx_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + &dev_attr_port_rx_bad_frame.attr, + &dev_attr_port_rx_large_frame.attr, + &dev_attr_port_rx_out_of_buffers_discard.attr, + &dev_attr_port_rx_filter_frame.attr, + NULL +}; + +static const struct attribute_group fm_rx_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_rx_port_dev_stats_attributes +}; + +/* TODO: add particular OH ports statistics */ +static struct attribute *fm_oh_port_dev_stats_attributes[] = { + &dev_attr_port_frame.attr, + &dev_attr_port_discard_frame.attr, + &dev_attr_port_dealloc_buf.attr, + &dev_attr_port_enq_total.attr, + /*TX*/ &dev_attr_port_length_err.attr, + &dev_attr_port_unsupprted_format.attr, + &dev_attr_port_deq_total.attr, + &dev_attr_port_deq_from_default.attr, + &dev_attr_port_deq_confirm.attr, + /*RX*/ &dev_attr_port_rx_bad_frame.attr, + &dev_attr_port_rx_large_frame.attr, + &dev_attr_port_rx_out_of_buffers_discard.attr, + /*&dev_attr_port_rx_filter_frame.attr, */ + NULL +}; + +static const struct attribute_group fm_oh_port_dev_stats_attr_grp = { + .name = "statistics", + .attrs = fm_oh_port_dev_stats_attributes +}; + +static ssize_t show_fm_port_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + unsigned n = 0; +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = + (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); +#endif + + if (attr == NULL || buf == NULL || dev == NULL) + return -EINVAL; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + local_irq_save(flags); + + if (!p_LnxWrpFmPortDev->h_Dev) { + n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); + return n; + } else { + n = snprintf(buf, PAGE_SIZE, + "FM port driver registers dump.\n"); + FM_PORT_DumpRegs(p_LnxWrpFmPortDev->h_Dev); + } + + local_irq_restore(flags); + + return n; +#else + + local_irq_save(flags); + n = snprintf(buf, PAGE_SIZE, + "Debug level is too low to dump registers!!!\n"); + local_irq_restore(flags); + + return n; +#endif +} + +static DEVICE_ATTR(fm_port_regs, 0x644, show_fm_port_regs, NULL); + +int fm_port_sysfs_create(struct device *dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; + + if (dev == NULL) + return -EINVAL; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return -EINVAL; + + /* store to remove them when module is disabled */ + p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs; + + /* Registers dump entry - in future will be moved to debugfs */ + if (device_create_file(dev, &dev_attr_fm_port_regs) != 0) + return -EIO; + + /* FM Ports statistics */ + switch (p_LnxWrpFmPortDev->settings.param.portType) { + case e_FM_PORT_TYPE_TX: + case e_FM_PORT_TYPE_TX_10G: + if (sysfs_create_group + (&dev->kobj, &fm_tx_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + case e_FM_PORT_TYPE_RX: + case e_FM_PORT_TYPE_RX_10G: + if (sysfs_create_group + (&dev->kobj, &fm_rx_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + /* TODO:FMD16 e_FM_PORT_TYPE_DUMMY is accutally a HC port. + * NetCommSw defined this way... no idea why!!! */ + case e_FM_PORT_TYPE_DUMMY: + case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: + if (sysfs_create_group + (&dev->kobj, &fm_oh_port_dev_stats_attr_grp) != 0) + return -EIO; + break; + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + return -EINVAL; + break; + }; + + return 0; +} + +void fm_port_sysfs_destroy(struct device *dev) +{ + t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; + + /* this function has never been tested !!! */ + + if (WARN_ON(dev == NULL)) + return; + + p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); + if (WARN_ON(p_LnxWrpFmPortDev == NULL)) + return; + + /* The name attribute will be freed also by these 2 functions? */ + switch (p_LnxWrpFmPortDev->settings.param.portType) { + case e_FM_PORT_TYPE_TX: + case e_FM_PORT_TYPE_TX_10G: + sysfs_remove_group(&dev->kobj, &fm_tx_port_dev_stats_attr_grp); + break; + case e_FM_PORT_TYPE_RX: + case e_FM_PORT_TYPE_RX_10G: + sysfs_remove_group(&dev->kobj, &fm_rx_port_dev_stats_attr_grp); + break; + /* TODO:FMD16 e_FM_PORT_TYPE_DUMMY is accutally a HC port. + * NetCommSw defined this way... no idea why!!! */ + case e_FM_PORT_TYPE_DUMMY: + case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: + sysfs_remove_group(&dev->kobj, &fm_oh_port_dev_stats_attr_grp); + break; + default: + WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + break; + }; + + device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs); +} diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h new file mode 100644 index 0000000..03b3a03 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008-2012 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. + */ + +/* + @File lnxwrp_sysfs_fm_port.h + + @Description FM port sysfs functions. + +*/ + +#ifndef LNXWRP_SYSFS_FM_PORT_H_ +#define LNXWRP_SYSFS_FM_PORT_H_ + +#include "lnxwrp_sysfs.h" + +int fm_port_sysfs_create(struct device *dev); +void fm_port_sysfs_destroy(struct device *dev); + +#endif /* LNXWRP_SYSFS_FM_PORT_H_ */ diff --git a/drivers/net/ethernet/freescale/fman/src/xx/Makefile b/drivers/net/ethernet/freescale/fman/src/xx/Makefile new file mode 100644 index 0000000..1e0db57 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/xx/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk + +obj-y += fsl-ncsw-xx.o + +fsl-ncsw-xx-objs := xx_linux.o udivdi3.o stdlib.o \ + module_strings.o diff --git a/drivers/net/ethernet/freescale/fman/src/xx/module_strings.c b/drivers/net/ethernet/freescale/fman/src/xx/module_strings.c new file mode 100644 index 0000000..98c64fb --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/xx/module_strings.c @@ -0,0 +1,45 @@ +/* + * Copyright 2012 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. + */ + +/* Module names for debug messages */ +const char *moduleStrings[] = +{ + "", /* MODULE_UNKNOWN */ + "FM", /* MODULE_FM */ + "FM-MURAM", /* MODULE_FM_MURAM */ + "FM-PCD", /* MODULE_FM_PCD */ + "FM-RTC", /* MODULE_FM_RTC */ + "FM-MAC", /* MODULE_FM_MAC */ + "FM-Port", /* MODULE_FM_PORT */ + "MM", /* MODULE_MM */ + "FM-SP" /* MODULE_FM_SP */ +}; diff --git a/drivers/net/ethernet/freescale/fman/src/xx/stdlib.c b/drivers/net/ethernet/freescale/fman/src/xx/stdlib.c new file mode 100644 index 0000000..851bcf1 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/xx/stdlib.c @@ -0,0 +1,264 @@ +/* + * Copyright 2008-2012 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. + */ + +/*------------------------------------------------------*/ +/* */ +/* File: stdlib.c */ +/* */ +/* Description: */ +/* Standard library routines (externals) */ +/* */ +/* Modifications: */ +/* ============== */ +/* */ +/*------------------------------------------------------*/ +#include "stdlib_ext.h" +#include "stdarg_ext.h" +#include "ctype_ext.h" +#include "string_ext.h" +#include "std_ext.h" +#include "xx_ext.h" + + +#ifdef MODULE +/** + * strtoul - convert a string to an uint32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint32_t strtoul(const char *cp,char **endp,uint32_t base) +{ + uint32_t result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && + (value = (uint32_t)(isdigit(*cp) ? *cp-'0' : toupper((uint8_t)(*cp))-'A'+10)) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/** + * strtol - convert a string to a int32_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long strtol(const char *cp,char **endp,uint32_t base) +{ + if(*cp=='-') + return (long)(-strtoul(cp+1,endp,base)); + return (long)strtoul(cp,endp,base); +} + +/** + * strtoull - convert a string to an uint64_t + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +uint64_t strtoull(const char *cp,char **endp,uint32_t base) +{ + uint64_t result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper((uint8_t)(*cp)) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/** + * strtoll - convert a string to a int64 + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long long strtoll(const char *cp,char **endp,uint32_t base) +{ + if(*cp=='-') + return (long long)(-strtoull(cp+1,endp,base)); + return (long long)(strtoull(cp,endp,base)); +} + +/** + * atoi - convert a string to a int + * @s: The start of the string + */ +int atoi(const char *s) +{ + int i=0; + const char **tmp_s = &s; + + while (isdigit(**tmp_s)) + i = i*10 + *((*tmp_s)++) - '0'; + return i; +} + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + + return sc - s; +} + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + + return sc - s; +} + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} +#endif /* MODULE */ + +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ +char *___strtok; + +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} + + +#ifdef MODULE +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return vsnprintf(buf, INT32_MAX, fmt, args); +} +#endif /* MODULE */ diff --git a/drivers/net/ethernet/freescale/fman/src/xx/udivdi3.c b/drivers/net/ethernet/freescale/fman/src/xx/udivdi3.c new file mode 100644 index 0000000..419e27e --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/xx/udivdi3.c @@ -0,0 +1,132 @@ +/* + * Copyright 2008-2012 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 <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <asm/div64.h> + + +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) + + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +struct DIstruct {SItype low, high;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + + +/* bit divisor, dividend and result. dynamic precision */ +static __inline__ uint64_t _div64_64(uint64_t dividend, uint64_t divisor) +{ + uint32_t d = divisor; + + if (divisor > 0xffffffffULL) + { + unsigned int shift = fls(divisor >> 32); + + d = divisor >> shift; + dividend >>= shift; + } + + /* avoid 64 bit division if possible */ + if (dividend >> 32) + do_div(dividend, d); + else + dividend = (uint32_t) dividend / d; + + return dividend; +} + +UDItype __udivdi3 (UDItype n, UDItype d) +{ + return _div64_64(n, d); +} + +DItype __divdi3 (DItype n, DItype d) +{ + DItype sign = 1; + if (n<0) + { + sign *= -1; + n *= -1; + } + if (d<0) + { + sign *= -1; + d *= -1; + } + return sign*_div64_64((UDItype)n, (UDItype)d); +} + +UDItype __umoddi3 (UDItype n, UDItype d) +{ + return n-(_div64_64(n, d)*d); +} + +#ifdef MODULE +word_type __ucmpdi2 (DItype a, DItype b) +{ + DIunion au, bu; + + au.ll = a, bu.ll = b; + + if ((USItype) au.s.high < (USItype) bu.s.high) + return 0; + else if ((USItype) au.s.high > (USItype) bu.s.high) + return 2; + if ((USItype) au.s.low < (USItype) bu.s.low) + return 0; + else if ((USItype) au.s.low > (USItype) bu.s.low) + return 2; + return 1; +} +#endif /* MODULE */ diff --git a/drivers/net/ethernet/freescale/fman/src/xx/xx_linux.c b/drivers/net/ethernet/freescale/fman/src/xx/xx_linux.c new file mode 100644 index 0000000..4b5c7863 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/src/xx/xx_linux.c @@ -0,0 +1,901 @@ +/* + * Copyright 2008-2012 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. + */ + +/**************************************************************************//** + @File xx_linux.c + + @Description XX routines implementation for Linux. +*//***************************************************************************/ +#include <linux/version.h> + +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include <config/modversions.h> +#endif /* MODVERSIONS */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/smp.h> +#include <linux/of.h> + +#include <linux/workqueue.h> + +#ifdef BIGPHYSAREA_ENABLE +#include <linux/bigphysarea.h> +#endif /* BIGPHYSAREA_ENABLE */ + +#include <sysdev/fsl_soc.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <asm/string.h> +#include <asm/byteorder.h> +#include <asm/page.h> + +#include "error_ext.h" +#include "std_ext.h" +#include "list_ext.h" +#include "mm_ext.h" +#include "sys_io_ext.h" +#include "xx.h" + + +#define __ERR_MODULE__ MODULE_UNKNOWN + +#ifdef BIGPHYSAREA_ENABLE +#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */ + + +/* TODO: large allocations => use big phys area */ +/****************************************************************************** + * routine: get_nr_pages + * + * description: + * calculates the number of memory pages for a given size (in bytes) + * + * arguments: + * size - the number of bytes + * + * return code: + * The number of pages + * + *****************************************************************************/ +static __inline__ uint32_t get_nr_pages (uint32_t size) +{ + return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0)); +} + +static bool in_big_phys_area (uint32_t addr) +{ + uint32_t base, size; + + bigphysarea_get_details (&base, &size); + return ((addr >= base) && (addr < base + size)); +} +#endif /* BIGPHYSAREA_ENABLE */ + +void * xx_Malloc(uint32_t n) +{ + void *a; + uint32_t flags; + + flags = XX_DisableAllIntr(); +#ifdef BIGPHYSAREA_ENABLE + if (n >= MAX_ALLOCATION_SIZE) + a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC); + else +#endif /* BIGPHYSAREA_ENABLE */ + a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC); + if (!a) + XX_Print("No memory for XX_Malloc\n"); + XX_RestoreAllIntr(flags); + + return a; +} + +void xx_Free(void *p) +{ +#ifdef BIGPHYSAREA_ENABLE + if (in_big_phys_area ((uint32_t)p)) + bigphysarea_free_pages(p); + else +#endif /* BIGPHYSAREA_ENABLE */ + kfree(p); +} + +void XX_Exit(int status) +{ + WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n"); +} + +#define BUF_SIZE 512 +void XX_Print(char *str, ...) +{ + va_list args; +#ifdef CONFIG_SMP + char buf[BUF_SIZE]; +#endif /* CONFIG_SMP */ + + va_start(args, str); +#ifdef CONFIG_SMP + if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) + printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); + printk (KERN_CRIT "cpu%d: %s",raw_smp_processor_id(), buf); +#else + vprintk(str, args); +#endif /* CONFIG_SMP */ + va_end(args); +} + +void XX_Fprint(void *file, char *str, ...) +{ + va_list args; +#ifdef CONFIG_SMP + char buf[BUF_SIZE]; +#endif /* CONFIG_SMP */ + + va_start(args, str); +#ifdef CONFIG_SMP + if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) + printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); + printk (KERN_CRIT "cpu%d: %s", raw_smp_processor_id(), buf); +#else + vprintk(str, args); +#endif /* CONFIG_SMP */ + va_end(args); +} + +#ifdef DEBUG_XX_MALLOC +typedef void (*t_ffn)(void *); +typedef struct { + t_ffn f_free; + void *mem; + char *fname; + int fline; + uint32_t size; + t_List node; +} t_MemDebug; +#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node) + +LIST(memDbgLst); + + +void * XX_MallocDebug(uint32_t size, char *fname, int line) +{ + void *mem; + t_MemDebug *p_MemDbg; + + p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug)); + if (p_MemDbg == NULL) + return NULL; + + mem = xx_Malloc(size); + if (mem == NULL) + { + XX_Free(p_MemDbg); + return NULL; + } + + INIT_LIST(&p_MemDbg->node); + p_MemDbg->f_free = xx_Free; + p_MemDbg->mem = mem; + p_MemDbg->fname = fname; + p_MemDbg->fline = line; + p_MemDbg->size = size+sizeof(t_MemDebug); + LIST_AddToTail(&p_MemDbg->node, &memDbgLst); + + return mem; +} + +void * XX_MallocSmartDebug(uint32_t size, + int memPartitionId, + uint32_t align, + char *fname, + int line) +{ + void *mem; + t_MemDebug *p_MemDbg; + + p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug)); + if (p_MemDbg == NULL) + return NULL; + + mem = xx_MallocSmart((uint32_t)size, memPartitionId, align); + if (mem == NULL) + { + XX_Free(p_MemDbg); + return NULL; + } + + INIT_LIST(&p_MemDbg->node); + p_MemDbg->f_free = xx_FreeSmart; + p_MemDbg->mem = mem; + p_MemDbg->fname = fname; + p_MemDbg->fline = line; + p_MemDbg->size = size+sizeof(t_MemDebug); + LIST_AddToTail(&p_MemDbg->node, &memDbgLst); + + return mem; +} + +static void debug_free(void *mem) +{ + t_List *p_MemDbgLh = NULL; + t_MemDebug *p_MemDbg; + bool found = FALSE; + + if (LIST_IsEmpty(&memDbgLst)) + { + REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem)); + return; + } + + LIST_FOR_EACH(p_MemDbgLh, &memDbgLst) + { + p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh); + if (p_MemDbg->mem == mem) + { + found = TRUE; + break; + } + } + + if (!found) + { + REPORT_ERROR(MAJOR, E_NOT_FOUND, + ("Attempt to free unallocated address (0x%08x)",mem)); + dump_stack(); + return; + } + + LIST_Del(p_MemDbgLh); + p_MemDbg->f_free(mem); + p_MemDbg->f_free(p_MemDbg); +} + +void XX_FreeSmart(void *p) +{ + debug_free(p); +} + + +void XX_Free(void *p) +{ + debug_free(p); +} + +#else /* not DEBUG_XX_MALLOC */ +void * XX_Malloc(uint32_t size) +{ + return xx_Malloc(size); +} + +void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) +{ + return xx_MallocSmart(size,memPartitionId, alignment); +} + +void XX_FreeSmart(void *p) +{ + xx_FreeSmart(p); +} + + +void XX_Free(void *p) +{ + xx_Free(p); +} +#endif /* not DEBUG_XX_MALLOC */ + + +#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) +void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg) +{ + e_Event eventCode = (e_Event)event; + + UNUSED(eventCode); + UNUSED(appId); + UNUSED(flags); + UNUSED(msg); +} +#endif /* (defined(REPORT_EVENTS) && ... */ + + +uint32_t XX_DisableAllIntr(void) +{ + unsigned long flags; + + local_irq_save(flags); + + return (uint32_t)flags; +} + +void XX_RestoreAllIntr(uint32_t flags) +{ + local_irq_restore((unsigned long)flags); +} + +t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags ) +{ + UNUSED(qid); + UNUSED(appId); + UNUSED(flags); + + return f(id); +} + +int XX_IsICacheEnable(void) +{ + return TRUE; +} + +int XX_IsDCacheEnable(void) +{ + return TRUE; +} + + +typedef struct { + t_Isr *f_Isr; + t_Handle handle; +} t_InterruptHandler; + + +t_Handle interruptHandlers[0x00010000]; + +static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id) +{ + t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id; + p_IntrHndl->f_Isr(p_IntrHndl->handle); + return IRQ_HANDLED; +} + +t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) +{ + const char *device; + t_InterruptHandler *p_IntrHndl; + + device = GetDeviceName(irq); + if (device == NULL) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq)); + + p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler)); + if (p_IntrHndl == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_IntrHndl->f_Isr = f_Isr; + p_IntrHndl->handle = handle; + interruptHandlers[irq] = p_IntrHndl; + + if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0) + RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device)); + disable_irq(GetDeviceIrqNum(irq)); + + return E_OK; +} + +t_Error XX_FreeIntr(int irq) +{ + t_InterruptHandler *p_IntrHndl = interruptHandlers[irq]; + free_irq(GetDeviceIrqNum(irq), p_IntrHndl); + XX_Free(p_IntrHndl); + interruptHandlers[irq] = 0; + return E_OK; +} + +t_Error XX_EnableIntr(int irq) +{ + enable_irq(GetDeviceIrqNum(irq)); + return E_OK; +} + +t_Error XX_DisableIntr(int irq) +{ + disable_irq(GetDeviceIrqNum(irq)); + return E_OK; +} + + +/*****************************************************************************/ +/* Tasklet Service Routines */ +/*****************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +typedef struct +{ + t_Handle h_Data; + void (*f_Callback) (void *); + struct delayed_work dwork; +} t_Tasklet; + +static void GenericTaskletCallback(struct work_struct *p_Work) +{ + t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work); + + p_Task->f_Callback(p_Task->h_Data); +} +#endif /* LINUX_VERSION_CODE */ + + +t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + struct work_struct *p_Task; + p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct)); + INIT_WORK(p_Task, routine, data); +#else + t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet)); + p_Task->h_Data = data; + p_Task->f_Callback = routine; + INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback); +#endif /* LINUX_VERSION_CODE */ + + return (t_TaskletHandle)p_Task; +} + + +void XX_FreeTasklet (t_TaskletHandle h_Tasklet) +{ + if (h_Tasklet) + XX_Free(h_Tasklet); +} + +int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate) +{ + int ans; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + if (immediate) + ans = schedule_work(h_Tasklet); + else + ans = schedule_delayed_work(h_Tasklet, 1); +#else + if (immediate) + ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0); + else + ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ); +#endif /* LINUX_VERSION_CODE */ + + return ans; +} + +void XX_FlushScheduledTasks(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + flush_scheduled_tasks(); +#else + flush_scheduled_work(); +#endif /* LINUX_VERSION_CODE */ +} + +int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + return (int)(((struct work_struct *)h_Tasklet)->pending); +#else + return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork); +#endif /* LINUX_VERSION_CODE */ +} + +void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + ((struct tq_struct *)h_Tasklet)->data = data; +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + ((struct work_struct *)h_Tasklet)->data = data; +#else + ((t_Tasklet *)h_Tasklet)->h_Data = data; +#endif /* LINUX_VERSION_CODE */ +} + +t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + return (t_Handle)(((struct work_struct *)h_Tasklet)->data); +#else + return ((t_Tasklet *)h_Tasklet)->h_Data; +#endif /* LINUX_VERSION_CODE */ +} + + +/*****************************************************************************/ +/* Spinlock Service Routines */ +/*****************************************************************************/ + +t_Handle XX_InitSpinlock(void) +{ + spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t)); + if (!p_Spinlock) + return NULL; + + spin_lock_init(p_Spinlock); + + return (t_Handle)p_Spinlock; +} + +void XX_FreeSpinlock(t_Handle h_Spinlock) +{ + if (h_Spinlock) + XX_Free(h_Spinlock); +} + +void XX_LockSpinlock(t_Handle h_Spinlock) +{ + spin_lock((spinlock_t *)h_Spinlock); +} + +void XX_UnlockSpinlock(t_Handle h_Spinlock) +{ + spin_unlock((spinlock_t *)h_Spinlock); +} + +uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock) +{ + unsigned long intrFlags; + spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags); + return intrFlags; +} + +void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags) +{ + spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags); +} + + +/*****************************************************************************/ +/* Timers Service Routines */ +/*****************************************************************************/ +/* The time now is in mili sec. resolution */ +uint32_t XX_CurrentTime(void) +{ + return (jiffies*1000)/HZ; +} + + +t_Handle XX_CreateTimer(void) +{ + struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list)); + if (p_Timer) + { + memset(p_Timer, 0, sizeof(struct timer_list)); + init_timer(p_Timer); + } + return (t_Handle)p_Timer; +} + +void XX_FreeTimer(t_Handle h_Timer) +{ + if (h_Timer) + XX_Free(h_Timer); +} + +void XX_StartTimer(t_Handle h_Timer, + uint32_t msecs, + bool periodic, + void (*f_TimerExpired)(t_Handle), + t_Handle h_Arg) +{ + int tmp_jiffies = (msecs*HZ)/1000; + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED); + + p_Timer->function = (void (*)(unsigned long))f_TimerExpired; + p_Timer->data = (unsigned long)h_Arg; + if ((msecs*HZ)%1000) + tmp_jiffies++; + p_Timer->expires = (jiffies + tmp_jiffies); + + add_timer((struct timer_list *)h_Timer); +} + +void XX_SetTimerData(t_Handle h_Timer, t_Handle data) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + p_Timer->data = (unsigned long)data; +} + +t_Handle XX_GetTimerData(t_Handle h_Timer) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + return (t_Handle)p_Timer->data; +} + +uint32_t XX_GetExpirationTime(t_Handle h_Timer) +{ + struct timer_list *p_Timer = (struct timer_list *)h_Timer; + + return (uint32_t)p_Timer->expires; +} + +void XX_StopTimer(t_Handle h_Timer) +{ + del_timer((struct timer_list *)h_Timer); +} + +void XX_ModTimer(t_Handle h_Timer, uint32_t msecs) +{ + int tmp_jiffies = (msecs*HZ)/1000; + + if ((msecs*HZ)%1000) + tmp_jiffies++; + mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies); +} + +int XX_TimerIsActive(t_Handle h_Timer) +{ + return timer_pending((struct timer_list *)h_Timer); +} + +uint32_t XX_Sleep(uint32_t msecs) +{ + int tmp_jiffies = (msecs*HZ)/1000; + + if ((msecs*HZ)%1000) + tmp_jiffies++; + return schedule_timeout(tmp_jiffies); +} + +/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/ +void XX_UDelay(uint32_t usecs) +{ + udelay(usecs); +} + +/* TODO: verify that these are correct */ +#define MSG_BODY_SIZE 512 +typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]); +typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]); +t_Error XX_SendMessage(char *p_DestAddr, + uint32_t msgId, + uint8_t msgBody[MSG_BODY_SIZE], + t_MsgCompletionCB *f_CompletionCB, + t_Handle h_CBArg); + +typedef struct { + char *p_Addr; + t_MsgHandler *f_MsgHandlerCB; + t_Handle h_Mod; + t_List node; +} t_MsgHndlr; +#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node) + +LIST(msgHndlrList); + +static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr) +{ + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList); + XX_RestoreAllIntr(intFlags); +} +/* TODO: add this for multi-platform support +static t_MsgHndlr * DequeueMsgHndlr(void) +{ + t_MsgHndlr *p_MsgHndlr = NULL; + uint32_t intFlags; + + intFlags = XX_DisableAllIntr(); + if (!LIST_IsEmpty(&msgHndlrList)) + { + p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next); + LIST_DelAndInit(&p_MsgHndlr->node); + } + XX_RestoreAllIntr(intFlags); + + return p_MsgHndlr; +} +*/ +static t_MsgHndlr * FindMsgHndlr(char *p_Addr) +{ + t_MsgHndlr *p_MsgHndlr; + t_List *p_Pos; + + LIST_FOR_EACH(p_Pos, &msgHndlrList) + { + p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos); + if (strstr(p_MsgHndlr->p_Addr, p_Addr)) + return p_MsgHndlr; + } + + return NULL; +} + +t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod) +{ + t_MsgHndlr *p_MsgHndlr; + uint32_t len; + + p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr)); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); + memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr)); + + len = strlen(p_Addr); + p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1); + strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1)); + + p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB; + p_MsgHndlr->h_Mod = h_Mod; + INIT_LIST(&p_MsgHndlr->node); + EnqueueMsgHndlr(p_MsgHndlr); + + return E_OK; +} + +t_Error XX_UnregisterMessageHandler (char *p_Addr) +{ + t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + LIST_Del(&p_MsgHndlr->node); + XX_Free(p_MsgHndlr->p_Addr); + XX_Free(p_MsgHndlr); + + return E_OK; +} + +t_Error XX_SendMessage(char *p_DestAddr, + uint32_t msgId, + uint8_t msgBody[MSG_BODY_SIZE], + t_MsgCompletionCB *f_CompletionCB, + t_Handle h_CBArg) +{ + t_Error ans; + t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr); + if (!p_MsgHndlr) + RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); + + ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody); + + if (f_CompletionCB) + f_CompletionCB(h_CBArg, msgBody); + + return ans; +} + +t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], + t_IpcMsgHandler *f_MsgHandler, + t_Handle h_Module, + uint32_t replyLength) +{ + UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength); + return E_OK; +} + +t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]) +{ + UNUSED(addr); + return E_OK; +} + + +t_Error XX_IpcSendMessage(t_Handle h_Session, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength, + t_IpcMsgCompletion *f_Completion, + t_Handle h_Arg) +{ + UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply); + UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg); + return E_OK; +} + +t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], + char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]) +{ + UNUSED(destAddr); UNUSED(srcAddr); + return E_OK; +} + +/*Forced to introduce due to PRINT_FMT_PARAMS define*/ +uint32_t E500_GetId(void) +{ + return raw_smp_processor_id(); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +int GetDeviceIrqNum(int irq) +{ + struct device_node *iPar; + struct irq_host *irqHost; + uint32_t hwIrq; + + /* Get the interrupt controller */ + iPar = of_find_node_by_name(NULL, "mpic"); + hwIrq = 0; + + ASSERT_COND(iPar != NULL); + /* Get the irq host */ + irqHost = irq_find_host(iPar); + of_node_put(iPar); + + /* Create irq mapping */ + return irq_create_mapping(irqHost, hwIrq); +} +#else +#error "kernel not supported!!!" +#endif /* LINUX_VERSION_CODE */ + +void * XX_PhysToVirt(physAddress_t addr) +{ + return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr)); +} + +physAddress_t XX_VirtToPhys(void * addr) +{ + return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr)); +} + +void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) +{ + uintptr_t *returnCode, tmp; + + if (alignment < sizeof(uintptr_t)) + alignment = sizeof(uintptr_t); + size += alignment + sizeof(returnCode); + tmp = (uintptr_t)xx_Malloc(size); + if (tmp == 0) + return NULL; + returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1)); + *(returnCode - 1) = tmp; + + return (void*)returnCode; +} + +void xx_FreeSmart(void *p) +{ + xx_Free((void*)(*((uintptr_t *)(p) - 1))); +} |