All of lore.kernel.org
 help / color / mirror / Atom feed
* [v2,5/9] fsl/fman: Add Frame Manager support
@ 2015-06-24 19:35 igal.liberman
  2015-06-25 23:53 ` Paul Bolle
  2015-06-26  3:54 ` Scott Wood
  0 siblings, 2 replies; 8+ messages in thread
From: igal.liberman @ 2015-06-24 19:35 UTC (permalink / raw)
  To: netdev; +Cc: linuxppc-dev, scottwood, madalin.bucur, pebolle, Igal Liberman

From: Igal Liberman <Igal.Liberman@freescale.com>

Add Frame Manger Driver support.
This patch adds The FMan configuration, initialization and
runtime control routines.

Signed-off-by: Igal Liberman <Igal.Liberman@freescale.com>
---
 drivers/net/ethernet/freescale/fman/Kconfig        |   35 +
 drivers/net/ethernet/freescale/fman/Makefile       |    2 +-
 drivers/net/ethernet/freescale/fman/fm.c           | 1406 ++++++++++++++++++++
 drivers/net/ethernet/freescale/fman/fm.h           |  394 ++++++
 drivers/net/ethernet/freescale/fman/fm_common.h    |  142 ++
 drivers/net/ethernet/freescale/fman/fm_drv.c       |  701 ++++++++++
 drivers/net/ethernet/freescale/fman/fm_drv.h       |  116 ++
 drivers/net/ethernet/freescale/fman/inc/enet_ext.h |  199 +++
 drivers/net/ethernet/freescale/fman/inc/fm_ext.h   |  488 +++++++
 .../net/ethernet/freescale/fman/inc/fsl_fman_drv.h |   99 ++
 drivers/net/ethernet/freescale/fman/inc/service.h  |   55 +
 11 files changed, 3636 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/freescale/fman/fm.c
 create mode 100644 drivers/net/ethernet/freescale/fman/fm.h
 create mode 100644 drivers/net/ethernet/freescale/fman/fm_common.h
 create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.c
 create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.h
 create mode 100644 drivers/net/ethernet/freescale/fman/inc/enet_ext.h
 create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_ext.h
 create mode 100644 drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
 create mode 100644 drivers/net/ethernet/freescale/fman/inc/service.h

diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig
index 825a0d5..12c75bfd 100644
--- a/drivers/net/ethernet/freescale/fman/Kconfig
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -7,3 +7,38 @@ config FSL_FMAN
 		Freescale Data-Path Acceleration Architecture Frame Manager
 		(FMan) support
 
+if FSL_FMAN
+
+config FSL_FM_MAX_FRAME_SIZE
+	int "Maximum L2 frame size"
+	range 64 9600
+	default "1522"
+	help
+		Configure this in relation to the maximum possible MTU of your
+		network configuration. In particular, one would need to
+		increase this value in order to use jumbo frames.
+		FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS
+		(4 bytes) and one ETH+VLAN header (18 bytes), to a total of
+		22 bytes in excess of the desired L3 MTU.
+
+		Note that having too large a FSL_FM_MAX_FRAME_SIZE (much larger
+		than the actual MTU) may lead to buffer exhaustion, especially
+		in the case of badly fragmented datagrams on the Rx path.
+		Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the
+		actual MTU will lead to frames being dropped.
+
+config FSL_FM_RX_EXTRA_HEADROOM
+	int "Add extra headroom at beginning of data buffers"
+	range 16 384
+	default "64"
+	help
+		Configure this to tell the Frame Manager to reserve some extra
+		space at the beginning of a data buffer on the receive path,
+		before Internal Context fields are copied. This is in addition
+		to the private data area already reserved for driver internal
+		use. The provided value must be a multiple of 16.
+
+		This option does not affect in any way the layout of
+		transmitted buffers.
+
+endif	# FSL_FMAN
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index 55c91bd..f61d3a6 100644
--- a/drivers/net/ethernet/freescale/fman/Makefile
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -4,7 +4,7 @@ subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman/flib \
 
 obj-y		+= fsl_fman.o
 
-fsl_fman-objs	:= fman.o fm_muram.o
+fsl_fman-objs	:= fman.o fm_muram.o fm.o fm_drv.o
 
 obj-y	+= port/
 obj-y	+= mac/
diff --git a/drivers/net/ethernet/freescale/fman/fm.c b/drivers/net/ethernet/freescale/fman/fm.c
new file mode 100644
index 0000000..1654f48
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -0,0 +1,1406 @@
+/*
+ * Copyright 2008-2015 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "service.h"
+
+#include "fm_common.h"
+#include "fm.h"
+#include "fm_muram_ext.h"
+#include <asm/mpc85xx.h>
+#include "fsl_fman.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+static struct fm_intg_t *fill_intg_params(uint8_t major, uint8_t minor,
+					  struct fm_params_t *p_fm_param)
+{
+	struct fm_intg_t *intg;
+
+	intg = kzalloc(sizeof(*intg), GFP_KERNEL);
+	if (!intg)
+		return NULL;
+
+	/* P1023 - Major 4
+	 * P4080 - Major 2
+	 * P2041/P3041/P5020/P5040 - Major 3
+	 * Tx/Bx - Major 6
+	 */
+
+	switch (major) {
+	case FM_IP_BLOCK_P2_P3_P5:
+		intg->fm_muram_size		= 160 * 1024;
+		intg->fm_iram_size		= 64 * 1024;
+		intg->fm_num_of_ctrl		= 2;
+
+		intg->dma_thresh_max_commq	= 31;
+		intg->dma_thresh_max_buf	= 127;
+
+		intg->qmi_max_num_of_tnums	= 64;
+		intg->qmi_def_tnums_thresh	= 48;
+
+		intg->bmi_max_num_of_tasks	= 128;
+		intg->bmi_max_num_of_dmas	= 32;
+		intg->port_max_weight		= 16;
+
+		intg->fm_port_num_of_cg		= 256;
+
+		intg->num_of_rx_ports		= 6;
+		break;
+
+	case FM_IP_BLOCK_P4:
+
+		intg->fm_muram_size		= 160 * 1024;
+		intg->fm_iram_size		= 64 * 1024;
+		intg->fm_num_of_ctrl		= 2;
+
+		intg->dma_thresh_max_commq	= 31;
+		intg->dma_thresh_max_buf	= 127;
+
+		intg->qmi_max_num_of_tnums	= 64;
+		intg->qmi_def_tnums_thresh	= 48;
+
+		intg->bmi_max_num_of_tasks	= 128;
+		intg->bmi_max_num_of_dmas	= 32;
+		intg->port_max_weight		= 16;
+
+		intg->fm_port_num_of_cg		= 256;
+
+		intg->num_of_rx_ports		= 5;
+		break;
+
+	case FM_IP_BLOCK_P1:
+
+		intg->fm_muram_size		= 64 * 1024;
+		intg->fm_iram_size		= 32 * 1024;
+		intg->fm_num_of_ctrl		= 2;
+
+		intg->dma_thresh_max_commq	= 15;
+		intg->dma_thresh_max_buf	= 7;
+
+		intg->qmi_max_num_of_tnums	= 15;
+
+		intg->bmi_max_num_of_tasks	= 64;
+		intg->bmi_max_num_of_dmas	= 16;
+		intg->port_max_weight		= 4;
+
+		intg->fm_port_num_of_cg		= 32;
+
+		intg->num_of_rx_ports		= 2;
+		break;
+
+	case FM_IP_BLOCK_B_T:
+		intg->dma_thresh_max_commq	= 83;
+		intg->dma_thresh_max_buf	= 127;
+
+		intg->qmi_max_num_of_tnums	= 64;
+		intg->qmi_def_tnums_thresh	= 32;
+
+		intg->port_max_weight		= 16;
+		intg->fm_port_num_of_cg		= 256;
+
+		/* FManV3L */
+		if (minor == 1 || minor == 4) {
+			intg->fm_muram_size		= 192 * 1024;
+			intg->fm_num_of_ctrl		= 2;
+
+			intg->bmi_max_num_of_tasks	= 64;
+			intg->bmi_max_num_of_dmas	= 32;
+
+			intg->num_of_rx_ports		= 5;
+
+			if (minor == 1)
+				intg->fm_iram_size	= 32 * 1024;
+			else
+				intg->fm_iram_size	= 64 * 1024;
+		}
+		/* FManV3H */
+		else if (minor == 0 || minor == 2 || minor == 3) {
+			intg->fm_muram_size		= 384 * 1024;
+			intg->fm_iram_size		= 64 * 1024;
+			intg->fm_num_of_ctrl		= 4;
+
+			intg->bmi_max_num_of_tasks	= 128;
+			intg->bmi_max_num_of_dmas	= 84;
+
+			intg->num_of_rx_ports		= 8;
+		} else {
+			pr_err("Unsupported FManv3 version\n");
+			kfree(intg);
+			return NULL;
+		}
+
+		break;
+	default:
+		pr_err("Unsupported FMan version\n");
+		kfree(intg);
+		return NULL;
+	}
+
+	intg->bmi_max_fifo_size = intg->fm_muram_size;
+
+	return intg;
+}
+
+static int is_init_done(struct fman_cfg *p_fm_drv_parameters)
+{
+	/* Checks if FMan driver parameters were initialized */
+	if (!p_fm_drv_parameters)
+		return 0;
+	return -EINVAL;
+}
+
+static void free_init_resources(struct fm_t *p_fm)
+{
+	if (p_fm->cam_offset)
+		fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
+				  p_fm->cam_size);
+	if (p_fm->fifo_offset)
+		fm_muram_free_mem(p_fm->p_muram, p_fm->fifo_offset,
+				  p_fm->fifo_size);
+}
+
+static bool is_fman_ctrl_code_loaded(struct fm_t *p_fm)
+{
+	struct fm_iram_regs_t __iomem *p_iram;
+
+	p_iram = (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm->base_addr +
+						       FM_MM_IMEM);
+
+	return (bool)!!(in_be32(&p_iram->iready) & IRAM_READY);
+}
+
+static int check_fm_parameters(struct fm_t *p_fm)
+{
+	if (is_fman_ctrl_code_loaded(p_fm) && !p_fm->reset_on_init) {
+		pr_err("Old FMan CTRL code is loaded; FM must be reset!\n");
+		return -EDOM;
+	}
+	if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
+		if (!p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats ||
+		    (p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats >
+			DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) {
+			pr_err("axiDbgNumOfBeats has to be in the range 1 - %d\n",
+			       DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS);
+			return -EDOM;
+		}
+	}
+	if (p_fm->p_fm_drv_param->dma_cam_num_of_entries %
+	    DMA_CAM_UNITS) {
+		pr_err("dma_cam_num_of_entries has to be divisble by %d\n",
+		       DMA_CAM_UNITS);
+		return -EDOM;
+	}
+	if (p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer >
+	    p_fm->intg->dma_thresh_max_commq) {
+		pr_err("dma_comm_qtsh_asrt_emer can not be larger than %d\n",
+		       p_fm->intg->dma_thresh_max_commq);
+		return -EDOM;
+	}
+	if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >
+	    p_fm->intg->dma_thresh_max_commq) {
+		pr_err("dma_comm_qtsh_clr_emer can not be larger than %d\n",
+		       p_fm->intg->dma_thresh_max_commq);
+		return -EDOM;
+	}
+	if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >=
+	    p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer) {
+		pr_err("dma_comm_qtsh_clr_emer must be smaller than dma_comm_qtsh_asrt_emer\n");
+		return -EDOM;
+	}
+	if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
+		if (p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer >
+		    p_fm->intg->dma_thresh_max_buf) {
+			pr_err("dma_read_buf_tsh_asrt_emer can not be larger than %d\n",
+			       p_fm->intg->dma_thresh_max_buf);
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >
+		      p_fm->intg->dma_thresh_max_buf) {
+			pr_err("dma_read_buf_tsh_clr_emer can not be larger than %d\n",
+			       p_fm->intg->dma_thresh_max_buf);
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >=
+		      p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer) {
+			pr_err("dma_read_buf_tsh_clr_emer must be < dma_read_buf_tsh_asrt_emer\n");
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer >
+		      p_fm->intg->dma_thresh_max_buf) {
+			pr_err("dma_write_buf_tsh_asrt_emer can not be larger than %d\n",
+			       p_fm->intg->dma_thresh_max_buf);
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >
+		      p_fm->intg->dma_thresh_max_buf) {
+			pr_err("dma_write_buf_tsh_clr_emer can not be larger than %d\n",
+			       p_fm->intg->dma_thresh_max_buf);
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >=
+		      p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer) {
+			pr_err("dma_write_buf_tsh_clr_emer has to be less than dma_write_buf_tsh_asrt_emer\n");
+			return -EDOM;
+		}
+	} else {
+		if ((p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
+				E_FMAN_DMA_DBG_CNT_INT_READ_EM) ||
+			(p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
+				E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
+			(p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
+				E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT)) {
+			pr_err("dma_dbg_cnt_mode value not supported by this integration.\n");
+			return -EDOM;
+		}
+		if ((p_fm->p_fm_drv_param->dma_emergency_bus_select ==
+		       FM_DMA_MURAM_READ_EMERGENCY) ||
+		      (p_fm->p_fm_drv_param->dma_emergency_bus_select ==
+		       FM_DMA_MURAM_WRITE_EMERGENCY)) {
+			pr_err("emergencyBusSelect value not supported by this integration.\n");
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_stop_on_bus_error) {
+			pr_err("dma_stop_on_bus_error not supported by this integration.\n");
+			return -EDOM;
+		}
+		/* FM_AID_MODE_NO_TNUM_SW005 Errata workaround */
+		if (p_fm->p_fm_state_struct->rev_info.major_rev >= 6 &&
+		    p_fm->p_fm_drv_param->dma_aid_mode !=
+		    E_FMAN_DMA_AID_OUT_PORT_ID) {
+			pr_err("dma_aid_mode not supported by this integration.\n");
+			return -EDOM;
+		}
+		if (p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats) {
+			pr_err("dma_axi_dbg_num_of_beats not supported by this integration.\n");
+			return -EDOM;
+		}
+	}
+
+	if (!p_fm->p_fm_state_struct->fm_clk_freq) {
+		pr_err("fm_clk_freq must be set.\n");
+		return -EDOM;
+	}
+	if ((p_fm->p_fm_drv_param->dma_watchdog *
+	    p_fm->p_fm_state_struct->fm_clk_freq) > DMA_MAX_WATCHDOG) {
+		pr_err("dma_watchdog depends on FM clock. dma_watchdog(in microseconds)*clk (in Mhz), may not exceed 0x08%x\n",
+		       DMA_MAX_WATCHDOG);
+		return -EDOM;
+	}
+	if (p_fm->p_fm_state_struct->total_fifo_size % BMI_FIFO_UNITS) {
+		pr_err("total_fifo_size number has to be divisible by %d\n",
+		       BMI_FIFO_UNITS);
+	}
+	if (!p_fm->p_fm_state_struct->total_fifo_size ||
+	    (p_fm->p_fm_state_struct->total_fifo_size >
+	       p_fm->intg->bmi_max_fifo_size)) {
+		pr_err("total_fifo_size (curr - %d) has to be in the range 256 - %d\n",
+		       p_fm->p_fm_state_struct->total_fifo_size,
+		       p_fm->intg->bmi_max_fifo_size);
+		return -EDOM;
+	}
+	if (!p_fm->p_fm_state_struct->total_num_of_tasks ||
+	    (p_fm->p_fm_state_struct->total_num_of_tasks >
+	       p_fm->intg->bmi_max_num_of_tasks)) {
+		pr_err("total_num_of_tasks number has to be in the range 1 - %d\n",
+		       p_fm->intg->bmi_max_num_of_tasks);
+		return -EDOM;
+	}
+
+	if ((p_fm->p_fm_state_struct->rev_info.major_rev < 6) &&
+	    (!p_fm->p_fm_state_struct->max_num_of_open_dmas ||
+	     (p_fm->p_fm_state_struct->max_num_of_open_dmas >
+		p_fm->intg->bmi_max_num_of_dmas))) {
+		pr_err("max_num_of_open_dmas number has to be in the range 1 - %d\n",
+		       p_fm->intg->bmi_max_num_of_dmas);
+		return -EDOM;
+	}
+
+	if (p_fm->p_fm_drv_param->disp_limit_tsh > FPM_MAX_DISP_LIMIT) {
+		pr_err("disp_limit_tsh can't be greater than %d\n",
+		       FPM_MAX_DISP_LIMIT);
+		return -EDOM;
+	}
+	if (!p_fm->f_exception) {
+		pr_err("Exceptions callback not provided\n");
+		return -EDOM;
+	}
+	if (!p_fm->f_bus_error) {
+		pr_err("Exceptions callback not provided\n");
+		return -EDOM;
+	}
+	if ((p_fm->p_fm_state_struct->rev_info.major_rev == 2) &&
+	    (p_fm->p_fm_drv_param->dma_watchdog)) {
+		pr_err("watchdog!\n");
+		return -EINVAL;
+	}
+
+	/* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 Errata workaround */
+	if ((p_fm->p_fm_state_struct->rev_info.major_rev < 6) &&
+	    (p_fm->p_fm_state_struct->rev_info.major_rev != 4) &&
+	    (p_fm->p_fm_drv_param->halt_on_unrecov_ecc_err)) {
+		pr_err("HaltOnEccError!\n");
+		return -EINVAL;
+	}
+
+	if ((p_fm->p_fm_state_struct->rev_info.major_rev != 4) &&
+	    (p_fm->p_fm_state_struct->rev_info.major_rev < 6))
+		if (p_fm->p_fm_drv_param->tnum_aging_period) {
+			pr_err("Tnum aging!\n");
+			return -EINVAL;
+		}
+
+	/* check that user did not set revision-dependent exceptions */
+	if ((p_fm->p_fm_state_struct->rev_info.major_rev != 4) &&
+	    (p_fm->p_fm_state_struct->rev_info.major_rev < 6))
+		if (p_fm->user_set_exceptions & FM_EX_BMI_DISPATCH_RAM_ECC) {
+			pr_err("exception FM_EX_BMI_DISPATCH_RAM_ECC!\n");
+			return -EINVAL;
+		}
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev == 4)
+		if (p_fm->user_set_exceptions &
+		    (FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC)) {
+			pr_err("exception FM_EX_QMI_SINGLE_ECC/FM_EX_QMI_DOUBLE_ECC!\n");
+			return -EINVAL;
+		}
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev >= 6)
+		if (p_fm->user_set_exceptions & FM_EX_QMI_SINGLE_ECC) {
+			pr_err("exception FM_EX_QMI_SINGLE_ECC!\n");
+			return -EINVAL;
+		}
+
+	return 0;
+}
+
+static void bmi_err_event(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs;
+
+	event = fman_get_bmi_err_event(bmi_rg);
+
+	if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_BMI_STORAGE_PROFILE_ECC);
+	if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_BMI_LIST_RAM_ECC);
+	if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_BMI_STATISTICS_RAM_ECC);
+	if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_BMI_DISPATCH_RAM_ECC);
+}
+
+static void qmi_err_event(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_qmi_regs __iomem *qmi_rg = p_fm->p_fm_qmi_regs;
+
+	event = fman_get_qmi_err_event(qmi_rg);
+
+	if (event & QMI_ERR_INTR_EN_DOUBLE_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_QMI_DOUBLE_ECC);
+	if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF)
+		p_fm->f_exception(p_fm->h_app,
+				  FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID);
+}
+
+static void dma_err_event(struct fm_t *p_fm)
+{
+	uint32_t status;
+	struct fman_dma_regs __iomem *dma_rg = p_fm->p_fm_dma_regs;
+
+	status = fman_get_dma_err_event(dma_rg);
+
+	if (status & DMA_STATUS_FM_SPDAT_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_DMA_SINGLE_PORT_ECC);
+	if (status & DMA_STATUS_READ_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_DMA_READ_ECC);
+	if (status & DMA_STATUS_SYSTEM_WRITE_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_DMA_SYSTEM_WRITE_ECC);
+	if (status & DMA_STATUS_FM_WRITE_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_DMA_FM_WRITE_ECC);
+}
+
+static void fpm_err_event(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+	event = fman_get_fpm_err_event(fpm_rg);
+
+	if ((event & FPM_EV_MASK_DOUBLE_ECC) &&
+	    (event & FPM_EV_MASK_DOUBLE_ECC_EN))
+		p_fm->f_exception(p_fm->h_app, FM_EX_FPM_DOUBLE_ECC);
+	if ((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN))
+		p_fm->f_exception(p_fm->h_app, FM_EX_FPM_STALL_ON_TASKS);
+	if ((event & FPM_EV_MASK_SINGLE_ECC) &&
+	    (event & FPM_EV_MASK_SINGLE_ECC_EN))
+		p_fm->f_exception(p_fm->h_app, FM_EX_FPM_SINGLE_ECC);
+}
+
+static void muram_err_intr(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+	event = fman_get_muram_err_event(fpm_rg);
+
+	if (event & FPM_RAM_MURAM_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_MURAM_ECC);
+}
+
+static void iram_err_intr(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+	event = fman_get_iram_err_event(fpm_rg);
+
+	if (event & FPM_RAM_IRAM_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_IRAM_ECC);
+}
+
+static void qmi_event(struct fm_t *p_fm)
+{
+	uint32_t event;
+	struct fman_qmi_regs __iomem *qmi_rg = p_fm->p_fm_qmi_regs;
+
+	event = fman_get_qmi_event(qmi_rg);
+
+	if (event & QMI_INTR_EN_SINGLE_ECC)
+		p_fm->f_exception(p_fm->h_app, FM_EX_QMI_SINGLE_ECC);
+}
+
+static void unimplemented_isr(void __maybe_unused *h_src_arg)
+{
+	pr_err("Unimplemented ISR!\n");
+}
+
+static void enable_time_stamp(struct fm_t *p_fm)
+{
+	struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+	ASSERT(p_fm->p_fm_state_struct);
+	ASSERT(p_fm->p_fm_state_struct->count1_micro_bit);
+
+	fman_enable_time_stamp(fpm_rg,
+			       p_fm->p_fm_state_struct->count1_micro_bit,
+			       p_fm->p_fm_state_struct->fm_clk_freq);
+
+	p_fm->p_fm_state_struct->enabled_time_stamp = true;
+}
+
+static int clear_iram(struct fm_t *p_fm)
+{
+	struct fm_iram_regs_t __iomem *p_iram;
+	int i;
+
+	p_iram = (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm->base_addr +
+						       FM_MM_IMEM);
+
+	/* Enable the auto-increment */
+	out_be32(&p_iram->iadd, IRAM_IADD_AIE);
+	while (in_be32(&p_iram->iadd) != IRAM_IADD_AIE)
+		;
+
+	for (i = 0; i < (p_fm->intg->fm_iram_size / 4); i++)
+		out_be32(&p_iram->idata, 0xffffffff);
+
+	out_be32(&p_iram->iadd, p_fm->intg->fm_iram_size - 4);
+	/* Memory barrier */
+	mb();
+	while (in_be32(&p_iram->idata) != 0xffffffff)
+		;
+
+	return 0;
+}
+
+static int load_fman_ctrl_code(struct fm_t *p_fm)
+{
+	struct fm_iram_regs_t __iomem *p_iram;
+	int i;
+	uint32_t tmp;
+	uint8_t comp_to_16;
+
+	p_iram = (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm->base_addr +
+						       FM_MM_IMEM);
+
+	/* Enable the auto-increment */
+	out_be32(&p_iram->iadd, IRAM_IADD_AIE);
+	while (in_be32(&p_iram->iadd) != IRAM_IADD_AIE)
+		;
+
+	for (i = 0; i < (p_fm->firmware.size / 4); i++)
+		out_be32(&p_iram->idata, p_fm->firmware.p_code[i]);
+
+	comp_to_16 = (uint8_t)(p_fm->firmware.size % 16);
+	if (comp_to_16)
+		for (i = 0; i < ((16 - comp_to_16) / 4); i++)
+			out_be32(&p_iram->idata, 0xffffffff);
+
+	out_be32(&p_iram->iadd, p_fm->firmware.size - 4);
+	while (in_be32(&p_iram->iadd) != (p_fm->firmware.size - 4))
+		;
+
+	/* verify that writing has completed */
+	while (in_be32(&p_iram->idata) !=
+	       p_fm->firmware.p_code[(p_fm->firmware.size / 4) - 1])
+		;
+
+	if (p_fm->fw_verify) {
+		out_be32(&p_iram->iadd, IRAM_IADD_AIE);
+		while (in_be32(&p_iram->iadd) != IRAM_IADD_AIE)
+			;
+		for (i = 0; i < (p_fm->firmware.size / 4); i++) {
+			tmp = in_be32(&p_iram->idata);
+			if (tmp != p_fm->firmware.p_code[i]) {
+				pr_err("UCode write error : write 0x%x, read 0x%x\n",
+				       p_fm->firmware.p_code[i], tmp);
+				return -EIO;
+			}
+		}
+		out_be32(&p_iram->iadd, 0x0);
+	}
+
+	/* Enable patch from IRAM */
+	out_be32(&p_iram->iready, IRAM_READY);
+	usleep_range(1000, 1001);
+
+	pr_debug("FMan-Controller code (ver %d.%d.%d) loaded to IRAM.\n",
+		 ((uint16_t *)p_fm->firmware.p_code)[2],
+		 ((uint8_t *)p_fm->firmware.p_code)[6],
+		 ((uint8_t *)p_fm->firmware.p_code)[7]);
+
+	return 0;
+}
+
+static int fw_not_reset_erratum_bugzilla6173wa(struct fm_t *p_fm)
+{
+	struct fm_iram_regs_t __iomem *p_iram =
+	    (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm->base_addr +
+							 FM_MM_IMEM);
+	uint32_t tmp_reg;
+	uint32_t saved_spliodn[63];
+
+	/* write to IRAM first location the debug instruction */
+	out_be32(&p_iram->iadd, 0);
+	while (in_be32(&p_iram->iadd) != 0)
+		;
+
+	out_be32(&p_iram->idata, FM_FW_DEBUG_INSTRUCTION);
+
+	out_be32(&p_iram->iadd, 0);
+	while (in_be32(&p_iram->iadd) != 0)
+		;
+	while (in_be32(&p_iram->idata) != FM_FW_DEBUG_INSTRUCTION)
+		;
+
+	/* Enable patch from IRAM */
+	out_be32(&p_iram->iready, IRAM_READY);
+	/* Memory barrier */
+	mb();
+	usleep_range(100, 101);
+
+	memcpy_fromio((void *)saved_spliodn,
+		      (void __iomem *)p_fm->p_fm_bmi_regs->fmbm_spliodn,
+		      63 * sizeof(uint32_t));
+
+	/* reset FMAN */
+	out_be32(&p_fm->p_fm_fpm_regs->fm_rstc, FPM_RSTC_FM_RESET);
+	/* Memory barrier */
+	mb();
+	usleep_range(100, 101);
+
+	/* verify breakpoint debug status register */
+	tmp_reg = in_be32((uint32_t __iomem *)
+				UINT_TO_PTR(p_fm->base_addr +
+				FM_DEBUG_STATUS_REGISTER_OFFSET));
+	if (!tmp_reg) {
+		pr_err("Invalid debug status register value is '0'\n");
+		return -EINVAL;
+	}
+
+	/* Load FMan-Controller code to IRAM */
+
+	if (clear_iram(p_fm) != 0)
+		return -EINVAL;
+	if (p_fm->firmware.p_code && (load_fman_ctrl_code(p_fm) != 0))
+		return -EINVAL;
+	usleep_range(100, 101);
+
+	/* reset FMAN again to start the microcode */
+	out_be32(&p_fm->p_fm_fpm_regs->fm_rstc, FPM_RSTC_FM_RESET);
+	/* Memory barrier */
+	mb();
+	usleep_range(100, 101);
+	memcpy_toio((void __iomem *)p_fm->p_fm_bmi_regs->fmbm_spliodn,
+		    (void *)saved_spliodn, 63 * sizeof(uint32_t));
+
+	if (fman_is_qmi_halt_not_busy_state(p_fm->p_fm_qmi_regs)) {
+		fman_resume(p_fm->p_fm_fpm_regs);
+		/* Memory barrier */
+		mb();
+		usleep_range(100, 101);
+	}
+
+	return 0;
+}
+
+void fm_register_intr(struct fm_t *p_fm, enum fm_event_modules module,
+		      uint8_t mod_id, enum fm_intr_type intr_type,
+		      void (*f_isr)(void *h_src_arg), void *h_src_arg)
+{
+	int event = 0;
+
+	GET_FM_MODULE_EVENT(p_fm, module, mod_id, intr_type, event);
+	ASSERT(event < FM_EV_DUMMY_LAST);
+
+	/* register in local FM structure */
+	p_fm->intr_mng[event].f_isr = f_isr;
+	p_fm->intr_mng[event].h_src_handle = h_src_arg;
+}
+
+void fm_unregister_intr(struct fm_t *p_fm, enum fm_event_modules module,
+			uint8_t mod_id, enum fm_intr_type intr_type)
+{
+	int event = 0;
+
+	GET_FM_MODULE_EVENT(p_fm, module, mod_id, intr_type, event);
+	ASSERT(event < FM_EV_DUMMY_LAST);
+
+	p_fm->intr_mng[event].f_isr = unimplemented_isr;
+	p_fm->intr_mng[event].h_src_handle = NULL;
+}
+
+uint8_t fm_get_id(struct fm_t *p_fm)
+{
+	return p_fm->p_fm_state_struct->fm_id;
+}
+
+uint16_t fm_get_clock_freq(struct fm_t *p_fm)
+{
+	return p_fm->p_fm_state_struct->fm_clk_freq;
+}
+
+uint32_t fm_get_bmi_max_fifo_size(struct fm_t *p_fm)
+{
+	return p_fm->intg->bmi_max_fifo_size;
+}
+
+static int init_fm_dma(struct fm_t *p_fm)
+{
+	int err;
+
+	err = (int)fman_dma_init(p_fm->p_fm_dma_regs,
+				     p_fm->p_fm_drv_param);
+	if (err != 0)
+		return err;
+
+	/* Allocate MURAM for CAM */
+	p_fm->cam_size = (uint32_t)(p_fm->p_fm_drv_param->
+					dma_cam_num_of_entries *
+					DMA_CAM_SIZEOF_ENTRY);
+	p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram, p_fm->cam_size);
+	if (IS_ERR_VALUE(p_fm->cam_offset)) {
+		pr_err("MURAM alloc for DMA CAM failed\n");
+		return -ENOMEM;
+	}
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev == 2) {
+		uintptr_t cam_base_addr;
+
+		fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
+				  p_fm->cam_size);
+
+		p_fm->cam_size =
+			p_fm->p_fm_drv_param->dma_cam_num_of_entries * 72 + 128;
+		p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram, (uint32_t)
+						     p_fm->cam_size);
+		if (IS_ERR_VALUE(p_fm->cam_offset)) {
+			pr_err("MURAM alloc for DMA CAM failed\n");
+			return -ENOMEM;
+		}
+
+		cam_base_addr = fm_muram_offset_to_vbase(p_fm->p_muram,
+							 p_fm->cam_offset);
+		switch (p_fm->p_fm_drv_param->dma_cam_num_of_entries) {
+		case (8):
+			out_be32((uint32_t __iomem *)cam_base_addr,
+				 0xff000000);
+			break;
+		case (16):
+			out_be32((uint32_t __iomem *)cam_base_addr,
+				 0xffff0000);
+			break;
+		case (24):
+			out_be32((uint32_t __iomem *)cam_base_addr,
+				 0xffffff00);
+			break;
+		case (32):
+			out_be32((uint32_t __iomem *)cam_base_addr,
+				 0xffffffff);
+			break;
+		default:
+			pr_err("wrong dma_cam_num_of_entries\n");
+			return -EDOM;
+		}
+	}
+
+	p_fm->p_fm_drv_param->cam_base_addr = p_fm->cam_offset;
+
+	return 0;
+}
+
+static int init_fm_fpm(struct fm_t *p_fm)
+{
+	return (int)fman_fpm_init(p_fm->p_fm_fpm_regs,
+				  p_fm->p_fm_drv_param);
+}
+
+static int init_fm_bmi(struct fm_t *p_fm)
+{
+	return (int)fman_bmi_init(p_fm->p_fm_bmi_regs,
+				  p_fm->p_fm_drv_param);
+}
+
+static int init_fm_qmi(struct fm_t *p_fm)
+{
+	return (int)fman_qmi_init(p_fm->p_fm_qmi_regs,
+				  p_fm->p_fm_drv_param);
+}
+
+void *fm_config(struct fm_params_t *p_fm_param)
+{
+	struct fm_t *p_fm;
+	uintptr_t base_addr;
+
+	if (!((p_fm_param->firmware.p_code && p_fm_param->firmware.size) ||
+	      (!p_fm_param->firmware.p_code && !p_fm_param->firmware.size)))
+		return NULL;
+
+	base_addr = p_fm_param->base_addr;
+
+	/* Allocate FM structure */
+	p_fm = kzalloc(sizeof(*p_fm), GFP_KERNEL);
+	if (!p_fm)
+		return NULL;
+
+	p_fm->p_fm_state_struct = kzalloc(sizeof(*p_fm->p_fm_state_struct),
+						 GFP_KERNEL);
+	if (!p_fm->p_fm_state_struct) {
+		kfree(p_fm);
+		pr_err("FM Status structure\n");
+		return NULL;
+	}
+
+	/* Initialize FM parameters which will be kept by the driver */
+	p_fm->p_fm_state_struct->fm_id = p_fm_param->fm_id;
+
+	/* Allocate the FM driver's parameters structure */
+	p_fm->p_fm_drv_param = kzalloc(sizeof(*p_fm->p_fm_drv_param),
+						 GFP_KERNEL);
+	if (!p_fm->p_fm_drv_param) {
+		kfree(p_fm->p_fm_state_struct);
+		kfree(p_fm);
+		pr_err("FM driver parameters\n");
+		return NULL;
+	}
+
+	/* Initialize FM parameters which will be kept by the driver */
+	p_fm->p_fm_state_struct->fm_id = p_fm_param->fm_id;
+	p_fm->p_muram = p_fm_param->p_muram;
+	p_fm->h_app = p_fm_param->h_app;
+	p_fm->p_fm_state_struct->fm_clk_freq = p_fm_param->fm_clk_freq;
+	p_fm->f_exception = p_fm_param->f_exception;
+	p_fm->f_bus_error = p_fm_param->f_bus_error;
+	p_fm->p_fm_fpm_regs =
+	    (struct fman_fpm_regs __iomem *)UINT_TO_PTR(base_addr + FM_MM_FPM);
+	p_fm->p_fm_bmi_regs =
+	    (struct fman_bmi_regs __iomem *)UINT_TO_PTR(base_addr + FM_MM_BMI);
+	p_fm->p_fm_qmi_regs =
+	    (struct fman_qmi_regs __iomem *)UINT_TO_PTR(base_addr + FM_MM_QMI);
+	p_fm->p_fm_dma_regs =
+	    (struct fman_dma_regs __iomem *)UINT_TO_PTR(base_addr + FM_MM_DMA);
+	p_fm->p_fm_regs = (struct fman_regs __iomem *)
+			   UINT_TO_PTR(base_addr + FM_MM_BMI);
+	p_fm->base_addr = base_addr;
+
+	p_fm->spinlock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!p_fm->spinlock) {
+		kfree(p_fm->p_fm_drv_param);
+		kfree(p_fm->p_fm_state_struct);
+		kfree(p_fm);
+		pr_err("can't allocate spinlock!\n");
+		return NULL;
+	}
+
+	spin_lock_init(p_fm->spinlock);
+	fman_defconfig(p_fm->p_fm_drv_param);
+
+	/* overide macros dependent parameters */
+	if (p_fm->p_fm_state_struct->rev_info.major_rev == 4) {
+		p_fm->p_fm_drv_param->pedantic_dma = true;
+		p_fm->p_fm_drv_param->dma_aid_override = true;
+	}
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev != 4)
+		p_fm->p_fm_drv_param->qmi_deq_option_support = true;
+
+	p_fm->p_fm_state_struct->rams_ecc_enable = false;
+	p_fm->p_fm_state_struct->extra_fifo_pool_size = 0;
+	p_fm->p_fm_state_struct->exceptions = DFLT_EXCEPTIONS;
+	p_fm->reset_on_init = DFLT_RESET_ON_INIT;
+	p_fm->fw_verify = DFLT_VERIFY_UCODE;
+	p_fm->firmware.size = p_fm_param->firmware.size;
+	if (p_fm->firmware.size) {
+		p_fm->firmware.p_code = kmalloc(p_fm->firmware.size,
+						GFP_KERNEL);
+		if (!p_fm->firmware.p_code) {
+			kfree(p_fm->spinlock);
+			kfree(p_fm->p_fm_state_struct);
+			kfree(p_fm->p_fm_drv_param);
+			kfree(p_fm);
+			pr_err("FM firmware code\n");
+			return NULL;
+		}
+		memcpy(p_fm->firmware.p_code,
+		       p_fm_param->firmware.p_code, p_fm->firmware.size);
+	}
+	/* read revision */
+	/* Chip dependent, will be configured in Init */
+	fman_get_revision(p_fm->p_fm_fpm_regs,
+			  &p_fm->p_fm_state_struct->rev_info.major_rev,
+			  &p_fm->p_fm_state_struct->rev_info.minor_rev);
+
+	p_fm->intg =
+		fill_intg_params(p_fm->p_fm_state_struct->rev_info.major_rev,
+				 p_fm->p_fm_state_struct->rev_info.minor_rev,
+				 p_fm_param);
+	if (!p_fm->intg) {
+			kfree(p_fm->firmware.p_code);
+			kfree(p_fm->spinlock);
+			kfree(p_fm->p_fm_state_struct);
+			kfree(p_fm->p_fm_drv_param);
+			kfree(p_fm);
+			return NULL;
+	}
+
+	/* FM_AID_MODE_NO_TNUM_SW005 Errata workaround */
+	if (p_fm->p_fm_state_struct->rev_info.major_rev >= 6)
+		p_fm->p_fm_drv_param->dma_aid_mode = FM_DMA_AID_OUT_PORT_ID;
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev != 4)
+		p_fm->p_fm_drv_param->qmi_def_tnums_thresh =
+		    p_fm->intg->qmi_def_tnums_thresh;
+
+	p_fm->p_fm_state_struct->total_fifo_size = 0;
+	p_fm->p_fm_state_struct->total_num_of_tasks =
+	(u8)DFLT_TOTAL_NUM_OF_TASKS(
+		p_fm->p_fm_state_struct->rev_info.major_rev,
+		p_fm->p_fm_state_struct->rev_info.minor_rev,
+		p_fm->intg->bmi_max_num_of_tasks);
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
+		p_fm->p_fm_state_struct->max_num_of_open_dmas =
+		p_fm->intg->bmi_max_num_of_dmas;
+		p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer =
+		(u8)DFLT_DMA_COMM_Q_LOW(p_fm->p_fm_state_struct->rev_info.
+				    major_rev,
+				    p_fm->intg->dma_thresh_max_commq);
+
+		p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer =
+		(u8)DFLT_DMA_COMM_Q_HIGH(p_fm->p_fm_state_struct->rev_info.
+				     major_rev,
+				     p_fm->intg->dma_thresh_max_commq);
+
+		p_fm->p_fm_drv_param->dma_cam_num_of_entries =
+		DFLT_DMA_CAM_NUM_OF_ENTRIES(p_fm->p_fm_state_struct->
+					    rev_info.major_rev);
+		p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer =
+		(u8)DFLT_DMA_READ_INT_BUF_LOW(p_fm->intg->dma_thresh_max_buf);
+
+		p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer =
+		(u8)DFLT_DMA_READ_INT_BUF_HIGH(p_fm->intg->dma_thresh_max_buf);
+
+		p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer =
+		(u8)DFLT_DMA_WRITE_INT_BUF_LOW(p_fm->intg->dma_thresh_max_buf);
+
+		p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer =
+		(u8)DFLT_DMA_WRITE_INT_BUF_HIGH(p_fm->intg->dma_thresh_max_buf);
+
+		p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats =
+		DFLT_AXI_DBG_NUM_OF_BEATS;
+	}
+
+	p_fm->p_fm_drv_param->tnum_aging_period = 0;
+	p_fm->tnum_aging_period = p_fm->p_fm_drv_param->tnum_aging_period;
+
+	return p_fm;
+}
+
+int fm_init(struct fm_t *p_fm)
+{
+	struct fman_cfg *p_fm_drv_param = NULL;
+	int err = 0;
+	int i;
+	struct fm_revision_info_t rev_info;
+	struct fman_rg fman_rg;
+	int ret, ret_err;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (!ret)
+		return -EINVAL;
+
+	fman_rg.bmi_rg = p_fm->p_fm_bmi_regs;
+	fman_rg.qmi_rg = p_fm->p_fm_qmi_regs;
+	fman_rg.fpm_rg = p_fm->p_fm_fpm_regs;
+	fman_rg.dma_rg = p_fm->p_fm_dma_regs;
+
+	p_fm->p_fm_state_struct->count1_micro_bit = FM_TIMESTAMP_1_USEC_BIT;
+	p_fm->p_fm_drv_param->num_of_fman_ctrl_evnt_regs =
+	    FM_NUM_OF_FMAN_CTRL_EVENT_REGS;
+
+	/* if user didn't configured total_fifo_size -
+	 * (total_fifo_size=0) we configure default
+	 * according to chip. otherwise, we use user's configuration.
+	 */
+	if (p_fm->p_fm_state_struct->total_fifo_size == 0)
+		p_fm->p_fm_state_struct->total_fifo_size =
+		DFLT_TOTAL_FIFO_SIZE(
+				p_fm->p_fm_state_struct->rev_info.major_rev,
+				p_fm->p_fm_state_struct->rev_info.minor_rev);
+
+	ret_err = check_fm_parameters(p_fm);
+	if (ret_err)
+		return ret_err;
+
+	p_fm_drv_param = p_fm->p_fm_drv_param;
+
+	fm_get_revision(p_fm, &rev_info);
+
+	/* clear revision-dependent non existing exception */
+	if ((rev_info.major_rev != 4) && (rev_info.major_rev < 6))
+		p_fm->p_fm_state_struct->exceptions &=
+		    ~FM_EX_BMI_DISPATCH_RAM_ECC;
+
+	if (rev_info.major_rev == 4)
+		p_fm->p_fm_state_struct->exceptions &=
+		    ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC);
+
+	if (rev_info.major_rev >= 6)
+		p_fm->p_fm_state_struct->exceptions &= ~FM_EX_QMI_SINGLE_ECC;
+
+	/* clear CPG */
+	memset_io(UINT_TO_PTR(p_fm->base_addr + FM_MM_CGP), 0,
+		  p_fm->intg->fm_port_num_of_cg);
+
+	/* add to the default exceptions the user's definitions */
+	p_fm->p_fm_state_struct->exceptions |= p_fm->user_set_exceptions;
+
+	if (p_fm->p_fm_state_struct->rev_info.major_rev < 6 &&
+	    p_fm->p_fm_state_struct->rev_info.major_rev != 4 &&
+	    p_fm->reset_on_init) {
+		err = fw_not_reset_erratum_bugzilla6173wa(p_fm);
+		if (err != 0)
+			return err;
+	} else {
+		/* Reset the FM if required. */
+		if (p_fm->reset_on_init) {
+			u32 svr = mfspr(SPRN_SVR);
+
+			if (((SVR_SOC_VER(svr) == SVR_T4240 &&
+			      SVR_REV(svr) > 0x10)) ||
+				((SVR_SOC_VER(svr) == SVR_T4160 &&
+				  SVR_REV(svr) > 0x10)) ||
+				((SVR_SOC_VER(svr) == SVR_T4080 &&
+				  SVR_REV(svr) > 0x10)) ||
+				(SVR_SOC_VER(svr) == SVR_T2080) ||
+				(SVR_SOC_VER(svr) == SVR_T2081)) {
+				pr_debug("Hack: No FM reset!\n");
+			} else {
+				out_be32(&p_fm->p_fm_fpm_regs->fm_rstc,
+					 FPM_RSTC_FM_RESET);
+				/* Memory barrier */
+				mb();
+				usleep_range(100, 101);
+			}
+
+			if (fman_is_qmi_halt_not_busy_state(
+				p_fm->p_fm_qmi_regs)) {
+				fman_resume(p_fm->p_fm_fpm_regs);
+				usleep_range(100, 101);
+			}
+		}
+
+		/* Load FMan-Controller code to IRAM */
+
+		if (clear_iram(p_fm) != 0)
+			return -EINVAL;
+		if (p_fm->firmware.p_code && (load_fman_ctrl_code(p_fm) != 0))
+			return -EINVAL;
+	}
+
+	/* General FM driver initialization */
+	for (i = 0; i < FM_EV_DUMMY_LAST; i++)
+		p_fm->intr_mng[i].f_isr = unimplemented_isr;
+
+	p_fm_drv_param->exceptions = p_fm->p_fm_state_struct->exceptions;
+
+	/* Init DMA Registers */
+
+	err = init_fm_dma(p_fm);
+	if (err != 0) {
+		free_init_resources(p_fm);
+		return err;
+	}
+
+	/* Init FPM Registers */
+
+	err = init_fm_fpm(p_fm);
+	if (err != 0) {
+		free_init_resources(p_fm);
+		return err;
+	}
+
+	/* define common resources */
+	/* allocate MURAM for FIFO according to total size */
+	p_fm->fifo_offset = fm_muram_alloc(p_fm->p_muram,
+					   p_fm->p_fm_state_struct->
+					   total_fifo_size);
+	if (IS_ERR_VALUE(p_fm->cam_offset)) {
+		free_init_resources(p_fm);
+		pr_err("MURAM alloc for BMI FIFO failed\n");
+		return -ENOMEM;
+	}
+
+	p_fm_drv_param->fifo_base_addr = p_fm->fifo_offset;
+	p_fm_drv_param->total_fifo_size =
+		p_fm->p_fm_state_struct->total_fifo_size;
+	p_fm_drv_param->total_num_of_tasks =
+		p_fm->p_fm_state_struct->total_num_of_tasks;
+	p_fm_drv_param->clk_freq = p_fm->p_fm_state_struct->fm_clk_freq;
+
+	/* Init BMI Registers */
+	err = init_fm_bmi(p_fm);
+	if (err != 0) {
+		free_init_resources(p_fm);
+		return err;
+	}
+
+	/* Init QMI Registers */
+	err = init_fm_qmi(p_fm);
+	if (err != 0) {
+		free_init_resources(p_fm);
+		return err;
+	}
+
+	err = (int)fman_enable(&fman_rg, p_fm_drv_param);
+	if (err != 0)
+		return err;
+
+	enable_time_stamp(p_fm);
+
+	kfree(p_fm->firmware.p_code);
+	p_fm->firmware.p_code = NULL;
+
+	kfree(p_fm->p_fm_drv_param);
+	p_fm->p_fm_drv_param = NULL;
+
+	return 0;
+}
+
+int fm_free(struct fm_t *p_fm)
+{
+	struct fman_rg fman_rg;
+
+	fman_rg.bmi_rg = p_fm->p_fm_bmi_regs;
+	fman_rg.qmi_rg = p_fm->p_fm_qmi_regs;
+	fman_rg.fpm_rg = p_fm->p_fm_fpm_regs;
+	fman_rg.dma_rg = p_fm->p_fm_dma_regs;
+
+	fman_free_resources(&fman_rg);
+
+	kfree(p_fm->spinlock);
+
+	if (p_fm->p_fm_drv_param) {
+		kfree(p_fm->firmware.p_code);
+		kfree(p_fm->p_fm_drv_param);
+		p_fm->p_fm_drv_param = NULL;
+	}
+
+	free_init_resources(p_fm);
+
+	kfree(p_fm->p_fm_state_struct);
+
+	kfree(p_fm);
+
+	return 0;
+}
+
+int fm_cfg_reset_on_init(struct fm_t *p_fm, bool enable)
+{
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (!ret)
+		return -EINVAL;
+
+	p_fm->reset_on_init = enable;
+
+	return 0;
+}
+
+int fm_cfg_total_fifo_size(struct fm_t *p_fm, uint32_t total_fifo_size)
+{
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (!ret)
+		return -EINVAL;
+
+	p_fm->p_fm_state_struct->total_fifo_size = total_fifo_size;
+
+	return 0;
+}
+
+int fm_cfg_dma_aid_override(struct fm_t *p_fm, bool aid_override)
+{
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (!ret)
+		return -EINVAL;
+
+	p_fm->p_fm_drv_param->dma_aid_override = aid_override;
+
+	return 0;
+}
+
+/* Macro for calling MAC interrupt handler */
+#define FM_M_CALL_MAC_ISR(_p_fm, _id)    \
+	(_p_fm->intr_mng[(enum fm_inter_module_event)(FM_EV_MAC0 + _id)]. \
+	f_isr(p_fm->intr_mng[(enum fm_inter_module_event)(FM_EV_MAC0 + _id)] \
+	.h_src_handle))
+
+void fm_event_isr(struct fm_t *p_fm)
+{
+	uint32_t pending;
+	int ret;
+	struct fman_fpm_regs __iomem *fpm_rg;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (ret)
+		return;
+
+	fpm_rg = p_fm->p_fm_fpm_regs;
+
+	/* normal interrupts */
+	pending = fman_get_normal_pending(fpm_rg);
+	if (!pending)
+		return;
+
+	if (pending & INTR_EN_QMI)
+		qmi_event(p_fm);
+	if (pending & INTR_EN_PRS)
+		p_fm->intr_mng[FM_EV_PRS].f_isr(p_fm->intr_mng[FM_EV_PRS].
+						 h_src_handle);
+	if (pending & INTR_EN_TMR)
+		p_fm->intr_mng[FM_EV_TMR].f_isr(p_fm->intr_mng[FM_EV_TMR].
+						 h_src_handle);
+
+	/* MAC interrupts */
+	if (pending & INTR_EN_MAC0)
+		FM_M_CALL_MAC_ISR(p_fm, 0);
+	if (pending & INTR_EN_MAC1)
+		FM_M_CALL_MAC_ISR(p_fm, 1);
+	if (pending & INTR_EN_MAC2)
+		FM_M_CALL_MAC_ISR(p_fm, 2);
+	if (pending & INTR_EN_MAC3)
+		FM_M_CALL_MAC_ISR(p_fm, 3);
+	if (pending & INTR_EN_MAC4)
+		FM_M_CALL_MAC_ISR(p_fm, 4);
+	if (pending & INTR_EN_MAC5)
+		FM_M_CALL_MAC_ISR(p_fm, 5);
+	if (pending & INTR_EN_MAC6)
+		FM_M_CALL_MAC_ISR(p_fm, 6);
+	if (pending & INTR_EN_MAC7)
+		FM_M_CALL_MAC_ISR(p_fm, 7);
+	if (pending & INTR_EN_MAC8)
+		FM_M_CALL_MAC_ISR(p_fm, 8);
+	if (pending & INTR_EN_MAC9)
+		FM_M_CALL_MAC_ISR(p_fm, 9);
+}
+
+/* Macro for calling MAC error interrupt handler */
+#define FM_M_CALL_MAC_ERR_ISR(_p_fm, _id) \
+	(_p_fm->intr_mng[(enum fm_inter_module_event)(FM_EV_ERR_MAC0 + _id)]. \
+	f_isr(p_fm->intr_mng[(enum fm_inter_module_event)\
+	(FM_EV_ERR_MAC0 + _id)].h_src_handle))
+int fm_error_isr(struct fm_t *p_fm)
+{
+	uint32_t pending;
+	struct fman_fpm_regs __iomem *fpm_rg;
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (ret)
+		return ret;
+
+	fpm_rg = p_fm->p_fm_fpm_regs;
+
+	/* error interrupts */
+	pending = fman_get_fpm_error_interrupts(fpm_rg);
+	if (!pending)
+		return -EINVAL;
+
+	if (pending & ERR_INTR_EN_BMI)
+		bmi_err_event(p_fm);
+	if (pending & ERR_INTR_EN_QMI)
+		qmi_err_event(p_fm);
+	if (pending & ERR_INTR_EN_FPM)
+		fpm_err_event(p_fm);
+	if (pending & ERR_INTR_EN_DMA)
+		dma_err_event(p_fm);
+	if (pending & ERR_INTR_EN_IRAM)
+		iram_err_intr(p_fm);
+	if (pending & ERR_INTR_EN_MURAM)
+		muram_err_intr(p_fm);
+	if (pending & ERR_INTR_EN_PRS)
+		p_fm->intr_mng[FM_EV_ERR_PRS].f_isr(p_fm->
+						     intr_mng[FM_EV_ERR_PRS].
+						     h_src_handle);
+
+	/* MAC error interrupts */
+	if (pending & ERR_INTR_EN_MAC0)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 0);
+	if (pending & ERR_INTR_EN_MAC1)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 1);
+	if (pending & ERR_INTR_EN_MAC2)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 2);
+	if (pending & ERR_INTR_EN_MAC3)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 3);
+	if (pending & ERR_INTR_EN_MAC4)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 4);
+	if (pending & ERR_INTR_EN_MAC5)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 5);
+	if (pending & ERR_INTR_EN_MAC6)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 6);
+	if (pending & ERR_INTR_EN_MAC7)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 7);
+	if (pending & ERR_INTR_EN_MAC8)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 8);
+	if (pending & ERR_INTR_EN_MAC9)
+		FM_M_CALL_MAC_ERR_ISR(p_fm, 9);
+
+	return 0;
+}
+
+int fm_disable_rams_ecc(struct fm_t *p_fm)
+{
+	bool explicit_disable = false;
+	struct fman_fpm_regs __iomem *fpm_rg;
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (ret)
+		return ret;
+
+	fpm_rg = p_fm->p_fm_fpm_regs;
+
+	if (!p_fm->p_fm_state_struct->internal_call)
+		explicit_disable = true;
+	p_fm->p_fm_state_struct->internal_call = false;
+
+	/* if rams are already disabled, or if rams were explicitly enabled and
+	 *  are currently called indirectly (not explicitly), ignore this call.
+	 */
+	if (!p_fm->p_fm_state_struct->rams_ecc_enable ||
+	    (p_fm->p_fm_state_struct->explicit_enable && !explicit_disable))
+		return 0;
+	if (p_fm->p_fm_state_struct->explicit_enable)
+		/* This is the case were both explicit are true.
+		 * Turn off this flag for cases were following
+		 * ramsEnable routines are called
+		 */
+		p_fm->p_fm_state_struct->explicit_enable = false;
+
+	fman_enable_rams_ecc(fpm_rg);
+	p_fm->p_fm_state_struct->rams_ecc_enable = false;
+
+	return 0;
+}
+
+int fm_set_exception(struct fm_t *p_fm, enum fm_exceptions exception,
+		     bool enable)
+{
+	uint32_t bit_mask = 0;
+	enum fman_exceptions fsl_exception;
+	struct fman_rg fman_rg;
+	int ret;
+
+	ret = is_init_done(p_fm->p_fm_drv_param);
+	if (ret)
+		return ret;
+
+	fman_rg.bmi_rg = p_fm->p_fm_bmi_regs;
+	fman_rg.qmi_rg = p_fm->p_fm_qmi_regs;
+	fman_rg.fpm_rg = p_fm->p_fm_fpm_regs;
+	fman_rg.dma_rg = p_fm->p_fm_dma_regs;
+
+	GET_EXCEPTION_FLAG(bit_mask, exception);
+	if (bit_mask) {
+		if (enable)
+			p_fm->p_fm_state_struct->exceptions |= bit_mask;
+		else
+			p_fm->p_fm_state_struct->exceptions &= ~bit_mask;
+
+		FMAN_EXCEPTION_TRANS(fsl_exception, exception);
+
+		return (int)fman_set_exception(&fman_rg,
+					       fsl_exception, enable);
+	} else {
+		pr_err("Undefined exceptioni\n");
+		return -EDOM;
+	}
+
+	return 0;
+}
+
+void fm_get_revision(struct fm_t *p_fm,
+		     struct fm_revision_info_t *p_fm_rev)
+{
+	p_fm_rev->major_rev = p_fm->p_fm_state_struct->rev_info.major_rev;
+	p_fm_rev->minor_rev = p_fm->p_fm_state_struct->rev_info.minor_rev;
+}
diff --git a/drivers/net/ethernet/freescale/fman/fm.h b/drivers/net/ethernet/freescale/fman/fm.h
new file mode 100644
index 0000000..5513933
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.h
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2008-2015 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 __FM_H
+#define __FM_H
+
+#include "service.h"
+#include "fm_ext.h"
+
+#include "fsl_fman.h"
+
+/* Prevents the use of TX port 1 with OP port 0 for FM Major Rev 4 (P1023) */
+#define FM_LOW_END_RESTRICTION
+
+/* Hardware defines */
+#define FM_MAX_NUM_OF_HW_PORT_IDS           64
+#define FM_MAX_NUM_OF_MACS	10
+
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS		4
+
+#define GET_EXCEPTION_FLAG(bit_mask, exception)			\
+do {									\
+	switch ((int)exception) {					\
+	case FM_EX_DMA_BUS_ERROR:					\
+		bit_mask = FM_EX_DMA_BUS_ERROR;			\
+		break;							\
+	case FM_EX_DMA_SINGLE_PORT_ECC:				\
+		bit_mask = FM_EX_DMA_SINGLE_PORT_ECC;			\
+		break;							\
+	case FM_EX_DMA_READ_ECC:					\
+		bit_mask = FM_EX_DMA_READ_ECC;				\
+		break;							\
+	case FM_EX_DMA_SYSTEM_WRITE_ECC:				\
+		bit_mask = FM_EX_DMA_SYSTEM_WRITE_ECC;			\
+		break;							\
+	case FM_EX_DMA_FM_WRITE_ECC:					\
+		bit_mask = FM_EX_DMA_FM_WRITE_ECC;			\
+		break;							\
+	case FM_EX_FPM_STALL_ON_TASKS:					\
+		bit_mask = FM_EX_FPM_STALL_ON_TASKS;			\
+		break;							\
+	case FM_EX_FPM_SINGLE_ECC:					\
+		bit_mask = FM_EX_FPM_SINGLE_ECC;			\
+		break;							\
+	case FM_EX_FPM_DOUBLE_ECC:					\
+		bit_mask = FM_EX_FPM_DOUBLE_ECC;			\
+		break;							\
+	case FM_EX_QMI_SINGLE_ECC:					\
+		bit_mask = FM_EX_QMI_SINGLE_ECC;			\
+		break;							\
+	case FM_EX_QMI_DOUBLE_ECC:					\
+		bit_mask = FM_EX_QMI_DOUBLE_ECC;			\
+		break;							\
+	case FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:			\
+		bit_mask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;		\
+		break;							\
+	case FM_EX_BMI_LIST_RAM_ECC:					\
+		bit_mask = FM_EX_BMI_LIST_RAM_ECC;			\
+		break;							\
+	case FM_EX_BMI_STORAGE_PROFILE_ECC:				\
+		bit_mask = FM_EX_BMI_STORAGE_PROFILE_ECC;		\
+		break;							\
+	case FM_EX_BMI_STATISTICS_RAM_ECC:				\
+		bit_mask = FM_EX_BMI_STATISTICS_RAM_ECC;		\
+		break;							\
+	case FM_EX_BMI_DISPATCH_RAM_ECC:				\
+		bit_mask = FM_EX_BMI_DISPATCH_RAM_ECC;			\
+		break;							\
+	case FM_EX_IRAM_ECC:						\
+		bit_mask = FM_EX_IRAM_ECC;				\
+		break;							\
+	case FM_EX_MURAM_ECC:						\
+		bit_mask = FM_EX_MURAM_ECC;				\
+		break;							\
+	default:							\
+		bit_mask = 0;						\
+		break;							\
+	}								\
+} while (0)
+
+#define GET_FM_MODULE_EVENT(_p_fm, _mod, _id, _intr_type, _event)	\
+do {									\
+	switch (_mod) {							\
+	case (FM_MOD_PRS):						\
+		if (_id)						\
+			_event = FM_EV_DUMMY_LAST;			\
+		else							\
+			event = (_intr_type == FM_INTR_TYPE_ERR) ?	\
+			FM_EV_ERR_PRS : FM_EV_PRS;			\
+		break;							\
+	case (FM_MOD_TMR):						\
+		if (_id)						\
+			_event = FM_EV_DUMMY_LAST;			\
+		else							\
+			_event = (_intr_type == FM_INTR_TYPE_ERR) ?	\
+			FM_EV_DUMMY_LAST : FM_EV_TMR;			\
+		break;							\
+	case (FM_MOD_MAC):						\
+			_event = (_intr_type == FM_INTR_TYPE_ERR) ?	\
+			(FM_EV_ERR_MAC0 + _id) :			\
+			(FM_EV_MAC0 + _id);				\
+		break;							\
+	case (FM_MOD_FMAN_CTRL):					\
+		if (_intr_type == FM_INTR_TYPE_ERR)			\
+			_event = FM_EV_DUMMY_LAST;			\
+		else							\
+			_event = (FM_EV_FMAN_CTRL_0 + _id);		\
+		break;							\
+	default:							\
+		_event = FM_EV_DUMMY_LAST;				\
+		break;							\
+	}								\
+} while (0)
+
+#define FMAN_EXCEPTION_TRANS(fsl_exception, _exception) do {\
+switch ((int)_exception) {\
+case  FM_EX_DMA_BUS_ERROR:                    \
+	fsl_exception =  E_FMAN_EX_DMA_BUS_ERROR;\
+	break;    \
+case  FM_EX_DMA_READ_ECC:                    \
+	fsl_exception =  E_FMAN_EX_DMA_READ_ECC;\
+	break;        \
+case  FM_EX_DMA_SYSTEM_WRITE_ECC:                \
+	fsl_exception =  E_FMAN_EX_DMA_SYSTEM_WRITE_ECC;\
+	break;    \
+case  FM_EX_DMA_FM_WRITE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_DMA_FM_WRITE_ECC;\
+	break;    \
+case  FM_EX_FPM_STALL_ON_TASKS:                \
+	fsl_exception =  E_FMAN_EX_FPM_STALL_ON_TASKS;\
+	break;    \
+case  FM_EX_FPM_SINGLE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_FPM_SINGLE_ECC;\
+	break;    \
+case  FM_EX_FPM_DOUBLE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_FPM_DOUBLE_ECC;\
+	break;    \
+case  FM_EX_QMI_SINGLE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_QMI_SINGLE_ECC;\
+	break;    \
+case  FM_EX_QMI_DOUBLE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_QMI_DOUBLE_ECC;\
+	break;    \
+case  FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:            \
+	fsl_exception =  E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;\
+	break; \
+case  FM_EX_BMI_LIST_RAM_ECC:                    \
+	fsl_exception =  E_FMAN_EX_BMI_LIST_RAM_ECC;\
+	break;    \
+case  FM_EX_BMI_STORAGE_PROFILE_ECC:                    \
+	fsl_exception =  E_FMAN_EX_BMI_STORAGE_PROFILE_ECC;\
+	break;    \
+case  FM_EX_BMI_STATISTICS_RAM_ECC:                \
+	fsl_exception =  E_FMAN_EX_BMI_STATISTICS_RAM_ECC;\
+	break; \
+case  FM_EX_BMI_DISPATCH_RAM_ECC:                \
+	fsl_exception =  E_FMAN_EX_BMI_DISPATCH_RAM_ECC;\
+	break;    \
+case  FM_EX_IRAM_ECC:                        \
+	fsl_exception =  E_FMAN_EX_IRAM_ECC;\
+	break;        \
+case  FM_EX_MURAM_ECC:                    \
+	fsl_exception =  E_FMAN_EX_MURAM_ECC;\
+	break;        \
+default: \
+	fsl_exception =  E_FMAN_EX_DMA_BUS_ERROR; break;    \
+} \
+} while (0)
+
+/* defaults */
+#define DFLT_EXCEPTIONS	\
+	((FM_EX_DMA_BUS_ERROR)            | \
+	(FM_EX_DMA_READ_ECC)              | \
+	(FM_EX_DMA_SYSTEM_WRITE_ECC)      | \
+	(FM_EX_DMA_FM_WRITE_ECC)          | \
+	(FM_EX_FPM_STALL_ON_TASKS)        | \
+	(FM_EX_FPM_SINGLE_ECC)            | \
+	(FM_EX_FPM_DOUBLE_ECC)            | \
+	(FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID) | \
+	(FM_EX_BMI_LIST_RAM_ECC)          | \
+	(FM_EX_BMI_STORAGE_PROFILE_ECC)   | \
+	(FM_EX_BMI_STATISTICS_RAM_ECC)    | \
+	(FM_EX_IRAM_ECC)                  | \
+	(FM_EX_MURAM_ECC)                 | \
+	(FM_EX_BMI_DISPATCH_RAM_ECC)      | \
+	(FM_EX_QMI_DOUBLE_ECC)            | \
+	(FM_EX_QMI_SINGLE_ECC))
+
+#define DFLT_AXI_DBG_NUM_OF_BEATS            1
+#define DFLT_RESET_ON_INIT                 false
+/* do not change! if changed, must be disabled for rev1 ! */
+#define DFLT_VERIFY_UCODE                 false
+
+#define DFLT_DMA_READ_INT_BUF_LOW(dma_thresh_max_buf)	\
+	((dma_thresh_max_buf + 1) / 2)
+#define DFLT_DMA_READ_INT_BUF_HIGH(dma_thresh_max_buf)	\
+	((dma_thresh_max_buf + 1) * 3 / 4)
+#define DFLT_DMA_WRITE_INT_BUF_LOW(dma_thresh_max_buf)	\
+	((dma_thresh_max_buf + 1) / 2)
+#define DFLT_DMA_WRITE_INT_BUF_HIGH(dma_thresh_max_buf)\
+	((dma_thresh_max_buf + 1) * 3 / 4)
+#define DFLT_DMA_COMM_Q_LOW(major, dma_thresh_max_commq)	\
+	((major == 6) ? 0x2A : ((dma_thresh_max_commq + 1) / 2))
+#define DFLT_DMA_COMM_Q_HIGH(major, dma_thresh_max_commq)	\
+	((major == 6) ? 0x3f : ((dma_thresh_max_commq + 1) * 3 / 4))
+#define DFLT_TOTAL_NUM_OF_TASKS(major, minor, bmi_max_num_of_tasks)	\
+	((major == 6) ? ((minor == 1 || minor == 4) ? 59 : 124) :	\
+	bmi_max_num_of_tasks)
+
+#define DFLT_DMA_CAM_NUM_OF_ENTRIES(major)	(major == 6 ? 64 : 32)
+
+#define DFLT_TOTAL_FIFO_SIZE(major, minor)			\
+	((major == 6) ?						\
+	((minor == 1 || minor == 4) ? (156 * 1024) : (295 * 1024)) :	\
+	(((major == 2) || (major == 5)) ?			\
+	(100 * 1024) : ((major == 4) ?			\
+	(46 * 1024) : (122 * 1024))))
+
+#define FM_TIMESTAMP_1_USEC_BIT             8
+
+/* Defines used for enabling/disabling FM interrupts */
+#define ERR_INTR_EN_DMA         0x00010000
+#define ERR_INTR_EN_FPM         0x80000000
+#define ERR_INTR_EN_BMI         0x00800000
+#define ERR_INTR_EN_QMI         0x00400000
+#define ERR_INTR_EN_PRS         0x00200000
+#define ERR_INTR_EN_MURAM       0x00040000
+#define ERR_INTR_EN_IRAM        0x00020000
+#define ERR_INTR_EN_MAC8        0x00008000
+#define ERR_INTR_EN_MAC9        0x00000040
+#define ERR_INTR_EN_MAC0        0x00004000
+#define ERR_INTR_EN_MAC1        0x00002000
+#define ERR_INTR_EN_MAC2        0x00001000
+#define ERR_INTR_EN_MAC3        0x00000800
+#define ERR_INTR_EN_MAC4        0x00000400
+#define ERR_INTR_EN_MAC5        0x00000200
+#define ERR_INTR_EN_MAC6        0x00000100
+#define ERR_INTR_EN_MAC7        0x00000080
+
+#define INTR_EN_QMI             0x40000000
+#define INTR_EN_PRS             0x20000000
+#define INTR_EN_MAC0            0x00080000
+#define INTR_EN_MAC1            0x00040000
+#define INTR_EN_MAC2            0x00020000
+#define INTR_EN_MAC3            0x00010000
+#define INTR_EN_MAC4            0x00000040
+#define INTR_EN_MAC5            0x00000020
+#define INTR_EN_MAC6            0x00000008
+#define INTR_EN_MAC7            0x00000002
+#define INTR_EN_MAC8            0x00200000
+#define INTR_EN_MAC9            0x00100000
+#define INTR_EN_REV0            0x00008000
+#define INTR_EN_REV1            0x00004000
+#define INTR_EN_REV2            0x00002000
+#define INTR_EN_REV3            0x00001000
+#define INTR_EN_BRK             0x00000080
+#define INTR_EN_TMR             0x01000000
+
+/* Modules registers offsets */
+#define FM_MM_MURAM             0x00000000
+#define FM_MM_BMI               0x00080000
+#define FM_MM_QMI               0x00080400
+#define FM_MM_PRS               0x000c7000
+#define FM_MM_DMA               0x000C2000
+#define FM_MM_FPM               0x000C3000
+#define FM_MM_IMEM              0x000C4000
+#define FM_MM_CGP               0x000DB000
+#define FM_MM_TRB(i)            (0x000D0200 + 0x400 * (i))
+#define FM_MM_SP                0x000dc000
+
+/* Memory Mapped Registers */
+
+struct fm_iram_regs_t {
+	uint32_t iadd;	/* FM IRAM instruction address register */
+	uint32_t idata;/* FM IRAM instruction data register */
+	uint32_t itcfg;/* FM IRAM timing config register */
+	uint32_t iready;/* FM IRAM ready register */
+	uint8_t res[0x80000 - 0x10];
+} __attribute__((__packed__));
+
+/* General defines */
+#define FM_FW_DEBUG_INSTRUCTION             0x6ffff805UL
+
+struct fm_state_struct_t {
+	uint8_t fm_id;
+	uint16_t fm_clk_freq;
+	struct fm_revision_info_t rev_info;
+	bool enabled_time_stamp;
+	uint8_t count1_micro_bit;
+	uint8_t total_num_of_tasks;
+	uint32_t total_fifo_size;
+	uint8_t max_num_of_open_dmas;
+	uint8_t accumulated_num_of_tasks;
+	uint32_t accumulated_fifo_size;
+	uint8_t accumulated_num_of_open_dmas;
+	uint8_t accumulated_num_of_deq_tnums;
+	bool low_end_restriction;
+	uint32_t exceptions;
+	bool rams_ecc_enable;
+	bool explicit_enable;
+	bool internal_call;
+	uint32_t extra_fifo_pool_size;
+	uint8_t extra_tasks_pool_size;
+	uint8_t extra_open_dmas_pool_size;
+};
+
+struct fm_intg_t {
+	/* Ram defines */
+	uint32_t fm_muram_size;
+	uint32_t fm_iram_size;
+	uint32_t fm_num_of_ctrl;
+
+	/* DMA defines */
+	uint32_t dma_thresh_max_commq;
+	uint32_t dma_thresh_max_buf;
+
+	/* QMI defines */
+	uint32_t qmi_max_num_of_tnums;
+	uint32_t qmi_def_tnums_thresh;
+
+	/* BMI defines */
+	uint32_t bmi_max_num_of_tasks;
+	uint32_t bmi_max_num_of_dmas;
+	uint32_t bmi_max_fifo_size;
+	uint32_t port_max_weight;
+
+	uint32_t fm_port_num_of_cg;
+	uint32_t num_of_rx_ports;
+};
+
+struct fm_t {
+	uintptr_t base_addr;
+	char fm_module_name[MODULE_NAME_SIZE];
+	struct fm_intr_src_t intr_mng[FM_EV_DUMMY_LAST];
+
+	struct fman_fpm_regs __iomem *p_fm_fpm_regs;
+	struct fman_bmi_regs __iomem *p_fm_bmi_regs;
+	struct fman_qmi_regs __iomem *p_fm_qmi_regs;
+	struct fman_dma_regs __iomem *p_fm_dma_regs;
+	struct fman_regs __iomem *p_fm_regs;
+	fm_exceptions_cb *f_exception;
+	fm_bus_error_cb *f_bus_error;
+	void *h_app;		/* Application handle */
+	spinlock_t *spinlock;
+	struct fm_state_struct_t *p_fm_state_struct;
+	uint16_t tnum_aging_period;
+
+	struct fman_cfg *p_fm_drv_param;
+	struct muram_info *p_muram;
+	/* cam section in muram */
+	int cam_offset;
+	uint32_t cam_size;
+	uintptr_t res_addr;
+	/* Fifo in MURAM */
+	int fifo_offset;
+	uint32_t fifo_size;
+	struct fm_firmware_params_t firmware;
+	bool fw_verify;
+	bool reset_on_init;
+	uint32_t user_set_exceptions;
+
+	struct fm_intg_t *intg;
+};
+
+#endif /* __FM_H */
diff --git a/drivers/net/ethernet/freescale/fman/fm_common.h b/drivers/net/ethernet/freescale/fman/fm_common.h
new file mode 100644
index 0000000..953cbeb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2008-2015 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 __FM_COMMON_H
+#define __FM_COMMON_H
+
+#include "service.h"
+#include "fm_ext.h"
+
+/* Enum for inter-module interrupts registration */
+enum fm_event_modules {
+	FM_MOD_PRS = 0,		/* Parser event */
+	FM_MOD_MAC,		/* MAC event */
+	FM_MOD_TMR,		/* Timer event */
+	FM_MOD_FMAN_CTRL,	/* FMAN Controller  Timer event */
+	FM_MOD_DUMMY_LAST
+};
+
+/* Enum for interrupts types */
+enum fm_intr_type {
+	FM_INTR_TYPE_ERR,
+	FM_INTR_TYPE_NORMAL
+};
+
+/* Enum for inter-module interrupts registration */
+enum fm_inter_module_event {
+	FM_EV_PRS = 0,		/* Parser event */
+	FM_EV_ERR_PRS,		/* Parser error event */
+	FM_EV_ERR_MAC8,		/* MAC 8 error event */
+	FM_EV_ERR_MAC9,		/* MAC 9 error event */
+	FM_EV_ERR_MAC0,		/* MAC 0 error event */
+	FM_EV_ERR_MAC1,		/* MAC 1 error event */
+	FM_EV_ERR_MAC2,		/* MAC 2 error event */
+	FM_EV_ERR_MAC3,		/* MAC 3 error event */
+	FM_EV_ERR_MAC4,		/* MAC 4 error event */
+	FM_EV_ERR_MAC5,		/* MAC 5 error event */
+	FM_EV_ERR_MAC6,		/* MAC 6 error event */
+	FM_EV_ERR_MAC7,		/* MAC 7 error event */
+	FM_EV_TMR,		/* Timer event */
+	FM_EV_MAC8,		/* MAC 8 event (Magic packet detection) */
+	FM_EV_MAC9,		/* MAC 9 event (Magic packet detection) */
+	FM_EV_MAC0,		/* MAC 0 event (Magic packet detection) */
+	FM_EV_MAC1,		/* MAC 1 event (Magic packet detection) */
+	FM_EV_MAC2,		/* MAC 2 (Magic packet detection) */
+	FM_EV_MAC3,		/* MAC 3 (Magic packet detection) */
+	FM_EV_MAC4,		/* MAC 4 (Magic packet detection) */
+	FM_EV_MAC5,		/* MAC 5 (Magic packet detection) */
+	FM_EV_MAC6,		/* MAC 6 (Magic packet detection) */
+	FM_EV_MAC7,		/* MAC 7 (Magic packet detection) */
+	FM_EV_FMAN_CTRL_0,	/* Fman controller event 0 */
+	FM_EV_FMAN_CTRL_1,	/* Fman controller event 1 */
+	FM_EV_FMAN_CTRL_2,	/* Fman controller event 2 */
+	FM_EV_FMAN_CTRL_3,	/* Fman controller event 3 */
+	FM_EV_DUMMY_LAST
+};
+
+/* FM IP BLOCK versions */
+#define FM_IP_BLOCK_P1			4
+#define FM_IP_BLOCK_P2_P3_P5		3
+#define FM_IP_BLOCK_P4			2
+#define FM_IP_BLOCK_B_T			6
+
+#define MODULE_NAME_SIZE        30
+#define DUMMY_PORT_ID           0
+
+#define FM_LIODN_OFFSET_MASK    0x3FF
+
+#define BMI_MAX_FIFO_SIZE                   (FM_MURAM_SIZE)
+#define BMI_FIFO_UNITS                      0x100
+
+struct fm_intr_src_t {
+	void (*f_isr)(void *h_src_arg);
+	void *h_src_handle;
+};
+
+void fm_register_intr(struct fm_t *p_fm,
+		      enum fm_event_modules mod,
+		      uint8_t mod_id,
+		      enum fm_intr_type intr_type,
+		      void (*f_isr)(void *h_src_arg), void *h_src_arg);
+
+void fm_unregister_intr(struct fm_t *p_fm,
+			enum fm_event_modules mod,
+			uint8_t mod_id, enum fm_intr_type intr_type);
+
+struct muram_info *fm_get_muram_pointer(struct fm_t *p_fm);
+
+void fm_get_physical_muram_base(struct fm_t *p_fm,
+				struct fm_phys_addr_t *fm_phys_addr);
+
+uint16_t fm_get_clock_freq(struct fm_t *p_fm);
+
+uint8_t fm_get_id(struct fm_t *p_fm);
+
+int fm_set_num_of_open_dmas(struct fm_t *p_fm,
+			    uint8_t port_id,
+			    uint8_t *p_num_of_open_dmas,
+			    uint8_t *p_num_of_extra_open_dmas,
+			    bool initial_config);
+int fm_set_num_of_tasks(struct fm_t *p_fm,
+			uint8_t port_id,
+			uint8_t *p_num_of_tasks,
+			uint8_t *p_num_of_extra_tasks,
+			bool initial_config);
+int fm_set_size_of_fifo(struct fm_t *p_fm,
+			uint8_t port_id,
+			uint32_t *p_size_of_fifo,
+			uint32_t *p_extra_size_of_fifo,
+			bool initial_config);
+
+uint32_t fm_get_bmi_max_fifo_size(struct fm_t *p_fm);
+struct num_of_ports_info_t *fm_get_num_of_ports(struct fm_t *p_fm);
+
+#endif /* __FM_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.c b/drivers/net/ethernet/freescale/fman/fm_drv.c
new file mode 100644
index 0000000..20df8a3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2008-2015 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/errno.h>
+#include <asm/qe.h>		/* For struct qe_firmware */
+#include <sysdev/fsl_soc.h>
+
+#include "service.h"
+#include "fm_ext.h"
+#include "fm_drv.h"
+#include "fm_muram_ext.h"
+
+/* 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"
+
+/* Minimum and maximum value for the fsl_fm_rx_extra_headroom bootarg */
+#define FSL_FM_RX_EXTRA_HEADROOM_MIN 16
+#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 accommodate 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;
+
+u16 fm_get_max_frm(void)
+{
+	return fsl_fm_max_frm;
+}
+EXPORT_SYMBOL(fm_get_max_frm);
+
+int fm_get_rx_extra_headroom(void)
+{
+	return ALIGN(fsl_fm_rx_extra_headroom, 16);
+}
+EXPORT_SYMBOL(fm_get_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.
+		 */
+		pr_err("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) {
+		pr_err("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;
+	}
+
+	pr_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) {
+		pr_err("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 < FSL_FM_RX_EXTRA_HEADROOM_MIN ||
+	    fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) {
+		pr_err("Invalid value for %s=%d prop in bootargs; will use the default FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n",
+		       FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
+		       fsl_fm_rx_extra_headroom,
+		       CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
+		fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
+	}
+
+	pr_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)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)_dev;
+
+	if (!fm_drv || !fm_drv->h_dev)
+		return IRQ_NONE;
+
+	fm_event_isr(fm_drv->h_dev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fm_err_irq(int irq, void *_dev)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)_dev;
+
+	if (!fm_drv || !fm_drv->h_dev)
+		return IRQ_NONE;
+
+	if (fm_error_isr(fm_drv->h_dev) == 0)
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+}
+
+/**
+ * find_fman_microcode - 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 FMan use the same firmware.
+ *
+ * Return: A pointer to the QE Firmware blob
+ */
+static const struct qe_firmware *find_fman_microcode(void)
+{
+	static const struct qe_firmware *uc_patch;
+	struct device_node *np;
+
+	if (uc_patch)
+		return uc_patch;
+
+	/* The firmware should be inside the device tree. */
+	np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
+	if (np) {
+		uc_patch = of_get_property(np, "fsl,firmware", NULL);
+		of_node_put(np);
+		if (uc_patch)
+			return uc_patch;
+
+		pr_info("firmware node is incomplete\n");
+	}
+
+	/* Returning NULL here forces the reuse of the IRAM content */
+	return NULL;
+}
+
+static int fill_qman_channhels_info(struct fm_drv_t *fm_drv)
+{
+	fm_drv->qman_channels = kcalloc(fm_drv->num_of_qman_channels,
+					sizeof(uint32_t), GFP_KERNEL);
+	if (!fm_drv->qman_channels)
+		return -ENOMEM;
+
+	if (fm_drv->fm_rev_info.major_rev >= 6) {
+		fm_drv->qman_channels[0] = 0x30;
+		fm_drv->qman_channels[1] = 0x31;
+		fm_drv->qman_channels[2] = 0x28;
+		fm_drv->qman_channels[3] = 0x29;
+		fm_drv->qman_channels[4] = 0x2a;
+		fm_drv->qman_channels[5] = 0x2b;
+		fm_drv->qman_channels[6] = 0x2c;
+		fm_drv->qman_channels[7] = 0x2d;
+		fm_drv->qman_channels[8] = 0x2;
+		fm_drv->qman_channels[9] = 0x3;
+		fm_drv->qman_channels[10] = 0x4;
+		fm_drv->qman_channels[11] = 0x5;
+		fm_drv->qman_channels[12] = 0x6;
+		fm_drv->qman_channels[13] = 0x7;
+	} else {
+		fm_drv->qman_channels[0] = 0x30;
+		fm_drv->qman_channels[1] = 0x28;
+		fm_drv->qman_channels[2] = 0x29;
+		fm_drv->qman_channels[3] = 0x2a;
+		fm_drv->qman_channels[4] = 0x2b;
+		fm_drv->qman_channels[5] = 0x2c;
+		fm_drv->qman_channels[6] = 0x1;
+		fm_drv->qman_channels[7] = 0x2;
+		fm_drv->qman_channels[8] = 0x3;
+		fm_drv->qman_channels[9] = 0x4;
+		fm_drv->qman_channels[10] = 0x5;
+		fm_drv->qman_channels[11] = 0x6;
+	}
+
+	return 0;
+}
+
+static struct fm_drv_t *read_fm_dev_tree_node(struct platform_device *of_dev)
+{
+	struct fm_drv_t *fm_drv;
+	struct device_node *fm_node, *dev_node;
+	struct of_device_id name;
+	struct resource res;
+	const uint32_t *uint32_prop;
+	int lenp, err;
+	struct clk *clk;
+	u32 clk_rate;
+
+	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)) {
+		pr_err("of_get_property(%s, cell-index) failed\n",
+		       fm_node->full_name);
+		goto _return_null;
+	}
+	if (WARN_ON(lenp != sizeof(uint32_t)))
+		return NULL;
+
+	fm_drv = kzalloc(sizeof(*fm_drv), GFP_KERNEL);
+	if (!fm_drv)
+		goto _return_null;
+
+	fm_drv->dev = &of_dev->dev;
+	fm_drv->id = (u8)*uint32_prop;
+
+	/* Get the FM interrupt */
+	fm_drv->irq = of_irq_to_resource(fm_node, 0, NULL);
+	if (unlikely(fm_drv->irq == 0)) {
+		pr_err("of_irq_to_resource() = %d\n", NO_IRQ);
+		goto _return_null;
+	}
+
+	/* Get the FM error interrupt */
+	fm_drv->err_irq = of_irq_to_resource(fm_node, 1, NULL);
+
+	/* Get the FM address */
+	err = of_address_to_resource(fm_node, 0, &res);
+	if (unlikely(err < 0)) {
+		pr_err("of_address_to_resource() = %d\n", err);
+		goto _return_null;
+	}
+
+	fm_drv->fm_base_addr = 0;
+	fm_drv->fm_phys_base_addr = res.start;
+	fm_drv->fm_mem_size = res.end + 1 - res.start;
+
+	clk = clk_get(fm_drv->dev, fm_drv->id == 0 ? "fm0clk" : "fm1clk");
+	if (IS_ERR(clk)) {
+		pr_err("Failed to get FM%d clock structure\n", fm_drv->id);
+		goto _return_null;
+	}
+
+	clk_rate = clk_get_rate(clk);
+	if (!clk_rate) {
+		pr_err("Failed to determine FM%d clock rate\n", fm_drv->id);
+		goto _return_null;
+	}
+	/* Rounding to MHz */
+	clk_rate = (clk_rate + 500000) / 1000000;
+	fm_drv->params.fm_clk_freq = (u16)clk_rate;
+
+	uint32_prop = (uint32_t *)of_get_property(fm_node,
+						  "fsl,qman-channel-range",
+						  &lenp);
+	if (unlikely(!uint32_prop)) {
+		pr_err("of_get_property(%s, fsl,qman-channel-range) failed\n",
+		       fm_node->full_name);
+		goto _return_null;
+	}
+	if (WARN_ON(lenp != sizeof(uint32_t) * 2))
+		goto _return_null;
+	fm_drv->qman_channel_base = uint32_prop[0];
+	fm_drv->num_of_qman_channels = uint32_prop[1];
+
+	/* Get the MURAM base address and size */
+	memset(&name, 0, sizeof(name));
+	if (WARN_ON(strlen("muram") >= sizeof(name.name)))
+		goto _return_null;
+	strcpy(name.name, "muram");
+	if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(name.compatible)))
+		goto _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))) {
+			err = of_address_to_resource(dev_node, 0, &res);
+			if (unlikely(err < 0)) {
+				pr_err("of_address_to_resource() = %d\n",
+				       err);
+				goto _return_null;
+			}
+
+			fm_drv->fm_muram_base_addr = 0;
+			fm_drv->fm_muram_phys_base_addr = res.start;
+			fm_drv->fm_muram_mem_size = res.end + 1 - res.start;
+			{
+				/* In B4 rev 2.0 (and above) the MURAM size is
+				 * 512KB.
+				 * Check the SVR and update MURAM size if
+				 * required.
+				 */
+				uint32_t svr;
+
+				svr = mfspr(SPRN_SVR);
+
+				if ((SVR_SOC_VER(svr) == SVR_B4860) &&
+				    (SVR_MAJ(svr) >= 2))
+					fm_drv->fm_muram_mem_size = 0x80000;
+			}
+		}
+	}
+
+	of_node_put(fm_node);
+
+	fm_drv->active = true;
+
+	goto _return;
+
+_return_null:
+	of_node_put(fm_node);
+	return NULL;
+_return:
+	return fm_drv;
+}
+
+static void fm_drv_exceptions_cb(void *h_app,
+				 enum fm_exceptions __maybe_unused exception)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)h_app;
+
+	ASSERT(fm_drv);
+
+	pr_debug("got fm exception %d\n", exception);
+}
+
+static void fm_drv_bus_error_cb(void *h_app,
+				enum fm_port_type __maybe_unused port_type,
+				uint8_t __maybe_unused port_id,
+				uint64_t __maybe_unused addr,
+				uint8_t __maybe_unused tnum,
+				uint16_t __maybe_unused liodn)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)h_app;
+
+	ASSERT(fm_drv);
+
+	pr_debug("got fm bus error: port_id[%d]\n", port_id);
+}
+
+uint32_t get_qman_channel_id(struct fm_drv_t *fm_drv,
+			     uint32_t port_id,
+			     enum fm_port_type port_type,
+			     enum fm_port_speed port_speed)
+{
+	uint32_t qman_channel = 0;
+	int i;
+
+	for (i = 0; i < fm_drv->num_of_qman_channels; i++) {
+		if (fm_drv->qman_channels[i] == port_id)
+			break;
+	}
+
+	if (i == fm_drv->num_of_qman_channels)
+		return 0;
+
+	qman_channel = fm_drv->qman_channel_base + i;
+
+	return qman_channel;
+}
+
+static int configure_fm_dev(struct fm_drv_t *fm_drv)
+{
+	int err;
+
+	if (!fm_drv->active) {
+		pr_err("FMan not configured\n");
+		return -EINVAL;
+	}
+
+	err = devm_request_irq(fm_drv->dev, fm_drv->irq, fm_irq,
+			       IRQF_NO_SUSPEND, "fman", fm_drv);
+	if (unlikely(err < 0)) {
+		pr_err("Error: allocating irq %d (error = %d)\n",
+		       fm_drv->irq, err);
+		return -EINVAL;
+	}
+
+	if (fm_drv->err_irq != 0) {
+		err = devm_request_irq(fm_drv->dev, fm_drv->err_irq,
+				       fm_err_irq,
+				       IRQF_SHARED | IRQF_NO_SUSPEND,
+				       "fman-err", fm_drv);
+		if (unlikely(err < 0)) {
+			pr_err("Error: allocating irq %d (error = %d)\n",
+			       fm_drv->err_irq, err);
+			return -EINVAL;
+		}
+	}
+
+	fm_drv->res = devm_request_mem_region(fm_drv->dev,
+					      fm_drv->fm_phys_base_addr,
+					      fm_drv->fm_mem_size, "fman");
+	if (unlikely(!fm_drv->res)) {
+		pr_err("request_mem_region() failed\n");
+		return -EINVAL;
+	}
+
+	fm_drv->fm_base_addr =
+			(uintptr_t)(devm_ioremap(fm_drv->dev,
+						 fm_drv->fm_phys_base_addr,
+						 fm_drv->fm_mem_size));
+	if (unlikely(fm_drv->fm_base_addr == 0)) {
+		pr_err("devm_ioremap() failed\n");
+		return -EINVAL;
+	}
+
+	fm_drv->params.base_addr = fm_drv->fm_base_addr;
+	fm_drv->params.fm_id = fm_drv->id;
+	fm_drv->params.f_exception = fm_drv_exceptions_cb;
+	fm_drv->params.f_bus_error = fm_drv_bus_error_cb;
+	fm_drv->params.h_app = fm_drv;
+
+	return 0;
+}
+
+static int init_fm_dev(struct fm_drv_t *fm_drv)
+{
+	const struct qe_firmware *fw;
+
+	if (!fm_drv->active) {
+		pr_err("FMan not configured\n");
+		return -EINVAL;
+	}
+
+	fm_drv->muram = fm_muram_init(fm_drv->fm_muram_phys_base_addr,
+				      fm_drv->fm_muram_mem_size);
+	if (!fm_drv->muram) {
+		pr_err("FMan MURAM initalization failed\n");
+		return -EINVAL;
+	}
+
+	fw = find_fman_microcode();
+
+	if (!fw) {
+		/* this forces the reuse of the current IRAM content */
+		fm_drv->params.firmware.size = 0;
+		fm_drv->params.firmware.p_code = NULL;
+	} else {
+		fm_drv->params.firmware.p_code =
+			(void *)fw + fw->microcode[0].code_offset;
+		fm_drv->params.firmware.size =
+			sizeof(u32) * fw->microcode[0].count;
+		pr_debug("Loading fman-controller code version %d.%d.%d\n",
+			 fw->microcode[0].major, fw->microcode[0].minor,
+			 fw->microcode[0].revision);
+	}
+
+	fm_drv->params.p_muram = fm_drv->muram;
+
+	fm_drv->h_dev = fm_config(&fm_drv->params);
+	if (!fm_drv->h_dev) {
+		pr_err("FMan config failed\n");
+		return -EINVAL;
+	}
+
+	fm_get_revision(fm_drv->h_dev, &fm_drv->fm_rev_info);
+
+	if (fm_cfg_reset_on_init(fm_drv->h_dev, true) != 0) {
+		pr_err("fm_cfg_reset_on_init() failed\n");
+		return -EINVAL;
+	}
+	/* Config fm_cfg_dma_aid_override for P1023 */
+	if (fm_drv->fm_rev_info.major_rev == 4)
+		if (fm_cfg_dma_aid_override(fm_drv->h_dev, true) != 0) {
+			pr_err("fm_cfg_dma_aid_override() failed\n");
+			return -EINVAL;
+		}
+	/* Config total fifo size for FManV3H */
+	if ((fm_drv->fm_rev_info.major_rev >= 6) &&
+	    (fm_drv->fm_rev_info.minor_rev != 1 &&
+	     fm_drv->fm_rev_info.minor_rev != 4))
+			fm_cfg_total_fifo_size(fm_drv->h_dev, 295 * 1024);
+
+	if (fm_init(fm_drv->h_dev) != 0) {
+		pr_err("fm_init() failed\n");
+		return -EINVAL;
+	}
+
+	if (fm_drv->err_irq == 0) {
+		fm_set_exception(fm_drv->h_dev, FM_EX_DMA_BUS_ERROR, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_DMA_READ_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_DMA_SYSTEM_WRITE_ECC, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_DMA_FM_WRITE_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_DMA_SINGLE_PORT_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_FPM_STALL_ON_TASKS, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_FPM_SINGLE_ECC, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_FPM_DOUBLE_ECC, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_QMI_SINGLE_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_QMI_DOUBLE_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_BMI_LIST_RAM_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_BMI_STORAGE_PROFILE_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_BMI_STATISTICS_RAM_ECC, false);
+		fm_set_exception(fm_drv->h_dev,
+				 FM_EX_BMI_DISPATCH_RAM_ECC, false);
+		fm_set_exception(fm_drv->h_dev, FM_EX_IRAM_ECC, false);
+	}
+
+	if (unlikely(fill_qman_channhels_info(fm_drv) < 0)) {
+		pr_err("can't fill qman channel info\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void free_fm_dev(struct fm_drv_t *fm_drv)
+{
+	if (!fm_drv->active)
+		return;
+
+	if (fm_drv->h_dev)
+		fm_free(fm_drv->h_dev);
+
+	if (fm_drv->muram)
+		fm_muram_free(fm_drv->muram);
+
+	if (fm_drv->err_irq != 0)
+		devm_free_irq(fm_drv->dev, fm_drv->err_irq, fm_drv);
+
+	devm_free_irq(fm_drv->dev, fm_drv->irq, fm_drv);
+}
+
+static int fm_probe(struct platform_device *of_dev)
+{
+	struct fm_drv_t *fm_drv;
+
+	fm_drv = read_fm_dev_tree_node(of_dev);
+	if (!fm_drv)
+		return -EIO;
+	if (configure_fm_dev(fm_drv) != 0)
+		return -EIO;
+	if (init_fm_dev(fm_drv) != 0)
+		return -EIO;
+
+	dev_set_drvdata(fm_drv->dev, fm_drv);
+
+	pr_debug("FM%d probed\n", fm_drv->id);
+
+	return 0;
+}
+
+static int fm_remove(struct platform_device *of_dev)
+{
+	struct fm_drv_t *fm_drv;
+	struct device *dev;
+
+	dev = &of_dev->dev;
+	fm_drv = dev_get_drvdata(dev);
+
+	free_fm_dev(fm_drv);
+
+	kfree(fm_drv);
+
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+struct fm *fm_bind(struct device *fm_dev)
+{
+	return (struct fm *)(dev_get_drvdata(get_device(fm_dev)));
+}
+
+void fm_unbind(struct fm *fm)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+	put_device(fm_drv->dev);
+}
+
+struct resource *fm_get_mem_region(struct fm *fm)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+	return fm_drv->res;
+}
+
+void *fm_get_handle(struct fm *fm)
+{
+	struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+	return (void *)fm_drv->h_dev;
+}
+
+static const struct of_device_id fm_match[] = {
+	{
+	 .compatible = "fsl,fman"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, fm_match);
+
+static struct platform_driver fm_driver = {
+	.driver = {
+		   .name = "fsl-fman",
+		   .of_match_table = fm_match,
+		   },
+	.probe = fm_probe,
+	.remove = fm_remove
+};
+
+static int __init __cold fm_load(void)
+{
+	if (platform_driver_register(&fm_driver)) {
+		pr_crit("platform_driver_register() failed\n");
+		return -ENODEV;
+	}
+
+	pr_info("Freescale FM module\n");
+	return 0;
+}
+
+static void __exit __cold fm_unload(void)
+{
+	platform_driver_unregister(&fm_driver);
+}
+
+module_init(fm_load);
+module_exit(fm_unload);
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.h b/drivers/net/ethernet/freescale/fman/fm_drv.h
new file mode 100644
index 0000000..33bfa1a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2008-2015 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 __FM_DRV_H__
+#define __FM_DRV_H__
+
+#include <asm/mpc85xx.h>
+
+#include "service.h"
+#include "fsl_fman_drv.h"
+
+#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       16
+#endif
+
+/* SoC info */
+#define SOC_VERSION(svr)        (((svr) & 0xFFF7FF00) >> 8)
+#define SOC_MAJOR_REV(svr)      (((svr) & 0x000000F0) >> 4)
+#define SOC_MINOR_REV(svr)      ((svr) & 0x0000000F)
+
+/* Port defines */
+#define NUM_OF_FM_PORTS			63
+#define FIRST_OP_PORT(major)		(major >= 6 ? 0x02 : 0x01)
+#define FIRST_RX_PORT			0x08
+#define FIRST_TX_PORT			0x28
+#define LAST_OP_PORT			0x07
+#define LAST_RX_PORT			0x11
+#define LAST_TX_PORT			0x31
+
+#define TX_10G_PORT_BASE		0x30
+#define RX_10G_PORT_BASE		0x10
+
+struct fm_port_t;
+
+struct fm_port_drv_t {
+	uint8_t id;
+	char name[20];
+	bool active;
+	uint64_t phys_base_addr;
+	uint64_t base_addr;	/* Port's *virtual* address */
+	resource_size_t mem_size;
+	struct fm_buffer_prefix_content_t buff_prefix_content;
+	struct fm_port_t *fm_port;
+	struct fm_drv_t *fm;
+	uint16_t tx_ch;
+	struct device *dev;
+	struct fm_revision_info_t fm_rev_info;
+};
+
+struct fm_drv_t {
+	uint8_t id;
+	char name[10];
+	bool active;
+	uint64_t fm_phys_base_addr;
+	uint64_t fm_base_addr;
+	resource_size_t fm_mem_size;
+	phys_addr_t fm_muram_phys_base_addr;
+	uint64_t fm_muram_base_addr;
+	resource_size_t fm_muram_mem_size;
+	int irq;
+	int err_irq;
+	struct fm_params_t params;
+	void *h_dev;
+	struct muram_info *muram;
+
+	struct fm_port_drv_t ports[NUM_OF_FM_PORTS];
+
+	struct device *dev;
+	struct resource *res;
+
+	struct fm_revision_info_t fm_rev_info;
+	uint32_t qman_channel_base;
+	uint32_t num_of_qman_channels;
+	uint32_t *qman_channels;
+
+};
+
+uint32_t get_qman_channel_id(struct fm_drv_t *fm_drv,
+			     uint32_t port_id,
+			     enum fm_port_type port_type,
+			     enum fm_port_speed port_speed);
+
+#endif /* __FM_DRV_H__ */
diff --git a/drivers/net/ethernet/freescale/fman/inc/enet_ext.h b/drivers/net/ethernet/freescale/fman/inc/enet_ext.h
new file mode 100644
index 0000000..cfade84
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/enet_ext.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008-2015 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.
+ */
+
+/* Ethernet generic definitions and enums. */
+
+#ifndef __ENET_EXT_H
+#define __ENET_EXT_H
+
+#include "fsl_enet.h"
+
+/* Number of octets (8-bit bytes) in an ethernet address */
+#define ENET_NUM_OCTETS_PER_ADDRESS 6
+/* Group address mask for ethernet addresses */
+#define ENET_GROUP_ADDR	    0x01
+
+/* Ethernet Address */
+typedef uint8_t enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS];
+
+/* Ethernet MAC-PHY Interface */
+enum ethernet_interface {
+	ENET_IF_MII = E_ENET_IF_MII,	 /* MII interface */
+	ENET_IF_RMII = E_ENET_IF_RMII, /* RMII interface */
+	ENET_IF_SMII = E_ENET_IF_SMII, /* SMII interface */
+	ENET_IF_GMII = E_ENET_IF_GMII, /* GMII interface */
+	ENET_IF_RGMII = E_ENET_IF_RGMII,
+					 /* RGMII interface */
+	ENET_IF_TBI = E_ENET_IF_TBI,	 /* TBI interface */
+	ENET_IF_RTBI = E_ENET_IF_RTBI, /* RTBI interface */
+	ENET_IF_SGMII = E_ENET_IF_SGMII,
+					 /* SGMII interface */
+	ENET_IF_XGMII = E_ENET_IF_XGMII,
+					 /* XGMII interface */
+	ENET_IF_QSGMII = E_ENET_IF_QSGMII,
+					 /* QSGMII interface */
+	ENET_IF_XFI = E_ENET_IF_XFI	 /* XFI interface */
+};
+
+/* SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC and phy
+ * or backplane; Note: 1000BaseX auto-negotiation relates only to interface
+ * between MAC and phy/backplane, SGMII phy can still synchronize with far-end
+ * phy at 10Mbps, 100Mbps or 1000Mbps
+ */
+#define ENET_IF_SGMII_BASEX       0x80000000
+
+/* Ethernet Speed (nominal data rate) */
+enum ethernet_speed {
+	ENET_SPEED_10 = E_ENET_SPEED_10,	 /* 10 Mbps */
+	ENET_SPEED_100 = E_ENET_SPEED_100,	 /* 100 Mbps */
+	ENET_SPEED_1000 = E_ENET_SPEED_1000,	 /* 1000 Mbps = 1 Gbps */
+	ENET_SPEED_10000 = E_ENET_SPEED_10000	 /* 10000 Mbps = 10 Gbps */
+};
+
+/* Ethernet mode (combination of MAC-PHY interface and speed) */
+enum e_enet_mode {
+	ENET_MODE_INVALID = 0,	/* Invalid Ethernet mode */
+	/*    10 Mbps MII   */
+	ENET_MODE_MII_10 = (ENET_IF_MII | ENET_SPEED_10),
+	/*   100 Mbps MII   */
+	ENET_MODE_MII_100 = (ENET_IF_MII | ENET_SPEED_100),
+	/*    10 Mbps RMII  */
+	ENET_MODE_RMII_10 = (ENET_IF_RMII | ENET_SPEED_10),
+	/*   100 Mbps RMII  */
+	ENET_MODE_RMII_100 = (ENET_IF_RMII | ENET_SPEED_100),
+	/*    10 Mbps SMII  */
+	ENET_MODE_SMII_10 = (ENET_IF_SMII | ENET_SPEED_10),
+	/*   100 Mbps SMII  */
+	ENET_MODE_SMII_100 = (ENET_IF_SMII | ENET_SPEED_100),
+	/*  1000 Mbps GMII  */
+	ENET_MODE_GMII_1000 = (ENET_IF_GMII | ENET_SPEED_1000),
+	/*    10 Mbps RGMII */
+	ENET_MODE_RGMII_10 = (ENET_IF_RGMII | ENET_SPEED_10),
+	/*   100 Mbps RGMII */
+	ENET_MODE_RGMII_100 = (ENET_IF_RGMII | ENET_SPEED_100),
+	/*  1000 Mbps RGMII */
+	ENET_MODE_RGMII_1000 = (ENET_IF_RGMII | ENET_SPEED_1000),
+	/*  1000 Mbps TBI   */
+	ENET_MODE_TBI_1000 = (ENET_IF_TBI | ENET_SPEED_1000),
+	/*  1000 Mbps RTBI  */
+	ENET_MODE_RTBI_1000 = (ENET_IF_RTBI | ENET_SPEED_1000),
+	/* 10 Mbps SGMII with auto-negotiation between MAC and
+	 * SGMII phy according to Cisco SGMII specification
+	 */
+	ENET_MODE_SGMII_10 = (ENET_IF_SGMII | ENET_SPEED_10),
+	/* 100 Mbps SGMII with auto-negotiation between MAC and
+	 * SGMII phy according to Cisco SGMII specification
+	 */
+	ENET_MODE_SGMII_100 = (ENET_IF_SGMII | ENET_SPEED_100),
+	/* 1000 Mbps SGMII with auto-negotiation between MAC and
+	 * SGMII phy according to Cisco SGMII specification
+	 */
+	ENET_MODE_SGMII_1000 = (ENET_IF_SGMII | ENET_SPEED_1000),
+	/* 10 Mbps SGMII with 1000BaseX auto-negotiation between
+	 * MAC and SGMII phy or backplane
+	 */
+	ENET_MODE_SGMII_BASEX_10 =
+	    (ENET_IF_SGMII_BASEX | ENET_IF_SGMII | ENET_SPEED_10),
+	/* 100 Mbps SGMII with 1000BaseX auto-negotiation between
+	 * MAC and SGMII phy or backplane
+	 */
+	ENET_MODE_SGMII_BASEX_100 =
+	    (ENET_IF_SGMII_BASEX | ENET_IF_SGMII | ENET_SPEED_100),
+	/* 1000 Mbps SGMII with 1000BaseX auto-negotiation between
+	 * MAC and SGMII phy or backplane
+	 */
+	ENET_MODE_SGMII_BASEX_1000 =
+	    (ENET_IF_SGMII_BASEX | ENET_IF_SGMII | ENET_SPEED_1000),
+	/* 1000 Mbps QSGMII with auto-negotiation between MAC and
+	 * QSGMII phy according to Cisco QSGMII specification
+	 */
+	ENET_MODE_QSGMII_1000 = (ENET_IF_QSGMII | ENET_SPEED_1000),
+	/* 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
+	 * MAC and QSGMII phy or backplane
+	 */
+	ENET_MODE_QSGMII_BASEX_1000 =
+	    (ENET_IF_SGMII_BASEX | ENET_IF_QSGMII | ENET_SPEED_1000),
+	/* 10000 Mbps XGMII */
+	ENET_MODE_XGMII_10000 = (ENET_IF_XGMII | ENET_SPEED_10000),
+	/* 10000 Mbps XFI */
+	ENET_MODE_XFI_10000 = (ENET_IF_XFI | ENET_SPEED_10000)
+};
+
+#define IS_ENET_MODE_VALID(mode)			\
+	(((mode) == ENET_MODE_MII_10) ||		\
+	((mode) == ENET_MODE_MII_100) ||		\
+	((mode) == ENET_MODE_RMII_10) ||		\
+	((mode) == ENET_MODE_RMII_100) ||		\
+	((mode) == ENET_MODE_SMII_10) ||		\
+	((mode) == ENET_MODE_SMII_100) ||		\
+	((mode) == ENET_MODE_GMII_1000) ||		\
+	((mode) == ENET_MODE_RGMII_10) ||		\
+	((mode) == ENET_MODE_RGMII_100) ||		\
+	((mode) == ENET_MODE_RGMII_1000) ||		\
+	((mode) == ENET_MODE_TBI_1000) ||		\
+	((mode) == ENET_MODE_RTBI_1000) ||		\
+	((mode) == ENET_MODE_SGMII_10) ||		\
+	((mode) == ENET_MODE_SGMII_100) ||		\
+	((mode) == ENET_MODE_SGMII_1000) ||		\
+	((mode) == ENET_MODE_SGMII_BASEX_10) ||	\
+	((mode) == ENET_MODE_SGMII_BASEX_100) ||	\
+	((mode) == ENET_MODE_SGMII_BASEX_1000) ||	\
+	((mode) == ENET_MODE_XGMII_10000) ||		\
+	((mode) == ENET_MODE_QSGMII_1000) ||		\
+	((mode) == ENET_MODE_QSGMII_BASEX_1000) ||	\
+	((mode) == ENET_MODE_XFI_10000))
+
+#define MAKE_ENET_MODE(_interface, _speed) \
+		      (enum e_enet_mode)((_interface) | (_speed))
+
+#define ENET_INTERFACE_FROM_MODE(mode) \
+				(enum ethernet_interface)((mode) & 0x0FFF0000)
+#define ENET_SPEED_FROM_MODE(mode) \
+			    (enum ethernet_speed)((mode) & 0x0000FFFF)
+
+#define ENET_ADDR_TO_UINT64(_enet_addr)		  \
+	(uint64_t)(((uint64_t)(_enet_addr)[0] << 40) |   \
+		   ((uint64_t)(_enet_addr)[1] << 32) |   \
+		   ((uint64_t)(_enet_addr)[2] << 24) |   \
+		   ((uint64_t)(_enet_addr)[3] << 16) |   \
+		   ((uint64_t)(_enet_addr)[4] << 8) |    \
+		   ((uint64_t)(_enet_addr)[5]))
+
+#define MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enet_addr) \
+	do { \
+		int i; \
+		for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) \
+			(_enet_addr)[i] = \
+			(uint8_t)((_addr64) >> ((5 - i) * 8)); \
+	} while (0)
+
+#endif /* __ENET_EXT_H */
diff --git a/drivers/net/ethernet/freescale/fman/inc/fm_ext.h b/drivers/net/ethernet/freescale/fman/inc/fm_ext.h
new file mode 100644
index 0000000..5344109
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_ext.h
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2008-2015 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.
+ */
+
+/* FM Application Programming Interface. */
+#ifndef __FM_EXT
+#define __FM_EXT
+
+#include "service.h"
+#include "fsl_fman_sp.h"
+
+/* Enum for defining port types */
+enum fm_port_type {
+	FM_PORT_TYPE_OP = 0,	/* OP Port */
+	FM_PORT_TYPE_TX,	/* TX Port */
+	FM_PORT_TYPE_RX,	/* RX Port */
+	FM_PORT_TYPE_DUMMY
+};
+
+/* Enum for defining port speed */
+enum fm_port_speed {
+	FM_PORT_SPEED_1G = 0,		/* 1G port */
+	FM_PORT_SPEED_10G,		/* 10G port */
+	FM_PORT_SPEED_OP
+};
+
+/* BMan defines */
+#define BM_MAX_NUM_OF_POOLS		64 /* Buffers pools */
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS	8  /* External BM pools per Rx port */
+
+/* General FM defines */
+#define FM_MAX_NUM_OF_PARTITIONS    64	 /* Maximum number of partitions */
+
+/* FM Frame descriptor macros  */
+/* Frame queue Context Override */
+#define FM_FD_CMD_FCO                   0x80000000
+#define FM_FD_CMD_RPD                   0x40000000  /* Read Prepended Data */
+#define FM_FD_CMD_DTC                   0x10000000  /* Do L4 Checksum */
+
+/* Not for Rx-Port! Unsupported Format */
+#define FM_FD_ERR_UNSUPPORTED_FORMAT    0x04000000
+/* Not for Rx-Port! Length Error */
+#define FM_FD_ERR_LENGTH                0x02000000
+#define FM_FD_ERR_DMA                   0x01000000  /* DMA Data error */
+
+/* IPR frame (not error) */
+#define FM_FD_IPR                       0x00000001
+/* IPR non-consistent-sp */
+#define FM_FD_ERR_IPR_NCSP              (0x00100000 | FM_FD_IPR)
+/* IPR error */
+#define FM_FD_ERR_IPR                   (0x00200000 | FM_FD_IPR)
+/* IPR timeout */
+#define FM_FD_ERR_IPR_TO                (0x00300000 | FM_FD_IPR)
+
+/* Rx FIFO overflow, FCS error, code error, running disparity error
+ * (SGMII and TBI modes), FIFO parity error. PHY Sequence error,
+ * PHY error control character detected.
+ */
+#define FM_FD_ERR_PHYSICAL              0x00080000
+/* Frame too long OR Frame size exceeds max_length_frame  */
+#define FM_FD_ERR_SIZE                  0x00040000
+/* classification discard */
+#define FM_FD_ERR_CLS_DISCARD           0x00020000
+/* Extract Out of Frame */
+#define FM_FD_ERR_EXTRACTION            0x00008000
+/* No Scheme Selected */
+#define FM_FD_ERR_NO_SCHEME             0x00004000
+/* Keysize Overflow */
+#define FM_FD_ERR_KEYSIZE_OVERFLOW      0x00002000
+/* Frame color is red */
+#define FM_FD_ERR_COLOR_RED             0x00000800
+/* Frame color is yellow */
+#define FM_FD_ERR_COLOR_YELLOW          0x00000400
+/* Parser Time out Exceed */
+#define FM_FD_ERR_PRS_TIMEOUT           0x00000080
+/* Invalid Soft Parser instruction */
+#define FM_FD_ERR_PRS_ILL_INSTRUCT      0x00000040
+/* Header error was identified during parsing */
+#define FM_FD_ERR_PRS_HDR_ERR           0x00000020
+/* Frame parsed beyind 256 first bytes */
+#define FM_FD_ERR_BLOCK_LIMIT_EXCEEDED  0x00000008
+
+/* non Frame-Manager error */
+#define FM_FD_RX_STATUS_ERR_NON_FM      0x00400000
+
+/* FM physical Address */
+struct fm_phys_addr_t {
+	uint8_t high;	      /* High part of the physical address */
+	uint32_t low;	      /* Low part of the physical address */
+} __attribute__((__packed__));
+
+/* Parse results memory layout */
+struct fm_prs_result_t {
+	 uint8_t lpid;		     /* Logical port id */
+	 uint8_t shimr;		     /* Shim header result  */
+	 uint16_t l2r;		     /* Layer 2 result */
+	 uint16_t l3r;		     /* Layer 3 result */
+	 uint8_t l4r;		     /* Layer 4 result */
+	 uint8_t cplan;		     /* Classification plan id */
+	 uint16_t nxthdr;	     /* Next Header  */
+	 uint16_t cksum;	     /* Running-sum */
+	/* Flags&fragment-offset field of the last IP-header */
+	 uint16_t flags_frag_off;
+	/* Routing type field of a IPV6 routing extension header */
+	 uint8_t route_type;
+	/* Routing Extension Header Present; last bit is IP valid */
+	 uint8_t rhp_ip_valid;
+	 uint8_t shim_off[2];	     /* Shim offset */
+	/* IP PID (last IP-proto) offset */
+	 uint8_t ip_pid_off;
+	 uint8_t eth_off;	     /* ETH offset */
+	 uint8_t llc_snap_off;	     /* LLC_SNAP offset */
+	 uint8_t vlan_off[2];	     /* VLAN offset */
+	 uint8_t etype_off;	     /* ETYPE offset */
+	 uint8_t pppoe_off;	     /* PPP offset */
+	 uint8_t mpls_off[2];	     /* MPLS offset */
+	 uint8_t ip_off[2];	     /* IP offset */
+	 uint8_t gre_off;	     /* GRE offset */
+	 uint8_t l4_off;	     /* Layer 4 offset */
+	 uint8_t nxthdr_off;	     /* Parser end point */
+} __attribute__((__packed__));
+
+/* @} */
+
+/* FM Exceptions */
+enum fm_exceptions {
+	FM_EX_DMA_BUS_ERROR = 0,	/* DMA bus error. */
+	/* Read Buffer ECC error (Valid for FM rev < 6) */
+	FM_EX_DMA_READ_ECC,
+	/* Write Buffer ECC error on system side (Valid for FM rev < 6) */
+	FM_EX_DMA_SYSTEM_WRITE_ECC,
+	/* Write Buffer ECC error on FM side (Valid for FM rev < 6) */
+	FM_EX_DMA_FM_WRITE_ECC,
+	/* Single Port ECC error on FM side (Valid for FM rev > 6) */
+	FM_EX_DMA_SINGLE_PORT_ECC,
+	FM_EX_FPM_STALL_ON_TASKS,	/* Stall of tasks on FPM */
+	FM_EX_FPM_SINGLE_ECC,		/* Single ECC on FPM. */
+	/* Double ECC error on FPM ram access */
+	FM_EX_FPM_DOUBLE_ECC,
+	FM_EX_QMI_SINGLE_ECC,		/* Single ECC on QMI. */
+	FM_EX_QMI_DOUBLE_ECC,		/* Double bit ECC occurred on QMI */
+	FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,
+					/* Dequeue from unknown port id */
+	FM_EX_BMI_LIST_RAM_ECC,	/* Linked List RAM ECC error */
+	FM_EX_BMI_STORAGE_PROFILE_ECC,/* Storage Profile ECC Error */
+	/* Statistics Count RAM ECC Error Enable */
+	FM_EX_BMI_STATISTICS_RAM_ECC,
+	FM_EX_BMI_DISPATCH_RAM_ECC,	/* Dispatch RAM ECC Error Enable */
+	FM_EX_IRAM_ECC,		/* Double bit ECC occurred on IRAM */
+	FM_EX_MURAM_ECC		/* Double bit ECC occurred on MURAM */
+};
+
+/*  fm_exceptions_cb
+ *   Exceptions user callback routine, will be called upon an
+ *		exception passing the exception identification.
+ *   h_app      - User's application descriptor.
+ *   exception  - The exception.
+ */
+typedef void (fm_exceptions_cb)(void *h_app,
+				 enum fm_exceptions exception);
+
+/*  fm_bus_error_cb
+ *   Bus error user callback routine, will be called upon a
+ *		bus error, passing parameters describing the errors and
+ *		the owner.
+ *   h_app       - User's application descriptor.
+ *   port_type    - Port type (enum fm_port_type)
+ *   port_id      - Port id - relative to type.
+ *   addr        - Address that caused the error
+ *   tnum        - Owner of error
+ *   liodn       - Logical IO device number
+ */
+typedef void (fm_bus_error_cb)(void *h_app,
+				enum fm_port_type port_type,
+				uint8_t port_id,
+				uint64_t addr,
+				uint8_t tnum, uint16_t liodn);
+
+/* A structure for defining buffer prefix area content. */
+struct fm_buffer_prefix_content_t {
+	/* Number of bytes to be left at the beginning of the external
+	 * buffer; Note that the private-area will start from the base
+	 * of the buffer address.
+	 */
+	uint16_t priv_data_size;
+	/* true to pass the parse result to/from the FM;
+	 * User may use FM_PORT_GetBufferPrsResult() in
+	 * order to get the parser-result from a buffer.
+	 */
+	bool pass_prs_result;
+	/* true to pass the timeStamp to/from the FM User may use
+	 * fm_port_get_buffer_time_stamp() in order to get the
+	 * parser-result from a buffer.
+	 */
+	bool pass_time_stamp;
+	/* true to pass the KG hash result to/from the FM User may
+	 * use FM_PORT_GetBufferHashResult() in order to get the
+	 * parser-result from a buffer.
+	 */
+	bool pass_hash_result;
+	/* Add all other Internal-Context information: AD,
+	 * hash-result, key, etc.
+	 */
+	uint16_t data_align;
+};
+
+/* A structure of information about each of the external
+ * buffer pools used by a port or storage-profile.
+ */
+struct fm_ext_pool_params_t {
+	uint8_t id;		    /* External buffer pool id */
+	uint16_t size;		    /* External buffer pool buffer size */
+};
+
+/* A structure for informing the driver about the external
+ * buffer pools allocated in the BM and used by a port or a
+ * storage-profile.
+ */
+struct fm_ext_pools_t {
+	uint8_t num_of_pools_used; /* Number of pools use by this port */
+	struct fm_ext_pool_params_t ext_buf_pool[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+					/* Parameters for each port */
+};
+
+/* A structure for defining backup BM Pools. */
+struct fm_backup_bm_pools_t {
+	/* Number of BM backup pools -  must be smaller
+	 * than the total number of pools defined for the specified port.
+	 */
+	uint8_t num_of_backup_pools;
+	/* num_of_backup_pools pool id's, specifying which pools should
+	 * be used only as backup. Pool id's specified here must be a
+	 * subset of the pools used by the specified port.
+	 */
+	uint8_t pool_ids[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+};
+
+/* A structure for defining BM pool depletion criteria */
+struct fm_buf_pool_depletion_t {
+	/* select mode in which pause frames will be sent after a
+	 * number of pools (all together!) are depleted
+	 */
+	bool pools_grp_mode_enable;
+	/* the number of depleted pools that will invoke pause
+	 * frames transmission.
+	 */
+	uint8_t num_of_pools;
+	/* For each pool, true if it should be considered for
+	 * depletion (Note - this pool must be used by this port!).
+	 */
+	bool pools_to_consider[BM_MAX_NUM_OF_POOLS];
+	/* select mode in which pause frames will be sent
+	 * after a single-pool is depleted;
+	 */
+	bool single_pool_mode_enable;
+	/* For each pool, true if it should be considered
+	 * for depletion (Note - this pool must be used by this port!)
+	 */
+	bool pools_to_consider_for_single_mode[BM_MAX_NUM_OF_POOLS];
+};
+
+/* A Structure for defining Ucode patch for loading. */
+struct fm_firmware_params_t {
+	uint32_t size;			/* Size of uCode */
+	uint32_t *p_code;		/* A pointer to the uCode */
+};
+
+/* A Structure for defining FM initialization parameters */
+struct fm_params_t {
+	uint8_t fm_id;
+	/* Index of the FM */
+	uintptr_t base_addr;
+	/* A pointer to base of memory mapped FM registers (virtual);
+	 * NOTE that this should include ALL common registers of the FM
+	 * including the PCD registers area.
+	 */
+	struct muram_info *p_muram;
+	/* A pointer to an initialized MURAM object, to be used by the FM. */
+	uint16_t fm_clk_freq;
+	/* In Mhz; */
+	fm_exceptions_cb *f_exception;
+	/* An application callback routine to handle exceptions; */
+	fm_bus_error_cb *f_bus_error;
+	/* An application callback routine to handle exceptions; */
+	void *h_app;
+	/* A handle to an application layer object; This handle will be
+	 * passed by the driver upon calling the above callbacks;
+	 */
+	struct fm_firmware_params_t firmware;
+	/* The firmware parameters structure; */
+};
+
+struct fm_t; /* FMan data */
+
+/**
+ * fm_config
+ * @p_fm_params		A pointer to a data structure of mandatory FM
+ *			parameters
+ *
+ * Creates the FM module and returns its handle (descriptor).
+ * This descriptor must be passed as first parameter to all other
+ * FM function calls.
+ * No actual initialization or configuration of FM hardware is
+ * done by this routine. All FM parameters get default values that
+ * may be changed by calling one or more of the advance config
+ * routines.
+ *
+ * Return: A handle to the FM object, or NULL for Failure.
+ */
+void *fm_config(struct fm_params_t *p_fm_params);
+
+/**
+ * fm_init
+ * @p_fm		Pointer to the FMan module
+ *
+ * Initializes the FM module by defining the software structure
+ * and configuring the hardware registers.
+ *
+ * Return 0 on success; Error code otherwise.
+ */
+int fm_init(struct fm_t *p_fm);
+
+/**
+ * fm_free
+ * @p_fm		Pointer to the FMan module
+ *
+ * Frees all resources that were assigned to FM module.
+ * Calling this routine invalidates the descriptor.
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_free(struct fm_t *p_fm);
+
+/* Enum for choosing the field that will be output on AID */
+enum fm_dma_aid_mode {
+	FM_DMA_AID_OUT_PORT_ID = 0,	    /* 4 LSB of PORT_ID */
+	FM_DMA_AID_OUT_TNUM		    /* 4 LSB of TNUM */
+};
+
+/* Enum for selecting DMA Emergency options */
+/* Enable emergency for MURAM1 */
+#define  FM_DMA_MURAM_READ_EMERGENCY        0x00800000
+/* Enable emergency for MURAM2 */
+#define  FM_DMA_MURAM_WRITE_EMERGENCY       0x00400000
+/* Enable emergency for external bus */
+#define  FM_DMA_EXT_BUS_EMERGENCY           0x00100000
+
+/**
+ * fm_cfg_reset_on_init
+ * @p_fm	Pointer to the FMan module
+ * @enable	When true, FM will be reset before any
+ *
+ * Define whether to reset the FM before initialization.
+ * Change the default configuration [DEFAULT_RESET_ON_INIT].
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_cfg_reset_on_init(struct fm_t *p_fm, bool enable);
+
+/**
+ * fm_cfg_total_fifo_size
+ * @p_fm		Pointer to the FMan module
+ * @total_fifo_size	The selected new value.
+ *
+ * Define Total FIFO size for the whole FM.
+ * Calling this routine changes the total Fifo size in the internal driver
+ * data base from its default configuration [DEFAULT_total_fifo_size]
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_cfg_total_fifo_size(struct fm_t *p_fm, uint32_t total_fifo_size);
+
+/**
+ * fm_cfg_dma_aid_override
+ * p_fm			Pointer to the FMan module
+ * aid_override		The selected new value.
+ *
+ * Define DMA AID OVERRIDE_MODE.
+ * Calling this routine changes the AID override mode in the internal driver
+ * data base from its default configuration  [DEFAULT_aid_override]
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_cfg_dma_aid_override(struct fm_t *p_fm, bool aid_override);
+
+/* A Structure for returning FM revision information */
+struct fm_revision_info_t {
+	uint8_t major_rev;		    /* Major revision */
+	uint8_t minor_rev;		    /* Minor revision */
+};
+
+/**
+ * fm_set_exception
+ * p_fm		Pointer to the FMan module
+ * exception	The exception to be selected.
+ * enable	True to enable interrupt, false to mask it.
+ *
+ * Calling this routine enables/disables the specified exception.
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_set_exception(struct fm_t *p_fm, enum fm_exceptions exception,
+		     bool enable);
+
+/**
+ * fm_disable_rams_ecc
+ * @p_fm		Pointer to the FMan module
+ * Disables ECC mechanism for all the different FM RAM's; E.g. IRAM,
+ * MURAM, etc. Note:
+ *	In opposed to fm_enable_rams_ecc, this routine must be called
+ *	explicitly to disable all Rams ECC.
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_disable_rams_ecc(struct fm_t *p_fm);
+
+/**
+ * fm_get_revision
+ * @p_fm		- Pointer to the FMan module
+ * p_fm_rev		- A structure of revision information parameters.
+ * Returns the FM revision
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+void fm_get_revision(struct fm_t *p_fm, struct fm_revision_info_t *p_fm_rev);
+
+/**
+ * fm_error_isr
+ * @p_fm		Pointer to the FMan module
+ * FM interrupt-service-routine for errors.
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; EMPTY if no errors found in register, other
+ *	   error code otherwise.
+ */
+int fm_error_isr(struct fm_t *p_fm);
+
+/**
+ * fm_event_isr
+ * @p_fm	Pointer to the FMan module
+ *
+ * FM interrupt-service-routine for normal events.
+ * Allowed only following fm_init().
+ */
+void fm_event_isr(struct fm_t *p_fm);
+
+#endif /* __FM_EXT */
diff --git a/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
new file mode 100644
index 0000000..c96cfd1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008-2015 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 __FSL_FMAN_DRV_H
+#define __FSL_FMAN_DRV_H
+
+#include <linux/types.h>
+#include <linux/device.h>	/* struct device */
+#include "fm_ext.h"
+
+/* FM device opaque structure used for type checking */
+struct fm;
+
+/**
+ * fm_bind
+ * @fm_dev:	the OF handle of the FM device.
+ *
+ * Bind to a specific FM device.
+ *
+ * Allowed only after the port was created.
+ *
+ * Return: A handle of the FM device.
+ */
+struct fm *fm_bind(struct device *fm_dev);
+
+/**
+ * fm_unbind
+ * @fm:		A handle of the FM device.
+ *
+ * Un-bind from a specific FM device.
+ *
+ * Allowed only after the port was created.
+ */
+void fm_unbind(struct fm *fm);
+
+/**
+ * fm_get_handle
+ * @fm:		A handle of the FM device
+ *
+ * Get pointer to internal FM strcuture
+ *
+ * Return: A pointer to internal FM structure
+ */
+void *fm_get_handle(struct fm *fm);
+
+/**
+ * fm_get_mem_region
+ * @fm:		A handle of the FM device
+ *
+ * Get FM memory region
+ *
+ * Return: A structure with FM memory region information
+ */
+
+struct resource *fm_get_mem_region(struct fm *fm);
+/**
+ * fm_get_max_frm
+ *
+ * Return: Max frame length configured in the FM driver
+ */
+u16 fm_get_max_frm(void);
+
+/**
+ * fm_get_rx_extra_headroom
+ *
+ * Return: Extra headroom size configured in the FM driver
+ */
+int fm_get_rx_extra_headroom(void);
+
+#endif /* __FSL_FMAN_DRV_H */
diff --git a/drivers/net/ethernet/freescale/fman/inc/service.h b/drivers/net/ethernet/freescale/fman/inc/service.h
new file mode 100644
index 0000000..a370a8e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/service.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008-2015 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 __SERVICE_h
+#define __SERVICE_h
+
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+/* Define ASSERT condition */
+#undef ASSERT
+#define ASSERT(x)       WARN_ON(!(x))
+
+/* In range macro */
+#define IN_RANGE(min, val, max) ((min) <= (val) && (val) <= (max))
+
+/* Pointers Manipulation */
+#define UINT_TO_PTR(_val)           ((void __iomem *)(uintptr_t)(_val))
+#define PTR_MOVE(_ptr, _offset)     (void *)((uint8_t *)(_ptr) + (_offset))
+
+#define ILLEGAL_BASE    (~0)
+
+#endif /* SERVICE */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [v2,5/9] fsl/fman: Add Frame Manager support
  2015-06-24 19:35 [v2,5/9] fsl/fman: Add Frame Manager support igal.liberman
@ 2015-06-25 23:53 ` Paul Bolle
  2015-06-26  0:09     ` Paul Bolle
  2015-06-26  3:54 ` Scott Wood
  1 sibling, 1 reply; 8+ messages in thread
From: Paul Bolle @ 2015-06-25 23:53 UTC (permalink / raw)
  To: igal.liberman, netdev; +Cc: linuxppc-dev, scottwood, madalin.bucur

On Wed, 2015-06-24 at 22:35 +0300, igal.liberman@freescale.com wrote:
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/fman/fm_drv.c

> +u16 fm_get_max_frm(void)
> +{
> +	return fsl_fm_max_frm;
> +}
> +EXPORT_SYMBOL(fm_get_max_frm);

Which module is using this export? (And what does this function
actually do?)

> +int fm_get_rx_extra_headroom(void)
> +{
> +	return ALIGN(fsl_fm_rx_extra_headroom, 16);
> +}
> +EXPORT_SYMBOL(fm_get_rx_extra_headroom);

This exports an unused function.

I don't know how to, well, review a series that adds almost 20K lines.
So I decided to pick one subject: exports. I think I had something to
comment on all eight of them.

I'm not sure if I'll try another scan with a different subject.

Thanks,


Paul Bolle

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [v2,5/9] fsl/fman: Add Frame Manager support
  2015-06-25 23:53 ` Paul Bolle
@ 2015-06-26  0:09     ` Paul Bolle
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Bolle @ 2015-06-26  0:09 UTC (permalink / raw)
  To: igal.liberman, netdev; +Cc: scottwood, linuxppc-dev, madalin.bucur

On Fri, 2015-06-26 at 01:53 +0200, Paul Bolle wrote:
> So I decided to pick one subject: exports. I think I had something to
> comment on all eight of them.

s/eight/twelve/


Paul Bolle
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [v2,5/9] fsl/fman: Add Frame Manager support
@ 2015-06-26  0:09     ` Paul Bolle
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Bolle @ 2015-06-26  0:09 UTC (permalink / raw)
  To: igal.liberman, netdev; +Cc: linuxppc-dev, scottwood, madalin.bucur

On Fri, 2015-06-26 at 01:53 +0200, Paul Bolle wrote:
> So I decided to pick one subject: exports. I think I had something to
> comment on all eight of them.

s/eight/twelve/


Paul Bolle

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [v2,5/9] fsl/fman: Add Frame Manager support
  2015-06-24 19:35 [v2,5/9] fsl/fman: Add Frame Manager support igal.liberman
  2015-06-25 23:53 ` Paul Bolle
@ 2015-06-26  3:54 ` Scott Wood
  2015-07-02 15:32     ` Liberman Igal
  1 sibling, 1 reply; 8+ messages in thread
From: Scott Wood @ 2015-06-26  3:54 UTC (permalink / raw)
  To: igal.liberman; +Cc: netdev, linuxppc-dev, madalin.bucur, pebolle

On Wed, 2015-06-24 at 22:35 +0300, igal.liberman@freescale.com wrote:
> From: Igal Liberman <Igal.Liberman@freescale.com>
> 
> Add Frame Manger Driver support.
> This patch adds The FMan configuration, initialization and
> runtime control routines.
> 
> Signed-off-by: Igal Liberman <Igal.Liberman@freescale.com>
> ---
>  drivers/net/ethernet/freescale/fman/Kconfig        |   35 +
>  drivers/net/ethernet/freescale/fman/Makefile       |    2 +-
>  drivers/net/ethernet/freescale/fman/fm.c           | 1406 
> ++++++++++++++++++++
>  drivers/net/ethernet/freescale/fman/fm.h           |  394 ++++++
>  drivers/net/ethernet/freescale/fman/fm_common.h    |  142 ++
>  drivers/net/ethernet/freescale/fman/fm_drv.c       |  701 ++++++++++
>  drivers/net/ethernet/freescale/fman/fm_drv.h       |  116 ++
>  drivers/net/ethernet/freescale/fman/inc/enet_ext.h |  199 +++
>  drivers/net/ethernet/freescale/fman/inc/fm_ext.h   |  488 +++++++
>  .../net/ethernet/freescale/fman/inc/fsl_fman_drv.h |   99 ++
>  drivers/net/ethernet/freescale/fman/inc/service.h  |   55 +
>  11 files changed, 3636 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/ethernet/freescale/fman/fm.c
>  create mode 100644 drivers/net/ethernet/freescale/fman/fm.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/fm_common.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.c
>  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/inc/enet_ext.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_ext.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
>  create mode 100644 drivers/net/ethernet/freescale/fman/inc/service.h

Again, please start with something pared down, without extraneous features, 
but *with* enough functionality to actually pass packets around.  Getting 
this thing into decent shape is going to be hard enough without carrying 
around the excess baggage.

> diff --git a/drivers/net/ethernet/freescale/fman/Kconfig 
> b/drivers/net/ethernet/freescale/fman/Kconfig
> index 825a0d5..12c75bfd 100644
> --- a/drivers/net/ethernet/freescale/fman/Kconfig
> +++ b/drivers/net/ethernet/freescale/fman/Kconfig
> @@ -7,3 +7,38 @@ config FSL_FMAN
>               Freescale Data-Path Acceleration Architecture Frame Manager
>               (FMan) support
>  
> +if FSL_FMAN
> +
> +config FSL_FM_MAX_FRAME_SIZE
> +     int "Maximum L2 frame size"
> +     range 64 9600
> +     default "1522"
> +     help
> +             Configure this in relation to the maximum possible MTU of your
> +             network configuration. In particular, one would need to
> +             increase this value in order to use jumbo frames.
> +             FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS
> +             (4 bytes) and one ETH+VLAN header (18 bytes), to a total of
> +             22 bytes in excess of the desired L3 MTU.
> +
> +             Note that having too large a FSL_FM_MAX_FRAME_SIZE (much larger
> +             than the actual MTU) may lead to buffer exhaustion, especially
> +             in the case of badly fragmented datagrams on the Rx path.
> +             Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the
> +             actual MTU will lead to frames being dropped.

Scatter gather can't be used for jumbo frames?

Why is this a compile-time option?

> +
> +config FSL_FM_RX_EXTRA_HEADROOM
> +     int "Add extra headroom at beginning of data buffers"
> +     range 16 384
> +     default "64"
> +     help
> +             Configure this to tell the Frame Manager to reserve some extra
> +             space at the beginning of a data buffer on the receive path,
> +             before Internal Context fields are copied. This is in addition
> +             to the private data area already reserved for driver internal
> +             use. The provided value must be a multiple of 16.
> +
> +             This option does not affect in any way the layout of
> +             transmitted buffers.

There's nothing here to indicate when a user would want to do this.

Why is this a compile-time option?

> +             /* FManV3H */
> +             else if (minor == 0 || minor == 2 || minor == 3) {
> +                     intg->fm_muram_size             = 384 * 1024;
> +                     intg->fm_iram_size              = 64 * 1024;
> +                     intg->fm_num_of_ctrl            = 4;
> +
> +                     intg->bmi_max_num_of_tasks      = 128;
> +                     intg->bmi_max_num_of_dmas       = 84;
> +
> +                     intg->num_of_rx_ports           = 8;
> +             } else {
> +                     pr_err("Unsupported FManv3 version\n");
> +                     kfree(intg);
> +                     return NULL;
> +             }
> +
> +             break;
> +     default:
> +             pr_err("Unsupported FMan version\n");
> +             kfree(intg);
> +             return NULL;
> +     }

Don't duplicate error paths.  Use goto like the rest of the kernel.

> +
> +     intg->bmi_max_fifo_size = intg->fm_muram_size;
> +
> +     return intg;
> +}
> +
> +static int is_init_done(struct fman_cfg *p_fm_drv_parameters)

No Hungarian notation.  Check throughout the patchset.

> +{
> +     /* Checks if FMan driver parameters were initialized */
> +     if (!p_fm_drv_parameters)
> +             return 0;
> +     return -EINVAL;
> +}

The name makes it sound like it returns a boolean, but instead it returns 
either 0 or -EINVAL?  Why do you need this wrapper just to do a NULL-pointer 
check?

> +static void free_init_resources(struct fm_t *p_fm)
> +{
> +     if (p_fm->cam_offset)
> +             fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
> +                               p_fm->cam_size);
> +     if (p_fm->fifo_offset)
> +             fm_muram_free_mem(p_fm->p_muram, p_fm->fifo_offset,
> +                               p_fm->fifo_size);
> +}
> +
> +static bool is_fman_ctrl_code_loaded(struct fm_t *p_fm)
> +{
> +     struct fm_iram_regs_t __iomem *p_iram;
> +
> +     p_iram = (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm->base_addr +
> +                                                    FM_MM_IMEM);
> +
> +     return (bool)!!(in_be32(&p_iram->iready) & IRAM_READY);
> +}
> +
> +static int check_fm_parameters(struct fm_t *p_fm)
> +{
> +     if (is_fman_ctrl_code_loaded(p_fm) && !p_fm->reset_on_init) {
> +             pr_err("Old FMan CTRL code is loaded; FM must be reset!\n");
> +             return -EDOM;
> +     }
> +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
> +             if (!p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats ||
> +                 (p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats >
> +                     DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) {
> +                     pr_err("axiDbgNumOfBeats has to be in the range 1 - %d\n",
> +                            DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS);
> +                     return -EDOM;
> +             }
> +     }
> +     if (p_fm->p_fm_drv_param->dma_cam_num_of_entries %
> +         DMA_CAM_UNITS) {
> +             pr_err("dma_cam_num_of_entries has to be divisble by %d\n",
> +                    DMA_CAM_UNITS);
> +             return -EDOM;
> +     }
> +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer >
> +         p_fm->intg->dma_thresh_max_commq) {
> +             pr_err("dma_comm_qtsh_asrt_emer can not be larger than %d\n",
> +                    p_fm->intg->dma_thresh_max_commq);
> +             return -EDOM;
> +     }
> +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >
> +         p_fm->intg->dma_thresh_max_commq) {
> +             pr_err("dma_comm_qtsh_clr_emer can not be larger than %d\n",
> +                    p_fm->intg->dma_thresh_max_commq);
> +             return -EDOM;
> +     }
> +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >=
> +         p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer) {
> +             pr_err("dma_comm_qtsh_clr_emer must be smaller than 
> dma_comm_qtsh_asrt_emer\n");
> +             return -EDOM;
> +     }
> +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
> +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer >
> +                 p_fm->intg->dma_thresh_max_buf) {
> +                     pr_err("dma_read_buf_tsh_asrt_emer can not be larger than %d\n",
> +                            p_fm->intg->dma_thresh_max_buf);
> +                     return -EDOM;
> +             }
> +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >
> +                   p_fm->intg->dma_thresh_max_buf) {
> +                     pr_err("dma_read_buf_tsh_clr_emer can not be larger than %d\n",
> +                            p_fm->intg->dma_thresh_max_buf);
> +                     return -EDOM;
> +             }
> +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >=
> +                   p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer) {
> +                     pr_err("dma_read_buf_tsh_clr_emer must be < 
> dma_read_buf_tsh_asrt_emer\n");
> +                     return -EDOM;
> +             }
> +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer >
> +                   p_fm->intg->dma_thresh_max_buf) {
> +                     pr_err("dma_write_buf_tsh_asrt_emer can not be larger than %d\n",
> +                            p_fm->intg->dma_thresh_max_buf);
> +                     return -EDOM;
> +             }
> +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >
> +                   p_fm->intg->dma_thresh_max_buf) {
> +                     pr_err("dma_write_buf_tsh_clr_emer can not be larger than %d\n",
> +                            p_fm->intg->dma_thresh_max_buf);
> +                     return -EDOM;
> +             }
> +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >=
> +                   p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer) {
> +                     pr_err("dma_write_buf_tsh_clr_emer has to be less than 
> dma_write_buf_tsh_asrt_emer\n");
> +                     return -EDOM;
> +             }
> +     } else {
> +             if ((p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> +                             E_FMAN_DMA_DBG_CNT_INT_READ_EM) ||
> +                     (p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> +                             E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
> +                     (p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> +                             E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT)) {
> +                     pr_err("dma_dbg_cnt_mode value not supported by this integration.\n");
> +                     return -EDOM;
> +             }
> +             if ((p_fm->p_fm_drv_param->dma_emergency_bus_select ==
> +                    FM_DMA_MURAM_READ_EMERGENCY) ||
> +                   (p_fm->p_fm_drv_param->dma_emergency_bus_select ==
> +                    FM_DMA_MURAM_WRITE_EMERGENCY)) {
> +                     pr_err("emergencyBusSelect value not supported by this integration.\n");
> +                     return -EDOM;
> +             }

What do you mean by "integration"?

Why are there still camelCaps in strings?

> +static void unimplemented_isr(void __maybe_unused *h_src_arg)
> +{
> +     pr_err("Unimplemented ISR!\n");
> +}
> +
> +

This message is severely lacking in context.

> +static int init_fm_dma(struct fm_t *p_fm)
> +{
> +     int err;
> +
> +     err = (int)fman_dma_init(p_fm->p_fm_dma_regs,
> +                                  p_fm->p_fm_drv_param);
> +     if (err != 0)
> +             return err;
> +
> +     /* Allocate MURAM for CAM */
> +     p_fm->cam_size = (uint32_t)(p_fm->p_fm_drv_param->
> +                                     dma_cam_num_of_entries *
> +                                     DMA_CAM_SIZEOF_ENTRY);
> +     p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram, p_fm->cam_size);
> +     if (IS_ERR_VALUE(p_fm->cam_offset)) {
> +             pr_err("MURAM alloc for DMA CAM failed\n");
> +             return -ENOMEM;
> +     }
> +
> +     if (p_fm->p_fm_state_struct->rev_info.major_rev == 2) {
> +             uintptr_t cam_base_addr;

u32 __iomem *cam_base_addr;

> +
> +             fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
> +                               p_fm->cam_size);
> +
> +             p_fm->cam_size =
> +                     p_fm->p_fm_drv_param->dma_cam_num_of_entries * 72 + 128;
> +             p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram, (uint32_t)
> +                                                  p_fm->cam_size);
> +                     pr_err("MURAM alloc for DMA CAM failed\n");
> +                     return -ENOMEM;
> +             }
> +
> +             cam_base_addr = fm_muram_offset_to_vbase(p_fm->p_muram,
> +                                                      p_fm->cam_offset);
> +             switch (p_fm->p_fm_drv_param->dma_cam_num_of_entries) {
> +             case (8):
> +                     out_be32((uint32_t __iomem *)cam_base_addr,
> +                              0xff000000);
> +                     break;
> +             case (16):
> +                     out_be32((uint32_t __iomem *)cam_base_addr,
> +                              0xffff0000);
> +                     break;
> +             case (24):
> +                     out_be32((uint32_t __iomem *)cam_base_addr,
> +                              0xffffff00);
> +                     break;
> +             case (32):
> +                     out_be32((uint32_t __iomem *)cam_base_addr,
> +                              0xffffffff);
> +                     break;
> +             default:
> +                     pr_err("wrong dma_cam_num_of_entries\n");
> +                     return -EDOM;
> +             }
> +     }
> +

Please don't use -EDOM for situations where the entire rest of the kernel 
uses -EINVAL.

Unnecessary parentheses.

Couldn't this just be replaced with:
        out_be32(cam_base_addr, ~(1 << (32 - dma_cam_num_of_entries)) - 1);
?

> void *fm_config(struct fm_params_t *p_fm_param)
> +{
> +     struct fm_t *p_fm;
> +     uintptr_t base_addr;
> +
> +     if (!((p_fm_param->firmware.p_code && p_fm_param->firmware.size) ||
> +           (!p_fm_param->firmware.p_code && !p_fm_param->firmware.size)))
> +             return NULL;
> +
> +     base_addr = p_fm_param->base_addr;
> +
> +     /* Allocate FM structure */
> +     p_fm = kzalloc(sizeof(*p_fm), GFP_KERNEL);
> +     if (!p_fm)
> +             return NULL;
> +
> +     p_fm->p_fm_state_struct = kzalloc(sizeof(*p_fm->p_fm_state_struct),
> +                                              GFP_KERNEL);
> +     if (!p_fm->p_fm_state_struct) {
> +             kfree(p_fm);
> +             pr_err("FM Status structure\n");
> +             return NULL;
> +     }

It's generally not recommended to print an error on memory allocation 
failure, but this message doesn't even make sense.

> +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6 &&
> +         p_fm->p_fm_state_struct->rev_info.major_rev != 4 &&
> +         p_fm->reset_on_init) {
> +             err = fw_not_reset_erratum_bugzilla6173wa(p_fm);
> +             if (err != 0)
> +                     return err;

bugzilla6173wa?

> +     } else {
> +             /* Reset the FM if required. */
> +             if (p_fm->reset_on_init) {
> +                     u32 svr = mfspr(SPRN_SVR);
> +
> +                     if (((SVR_SOC_VER(svr) == SVR_T4240 &&
> +                           SVR_REV(svr) > 0x10)) ||
> +                             ((SVR_SOC_VER(svr) == SVR_T4160 &&
> +                               SVR_REV(svr) > 0x10)) ||
> +                             ((SVR_SOC_VER(svr) == SVR_T4080 &&
> +                               SVR_REV(svr) > 0x10)) ||
> +                             (SVR_SOC_VER(svr) == SVR_T2080) ||
> +                             (SVR_SOC_VER(svr) == SVR_T2081)) {
> +                             pr_debug("Hack: No FM reset!\n");
                if (IS_ERR_VALUE(p_fm->cam_offset)) {
Why?

> +                     } else {
> +                             out_be32(&p_fm->p_fm_fpm_regs->fm_rstc,
> +                                      FPM_RSTC_FM_RESET);
> +                             /* Memory barrier */
> +                             mb();
> +                             usleep_range(100, 101);
> +                     }
> +
> +                     if (fman_is_qmi_halt_not_busy_state(
> +                             p_fm->p_fm_qmi_regs)) {

Don't align continuation lines with the if-body.

> +                             fman_resume(p_fm->p_fm_fpm_regs);
> +                             usleep_range(100, 101);
> +                     }
> +             }
> +

Why such a narrow range in usleep_range()?

> +/* Macro for calling MAC error interrupt handler */
> +#define FM_M_CALL_MAC_ERR_ISR(_p_fm, _id) \
> +     (_p_fm->intr_mng[(enum fm_inter_module_event)(FM_EV_ERR_MAC0 + _id)]. \
> +     f_isr(p_fm->intr_mng[(enum fm_inter_module_event)\
> +     (FM_EV_ERR_MAC0 + _id)].h_src_handle))

Why are you casting to an enum just to use it as an array index?

> +int fm_set_exception(struct fm_t *p_fm, enum fm_exceptions exception,
> +                  bool enable)
> +{
> +     uint32_t bit_mask = 0;
> +     enum fman_exceptions fsl_exception;
> +     struct fman_rg fman_rg;
> +     int ret;
> +
> +     ret = is_init_done(p_fm->p_fm_drv_param);
> +     if (ret)
> +             return ret;
> +
> +     fman_rg.bmi_rg = p_fm->p_fm_bmi_regs;
> +     fman_rg.qmi_rg = p_fm->p_fm_qmi_regs;
> +     fman_rg.fpm_rg = p_fm->p_fm_fpm_regs;
> +     fman_rg.dma_rg = p_fm->p_fm_dma_regs;
> +
> +     GET_EXCEPTION_FLAG(bit_mask, exception);
> +     if (bit_mask) {
> +             if (enable)
> +                     p_fm->p_fm_state_struct->exceptions |= bit_mask;
> +             else
> +                     p_fm->p_fm_state_struct->exceptions &= ~bit_mask;
> +
> +             FMAN_EXCEPTION_TRANS(fsl_exception, exception);
> +
> +             return (int)fman_set_exception(&fman_rg,
> +                                            fsl_exception, enable);

fman_set_exception() already returns int.

> +     } else {
> +             pr_err("Undefined exceptioni\n");

Typo.

> +             return -EDOM;

Math argument out of range of function?

What math function is involved?

> +/* Prevents the use of TX port 1 with OP port 0 for FM Major Rev 4 (P1023) 
> */
> 
> +#define FM_LOW_END_RESTRICTION

This is never used (and would be a multiplatform violation if it were).

> +
> +#define GET_EXCEPTION_FLAG(bit_mask, exception)                      \
> +do {                                                                 \
> +     switch ((int)exception) {                                       \
> +     case FM_EX_DMA_BUS_ERROR:                                       \
> +             bit_mask = FM_EX_DMA_BUS_ERROR;                 \
> +             break;                                                  \
> +     case FM_EX_DMA_SINGLE_PORT_ECC:                         \
> +             bit_mask = FM_EX_DMA_SINGLE_PORT_ECC;                   \
> +             break;                                                  \
> +     case FM_EX_DMA_READ_ECC:                                        \
> +             bit_mask = FM_EX_DMA_READ_ECC;                          \
> +             break;                                                  \
> +     case FM_EX_DMA_SYSTEM_WRITE_ECC:                                \
> +             bit_mask = FM_EX_DMA_SYSTEM_WRITE_ECC;                  \
> +             break;                                                  \
> +     case FM_EX_DMA_FM_WRITE_ECC:                                    \
> +             bit_mask = FM_EX_DMA_FM_WRITE_ECC;                      \
> +             break;                                                  \
> +     case FM_EX_FPM_STALL_ON_TASKS:                                  \
> +             bit_mask = FM_EX_FPM_STALL_ON_TASKS;                    \
> +             break;                                                  \
> +     case FM_EX_FPM_SINGLE_ECC:                                      \
> +             bit_mask = FM_EX_FPM_SINGLE_ECC;                        \
> +             break;                                                  \
> +     case FM_EX_FPM_DOUBLE_ECC:                                      \
> +             bit_mask = FM_EX_FPM_DOUBLE_ECC;                        \
> +             break;                                                  \
> +     case FM_EX_QMI_SINGLE_ECC:                                      \
> +             bit_mask = FM_EX_QMI_SINGLE_ECC;                        \
> +             break;                                                  \
> +     case FM_EX_QMI_DOUBLE_ECC:                                      \
> +             bit_mask = FM_EX_QMI_DOUBLE_ECC;                        \
> +             break;                                                  \
> +     case FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:                 \
> +             bit_mask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;           \
> +             break;                                                  \
> +     case FM_EX_BMI_LIST_RAM_ECC:                                    \
> +             bit_mask = FM_EX_BMI_LIST_RAM_ECC;                      \
> +             break;                                                  \
> +     case FM_EX_BMI_STORAGE_PROFILE_ECC:                             \
> +             bit_mask = FM_EX_BMI_STORAGE_PROFILE_ECC;               \
> +             break;                                                  \
> +     case FM_EX_BMI_STATISTICS_RAM_ECC:                              \
> +             bit_mask = FM_EX_BMI_STATISTICS_RAM_ECC;                \
> +             break;                                                  \
> +     case FM_EX_BMI_DISPATCH_RAM_ECC:                                \
> +             bit_mask = FM_EX_BMI_DISPATCH_RAM_ECC;                  \
> +             break;                                                  \
> +     case FM_EX_IRAM_ECC:                                            \
> +             bit_mask = FM_EX_IRAM_ECC;                              \
> +             break;                                                  \
> +     case FM_EX_MURAM_ECC:                                           \
> +             bit_mask = FM_EX_MURAM_ECC;                             \
> +             break;                                                  \
> +     default:                                                        \
> +             bit_mask = 0;                                           \
> +             break;                                                  \
> +     }                                                               \
> +} while (0)
> +
> +#define GET_FM_MODULE_EVENT(_p_fm, _mod, _id, _intr_type, _event)    \
> +do {                                                                 \
> +     switch (_mod) {                                                 \
> +     case (FM_MOD_PRS):                                              \
> +             if (_id)                                                \
> +                     _event = FM_EV_DUMMY_LAST;                      \
> +             else                                                    \
> +                     event = (_intr_type == FM_INTR_TYPE_ERR) ?      \
> +                     FM_EV_ERR_PRS : FM_EV_PRS;                      \
> +             break;                                                  \
> +     case (FM_MOD_TMR):                                              \
> +             if (_id)                                                \
> +                     _event = FM_EV_DUMMY_LAST;                      \
> +             else                                                    \
> +                     _event = (_intr_type == FM_INTR_TYPE_ERR) ?     \
> +                     FM_EV_DUMMY_LAST : FM_EV_TMR;                   \
> +             break;                                                  \
> +     case (FM_MOD_MAC):                                              \
> +                     _event = (_intr_type == FM_INTR_TYPE_ERR) ?     \
> +                     (FM_EV_ERR_MAC0 + _id) :                        \
> +                     (FM_EV_MAC0 + _id);                             \
> +             break;                                                  \
> +     case (FM_MOD_FMAN_CTRL):                                        \
> +             if (_intr_type == FM_INTR_TYPE_ERR)                     \
> +                     _event = FM_EV_DUMMY_LAST;                      \
> +             else                                                    \
> +                     _event = (FM_EV_FMAN_CTRL_0 + _id);             \
> +             break;                                                  \
> +     default:                                                        \
> +             _event = FM_EV_DUMMY_LAST;                              \
> +             break;                                                  \
> +     }                                                               \
> +} while (0)

Use functions instead of macros wherever possible.

> +/* do not change! if changed, must be disabled for rev1 ! */
> +#define DFLT_VERIFY_UCODE                 false

I know I complained about this last time...


> +
> +#define DFLT_DMA_READ_INT_BUF_LOW(dma_thresh_max_buf)        \
> +     ((dma_thresh_max_buf + 1) / 2)
> +#define DFLT_DMA_READ_INT_BUF_HIGH(dma_thresh_max_buf)       \
> +     ((dma_thresh_max_buf + 1) * 3 / 4)
> +#define DFLT_DMA_WRITE_INT_BUF_LOW(dma_thresh_max_buf)       \
> +     ((dma_thresh_max_buf + 1) / 2)
> +#define DFLT_DMA_WRITE_INT_BUF_HIGH(dma_thresh_max_buf)\
> +     ((dma_thresh_max_buf + 1) * 3 / 4)
> +#define DFLT_DMA_COMM_Q_LOW(major, dma_thresh_max_commq)     \
> +     ((major == 6) ? 0x2A : ((dma_thresh_max_commq + 1) / 2))
> +#define DFLT_DMA_COMM_Q_HIGH(major, dma_thresh_max_commq)    \
> +     ((major == 6) ? 0x3f : ((dma_thresh_max_commq + 1) * 3 / 4))
> +#define DFLT_TOTAL_NUM_OF_TASKS(major, minor, bmi_max_num_of_tasks)  \
> +     ((major == 6) ? ((minor == 1 || minor == 4) ? 59 : 124) :       \
> +     bmi_max_num_of_tasks)

Where do 0x2a, 0x3f, 59, 124, etc come from?  Please define symbolically.

> +#define DFLT_TOTAL_FIFO_SIZE(major, minor)                   \
> +     ((major == 6) ?                                         \
> +     ((minor == 1 || minor == 4) ? (156 * 1024) : (295 * 1024)) :    \
> +     (((major == 2) || (major == 5)) ?                       \
> +     (100 * 1024) : ((major == 4) ?                  \
> +     (46 * 1024) : (122 * 1024))))

This isn't the International Obfuscated C Code Contest.

> 
> +/* Memory Mapped Registers */
> +
> +struct fm_iram_regs_t {
> +     uint32_t iadd;  /* FM IRAM instruction address register */
> +     uint32_t idata;/* FM IRAM instruction data register */
> +     uint32_t itcfg;/* FM IRAM timing config register */
> +     uint32_t iready;/* FM IRAM ready register */
> +     uint8_t res[0x80000 - 0x10];
> +} __attribute__((__packed__));

Why do you need __packed__ on this?

Why do you need the padding on the end?

> +struct fm_t {
> +     uintptr_t base_addr;
> +     char fm_module_name[MODULE_NAME_SIZE];
> +     struct fm_intr_src_t intr_mng[FM_EV_DUMMY_LAST];
> +
> +     struct fman_fpm_regs __iomem *p_fm_fpm_regs;
> +     struct fman_bmi_regs __iomem *p_fm_bmi_regs;
> +     struct fman_qmi_regs __iomem *p_fm_qmi_regs;
> +     struct fman_dma_regs __iomem *p_fm_dma_regs;
> +     struct fman_regs __iomem *p_fm_regs;
> +     fm_exceptions_cb *f_exception;
> +     fm_bus_error_cb *f_bus_error;
> +     void *h_app;            /* Application handle */
> +     spinlock_t *spinlock;

Why is the spinlock dynamically allocated?

> +/* 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"

Is this indirection really needed?

> +/* 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;

If it's configurable via bootargs, why is the kconfig needed?

> +
> +u16 fm_get_max_frm(void)
> +{
> +     return fsl_fm_max_frm;
> +}
> +EXPORT_SYMBOL(fm_get_max_frm);

fsl_fm_max_frm isn't static, so why is this accessor needed?

> +int fm_get_rx_extra_headroom(void)
> +{
> +     return ALIGN(fsl_fm_rx_extra_headroom, 16);
> +}
> +EXPORT_SYMBOL(fm_get_rx_extra_headroom);

Why not just align it when you set the variable?

> +
> +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.
> +              */
> +             pr_err("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) {
> +             pr_err("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;
> +     }
> +
> +     pr_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) {
> +             pr_err("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 < FSL_FM_RX_EXTRA_HEADROOM_MIN ||
> +         fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) {
> +             pr_err("Invalid value for %s=%d prop in bootargs; will use the default 
> FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n",
> +                    FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
> +                    fsl_fm_rx_extra_headroom,
> +                    CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
> +             fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
> +     }
> +
> +     pr_info("Using fsl_fm_rx_extra_headroom=%d from bootargs\n",
> +             fsl_fm_rx_extra_headroom);

This is unnecessarily verbose.

> +
> +     return 0;
> +}
> +early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, fm_set_rx_extra_headroom);

Why early?

> +static irqreturn_t fm_err_irq(int irq, void *_dev)
> +{
> +     struct fm_drv_t *fm_drv = (struct fm_drv_t *)_dev;
> +
> +     if (!fm_drv || !fm_drv->h_dev)
> +             return IRQ_NONE;

Why would you request the IRQ if either of these are NULL?

> +static const struct qe_firmware *find_fman_microcode(void)
> +{
> +     static const struct qe_firmware *uc_patch;
> +     struct device_node *np;
> +
> +     if (uc_patch)
> +             return uc_patch;
> +
> +     /* The firmware should be inside the device tree. */
> +     np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
> +     if (np) {
> +             uc_patch = of_get_property(np, "fsl,firmware", NULL);

I don't see any binding for this.

> +static int fill_qman_channhels_info(struct fm_drv_t *fm_drv)

"channhels"?


> +static struct fm_drv_t *read_fm_dev_tree_node(struct platform_device 
> *of_dev)
> +{
> +     struct fm_drv_t *fm_drv;
> +     struct device_node *fm_node, *dev_node;
> +     struct of_device_id name;
> +     struct resource res;
> +     const uint32_t *uint32_prop;
> +     int lenp, err;
> +     struct clk *clk;
> +     u32 clk_rate;
> +
> +     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)) {
> +             pr_err("of_get_property(%s, cell-index) failed\n",
> +                    fm_node->full_name);
> +             goto _return_null;
> +     }
> +     if (WARN_ON(lenp != sizeof(uint32_t)))
> +             return NULL;
> +
> +     fm_drv = kzalloc(sizeof(*fm_drv), GFP_KERNEL);
> +     if (!fm_drv)
> +             goto _return_null;
> +
> +     fm_drv->dev = &of_dev->dev;
> +     fm_drv->id = (u8)*uint32_prop;
> +
> +     /* Get the FM interrupt */
> +     fm_drv->irq = of_irq_to_resource(fm_node, 0, NULL);
> +     if (unlikely(fm_drv->irq == 0)) {
> +             pr_err("of_irq_to_resource() = %d\n", NO_IRQ);
> +             goto _return_null;
> +     }
> +
> +     /* Get the FM error interrupt */
> +     fm_drv->err_irq = of_irq_to_resource(fm_node, 1, NULL);
> +
> +     /* Get the FM address */
> +     err = of_address_to_resource(fm_node, 0, &res);
> +     if (unlikely(err < 0)) {
> +             pr_err("of_address_to_resource() = %d\n", err);
> +             goto _return_null;
> +     }
> +
> +     fm_drv->fm_base_addr = 0;
> +     fm_drv->fm_phys_base_addr = res.start;
> +     fm_drv->fm_mem_size = res.end + 1 - res.start;
> +

Why are you using these OF functions rather than using platform_device 
mechanisms?

> +     clk = clk_get(fm_drv->dev, fm_drv->id == 0 ? "fm0clk" : "fm1clk");
> +     if (IS_ERR(clk)) {
> +             pr_err("Failed to get FM%d clock structure\n", fm_drv->id);
> +             goto _return_null;
> +     }

Get the clock from the clocks property of the device tree node, not by 
hardcoding what you think the clock's name will be.

> +     uint32_prop = (uint32_t *)of_get_property(fm_node,
> +                                               "fsl,qman-channel-range",
> +                                               &lenp);
> 

Don't cast away the const.

> +     if (unlikely(!uint32_prop)) {

Don't use unlikely() in paths that aren't performance-critical.

> +     /* Get the MURAM base address and size */
> +     memset(&name, 0, sizeof(name));
> +     if (WARN_ON(strlen("muram") >= sizeof(name.name)))
> +             goto _return_null;
> +     strcpy(name.name, "muram");
> +     if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(name.compatible)))
> +             goto _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))) {

Why not just define the match struct statically?

> +#ifndef __SERVICE_h
> +#define __SERVICE_h
> +
> +#include <linux/version.h>

What do you need this for?

> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/io.h>

What do you use in this file from linux/io.h?

> +/* Define ASSERT condition */
> +#undef ASSERT
> +#define ASSERT(x)       WARN_ON(!(x))

Why not just use WARN_ON directly?

> +/* Pointers Manipulation */
> +#define UINT_TO_PTR(_val)           ((void __iomem *)(uintptr_t)(_val))

Why are you doing so much of this that you need macros for it?

UINT_TO_PTR seems like it could be hiding 64-bit-cleanliness bugs.  From 
looking at the places it's used, it certainly would be if the value fed into 
it were actually "unsigned int".

Just define base_addr and such as "void __iomem *".

> +#define PTR_MOVE(_ptr, _offset)     (void *)((uint8_t *)(_ptr) + (_offset))

I don't see this used anywhere.  Likewise IN_RANGE and ILLEGAL_BASE.

-Scott

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [v2,5/9] fsl/fman: Add Frame Manager support
  2015-06-26  3:54 ` Scott Wood
@ 2015-07-02 15:32     ` Liberman Igal
  0 siblings, 0 replies; 8+ messages in thread
From: Liberman Igal @ 2015-07-02 15:32 UTC (permalink / raw)
  To: Scott Wood; +Cc: netdev, linuxppc-dev, Madalin-Cristian Bucur, pebolle

Hi Scott,
Thank you for your feedback, please take a look at my comments/questions.

Regards,
Igal Liberman.

> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Friday, June 26, 2015 6:55 AM
> To: Liberman Igal-B31950
> Cc: netdev@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; Bucur Madalin-
> Cristian-B32716; pebolle@tiscali.nl
> Subject: Re: [v2,5/9] fsl/fman: Add Frame Manager support
> 
> On Wed, 2015-06-24 at 22:35 +0300, igal.liberman@freescale.com wrote:
> > From: Igal Liberman <Igal.Liberman@freescale.com>
> >
> > Add Frame Manger Driver support.
> > This patch adds The FMan configuration, initialization and runtime
> > control routines.
> >
> > Signed-off-by: Igal Liberman <Igal.Liberman@freescale.com>
> > ---
> >  drivers/net/ethernet/freescale/fman/Kconfig        |   35 +
> >  drivers/net/ethernet/freescale/fman/Makefile       |    2 +-
> >  drivers/net/ethernet/freescale/fman/fm.c           | 1406
> > ++++++++++++++++++++
> >  drivers/net/ethernet/freescale/fman/fm.h           |  394 ++++++
> >  drivers/net/ethernet/freescale/fman/fm_common.h    |  142 ++
> >  drivers/net/ethernet/freescale/fman/fm_drv.c       |  701 ++++++++++
> >  drivers/net/ethernet/freescale/fman/fm_drv.h       |  116 ++
> >  drivers/net/ethernet/freescale/fman/inc/enet_ext.h |  199 +++
> >  drivers/net/ethernet/freescale/fman/inc/fm_ext.h   |  488 +++++++
> >  .../net/ethernet/freescale/fman/inc/fsl_fman_drv.h |   99 ++
> >  drivers/net/ethernet/freescale/fman/inc/service.h  |   55 +
> >  11 files changed, 3636 insertions(+), 1 deletion(-)  create mode
> > 100644 drivers/net/ethernet/freescale/fman/fm.c
> >  create mode 100644 drivers/net/ethernet/freescale/fman/fm.h
> >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_common.h
> >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.c
> >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.h
> >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/enet_ext.h
> >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_ext.h
> >  create mode 100644
> > drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
> >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/service.h
> 
> Again, please start with something pared down, without extraneous
> features, but *with* enough functionality to actually pass packets around.
> Getting this thing into decent shape is going to be hard enough without
> carrying around the excess baggage.
> 
> > diff --git a/drivers/net/ethernet/freescale/fman/Kconfig
> > b/drivers/net/ethernet/freescale/fman/Kconfig
> > index 825a0d5..12c75bfd 100644
> > --- a/drivers/net/ethernet/freescale/fman/Kconfig
> > +++ b/drivers/net/ethernet/freescale/fman/Kconfig
> > @@ -7,3 +7,38 @@ config FSL_FMAN
> >               Freescale Data-Path Acceleration Architecture Frame Manager
> >               (FMan) support
> >
> > +if FSL_FMAN
> > +
> > +config FSL_FM_MAX_FRAME_SIZE
> > +     int "Maximum L2 frame size"
> > +     range 64 9600
> > +     default "1522"
> > +     help
> > +             Configure this in relation to the maximum possible MTU of your
> > +             network configuration. In particular, one would need to
> > +             increase this value in order to use jumbo frames.
> > +             FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS
> > +             (4 bytes) and one ETH+VLAN header (18 bytes), to a total of
> > +             22 bytes in excess of the desired L3 MTU.
> > +
> > +             Note that having too large a FSL_FM_MAX_FRAME_SIZE (much
> larger
> > +             than the actual MTU) may lead to buffer exhaustion, especially
> > +             in the case of badly fragmented datagrams on the Rx path.
> > +             Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the
> > +             actual MTU will lead to frames being dropped.
> 
> Scatter gather can't be used for jumbo frames?
> 

Scatter gather is used, it's introduced in dpaa_eth as a separate patch from the basic support.
The dpaa_eth can work in S/G mode or use large buffers, max frame size sized to reduce S/G overhead (performance vs memory used trade-off).

> Why is this a compile-time option?
> 

This is needed for a couple of reasons:
 - FMan resource sizing - we need to know the maximum frame size we plan to use for determining the Rx FIFO sizes at config time
 - There are issues when changing the MAC maximum frame size at runtime thus the need to set in HW the maximum allowable and compensate from sw (drop frames above the set MTU).

> > +
> > +config FSL_FM_RX_EXTRA_HEADROOM
> > +     int "Add extra headroom at beginning of data buffers"
> > +     range 16 384
> > +     default "64"
> > +     help
> > +             Configure this to tell the Frame Manager to reserve some extra
> > +             space at the beginning of a data buffer on the receive path,
> > +             before Internal Context fields are copied. This is in addition
> > +             to the private data area already reserved for driver internal
> > +             use. The provided value must be a multiple of 16.
> > +
> > +             This option does not affect in any way the layout of
> > +             transmitted buffers.
> 
> There's nothing here to indicate when a user would want to do this.
> 
> Why is this a compile-time option?
> 

This allows reserving some more space at the start of the skb and may avoid the need for a skb_realloc_headroom().

> > +             /* FManV3H */
> > +             else if (minor == 0 || minor == 2 || minor == 3) {
> > +                     intg->fm_muram_size             = 384 * 1024;
> > +                     intg->fm_iram_size              = 64 * 1024;
> > +                     intg->fm_num_of_ctrl            = 4;
> > +
> > +                     intg->bmi_max_num_of_tasks      = 128;
> > +                     intg->bmi_max_num_of_dmas       = 84;
> > +
> > +                     intg->num_of_rx_ports           = 8;
> > +             } else {
> > +                     pr_err("Unsupported FManv3 version\n");
> > +                     kfree(intg);
> > +                     return NULL;
> > +             }
> > +
> > +             break;
> > +     default:
> > +             pr_err("Unsupported FMan version\n");
> > +             kfree(intg);
> > +             return NULL;
> > +     }
> 
> Don't duplicate error paths.  Use goto like the rest of the kernel.
> 

Done, here and in other places too.

> > +
> > +     intg->bmi_max_fifo_size = intg->fm_muram_size;
> > +
> > +     return intg;
> > +}
> > +
> > +static int is_init_done(struct fman_cfg *p_fm_drv_parameters)
> 
> No Hungarian notation.  Check throughout the patchset.
> 

I'm removing Hungarian notation from the code. 

> > +{
> > +     /* Checks if FMan driver parameters were initialized */
> > +     if (!p_fm_drv_parameters)
> > +             return 0;
> > +     return -EINVAL;
> > +}
> 
> The name makes it sound like it returns a boolean, but instead it returns
> either 0 or -EINVAL?  Why do you need this wrapper just to do a NULL-
> pointer check?
> 

Changed to boolean.
This is used to check that a certain API call is made after initialization is finalized.
If we were to use the pointer check in every place it would be less obvious what we're checking for (it could appear we check for a pointer we're not using).

> > +static void free_init_resources(struct fm_t *p_fm) {
> > +     if (p_fm->cam_offset)
> > +             fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
> > +                               p_fm->cam_size);
> > +     if (p_fm->fifo_offset)
> > +             fm_muram_free_mem(p_fm->p_muram, p_fm->fifo_offset,
> > +                               p_fm->fifo_size); }
> > +
> > +static bool is_fman_ctrl_code_loaded(struct fm_t *p_fm) {
> > +     struct fm_iram_regs_t __iomem *p_iram;
> > +
> > +     p_iram = (struct fm_iram_regs_t __iomem *)UINT_TO_PTR(p_fm-
> >base_addr +
> > +                                                    FM_MM_IMEM);
> > +
> > +     return (bool)!!(in_be32(&p_iram->iready) & IRAM_READY); }
> > +
> > +static int check_fm_parameters(struct fm_t *p_fm) {
> > +     if (is_fman_ctrl_code_loaded(p_fm) && !p_fm->reset_on_init) {
> > +             pr_err("Old FMan CTRL code is loaded; FM must be reset!\n");
> > +             return -EDOM;
> > +     }
> > +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
> > +             if (!p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats ||
> > +                 (p_fm->p_fm_drv_param->dma_axi_dbg_num_of_beats >
> > +                     DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) {
> > +                     pr_err("axiDbgNumOfBeats has to be in the range 1 - %d\n",
> > +                            DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS);
> > +                     return -EDOM;
> > +             }
> > +     }
> > +     if (p_fm->p_fm_drv_param->dma_cam_num_of_entries %
> > +         DMA_CAM_UNITS) {
> > +             pr_err("dma_cam_num_of_entries has to be divisble by %d\n",
> > +                    DMA_CAM_UNITS);
> > +             return -EDOM;
> > +     }
> > +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer >
> > +         p_fm->intg->dma_thresh_max_commq) {
> > +             pr_err("dma_comm_qtsh_asrt_emer can not be larger than %d\n",
> > +                    p_fm->intg->dma_thresh_max_commq);
> > +             return -EDOM;
> > +     }
> > +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >
> > +         p_fm->intg->dma_thresh_max_commq) {
> > +             pr_err("dma_comm_qtsh_clr_emer can not be larger than %d\n",
> > +                    p_fm->intg->dma_thresh_max_commq);
> > +             return -EDOM;
> > +     }
> > +     if (p_fm->p_fm_drv_param->dma_comm_qtsh_clr_emer >=
> > +         p_fm->p_fm_drv_param->dma_comm_qtsh_asrt_emer) {
> > +             pr_err("dma_comm_qtsh_clr_emer must be smaller than
> > dma_comm_qtsh_asrt_emer\n");
> > +             return -EDOM;
> > +     }
> > +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
> > +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer >
> > +                 p_fm->intg->dma_thresh_max_buf) {
> > +                     pr_err("dma_read_buf_tsh_asrt_emer can not be larger than
> %d\n",
> > +                            p_fm->intg->dma_thresh_max_buf);
> > +                     return -EDOM;
> > +             }
> > +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >
> > +                   p_fm->intg->dma_thresh_max_buf) {
> > +                     pr_err("dma_read_buf_tsh_clr_emer can not be larger than
> %d\n",
> > +                            p_fm->intg->dma_thresh_max_buf);
> > +                     return -EDOM;
> > +             }
> > +             if (p_fm->p_fm_drv_param->dma_read_buf_tsh_clr_emer >=
> > +                   p_fm->p_fm_drv_param->dma_read_buf_tsh_asrt_emer) {
> > +                     pr_err("dma_read_buf_tsh_clr_emer must be <
> > dma_read_buf_tsh_asrt_emer\n");
> > +                     return -EDOM;
> > +             }
> > +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer >
> > +                   p_fm->intg->dma_thresh_max_buf) {
> > +                     pr_err("dma_write_buf_tsh_asrt_emer can not be larger than
> %d\n",
> > +                            p_fm->intg->dma_thresh_max_buf);
> > +                     return -EDOM;
> > +             }
> > +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >
> > +                   p_fm->intg->dma_thresh_max_buf) {
> > +                     pr_err("dma_write_buf_tsh_clr_emer can not be larger than
> %d\n",
> > +                            p_fm->intg->dma_thresh_max_buf);
> > +                     return -EDOM;
> > +             }
> > +             if (p_fm->p_fm_drv_param->dma_write_buf_tsh_clr_emer >=
> > +                   p_fm->p_fm_drv_param->dma_write_buf_tsh_asrt_emer) {
> > +                     pr_err("dma_write_buf_tsh_clr_emer has to be
> > + less than
> > dma_write_buf_tsh_asrt_emer\n");
> > +                     return -EDOM;
> > +             }
> > +     } else {
> > +             if ((p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> > +                             E_FMAN_DMA_DBG_CNT_INT_READ_EM) ||
> > +                     (p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> > +                             E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
> > +                     (p_fm->p_fm_drv_param->dma_dbg_cnt_mode ==
> > +                             E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT)) {
> > +                     pr_err("dma_dbg_cnt_mode value not supported by this
> integration.\n");
> > +                     return -EDOM;
> > +             }
> > +             if ((p_fm->p_fm_drv_param->dma_emergency_bus_select ==
> > +                    FM_DMA_MURAM_READ_EMERGENCY) ||
> > +                   (p_fm->p_fm_drv_param->dma_emergency_bus_select ==
> > +                    FM_DMA_MURAM_WRITE_EMERGENCY)) {
> > +                     pr_err("emergencyBusSelect value not supported by this
> integration.\n");
> > +                     return -EDOM;
> > +             }
> 
> What do you mean by "integration"?
> 

Changed it to SoC, those are run time checks for different SoCs (Different FMan versions).

> Why are there still camelCaps in strings?
> 

Leftovers. Removed (here and in other places).

> > +static void unimplemented_isr(void __maybe_unused *h_src_arg) {
> > +     pr_err("Unimplemented ISR!\n");
> > +}
> > +
> > +
> 
> This message is severely lacking in context.
> 

We'll, it's used in a case there's an event with no registered call back.
I think checking for NULL is better (instead of calling this ISR).
I'll change this code. 

> > +static int init_fm_dma(struct fm_t *p_fm) {
> > +     int err;
> > +
> > +     err = (int)fman_dma_init(p_fm->p_fm_dma_regs,
> > +                                  p_fm->p_fm_drv_param);
> > +     if (err != 0)
> > +             return err;
> > +
> > +     /* Allocate MURAM for CAM */
> > +     p_fm->cam_size = (uint32_t)(p_fm->p_fm_drv_param->
> > +                                     dma_cam_num_of_entries *
> > +                                     DMA_CAM_SIZEOF_ENTRY);
> > +     p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram, p_fm-
> >cam_size);
> > +     if (IS_ERR_VALUE(p_fm->cam_offset)) {
> > +             pr_err("MURAM alloc for DMA CAM failed\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     if (p_fm->p_fm_state_struct->rev_info.major_rev == 2) {
> > +             uintptr_t cam_base_addr;
> 
> u32 __iomem *cam_base_addr;
> 

Done.

> > +
> > +             fm_muram_free_mem(p_fm->p_muram, p_fm->cam_offset,
> > +                               p_fm->cam_size);
> > +
> > +             p_fm->cam_size =
> > +                     p_fm->p_fm_drv_param->dma_cam_num_of_entries * 72 +
> 128;
> > +             p_fm->cam_offset = fm_muram_alloc(p_fm->p_muram,
> (uint32_t)
> > +                                                  p_fm->cam_size);
> > +                     pr_err("MURAM alloc for DMA CAM failed\n");
> > +                     return -ENOMEM;
> > +             }
> > +
> > +             cam_base_addr = fm_muram_offset_to_vbase(p_fm->p_muram,
> > +                                                      p_fm->cam_offset);
> > +             switch (p_fm->p_fm_drv_param->dma_cam_num_of_entries) {
> > +             case (8):
> > +                     out_be32((uint32_t __iomem *)cam_base_addr,
> > +                              0xff000000);
> > +                     break;
> > +             case (16):
> > +                     out_be32((uint32_t __iomem *)cam_base_addr,
> > +                              0xffff0000);
> > +                     break;
> > +             case (24):
> > +                     out_be32((uint32_t __iomem *)cam_base_addr,
> > +                              0xffffff00);
> > +                     break;
> > +             case (32):
> > +                     out_be32((uint32_t __iomem *)cam_base_addr,
> > +                              0xffffffff);
> > +                     break;
> > +             default:
> > +                     pr_err("wrong dma_cam_num_of_entries\n");
> > +                     return -EDOM;
> > +             }
> > +     }
> > +
> 
> Please don't use -EDOM for situations where the entire rest of the kernel
> uses -EINVAL.
> 
> Unnecessary parentheses.
> 
> Couldn't this just be replaced with:
>         out_be32(cam_base_addr, ~(1 << (32 - dma_cam_num_of_entries)) - 1);
> ?
> 

Changed this to something similar to your suggestion. 

> > void *fm_config(struct fm_params_t *p_fm_param)
> > +{
> > +     struct fm_t *p_fm;
> > +     uintptr_t base_addr;
> > +
> > +     if (!((p_fm_param->firmware.p_code && p_fm_param-
> >firmware.size) ||
> > +           (!p_fm_param->firmware.p_code && !p_fm_param-
> >firmware.size)))
> > +             return NULL;
> > +
> > +     base_addr = p_fm_param->base_addr;
> > +
> > +     /* Allocate FM structure */
> > +     p_fm = kzalloc(sizeof(*p_fm), GFP_KERNEL);
> > +     if (!p_fm)
> > +             return NULL;
> > +
> > +     p_fm->p_fm_state_struct = kzalloc(sizeof(*p_fm-
> >p_fm_state_struct),
> > +                                              GFP_KERNEL);
> > +     if (!p_fm->p_fm_state_struct) {
> > +             kfree(p_fm);
> > +             pr_err("FM Status structure\n");
> > +             return NULL;
> > +     }
> 
> It's generally not recommended to print an error on memory allocation
> failure, but this message doesn't even make sense.
> 

Removed those prints (here and in other places).

> > +     if (p_fm->p_fm_state_struct->rev_info.major_rev < 6 &&
> > +         p_fm->p_fm_state_struct->rev_info.major_rev != 4 &&
> > +         p_fm->reset_on_init) {
> > +             err = fw_not_reset_erratum_bugzilla6173wa(p_fm);
> > +             if (err != 0)
> > +                     return err;
> 
> bugzilla6173wa?
> 

This is the name of an old issue tracking system id that leaked into the codebase.
I'll rename it.

> > +     } else {
> > +             /* Reset the FM if required. */
> > +             if (p_fm->reset_on_init) {
> > +                     u32 svr = mfspr(SPRN_SVR);
> > +
> > +                     if (((SVR_SOC_VER(svr) == SVR_T4240 &&
> > +                           SVR_REV(svr) > 0x10)) ||
> > +                             ((SVR_SOC_VER(svr) == SVR_T4160 &&
> > +                               SVR_REV(svr) > 0x10)) ||
> > +                             ((SVR_SOC_VER(svr) == SVR_T4080 &&
> > +                               SVR_REV(svr) > 0x10)) ||
> > +                             (SVR_SOC_VER(svr) == SVR_T2080) ||
> > +                             (SVR_SOC_VER(svr) == SVR_T2081)) {
> > +                             pr_debug("Hack: No FM reset!\n");
>                 if (IS_ERR_VALUE(p_fm->cam_offset)) { Why?
> 

fm_muram_alloc () can return an offset or an Error.

> > +                     } else {
> > +                             out_be32(&p_fm->p_fm_fpm_regs->fm_rstc,
> > +                                      FPM_RSTC_FM_RESET);
> > +                             /* Memory barrier */
> > +                             mb();
> > +                             usleep_range(100, 101);
> > +                     }
> > +
> > +                     if (fman_is_qmi_halt_not_busy_state(
> > +                             p_fm->p_fm_qmi_regs)) {
> 
> Don't align continuation lines with the if-body.
> 

Done.

> > +                             fman_resume(p_fm->p_fm_fpm_regs);
> > +                             usleep_range(100, 101);
> > +                     }
> > +             }
> > +
> 
> Why such a narrow range in usleep_range()?
> 

I was looking here: https://www.kernel.org/doc/Documentation/timers/timers-howto.txt
In addition, checkpatch says that usleep_range is preferred over udelay.
So instead of udelay(100), I used usleep_range(100, 101);
We can change the range, in your opinion, what is the more appropriate range?

> > +/* Macro for calling MAC error interrupt handler */ #define
> > +FM_M_CALL_MAC_ERR_ISR(_p_fm, _id) \
> > +     (_p_fm->intr_mng[(enum
> fm_inter_module_event)(FM_EV_ERR_MAC0 + _id)]. \
> > +     f_isr(p_fm->intr_mng[(enum fm_inter_module_event)\
> > +     (FM_EV_ERR_MAC0 + _id)].h_src_handle))
> 
> Why are you casting to an enum just to use it as an array index?
> 

Removed this casting.

> > +int fm_set_exception(struct fm_t *p_fm, enum fm_exceptions
> exception,
> > +                  bool enable)
> > +{
> > +     uint32_t bit_mask = 0;
> > +     enum fman_exceptions fsl_exception;
> > +     struct fman_rg fman_rg;
> > +     int ret;
> > +
> > +     ret = is_init_done(p_fm->p_fm_drv_param);
> > +     if (ret)
> > +             return ret;
> > +
> > +     fman_rg.bmi_rg = p_fm->p_fm_bmi_regs;
> > +     fman_rg.qmi_rg = p_fm->p_fm_qmi_regs;
> > +     fman_rg.fpm_rg = p_fm->p_fm_fpm_regs;
> > +     fman_rg.dma_rg = p_fm->p_fm_dma_regs;
> > +
> > +     GET_EXCEPTION_FLAG(bit_mask, exception);
> > +     if (bit_mask) {
> > +             if (enable)
> > +                     p_fm->p_fm_state_struct->exceptions |= bit_mask;
> > +             else
> > +                     p_fm->p_fm_state_struct->exceptions &=
> > + ~bit_mask;
> > +
> > +             FMAN_EXCEPTION_TRANS(fsl_exception, exception);
> > +
> > +             return (int)fman_set_exception(&fman_rg,
> > +                                            fsl_exception, enable);
> 
> fman_set_exception() already returns int.
> 

Removed this casting (here and elsewhere).

> > +     } else {
> > +             pr_err("Undefined exceptioni\n");
> 
> Typo.

Fixed, thanks.

> 
> > +             return -EDOM;
> 
> Math argument out of range of function?
> 
> What math function is involved?
> 

Dropped the use of EDOM, changed to EINVAL (here and elsewhere).

> > +/* Prevents the use of TX port 1 with OP port 0 for FM Major Rev 4
> > +(P1023)
> > */
> >
> > +#define FM_LOW_END_RESTRICTION
> 
> This is never used (and would be a multiplatform violation if it were).
> 

Leftovers, removed.

> > +
> > +#define GET_EXCEPTION_FLAG(bit_mask, exception)                      \
> > +do {                                                                 \
> > +     switch ((int)exception) {                                       \
> > +     case FM_EX_DMA_BUS_ERROR:                                       \
> > +             bit_mask = FM_EX_DMA_BUS_ERROR;                 \
> > +             break;                                                  \
> > +     case FM_EX_DMA_SINGLE_PORT_ECC:                         \
> > +             bit_mask = FM_EX_DMA_SINGLE_PORT_ECC;                   \
> > +             break;                                                  \
> > +     case FM_EX_DMA_READ_ECC:                                        \
> > +             bit_mask = FM_EX_DMA_READ_ECC;                          \
> > +             break;                                                  \
> > +     case FM_EX_DMA_SYSTEM_WRITE_ECC:                                \
> > +             bit_mask = FM_EX_DMA_SYSTEM_WRITE_ECC;                  \
> > +             break;                                                  \
> > +     case FM_EX_DMA_FM_WRITE_ECC:                                    \
> > +             bit_mask = FM_EX_DMA_FM_WRITE_ECC;                      \
> > +             break;                                                  \
> > +     case FM_EX_FPM_STALL_ON_TASKS:                                  \
> > +             bit_mask = FM_EX_FPM_STALL_ON_TASKS;                    \
> > +             break;                                                  \
> > +     case FM_EX_FPM_SINGLE_ECC:                                      \
> > +             bit_mask = FM_EX_FPM_SINGLE_ECC;                        \
> > +             break;                                                  \
> > +     case FM_EX_FPM_DOUBLE_ECC:                                      \
> > +             bit_mask = FM_EX_FPM_DOUBLE_ECC;                        \
> > +             break;                                                  \
> > +     case FM_EX_QMI_SINGLE_ECC:                                      \
> > +             bit_mask = FM_EX_QMI_SINGLE_ECC;                        \
> > +             break;                                                  \
> > +     case FM_EX_QMI_DOUBLE_ECC:                                      \
> > +             bit_mask = FM_EX_QMI_DOUBLE_ECC;                        \
> > +             break;                                                  \
> > +     case FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:                 \
> > +             bit_mask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;           \
> > +             break;                                                  \
> > +     case FM_EX_BMI_LIST_RAM_ECC:                                    \
> > +             bit_mask = FM_EX_BMI_LIST_RAM_ECC;                      \
> > +             break;                                                  \
> > +     case FM_EX_BMI_STORAGE_PROFILE_ECC:                             \
> > +             bit_mask = FM_EX_BMI_STORAGE_PROFILE_ECC;               \
> > +             break;                                                  \
> > +     case FM_EX_BMI_STATISTICS_RAM_ECC:                              \
> > +             bit_mask = FM_EX_BMI_STATISTICS_RAM_ECC;                \
> > +             break;                                                  \
> > +     case FM_EX_BMI_DISPATCH_RAM_ECC:                                \
> > +             bit_mask = FM_EX_BMI_DISPATCH_RAM_ECC;                  \
> > +             break;                                                  \
> > +     case FM_EX_IRAM_ECC:                                            \
> > +             bit_mask = FM_EX_IRAM_ECC;                              \
> > +             break;                                                  \
> > +     case FM_EX_MURAM_ECC:                                           \
> > +             bit_mask = FM_EX_MURAM_ECC;                             \
> > +             break;                                                  \
> > +     default:                                                        \
> > +             bit_mask = 0;                                           \
> > +             break;                                                  \
> > +     }                                                               \
> > +} while (0)
> > +
> > +#define GET_FM_MODULE_EVENT(_p_fm, _mod, _id, _intr_type,
> _event)    \
> > +do {                                                                 \
> > +     switch (_mod) {                                                 \
> > +     case (FM_MOD_PRS):                                              \
> > +             if (_id)                                                \
> > +                     _event = FM_EV_DUMMY_LAST;                      \
> > +             else                                                    \
> > +                     event = (_intr_type == FM_INTR_TYPE_ERR) ?      \
> > +                     FM_EV_ERR_PRS : FM_EV_PRS;                      \
> > +             break;                                                  \
> > +     case (FM_MOD_TMR):                                              \
> > +             if (_id)                                                \
> > +                     _event = FM_EV_DUMMY_LAST;                      \
> > +             else                                                    \
> > +                     _event = (_intr_type == FM_INTR_TYPE_ERR) ?     \
> > +                     FM_EV_DUMMY_LAST : FM_EV_TMR;                   \
> > +             break;                                                  \
> > +     case (FM_MOD_MAC):                                              \
> > +                     _event = (_intr_type == FM_INTR_TYPE_ERR) ?     \
> > +                     (FM_EV_ERR_MAC0 + _id) :                        \
> > +                     (FM_EV_MAC0 + _id);                             \
> > +             break;                                                  \
> > +     case (FM_MOD_FMAN_CTRL):                                        \
> > +             if (_intr_type == FM_INTR_TYPE_ERR)                     \
> > +                     _event = FM_EV_DUMMY_LAST;                      \
> > +             else                                                    \
> > +                     _event = (FM_EV_FMAN_CTRL_0 + _id);             \
> > +             break;                                                  \
> > +     default:                                                        \
> > +             _event = FM_EV_DUMMY_LAST;                              \
> > +             break;                                                  \
> > +     }                                                               \
> > +} while (0)
> 
> Use functions instead of macros wherever possible.
> 

Replaced complex Macros with functions.

> > +/* do not change! if changed, must be disabled for rev1 ! */
> > +#define DFLT_VERIFY_UCODE                 false
> 
> I know I complained about this last time...
> 
> 

Leftovers, removed.

> > +
> > +#define DFLT_DMA_READ_INT_BUF_LOW(dma_thresh_max_buf)        \
> > +     ((dma_thresh_max_buf + 1) / 2)
> > +#define DFLT_DMA_READ_INT_BUF_HIGH(dma_thresh_max_buf)       \
> > +     ((dma_thresh_max_buf + 1) * 3 / 4)
> > +#define DFLT_DMA_WRITE_INT_BUF_LOW(dma_thresh_max_buf)       \
> > +     ((dma_thresh_max_buf + 1) / 2)
> > +#define DFLT_DMA_WRITE_INT_BUF_HIGH(dma_thresh_max_buf)\
> > +     ((dma_thresh_max_buf + 1) * 3 / 4)
> > +#define DFLT_DMA_COMM_Q_LOW(major, dma_thresh_max_commq)
> \
> > +     ((major == 6) ? 0x2A : ((dma_thresh_max_commq + 1) / 2))
> > +#define DFLT_DMA_COMM_Q_HIGH(major, dma_thresh_max_commq)
> \
> > +     ((major == 6) ? 0x3f : ((dma_thresh_max_commq + 1) * 3 / 4))
> > +#define DFLT_TOTAL_NUM_OF_TASKS(major, minor,
> bmi_max_num_of_tasks)  \
> > +     ((major == 6) ? ((minor == 1 || minor == 4) ? 59 : 124) :       \
> > +     bmi_max_num_of_tasks)
> 
> Where do 0x2a, 0x3f, 59, 124, etc come from?  Please define symbolically.
> 

Added defines for the values above.

> > +#define DFLT_TOTAL_FIFO_SIZE(major, minor)                   \
> > +     ((major == 6) ?                                         \
> > +     ((minor == 1 || minor == 4) ? (156 * 1024) : (295 * 1024)) :    \
> > +     (((major == 2) || (major == 5)) ?                       \
> > +     (100 * 1024) : ((major == 4) ?                  \
> > +     (46 * 1024) : (122 * 1024))))
> 
> This isn't the International Obfuscated C Code Contest.
> 

Made it look slightly better.
Given the large number of HW platforms supported, this selection will look complicated as much as we try to beautify it.
This code determines the KB of MURAM to use as total FIFO size based on FMan revision.

> >
> > +/* Memory Mapped Registers */
> > +
> > +struct fm_iram_regs_t {
> > +     uint32_t iadd;  /* FM IRAM instruction address register */
> > +     uint32_t idata;/* FM IRAM instruction data register */
> > +     uint32_t itcfg;/* FM IRAM timing config register */
> > +     uint32_t iready;/* FM IRAM ready register */
> > +     uint8_t res[0x80000 - 0x10];
> > +} __attribute__((__packed__));
> 
> Why do you need __packed__ on this?
> 

As all but the last the member of this memory mapped struct are u32, it's not mandatory but at a certain moment someone considered a good idea to throw in the packed attribute.
I you prefer to remove it, II can do so.

> Why do you need the padding on the end?	

Again, it is memory mapped, we don't have other regs after those, so we can drop the padding, I can remove it.
I you prefer to remove it, II can do so.
 
> 
> > +struct fm_t {
> > +     uintptr_t base_addr;
> > +     char fm_module_name[MODULE_NAME_SIZE];
> > +     struct fm_intr_src_t intr_mng[FM_EV_DUMMY_LAST];
> > +
> > +     struct fman_fpm_regs __iomem *p_fm_fpm_regs;
> > +     struct fman_bmi_regs __iomem *p_fm_bmi_regs;
> > +     struct fman_qmi_regs __iomem *p_fm_qmi_regs;
> > +     struct fman_dma_regs __iomem *p_fm_dma_regs;
> > +     struct fman_regs __iomem *p_fm_regs;
> > +     fm_exceptions_cb *f_exception;
> > +     fm_bus_error_cb *f_bus_error;
> > +     void *h_app;            /* Application handle */
> > +     spinlock_t *spinlock;
> 
> Why is the spinlock dynamically allocated?
> 

Removed the dynamic allocation.

> > +/* 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"
> 
> Is this indirection really needed?
> 

I think we can remove, I'll look into it. 

> > +/* 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;
> 
> If it's configurable via bootargs, why is the kconfig needed?
> 

KConfig sets default value, in bootargs you can override.

> > +
> > +u16 fm_get_max_frm(void)
> > +{
> > +     return fsl_fm_max_frm;
> > +}
> > +EXPORT_SYMBOL(fm_get_max_frm);
> 
> fsl_fm_max_frm isn't static, so why is this accessor needed?
> 
> > +int fm_get_rx_extra_headroom(void)
> > +{
> > +     return ALIGN(fsl_fm_rx_extra_headroom, 16); }
> > +EXPORT_SYMBOL(fm_get_rx_extra_headroom);
> 
> Why not just align it when you set the variable?
> 

It's possible, I'll take a look.

> > +
> > +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.
> > +              */
> > +             pr_err("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) {
> > +             pr_err("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;
> > +     }
> > +
> > +     pr_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) {
> > +             pr_err("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 <
> FSL_FM_RX_EXTRA_HEADROOM_MIN ||
> > +         fsl_fm_rx_extra_headroom >
> FSL_FM_RX_EXTRA_HEADROOM_MAX) {
> > +             pr_err("Invalid value for %s=%d prop in bootargs; will
> > + use the default
> > FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n",
> > +                    FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
> > +                    fsl_fm_rx_extra_headroom,
> > +                    CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
> > +             fsl_fm_rx_extra_headroom =
> CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
> > +     }
> > +
> > +     pr_info("Using fsl_fm_rx_extra_headroom=%d from bootargs\n",
> > +             fsl_fm_rx_extra_headroom);
> 
> This is unnecessarily verbose.
> 

OK.

> > +
> > +     return 0;
> > +}
> > +early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
> > +fm_set_rx_extra_headroom);
> 
> Why early?
> 

I think it's from the time when those variables were in DPAA_ETH, I'll check if we can drop the early.

> > +static irqreturn_t fm_err_irq(int irq, void *_dev) {
> > +     struct fm_drv_t *fm_drv = (struct fm_drv_t *)_dev;
> > +
> > +     if (!fm_drv || !fm_drv->h_dev)
> > +             return IRQ_NONE;
> 
> Why would you request the IRQ if either of these are NULL?
> 

Too much Cautiousness. I'll remove.

> > +static const struct qe_firmware *find_fman_microcode(void) {
> > +     static const struct qe_firmware *uc_patch;
> > +     struct device_node *np;
> > +
> > +     if (uc_patch)
> > +             return uc_patch;
> > +
> > +     /* The firmware should be inside the device tree. */
> > +     np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
> > +     if (np) {
> > +             uc_patch = of_get_property(np, "fsl,firmware", NULL);
> 
> I don't see any binding for this.
> 

Yes, binding is required here. 

> > +static int fill_qman_channhels_info(struct fm_drv_t *fm_drv)
> 
> "channhels"?
> 

Typo, fixed.

> 
> > +static struct fm_drv_t *read_fm_dev_tree_node(struct platform_device
> > *of_dev)
> > +{
> > +     struct fm_drv_t *fm_drv;
> > +     struct device_node *fm_node, *dev_node;
> > +     struct of_device_id name;
> > +     struct resource res;
> > +     const uint32_t *uint32_prop;
> > +     int lenp, err;
> > +     struct clk *clk;
> > +     u32 clk_rate;
> > +
> > +     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)) {
> > +             pr_err("of_get_property(%s, cell-index) failed\n",
> > +                    fm_node->full_name);
> > +             goto _return_null;
> > +     }
> > +     if (WARN_ON(lenp != sizeof(uint32_t)))
> > +             return NULL;
> > +
> > +     fm_drv = kzalloc(sizeof(*fm_drv), GFP_KERNEL);
> > +     if (!fm_drv)
> > +             goto _return_null;
> > +
> > +     fm_drv->dev = &of_dev->dev;
> > +     fm_drv->id = (u8)*uint32_prop;
> > +
> > +     /* Get the FM interrupt */
> > +     fm_drv->irq = of_irq_to_resource(fm_node, 0, NULL);
> > +     if (unlikely(fm_drv->irq == 0)) {
> > +             pr_err("of_irq_to_resource() = %d\n", NO_IRQ);
> > +             goto _return_null;
> > +     }
> > +
> > +     /* Get the FM error interrupt */
> > +     fm_drv->err_irq = of_irq_to_resource(fm_node, 1, NULL);
> > +
> > +     /* Get the FM address */
> > +     err = of_address_to_resource(fm_node, 0, &res);
> > +     if (unlikely(err < 0)) {
> > +             pr_err("of_address_to_resource() = %d\n", err);
> > +             goto _return_null;
> > +     }
> > +
> > +     fm_drv->fm_base_addr = 0;
> > +     fm_drv->fm_phys_base_addr = res.start;
> > +     fm_drv->fm_mem_size = res.end + 1 - res.start;
> > +
> 
> Why are you using these OF functions rather than using platform_device
> mechanisms?
> 

I'll have to look into it, there's no special reason for the OF use.
Can you please elaborate why platform device mechanisms are better?

> > +     clk = clk_get(fm_drv->dev, fm_drv->id == 0 ? "fm0clk" : "fm1clk");
> > +     if (IS_ERR(clk)) {
> > +             pr_err("Failed to get FM%d clock structure\n", fm_drv->id);
> > +             goto _return_null;
> > +     }
> 
> Get the clock from the clocks property of the device tree node, not by
> hardcoding what you think the clock's name will be.
> 

Done.

> > +     uint32_prop = (uint32_t *)of_get_property(fm_node,
> > +                                               "fsl,qman-channel-range",
> > +                                               &lenp);
> >
> 
> Don't cast away the const.
> 

Done.

> > +     if (unlikely(!uint32_prop)) {
> 
> Don't use unlikely() in paths that aren't performance-critical.
> 

Ok, I'll check the rest of the code for that issue.
 
> > +     /* Get the MURAM base address and size */
> > +     memset(&name, 0, sizeof(name));
> > +     if (WARN_ON(strlen("muram") >= sizeof(name.name)))
> > +             goto _return_null;
> > +     strcpy(name.name, "muram");
> > +     if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(name.compatible)))
> > +             goto _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))) {
> 
> Why not just define the match struct statically?
> 

Done.

> > +#ifndef __SERVICE_h
> > +#define __SERVICE_h
> > +
> > +#include <linux/version.h>
> 
> What do you need this for?
> 

Not used, removed.

> > +
> > +#include <linux/kernel.h>
> > +#include <linux/types.h>
> > +#include <linux/io.h>
> 
> What do you use in this file from linux/io.h?
> 

Moved #include <linux/io.h> the the files which use it. 

> > +/* Define ASSERT condition */
> > +#undef ASSERT
> > +#define ASSERT(x)       WARN_ON(!(x))
> 
> Why not just use WARN_ON directly?
> 

Mostly personal preference, I've also seen similar constructs used in other drivers.
One can decide later to change this to BUG_ON() or disable it for debug purposes.

> > +/* Pointers Manipulation */
> > +#define UINT_TO_PTR(_val)           ((void __iomem *)(uintptr_t)(_val))
> 
> Why are you doing so much of this that you need macros for it?
> 
> UINT_TO_PTR seems like it could be hiding 64-bit-cleanliness bugs.  From
> looking at the places it's used, it certainly would be if the value fed into it
> were actually "unsigned int".
> 
> Just define base_addr and such as "void __iomem *".
> 

Using void __iomem * instead of uintptr_t, no need for this Macro anymore.

> > +#define PTR_MOVE(_ptr, _offset)     (void *)((uint8_t *)(_ptr) + (_offset))
> 
> I don't see this used anywhere.  Likewise IN_RANGE and ILLEGAL_BASE.
> 

PTR_MOVE was used however during the work on your feedback, I removed it. 
IN_RANGE is used too, but I'll remove it (used for extra checks which are not mandatory (too much Cautiousness)).
ILLEGAL_BASE is used in fm_sp.c, I'll consider moving it from this file.

> -Scott
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [v2,5/9] fsl/fman: Add Frame Manager support
@ 2015-07-02 15:32     ` Liberman Igal
  0 siblings, 0 replies; 8+ messages in thread
From: Liberman Igal @ 2015-07-02 15:32 UTC (permalink / raw)
  To: Scott Wood; +Cc: netdev, linuxppc-dev, Madalin-Cristian Bucur, pebolle

SGkgU2NvdHQsDQpUaGFuayB5b3UgZm9yIHlvdXIgZmVlZGJhY2ssIHBsZWFzZSB0YWtlIGEgbG9v
ayBhdCBteSBjb21tZW50cy9xdWVzdGlvbnMuDQoNClJlZ2FyZHMsDQpJZ2FsIExpYmVybWFuLg0K
DQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFdvb2QgU2NvdHQtQjA3NDIx
DQo+IFNlbnQ6IEZyaWRheSwgSnVuZSAyNiwgMjAxNSA2OjU1IEFNDQo+IFRvOiBMaWJlcm1hbiBJ
Z2FsLUIzMTk1MA0KPiBDYzogbmV0ZGV2QHZnZXIua2VybmVsLm9yZzsgbGludXhwcGMtZGV2QGxp
c3RzLm96bGFicy5vcmc7IEJ1Y3VyIE1hZGFsaW4tDQo+IENyaXN0aWFuLUIzMjcxNjsgcGVib2xs
ZUB0aXNjYWxpLm5sDQo+IFN1YmplY3Q6IFJlOiBbdjIsNS85XSBmc2wvZm1hbjogQWRkIEZyYW1l
IE1hbmFnZXIgc3VwcG9ydA0KPiANCj4gT24gV2VkLCAyMDE1LTA2LTI0IGF0IDIyOjM1ICswMzAw
LCBpZ2FsLmxpYmVybWFuQGZyZWVzY2FsZS5jb20gd3JvdGU6DQo+ID4gRnJvbTogSWdhbCBMaWJl
cm1hbiA8SWdhbC5MaWJlcm1hbkBmcmVlc2NhbGUuY29tPg0KPiA+DQo+ID4gQWRkIEZyYW1lIE1h
bmdlciBEcml2ZXIgc3VwcG9ydC4NCj4gPiBUaGlzIHBhdGNoIGFkZHMgVGhlIEZNYW4gY29uZmln
dXJhdGlvbiwgaW5pdGlhbGl6YXRpb24gYW5kIHJ1bnRpbWUNCj4gPiBjb250cm9sIHJvdXRpbmVz
Lg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogSWdhbCBMaWJlcm1hbiA8SWdhbC5MaWJlcm1hbkBm
cmVlc2NhbGUuY29tPg0KPiA+IC0tLQ0KPiA+ICBkcml2ZXJzL25ldC9ldGhlcm5ldC9mcmVlc2Nh
bGUvZm1hbi9LY29uZmlnICAgICAgICB8ICAgMzUgKw0KPiA+ICBkcml2ZXJzL25ldC9ldGhlcm5l
dC9mcmVlc2NhbGUvZm1hbi9NYWtlZmlsZSAgICAgICB8ICAgIDIgKy0NCj4gPiAgZHJpdmVycy9u
ZXQvZXRoZXJuZXQvZnJlZXNjYWxlL2ZtYW4vZm0uYyAgICAgICAgICAgfCAxNDA2DQo+ID4gKysr
KysrKysrKysrKysrKysrKysNCj4gPiAgZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNjYWxlL2Zt
YW4vZm0uaCAgICAgICAgICAgfCAgMzk0ICsrKysrKw0KPiA+ICBkcml2ZXJzL25ldC9ldGhlcm5l
dC9mcmVlc2NhbGUvZm1hbi9mbV9jb21tb24uaCAgICB8ICAxNDIgKysNCj4gPiAgZHJpdmVycy9u
ZXQvZXRoZXJuZXQvZnJlZXNjYWxlL2ZtYW4vZm1fZHJ2LmMgICAgICAgfCAgNzAxICsrKysrKysr
KysNCj4gPiAgZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNjYWxlL2ZtYW4vZm1fZHJ2LmggICAg
ICAgfCAgMTE2ICsrDQo+ID4gIGRyaXZlcnMvbmV0L2V0aGVybmV0L2ZyZWVzY2FsZS9mbWFuL2lu
Yy9lbmV0X2V4dC5oIHwgIDE5OSArKysNCj4gPiAgZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNj
YWxlL2ZtYW4vaW5jL2ZtX2V4dC5oICAgfCAgNDg4ICsrKysrKysNCj4gPiAgLi4uL25ldC9ldGhl
cm5ldC9mcmVlc2NhbGUvZm1hbi9pbmMvZnNsX2ZtYW5fZHJ2LmggfCAgIDk5ICsrDQo+ID4gIGRy
aXZlcnMvbmV0L2V0aGVybmV0L2ZyZWVzY2FsZS9mbWFuL2luYy9zZXJ2aWNlLmggIHwgICA1NSAr
DQo+ID4gIDExIGZpbGVzIGNoYW5nZWQsIDM2MzYgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlvbigt
KSAgY3JlYXRlIG1vZGUNCj4gPiAxMDA2NDQgZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNjYWxl
L2ZtYW4vZm0uYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9uZXQvZXRoZXJuZXQv
ZnJlZXNjYWxlL2ZtYW4vZm0uaA0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9uZXQv
ZXRoZXJuZXQvZnJlZXNjYWxlL2ZtYW4vZm1fY29tbW9uLmgNCj4gPiAgY3JlYXRlIG1vZGUgMTAw
NjQ0IGRyaXZlcnMvbmV0L2V0aGVybmV0L2ZyZWVzY2FsZS9mbWFuL2ZtX2Rydi5jDQo+ID4gIGNy
ZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL25ldC9ldGhlcm5ldC9mcmVlc2NhbGUvZm1hbi9mbV9k
cnYuaA0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNj
YWxlL2ZtYW4vaW5jL2VuZXRfZXh0LmgNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMv
bmV0L2V0aGVybmV0L2ZyZWVzY2FsZS9mbWFuL2luYy9mbV9leHQuaA0KPiA+ICBjcmVhdGUgbW9k
ZSAxMDA2NDQNCj4gPiBkcml2ZXJzL25ldC9ldGhlcm5ldC9mcmVlc2NhbGUvZm1hbi9pbmMvZnNs
X2ZtYW5fZHJ2LmgNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvbmV0L2V0aGVybmV0
L2ZyZWVzY2FsZS9mbWFuL2luYy9zZXJ2aWNlLmgNCj4gDQo+IEFnYWluLCBwbGVhc2Ugc3RhcnQg
d2l0aCBzb21ldGhpbmcgcGFyZWQgZG93biwgd2l0aG91dCBleHRyYW5lb3VzDQo+IGZlYXR1cmVz
LCBidXQgKndpdGgqIGVub3VnaCBmdW5jdGlvbmFsaXR5IHRvIGFjdHVhbGx5IHBhc3MgcGFja2V0
cyBhcm91bmQuDQo+IEdldHRpbmcgdGhpcyB0aGluZyBpbnRvIGRlY2VudCBzaGFwZSBpcyBnb2lu
ZyB0byBiZSBoYXJkIGVub3VnaCB3aXRob3V0DQo+IGNhcnJ5aW5nIGFyb3VuZCB0aGUgZXhjZXNz
IGJhZ2dhZ2UuDQo+IA0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC9ldGhlcm5ldC9mcmVl
c2NhbGUvZm1hbi9LY29uZmlnDQo+ID4gYi9kcml2ZXJzL25ldC9ldGhlcm5ldC9mcmVlc2NhbGUv
Zm1hbi9LY29uZmlnDQo+ID4gaW5kZXggODI1YTBkNS4uMTJjNzViZmQgMTAwNjQ0DQo+ID4gLS0t
IGEvZHJpdmVycy9uZXQvZXRoZXJuZXQvZnJlZXNjYWxlL2ZtYW4vS2NvbmZpZw0KPiA+ICsrKyBi
L2RyaXZlcnMvbmV0L2V0aGVybmV0L2ZyZWVzY2FsZS9mbWFuL0tjb25maWcNCj4gPiBAQCAtNywz
ICs3LDM4IEBAIGNvbmZpZyBGU0xfRk1BTg0KPiA+ICAgICAgICAgICAgICAgRnJlZXNjYWxlIERh
dGEtUGF0aCBBY2NlbGVyYXRpb24gQXJjaGl0ZWN0dXJlIEZyYW1lIE1hbmFnZXINCj4gPiAgICAg
ICAgICAgICAgIChGTWFuKSBzdXBwb3J0DQo+ID4NCj4gPiAraWYgRlNMX0ZNQU4NCj4gPiArDQo+
ID4gK2NvbmZpZyBGU0xfRk1fTUFYX0ZSQU1FX1NJWkUNCj4gPiArICAgICBpbnQgIk1heGltdW0g
TDIgZnJhbWUgc2l6ZSINCj4gPiArICAgICByYW5nZSA2NCA5NjAwDQo+ID4gKyAgICAgZGVmYXVs
dCAiMTUyMiINCj4gPiArICAgICBoZWxwDQo+ID4gKyAgICAgICAgICAgICBDb25maWd1cmUgdGhp
cyBpbiByZWxhdGlvbiB0byB0aGUgbWF4aW11bSBwb3NzaWJsZSBNVFUgb2YgeW91cg0KPiA+ICsg
ICAgICAgICAgICAgbmV0d29yayBjb25maWd1cmF0aW9uLiBJbiBwYXJ0aWN1bGFyLCBvbmUgd291
bGQgbmVlZCB0bw0KPiA+ICsgICAgICAgICAgICAgaW5jcmVhc2UgdGhpcyB2YWx1ZSBpbiBvcmRl
ciB0byB1c2UganVtYm8gZnJhbWVzLg0KPiA+ICsgICAgICAgICAgICAgRlNMX0ZNX01BWF9GUkFN
RV9TSVpFIG11c3QgYWNjb21tb2RhdGUgdGhlIEV0aGVybmV0IEZDUw0KPiA+ICsgICAgICAgICAg
ICAgKDQgYnl0ZXMpIGFuZCBvbmUgRVRIK1ZMQU4gaGVhZGVyICgxOCBieXRlcyksIHRvIGEgdG90
YWwgb2YNCj4gPiArICAgICAgICAgICAgIDIyIGJ5dGVzIGluIGV4Y2VzcyBvZiB0aGUgZGVzaXJl
ZCBMMyBNVFUuDQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgTm90ZSB0aGF0IGhhdmluZyB0b28g
bGFyZ2UgYSBGU0xfRk1fTUFYX0ZSQU1FX1NJWkUgKG11Y2gNCj4gbGFyZ2VyDQo+ID4gKyAgICAg
ICAgICAgICB0aGFuIHRoZSBhY3R1YWwgTVRVKSBtYXkgbGVhZCB0byBidWZmZXIgZXhoYXVzdGlv
biwgZXNwZWNpYWxseQ0KPiA+ICsgICAgICAgICAgICAgaW4gdGhlIGNhc2Ugb2YgYmFkbHkgZnJh
Z21lbnRlZCBkYXRhZ3JhbXMgb24gdGhlIFJ4IHBhdGguDQo+ID4gKyAgICAgICAgICAgICBDb252
ZXJzZWx5LCBoYXZpbmcgYSBGU0xfRk1fTUFYX0ZSQU1FX1NJWkUgc21hbGxlciB0aGFuIHRoZQ0K
PiA+ICsgICAgICAgICAgICAgYWN0dWFsIE1UVSB3aWxsIGxlYWQgdG8gZnJhbWVzIGJlaW5nIGRy
b3BwZWQuDQo+IA0KPiBTY2F0dGVyIGdhdGhlciBjYW4ndCBiZSB1c2VkIGZvciBqdW1ibyBmcmFt
ZXM/DQo+IA0KDQpTY2F0dGVyIGdhdGhlciBpcyB1c2VkLCBpdCdzIGludHJvZHVjZWQgaW4gZHBh
YV9ldGggYXMgYSBzZXBhcmF0ZSBwYXRjaCBmcm9tIHRoZSBiYXNpYyBzdXBwb3J0Lg0KVGhlIGRw
YWFfZXRoIGNhbiB3b3JrIGluIFMvRyBtb2RlIG9yIHVzZSBsYXJnZSBidWZmZXJzLCBtYXggZnJh
bWUgc2l6ZSBzaXplZCB0byByZWR1Y2UgUy9HIG92ZXJoZWFkIChwZXJmb3JtYW5jZSB2cyBtZW1v
cnkgdXNlZCB0cmFkZS1vZmYpLg0KDQo+IFdoeSBpcyB0aGlzIGEgY29tcGlsZS10aW1lIG9wdGlv
bj8NCj4gDQoNClRoaXMgaXMgbmVlZGVkIGZvciBhIGNvdXBsZSBvZiByZWFzb25zOg0KIC0gRk1h
biByZXNvdXJjZSBzaXppbmcgLSB3ZSBuZWVkIHRvIGtub3cgdGhlIG1heGltdW0gZnJhbWUgc2l6
ZSB3ZSBwbGFuIHRvIHVzZSBmb3IgZGV0ZXJtaW5pbmcgdGhlIFJ4IEZJRk8gc2l6ZXMgYXQgY29u
ZmlnIHRpbWUNCiAtIFRoZXJlIGFyZSBpc3N1ZXMgd2hlbiBjaGFuZ2luZyB0aGUgTUFDIG1heGlt
dW0gZnJhbWUgc2l6ZSBhdCBydW50aW1lIHRodXMgdGhlIG5lZWQgdG8gc2V0IGluIEhXIHRoZSBt
YXhpbXVtIGFsbG93YWJsZSBhbmQgY29tcGVuc2F0ZSBmcm9tIHN3IChkcm9wIGZyYW1lcyBhYm92
ZSB0aGUgc2V0IE1UVSkuDQoNCj4gPiArDQo+ID4gK2NvbmZpZyBGU0xfRk1fUlhfRVhUUkFfSEVB
RFJPT00NCj4gPiArICAgICBpbnQgIkFkZCBleHRyYSBoZWFkcm9vbSBhdCBiZWdpbm5pbmcgb2Yg
ZGF0YSBidWZmZXJzIg0KPiA+ICsgICAgIHJhbmdlIDE2IDM4NA0KPiA+ICsgICAgIGRlZmF1bHQg
IjY0Ig0KPiA+ICsgICAgIGhlbHANCj4gPiArICAgICAgICAgICAgIENvbmZpZ3VyZSB0aGlzIHRv
IHRlbGwgdGhlIEZyYW1lIE1hbmFnZXIgdG8gcmVzZXJ2ZSBzb21lIGV4dHJhDQo+ID4gKyAgICAg
ICAgICAgICBzcGFjZSBhdCB0aGUgYmVnaW5uaW5nIG9mIGEgZGF0YSBidWZmZXIgb24gdGhlIHJl
Y2VpdmUgcGF0aCwNCj4gPiArICAgICAgICAgICAgIGJlZm9yZSBJbnRlcm5hbCBDb250ZXh0IGZp
ZWxkcyBhcmUgY29waWVkLiBUaGlzIGlzIGluIGFkZGl0aW9uDQo+ID4gKyAgICAgICAgICAgICB0
byB0aGUgcHJpdmF0ZSBkYXRhIGFyZWEgYWxyZWFkeSByZXNlcnZlZCBmb3IgZHJpdmVyIGludGVy
bmFsDQo+ID4gKyAgICAgICAgICAgICB1c2UuIFRoZSBwcm92aWRlZCB2YWx1ZSBtdXN0IGJlIGEg
bXVsdGlwbGUgb2YgMTYuDQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgVGhpcyBvcHRpb24gZG9l
cyBub3QgYWZmZWN0IGluIGFueSB3YXkgdGhlIGxheW91dCBvZg0KPiA+ICsgICAgICAgICAgICAg
dHJhbnNtaXR0ZWQgYnVmZmVycy4NCj4gDQo+IFRoZXJlJ3Mgbm90aGluZyBoZXJlIHRvIGluZGlj
YXRlIHdoZW4gYSB1c2VyIHdvdWxkIHdhbnQgdG8gZG8gdGhpcy4NCj4gDQo+IFdoeSBpcyB0aGlz
IGEgY29tcGlsZS10aW1lIG9wdGlvbj8NCj4gDQoNClRoaXMgYWxsb3dzIHJlc2VydmluZyBzb21l
IG1vcmUgc3BhY2UgYXQgdGhlIHN0YXJ0IG9mIHRoZSBza2IgYW5kIG1heSBhdm9pZCB0aGUgbmVl
ZCBmb3IgYSBza2JfcmVhbGxvY19oZWFkcm9vbSgpLg0KDQo+ID4gKyAgICAgICAgICAgICAvKiBG
TWFuVjNIICovDQo+ID4gKyAgICAgICAgICAgICBlbHNlIGlmIChtaW5vciA9PSAwIHx8IG1pbm9y
ID09IDIgfHwgbWlub3IgPT0gMykgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBpbnRnLT5m
bV9tdXJhbV9zaXplICAgICAgICAgICAgID0gMzg0ICogMTAyNDsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgaW50Zy0+Zm1faXJhbV9zaXplICAgICAgICAgICAgICA9IDY0ICogMTAyNDsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgaW50Zy0+Zm1fbnVtX29mX2N0cmwgICAgICAgICAgICA9
IDQ7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBpbnRnLT5ibWlfbWF4X251bV9v
Zl90YXNrcyAgICAgID0gMTI4Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBpbnRnLT5ibWlf
bWF4X251bV9vZl9kbWFzICAgICAgID0gODQ7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICBpbnRnLT5udW1fb2ZfcnhfcG9ydHMgICAgICAgICAgID0gODsNCj4gPiArICAgICAgICAg
ICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHByX2VycigiVW5zdXBwb3J0
ZWQgRk1hbnYzIHZlcnNpb25cbiIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBrZnJlZShp
bnRnKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKyAgICAg
ICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgZGVm
YXVsdDoNCj4gPiArICAgICAgICAgICAgIHByX2VycigiVW5zdXBwb3J0ZWQgRk1hbiB2ZXJzaW9u
XG4iKTsNCj4gPiArICAgICAgICAgICAgIGtmcmVlKGludGcpOw0KPiA+ICsgICAgICAgICAgICAg
cmV0dXJuIE5VTEw7DQo+ID4gKyAgICAgfQ0KPiANCj4gRG9uJ3QgZHVwbGljYXRlIGVycm9yIHBh
dGhzLiAgVXNlIGdvdG8gbGlrZSB0aGUgcmVzdCBvZiB0aGUga2VybmVsLg0KPiANCg0KRG9uZSwg
aGVyZSBhbmQgaW4gb3RoZXIgcGxhY2VzIHRvby4NCg0KPiA+ICsNCj4gPiArICAgICBpbnRnLT5i
bWlfbWF4X2ZpZm9fc2l6ZSA9IGludGctPmZtX211cmFtX3NpemU7DQo+ID4gKw0KPiA+ICsgICAg
IHJldHVybiBpbnRnOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGlzX2luaXRfZG9u
ZShzdHJ1Y3QgZm1hbl9jZmcgKnBfZm1fZHJ2X3BhcmFtZXRlcnMpDQo+IA0KPiBObyBIdW5nYXJp
YW4gbm90YXRpb24uICBDaGVjayB0aHJvdWdob3V0IHRoZSBwYXRjaHNldC4NCj4gDQoNCkknbSBy
ZW1vdmluZyBIdW5nYXJpYW4gbm90YXRpb24gZnJvbSB0aGUgY29kZS4gDQoNCj4gPiArew0KPiA+
ICsgICAgIC8qIENoZWNrcyBpZiBGTWFuIGRyaXZlciBwYXJhbWV0ZXJzIHdlcmUgaW5pdGlhbGl6
ZWQgKi8NCj4gPiArICAgICBpZiAoIXBfZm1fZHJ2X3BhcmFtZXRlcnMpDQo+ID4gKyAgICAgICAg
ICAgICByZXR1cm4gMDsNCj4gPiArICAgICByZXR1cm4gLUVJTlZBTDsNCj4gPiArfQ0KPiANCj4g
VGhlIG5hbWUgbWFrZXMgaXQgc291bmQgbGlrZSBpdCByZXR1cm5zIGEgYm9vbGVhbiwgYnV0IGlu
c3RlYWQgaXQgcmV0dXJucw0KPiBlaXRoZXIgMCBvciAtRUlOVkFMPyAgV2h5IGRvIHlvdSBuZWVk
IHRoaXMgd3JhcHBlciBqdXN0IHRvIGRvIGEgTlVMTC0NCj4gcG9pbnRlciBjaGVjaz8NCj4gDQoN
CkNoYW5nZWQgdG8gYm9vbGVhbi4NClRoaXMgaXMgdXNlZCB0byBjaGVjayB0aGF0IGEgY2VydGFp
biBBUEkgY2FsbCBpcyBtYWRlIGFmdGVyIGluaXRpYWxpemF0aW9uIGlzIGZpbmFsaXplZC4NCklm
IHdlIHdlcmUgdG8gdXNlIHRoZSBwb2ludGVyIGNoZWNrIGluIGV2ZXJ5IHBsYWNlIGl0IHdvdWxk
IGJlIGxlc3Mgb2J2aW91cyB3aGF0IHdlJ3JlIGNoZWNraW5nIGZvciAoaXQgY291bGQgYXBwZWFy
IHdlIGNoZWNrIGZvciBhIHBvaW50ZXIgd2UncmUgbm90IHVzaW5nKS4NCg0KPiA+ICtzdGF0aWMg
dm9pZCBmcmVlX2luaXRfcmVzb3VyY2VzKHN0cnVjdCBmbV90ICpwX2ZtKSB7DQo+ID4gKyAgICAg
aWYgKHBfZm0tPmNhbV9vZmZzZXQpDQo+ID4gKyAgICAgICAgICAgICBmbV9tdXJhbV9mcmVlX21l
bShwX2ZtLT5wX211cmFtLCBwX2ZtLT5jYW1fb2Zmc2V0LA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgcF9mbS0+Y2FtX3NpemUpOw0KPiA+ICsgICAgIGlmIChwX2ZtLT5maWZv
X29mZnNldCkNCj4gPiArICAgICAgICAgICAgIGZtX211cmFtX2ZyZWVfbWVtKHBfZm0tPnBfbXVy
YW0sIHBfZm0tPmZpZm9fb2Zmc2V0LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgcF9mbS0+Zmlmb19zaXplKTsgfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgaXNfZm1hbl9j
dHJsX2NvZGVfbG9hZGVkKHN0cnVjdCBmbV90ICpwX2ZtKSB7DQo+ID4gKyAgICAgc3RydWN0IGZt
X2lyYW1fcmVnc190IF9faW9tZW0gKnBfaXJhbTsNCj4gPiArDQo+ID4gKyAgICAgcF9pcmFtID0g
KHN0cnVjdCBmbV9pcmFtX3JlZ3NfdCBfX2lvbWVtICopVUlOVF9UT19QVFIocF9mbS0NCj4gPmJh
c2VfYWRkciArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBGTV9NTV9JTUVNKTsNCj4gPiArDQo+ID4gKyAgICAgcmV0dXJuIChib29sKSEh
KGluX2JlMzIoJnBfaXJhbS0+aXJlYWR5KSAmIElSQU1fUkVBRFkpOyB9DQo+ID4gKw0KPiA+ICtz
dGF0aWMgaW50IGNoZWNrX2ZtX3BhcmFtZXRlcnMoc3RydWN0IGZtX3QgKnBfZm0pIHsNCj4gPiAr
ICAgICBpZiAoaXNfZm1hbl9jdHJsX2NvZGVfbG9hZGVkKHBfZm0pICYmICFwX2ZtLT5yZXNldF9v
bl9pbml0KSB7DQo+ID4gKyAgICAgICAgICAgICBwcl9lcnIoIk9sZCBGTWFuIENUUkwgY29kZSBp
cyBsb2FkZWQ7IEZNIG11c3QgYmUgcmVzZXQhXG4iKTsNCj4gPiArICAgICAgICAgICAgIHJldHVy
biAtRURPTTsNCj4gPiArICAgICB9DQo+ID4gKyAgICAgaWYgKHBfZm0tPnBfZm1fc3RhdGVfc3Ry
dWN0LT5yZXZfaW5mby5tYWpvcl9yZXYgPCA2KSB7DQo+ID4gKyAgICAgICAgICAgICBpZiAoIXBf
Zm0tPnBfZm1fZHJ2X3BhcmFtLT5kbWFfYXhpX2RiZ19udW1fb2ZfYmVhdHMgfHwNCj4gPiArICAg
ICAgICAgICAgICAgICAocF9mbS0+cF9mbV9kcnZfcGFyYW0tPmRtYV9heGlfZGJnX251bV9vZl9i
ZWF0cyA+DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIERNQV9NT0RFX01BWF9BWElfREJHX05V
TV9PRl9CRUFUUykpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcHJfZXJyKCJheGlEYmdO
dW1PZkJlYXRzIGhhcyB0byBiZSBpbiB0aGUgcmFuZ2UgMSAtICVkXG4iLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgRE1BX01PREVfTUFYX0FYSV9EQkdfTlVNX09GX0JFQVRTKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgICAgICAg
ICAgfQ0KPiA+ICsgICAgIH0NCj4gPiArICAgICBpZiAocF9mbS0+cF9mbV9kcnZfcGFyYW0tPmRt
YV9jYW1fbnVtX29mX2VudHJpZXMgJQ0KPiA+ICsgICAgICAgICBETUFfQ0FNX1VOSVRTKSB7DQo+
ID4gKyAgICAgICAgICAgICBwcl9lcnIoImRtYV9jYW1fbnVtX29mX2VudHJpZXMgaGFzIHRvIGJl
IGRpdmlzYmxlIGJ5ICVkXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgIERNQV9DQU1fVU5J
VFMpOw0KPiA+ICsgICAgICAgICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgIH0NCj4gPiAr
ICAgICBpZiAocF9mbS0+cF9mbV9kcnZfcGFyYW0tPmRtYV9jb21tX3F0c2hfYXNydF9lbWVyID4N
Cj4gPiArICAgICAgICAgcF9mbS0+aW50Zy0+ZG1hX3RocmVzaF9tYXhfY29tbXEpIHsNCj4gPiAr
ICAgICAgICAgICAgIHByX2VycigiZG1hX2NvbW1fcXRzaF9hc3J0X2VtZXIgY2FuIG5vdCBiZSBs
YXJnZXIgdGhhbiAlZFxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICBwX2ZtLT5pbnRnLT5k
bWFfdGhyZXNoX21heF9jb21tcSk7DQo+ID4gKyAgICAgICAgICAgICByZXR1cm4gLUVET007DQo+
ID4gKyAgICAgfQ0KPiA+ICsgICAgIGlmIChwX2ZtLT5wX2ZtX2Rydl9wYXJhbS0+ZG1hX2NvbW1f
cXRzaF9jbHJfZW1lciA+DQo+ID4gKyAgICAgICAgIHBfZm0tPmludGctPmRtYV90aHJlc2hfbWF4
X2NvbW1xKSB7DQo+ID4gKyAgICAgICAgICAgICBwcl9lcnIoImRtYV9jb21tX3F0c2hfY2xyX2Vt
ZXIgY2FuIG5vdCBiZSBsYXJnZXIgdGhhbiAlZFxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICBwX2ZtLT5pbnRnLT5kbWFfdGhyZXNoX21heF9jb21tcSk7DQo+ID4gKyAgICAgICAgICAgICBy
ZXR1cm4gLUVET007DQo+ID4gKyAgICAgfQ0KPiA+ICsgICAgIGlmIChwX2ZtLT5wX2ZtX2Rydl9w
YXJhbS0+ZG1hX2NvbW1fcXRzaF9jbHJfZW1lciA+PQ0KPiA+ICsgICAgICAgICBwX2ZtLT5wX2Zt
X2Rydl9wYXJhbS0+ZG1hX2NvbW1fcXRzaF9hc3J0X2VtZXIpIHsNCj4gPiArICAgICAgICAgICAg
IHByX2VycigiZG1hX2NvbW1fcXRzaF9jbHJfZW1lciBtdXN0IGJlIHNtYWxsZXIgdGhhbg0KPiA+
IGRtYV9jb21tX3F0c2hfYXNydF9lbWVyXG4iKTsNCj4gPiArICAgICAgICAgICAgIHJldHVybiAt
RURPTTsNCj4gPiArICAgICB9DQo+ID4gKyAgICAgaWYgKHBfZm0tPnBfZm1fc3RhdGVfc3RydWN0
LT5yZXZfaW5mby5tYWpvcl9yZXYgPCA2KSB7DQo+ID4gKyAgICAgICAgICAgICBpZiAocF9mbS0+
cF9mbV9kcnZfcGFyYW0tPmRtYV9yZWFkX2J1Zl90c2hfYXNydF9lbWVyID4NCj4gPiArICAgICAg
ICAgICAgICAgICBwX2ZtLT5pbnRnLT5kbWFfdGhyZXNoX21heF9idWYpIHsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgcHJfZXJyKCJkbWFfcmVhZF9idWZfdHNoX2FzcnRfZW1lciBjYW4gbm90
IGJlIGxhcmdlciB0aGFuDQo+ICVkXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgcF9mbS0+aW50Zy0+ZG1hX3RocmVzaF9tYXhfYnVmKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAg
ICAgaWYgKHBfZm0tPnBfZm1fZHJ2X3BhcmFtLT5kbWFfcmVhZF9idWZfdHNoX2Nscl9lbWVyID4N
Cj4gPiArICAgICAgICAgICAgICAgICAgIHBfZm0tPmludGctPmRtYV90aHJlc2hfbWF4X2J1Zikg
ew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBwcl9lcnIoImRtYV9yZWFkX2J1Zl90c2hfY2xy
X2VtZXIgY2FuIG5vdCBiZSBsYXJnZXIgdGhhbg0KPiAlZFxuIiwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHBfZm0tPmludGctPmRtYV90aHJlc2hfbWF4X2J1Zik7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgIHJldHVybiAtRURPTTsNCj4gPiArICAgICAgICAgICAgIH0NCj4g
PiArICAgICAgICAgICAgIGlmIChwX2ZtLT5wX2ZtX2Rydl9wYXJhbS0+ZG1hX3JlYWRfYnVmX3Rz
aF9jbHJfZW1lciA+PQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgcF9mbS0+cF9mbV9kcnZfcGFy
YW0tPmRtYV9yZWFkX2J1Zl90c2hfYXNydF9lbWVyKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgIHByX2VycigiZG1hX3JlYWRfYnVmX3RzaF9jbHJfZW1lciBtdXN0IGJlIDwNCj4gPiBkbWFf
cmVhZF9idWZfdHNoX2FzcnRfZW1lclxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHJl
dHVybiAtRURPTTsNCj4gPiArICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICAgIGlmIChw
X2ZtLT5wX2ZtX2Rydl9wYXJhbS0+ZG1hX3dyaXRlX2J1Zl90c2hfYXNydF9lbWVyID4NCj4gPiAr
ICAgICAgICAgICAgICAgICAgIHBfZm0tPmludGctPmRtYV90aHJlc2hfbWF4X2J1Zikgew0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICBwcl9lcnIoImRtYV93cml0ZV9idWZfdHNoX2FzcnRfZW1l
ciBjYW4gbm90IGJlIGxhcmdlciB0aGFuDQo+ICVkXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgcF9mbS0+aW50Zy0+ZG1hX3RocmVzaF9tYXhfYnVmKTsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgICAgICAgICAgfQ0KPiA+ICsg
ICAgICAgICAgICAgaWYgKHBfZm0tPnBfZm1fZHJ2X3BhcmFtLT5kbWFfd3JpdGVfYnVmX3RzaF9j
bHJfZW1lciA+DQo+ID4gKyAgICAgICAgICAgICAgICAgICBwX2ZtLT5pbnRnLT5kbWFfdGhyZXNo
X21heF9idWYpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcHJfZXJyKCJkbWFfd3JpdGVf
YnVmX3RzaF9jbHJfZW1lciBjYW4gbm90IGJlIGxhcmdlciB0aGFuDQo+ICVkXG4iLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9mbS0+aW50Zy0+ZG1hX3RocmVzaF9tYXhfYnVm
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgICAg
ICAgICAgfQ0KPiA+ICsgICAgICAgICAgICAgaWYgKHBfZm0tPnBfZm1fZHJ2X3BhcmFtLT5kbWFf
d3JpdGVfYnVmX3RzaF9jbHJfZW1lciA+PQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgcF9mbS0+
cF9mbV9kcnZfcGFyYW0tPmRtYV93cml0ZV9idWZfdHNoX2FzcnRfZW1lcikgew0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICBwcl9lcnIoImRtYV93cml0ZV9idWZfdHNoX2Nscl9lbWVyIGhhcyB0
byBiZQ0KPiA+ICsgbGVzcyB0aGFuDQo+ID4gZG1hX3dyaXRlX2J1Zl90c2hfYXNydF9lbWVyXG4i
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FRE9NOw0KPiA+ICsgICAgICAg
ICAgICAgfQ0KPiA+ICsgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICBpZiAoKHBfZm0t
PnBfZm1fZHJ2X3BhcmFtLT5kbWFfZGJnX2NudF9tb2RlID09DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgRV9GTUFOX0RNQV9EQkdfQ05UX0lOVF9SRUFEX0VNKSB8fA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAocF9mbS0+cF9mbV9kcnZfcGFyYW0tPmRtYV9kYmdfY250X21v
ZGUgPT0NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFX0ZNQU5fRE1BX0RCR19D
TlRfSU5UX1dSSVRFX0VNKSB8fA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAocF9mbS0+cF9m
bV9kcnZfcGFyYW0tPmRtYV9kYmdfY250X21vZGUgPT0NCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBFX0ZNQU5fRE1BX0RCR19DTlRfUkFXX1dBUl9QUk9UKSkgew0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICBwcl9lcnIoImRtYV9kYmdfY250X21vZGUgdmFsdWUgbm90IHN1cHBv
cnRlZCBieSB0aGlzDQo+IGludGVncmF0aW9uLlxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgIHJldHVybiAtRURPTTsNCj4gPiArICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICAg
IGlmICgocF9mbS0+cF9mbV9kcnZfcGFyYW0tPmRtYV9lbWVyZ2VuY3lfYnVzX3NlbGVjdCA9PQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgIEZNX0RNQV9NVVJBTV9SRUFEX0VNRVJHRU5DWSkgfHwN
Cj4gPiArICAgICAgICAgICAgICAgICAgIChwX2ZtLT5wX2ZtX2Rydl9wYXJhbS0+ZG1hX2VtZXJn
ZW5jeV9idXNfc2VsZWN0ID09DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgRk1fRE1BX01VUkFN
X1dSSVRFX0VNRVJHRU5DWSkpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcHJfZXJyKCJl
bWVyZ2VuY3lCdXNTZWxlY3QgdmFsdWUgbm90IHN1cHBvcnRlZCBieSB0aGlzDQo+IGludGVncmF0
aW9uLlxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHJldHVybiAtRURPTTsNCj4gPiAr
ICAgICAgICAgICAgIH0NCj4gDQo+IFdoYXQgZG8geW91IG1lYW4gYnkgImludGVncmF0aW9uIj8N
Cj4gDQoNCkNoYW5nZWQgaXQgdG8gU29DLCB0aG9zZSBhcmUgcnVuIHRpbWUgY2hlY2tzIGZvciBk
aWZmZXJlbnQgU29DcyAoRGlmZmVyZW50IEZNYW4gdmVyc2lvbnMpLg0KDQo+IFdoeSBhcmUgdGhl
cmUgc3RpbGwgY2FtZWxDYXBzIGluIHN0cmluZ3M/DQo+IA0KDQpMZWZ0b3ZlcnMuIFJlbW92ZWQg
KGhlcmUgYW5kIGluIG90aGVyIHBsYWNlcykuDQoNCj4gPiArc3RhdGljIHZvaWQgdW5pbXBsZW1l
bnRlZF9pc3Iodm9pZCBfX21heWJlX3VudXNlZCAqaF9zcmNfYXJnKSB7DQo+ID4gKyAgICAgcHJf
ZXJyKCJVbmltcGxlbWVudGVkIElTUiFcbiIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICsNCj4gDQo+
IFRoaXMgbWVzc2FnZSBpcyBzZXZlcmVseSBsYWNraW5nIGluIGNvbnRleHQuDQo+IA0KDQpXZSds
bCwgaXQncyB1c2VkIGluIGEgY2FzZSB0aGVyZSdzIGFuIGV2ZW50IHdpdGggbm8gcmVnaXN0ZXJl
ZCBjYWxsIGJhY2suDQpJIHRoaW5rIGNoZWNraW5nIGZvciBOVUxMIGlzIGJldHRlciAoaW5zdGVh
ZCBvZiBjYWxsaW5nIHRoaXMgSVNSKS4NCkknbGwgY2hhbmdlIHRoaXMgY29kZS4gDQoNCj4gPiAr
c3RhdGljIGludCBpbml0X2ZtX2RtYShzdHJ1Y3QgZm1fdCAqcF9mbSkgew0KPiA+ICsgICAgIGlu
dCBlcnI7DQo+ID4gKw0KPiA+ICsgICAgIGVyciA9IChpbnQpZm1hbl9kbWFfaW5pdChwX2ZtLT5w
X2ZtX2RtYV9yZWdzLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9m
bS0+cF9mbV9kcnZfcGFyYW0pOw0KPiA+ICsgICAgIGlmIChlcnIgIT0gMCkNCj4gPiArICAgICAg
ICAgICAgIHJldHVybiBlcnI7DQo+ID4gKw0KPiA+ICsgICAgIC8qIEFsbG9jYXRlIE1VUkFNIGZv
ciBDQU0gKi8NCj4gPiArICAgICBwX2ZtLT5jYW1fc2l6ZSA9ICh1aW50MzJfdCkocF9mbS0+cF9m
bV9kcnZfcGFyYW0tPg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ZG1hX2NhbV9udW1fb2ZfZW50cmllcyAqDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBETUFfQ0FNX1NJWkVPRl9FTlRSWSk7DQo+ID4gKyAgICAgcF9mbS0+Y2FtX29m
ZnNldCA9IGZtX211cmFtX2FsbG9jKHBfZm0tPnBfbXVyYW0sIHBfZm0tDQo+ID5jYW1fc2l6ZSk7
DQo+ID4gKyAgICAgaWYgKElTX0VSUl9WQUxVRShwX2ZtLT5jYW1fb2Zmc2V0KSkgew0KPiA+ICsg
ICAgICAgICAgICAgcHJfZXJyKCJNVVJBTSBhbGxvYyBmb3IgRE1BIENBTSBmYWlsZWRcbiIpOw0K
PiA+ICsgICAgICAgICAgICAgcmV0dXJuIC1FTk9NRU07DQo+ID4gKyAgICAgfQ0KPiA+ICsNCj4g
PiArICAgICBpZiAocF9mbS0+cF9mbV9zdGF0ZV9zdHJ1Y3QtPnJldl9pbmZvLm1ham9yX3JldiA9
PSAyKSB7DQo+ID4gKyAgICAgICAgICAgICB1aW50cHRyX3QgY2FtX2Jhc2VfYWRkcjsNCj4gDQo+
IHUzMiBfX2lvbWVtICpjYW1fYmFzZV9hZGRyOw0KPiANCg0KRG9uZS4NCg0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgIGZtX211cmFtX2ZyZWVfbWVtKHBfZm0tPnBfbXVyYW0sIHBfZm0tPmNhbV9v
ZmZzZXQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2ZtLT5jYW1fc2l6
ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgcF9mbS0+Y2FtX3NpemUgPQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICBwX2ZtLT5wX2ZtX2Rydl9wYXJhbS0+ZG1hX2NhbV9udW1fb2ZfZW50
cmllcyAqIDcyICsNCj4gMTI4Ow0KPiA+ICsgICAgICAgICAgICAgcF9mbS0+Y2FtX29mZnNldCA9
IGZtX211cmFtX2FsbG9jKHBfZm0tPnBfbXVyYW0sDQo+ICh1aW50MzJfdCkNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2ZtLT5jYW1fc2l6
ZSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHByX2VycigiTVVSQU0gYWxsb2MgZm9yIERN
QSBDQU0gZmFpbGVkXG4iKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FTk9N
RU07DQo+ID4gKyAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgY2FtX2Jh
c2VfYWRkciA9IGZtX211cmFtX29mZnNldF90b192YmFzZShwX2ZtLT5wX211cmFtLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2Zt
LT5jYW1fb2Zmc2V0KTsNCj4gPiArICAgICAgICAgICAgIHN3aXRjaCAocF9mbS0+cF9mbV9kcnZf
cGFyYW0tPmRtYV9jYW1fbnVtX29mX2VudHJpZXMpIHsNCj4gPiArICAgICAgICAgICAgIGNhc2Ug
KDgpOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBvdXRfYmUzMigodWludDMyX3QgX19pb21l
bSAqKWNhbV9iYXNlX2FkZHIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDB4
ZmYwMDAwMDApOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAg
ICAgICAgIGNhc2UgKDE2KToNCj4gPiArICAgICAgICAgICAgICAgICAgICAgb3V0X2JlMzIoKHVp
bnQzMl90IF9faW9tZW0gKiljYW1fYmFzZV9hZGRyLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAweGZmZmYwMDAwKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgYnJlYWs7
DQo+ID4gKyAgICAgICAgICAgICBjYXNlICgyNCk6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
IG91dF9iZTMyKCh1aW50MzJfdCBfX2lvbWVtICopY2FtX2Jhc2VfYWRkciwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgMHhmZmZmZmYwMCk7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgICAgICAgY2FzZSAoMzIpOg0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICBvdXRfYmUzMigodWludDMyX3QgX19pb21lbSAqKWNhbV9iYXNlX2FkZHIs
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDB4ZmZmZmZmZmYpOw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgICAgICAgIGRlZmF1bHQ6DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgIHByX2Vycigid3JvbmcgZG1hX2NhbV9udW1fb2ZfZW50
cmllc1xuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHJldHVybiAtRURPTTsNCj4gPiAr
ICAgICAgICAgICAgIH0NCj4gPiArICAgICB9DQo+ID4gKw0KPiANCj4gUGxlYXNlIGRvbid0IHVz
ZSAtRURPTSBmb3Igc2l0dWF0aW9ucyB3aGVyZSB0aGUgZW50aXJlIHJlc3Qgb2YgdGhlIGtlcm5l
bA0KPiB1c2VzIC1FSU5WQUwuDQo+IA0KPiBVbm5lY2Vzc2FyeSBwYXJlbnRoZXNlcy4NCj4gDQo+
IENvdWxkbid0IHRoaXMganVzdCBiZSByZXBsYWNlZCB3aXRoOg0KPiAgICAgICAgIG91dF9iZTMy
KGNhbV9iYXNlX2FkZHIsIH4oMSA8PCAoMzIgLSBkbWFfY2FtX251bV9vZl9lbnRyaWVzKSkgLSAx
KTsNCj4gPw0KPiANCg0KQ2hhbmdlZCB0aGlzIHRvIHNvbWV0aGluZyBzaW1pbGFyIHRvIHlvdXIg
c3VnZ2VzdGlvbi4gDQoNCj4gPiB2b2lkICpmbV9jb25maWcoc3RydWN0IGZtX3BhcmFtc190ICpw
X2ZtX3BhcmFtKQ0KPiA+ICt7DQo+ID4gKyAgICAgc3RydWN0IGZtX3QgKnBfZm07DQo+ID4gKyAg
ICAgdWludHB0cl90IGJhc2VfYWRkcjsNCj4gPiArDQo+ID4gKyAgICAgaWYgKCEoKHBfZm1fcGFy
YW0tPmZpcm13YXJlLnBfY29kZSAmJiBwX2ZtX3BhcmFtLQ0KPiA+ZmlybXdhcmUuc2l6ZSkgfHwN
Cj4gPiArICAgICAgICAgICAoIXBfZm1fcGFyYW0tPmZpcm13YXJlLnBfY29kZSAmJiAhcF9mbV9w
YXJhbS0NCj4gPmZpcm13YXJlLnNpemUpKSkNCj4gPiArICAgICAgICAgICAgIHJldHVybiBOVUxM
Ow0KPiA+ICsNCj4gPiArICAgICBiYXNlX2FkZHIgPSBwX2ZtX3BhcmFtLT5iYXNlX2FkZHI7DQo+
ID4gKw0KPiA+ICsgICAgIC8qIEFsbG9jYXRlIEZNIHN0cnVjdHVyZSAqLw0KPiA+ICsgICAgIHBf
Zm0gPSBremFsbG9jKHNpemVvZigqcF9mbSksIEdGUF9LRVJORUwpOw0KPiA+ICsgICAgIGlmICgh
cF9mbSkNCj4gPiArICAgICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICBw
X2ZtLT5wX2ZtX3N0YXRlX3N0cnVjdCA9IGt6YWxsb2Moc2l6ZW9mKCpwX2ZtLQ0KPiA+cF9mbV9z
dGF0ZV9zdHJ1Y3QpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgR0ZQX0tFUk5FTCk7DQo+ID4gKyAgICAgaWYgKCFwX2ZtLT5wX2ZtX3N0YXRlX3N0
cnVjdCkgew0KPiA+ICsgICAgICAgICAgICAga2ZyZWUocF9mbSk7DQo+ID4gKyAgICAgICAgICAg
ICBwcl9lcnIoIkZNIFN0YXR1cyBzdHJ1Y3R1cmVcbiIpOw0KPiA+ICsgICAgICAgICAgICAgcmV0
dXJuIE5VTEw7DQo+ID4gKyAgICAgfQ0KPiANCj4gSXQncyBnZW5lcmFsbHkgbm90IHJlY29tbWVu
ZGVkIHRvIHByaW50IGFuIGVycm9yIG9uIG1lbW9yeSBhbGxvY2F0aW9uDQo+IGZhaWx1cmUsIGJ1
dCB0aGlzIG1lc3NhZ2UgZG9lc24ndCBldmVuIG1ha2Ugc2Vuc2UuDQo+IA0KDQpSZW1vdmVkIHRo
b3NlIHByaW50cyAoaGVyZSBhbmQgaW4gb3RoZXIgcGxhY2VzKS4NCg0KPiA+ICsgICAgIGlmIChw
X2ZtLT5wX2ZtX3N0YXRlX3N0cnVjdC0+cmV2X2luZm8ubWFqb3JfcmV2IDwgNiAmJg0KPiA+ICsg
ICAgICAgICBwX2ZtLT5wX2ZtX3N0YXRlX3N0cnVjdC0+cmV2X2luZm8ubWFqb3JfcmV2ICE9IDQg
JiYNCj4gPiArICAgICAgICAgcF9mbS0+cmVzZXRfb25faW5pdCkgew0KPiA+ICsgICAgICAgICAg
ICAgZXJyID0gZndfbm90X3Jlc2V0X2VycmF0dW1fYnVnemlsbGE2MTczd2EocF9mbSk7DQo+ID4g
KyAgICAgICAgICAgICBpZiAoZXJyICE9IDApDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIHJl
dHVybiBlcnI7DQo+IA0KPiBidWd6aWxsYTYxNzN3YT8NCj4gDQoNClRoaXMgaXMgdGhlIG5hbWUg
b2YgYW4gb2xkIGlzc3VlIHRyYWNraW5nIHN5c3RlbSBpZCB0aGF0IGxlYWtlZCBpbnRvIHRoZSBj
b2RlYmFzZS4NCkknbGwgcmVuYW1lIGl0Lg0KDQo+ID4gKyAgICAgfSBlbHNlIHsNCj4gPiArICAg
ICAgICAgICAgIC8qIFJlc2V0IHRoZSBGTSBpZiByZXF1aXJlZC4gKi8NCj4gPiArICAgICAgICAg
ICAgIGlmIChwX2ZtLT5yZXNldF9vbl9pbml0KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
IHUzMiBzdnIgPSBtZnNwcihTUFJOX1NWUik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICBpZiAoKChTVlJfU09DX1ZFUihzdnIpID09IFNWUl9UNDI0MCAmJg0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICBTVlJfUkVWKHN2cikgPiAweDEwKSkgfHwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAoKFNWUl9TT0NfVkVSKHN2cikgPT0gU1ZSX1Q0MTYwICYm
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTVlJfUkVWKHN2cikgPiAweDEw
KSkgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNWUl9TT0NfVkVSKHN2
cikgPT0gU1ZSX1Q0MDgwICYmDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBT
VlJfUkVWKHN2cikgPiAweDEwKSkgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAoU1ZSX1NPQ19WRVIoc3ZyKSA9PSBTVlJfVDIwODApIHx8DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgKFNWUl9TT0NfVkVSKHN2cikgPT0gU1ZSX1QyMDgxKSkgew0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByX2RlYnVnKCJIYWNrOiBObyBGTSByZXNldCFc
biIpOw0KPiAgICAgICAgICAgICAgICAgaWYgKElTX0VSUl9WQUxVRShwX2ZtLT5jYW1fb2Zmc2V0
KSkgeyBXaHk/DQo+IA0KDQpmbV9tdXJhbV9hbGxvYyAoKSBjYW4gcmV0dXJuIGFuIG9mZnNldCBv
ciBhbiBFcnJvci4NCg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dF9iZTMyKCZwX2ZtLT5wX2ZtX2ZwbV9yZWdz
LT5mbV9yc3RjLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZQ
TV9SU1RDX0ZNX1JFU0VUKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBN
ZW1vcnkgYmFycmllciAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1iKCk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNsZWVwX3JhbmdlKDEwMCwgMTAx
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgaWYgKGZtYW5faXNfcW1pX2hhbHRfbm90X2J1c3lfc3RhdGUoDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgcF9mbS0+cF9mbV9xbWlfcmVncykpIHsNCj4gDQo+IERv
bid0IGFsaWduIGNvbnRpbnVhdGlvbiBsaW5lcyB3aXRoIHRoZSBpZi1ib2R5Lg0KPiANCg0KRG9u
ZS4NCg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtYW5fcmVzdW1lKHBfZm0t
PnBfZm1fZnBtX3JlZ3MpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzbGVl
cF9yYW5nZSgxMDAsIDEwMSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIH0NCj4gPiArICAg
ICAgICAgICAgIH0NCj4gPiArDQo+IA0KPiBXaHkgc3VjaCBhIG5hcnJvdyByYW5nZSBpbiB1c2xl
ZXBfcmFuZ2UoKT8NCj4gDQoNCkkgd2FzIGxvb2tpbmcgaGVyZTogaHR0cHM6Ly93d3cua2VybmVs
Lm9yZy9kb2MvRG9jdW1lbnRhdGlvbi90aW1lcnMvdGltZXJzLWhvd3RvLnR4dA0KSW4gYWRkaXRp
b24sIGNoZWNrcGF0Y2ggc2F5cyB0aGF0IHVzbGVlcF9yYW5nZSBpcyBwcmVmZXJyZWQgb3ZlciB1
ZGVsYXkuDQpTbyBpbnN0ZWFkIG9mIHVkZWxheSgxMDApLCBJIHVzZWQgdXNsZWVwX3JhbmdlKDEw
MCwgMTAxKTsNCldlIGNhbiBjaGFuZ2UgdGhlIHJhbmdlLCBpbiB5b3VyIG9waW5pb24sIHdoYXQg
aXMgdGhlIG1vcmUgYXBwcm9wcmlhdGUgcmFuZ2U/DQoNCj4gPiArLyogTWFjcm8gZm9yIGNhbGxp
bmcgTUFDIGVycm9yIGludGVycnVwdCBoYW5kbGVyICovICNkZWZpbmUNCj4gPiArRk1fTV9DQUxM
X01BQ19FUlJfSVNSKF9wX2ZtLCBfaWQpIFwNCj4gPiArICAgICAoX3BfZm0tPmludHJfbW5nWyhl
bnVtDQo+IGZtX2ludGVyX21vZHVsZV9ldmVudCkoRk1fRVZfRVJSX01BQzAgKyBfaWQpXS4gXA0K
PiA+ICsgICAgIGZfaXNyKHBfZm0tPmludHJfbW5nWyhlbnVtIGZtX2ludGVyX21vZHVsZV9ldmVu
dClcDQo+ID4gKyAgICAgKEZNX0VWX0VSUl9NQUMwICsgX2lkKV0uaF9zcmNfaGFuZGxlKSkNCj4g
DQo+IFdoeSBhcmUgeW91IGNhc3RpbmcgdG8gYW4gZW51bSBqdXN0IHRvIHVzZSBpdCBhcyBhbiBh
cnJheSBpbmRleD8NCj4gDQoNClJlbW92ZWQgdGhpcyBjYXN0aW5nLg0KDQo+ID4gK2ludCBmbV9z
ZXRfZXhjZXB0aW9uKHN0cnVjdCBmbV90ICpwX2ZtLCBlbnVtIGZtX2V4Y2VwdGlvbnMNCj4gZXhj
ZXB0aW9uLA0KPiA+ICsgICAgICAgICAgICAgICAgICBib29sIGVuYWJsZSkNCj4gPiArew0KPiA+
ICsgICAgIHVpbnQzMl90IGJpdF9tYXNrID0gMDsNCj4gPiArICAgICBlbnVtIGZtYW5fZXhjZXB0
aW9ucyBmc2xfZXhjZXB0aW9uOw0KPiA+ICsgICAgIHN0cnVjdCBmbWFuX3JnIGZtYW5fcmc7DQo+
ID4gKyAgICAgaW50IHJldDsNCj4gPiArDQo+ID4gKyAgICAgcmV0ID0gaXNfaW5pdF9kb25lKHBf
Zm0tPnBfZm1fZHJ2X3BhcmFtKTsNCj4gPiArICAgICBpZiAocmV0KQ0KPiA+ICsgICAgICAgICAg
ICAgcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKyAgICAgZm1hbl9yZy5ibWlfcmcgPSBwX2ZtLT5w
X2ZtX2JtaV9yZWdzOw0KPiA+ICsgICAgIGZtYW5fcmcucW1pX3JnID0gcF9mbS0+cF9mbV9xbWlf
cmVnczsNCj4gPiArICAgICBmbWFuX3JnLmZwbV9yZyA9IHBfZm0tPnBfZm1fZnBtX3JlZ3M7DQo+
ID4gKyAgICAgZm1hbl9yZy5kbWFfcmcgPSBwX2ZtLT5wX2ZtX2RtYV9yZWdzOw0KPiA+ICsNCj4g
PiArICAgICBHRVRfRVhDRVBUSU9OX0ZMQUcoYml0X21hc2ssIGV4Y2VwdGlvbik7DQo+ID4gKyAg
ICAgaWYgKGJpdF9tYXNrKSB7DQo+ID4gKyAgICAgICAgICAgICBpZiAoZW5hYmxlKQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICBwX2ZtLT5wX2ZtX3N0YXRlX3N0cnVjdC0+ZXhjZXB0aW9ucyB8
PSBiaXRfbWFzazsNCj4gPiArICAgICAgICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgcF9mbS0+cF9mbV9zdGF0ZV9zdHJ1Y3QtPmV4Y2VwdGlvbnMgJj0NCj4gPiArIH5iaXRf
bWFzazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICBGTUFOX0VYQ0VQVElPTl9UUkFOUyhmc2xf
ZXhjZXB0aW9uLCBleGNlcHRpb24pOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgIHJldHVybiAo
aW50KWZtYW5fc2V0X2V4Y2VwdGlvbigmZm1hbl9yZywNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBmc2xfZXhjZXB0aW9uLCBlbmFibGUpOw0KPiANCj4g
Zm1hbl9zZXRfZXhjZXB0aW9uKCkgYWxyZWFkeSByZXR1cm5zIGludC4NCj4gDQoNClJlbW92ZWQg
dGhpcyBjYXN0aW5nIChoZXJlIGFuZCBlbHNld2hlcmUpLg0KDQo+ID4gKyAgICAgfSBlbHNlIHsN
Cj4gPiArICAgICAgICAgICAgIHByX2VycigiVW5kZWZpbmVkIGV4Y2VwdGlvbmlcbiIpOw0KPiAN
Cj4gVHlwby4NCg0KRml4ZWQsIHRoYW5rcy4NCg0KPiANCj4gPiArICAgICAgICAgICAgIHJldHVy
biAtRURPTTsNCj4gDQo+IE1hdGggYXJndW1lbnQgb3V0IG9mIHJhbmdlIG9mIGZ1bmN0aW9uPw0K
PiANCj4gV2hhdCBtYXRoIGZ1bmN0aW9uIGlzIGludm9sdmVkPw0KPiANCg0KRHJvcHBlZCB0aGUg
dXNlIG9mIEVET00sIGNoYW5nZWQgdG8gRUlOVkFMIChoZXJlIGFuZCBlbHNld2hlcmUpLg0KDQo+
ID4gKy8qIFByZXZlbnRzIHRoZSB1c2Ugb2YgVFggcG9ydCAxIHdpdGggT1AgcG9ydCAwIGZvciBG
TSBNYWpvciBSZXYgNA0KPiA+ICsoUDEwMjMpDQo+ID4gKi8NCj4gPg0KPiA+ICsjZGVmaW5lIEZN
X0xPV19FTkRfUkVTVFJJQ1RJT04NCj4gDQo+IFRoaXMgaXMgbmV2ZXIgdXNlZCAoYW5kIHdvdWxk
IGJlIGEgbXVsdGlwbGF0Zm9ybSB2aW9sYXRpb24gaWYgaXQgd2VyZSkuDQo+IA0KDQpMZWZ0b3Zl
cnMsIHJlbW92ZWQuDQoNCj4gPiArDQo+ID4gKyNkZWZpbmUgR0VUX0VYQ0VQVElPTl9GTEFHKGJp
dF9tYXNrLCBleGNlcHRpb24pICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArZG8geyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgXA0KPiA+ICsgICAgIHN3aXRjaCAoKGludClleGNlcHRpb24pIHsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgY2FzZSBGTV9FWF9ETUFfQlVTX0VS
Uk9SOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICAg
ICAgICAgIGJpdF9tYXNrID0gRk1fRVhfRE1BX0JVU19FUlJPUjsgICAgICAgICAgICAgICAgIFwN
Cj4gPiArICAgICAgICAgICAgIGJyZWFrOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgIGNhc2UgRk1fRVhfRE1BX1NJTkdMRV9QT1JU
X0VDQzogICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYml0X21h
c2sgPSBGTV9FWF9ETUFfU0lOR0xFX1BPUlRfRUNDOyAgICAgICAgICAgICAgICAgICBcDQo+ID4g
KyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0RNQV9SRUFEX0VDQzogICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYml0
X21hc2sgPSBGTV9FWF9ETUFfUkVBRF9FQ0M7ICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+
ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0RNQV9TWVNURU1fV1JJVEVf
RUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAg
Yml0X21hc2sgPSBGTV9FWF9ETUFfU1lTVEVNX1dSSVRFX0VDQzsgICAgICAgICAgICAgICAgICBc
DQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0RNQV9GTV9XUklURV9F
Q0M6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAg
ICAgYml0X21hc2sgPSBGTV9FWF9ETUFfRk1fV1JJVEVfRUNDOyAgICAgICAgICAgICAgICAgICAg
ICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0ZQTV9TVEFMTF9P
Tl9UQVNLUzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAg
ICAgICAgYml0X21hc2sgPSBGTV9FWF9GUE1fU1RBTExfT05fVEFTS1M7ICAgICAgICAgICAgICAg
ICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0ZQTV9TSU5H
TEVfRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAg
ICAgICAgICAgYml0X21hc2sgPSBGTV9FWF9GUE1fU0lOR0xFX0VDQzsgICAgICAgICAgICAgICAg
ICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX0ZQTV9E
T1VCTEVfRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsg
ICAgICAgICAgICAgYml0X21hc2sgPSBGTV9FWF9GUE1fRE9VQkxFX0VDQzsgICAgICAgICAgICAg
ICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VYX1FN
SV9TSU5HTEVfRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+
ICsgICAgICAgICAgICAgYml0X21hc2sgPSBGTV9FWF9RTUlfU0lOR0xFX0VDQzsgICAgICAgICAg
ICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZNX0VY
X1FNSV9ET1VCTEVfRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0K
PiA+ICsgICAgICAgICAgICAgYml0X21hc2sgPSBGTV9FWF9RTUlfRE9VQkxFX0VDQzsgICAgICAg
ICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIEZN
X0VYX1FNSV9ERVFfRlJPTV9VTktOT1dOX1BPUlRJRDogICAgICAgICAgICAgICAgIFwNCj4gPiAr
ICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfUU1JX0RFUV9GUk9NX1VOS05PV05fUE9SVElE
OyAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgY2FzZSBGTV9FWF9C
TUlfTElTVF9SQU1fRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4g
PiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfQk1JX0xJU1RfUkFNX0VDQzsgICAgICAg
ICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgY2FzZSBGTV9F
WF9CTUlfU1RPUkFHRV9QUk9GSUxFX0VDQzogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwN
Cj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfQk1JX1NUT1JBR0VfUFJPRklMRV9F
Q0M7ICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgY2FzZSBG
TV9FWF9CTUlfU1RBVElTVElDU19SQU1fRUNDOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IFwNCj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfQk1JX1NUQVRJU1RJQ1NfUkFN
X0VDQzsgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgY2Fz
ZSBGTV9FWF9CTUlfRElTUEFUQ0hfUkFNX0VDQzogICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIFwNCj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfQk1JX0RJU1BBVENIX1JB
TV9FQ0M7ICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAg
Y2FzZSBGTV9FWF9JUkFNX0VDQzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfSVJBTV9FQ0M7ICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7ICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAg
ICAgY2FzZSBGTV9FWF9NVVJBTV9FQ0M6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gRk1fRVhfTVVSQU1fRUND
OyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJlYWs7
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4g
KyAgICAgZGVmYXVsdDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGJpdF9tYXNrID0gMDsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgYnJl
YWs7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+
ID4gKyAgICAgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIFwNCj4gPiArfSB3aGlsZSAoMCkNCj4gPiArDQo+ID4gKyNkZWZpbmUg
R0VUX0ZNX01PRFVMRV9FVkVOVChfcF9mbSwgX21vZCwgX2lkLCBfaW50cl90eXBlLA0KPiBfZXZl
bnQpICAgIFwNCj4gPiArZG8geyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgIHN3aXRjaCAoX21vZCkgeyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAg
ICAgY2FzZSAoRk1fTU9EX1BSUyk6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGlmIChfaWQpICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICBfZXZlbnQgPSBGTV9FVl9EVU1NWV9MQVNUOyAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4g
KyAgICAgICAgICAgICBlbHNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgZXZlbnQgPSAoX2ludHJf
dHlwZSA9PSBGTV9JTlRSX1RZUEVfRVJSKSA/ICAgICAgXA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICBGTV9FVl9FUlJfUFJTIDogRk1fRVZfUFJTOyAgICAgICAgICAgICAgICAgICAgICBcDQo+
ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIChGTV9NT0RfVE1SKTogICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAgICAg
aWYgKF9pZCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBc
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIF9ldmVudCA9IEZNX0VWX0RVTU1ZX0xBU1Q7ICAg
ICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGVsc2UgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICBfZXZlbnQgPSAoX2ludHJfdHlwZSA9PSBGTV9JTlRSX1RZUEVfRVJSKSA/ICAg
ICBcDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIEZNX0VWX0RVTU1ZX0xBU1QgOiBGTV9FVl9U
TVI7ICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGJyZWFrOyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAgIGNh
c2UgKEZNX01PRF9NQUMpOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBcDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIF9ldmVudCA9IChfaW50cl90eXBlID09
IEZNX0lOVFJfVFlQRV9FUlIpID8gICAgIFwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgKEZN
X0VWX0VSUl9NQUMwICsgX2lkKSA6ICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAoRk1fRVZfTUFDMCArIF9pZCk7ICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBjYXNlIChGTV9NT0RfRk1B
Tl9DVFJMKTogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+ICsg
ICAgICAgICAgICAgaWYgKF9pbnRyX3R5cGUgPT0gRk1fSU5UUl9UWVBFX0VSUikgICAgICAgICAg
ICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIF9ldmVudCA9IEZNX0VWX0RV
TU1ZX0xBU1Q7ICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICAgICAgICAgIGVsc2Ug
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICBfZXZlbnQgPSAoRk1fRVZfRk1BTl9DVFJMXzAgKyBfaWQp
OyAgICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICBkZWZhdWx0OiAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXA0K
PiA+ICsgICAgICAgICAgICAgX2V2ZW50ID0gRk1fRVZfRFVNTVlfTEFTVDsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgICAgICAgICBicmVhazsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwNCj4gPiArICAgICB9ICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
XA0KPiA+ICt9IHdoaWxlICgwKQ0KPiANCj4gVXNlIGZ1bmN0aW9ucyBpbnN0ZWFkIG9mIG1hY3Jv
cyB3aGVyZXZlciBwb3NzaWJsZS4NCj4gDQoNClJlcGxhY2VkIGNvbXBsZXggTWFjcm9zIHdpdGgg
ZnVuY3Rpb25zLg0KDQo+ID4gKy8qIGRvIG5vdCBjaGFuZ2UhIGlmIGNoYW5nZWQsIG11c3QgYmUg
ZGlzYWJsZWQgZm9yIHJldjEgISAqLw0KPiA+ICsjZGVmaW5lIERGTFRfVkVSSUZZX1VDT0RFICAg
ICAgICAgICAgICAgICBmYWxzZQ0KPiANCj4gSSBrbm93IEkgY29tcGxhaW5lZCBhYm91dCB0aGlz
IGxhc3QgdGltZS4uLg0KPiANCj4gDQoNCkxlZnRvdmVycywgcmVtb3ZlZC4NCg0KPiA+ICsNCj4g
PiArI2RlZmluZSBERkxUX0RNQV9SRUFEX0lOVF9CVUZfTE9XKGRtYV90aHJlc2hfbWF4X2J1Zikg
ICAgICAgIFwNCj4gPiArICAgICAoKGRtYV90aHJlc2hfbWF4X2J1ZiArIDEpIC8gMikNCj4gPiAr
I2RlZmluZSBERkxUX0RNQV9SRUFEX0lOVF9CVUZfSElHSChkbWFfdGhyZXNoX21heF9idWYpICAg
ICAgIFwNCj4gPiArICAgICAoKGRtYV90aHJlc2hfbWF4X2J1ZiArIDEpICogMyAvIDQpDQo+ID4g
KyNkZWZpbmUgREZMVF9ETUFfV1JJVEVfSU5UX0JVRl9MT1coZG1hX3RocmVzaF9tYXhfYnVmKSAg
ICAgICBcDQo+ID4gKyAgICAgKChkbWFfdGhyZXNoX21heF9idWYgKyAxKSAvIDIpDQo+ID4gKyNk
ZWZpbmUgREZMVF9ETUFfV1JJVEVfSU5UX0JVRl9ISUdIKGRtYV90aHJlc2hfbWF4X2J1ZilcDQo+
ID4gKyAgICAgKChkbWFfdGhyZXNoX21heF9idWYgKyAxKSAqIDMgLyA0KQ0KPiA+ICsjZGVmaW5l
IERGTFRfRE1BX0NPTU1fUV9MT1cobWFqb3IsIGRtYV90aHJlc2hfbWF4X2NvbW1xKQ0KPiBcDQo+
ID4gKyAgICAgKChtYWpvciA9PSA2KSA/IDB4MkEgOiAoKGRtYV90aHJlc2hfbWF4X2NvbW1xICsg
MSkgLyAyKSkNCj4gPiArI2RlZmluZSBERkxUX0RNQV9DT01NX1FfSElHSChtYWpvciwgZG1hX3Ro
cmVzaF9tYXhfY29tbXEpDQo+IFwNCj4gPiArICAgICAoKG1ham9yID09IDYpID8gMHgzZiA6ICgo
ZG1hX3RocmVzaF9tYXhfY29tbXEgKyAxKSAqIDMgLyA0KSkNCj4gPiArI2RlZmluZSBERkxUX1RP
VEFMX05VTV9PRl9UQVNLUyhtYWpvciwgbWlub3IsDQo+IGJtaV9tYXhfbnVtX29mX3Rhc2tzKSAg
XA0KPiA+ICsgICAgICgobWFqb3IgPT0gNikgPyAoKG1pbm9yID09IDEgfHwgbWlub3IgPT0gNCkg
PyA1OSA6IDEyNCkgOiAgICAgICBcDQo+ID4gKyAgICAgYm1pX21heF9udW1fb2ZfdGFza3MpDQo+
IA0KPiBXaGVyZSBkbyAweDJhLCAweDNmLCA1OSwgMTI0LCBldGMgY29tZSBmcm9tPyAgUGxlYXNl
IGRlZmluZSBzeW1ib2xpY2FsbHkuDQo+IA0KDQpBZGRlZCBkZWZpbmVzIGZvciB0aGUgdmFsdWVz
IGFib3ZlLg0KDQo+ID4gKyNkZWZpbmUgREZMVF9UT1RBTF9GSUZPX1NJWkUobWFqb3IsIG1pbm9y
KSAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgKChtYWpvciA9PSA2KSA/ICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcDQo+ID4gKyAgICAgKChtaW5vciA9PSAx
IHx8IG1pbm9yID09IDQpID8gKDE1NiAqIDEwMjQpIDogKDI5NSAqIDEwMjQpKSA6ICAgIFwNCj4g
PiArICAgICAoKChtYWpvciA9PSAyKSB8fCAobWFqb3IgPT0gNSkpID8gICAgICAgICAgICAgICAg
ICAgICAgIFwNCj4gPiArICAgICAoMTAwICogMTAyNCkgOiAoKG1ham9yID09IDQpID8gICAgICAg
ICAgICAgICAgICBcDQo+ID4gKyAgICAgKDQ2ICogMTAyNCkgOiAoMTIyICogMTAyNCkpKSkNCj4g
DQo+IFRoaXMgaXNuJ3QgdGhlIEludGVybmF0aW9uYWwgT2JmdXNjYXRlZCBDIENvZGUgQ29udGVz
dC4NCj4gDQoNCk1hZGUgaXQgbG9vayBzbGlnaHRseSBiZXR0ZXIuDQpHaXZlbiB0aGUgbGFyZ2Ug
bnVtYmVyIG9mIEhXIHBsYXRmb3JtcyBzdXBwb3J0ZWQsIHRoaXMgc2VsZWN0aW9uIHdpbGwgbG9v
ayBjb21wbGljYXRlZCBhcyBtdWNoIGFzIHdlIHRyeSB0byBiZWF1dGlmeSBpdC4NClRoaXMgY29k
ZSBkZXRlcm1pbmVzIHRoZSBLQiBvZiBNVVJBTSB0byB1c2UgYXMgdG90YWwgRklGTyBzaXplIGJh
c2VkIG9uIEZNYW4gcmV2aXNpb24uDQoNCj4gPg0KPiA+ICsvKiBNZW1vcnkgTWFwcGVkIFJlZ2lz
dGVycyAqLw0KPiA+ICsNCj4gPiArc3RydWN0IGZtX2lyYW1fcmVnc190IHsNCj4gPiArICAgICB1
aW50MzJfdCBpYWRkOyAgLyogRk0gSVJBTSBpbnN0cnVjdGlvbiBhZGRyZXNzIHJlZ2lzdGVyICov
DQo+ID4gKyAgICAgdWludDMyX3QgaWRhdGE7LyogRk0gSVJBTSBpbnN0cnVjdGlvbiBkYXRhIHJl
Z2lzdGVyICovDQo+ID4gKyAgICAgdWludDMyX3QgaXRjZmc7LyogRk0gSVJBTSB0aW1pbmcgY29u
ZmlnIHJlZ2lzdGVyICovDQo+ID4gKyAgICAgdWludDMyX3QgaXJlYWR5Oy8qIEZNIElSQU0gcmVh
ZHkgcmVnaXN0ZXIgKi8NCj4gPiArICAgICB1aW50OF90IHJlc1sweDgwMDAwIC0gMHgxMF07DQo+
ID4gK30gX19hdHRyaWJ1dGVfXygoX19wYWNrZWRfXykpOw0KPiANCj4gV2h5IGRvIHlvdSBuZWVk
IF9fcGFja2VkX18gb24gdGhpcz8NCj4gDQoNCkFzIGFsbCBidXQgdGhlIGxhc3QgdGhlIG1lbWJl
ciBvZiB0aGlzIG1lbW9yeSBtYXBwZWQgc3RydWN0IGFyZSB1MzIsIGl0J3Mgbm90IG1hbmRhdG9y
eSBidXQgYXQgYSBjZXJ0YWluIG1vbWVudCBzb21lb25lIGNvbnNpZGVyZWQgYSBnb29kIGlkZWEg
dG8gdGhyb3cgaW4gdGhlIHBhY2tlZCBhdHRyaWJ1dGUuDQpJIHlvdSBwcmVmZXIgdG8gcmVtb3Zl
IGl0LCBJSSBjYW4gZG8gc28uDQoNCj4gV2h5IGRvIHlvdSBuZWVkIHRoZSBwYWRkaW5nIG9uIHRo
ZSBlbmQ/CQ0KDQpBZ2FpbiwgaXQgaXMgbWVtb3J5IG1hcHBlZCwgd2UgZG9uJ3QgaGF2ZSBvdGhl
ciByZWdzIGFmdGVyIHRob3NlLCBzbyB3ZSBjYW4gZHJvcCB0aGUgcGFkZGluZywgSSBjYW4gcmVt
b3ZlIGl0Lg0KSSB5b3UgcHJlZmVyIHRvIHJlbW92ZSBpdCwgSUkgY2FuIGRvIHNvLg0KIA0KPiAN
Cj4gPiArc3RydWN0IGZtX3Qgew0KPiA+ICsgICAgIHVpbnRwdHJfdCBiYXNlX2FkZHI7DQo+ID4g
KyAgICAgY2hhciBmbV9tb2R1bGVfbmFtZVtNT0RVTEVfTkFNRV9TSVpFXTsNCj4gPiArICAgICBz
dHJ1Y3QgZm1faW50cl9zcmNfdCBpbnRyX21uZ1tGTV9FVl9EVU1NWV9MQVNUXTsNCj4gPiArDQo+
ID4gKyAgICAgc3RydWN0IGZtYW5fZnBtX3JlZ3MgX19pb21lbSAqcF9mbV9mcG1fcmVnczsNCj4g
PiArICAgICBzdHJ1Y3QgZm1hbl9ibWlfcmVncyBfX2lvbWVtICpwX2ZtX2JtaV9yZWdzOw0KPiA+
ICsgICAgIHN0cnVjdCBmbWFuX3FtaV9yZWdzIF9faW9tZW0gKnBfZm1fcW1pX3JlZ3M7DQo+ID4g
KyAgICAgc3RydWN0IGZtYW5fZG1hX3JlZ3MgX19pb21lbSAqcF9mbV9kbWFfcmVnczsNCj4gPiAr
ICAgICBzdHJ1Y3QgZm1hbl9yZWdzIF9faW9tZW0gKnBfZm1fcmVnczsNCj4gPiArICAgICBmbV9l
eGNlcHRpb25zX2NiICpmX2V4Y2VwdGlvbjsNCj4gPiArICAgICBmbV9idXNfZXJyb3JfY2IgKmZf
YnVzX2Vycm9yOw0KPiA+ICsgICAgIHZvaWQgKmhfYXBwOyAgICAgICAgICAgIC8qIEFwcGxpY2F0
aW9uIGhhbmRsZSAqLw0KPiA+ICsgICAgIHNwaW5sb2NrX3QgKnNwaW5sb2NrOw0KPiANCj4gV2h5
IGlzIHRoZSBzcGlubG9jayBkeW5hbWljYWxseSBhbGxvY2F0ZWQ/DQo+IA0KDQpSZW1vdmVkIHRo
ZSBkeW5hbWljIGFsbG9jYXRpb24uDQoNCj4gPiArLyogQm9vdGFyZyB1c2VkIHRvIG92ZXJyaWRl
IHRoZSBLY29uZmlnIEZTTF9GTV9NQVhfRlJBTUVfU0laRSB2YWx1ZQ0KPiAqLw0KPiA+ICsjZGVm
aW5lIEZTTF9GTV9NQVhfRlJNX0JPT1RBUkcgICAgICJmc2xfZm1fbWF4X2ZybSINCj4gPiArDQo+
ID4gKy8qIEJvb3RhcmcgdXNlZCB0byBvdmVycmlkZSBGU0xfRk1fUlhfRVhUUkFfSEVBRFJPT00g
S2NvbmZpZw0KPiB2YWx1ZSAqLw0KPiA+ICsjZGVmaW5lIEZTTF9GTV9SWF9FWFRSQV9IRUFEUk9P
TV9CT09UQVJHDQo+ICJmc2xfZm1fcnhfZXh0cmFfaGVhZHJvb20iDQo+IA0KPiBJcyB0aGlzIGlu
ZGlyZWN0aW9uIHJlYWxseSBuZWVkZWQ/DQo+IA0KDQpJIHRoaW5rIHdlIGNhbiByZW1vdmUsIEkn
bGwgbG9vayBpbnRvIGl0LiANCg0KPiA+ICsvKiBFeHRyYSBoZWFkcm9vbSBmb3IgUnggYnVmZmVy
cy4NCj4gPiArICogRk1hbiBpcyBpbnN0cnVjdGVkIHRvIGFsbG9jYXRlLCBvbiB0aGUgUnggcGF0
aCwgdGhpcyBhbW91bnQgb2YNCj4gPiArICogc3BhY2UgYXQgdGhlIGJlZ2lubmluZyBvZiBhIGRh
dGEgYnVmZmVyLCBiZXNpZGUgdGhlIERQQSBwcml2YXRlDQo+ID4gKyAqIGRhdGEgYXJlYSBhbmQg
dGhlIElDIGZpZWxkcy4NCj4gPiArICogRG9lcyBub3QgaW1wYWN0IFR4IGJ1ZmZlciBsYXlvdXQu
DQo+ID4gKyAqIENvbmZpZ3VyYWJsZSBmcm9tIEtjb25maWcgb3IgYm9vdGFyZ3MuIFplcm8gYnkg
ZGVmYXVsdCwgaXQncw0KPiA+ICtuZWVkZWQgb24NCj4gPiArICogcGFydGljdWxhciBmb3J3YXJk
aW5nIHNjZW5hcmlvcyB0aGF0IGFkZCBleHRyYSBoZWFkZXJzIHRvIHRoZQ0KPiA+ICsgKiBmb3J3
YXJkZWQgZnJhbWUuDQo+ID4gKyAqLw0KPiA+ICtpbnQgZnNsX2ZtX3J4X2V4dHJhX2hlYWRyb29t
ID0NCj4gQ09ORklHX0ZTTF9GTV9SWF9FWFRSQV9IRUFEUk9PTTsNCj4gDQo+IElmIGl0J3MgY29u
ZmlndXJhYmxlIHZpYSBib290YXJncywgd2h5IGlzIHRoZSBrY29uZmlnIG5lZWRlZD8NCj4gDQoN
CktDb25maWcgc2V0cyBkZWZhdWx0IHZhbHVlLCBpbiBib290YXJncyB5b3UgY2FuIG92ZXJyaWRl
Lg0KDQo+ID4gKw0KPiA+ICt1MTYgZm1fZ2V0X21heF9mcm0odm9pZCkNCj4gPiArew0KPiA+ICsg
ICAgIHJldHVybiBmc2xfZm1fbWF4X2ZybTsNCj4gPiArfQ0KPiA+ICtFWFBPUlRfU1lNQk9MKGZt
X2dldF9tYXhfZnJtKTsNCj4gDQo+IGZzbF9mbV9tYXhfZnJtIGlzbid0IHN0YXRpYywgc28gd2h5
IGlzIHRoaXMgYWNjZXNzb3IgbmVlZGVkPw0KPiANCj4gPiAraW50IGZtX2dldF9yeF9leHRyYV9o
ZWFkcm9vbSh2b2lkKQ0KPiA+ICt7DQo+ID4gKyAgICAgcmV0dXJuIEFMSUdOKGZzbF9mbV9yeF9l
eHRyYV9oZWFkcm9vbSwgMTYpOyB9DQo+ID4gK0VYUE9SVF9TWU1CT0woZm1fZ2V0X3J4X2V4dHJh
X2hlYWRyb29tKTsNCj4gDQo+IFdoeSBub3QganVzdCBhbGlnbiBpdCB3aGVuIHlvdSBzZXQgdGhl
IHZhcmlhYmxlPw0KPiANCg0KSXQncyBwb3NzaWJsZSwgSSdsbCB0YWtlIGEgbG9vay4NCg0KPiA+
ICsNCj4gPiArc3RhdGljIGludCBfX2luaXQgZm1fc2V0X21heF9mcm0oY2hhciAqc3RyKSB7DQo+
ID4gKyAgICAgaW50IHJldCA9IDA7DQo+ID4gKw0KPiA+ICsgICAgIHJldCA9IGdldF9vcHRpb24o
JnN0ciwgJmZzbF9mbV9tYXhfZnJtKTsNCj4gPiArICAgICBpZiAocmV0ICE9IDEpIHsNCj4gPiAr
ICAgICAgICAgICAgIC8qIFRoaXMgd2lsbCBvbmx5IHdvcmsgaWYgQ09ORklHX0VBUkxZX1BSSU5U
SyBpcyBjb21waWxlZCBpbiwNCj4gPiArICAgICAgICAgICAgICAqIGFuZCBzb21ldGhpbmcgbGlr
ZSAiZWFybHlwcmludGs9c2VyaWFsLHVhcnQwLDExNTIwMCIgaXMNCj4gPiArICAgICAgICAgICAg
ICAqIHNwZWNpZmllZCBpbiB0aGUgYm9vdGFyZ3MuDQo+ID4gKyAgICAgICAgICAgICAgKi8NCj4g
PiArICAgICAgICAgICAgIHByX2VycigiTm8gc3VpdGFibGUgJXM9PGludD4gcHJvcCBpbiBib290
YXJnczsgd2lsbCB1c2UNCj4gPiArIHRoZSBkZWZhdWx0DQo+ID4gRlNMX0ZNX01BWF9GUkFNRV9T
SVpFICglZCkgZnJvbSBLY29uZmlnLlxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICBGU0xf
Rk1fTUFYX0ZSTV9CT09UQVJHLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgIENPTkZJR19GU0xf
Rk1fTUFYX0ZSQU1FX1NJWkUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgIGZzbF9mbV9tYXhf
ZnJtID0gQ09ORklHX0ZTTF9GTV9NQVhfRlJBTUVfU0laRTsNCj4gPiArICAgICAgICAgICAgIHJl
dHVybiAxOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgLyogRG9uJ3QgYWxsb3cgaW52
YWxpZCBib290YXJnczsgZmFsbGJhY2sgdG8gdGhlIEtjb25maWcgdmFsdWUgKi8NCj4gPiArICAg
ICBpZiAoZnNsX2ZtX21heF9mcm0gPCA2NCB8fCBmc2xfZm1fbWF4X2ZybSA+IDk2MDApIHsNCj4g
PiArICAgICAgICAgICAgIHByX2VycigiSW52YWxpZCAlcz0lZCBpbiBib290YXJncywgdmFsaWQg
cmFuZ2UgaXMNCj4gPiArIDY0LTk2MDAuIEZhbGxpbmcgYmFjaw0KPiA+IHRvIHRoZSBGU0xfRk1f
TUFYX0ZSQU1FX1NJWkUgKCVkKSBmcm9tIEtjb25maWcuXG4iLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgIEZTTF9GTV9NQVhfRlJNX0JPT1RBUkcsIGZzbF9mbV9tYXhfZnJtLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgIENPTkZJR19GU0xfRk1fTUFYX0ZSQU1FX1NJWkUpOw0KPiA+ICsNCj4g
PiArICAgICAgICAgICAgIGZzbF9mbV9tYXhfZnJtID0gQ09ORklHX0ZTTF9GTV9NQVhfRlJBTUVf
U0laRTsNCj4gPiArICAgICAgICAgICAgIHJldHVybiAxOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+
ID4gKyAgICAgcHJfaW5mbygiVXNpbmcgZnNsX2ZtX21heF9mcm09JWQgZnJvbSBib290YXJnc1xu
IiwNCj4gZnNsX2ZtX21heF9mcm0pOw0KPiA+ICsgICAgIHJldHVybiAwOw0KPiA+ICt9DQo+ID4g
K2Vhcmx5X3BhcmFtKEZTTF9GTV9NQVhfRlJNX0JPT1RBUkcsIGZtX3NldF9tYXhfZnJtKTsNCj4g
PiArDQo+ID4gK3N0YXRpYyBpbnQgX19pbml0IGZtX3NldF9yeF9leHRyYV9oZWFkcm9vbShjaGFy
ICpzdHIpIHsNCj4gPiArICAgICBpbnQgcmV0Ow0KPiA+ICsNCj4gPiArICAgICByZXQgPSBnZXRf
b3B0aW9uKCZzdHIsICZmc2xfZm1fcnhfZXh0cmFfaGVhZHJvb20pOw0KPiA+ICsNCj4gPiArICAg
ICBpZiAocmV0ICE9IDEpIHsNCj4gPiArICAgICAgICAgICAgIHByX2VycigiTm8gc3VpdGFibGUg
JXM9PGludD4gcHJvcCBpbiBib290YXJnczsgd2lsbCB1c2UNCj4gPiArIHRoZSBkZWZhdWx0DQo+
ID4gRlNMX0ZNX1JYX0VYVFJBX0hFQURST09NICglZCkgZnJvbSBLY29uZmlnLlxuIiwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICBGU0xfRk1fUlhfRVhUUkFfSEVBRFJPT01fQk9PVEFSRywNCj4g
PiArICAgICAgICAgICAgICAgICAgICBDT05GSUdfRlNMX0ZNX1JYX0VYVFJBX0hFQURST09NKTsN
Cj4gPiArICAgICAgICAgICAgIGZzbF9mbV9yeF9leHRyYV9oZWFkcm9vbSA9DQo+ID4gKyBDT05G
SUdfRlNMX0ZNX1JYX0VYVFJBX0hFQURST09NOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgIHJl
dHVybiAxOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgaWYgKGZzbF9mbV9yeF9leHRy
YV9oZWFkcm9vbSA8DQo+IEZTTF9GTV9SWF9FWFRSQV9IRUFEUk9PTV9NSU4gfHwNCj4gPiArICAg
ICAgICAgZnNsX2ZtX3J4X2V4dHJhX2hlYWRyb29tID4NCj4gRlNMX0ZNX1JYX0VYVFJBX0hFQURS
T09NX01BWCkgew0KPiA+ICsgICAgICAgICAgICAgcHJfZXJyKCJJbnZhbGlkIHZhbHVlIGZvciAl
cz0lZCBwcm9wIGluIGJvb3RhcmdzOyB3aWxsDQo+ID4gKyB1c2UgdGhlIGRlZmF1bHQNCj4gPiBG
U0xfRk1fUlhfRVhUUkFfSEVBRFJPT00gKCVkKSBmcm9tIEtjb25maWcuXG4iLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgIEZTTF9GTV9SWF9FWFRSQV9IRUFEUk9PTV9CT09UQVJHLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgIGZzbF9mbV9yeF9leHRyYV9oZWFkcm9vbSwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICBDT05GSUdfRlNMX0ZNX1JYX0VYVFJBX0hFQURST09NKTsNCj4gPiArICAg
ICAgICAgICAgIGZzbF9mbV9yeF9leHRyYV9oZWFkcm9vbSA9DQo+IENPTkZJR19GU0xfRk1fUlhf
RVhUUkFfSEVBRFJPT007DQo+ID4gKyAgICAgfQ0KPiA+ICsNCj4gPiArICAgICBwcl9pbmZvKCJV
c2luZyBmc2xfZm1fcnhfZXh0cmFfaGVhZHJvb209JWQgZnJvbSBib290YXJnc1xuIiwNCj4gPiAr
ICAgICAgICAgICAgIGZzbF9mbV9yeF9leHRyYV9oZWFkcm9vbSk7DQo+IA0KPiBUaGlzIGlzIHVu
bmVjZXNzYXJpbHkgdmVyYm9zZS4NCj4gDQoNCk9LLg0KDQo+ID4gKw0KPiA+ICsgICAgIHJldHVy
biAwOw0KPiA+ICt9DQo+ID4gK2Vhcmx5X3BhcmFtKEZTTF9GTV9SWF9FWFRSQV9IRUFEUk9PTV9C
T09UQVJHLA0KPiA+ICtmbV9zZXRfcnhfZXh0cmFfaGVhZHJvb20pOw0KPiANCj4gV2h5IGVhcmx5
Pw0KPiANCg0KSSB0aGluayBpdCdzIGZyb20gdGhlIHRpbWUgd2hlbiB0aG9zZSB2YXJpYWJsZXMg
d2VyZSBpbiBEUEFBX0VUSCwgSSdsbCBjaGVjayBpZiB3ZSBjYW4gZHJvcCB0aGUgZWFybHkuDQoN
Cj4gPiArc3RhdGljIGlycXJldHVybl90IGZtX2Vycl9pcnEoaW50IGlycSwgdm9pZCAqX2Rldikg
ew0KPiA+ICsgICAgIHN0cnVjdCBmbV9kcnZfdCAqZm1fZHJ2ID0gKHN0cnVjdCBmbV9kcnZfdCAq
KV9kZXY7DQo+ID4gKw0KPiA+ICsgICAgIGlmICghZm1fZHJ2IHx8ICFmbV9kcnYtPmhfZGV2KQ0K
PiA+ICsgICAgICAgICAgICAgcmV0dXJuIElSUV9OT05FOw0KPiANCj4gV2h5IHdvdWxkIHlvdSBy
ZXF1ZXN0IHRoZSBJUlEgaWYgZWl0aGVyIG9mIHRoZXNlIGFyZSBOVUxMPw0KPiANCg0KVG9vIG11
Y2ggQ2F1dGlvdXNuZXNzLiBJJ2xsIHJlbW92ZS4NCg0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0
IHFlX2Zpcm13YXJlICpmaW5kX2ZtYW5fbWljcm9jb2RlKHZvaWQpIHsNCj4gPiArICAgICBzdGF0
aWMgY29uc3Qgc3RydWN0IHFlX2Zpcm13YXJlICp1Y19wYXRjaDsNCj4gPiArICAgICBzdHJ1Y3Qg
ZGV2aWNlX25vZGUgKm5wOw0KPiA+ICsNCj4gPiArICAgICBpZiAodWNfcGF0Y2gpDQo+ID4gKyAg
ICAgICAgICAgICByZXR1cm4gdWNfcGF0Y2g7DQo+ID4gKw0KPiA+ICsgICAgIC8qIFRoZSBmaXJt
d2FyZSBzaG91bGQgYmUgaW5zaWRlIHRoZSBkZXZpY2UgdHJlZS4gKi8NCj4gPiArICAgICBucCA9
IG9mX2ZpbmRfY29tcGF0aWJsZV9ub2RlKE5VTEwsIE5VTEwsICJmc2wsZm1hbi1maXJtd2FyZSIp
Ow0KPiA+ICsgICAgIGlmIChucCkgew0KPiA+ICsgICAgICAgICAgICAgdWNfcGF0Y2ggPSBvZl9n
ZXRfcHJvcGVydHkobnAsICJmc2wsZmlybXdhcmUiLCBOVUxMKTsNCj4gDQo+IEkgZG9uJ3Qgc2Vl
IGFueSBiaW5kaW5nIGZvciB0aGlzLg0KPiANCg0KWWVzLCBiaW5kaW5nIGlzIHJlcXVpcmVkIGhl
cmUuIA0KDQo+ID4gK3N0YXRpYyBpbnQgZmlsbF9xbWFuX2NoYW5uaGVsc19pbmZvKHN0cnVjdCBm
bV9kcnZfdCAqZm1fZHJ2KQ0KPiANCj4gImNoYW5uaGVscyI/DQo+IA0KDQpUeXBvLCBmaXhlZC4N
Cg0KPiANCj4gPiArc3RhdGljIHN0cnVjdCBmbV9kcnZfdCAqcmVhZF9mbV9kZXZfdHJlZV9ub2Rl
KHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UNCj4gPiAqb2ZfZGV2KQ0KPiA+ICt7DQo+ID4gKyAgICAg
c3RydWN0IGZtX2Rydl90ICpmbV9kcnY7DQo+ID4gKyAgICAgc3RydWN0IGRldmljZV9ub2RlICpm
bV9ub2RlLCAqZGV2X25vZGU7DQo+ID4gKyAgICAgc3RydWN0IG9mX2RldmljZV9pZCBuYW1lOw0K
PiA+ICsgICAgIHN0cnVjdCByZXNvdXJjZSByZXM7DQo+ID4gKyAgICAgY29uc3QgdWludDMyX3Qg
KnVpbnQzMl9wcm9wOw0KPiA+ICsgICAgIGludCBsZW5wLCBlcnI7DQo+ID4gKyAgICAgc3RydWN0
IGNsayAqY2xrOw0KPiA+ICsgICAgIHUzMiBjbGtfcmF0ZTsNCj4gPiArDQo+ID4gKyAgICAgZm1f
bm9kZSA9IG9mX25vZGVfZ2V0KG9mX2Rldi0+ZGV2Lm9mX25vZGUpOw0KPiA+ICsNCj4gPiArICAg
ICB1aW50MzJfcHJvcCA9ICh1aW50MzJfdCAqKW9mX2dldF9wcm9wZXJ0eShmbV9ub2RlLCAiY2Vs
bC1pbmRleCIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgJmxlbnApOw0KPiA+ICsgICAgIGlmICh1bmxpa2VseSghdWludDMyX3Byb3ApKSB7DQo+
ID4gKyAgICAgICAgICAgICBwcl9lcnIoIm9mX2dldF9wcm9wZXJ0eSglcywgY2VsbC1pbmRleCkg
ZmFpbGVkXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgIGZtX25vZGUtPmZ1bGxfbmFtZSk7
DQo+ID4gKyAgICAgICAgICAgICBnb3RvIF9yZXR1cm5fbnVsbDsNCj4gPiArICAgICB9DQo+ID4g
KyAgICAgaWYgKFdBUk5fT04obGVucCAhPSBzaXplb2YodWludDMyX3QpKSkNCj4gPiArICAgICAg
ICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICBmbV9kcnYgPSBremFsbG9jKHNp
emVvZigqZm1fZHJ2KSwgR0ZQX0tFUk5FTCk7DQo+ID4gKyAgICAgaWYgKCFmbV9kcnYpDQo+ID4g
KyAgICAgICAgICAgICBnb3RvIF9yZXR1cm5fbnVsbDsNCj4gPiArDQo+ID4gKyAgICAgZm1fZHJ2
LT5kZXYgPSAmb2ZfZGV2LT5kZXY7DQo+ID4gKyAgICAgZm1fZHJ2LT5pZCA9ICh1OCkqdWludDMy
X3Byb3A7DQo+ID4gKw0KPiA+ICsgICAgIC8qIEdldCB0aGUgRk0gaW50ZXJydXB0ICovDQo+ID4g
KyAgICAgZm1fZHJ2LT5pcnEgPSBvZl9pcnFfdG9fcmVzb3VyY2UoZm1fbm9kZSwgMCwgTlVMTCk7
DQo+ID4gKyAgICAgaWYgKHVubGlrZWx5KGZtX2Rydi0+aXJxID09IDApKSB7DQo+ID4gKyAgICAg
ICAgICAgICBwcl9lcnIoIm9mX2lycV90b19yZXNvdXJjZSgpID0gJWRcbiIsIE5PX0lSUSk7DQo+
ID4gKyAgICAgICAgICAgICBnb3RvIF9yZXR1cm5fbnVsbDsNCj4gPiArICAgICB9DQo+ID4gKw0K
PiA+ICsgICAgIC8qIEdldCB0aGUgRk0gZXJyb3IgaW50ZXJydXB0ICovDQo+ID4gKyAgICAgZm1f
ZHJ2LT5lcnJfaXJxID0gb2ZfaXJxX3RvX3Jlc291cmNlKGZtX25vZGUsIDEsIE5VTEwpOw0KPiA+
ICsNCj4gPiArICAgICAvKiBHZXQgdGhlIEZNIGFkZHJlc3MgKi8NCj4gPiArICAgICBlcnIgPSBv
Zl9hZGRyZXNzX3RvX3Jlc291cmNlKGZtX25vZGUsIDAsICZyZXMpOw0KPiA+ICsgICAgIGlmICh1
bmxpa2VseShlcnIgPCAwKSkgew0KPiA+ICsgICAgICAgICAgICAgcHJfZXJyKCJvZl9hZGRyZXNz
X3RvX3Jlc291cmNlKCkgPSAlZFxuIiwgZXJyKTsNCj4gPiArICAgICAgICAgICAgIGdvdG8gX3Jl
dHVybl9udWxsOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgZm1fZHJ2LT5mbV9iYXNl
X2FkZHIgPSAwOw0KPiA+ICsgICAgIGZtX2Rydi0+Zm1fcGh5c19iYXNlX2FkZHIgPSByZXMuc3Rh
cnQ7DQo+ID4gKyAgICAgZm1fZHJ2LT5mbV9tZW1fc2l6ZSA9IHJlcy5lbmQgKyAxIC0gcmVzLnN0
YXJ0Ow0KPiA+ICsNCj4gDQo+IFdoeSBhcmUgeW91IHVzaW5nIHRoZXNlIE9GIGZ1bmN0aW9ucyBy
YXRoZXIgdGhhbiB1c2luZyBwbGF0Zm9ybV9kZXZpY2UNCj4gbWVjaGFuaXNtcz8NCj4gDQoNCkkn
bGwgaGF2ZSB0byBsb29rIGludG8gaXQsIHRoZXJlJ3Mgbm8gc3BlY2lhbCByZWFzb24gZm9yIHRo
ZSBPRiB1c2UuDQpDYW4geW91IHBsZWFzZSBlbGFib3JhdGUgd2h5IHBsYXRmb3JtIGRldmljZSBt
ZWNoYW5pc21zIGFyZSBiZXR0ZXI/DQoNCj4gPiArICAgICBjbGsgPSBjbGtfZ2V0KGZtX2Rydi0+
ZGV2LCBmbV9kcnYtPmlkID09IDAgPyAiZm0wY2xrIiA6ICJmbTFjbGsiKTsNCj4gPiArICAgICBp
ZiAoSVNfRVJSKGNsaykpIHsNCj4gPiArICAgICAgICAgICAgIHByX2VycigiRmFpbGVkIHRvIGdl
dCBGTSVkIGNsb2NrIHN0cnVjdHVyZVxuIiwgZm1fZHJ2LT5pZCk7DQo+ID4gKyAgICAgICAgICAg
ICBnb3RvIF9yZXR1cm5fbnVsbDsNCj4gPiArICAgICB9DQo+IA0KPiBHZXQgdGhlIGNsb2NrIGZy
b20gdGhlIGNsb2NrcyBwcm9wZXJ0eSBvZiB0aGUgZGV2aWNlIHRyZWUgbm9kZSwgbm90IGJ5DQo+
IGhhcmRjb2Rpbmcgd2hhdCB5b3UgdGhpbmsgdGhlIGNsb2NrJ3MgbmFtZSB3aWxsIGJlLg0KPiAN
Cg0KRG9uZS4NCg0KPiA+ICsgICAgIHVpbnQzMl9wcm9wID0gKHVpbnQzMl90ICopb2ZfZ2V0X3By
b3BlcnR5KGZtX25vZGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgImZzbCxxbWFuLWNoYW5uZWwtcmFuZ2UiLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZsZW5wKTsNCj4gPg0KPiANCj4gRG9u
J3QgY2FzdCBhd2F5IHRoZSBjb25zdC4NCj4gDQoNCkRvbmUuDQoNCj4gPiArICAgICBpZiAodW5s
aWtlbHkoIXVpbnQzMl9wcm9wKSkgew0KPiANCj4gRG9uJ3QgdXNlIHVubGlrZWx5KCkgaW4gcGF0
aHMgdGhhdCBhcmVuJ3QgcGVyZm9ybWFuY2UtY3JpdGljYWwuDQo+IA0KDQpPaywgSSdsbCBjaGVj
ayB0aGUgcmVzdCBvZiB0aGUgY29kZSBmb3IgdGhhdCBpc3N1ZS4NCiANCj4gPiArICAgICAvKiBH
ZXQgdGhlIE1VUkFNIGJhc2UgYWRkcmVzcyBhbmQgc2l6ZSAqLw0KPiA+ICsgICAgIG1lbXNldCgm
bmFtZSwgMCwgc2l6ZW9mKG5hbWUpKTsNCj4gPiArICAgICBpZiAoV0FSTl9PTihzdHJsZW4oIm11
cmFtIikgPj0gc2l6ZW9mKG5hbWUubmFtZSkpKQ0KPiA+ICsgICAgICAgICAgICAgZ290byBfcmV0
dXJuX251bGw7DQo+ID4gKyAgICAgc3RyY3B5KG5hbWUubmFtZSwgIm11cmFtIik7DQo+ID4gKyAg
ICAgaWYgKFdBUk5fT04oc3RybGVuKCJmc2wsZm1hbi1tdXJhbSIpID49IHNpemVvZihuYW1lLmNv
bXBhdGlibGUpKSkNCj4gPiArICAgICAgICAgICAgIGdvdG8gX3JldHVybl9udWxsOw0KPiA+ICsg
ICAgIHN0cmNweShuYW1lLmNvbXBhdGlibGUsICJmc2wsZm1hbi1tdXJhbSIpOw0KPiA+ICsgICAg
IGZvcl9lYWNoX2NoaWxkX29mX25vZGUoZm1fbm9kZSwgZGV2X25vZGUpIHsNCj4gPiArICAgICAg
ICAgICAgIGlmIChsaWtlbHkob2ZfbWF0Y2hfbm9kZSgmbmFtZSwgZGV2X25vZGUpKSkgew0KPiAN
Cj4gV2h5IG5vdCBqdXN0IGRlZmluZSB0aGUgbWF0Y2ggc3RydWN0IHN0YXRpY2FsbHk/DQo+IA0K
DQpEb25lLg0KDQo+ID4gKyNpZm5kZWYgX19TRVJWSUNFX2gNCj4gPiArI2RlZmluZSBfX1NFUlZJ
Q0VfaA0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPGxpbnV4L3ZlcnNpb24uaD4NCj4gDQo+IFdoYXQg
ZG8geW91IG5lZWQgdGhpcyBmb3I/DQo+IA0KDQpOb3QgdXNlZCwgcmVtb3ZlZC4NCg0KPiA+ICsN
Cj4gPiArI2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvdHlw
ZXMuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2lvLmg+DQo+IA0KPiBXaGF0IGRvIHlvdSB1c2Ug
aW4gdGhpcyBmaWxlIGZyb20gbGludXgvaW8uaD8NCj4gDQoNCk1vdmVkICNpbmNsdWRlIDxsaW51
eC9pby5oPiB0aGUgdGhlIGZpbGVzIHdoaWNoIHVzZSBpdC4gDQoNCj4gPiArLyogRGVmaW5lIEFT
U0VSVCBjb25kaXRpb24gKi8NCj4gPiArI3VuZGVmIEFTU0VSVA0KPiA+ICsjZGVmaW5lIEFTU0VS
VCh4KSAgICAgICBXQVJOX09OKCEoeCkpDQo+IA0KPiBXaHkgbm90IGp1c3QgdXNlIFdBUk5fT04g
ZGlyZWN0bHk/DQo+IA0KDQpNb3N0bHkgcGVyc29uYWwgcHJlZmVyZW5jZSwgSSd2ZSBhbHNvIHNl
ZW4gc2ltaWxhciBjb25zdHJ1Y3RzIHVzZWQgaW4gb3RoZXIgZHJpdmVycy4NCk9uZSBjYW4gZGVj
aWRlIGxhdGVyIHRvIGNoYW5nZSB0aGlzIHRvIEJVR19PTigpIG9yIGRpc2FibGUgaXQgZm9yIGRl
YnVnIHB1cnBvc2VzLg0KDQo+ID4gKy8qIFBvaW50ZXJzIE1hbmlwdWxhdGlvbiAqLw0KPiA+ICsj
ZGVmaW5lIFVJTlRfVE9fUFRSKF92YWwpICAgICAgICAgICAoKHZvaWQgX19pb21lbSAqKSh1aW50
cHRyX3QpKF92YWwpKQ0KPiANCj4gV2h5IGFyZSB5b3UgZG9pbmcgc28gbXVjaCBvZiB0aGlzIHRo
YXQgeW91IG5lZWQgbWFjcm9zIGZvciBpdD8NCj4gDQo+IFVJTlRfVE9fUFRSIHNlZW1zIGxpa2Ug
aXQgY291bGQgYmUgaGlkaW5nIDY0LWJpdC1jbGVhbmxpbmVzcyBidWdzLiAgRnJvbQ0KPiBsb29r
aW5nIGF0IHRoZSBwbGFjZXMgaXQncyB1c2VkLCBpdCBjZXJ0YWlubHkgd291bGQgYmUgaWYgdGhl
IHZhbHVlIGZlZCBpbnRvIGl0DQo+IHdlcmUgYWN0dWFsbHkgInVuc2lnbmVkIGludCIuDQo+IA0K
PiBKdXN0IGRlZmluZSBiYXNlX2FkZHIgYW5kIHN1Y2ggYXMgInZvaWQgX19pb21lbSAqIi4NCj4g
DQoNClVzaW5nIHZvaWQgX19pb21lbSAqIGluc3RlYWQgb2YgdWludHB0cl90LCBubyBuZWVkIGZv
ciB0aGlzIE1hY3JvIGFueW1vcmUuDQoNCj4gPiArI2RlZmluZSBQVFJfTU9WRShfcHRyLCBfb2Zm
c2V0KSAgICAgKHZvaWQgKikoKHVpbnQ4X3QgKikoX3B0cikgKyAoX29mZnNldCkpDQo+IA0KPiBJ
IGRvbid0IHNlZSB0aGlzIHVzZWQgYW55d2hlcmUuICBMaWtld2lzZSBJTl9SQU5HRSBhbmQgSUxM
RUdBTF9CQVNFLg0KPiANCg0KUFRSX01PVkUgd2FzIHVzZWQgaG93ZXZlciBkdXJpbmcgdGhlIHdv
cmsgb24geW91ciBmZWVkYmFjaywgSSByZW1vdmVkIGl0LiANCklOX1JBTkdFIGlzIHVzZWQgdG9v
LCBidXQgSSdsbCByZW1vdmUgaXQgKHVzZWQgZm9yIGV4dHJhIGNoZWNrcyB3aGljaCBhcmUgbm90
IG1hbmRhdG9yeSAodG9vIG11Y2ggQ2F1dGlvdXNuZXNzKSkuDQpJTExFR0FMX0JBU0UgaXMgdXNl
ZCBpbiBmbV9zcC5jLCBJJ2xsIGNvbnNpZGVyIG1vdmluZyBpdCBmcm9tIHRoaXMgZmlsZS4NCg0K
PiAtU2NvdHQNCj4gDQoNCg==

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [v2,5/9] fsl/fman: Add Frame Manager support
  2015-07-02 15:32     ` Liberman Igal
  (?)
@ 2015-07-02 20:17     ` Scott Wood
  -1 siblings, 0 replies; 8+ messages in thread
From: Scott Wood @ 2015-07-02 20:17 UTC (permalink / raw)
  To: Liberman Igal-B31950
  Cc: netdev, linuxppc-dev, Bucur Madalin-Cristian-B32716, pebolle

On Thu, 2015-07-02 at 10:32 -0500, Liberman Igal-B31950 wrote:
> Hi Scott,
> Thank you for your feedback, please take a look at my comments/questions.
> 
> Regards,
> Igal Liberman.
> 
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Friday, June 26, 2015 6:55 AM
> > To: Liberman Igal-B31950
> > Cc: netdev@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; Bucur Madalin-
> > Cristian-B32716; pebolle@tiscali.nl
> > Subject: Re: [v2,5/9] fsl/fman: Add Frame Manager support
> > 
> > On Wed, 2015-06-24 at 22:35 +0300,  igal.liberman@freescale.comwrote:
> > > From: Igal Liberman <Igal.Liberman@freescale.com>
> > > 
> > > Add Frame Manger Driver support.
> > > This patch adds The FMan configuration, initialization and runtime
> > > control routines.
> > > 
> > > Signed-off-by: Igal Liberman <Igal.Liberman@freescale.com>
> > > ---
> > >  drivers/net/ethernet/freescale/fman/Kconfig        |   35 +
> > >  drivers/net/ethernet/freescale/fman/Makefile       |    2 +-
> > >  drivers/net/ethernet/freescale/fman/fm.c           | 1406
> > > ++++++++++++++++++++
> > >  drivers/net/ethernet/freescale/fman/fm.h           |  394 ++++++
> > >  drivers/net/ethernet/freescale/fman/fm_common.h    |  142 ++
> > >  drivers/net/ethernet/freescale/fman/fm_drv.c       |  701 ++++++++++
> > >  drivers/net/ethernet/freescale/fman/fm_drv.h       |  116 ++
> > >  drivers/net/ethernet/freescale/fman/inc/enet_ext.h |  199 +++
> > >  drivers/net/ethernet/freescale/fman/inc/fm_ext.h   |  488 +++++++
> > >  .../net/ethernet/freescale/fman/inc/fsl_fman_drv.h |   99 ++
> > >  drivers/net/ethernet/freescale/fman/inc/service.h  |   55 +
> > >  11 files changed, 3636 insertions(+), 1 deletion(-)  create mode
> > > 100644 drivers/net/ethernet/freescale/fman/fm.c
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/fm.h
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_common.h
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.c
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/fm_drv.h
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/enet_ext.h
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_ext.h
> > >  create mode 100644
> > > drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
> > >  create mode 100644 drivers/net/ethernet/freescale/fman/inc/service.h
> > 
> > Again, please start with something pared down, without extraneous
> > features, but *with* enough functionality to actually pass packets around.
> > Getting this thing into decent shape is going to be hard enough without
> > carrying around the excess baggage.
> > 
> > > diff --git a/drivers/net/ethernet/freescale/fman/Kconfig
> > > b/drivers/net/ethernet/freescale/fman/Kconfig
> > > index 825a0d5..12c75bfd 100644
> > > --- a/drivers/net/ethernet/freescale/fman/Kconfig
> > > +++ b/drivers/net/ethernet/freescale/fman/Kconfig
> > > @@ -7,3 +7,38 @@ config FSL_FMAN
> > >               Freescale Data-Path Acceleration Architecture Frame 
> > > Manager
> > >               (FMan) support
> > > 
> > > +if FSL_FMAN
> > > +
> > > +config FSL_FM_MAX_FRAME_SIZE
> > > +     int "Maximum L2 frame size"
> > > +     range 64 9600
> > > +     default "1522"
> > > +     help
> > > +             Configure this in relation to the maximum possible MTU of 
> > > your
> > > +             network configuration. In particular, one would need to
> > > +             increase this value in order to use jumbo frames.
> > > +             FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS
> > > +             (4 bytes) and one ETH+VLAN header (18 bytes), to a total 
> > > of
> > > +             22 bytes in excess of the desired L3 MTU.
> > > +
> > > +             Note that having too large a FSL_FM_MAX_FRAME_SIZE (much
> > larger
> > > +             than the actual MTU) may lead to buffer exhaustion, 
> > > especially
> > > +             in the case of badly fragmented datagrams on the Rx path.
> > > +             Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than 
> > > the
> > > +             actual MTU will lead to frames being dropped.
> > 
> > Scatter gather can't be used for jumbo frames?
> > 
> 
> Scatter gather is used, it's introduced in dpaa_eth as a separate patch 
> from the basic support.
> The dpaa_eth can work in S/G mode or use large buffers, max frame size 
> sized to reduce S/G overhead (performance vs memory used trade-off).

That's not what the help text says: "In particular, one would need to
increase this value in order to use jumbo frames" and "Conversely, having a 
FSL_FM_MAX_FRAME_SIZE smaller than the actual MTU will lead to frames being 
dropped."

> > Why is this a compile-time option?
> > 
> 
> This is needed for a couple of reasons:
>  - FMan resource sizing - we need to know the maximum frame size we plan to 
> use for determining the Rx FIFO sizes at config time

Why can't the FIFO be resized at runtime?

>  - There are issues when changing the MAC maximum frame size at runtime 
> thus the need to set in HW the maximum allowable and compensate from sw 
> (drop frames above the set MTU).

What are the issues?

In any case, it could at least be a module parameter (i.e. a kernel command 
line argument when not built as a module), rather than a compile-time option.

> > > +
> > > +config FSL_FM_RX_EXTRA_HEADROOM
> > > +     int "Add extra headroom at beginning of data buffers"
> > > +     range 16 384
> > > +     default "64"
> > > +     help
> > > +             Configure this to tell the Frame Manager to reserve some 
> > > extra
> > > +             space at the beginning of a data buffer on the receive 
> > > path,
> > > +             before Internal Context fields are copied. This is in 
> > > addition
> > > +             to the private data area already reserved for driver 
> > > internal
> > > +             use. The provided value must be a multiple of 16.
> > > +
> > > +             This option does not affect in any way the layout of
> > > +             transmitted buffers.
> > 
> > There's nothing here to indicate when a user would want to do this.
> > 
> > Why is this a compile-time option?
> > 
> 
> This allows reserving some more space at the start of the skb and may avoid 
> the need for a skb_realloc_headroom().

That doesn't tell an end-user when they would want to change this.

> > > +     } else {
> > > +             /* Reset the FM if required. */
> > > +             if (p_fm->reset_on_init) {
> > > +                     u32 svr = mfspr(SPRN_SVR);
> > > +
> > > +                     if (((SVR_SOC_VER(svr) == SVR_T4240 &&
> > > +                           SVR_REV(svr) > 0x10)) ||
> > > +                             ((SVR_SOC_VER(svr) == SVR_T4160 &&
> > > +                               SVR_REV(svr) > 0x10)) ||
> > > +                             ((SVR_SOC_VER(svr) == SVR_T4080 &&
> > > +                               SVR_REV(svr) > 0x10)) ||
> > > +                             (SVR_SOC_VER(svr) == SVR_T2080) ||
> > > +                             (SVR_SOC_VER(svr) == SVR_T2081)) {
> > > +                             pr_debug("Hack: No FM reset!\n");
> >                 if (IS_ERR_VALUE(p_fm->cam_offset)) { Why?
> > 
> 
> fm_muram_alloc () can return an offset or an Error.

No, I mean why "Hack: No FM reset!"?


> > > +                             fman_resume(p_fm->p_fm_fpm_regs);
> > > +                             usleep_range(100, 101);
> > > +                     }
> > > +             }
> > > +
> > 
> > Why such a narrow range in usleep_range()?
> > 
> 
> I was looking here: > 
> > Ihttps://www.kernel.org/doc/Documentation/timers/timers-howto.ttn addition, 
> > checkpatch says that usleep_range is preferred over udelay.
> So instead of udelay(100), I used usleep_range(100, 101);
> We can change the range, in your opinion, what is the more appropriate 
> range?
> 

"The larger a range you supply, the greater a chance that you will not 
trigger an interrupt; this should be balanced with what is an acceptable 
upper bound on delay / performance for your specific code path. Exact 
tolerances here are very situation specific, thus it is left to the caller to 
determine a reasonable range."

A spread of only 1us is pretty much useless, and for the shorter delays (e.g. 
10us) just use udelay().

> > > +/* do not change! if changed, must be disabled for rev1 ! */
> > > +#define DFLT_VERIFY_UCODE                 false
> > 
> > I know I complained about this last time...
> > 
> > 
> 
> Leftovers, removed.

Please also check for any leftovers I didn't spot, throughout the patchset.

> 
> > > +
> > > +#define DFLT_DMA_READ_INT_BUF_LOW(dma_thresh_max_buf)        \
> > > +     ((dma_thresh_max_buf + 1) / 2)
> > > +#define DFLT_DMA_READ_INT_BUF_HIGH(dma_thresh_max_buf)       \
> > > +     ((dma_thresh_max_buf + 1) * 3 / 4)
> > > +#define DFLT_DMA_WRITE_INT_BUF_LOW(dma_thresh_max_buf)       \
> > > +     ((dma_thresh_max_buf + 1) / 2)
> > > +#define DFLT_DMA_WRITE_INT_BUF_HIGH(dma_thresh_max_buf)\
> > > +     ((dma_thresh_max_buf + 1) * 3 / 4)
> > > +#define DFLT_DMA_COMM_Q_LOW(major, dma_thresh_max_commq)
> > \
> > > +     ((major == 6) ? 0x2A : ((dma_thresh_max_commq + 1) / 2))
> > > +#define DFLT_DMA_COMM_Q_HIGH(major, dma_thresh_max_commq)
> > \
> > > +     ((major == 6) ? 0x3f : ((dma_thresh_max_commq + 1) * 3 / 4))
> > > +#define DFLT_TOTAL_NUM_OF_TASKS(major, minor,
> > bmi_max_num_of_tasks)  \
> > > +     ((major == 6) ? ((minor == 1 || minor == 4) ? 59 : 124) :       \
> > > +     bmi_max_num_of_tasks)
> > 
> > Where do 0x2a, 0x3f, 59, 124, etc come from?  Please define symbolically.
> > 
> 
> Added defines for the values above.

Please also check the entire patchset for similar magic numbers.

> > > +#define DFLT_TOTAL_FIFO_SIZE(major, minor)                   \
> > > +     ((major == 6) ?                                         \
> > > +     ((minor == 1 || minor == 4) ? (156 * 1024) : (295 * 1024)) :    \
> > > +     (((major == 2) || (major == 5)) ?                       \
> > > +     (100 * 1024) : ((major == 4) ?                  \
> > > +     (46 * 1024) : (122 * 1024))))
> > 
> > This isn't the International Obfuscated C Code Contest.
> > 
> 
> Made it look slightly better.
> Given the large number of HW platforms supported, this selection will look 
> complicated as much as we try to beautify it.
> This code determines the KB of MURAM to use as total FIFO size based on 
> FMan revision.

static inline int fm_default_total_fifo_size(int major, int minor)
{
        switch (major) {
        case 2:
        case 5:
                return 100 * 1024;
        case 4:
                return 46 * 1024;
        case 6:
                if (minor == 1 || minor == 4)
                        return 156 * 1024;
                return 295 * 1024;
        default:
                return 122 * 1024;
        }
}

A comment explaining how these values are chosen and what the relevant 
difference in the FMan versions is, would also be helpful.

> > > 
> > > +/* Memory Mapped Registers */
> > > +
> > > +struct fm_iram_regs_t {
> > > +     uint32_t iadd;  /* FM IRAM instruction address register */
> > > +     uint32_t idata;/* FM IRAM instruction data register */
> > > +     uint32_t itcfg;/* FM IRAM timing config register */
> > > +     uint32_t iready;/* FM IRAM ready register */
> > > +     uint8_t res[0x80000 - 0x10];
> > > +} __attribute__((__packed__));
> > 
> > Why do you need __packed__ on this?
> > 
> 
> As all but the last the member of this memory mapped struct are u32, it's 
> not mandatory but at a certain moment someone considered a good idea to 
> throw in the packed attribute.
> I you prefer to remove it, II can do so.

I prever removing it.

> > Why do you need the padding on the end?     
> 
> Again, it is memory mapped, we don't have other regs after those, so we can 
> drop the padding, I can remove it.
> I you prefer to remove it, II can do so.

Likewise.

> > > 
> > > +/* 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;
> > 
> > If it's configurable via bootargs, why is the kconfig needed?
> > 
> 
> KConfig sets default value, in bootargs you can override.

Why can't the default just be hardcoded, and have only bootargs to override?

> > > +/* Define ASSERT condition */
> > > +#undef ASSERT
> > > +#define ASSERT(x)       WARN_ON(!(x))
> > 
> > Why not just use WARN_ON directly?
> > 
> 
> Mostly personal preference, I've also seen similar constructs used in other 
> drivers.
> One can decide later to change this to BUG_ON() or disable it for debug 
> purposes.

...and with that undef you end up with behavior that might depend on the 
order in which you include headers. :-P

Why is it so important to be able to change it?

-Scott

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-07-02 20:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-24 19:35 [v2,5/9] fsl/fman: Add Frame Manager support igal.liberman
2015-06-25 23:53 ` Paul Bolle
2015-06-26  0:09   ` Paul Bolle
2015-06-26  0:09     ` Paul Bolle
2015-06-26  3:54 ` Scott Wood
2015-07-02 15:32   ` Liberman Igal
2015-07-02 15:32     ` Liberman Igal
2015-07-02 20:17     ` Scott Wood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.