The Freescale Data Path Acceleration Architecture (DPAA)
is a set of hardware components on specific QorIQ multicore
processors. This architecture provides the infrastructure to
support simplified sharing of networking interfaces and
accelerators by multiple CPU cores and the accelerators.
One of the DPAA accelerators is the Frame Manager (FMan)
which contains a series of hardware blocks: ports, Ethernet
MACs, a multi user RAM (MURAM) and Storage Profile (SP).
This patch set introduced the FMan driver code that configures
and initializes the FMan hardware blocks, offering support for
three different types of MACs (DTSEC, TGEC, MEMAC).
The first 6 patches present the FMan Foundation Libraries (FLIBs).
The FMan drivers make use of the basic API the FMan FLib provides
to configure and control the FMan hardware. The remaining patches
present the required FMan hardware module drivers.
The driver structure and a hint on file naming:
--------------------------------
| FMan MAC driver | mac* files
------ ------ ----- ------- ----
| FMan | Port | MAC | MURAM | SP | fm_* files
------ ------ ----- ------- ----
: : FLib : : fman_* files
-------------------
This submission is based on the prior Freescale DPAA FMan V3,RFC
submission. Several issues addresses in this submission:
- Reduced MAC layering and complexity
- Reduced code base
- T1024/T2080 10G best effort support
Igal Liberman (12):
fsl/fman: Add the FMan FLIB headers
fsl/fman: Add the FMan FLIB
fsl/fman: Add the FMan port FLIB headers
fsl/fman: Add the FMan port FLIB
fsl/fman: Add the FMan MAC FLIB headers
fsl/fman: Add the FMan MAC FLIB
fsl/fman: Add FMan MURAM support
fsl/fman: Add Frame Manager support
fsl/fman: Add FMan MAC support
fsl/fman: Add FMan SP support
fsl/fman: Add FMan Port Support
fsl/fman: Add FMan MAC driver
drivers/net/ethernet/freescale/Kconfig | 1 +
drivers/net/ethernet/freescale/Makefile | 2 +
drivers/net/ethernet/freescale/fman/Kconfig | 46 +
drivers/net/ethernet/freescale/fman/Makefile | 12 +
.../ethernet/freescale/fman/flib/common/general.h | 41 +
.../net/ethernet/freescale/fman/flib/fman_common.h | 73 +
.../net/ethernet/freescale/fman/flib/fsl_enet.h | 275 +++
.../net/ethernet/freescale/fman/flib/fsl_fman.h | 609 ++++++
.../ethernet/freescale/fman/flib/fsl_fman_dtsec.h | 791 ++++++++
.../freescale/fman/flib/fsl_fman_dtsec_mii_acc.h | 103 +
.../ethernet/freescale/fman/flib/fsl_fman_memac.h | 453 +++++
.../freescale/fman/flib/fsl_fman_memac_mii_acc.h | 76 +
.../ethernet/freescale/fman/flib/fsl_fman_port.h | 427 ++++
.../net/ethernet/freescale/fman/flib/fsl_fman_sp.h | 54 +
.../ethernet/freescale/fman/flib/fsl_fman_tgec.h | 409 ++++
drivers/net/ethernet/freescale/fman/fm.c | 2036 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/fm.h | 407 ++++
drivers/net/ethernet/freescale/fman/fm_common.h | 576 ++++++
drivers/net/ethernet/freescale/fman/fm_drv.c | 933 +++++++++
drivers/net/ethernet/freescale/fman/fm_drv.h | 125 ++
drivers/net/ethernet/freescale/fman/fm_muram.c | 127 ++
drivers/net/ethernet/freescale/fman/fm_port_drv.c | 496 +++++
drivers/net/ethernet/freescale/fman/fm_sp_common.h | 104 +
drivers/net/ethernet/freescale/fman/fman.c | 973 ++++++++++
.../ethernet/freescale/fman/inc/crc_mac_addr_ext.h | 343 ++++
drivers/net/ethernet/freescale/fman/inc/enet_ext.h | 199 ++
drivers/net/ethernet/freescale/fman/inc/fm_ext.h | 453 +++++
.../net/ethernet/freescale/fman/inc/fm_muram_ext.h | 103 +
.../net/ethernet/freescale/fman/inc/fm_port_ext.h | 376 ++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 195 ++
drivers/net/ethernet/freescale/fman/inc/mac.h | 136 ++
drivers/net/ethernet/freescale/fman/inc/net_ext.h | 534 +++++
drivers/net/ethernet/freescale/fman/inc/service.h | 90 +
drivers/net/ethernet/freescale/fman/mac/Makefile | 8 +
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c | 1089 +++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h | 227 +++
.../ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c | 82 +
.../ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h | 43 +
drivers/net/ethernet/freescale/fman/mac/fm_mac.h | 250 +++
drivers/net/ethernet/freescale/fman/mac/fm_memac.c | 741 +++++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.h | 124 ++
.../ethernet/freescale/fman/mac/fm_memac_mii_acc.c | 66 +
.../ethernet/freescale/fman/mac/fm_memac_mii_acc.h | 50 +
drivers/net/ethernet/freescale/fman/mac/fm_tgec.c | 652 +++++++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.h | 126 ++
.../net/ethernet/freescale/fman/mac/fman_dtsec.c | 571 ++++++
.../freescale/fman/mac/fman_dtsec_mii_acc.c | 168 ++
.../net/ethernet/freescale/fman/mac/fman_memac.c | 365 ++++
.../freescale/fman/mac/fman_memac_mii_acc.c | 217 +++
.../net/ethernet/freescale/fman/mac/fman_tgec.c | 217 +++
drivers/net/ethernet/freescale/fman/mac/mac-api.c | 765 ++++++++
drivers/net/ethernet/freescale/fman/mac/mac.c | 526 +++++
drivers/net/ethernet/freescale/fman/port/Makefile | 3 +
drivers/net/ethernet/freescale/fman/port/fm_port.c | 1435 ++++++++++++++
drivers/net/ethernet/freescale/fman/port/fm_port.h | 527 +++++
.../net/ethernet/freescale/fman/port/fman_port.c | 619 ++++++
drivers/net/ethernet/freescale/fman/sp/Makefile | 3 +
drivers/net/ethernet/freescale/fman/sp/fm_sp.c | 398 ++++
58 files changed, 20850 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/Kconfig
create mode 100644 drivers/net/ethernet/freescale/fman/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/flib/common/general.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fman_common.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h
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/fm_muram.c
create mode 100644 drivers/net/ethernet/freescale/fman/fm_port_drv.c
create mode 100644 drivers/net/ethernet/freescale/fman/fm_sp_common.h
create mode 100644 drivers/net/ethernet/freescale/fman/fman.c
create mode 100644 drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.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/fm_muram_ext.h
create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h
create mode 100644 drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
create mode 100644 drivers/net/ethernet/freescale/fman/inc/mac.h
create mode 100644 drivers/net/ethernet/freescale/fman/inc/net_ext.h
create mode 100644 drivers/net/ethernet/freescale/fman/inc/service.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_mac.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_tgec.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_memac.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_tgec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/mac-api.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/mac.c
create mode 100644 drivers/net/ethernet/freescale/fman/port/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/port/fm_port.c
create mode 100644 drivers/net/ethernet/freescale/fman/port/fm_port.h
create mode 100644 drivers/net/ethernet/freescale/fman/port/fman_port.c
create mode 100644 drivers/net/ethernet/freescale/fman/sp/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/sp/fm_sp.c
--
1.7.11.7
I'm re-sending this as Igal's emails to netdev are not getting through.
Madalin
From: Igal Liberman <[email protected]>
Add Frame Manager Multi-User RAM support.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Kconfig | 1 +
drivers/net/ethernet/freescale/fman/Makefile | 6 +-
drivers/net/ethernet/freescale/fman/fm_muram.c | 127 +++++++++++++++++++++
.../net/ethernet/freescale/fman/inc/fm_muram_ext.h | 103 +++++++++++++++++
4 files changed, 235 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/freescale/fman/fm_muram.c
create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_muram_ext.h
diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig
index af42c3a..825a0d5 100644
--- a/drivers/net/ethernet/freescale/fman/Kconfig
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -1,6 +1,7 @@
config FSL_FMAN
bool "FMan support"
depends on FSL_SOC || COMPILE_TEST
+ select GENERIC_ALLOCATOR
default n
help
Freescale Data-Path Acceleration Architecture Frame Manager
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index 1841b03..55c91bd 100644
--- a/drivers/net/ethernet/freescale/fman/Makefile
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -1,8 +1,10 @@
-subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman/flib
+subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman/flib \
+ -I$(srctree)/drivers/net/ethernet/freescale/fman/inc \
+ -I$(srctree)/drivers/net/ethernet/freescale/fman
obj-y += fsl_fman.o
-fsl_fman-objs := fman.o
+fsl_fman-objs := fman.o fm_muram.o
obj-y += port/
obj-y += mac/
diff --git a/drivers/net/ethernet/freescale/fman/fm_muram.c b/drivers/net/ethernet/freescale/fman/fm_muram.c
new file mode 100644
index 0000000..f62042a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_muram.c
@@ -0,0 +1,127 @@
+/*
+ * 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 MURAM ... */
+#include "fm_muram_ext.h"
+
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/genalloc.h>
+
+struct muram_info {
+ struct gen_pool *pool;
+ void __iomem *vbase;
+ uint64_t size;
+ phys_addr_t pbase;
+};
+
+struct muram_info *fm_muram_init(phys_addr_t base, uint64_t size)
+{
+ struct muram_info *p_muram;
+ void __iomem *vaddr;
+ int ret;
+
+ p_muram = kzalloc(sizeof(*p_muram), GFP_KERNEL);
+ if (!p_muram)
+ return NULL;
+
+ p_muram->pool = gen_pool_create(ilog2(64), -1);
+ if (!p_muram->pool) {
+ pr_err("%s(): MURAM pool create failed\n", __func__);
+ return NULL;
+ }
+
+ vaddr = ioremap(base, size);
+ if (!vaddr) {
+ pr_err("%s(): MURAM ioremap failed\n", __func__);
+ return NULL;
+ }
+
+ ret = gen_pool_add_virt(p_muram->pool, (unsigned long)vaddr,
+ base, size, -1);
+ if (ret < 0) {
+ pr_err("%s(): MURAM pool add failed\n", __func__);
+ iounmap(vaddr);
+ return NULL;
+ }
+
+ memset_io(vaddr, 0, (int)size);
+
+ p_muram->vbase = vaddr;
+ p_muram->pbase = base;
+ return p_muram;
+}
+
+void fm_muram_free(struct muram_info *p_muram)
+{
+ /* Destroy pool */
+ gen_pool_destroy(p_muram->pool);
+ /* Unmap memory */
+ iounmap(p_muram->vbase);
+ /* Free pointer */
+ kfree(p_muram);
+}
+
+unsigned long fm_muram_vbase_to_offset(struct muram_info *p_muram,
+ unsigned long vaddr)
+{
+ return vaddr - (unsigned long)p_muram->vbase;
+}
+
+unsigned long fm_muram_offset_to_vbase(struct muram_info *p_muram,
+ unsigned long offset)
+{
+ return offset + (unsigned long)p_muram->vbase;
+}
+
+int fm_muram_alloc(struct muram_info *p_muram, uint32_t size)
+{
+ unsigned long vaddr;
+
+ vaddr = gen_pool_alloc(p_muram->pool, size);
+ if (!vaddr)
+ return -ENOMEM;
+
+ memset_io((void __iomem *)vaddr, 0, (int)size);
+
+ return fm_muram_vbase_to_offset(p_muram, vaddr);
+}
+
+void fm_muram_free_mem(struct muram_info *p_muram, uint32_t offset,
+ uint32_t size)
+{
+ unsigned long addr = fm_muram_offset_to_vbase(p_muram, offset);
+
+ gen_pool_free(p_muram->pool, addr, size);
+}
+
diff --git a/drivers/net/ethernet/freescale/fman/inc/fm_muram_ext.h b/drivers/net/ethernet/freescale/fman/inc/fm_muram_ext.h
new file mode 100644
index 0000000..bc25764
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_muram_ext.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/* File fm_muram_ext.h
+ * Description FM MURAM Application Programming Interface.
+ */
+#ifndef __FM_MURAM_EXT
+#define __FM_MURAM_EXT
+
+#include "linux/types.h"
+
+#define FM_MURAM_INVALID_ALLOCATION -1
+
+/* Structure for FM MURAM information */
+struct muram_info;
+
+/* FM MURAM initialization API functions, definitions and enums */
+
+/* Function fm_muram_init
+ * Description Creates partition in the MURAM.
+ * The routine returns a pointer to the MURAM partition.
+ * This pointer must be passed as first parameter to all other
+ * FM-MURAM function calls.
+ * No actual initialization or configuration of FM_MURAM hardware
+ * is done by this routine.
+ * Param[in] base - Pointer to base of memory mapped FM-MURAM.
+ * Param[in] size - Size of the FM-MURAM partition.
+ * Return pointer to FM-MURAM object, or NULL for Failure.
+ */
+struct muram_info *fm_muram_init(phys_addr_t base, uint64_t size);
+
+/* Function fm_muram_free
+ * Description Frees all resources that were assigned to FM-MURAM module.
+ * Calling this routine invalidates the pointer.
+ * Param[in] p_muram - FM-MURAM module pointer.
+ */
+void fm_muram_free(struct muram_info *p_muram);
+
+/* Function fm_muram_vbase_to_offset
+ * Description gives the offset of the memory region in the MURAM
+ * Param[in] p_muram - FM-MURAM module pointer.
+ * Param[in] vaddr - the virtual address of the memoru block
+ * Return the offset of the memory block
+ */
+unsigned long fm_muram_vbase_to_offset(struct muram_info *p_muram,
+ unsigned long vaddr);
+
+/* Function fm_muram_vbase_to_offset
+ * Description gives the address of the memory region from specific oddset
+ * Param[in] p_muram - FM-MURAM module pointer.
+ * Param[in] offset - the offset of the memory block
+ * Return the address of the memory blocl
+ */
+unsigned long fm_muram_offset_to_vbase(struct muram_info *p_muram,
+ unsigned long offset);
+
+/* Function fm_muram_alloc
+ * Description Allocate some memory from FM-MURAM partition.
+ * Param[in] p_muram - FM-MURAM module pointer.
+ * Param[in] size - size of the memory to be allocated.
+ * Return address of the allocated memory; NULL otherwise.
+ */
+int fm_muram_alloc(struct muram_info *p_muram, uint32_t size);
+
+/* Function fm_muram_free_mem
+ * Description Free an allocated memory from FM-MURAM partition.
+ * Param[in] p_muram - FM-MURAM module pointer.
+ * Param[in] offset - offset of the memory region to be freed.
+ * Param[in] size - size of the memory to be freed.
+ */
+void fm_muram_free_mem(struct muram_info *p_muram, uint32_t offset,
+ uint32_t size);
+
+#endif /* __FM_MURAM_EXT */
--
1.7.11.7
From: Igal Liberman <[email protected]>
This patch presents the FMan Foundation Libraries (FLIB) headers.
The FMan FLib provides the basic API used by the FMan drivers to
configure and control the FMan hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
.../ethernet/freescale/fman/flib/common/general.h | 41 ++
.../net/ethernet/freescale/fman/flib/fsl_fman.h | 609 +++++++++++++++++++++
2 files changed, 650 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/flib/common/general.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
diff --git a/drivers/net/ethernet/freescale/fman/flib/common/general.h b/drivers/net/ethernet/freescale/fman/flib/common/general.h
new file mode 100644
index 0000000..0501f01
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/common/general.h
@@ -0,0 +1,41 @@
+/*
+ * 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 __GENERAL_H
+#define __GENERAL_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define iowrite32be(val, addr) out_be32(&(*addr), val)
+#define ioread32be(addr) in_be32(&(*addr))
+
+#endif /* __GENERAL_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
new file mode 100644
index 0000000..95eef30
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
@@ -0,0 +1,609 @@
+/*
+ * 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_H
+#define __FSL_FMAN_H
+
+#include "common/general.h"
+#include <linux/delay.h>
+
+typedef struct fm_prs_result_t fm_prs_result;
+typedef enum e_enet_mode enet_mode_t;
+
+struct fman_revision_info {
+ uint8_t major_rev; /* Major revision */
+ uint8_t minor_rev; /* Minor revision */
+};
+
+/* sizes */
+#define OFFSET_UNITS 16
+#define MAX_INT_OFFSET 240
+#define MAX_IC_SIZE 256
+#define MAX_EXT_OFFSET 496
+#define MAX_EXT_BUFFER_OFFSET 511
+
+/* Memory Mapped Registers */
+#define FMAN_LIODN_TBL 64 /* size of LIODN table */
+
+struct fman_fpm_regs {
+ uint32_t fmfp_tnc; /* FPM TNUM Control 0x00 */
+ uint32_t fmfp_prc; /* FPM Port_ID FmCtl Association 0x04 */
+ uint32_t fmfp_brkc; /* FPM Breakpoint Control 0x08 */
+ uint32_t fmfp_mxd; /* FPM Flush Control 0x0c */
+ uint32_t fmfp_dist1; /* FPM Dispatch Thresholds1 0x10 */
+ uint32_t fmfp_dist2; /* FPM Dispatch Thresholds2 0x14 */
+ uint32_t fm_epi; /* FM Error Pending Interrupts 0x18 */
+ uint32_t fm_rie; /* FM Error Interrupt Enable 0x1c */
+ uint32_t fmfp_fcev[4]; /* FPM FMan-Controller Event 1-4 0x20-0x2f */
+ uint32_t res0030[4]; /* res 0x30 - 0x3f */
+ uint32_t fmfp_cee[4]; /* PM FMan-Controller Event 1-4 0x40-0x4f */
+ uint32_t res0050[4]; /* res 0x50-0x5f */
+ uint32_t fmfp_tsc1; /* FPM TimeStamp Control1 0x60 */
+ uint32_t fmfp_tsc2; /* FPM TimeStamp Control2 0x64 */
+ uint32_t fmfp_tsp; /* FPM Time Stamp 0x68 */
+ uint32_t fmfp_tsf; /* FPM Time Stamp Fraction 0x6c */
+ uint32_t fm_rcr; /* FM Rams Control 0x70 */
+ uint32_t fmfp_extc; /* FPM External Requests Control 0x74 */
+ uint32_t fmfp_ext1; /* FPM External Requests Config1 0x78 */
+ uint32_t fmfp_ext2; /* FPM External Requests Config2 0x7c */
+ uint32_t fmfp_drd[16]; /* FPM Data_Ram Data 0-15 0x80 - 0xbf */
+ uint32_t fmfp_dra; /* FPM Data Ram Access 0xc0 */
+ uint32_t fm_ip_rev_1; /* FM IP Block Revision 1 0xc4 */
+ uint32_t fm_ip_rev_2; /* FM IP Block Revision 2 0xc8 */
+ uint32_t fm_rstc; /* FM Reset Command 0xcc */
+ uint32_t fm_cld; /* FM Classifier Debug 0xd0 */
+ uint32_t fm_npi; /* FM Normal Pending Interrupts 0xd4 */
+ uint32_t fmfp_exte; /* FPM External Requests Enable 0xd8 */
+ uint32_t fmfp_ee; /* FPM Event&Mask 0xdc */
+ uint32_t fmfp_cev[4]; /* FPM CPU Event 1-4 0xe0-0xef */
+ uint32_t res00f0[4]; /* res 0xf0-0xff */
+ uint32_t fmfp_ps[50]; /* FPM Port Status 0x100-0x1c7 */
+ uint32_t res01c8[14]; /* res 0x1c8-0x1ff */
+ uint32_t fmfp_clfabc; /* FPM CLFABC 0x200 */
+ uint32_t fmfp_clfcc; /* FPM CLFCC 0x204 */
+ uint32_t fmfp_clfaval; /* FPM CLFAVAL 0x208 */
+ uint32_t fmfp_clfbval; /* FPM CLFBVAL 0x20c */
+ uint32_t fmfp_clfcval; /* FPM CLFCVAL 0x210 */
+ uint32_t fmfp_clfamsk; /* FPM CLFAMSK 0x214 */
+ uint32_t fmfp_clfbmsk; /* FPM CLFBMSK 0x218 */
+ uint32_t fmfp_clfcmsk; /* FPM CLFCMSK 0x21c */
+ uint32_t fmfp_clfamc; /* FPM CLFAMC 0x220 */
+ uint32_t fmfp_clfbmc; /* FPM CLFBMC 0x224 */
+ uint32_t fmfp_clfcmc; /* FPM CLFCMC 0x228 */
+ uint32_t fmfp_decceh; /* FPM DECCEH 0x22c */
+ uint32_t res0230[116]; /* res 0x230 - 0x3ff */
+ uint32_t fmfp_ts[128]; /* 0x400: FPM Task Status 0x400 - 0x5ff */
+ uint32_t res0600[0x400 - 384];
+};
+
+struct fman_bmi_regs {
+ uint32_t fmbm_init; /* BMI Initialization 0x00 */
+ uint32_t fmbm_cfg1; /* BMI Configuration 1 0x04 */
+ uint32_t fmbm_cfg2; /* BMI Configuration 2 0x08 */
+ uint32_t res000c[5]; /* 0x0c - 0x1f */
+ uint32_t fmbm_ievr; /* Interrupt Event Register 0x20 */
+ uint32_t fmbm_ier; /* Interrupt Enable Register 0x24 */
+ uint32_t fmbm_ifr; /* Interrupt Force Register 0x28 */
+ uint32_t res002c[5]; /* 0x2c - 0x3f */
+ uint32_t fmbm_arb[8]; /* BMI Arbitration 0x40 - 0x5f */
+ uint32_t res0060[12]; /*0x60 - 0x8f */
+ uint32_t fmbm_dtc[3]; /* Debug Trap Counter 0x90 - 0x9b */
+ uint32_t res009c; /* 0x9c */
+ uint32_t fmbm_dcv[3][4]; /* Debug Compare val 0xa0-0xcf */
+ uint32_t fmbm_dcm[3][4]; /* Debug Compare Mask 0xd0-0xff */
+ uint32_t fmbm_gde; /* BMI Global Debug Enable 0x100 */
+ uint32_t fmbm_pp[63]; /* BMI Port Parameters 0x104 - 0x1ff */
+ uint32_t res0200; /* 0x200 */
+ uint32_t fmbm_pfs[63]; /* BMI Port FIFO Size 0x204 - 0x2ff */
+ uint32_t res0300; /* 0x300 */
+ uint32_t fmbm_spliodn[63]; /* Port Partition ID 0x304 - 0x3ff */
+};
+
+struct fman_qmi_regs {
+ uint32_t fmqm_gc; /* General Configuration Register 0x00 */
+ uint32_t res0004; /* 0x04 */
+ uint32_t fmqm_eie; /* Error Interrupt Event Register 0x08 */
+ uint32_t fmqm_eien; /* Error Interrupt Enable Register 0x0c */
+ uint32_t fmqm_eif; /* Error Interrupt Force Register 0x10 */
+ uint32_t fmqm_ie; /* Interrupt Event Register 0x14 */
+ uint32_t fmqm_ien; /* Interrupt Enable Register 0x18 */
+ uint32_t fmqm_if; /* Interrupt Force Register 0x1c */
+ uint32_t fmqm_gs; /* Global Status Register 0x20 */
+ uint32_t fmqm_ts; /* Task Status Register 0x24 */
+ uint32_t fmqm_etfc; /* Enqueue Total Frame Counter 0x28 */
+ uint32_t fmqm_dtfc; /* Dequeue Total Frame Counter 0x2c */
+ uint32_t fmqm_dc0; /* Dequeue Counter 0 0x30 */
+ uint32_t fmqm_dc1; /* Dequeue Counter 1 0x34 */
+ uint32_t fmqm_dc2; /* Dequeue Counter 2 0x38 */
+ uint32_t fmqm_dc3; /* Dequeue Counter 3 0x3c */
+ uint32_t fmqm_dfdc; /* Dequeue FQID from Default Counter 0x40 */
+ uint32_t fmqm_dfcc; /* Dequeue FQID from Context Counter 0x44 */
+ uint32_t fmqm_dffc; /* Dequeue FQID from FD Counter 0x48 */
+ uint32_t fmqm_dcc; /* Dequeue Confirm Counter 0x4c */
+ uint32_t res0050[7]; /* 0x50 - 0x6b */
+ uint32_t fmqm_tapc; /* Tnum Aging Period Control 0x6c */
+ uint32_t fmqm_dmcvc; /* Dequeue MAC Command Valid Counter 0x70 */
+ uint32_t fmqm_difdcc; /* Dequeue Invalid FD Command Counter 0x74 */
+ uint32_t fmqm_da1v; /* Dequeue A1 Valid Counter 0x78 */
+ uint32_t res007c; /* 0x7c */
+ uint32_t fmqm_dtc; /* 0x80 Debug Trap Counter 0x80 */
+ uint32_t fmqm_efddd; /* 0x84 Enqueue Frame desc Dynamic dbg 0x84 */
+ uint32_t res0088[2]; /* 0x88 - 0x8f */
+ struct {
+ uint32_t fmqm_dtcfg1; /* 0x90 dbg trap cfg 1 Register 0x00 */
+ uint32_t fmqm_dtval1; /* Debug Trap Value 1 Register 0x04 */
+ uint32_t fmqm_dtm1; /* Debug Trap Mask 1 Register 0x08 */
+ uint32_t fmqm_dtc1; /* Debug Trap Counter 1 Register 0x0c */
+ uint32_t fmqm_dtcfg2; /* dbg Trap cfg 2 Register 0x10 */
+ uint32_t fmqm_dtval2; /* Debug Trap Value 2 Register 0x14 */
+ uint32_t fmqm_dtm2; /* Debug Trap Mask 2 Register 0x18 */
+ uint32_t res001c; /* 0x1c */
+ } dbg_traps[3]; /* 0x90 - 0xef */
+ uint8_t res00f0[0x400 - 0xf0]; /* 0xf0 - 0x3ff */
+};
+
+struct fman_dma_regs {
+ uint32_t fmdmsr; /* FM DMA status register 0x00 */
+ uint32_t fmdmmr; /* FM DMA mode register 0x04 */
+ uint32_t fmdmtr; /* FM DMA bus threshold register 0x08 */
+ uint32_t fmdmhy; /* FM DMA bus hysteresis register 0x0c */
+ uint32_t fmdmsetr; /* FM DMA SOS emergency Threshold Register 0x10 */
+ uint32_t fmdmtah; /* FM DMA transfer bus address high reg 0x14 */
+ uint32_t fmdmtal; /* FM DMA transfer bus address low reg 0x18 */
+ uint32_t fmdmtcid; /* FM DMA transfer bus communication ID reg 0x1c */
+ uint32_t fmdmra; /* FM DMA bus internal ram address register 0x20 */
+ uint32_t fmdmrd; /* FM DMA bus internal ram data register 0x24 */
+ uint32_t fmdmwcr; /* FM DMA CAM watchdog counter value 0x28 */
+ uint32_t fmdmebcr; /* FM DMA CAM base in MURAM register 0x2c */
+ uint32_t fmdmccqdr; /* FM DMA CAM and CMD Queue Debug reg 0x30 */
+ uint32_t fmdmccqvr1; /* FM DMA CAM and CMD Queue Value reg #1 0x34 */
+ uint32_t fmdmccqvr2; /* FM DMA CAM and CMD Queue Value reg #2 0x38 */
+ uint32_t fmdmcqvr3; /* FM DMA CMD Queue Value register #3 0x3c */
+ uint32_t fmdmcqvr4; /* FM DMA CMD Queue Value register #4 0x40 */
+ uint32_t fmdmcqvr5; /* FM DMA CMD Queue Value register #5 0x44 */
+ uint32_t fmdmsefrc; /* FM DMA Semaphore Entry Full Reject Cntr 0x48 */
+ uint32_t fmdmsqfrc; /* FM DMA Semaphore Queue Full Reject Cntr 0x4c */
+ uint32_t fmdmssrc; /* FM DMA Semaphore SYNC Reject Counter 0x50 */
+ uint32_t fmdmdcr; /* FM DMA Debug Counter 0x54 */
+ uint32_t fmdmemsr; /* FM DMA Emergency Smoother Register 0x58 */
+ uint32_t res005c; /* 0x5c */
+ uint32_t fmdmplr[FMAN_LIODN_TBL / 2]; /* DMA LIODN regs 0x60-0xdf */
+ uint32_t res00e0[0x400 - 56];
+};
+
+struct fman_rg {
+ struct fman_fpm_regs __iomem *fpm_rg;
+ struct fman_dma_regs __iomem *dma_rg;
+ struct fman_bmi_regs __iomem *bmi_rg;
+ struct fman_qmi_regs __iomem *qmi_rg;
+};
+
+enum fman_dma_cache_override {
+ E_FMAN_DMA_NO_CACHE_OR = 0, /* No override of the Cache field */
+ E_FMAN_DMA_NO_STASH_DATA, /* No data stashing in system level cache */
+ E_FMAN_DMA_MAY_STASH_DATA, /* Stashing allowed in sys level cache */
+ E_FMAN_DMA_STASH_DATA /* Stashing performed in system level cache */
+};
+
+enum fman_dma_aid_mode {
+ E_FMAN_DMA_AID_OUT_PORT_ID = 0, /* 4 LSB of PORT_ID */
+ E_FMAN_DMA_AID_OUT_TNUM /* 4 LSB of TNUM */
+};
+
+enum fman_dma_dbg_cnt_mode {
+ E_FMAN_DMA_DBG_NO_CNT = 0, /* No counting */
+ E_FMAN_DMA_DBG_CNT_DONE, /* Count DONE commands */
+ E_FMAN_DMA_DBG_CNT_COMM_Q_EM, /* command Q emergency signal */
+ E_FMAN_DMA_DBG_CNT_INT_READ_EM, /* Read buf emergency signal */
+ E_FMAN_DMA_DBG_CNT_INT_WRITE_EM, /* Write buf emergency signal */
+ E_FMAN_DMA_DBG_CNT_FPM_WAIT, /* FPM WAIT signal */
+ E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC, /* Single bit ECC errors */
+ E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT /* RAW&WAR protection counter */
+};
+
+enum fman_dma_emergency_level {
+ E_FMAN_DMA_EM_EBS = 0, /* EBS emergency */
+ E_FMAN_DMA_EM_SOS /* SOS emergency */
+};
+
+enum fman_catastrophic_err {
+ E_FMAN_CATAST_ERR_STALL_PORT = 0, /* Port_ID stalled reset required */
+ E_FMAN_CATAST_ERR_STALL_TASK /* Only erroneous task is stalled */
+};
+
+enum fman_dma_err {
+ E_FMAN_DMA_ERR_CATASTROPHIC = 0, /* Catastrophic DMA error */
+ E_FMAN_DMA_ERR_REPORT /* Reported DMA error */
+};
+
+struct fman_cfg {
+ uint8_t disp_limit_tsh;
+ uint8_t prs_disp_tsh;
+ uint8_t plcr_disp_tsh;
+ uint8_t kg_disp_tsh;
+ uint8_t bmi_disp_tsh;
+ uint8_t qmi_enq_disp_tsh;
+ uint8_t qmi_deq_disp_tsh;
+ uint8_t fm_ctl1_disp_tsh;
+ uint8_t fm_ctl2_disp_tsh;
+ enum fman_dma_cache_override dma_cache_override;
+ enum fman_dma_aid_mode dma_aid_mode;
+ bool dma_aid_override;
+ uint8_t dma_axi_dbg_num_of_beats;
+ uint8_t dma_cam_num_of_entries;
+ uint32_t dma_watchdog;
+ uint8_t dma_comm_qtsh_asrt_emer;
+ uint8_t dma_write_buf_tsh_asrt_emer;
+ uint8_t dma_read_buf_tsh_asrt_emer;
+ uint8_t dma_comm_qtsh_clr_emer;
+ uint8_t dma_write_buf_tsh_clr_emer;
+ uint8_t dma_read_buf_tsh_clr_emer;
+ uint32_t dma_sos_emergency;
+ enum fman_dma_dbg_cnt_mode dma_dbg_cnt_mode;
+ bool dma_stop_on_bus_error;
+ bool dma_en_emergency;
+ uint32_t dma_emergency_bus_select;
+ enum fman_dma_emergency_level dma_emergency_level;
+ bool dma_en_emergency_smoother;
+ uint32_t dma_emergency_switch_counter;
+ bool halt_on_external_activ;
+ bool halt_on_unrecov_ecc_err;
+ enum fman_catastrophic_err catastrophic_err;
+ enum fman_dma_err dma_err;
+ bool en_muram_test_mode;
+ bool en_iram_test_mode;
+ bool external_ecc_rams_enable;
+ uint16_t tnum_aging_period;
+ uint32_t exceptions;
+ uint16_t clk_freq;
+ bool pedantic_dma;
+ uint32_t cam_base_addr;
+ uint32_t fifo_base_addr;
+ uint32_t total_fifo_size;
+ uint8_t total_num_of_tasks;
+ bool qmi_deq_option_support;
+ uint32_t qmi_def_tnums_thresh;
+ uint8_t num_of_fman_ctrl_evnt_regs;
+};
+
+/* Exceptions */
+#define FMAN_EX_DMA_BUS_ERROR 0x80000000
+#define FMAN_EX_DMA_READ_ECC 0x40000000
+#define FMAN_EX_DMA_SYSTEM_WRITE_ECC 0x20000000
+#define FMAN_EX_DMA_FM_WRITE_ECC 0x10000000
+#define FMAN_EX_FPM_STALL_ON_TASKS 0x08000000
+#define FMAN_EX_FPM_SINGLE_ECC 0x04000000
+#define FMAN_EX_FPM_DOUBLE_ECC 0x02000000
+#define FMAN_EX_QMI_SINGLE_ECC 0x01000000
+#define FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000
+#define FMAN_EX_QMI_DOUBLE_ECC 0x00400000
+#define FMAN_EX_BMI_LIST_RAM_ECC 0x00200000
+#define FMAN_EX_BMI_PIPELINE_ECC 0x00100000
+#define FMAN_EX_BMI_STATISTICS_RAM_ECC 0x00080000
+#define FMAN_EX_IRAM_ECC 0x00040000
+#define FMAN_EX_NURAM_ECC 0x00020000
+#define FMAN_EX_BMI_DISPATCH_RAM_ECC 0x00010000
+
+enum fman_exceptions {
+ E_FMAN_EX_DMA_BUS_ERROR = 0, /* DMA bus error. */
+ E_FMAN_EX_DMA_READ_ECC, /* Read Buffer ECC error */
+ E_FMAN_EX_DMA_SYSTEM_WRITE_ECC, /* Write Buffer ECC err on sys side */
+ E_FMAN_EX_DMA_FM_WRITE_ECC, /* Write Buffer ECC error on FM side */
+ E_FMAN_EX_FPM_STALL_ON_TASKS, /* Stall of tasks on FPM */
+ E_FMAN_EX_FPM_SINGLE_ECC, /* Single ECC on FPM. */
+ E_FMAN_EX_FPM_DOUBLE_ECC, /* Double ECC error on FPM ram access */
+ E_FMAN_EX_QMI_SINGLE_ECC, /* Single ECC on QMI. */
+ E_FMAN_EX_QMI_DOUBLE_ECC, /* Double bit ECC occurred on QMI */
+ E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/* DeQ from unknown port id */
+ E_FMAN_EX_BMI_LIST_RAM_ECC, /* Linked List RAM ECC error */
+ E_FMAN_EX_BMI_STORAGE_PROFILE_ECC, /* storage profile */
+ E_FMAN_EX_BMI_STATISTICS_RAM_ECC, /* Statistics RAM ECC Err Enable */
+ E_FMAN_EX_BMI_DISPATCH_RAM_ECC, /* Dispatch RAM ECC Error Enable */
+ E_FMAN_EX_IRAM_ECC, /* Double bit ECC occurred on IRAM*/
+ E_FMAN_EX_MURAM_ECC /* Double bit ECC occurred on MURAM*/
+};
+
+#define FPM_PRT_FM_CTL1 0x00000001
+#define FPM_PRT_FM_CTL2 0x00000002
+
+/* DMA definitions */
+
+/* masks */
+#define DMA_MODE_AID_OR 0x20000000
+#define DMA_MODE_SBER 0x10000000
+#define DMA_MODE_BER 0x00200000
+#define DMA_MODE_ECC 0x00000020
+#define DMA_MODE_SECURE_PROT 0x00000800
+#define DMA_MODE_EMER_READ 0x00080000
+#define DMA_MODE_AXI_DBG_MASK 0x0F000000
+
+#define DMA_TRANSFER_PORTID_MASK 0xFF000000
+#define DMA_TRANSFER_TNUM_MASK 0x00FF0000
+#define DMA_TRANSFER_LIODN_MASK 0x00000FFF
+
+#define DMA_STATUS_BUS_ERR 0x08000000
+#define DMA_STATUS_READ_ECC 0x04000000
+#define DMA_STATUS_SYSTEM_WRITE_ECC 0x02000000
+#define DMA_STATUS_FM_WRITE_ECC 0x01000000
+#define DMA_STATUS_FM_SPDAT_ECC 0x00080000
+
+#define FM_LIODN_BASE_MASK 0x00000FFF
+
+/* shifts */
+#define DMA_MODE_CACHE_OR_SHIFT 30
+#define DMA_MODE_AXI_DBG_SHIFT 24
+#define DMA_MODE_CEN_SHIFT 13
+#define DMA_MODE_DBG_SHIFT 7
+#define DMA_MODE_EMER_LVL_SHIFT 6
+#define DMA_MODE_AID_MODE_SHIFT 4
+#define DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS 16
+
+#define DMA_THRESH_COMMQ_SHIFT 24
+#define DMA_THRESH_READ_INT_BUF_SHIFT 16
+
+#define DMA_LIODN_SHIFT 16
+
+#define DMA_TRANSFER_PORTID_SHIFT 24
+#define DMA_TRANSFER_TNUM_SHIFT 16
+
+/* sizes */
+#define DMA_MAX_WATCHDOG 0xffffffff
+
+/* others */
+#define DMA_CAM_SIZEOF_ENTRY 0x40
+#define DMA_CAM_ALIGN 0x40
+#define DMA_CAM_UNITS 8
+
+/* General defines */
+#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL
+
+/* FPM defines */
+
+/* masks */
+#define FPM_EV_MASK_DOUBLE_ECC 0x80000000
+#define FPM_EV_MASK_STALL 0x40000000
+#define FPM_EV_MASK_SINGLE_ECC 0x20000000
+#define FPM_EV_MASK_RELEASE_FM 0x00010000
+#define FPM_EV_MASK_DOUBLE_ECC_EN 0x00008000
+#define FPM_EV_MASK_STALL_EN 0x00004000
+#define FPM_EV_MASK_SINGLE_ECC_EN 0x00002000
+#define FPM_EV_MASK_EXTERNAL_HALT 0x00000008
+#define FPM_EV_MASK_ECC_ERR_HALT 0x00000004
+
+#define FPM_RAM_RAMS_ECC_EN 0x80000000
+#define FPM_RAM_IRAM_ECC_EN 0x40000000
+#define FPM_RAM_MURAM_ECC 0x00008000
+#define FPM_RAM_IRAM_ECC 0x00004000
+#define FPM_RAM_MURAM_TEST_ECC 0x20000000
+#define FPM_RAM_IRAM_TEST_ECC 0x10000000
+#define FPM_RAM_RAMS_ECC_EN_SRC_SEL 0x08000000
+
+#define FPM_IRAM_ECC_ERR_EX_EN 0x00020000
+#define FPM_MURAM_ECC_ERR_EX_EN 0x00040000
+
+#define FPM_REV1_MAJOR_MASK 0x0000FF00
+#define FPM_REV1_MINOR_MASK 0x000000FF
+
+#define FPM_TS_CTL_EN 0x80000000
+
+#define FPM_RSTC_FM_RESET 0x80000000
+
+/* shifts */
+#define FPM_DISP_LIMIT_SHIFT 24
+
+#define FPM_THR1_PRS_SHIFT 24
+#define FPM_THR1_KG_SHIFT 16
+#define FPM_THR1_PLCR_SHIFT 8
+#define FPM_THR1_BMI_SHIFT 0
+
+#define FPM_THR2_QMI_ENQ_SHIFT 24
+#define FPM_THR2_QMI_DEQ_SHIFT 0
+#define FPM_THR2_FM_CTL1_SHIFT 16
+#define FPM_THR2_FM_CTL2_SHIFT 8
+
+#define FPM_EV_MASK_CAT_ERR_SHIFT 1
+#define FPM_EV_MASK_DMA_ERR_SHIFT 0
+
+#define FPM_REV1_MAJOR_SHIFT 8
+#define FPM_REV1_MINOR_SHIFT 0
+
+#define FPM_TS_INT_SHIFT 16
+
+#define FPM_PORT_FM_CTL_PORTID_SHIFT 24
+
+#define FPM_PRC_ORA_FM_CTL_SEL_SHIFT 16
+
+/* others */
+#define FPM_MAX_DISP_LIMIT 31
+#define FPM_RSTC_FM_RESET 0x80000000
+#define FPM_RSTC_MAC0_RESET 0x40000000
+#define FPM_RSTC_MAC1_RESET 0x20000000
+#define FPM_RSTC_MAC2_RESET 0x10000000
+#define FPM_RSTC_MAC3_RESET 0x08000000
+#define FPM_RSTC_MAC8_RESET 0x04000000
+#define FPM_RSTC_MAC4_RESET 0x02000000
+#define FPM_RSTC_MAC5_RESET 0x01000000
+#define FPM_RSTC_MAC6_RESET 0x00800000
+#define FPM_RSTC_MAC7_RESET 0x00400000
+#define FPM_RSTC_MAC9_RESET 0x00200000
+/* BMI defines */
+/* masks */
+#define BMI_INIT_START 0x80000000
+#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000
+#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000
+#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000
+#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000
+#define BMI_NUM_OF_TASKS_MASK 0x3F000000
+#define BMI_NUM_OF_EXTRA_TASKS_MASK 0x000F0000
+#define BMI_NUM_OF_DMAS_MASK 0x00000F00
+#define BMI_NUM_OF_EXTRA_DMAS_MASK 0x0000000F
+#define BMI_FIFO_SIZE_MASK 0x000003FF
+#define BMI_EXTRA_FIFO_SIZE_MASK 0x03FF0000
+#define BMI_CFG2_DMAS_MASK 0x0000003F
+
+/* shifts */
+#define BMI_CFG2_TASKS_SHIFT 16
+#define BMI_CFG2_DMAS_SHIFT 0
+#define BMI_CFG1_FIFO_SIZE_SHIFT 16
+#define BMI_EXTRA_FIFO_SIZE_SHIFT 16
+#define BMI_NUM_OF_TASKS_SHIFT 24
+#define BMI_EXTRA_NUM_OF_TASKS_SHIFT 16
+#define BMI_NUM_OF_DMAS_SHIFT 8
+#define BMI_EXTRA_NUM_OF_DMAS_SHIFT 0
+
+/* others */
+#define BMI_FIFO_ALIGN 0x100
+#define FMAN_BMI_FIFO_UNITS 0x100
+
+/* QMI defines */
+/* masks */
+#define QMI_CFG_ENQ_EN 0x80000000
+#define QMI_CFG_DEQ_EN 0x40000000
+#define QMI_CFG_EN_COUNTERS 0x10000000
+#define QMI_CFG_DEQ_MASK 0x0000003F
+#define QMI_CFG_ENQ_MASK 0x00003F00
+
+#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000
+#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000
+#define QMI_INTR_EN_SINGLE_ECC 0x80000000
+
+/* shifts */
+#define QMI_TAPC_TAP 22
+
+#define QMI_GS_HALT_NOT_BUSY 0x00000002
+
+/* IRAM defines */
+/* masks */
+#define IRAM_IADD_AIE 0x80000000
+#define IRAM_READY 0x80000000
+
+uint32_t fman_get_bmi_err_event(struct fman_bmi_regs __iomem *bmi_rg);
+uint32_t fman_get_qmi_err_event(struct fman_qmi_regs __iomem *qmi_rg);
+uint32_t fman_get_dma_com_id(struct fman_dma_regs __iomem *dma_rg);
+uint64_t fman_get_dma_addr(struct fman_dma_regs __iomem *dma_rg);
+uint32_t fman_get_dma_err_event(struct fman_dma_regs __iomem *dma_rg);
+uint32_t fman_get_fpm_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+uint32_t fman_get_muram_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+uint32_t fman_get_iram_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+uint32_t fman_get_qmi_event(struct fman_qmi_regs __iomem *qmi_rg);
+uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs __iomem *fpm_rg);
+uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg);
+uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg);
+uint16_t fman_get_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_of_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id);
+uint32_t fman_get_normal_pending(struct fman_fpm_regs __iomem *fpm_rg);
+uint32_t fman_get_controller_event(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t reg_id);
+uint32_t fman_get_error_pending(struct fman_fpm_regs __iomem *fpm_rg);
+void fman_get_revision(struct fman_fpm_regs __iomem *fpm_rg, uint8_t *major,
+ uint8_t *minor);
+
+int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs __iomem *fpm_rg);
+void fman_set_order_restoration_per_port(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t port_id, bool is_rx_port);
+void fman_set_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg, uint8_t val);
+void fman_set_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg, uint8_t val);
+void fman_set_liodn_per_port(struct fman_rg *fman_rg,
+ uint8_t port_id,
+ uint16_t liodn_base, uint16_t liodn_offset);
+void fman_set_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id,
+ uint32_t size_of_fifo, uint32_t extra_size_of_fifo);
+void fman_set_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_of_tasks, uint8_t num_of_extra_tasks);
+void fman_set_num_of_open_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_of_open_dmas,
+ uint8_t num_of_extra_open_dmas,
+ uint8_t total_num_of_dmas);
+int fman_set_exception(struct fman_rg *fman_rg,
+ enum fman_exceptions exception, bool enable);
+
+void fman_defconfig(struct fman_cfg *cfg);
+int fman_fpm_init(struct fman_fpm_regs __iomem *fpm_rg, struct fman_cfg *cfg);
+int fman_bmi_init(struct fman_bmi_regs __iomem *bmi_rg, struct fman_cfg *cfg);
+int fman_qmi_init(struct fman_qmi_regs __iomem *qmi_rg, struct fman_cfg *cfg);
+int fman_dma_init(struct fman_dma_regs __iomem *dma_rg, struct fman_cfg *cfg);
+void fman_free_resources(struct fman_rg *fman_rg);
+int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg);
+void fman_resume(struct fman_fpm_regs __iomem *fpm_rg);
+
+void fman_enable_time_stamp(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t count1ubit, uint16_t fm_clk_freq);
+void fman_enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg);
+void fman_disable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg);
+int fman_reset_mac(struct fman_fpm_regs __iomem *fpm_rg, uint8_t mac_id);
+bool fman_rams_ecc_is_external_ctl(struct fman_fpm_regs __iomem *fpm_rg);
+bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs __iomem *qmi_rg);
+
+/* default values */
+#define DEFAULT_CATASTROPHIC_ERR E_FMAN_CATAST_ERR_STALL_PORT
+#define DEFAULT_DMA_ERR E_FMAN_DMA_ERR_CATASTROPHIC
+/* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION false
+/* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR false
+#define DEFAULT_EXTERNAL_ECC_RAMS_ENABLE false
+#define DEFAULT_AID_OVERRIDE false
+#define DEFAULT_AID_MODE E_FMAN_DMA_AID_OUT_TNUM
+#define DEFAULT_DMA_COMM_Q_LOW 0x2A
+#define DEFAULT_DMA_COMM_Q_HIGH 0x3F
+#define DEFAULT_CACHE_OVERRIDE E_FMAN_DMA_NO_CACHE_OR
+#define DEFAULT_DMA_CAM_NUM_OF_ENTRIES 64
+#define DEFAULT_DMA_DBG_CNT_MODE E_FMAN_DMA_DBG_NO_CNT
+#define DEFAULT_DMA_EN_EMERGENCY false
+#define DEFAULT_DMA_SOS_EMERGENCY 0
+#define DEFAULT_DMA_WATCHDOG 0 /* disabled */
+#define DEFAULT_DMA_EN_EMERGENCY_SMOOTHER false
+#define DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER 0
+#define DEFAULT_DISP_LIMIT 0
+#define DEFAULT_PRS_DISP_TH 16
+#define DEFAULT_PLCR_DISP_TH 16
+#define DEFAULT_KG_DISP_TH 16
+#define DEFAULT_BMI_DISP_TH 16
+#define DEFAULT_QMI_ENQ_DISP_TH 16
+#define DEFAULT_QMI_DEQ_DISP_TH 16
+#define DEFAULT_FM_CTL1_DISP_TH 16
+#define DEFAULT_FM_CTL2_DISP_TH 16
+#define DEFAULT_TNUM_AGING_PERIOD 4
+
+#endif /* __FSL_FMAN_H */
--
1.7.11.7
From: Igal Liberman <[email protected]>
Add Frame Manger Driver support.
This patch adds The FMan configuration, initialization and
runtime control routines.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Kconfig | 37 +
drivers/net/ethernet/freescale/fman/Makefile | 2 +-
drivers/net/ethernet/freescale/fman/fm.c | 1478 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/fm.h | 404 ++++++
drivers/net/ethernet/freescale/fman/fm_common.h | 367 +++++
drivers/net/ethernet/freescale/fman/fm_drv.c | 827 +++++++++++
drivers/net/ethernet/freescale/fman/fm_drv.h | 123 ++
drivers/net/ethernet/freescale/fman/inc/enet_ext.h | 199 +++
drivers/net/ethernet/freescale/fman/inc/fm_ext.h | 453 ++++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 94 ++
drivers/net/ethernet/freescale/fman/inc/net_ext.h | 534 +++++++
drivers/net/ethernet/freescale/fman/inc/service.h | 90 ++
12 files changed, 4607 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/net_ext.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..d7de35f 100644
--- a/drivers/net/ethernet/freescale/fman/Kconfig
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -7,3 +7,40 @@ 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"
+ depends on FSL_FMAN
+ 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"
+ depends on FSL_FMAN
+ 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..5beb118
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -0,0 +1,1478 @@
+/*
+ * 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 driver routines implementation. */
+
+#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 functions */
+
+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;
+}
+
+/* Checks if p_fm driver parameters were initialized
+ * returns 0 if success else returns error code
+ */
+static int is_init_done(struct fman_cfg *p_fm_drv_parameters)
+{
+ 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)!!(GET_UINT32(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;
+ }
+#ifdef FM_AID_MODE_NO_TNUM_SW005
+ 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;
+ }
+#endif /* FM_AID_MODE_NO_TNUM_SW005 */
+ 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 (USEC_TO_CLK
+ (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;
+ }
+
+#ifdef FM_HAS_TOTAL_DMAS
+ 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;
+ }
+#endif /* FM_HAS_TOTAL_DMAS */
+
+ 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;
+ }
+#ifdef FM_NO_WATCHDOG
+ 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;
+ }
+#endif /* FM_NO_WATCHDOG */
+
+#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008
+ 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;
+ }
+#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */
+
+#ifdef FM_NO_TNUM_AGING
+ 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;
+ }
+#endif /* FM_NO_TNUM_AGING */
+
+ /* check that user did not set revision-dependent exceptions */
+#ifdef FM_NO_DISPATCH_RAM_ECC
+ 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;
+ }
+#endif /* FM_NO_DISPATCH_RAM_ECC */
+
+#ifdef FM_QMI_NO_ECC_EXCEPTIONS
+ 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;
+ }
+#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
+
+#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
+ 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;
+ }
+#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
+
+ 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 */
+ WRITE_UINT32(p_iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_iram->iadd) != IRAM_IADD_AIE)
+ ;
+
+ for (i = 0; i < (p_fm->intg->fm_iram_size / 4); i++)
+ WRITE_UINT32(p_iram->idata, 0xffffffff);
+
+ WRITE_UINT32(p_iram->iadd, p_fm->intg->fm_iram_size - 4);
+ /* Memory barrier */
+ mb();
+ while (GET_UINT32(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 */
+ WRITE_UINT32(p_iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_iram->iadd) != IRAM_IADD_AIE)
+ ;
+
+ for (i = 0; i < (p_fm->firmware.size / 4); i++)
+ WRITE_UINT32(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++)
+ WRITE_UINT32(p_iram->idata, 0xffffffff);
+
+ WRITE_UINT32(p_iram->iadd, p_fm->firmware.size - 4);
+ while (GET_UINT32(p_iram->iadd) != (p_fm->firmware.size - 4))
+ ;
+
+ /* verify that writing has completed */
+ while (GET_UINT32(p_iram->idata) !=
+ p_fm->firmware.p_code[(p_fm->firmware.size / 4) - 1])
+ ;
+
+ if (p_fm->fw_verify) {
+ WRITE_UINT32(p_iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_iram->iadd) != IRAM_IADD_AIE)
+ ;
+ for (i = 0; i < (p_fm->firmware.size / 4); i++) {
+ tmp = GET_UINT32(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;
+ }
+ }
+ WRITE_UINT32(p_iram->iadd, 0x0);
+ }
+
+ /* Enable patch from IRAM */
+ WRITE_UINT32(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;
+}
+
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+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 */
+ WRITE_UINT32(p_iram->iadd, 0);
+ while (GET_UINT32(p_iram->iadd) != 0)
+ ;
+
+ WRITE_UINT32(p_iram->idata, FM_FW_DEBUG_INSTRUCTION);
+
+ WRITE_UINT32(p_iram->iadd, 0);
+ while (GET_UINT32(p_iram->iadd) != 0)
+ ;
+ while (GET_UINT32(p_iram->idata) != FM_FW_DEBUG_INSTRUCTION)
+ ;
+
+ /* Enable patch from IRAM */
+ WRITE_UINT32(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 */
+ WRITE_UINT32(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 =
+ GET_UINT32(*(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 */
+ WRITE_UINT32(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;
+}
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+/* Inter-Module functions */
+
+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)
+{
+ /* for multicore environment: this depends on the
+ * fact that fm_clk_freq was properly initialized at "init".
+ */
+ 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):
+ WRITE_UINT32(*(uint32_t __iomem *)cam_base_addr,
+ 0xff000000);
+ break;
+ case (16):
+ WRITE_UINT32(*(uint32_t __iomem *)cam_base_addr,
+ 0xffff0000);
+ break;
+ case (24):
+ WRITE_UINT32(*(uint32_t __iomem *)cam_base_addr,
+ 0xffffff00);
+ break;
+ case (32):
+ WRITE_UINT32(*(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);
+}
+
+/* API Init unit functions */
+
+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 */
+#ifdef FM_PEDANTIC_DMA
+ 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;
+ }
+#endif /* FM_PEDANTIC_DMA */
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_fm->p_fm_state_struct->rev_info.major_rev != 4)
+ p_fm->p_fm_drv_param->qmi_deq_option_support = true;
+#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ 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;
+ }
+
+#ifdef FM_AID_MODE_NO_TNUM_SW005
+ 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;
+#endif /* FM_AID_MODE_NO_TNUM_SW005 */
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ 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;
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ 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);
+#ifdef FM_HAS_TOTAL_DMAS
+ 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;
+#endif /* FM_HAS_TOTAL_DMAS */
+ if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
+ 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;
+ }
+
+#ifdef FM_NO_TNUM_AGING
+ p_fm->p_fm_drv_param->tnum_aging_period = 0;
+#endif /* FM_NO_TNUM_AGING */
+ p_fm->tnum_aging_period = p_fm->p_fm_drv_param->tnum_aging_period;
+
+ return p_fm;
+}
+
+/* fm_init
+ *
+ * Initializes the FM module
+ *
+ * @Param[in] p_fm - FM module descriptor
+ *
+ * @Return 0 on success; Error code otherwise.
+ */
+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 */
+#ifdef FM_NO_DISPATCH_RAM_ECC
+ if ((rev_info.major_rev != 4) && (rev_info.major_rev < 6))
+ p_fm->p_fm_state_struct->exceptions &=
+ ~FM_EX_BMI_DISPATCH_RAM_ECC;
+#endif /* FM_NO_DISPATCH_RAM_ECC */
+
+#ifdef FM_QMI_NO_ECC_EXCEPTIONS
+ if (rev_info.major_rev == 4)
+ p_fm->p_fm_state_struct->exceptions &=
+ ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC);
+#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
+
+#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
+ if (rev_info.major_rev >= 6)
+ p_fm->p_fm_state_struct->exceptions &= ~FM_EX_QMI_SINGLE_ECC;
+#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
+
+ /* 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;
+
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+ 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 {
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+ /* 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 {
+ WRITE_UINT32(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;
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+ }
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+ /* 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; /* FIXME */
+
+ 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;
+}
+
+/* fm_free
+ * Frees all resources that were assigned to FM module.
+ * Calling this routine invalidates the descriptor.
+ * p_fm - FM module descriptor
+ *Return 0 on success; Error code otherwise.
+ */
+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;
+}
+
+/* API Advanced Init unit functions */
+
+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;
+}
+
+/* API Run-time Control uint functions */
+
+void fm_event_isr(struct fm_t *p_fm)
+{
+#define FM_M_CALL_MAC_ISR(_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))
+ 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 events may belong to different partitions */
+ if (pending & INTR_EN_MAC0)
+ FM_M_CALL_MAC_ISR(0);
+ if (pending & INTR_EN_MAC1)
+ FM_M_CALL_MAC_ISR(1);
+ if (pending & INTR_EN_MAC2)
+ FM_M_CALL_MAC_ISR(2);
+ if (pending & INTR_EN_MAC3)
+ FM_M_CALL_MAC_ISR(3);
+ if (pending & INTR_EN_MAC4)
+ FM_M_CALL_MAC_ISR(4);
+ if (pending & INTR_EN_MAC5)
+ FM_M_CALL_MAC_ISR(5);
+ if (pending & INTR_EN_MAC6)
+ FM_M_CALL_MAC_ISR(6);
+ if (pending & INTR_EN_MAC7)
+ FM_M_CALL_MAC_ISR(7);
+ if (pending & INTR_EN_MAC8)
+ FM_M_CALL_MAC_ISR(8);
+ if (pending & INTR_EN_MAC9)
+ FM_M_CALL_MAC_ISR(9);
+}
+
+int fm_error_isr(struct fm_t *p_fm)
+{
+#define FM_M_CALL_MAC_ERR_ISR(_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))
+ 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 events may belong to different partitions */
+ if (pending & ERR_INTR_EN_MAC0)
+ FM_M_CALL_MAC_ERR_ISR(0);
+ if (pending & ERR_INTR_EN_MAC1)
+ FM_M_CALL_MAC_ERR_ISR(1);
+ if (pending & ERR_INTR_EN_MAC2)
+ FM_M_CALL_MAC_ERR_ISR(2);
+ if (pending & ERR_INTR_EN_MAC3)
+ FM_M_CALL_MAC_ERR_ISR(3);
+ if (pending & ERR_INTR_EN_MAC4)
+ FM_M_CALL_MAC_ERR_ISR(4);
+ if (pending & ERR_INTR_EN_MAC5)
+ FM_M_CALL_MAC_ERR_ISR(5);
+ if (pending & ERR_INTR_EN_MAC6)
+ FM_M_CALL_MAC_ERR_ISR(6);
+ if (pending & ERR_INTR_EN_MAC7)
+ FM_M_CALL_MAC_ERR_ISR(7);
+ if (pending & ERR_INTR_EN_MAC8)
+ FM_M_CALL_MAC_ERR_ISR(8);
+ if (pending & ERR_INTR_EN_MAC9)
+ FM_M_CALL_MAC_ERR_ISR(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;
+}
+
+int fm_get_revision(struct fm_t *p_fm, struct fm_revision_info_t
+ *p_fm_revision_info)
+{
+ p_fm_revision_info->major_rev = p_fm->p_fm_state_struct->
+ rev_info.major_rev;
+ p_fm_revision_info->minor_rev = p_fm->p_fm_state_struct->
+ rev_info.minor_rev;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/fman/fm.h b/drivers/net/ethernet/freescale/fman/fm.h
new file mode 100644
index 0000000..f7f56e3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.h
@@ -0,0 +1,404 @@
+/*
+ * 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 internal structures and definitions. */
+#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;
+#ifdef FM_LOW_END_RESTRICTION
+ bool low_end_restriction;
+#endif /* FM_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 {
+/* locals for recovery */
+ uintptr_t base_addr;
+
+/* un-needed for recovery */
+ char fm_module_name[MODULE_NAME_SIZE];
+ /* FM exceptions user callback */
+ struct fm_intr_src_t intr_mng[FM_EV_DUMMY_LAST];
+
+/* Master Only parameters */
+
+/* locals for recovery */
+ 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..125c057
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -0,0 +1,367 @@
+/*
+ * 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.
+ */
+
+/* File fm_common.h
+ * Description FM internal structures and definitions.
+ */
+#ifndef __FM_COMMON_H
+#define __FM_COMMON_H
+
+#include "service.h"
+#include "fm_ext.h"
+
+/* Uniqe defines */
+#define FM_QMI_NO_ECC_EXCEPTIONS /* P1 */
+#define FM_CSI_CFED_LIMIT /* P1 */
+#define FM_PEDANTIC_DMA /* P1 */
+#define FM_QMI_NO_DEQ_OPTIONS_SUPPORT /* P1 */
+#define FM_HAS_TOTAL_DMAS /* P1-P5 */
+#define FM_DEQ_PIPELINE_PARAMS_FOR_OP /* P1, T/B */
+#define FM_NO_DISPATCH_RAM_ECC /* P2-P5 */
+#define FM_NO_WATCHDOG /* P4 */
+#define FM_NO_TNUM_AGING /* P2-P5 */
+#define FM_NO_BACKUP_POOLS /* P2-P5 */
+#define FM_NO_OP_OBSERVED_POOLS /* P2-P5, T/B */
+#define FM_NO_ADVANCED_RATE_LIMITER /* P2-P5 */
+#define FM_OP_OPEN_DMA_MIN_LIMIT /* T/B */
+#define FM_NO_RESTRICT_ON_ACCESS_RSRC /* T/B */
+#define FM_FRAME_END_PARAMS_FOR_OP /* T/B */
+#define FM_QMI_NO_SINGLE_ECC_EXCEPTION /* T/B */
+
+/* FMan Errata */
+#define FM_RX_PREAM_4_ERRATA_DTSEC_A001 /* Dtsec */
+#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 /* Dtsec */
+#define FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 /* Tgec */
+#define FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 /* P2-P5 */
+#define FM_GRS_ERRATA_DTSEC_A002 /* P4080 */
+#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 /* P4080 */
+#define FM_GTS_ERRATA_DTSEC_A004 /* P4080 */
+#define FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 /* P4080 */
+#define FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 /* P2-P5 */
+#define FM_TX_LOCKUP_ERRATA_DTSEC6 /* P4080 */
+#define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 /* P2-P5 */
+#define FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 /* P4080 */
+#define FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 /* P2-P5 */
+#define FM_LEN_CHECK_ERRATA_FMAN_SW002 /* P2-P5, T/B */
+#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 /* T/B */
+#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 /* mEMAC */
+#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 /* T4/B4 rev1 */
+#define FM_AID_MODE_NO_TNUM_SW005
+/* refer to pdm TKT068794 - only support of port_id on aid - T/B */
+#define FM_ERROR_VSP_NO_MATCH_SW006
+/* refer to pdm TKT174304 - no match between errorQ and VSP - T/B */
+
+#define CLS_PLAN_NUM_PER_GRP 8
+
+/* list_object
+ * Macro to get the struct (object) for this entry.
+ * type - The type of the struct (object) this list
+ * is embedded in.
+ * member - The name of the struct list_head object
+ * within the struct.
+ * Return The structure pointer for this entry.
+ */
+#define member_offset(type, member) (PTR_TO_UINT(&((type *)0)->member))
+#define list_object(p_list, type, member) \
+((type *)((char *)(p_list) - member_offset(type, member)))
+
+/* 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
+
+/*for UNDER_CONSTRUCTION_FM_RMU_USE_SEC its defined in fm_ext.h*/
+typedef uint32_t fm_fman_ctrl_t;
+
+#define FPM_PORT_FM_CTL1 0x00000001
+#define FPM_PORT_FM_CTL2 0x00000002
+
+static inline bool TRY_LOCK(spinlock_t *spinlock, volatile bool *p_flag)
+{
+ unsigned long int_flags;
+
+ if (spinlock)
+ spin_lock_irqsave(spinlock, int_flags);
+ else
+ local_irq_save(int_flags);
+
+ if (*p_flag) {
+ if (spinlock)
+ spin_unlock_irqrestore(spinlock, int_flags);
+ else
+ local_irq_restore(int_flags);
+ return false;
+ }
+ *p_flag = true;
+
+ if (spinlock)
+ spin_unlock_irqrestore(spinlock, int_flags);
+ else
+ local_irq_restore(int_flags);
+
+ return true;
+}
+
+#define RELEASE_LOCK(_flag) (_flag = false)
+
+/* Defines used for manipulation CC and BMI */
+#define INTERNAL_CONTEXT_OFFSET 0x80000000
+#define OFFSET_OF_PR 0x40000000
+#define NUM_OF_TASKS 0x10000000
+#define OFFSET_OF_DATA 0x08000000
+#define HW_PORT_ID 0x04000000
+#define FM_REV 0x02000000
+#define GET_NIA_FPNE 0x01000000
+#define GET_NIA_PNDN 0x00800000
+#define NUM_OF_EXTRA_TASKS 0x00400000
+#define DISCARD_MASK 0x00200000
+
+#define UPDATE_NIA_PNEN 0x80000000
+#define UPDATE_PSO 0x40000000
+#define UPDATE_NIA_PNDN 0x20000000
+#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000
+#define UPDATE_NIA_FENE 0x04000000
+#define UPDATE_NIA_CMNE 0x02000000
+#define UPDATE_NIA_FPNE 0x01000000
+
+/* Defines used for manipulation CC and CC */
+#define UPDATE_NIA_ENQ_WITHOUT_DMA 0x80000000
+
+#define MODULE_NAME_SIZE 30
+#define DUMMY_PORT_ID 0
+
+#define FM_LIODN_OFFSET_MASK 0x3FF
+
+/* Description CTRL Parameters Page defines */
+#define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000
+#define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100
+
+#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK 0x0000003f
+
+#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;
+};
+
+#define ILLEGAL_HDR_NUM 0xFF
+#define NO_HDR_NUM FM_PCD_PRS_NUM_OF_HDRS
+
+#define IS_PRIVATE_HEADER(hdr) (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) || \
+ ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2))
+
+#define GET_PRS_HDR_NUM(num, hdr) do {\
+switch (hdr) { \
+case (HEADER_TYPE_ETH):\
+ num = 0; break; \
+case (HEADER_TYPE_LLC_SNAP):\
+ num = 1; break; \
+case (HEADER_TYPE_VLAN):\
+ num = 2; break; \
+case (HEADER_TYPE_PPPOE):\
+ num = 3; break; \
+case (HEADER_TYPE_PPP):\
+ num = 3; break; \
+case (HEADER_TYPE_MPLS):\
+ num = 4; break; \
+case (HEADER_TYPE_IPV4):\
+ num = 5; break; \
+case (HEADER_TYPE_IPV6):\
+ num = 6; break; \
+case (HEADER_TYPE_GRE):\
+ num = 7; break; \
+case (HEADER_TYPE_MINENCAP):\
+ num = 8; break; \
+case (HEADER_TYPE_USER_DEFINED_L3):\
+ num = 9; break; \
+case (HEADER_TYPE_TCP):\
+ num = 10; break; \
+case (HEADER_TYPE_UDP):\
+ num = 11; break; \
+case (HEADER_TYPE_IPSEC_AH): \
+case (HEADER_TYPE_IPSEC_ESP):\
+ num = 12; break; \
+case (HEADER_TYPE_SCTP):\
+ num = 13; break; \
+case (HEADER_TYPE_DCCP):\
+ num = 14; break; \
+case (HEADER_TYPE_USER_DEFINED_L4):\
+ num = 15; break; \
+case (HEADER_TYPE_USER_DEFINED_SHIM1): \
+case (HEADER_TYPE_USER_DEFINED_SHIM2): \
+ num = NO_HDR_NUM; break; \
+default: \
+ pr_err("Unsupported header for parser\n");\
+ num = ILLEGAL_HDR_NUM; break; \
+} \
+} while (0)
+
+/* Function fm_register_intr
+ * Description Used to register
+ * an inter-module event handler to be processed by FM
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in] mod The module that causes the event
+ * Param[in] mod_id Module id - if more than 1 instance of this
+ * mode exists,0 otherwise.
+ * Param[in] intr_type Interrupt type (error/normal) selection.
+ * Param[in] f_isr The interrupt service routine.
+ * Param[in] h_src_arg Argument to be passed to f_isr.
+ * Return None.
+ */
+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);
+
+/* Function fm_unregister_intr
+ * Description Used to un-register an
+ * inter-module event handler that was processed by FM
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in] mod The module that causes the event
+ * Param[in] mod_id Module id - if more than 1 instance of this
+ * mode exists,0 otherwise.
+ * Param[in] intr_type Interrupt type (error/normal) selection.
+ * Return None.
+ */
+void fm_unregister_intr(struct fm_t *p_fm,
+ enum fm_event_modules mod,
+ uint8_t mod_id, enum fm_intr_type intr_type);
+
+/* Description enum for defining MAC types */
+enum fm_mac_type {
+ FM_MAC_10G = 0, /* 10G MAC */
+ FM_MAC_1G /* 1G MAC */
+};
+
+/* Function fm_get_muram_pointer
+ * Description Get the pointer of the MURAM from the FM module
+ * Param[in] h_fm A handle to an FM Module.
+ * Return MURAM module pointer.
+ */
+struct muram_info *fm_get_muram_pointer(struct fm_t *p_fm);
+
+/* Function fm_get_physical_muram_base
+ * Description Get the physical base address of the MURAM from the FM module
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in] fm_phys_addr Physical MURAM base
+ * Return Physical base address.
+ */
+void fm_get_physical_muram_base(struct fm_t *p_fm,
+ struct fm_phys_addr_t *fm_phys_addr);
+
+/* Function fm_get_clock_freq
+ * Description Used by MAC driver to get the FM clock frequency
+ * Param[in] h_fm A handle to an FM Module.
+ * Return clock-freq on success; 0 otherwise.
+ * Cautions Allowed only following fm_init().
+ */
+uint16_t fm_get_clock_freq(struct fm_t *p_fm);
+
+/*Function fm_get_id
+ * Description Used by PCD driver to read rhe FM id
+ * Param[in] h_fm A handle to an FM Module.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_init().
+ */
+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..2c78829
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
@@ -0,0 +1,827 @@
+/*
+ * 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/version.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <asm/qe.h> /* For struct qe_firmware */
+#include <sysdev/fsl_soc.h>
+#include <linux/stat.h> /* For file access mask */
+#include <linux/skbuff.h>
+
+/* Internal services */
+#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;
+
+static struct fm_drvs_t fm_drvs;
+
+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 *p_fm_drv = (struct fm_drv_t *)_dev;
+
+ if (!p_fm_drv || !p_fm_drv->h_dev)
+ return IRQ_NONE;
+
+ fm_event_isr(p_fm_drv->h_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fm_err_irq(int irq, void *_dev)
+{
+ struct fm_drv_t *p_fm_drv = (struct fm_drv_t *)_dev;
+
+ if (!p_fm_drv || !p_fm_drv->h_dev)
+ return IRQ_NONE;
+
+ if (fm_error_isr(p_fm_drv->h_dev) == 0)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+/* used to protect FMD from concurrent calls in functions
+ * fm_mutex_lock / fm_mutex_unlock
+ */
+static struct mutex fm_drv_mutex;
+
+static struct fm_drv_t *create_fm_dev(uint8_t id)
+{
+ struct fm_drv_t *p_fm_drv;
+
+ p_fm_drv = kzalloc(sizeof(*p_fm_drv), GFP_KERNEL);
+ if (!p_fm_drv)
+ return NULL;
+
+ return p_fm_drv;
+}
+
+static void destroy_fm_dev(struct fm_drv_t *p_fm_drv)
+{
+ kfree(p_fm_drv);
+}
+
+/**
+*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 Fmen use the same firmware.
+ */
+static const struct qe_firmware *find_fman_microcode(void)
+{
+ static const struct qe_firmware *p4080_uc_patch;
+ struct device_node *np;
+
+ if (p4080_uc_patch)
+ return p4080_uc_patch;
+
+ /* The firmware should be inside the device tree. */
+ np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
+ if (np) {
+ p4080_uc_patch = of_get_property(np, "fsl,firmware", NULL);
+ of_node_put(np);
+ if (p4080_uc_patch)
+ return p4080_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 *p_fm_drv)
+{
+ p_fm_drv->qman_channels = kcalloc(p_fm_drv->num_of_qman_channels,
+ sizeof(uint32_t),
+ GFP_KERNEL);
+ if (!p_fm_drv->qman_channels)
+ return -ENOMEM;
+
+ if (p_fm_drv->fm_rev_info.major_rev >= 6) {
+ p_fm_drv->qman_channels[0] = 0x30;
+ p_fm_drv->qman_channels[1] = 0x31;
+ p_fm_drv->qman_channels[2] = 0x28;
+ p_fm_drv->qman_channels[3] = 0x29;
+ p_fm_drv->qman_channels[4] = 0x2a;
+ p_fm_drv->qman_channels[5] = 0x2b;
+ p_fm_drv->qman_channels[6] = 0x2c;
+ p_fm_drv->qman_channels[7] = 0x2d;
+ p_fm_drv->qman_channels[8] = 0x2;
+ p_fm_drv->qman_channels[9] = 0x3;
+ p_fm_drv->qman_channels[10] = 0x4;
+ p_fm_drv->qman_channels[11] = 0x5;
+ p_fm_drv->qman_channels[12] = 0x6;
+ p_fm_drv->qman_channels[13] = 0x7;
+ } else {
+ p_fm_drv->qman_channels[0] = 0x30;
+ p_fm_drv->qman_channels[1] = 0x28;
+ p_fm_drv->qman_channels[2] = 0x29;
+ p_fm_drv->qman_channels[3] = 0x2a;
+ p_fm_drv->qman_channels[4] = 0x2b;
+ p_fm_drv->qman_channels[5] = 0x2c;
+ p_fm_drv->qman_channels[6] = 0x1;
+ p_fm_drv->qman_channels[7] = 0x2;
+ p_fm_drv->qman_channels[8] = 0x3;
+ p_fm_drv->qman_channels[9] = 0x4;
+ p_fm_drv->qman_channels[10] = 0x5;
+ p_fm_drv->qman_channels[11] = 0x6;
+ }
+
+ return 0;
+}
+
+#define SVR_SECURITY_MASK 0x00080000
+#define SVR_PERSONALITY_MASK 0x0000FF00
+#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
+#define SVR_B4860_REV1_VALUE 0x86800010
+#define SVR_B4860_REV2_VALUE 0x86800020
+
+static struct fm_drv_t *read_fm_dev_tree_node(struct platform_device
+ *of_dev)
+{
+ struct fm_drv_t *p_fm_drv;
+ struct device_node *fm_node, *dev_node;
+ struct of_device_id name; /* used temporarily */
+ struct resource res;
+ const uint32_t *uint32_prop;
+ int lenp, err;
+ struct clk *clk;
+ u32 clk_rate;
+ u8 cell_index;
+
+ 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;
+
+ cell_index = (u8)*uint32_prop;
+ p_fm_drv = create_fm_dev(cell_index);
+ if (!p_fm_drv)
+ goto _return_null;
+ p_fm_drv->dev = &of_dev->dev;
+ p_fm_drv->id = cell_index;
+
+ /* Get the FM interrupt */
+ p_fm_drv->irq = of_irq_to_resource(fm_node, 0, NULL);
+ if (unlikely(p_fm_drv->irq == /*NO_IRQ */ 0)) {
+ pr_err("of_irq_to_resource() = %d\n", NO_IRQ);
+ goto _return_null;
+ }
+
+ /* Get the FM error interrupt */
+ p_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;
+ }
+
+ p_fm_drv->fm_base_addr = 0;
+ p_fm_drv->fm_phys_base_addr = res.start;
+ p_fm_drv->fm_mem_size = res.end + 1 - res.start;
+
+ clk = clk_get(p_fm_drv->dev, p_fm_drv->id == 0 ? "fm0clk" : "fm1clk");
+ if (IS_ERR(clk)) {
+ pr_err("Failed to get FM%d clock structure\n", p_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", p_fm_drv->id);
+ goto _return_null;
+ }
+ /* Rounding to MHz */
+ clk_rate = (clk_rate + 500000) / 1000000;
+ p_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;
+ p_fm_drv->qman_channel_base = uint32_prop[0];
+ p_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;
+ }
+
+ p_fm_drv->fm_muram_base_addr = 0;
+ p_fm_drv->fm_muram_phys_base_addr = res.start;
+ p_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 & ~SVR_VER_IGNORE_MASK) >=
+ SVR_B4860_REV2_VALUE)
+ p_fm_drv->fm_muram_mem_size = 0x80000;
+ }
+ }
+ }
+
+ of_node_put(fm_node);
+
+ p_fm_drv->active = true;
+
+ goto _return;
+
+_return_null:
+ of_node_put(fm_node);
+ return NULL;
+_return:
+ return p_fm_drv;
+}
+
+static void fm_drv_exceptions_cb(void *h_app,
+ enum fm_exceptions __maybe_unused exception)
+{
+ struct fm_drv_t *p_fm_drv = (struct fm_drv_t *)h_app;
+
+ ASSERT(p_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 *p_fm_drv = (struct fm_drv_t *)h_app;
+
+ ASSERT(p_fm_drv);
+}
+
+uint32_t get_qman_channel_id(struct fm_drv_t *p_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 < p_fm_drv->num_of_qman_channels; i++) {
+ if (p_fm_drv->qman_channels[i] == port_id)
+ break;
+ }
+
+ if (i == p_fm_drv->num_of_qman_channels)
+ return 0;
+
+ qman_channel = p_fm_drv->qman_channel_base + i;
+
+ return qman_channel;
+}
+
+static int configure_fm_dev(struct fm_drv_t *p_fm_drv)
+{
+ int err;
+
+ if (!p_fm_drv->active) {
+ pr_err("FM not configured!\n");
+ return -EINVAL;
+ }
+
+#ifndef MODULE
+ err = can_request_irq(p_fm_drv->irq, 0);
+ if (unlikely(err < 0)) {
+ pr_err("can_request_irq() = %d\n", err);
+ return -EINVAL;
+ }
+#endif
+ err = devm_request_irq(p_fm_drv->dev, p_fm_drv->irq, fm_irq,
+ IRQF_NO_SUSPEND, "fman", p_fm_drv);
+ if (unlikely(err < 0)) {
+ pr_err("request_irq(%d) = %d\n", p_fm_drv->irq,
+ err);
+ return -EINVAL;
+ }
+
+ if (p_fm_drv->err_irq != 0) {
+#ifndef MODULE
+ err = can_request_irq(p_fm_drv->err_irq, 0);
+ if (unlikely(err < 0)) {
+ pr_err("can_request_irq() = %d\n", err);
+ return -EINVAL;
+ }
+#endif
+ err = devm_request_irq(p_fm_drv->dev, p_fm_drv->err_irq,
+ fm_err_irq,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "fman-err", p_fm_drv);
+ if (unlikely(err < 0)) {
+ pr_err("request_irq(%d) = %d\n",
+ p_fm_drv->err_irq, err);
+ return -EINVAL;
+ }
+ }
+
+ p_fm_drv->res = devm_request_mem_region(p_fm_drv->dev,
+ p_fm_drv->fm_phys_base_addr,
+ p_fm_drv->fm_mem_size, "fman");
+ if (unlikely(!p_fm_drv->res)) {
+ pr_err("request_mem_region() failed\n");
+ return -EINVAL;
+ }
+
+ p_fm_drv->fm_base_addr =
+ PTR_TO_UINT(devm_ioremap(p_fm_drv->dev,
+ p_fm_drv->fm_phys_base_addr,
+ p_fm_drv->fm_mem_size));
+ if (unlikely(p_fm_drv->fm_base_addr == 0)) {
+ pr_err("devm_ioremap() failed\n");
+ return -EINVAL;
+ }
+
+ p_fm_drv->params.base_addr = p_fm_drv->fm_base_addr;
+ p_fm_drv->params.fm_id = p_fm_drv->id;
+ p_fm_drv->params.f_exception = fm_drv_exceptions_cb;
+ p_fm_drv->params.f_bus_error = fm_drv_bus_error_cb;
+ p_fm_drv->params.h_app = p_fm_drv;
+
+ return 0;
+}
+
+static int init_fm_dev(struct fm_drv_t *p_fm_drv)
+{
+ const struct qe_firmware *fw;
+
+ if (!p_fm_drv->active) {
+ pr_err("FM not configured!!!\n");
+ return -EINVAL;
+ }
+
+ p_fm_drv->p_muram =
+ fm_muram_init(p_fm_drv->fm_muram_phys_base_addr,
+ p_fm_drv->fm_muram_mem_size);
+ if (!p_fm_drv->p_muram) {
+ pr_err("FM-MURAM!\n");
+ return -EINVAL;
+ }
+
+ fw = find_fman_microcode();
+
+ if (!fw) {
+ /* this forces the reuse of the current IRAM content */
+ p_fm_drv->params.firmware.size = 0;
+ p_fm_drv->params.firmware.p_code = NULL;
+ } else {
+ p_fm_drv->params.firmware.p_code =
+ (void *)fw + fw->microcode[0].code_offset;
+ p_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);
+ }
+
+ p_fm_drv->params.p_muram = p_fm_drv->p_muram;
+
+ p_fm_drv->h_dev = fm_config(&p_fm_drv->params);
+ if (!p_fm_drv->h_dev) {
+ pr_err("FM\n");
+ return -EINVAL;
+ }
+
+ if (fm_get_revision(p_fm_drv->h_dev, &p_fm_drv->fm_rev_info) != 0) {
+ pr_err("FM\n");
+ return -EINVAL;
+ }
+
+ if (fm_cfg_reset_on_init(p_fm_drv->h_dev, true) != 0) {
+ pr_err("FM\n");
+ return -EINVAL;
+ }
+ /* Config fm_cfg_dma_aid_override for P1023 */
+ if (p_fm_drv->fm_rev_info.major_rev == 4)
+ if (fm_cfg_dma_aid_override(p_fm_drv->h_dev, true) != 0) {
+ pr_err("FM\n");
+ return -EINVAL;
+ }
+ /* Config total fifo size for FManV3H */
+ if ((p_fm_drv->fm_rev_info.major_rev >= 6) &&
+ (p_fm_drv->fm_rev_info.minor_rev != 1 &&
+ p_fm_drv->fm_rev_info.minor_rev != 4))
+ fm_cfg_total_fifo_size(p_fm_drv->h_dev, 295 * 1024);
+
+ if (fm_init(p_fm_drv->h_dev) != 0) {
+ pr_err("FM\n");
+ return -EINVAL;
+ }
+
+ /* TODO: Why we mask these interrupts? */
+ if (p_fm_drv->err_irq == 0) {
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_DMA_BUS_ERROR, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_DMA_READ_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_DMA_SYSTEM_WRITE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_DMA_FM_WRITE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_DMA_SINGLE_PORT_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_FPM_STALL_ON_TASKS, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_FPM_SINGLE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_FPM_DOUBLE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_QMI_SINGLE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_QMI_DOUBLE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_BMI_LIST_RAM_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_BMI_STORAGE_PROFILE_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_BMI_STATISTICS_RAM_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev,
+ FM_EX_BMI_DISPATCH_RAM_ECC, false);
+ fm_set_exception(p_fm_drv->h_dev, FM_EX_IRAM_ECC,
+ false);
+ /* TODO: _fm_disable_rams_ecc assert for rams_ecc_owners.
+ * fm_set_exception(p_fm_drv->h_dev,FM_EX_MURAM_ECC,
+ * false);
+ */
+ }
+
+ if (unlikely(fill_qman_channhels_info(p_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 *p_fm_drv)
+{
+ if (!p_fm_drv->active)
+ return;
+
+ if (p_fm_drv->h_dev)
+ fm_free(p_fm_drv->h_dev);
+
+ if (p_fm_drv->p_muram)
+ fm_muram_free(p_fm_drv->p_muram);
+
+ devm_iounmap(p_fm_drv->dev,
+ UINT_TO_PTR(p_fm_drv->fm_base_addr));
+ devm_release_mem_region(p_fm_drv->dev,
+ p_fm_drv->fm_phys_base_addr,
+ p_fm_drv->fm_mem_size);
+
+ if (p_fm_drv->err_irq != 0)
+ devm_free_irq(p_fm_drv->dev, p_fm_drv->err_irq, p_fm_drv);
+
+ devm_free_irq(p_fm_drv->dev, p_fm_drv->irq, p_fm_drv);
+}
+
+/* FMan character device file operations */
+static const struct file_operations fm_fops;
+
+static int /*__devinit*/ fm_probe(struct platform_device *of_dev)
+{
+ struct fm_drv_t *p_fm_drv;
+
+ p_fm_drv = read_fm_dev_tree_node(of_dev);
+ if (!p_fm_drv)
+ return -EIO;
+ if (configure_fm_dev(p_fm_drv) != 0)
+ return -EIO;
+ if (init_fm_dev(p_fm_drv) != 0)
+ return -EIO;
+
+ dev_set_drvdata(p_fm_drv->dev, p_fm_drv);
+
+ pr_debug("FM%d probed\n", p_fm_drv->id);
+
+ return 0;
+}
+
+static int fm_remove(struct platform_device *of_dev)
+{
+ struct fm_drv_t *p_fm_drv;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+ p_fm_drv = dev_get_drvdata(dev);
+
+ free_fm_dev(p_fm_drv);
+
+ destroy_fm_dev(p_fm_drv);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id fm_match[] = {
+ {
+ .compatible = "fsl,fman"},
+ {}
+};
+
+#ifndef MODULE
+MODULE_DEVICE_TABLE(of, fm_match);
+#endif /* !MODULE */
+
+static struct platform_driver fm_driver = {
+ .driver = {
+ .name = "fsl-fman",
+ .of_match_table = fm_match,
+ },
+ .probe = fm_probe,
+ .remove = fm_remove
+};
+
+void *fm_drv_init(void)
+{
+ memset(&fm_drvs, 0, sizeof(fm_drvs));
+ mutex_init(&fm_drv_mutex);
+
+ /* Register to the DTB for basic FM API */
+ platform_driver_register(&fm_driver);
+
+ return &fm_drvs;
+}
+
+int fm_drv_free(void *p_fm_drv)
+{
+ platform_driver_unregister(&fm_driver);
+ mutex_destroy(&fm_drv_mutex);
+
+ return 0;
+}
+
+struct fm *fm_bind(struct device *fm_dev)
+{
+ return (struct fm *)(dev_get_drvdata(get_device(fm_dev)));
+}
+EXPORT_SYMBOL(fm_bind);
+
+void fm_unbind(struct fm *fm)
+{
+ struct fm_drv_t *p_fm_drv = (struct fm_drv_t *)fm;
+
+ put_device(p_fm_drv->dev);
+}
+EXPORT_SYMBOL(fm_unbind);
+
+struct resource *fm_get_mem_region(struct fm *fm)
+{
+ struct fm_drv_t *p_fm_drv = (struct fm_drv_t *)fm;
+
+ return p_fm_drv->res;
+}
+EXPORT_SYMBOL(fm_get_mem_region);
+
+void *fm_get_handle(struct fm *fm)
+{
+ struct fm_drv_t *p_fm_drv = (struct fm_drv_t *)fm;
+
+ return (void *)p_fm_drv->h_dev;
+}
+EXPORT_SYMBOL(fm_get_handle);
+
+
+void fm_mutex_lock(void)
+{
+ mutex_lock(&fm_drv_mutex);
+}
+EXPORT_SYMBOL(fm_mutex_lock);
+
+void fm_mutex_unlock(void)
+{
+ mutex_unlock(&fm_drv_mutex);
+}
+EXPORT_SYMBOL(fm_mutex_unlock);
+
+static void *p_fm_drv;
+
+static int __init __cold fm_load(void)
+{
+ p_fm_drv = fm_drv_init();
+ if (!p_fm_drv) {
+ pr_err("Failed to init FM wrapper!\n");
+ return -ENODEV;
+ }
+
+ pr_info("Freescale FM module\n");
+ return 0;
+}
+
+static void __exit __cold fm_unload(void)
+{
+ if (p_fm_drv)
+ fm_drv_free(p_fm_drv);
+}
+
+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..2acd77b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.h
@@ -0,0 +1,123 @@
+/*
+ * 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 "service.h"
+#include "fsl_fman_drv.h"
+
+/* FMan Driver Errata */
+#define FM_BCB_ERRATA_BMI_SW001 /* T/B */
+#define FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 /* P2-P5 */
+
+#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
+
+#define NUM_OF_FMS 2
+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 *h_dev;
+ struct fm_drv_t *p_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 *p_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;
+
+};
+
+struct fm_drvs_t {
+ struct fm_drv_t *p_fm_devs[NUM_OF_FMS];
+};
+
+uint32_t get_qman_channel_id(struct fm_drv_t *p_fm_dr,
+ 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..bc5d964
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_ext.h
@@ -0,0 +1,453 @@
+/*
+ * 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
+ * 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.
+ * p_fm_params A pointer to a data structure of mandatory FM
+ * parameters
+ * Return A handle to the FM object, or NULL for Failure.
+ */
+void *fm_config(struct fm_params_t *p_fm_params);
+
+/* fm_init
+ * Initializes the FM module by defining the software structure
+ * and configuring the hardware registers.
+ * p_fm Pointer to the FMan module
+ * Return 0 on success; Error code otherwise.
+ */
+int fm_init(struct fm_t *p_fm);
+
+/* fm_free
+ * Frees all resources that were assigned to FM module.
+ * Calling this routine invalidates the descriptor.
+ * p_fm Pointer to the FMan module
+ * 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
+ * Define whether to reset the FM before initialization.
+ * Change the default configuration [DEFAULT_RESET_ON_INIT].
+ * p_fm Pointer to the FMan module
+ * enable When true, FM will be reset before any
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_config() and before fm_init().
+ */
+int fm_cfg_reset_on_init(struct fm_t *p_fm, bool enable);
+
+/* fm_cfg_total_fifo_size
+ * 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]
+ * p_fm Pointer to the FMan module
+ * total_fifo_size The selected new value.
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_config() and before fm_init().
+ */
+int fm_cfg_total_fifo_size(struct fm_t *p_fm, uint32_t total_fifo_size);
+
+/* fm_cfg_dma_aid_override
+ * 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]
+ * p_fm Pointer to the FMan module
+ * aid_override The selected new value.
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_config() and before fm_init().
+ */
+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
+ * Calling this routine enables/disables the specified exception.
+ * p_fm Pointer to the FMan module
+ * exception The exception to be selected.
+ * enable True to enable interrupt, false to mask it.
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_init().
+ */
+int fm_set_exception(struct fm_t *p_fm, enum fm_exceptions exception,
+ bool enable);
+
+/* fm_disable_rams_ecc
+ * 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.
+ * p_fm Pointer to the FMan module
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_config() and before fm_init().
+ */
+int fm_disable_rams_ecc(struct fm_t *p_fm);
+
+/* fm_get_revision
+ * Returns the FM revision
+ * p_fm - Pointer to the FMan module
+ * p_fm_revision_info - A structure of revision information parameters.
+ * Return 0 on success; Error code otherwise.
+ * Allowed only following fm_init().
+ */
+int fm_get_revision(struct fm_t *p_fm,
+ struct fm_revision_info_t *p_fm_revision_info);
+
+/* fm_error_isr
+ * FM interrupt-service-routine for errors.
+ * p_fm Pointer to the FMan module
+ * Return 0 on success; EMPTY if no errors found in register, other
+ * error code otherwise.
+ * Allowed only following fm_init().
+ */
+int fm_error_isr(struct fm_t *p_fm);
+
+/* fm_event_isr
+ * FM interrupt-service-routine for normal events.
+ * p_fm Pointer to the FMan module
+ * 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..cfbf462
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/* Linux internal kernel API */
+
+#ifndef __FSL_FMAN_DRV_H
+#define __FSL_FMAN_DRV_H
+
+#include <linux/types.h>
+#include <linux/device.h> /* struct device */
+
+/* FM device opaque structure used for type checking */
+struct fm;
+
+/* fm_bind
+ * Bind to a specific FM device.
+ *
+ * fm_dev - the OF handle of the FM device.
+ * Return A handle of the FM device.
+ * Allowed only after the port was created.
+ */
+struct fm *fm_bind(struct device *fm_dev);
+
+/* fm_unbind
+ * Un-bind from a specific FM device.
+ * fm - A handle of the FM device.
+ * Allowed only after the port was created.
+ */
+void fm_unbind(struct fm *fm);
+
+void *fm_get_handle(struct fm *fm);
+struct resource *fm_get_mem_region(struct fm *fm);
+
+/* fm_mutex_lock
+ *
+ * Lock function required before any FMD/LLD call.
+ */
+void fm_mutex_lock(void);
+
+/* fm_mutex_unlock
+ *
+ * Unlock function required after any FMD/LLD call.
+ */
+void fm_mutex_unlock(void);
+
+/* fm_get_max_frm
+ *
+ * Get the maximum frame size
+ */
+u16 fm_get_max_frm(void);
+
+/* fm_get_rx_extra_headroom
+ *
+ * Get the extra headroom size
+ */
+int fm_get_rx_extra_headroom(void);
+
+/* default values for initializing PTP 1588 timer clock */
+/* power of 2 for better performance */
+#define DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT 2
+/* 4ns,250MHz */
+#define DPA_PTP_NOMINAL_FREQ_PERIOD_NS \
+(1 << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT)
+
+#endif /* __FSL_FMAN_DRV_H */
diff --git a/drivers/net/ethernet/freescale/fman/inc/net_ext.h b/drivers/net/ethernet/freescale/fman/inc/net_ext.h
new file mode 100644
index 0000000..a05ace0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/net_ext.h
@@ -0,0 +1,534 @@
+/*
+ * 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.
+ */
+
+/* net_ext.h
+ * This file contains common and general headers definitions.
+ */
+#ifndef __NET_EXT_H
+#define __NET_EXT_H
+
+#define NET_HEADER_FIELD_PPP_PID (1)
+#define NET_HEADER_FIELD_PPP_COMPRESSED \
+(NET_HEADER_FIELD_PPP_PID << 1)
+#define NET_HEADER_FIELD_PPP_ALL_FIELDS \
+((NET_HEADER_FIELD_PPP_PID << 2) - 1)
+
+#define NET_HEADER_FIELD_PPPOE_VER (1)
+#define NET_HEADER_FIELD_PPPOE_TYPE \
+(NET_HEADER_FIELD_PPPOE_VER << 1)
+#define NET_HEADER_FIELD_PPPOE_CODE \
+(NET_HEADER_FIELD_PPPOE_VER << 2)
+#define NET_HEADER_FIELD_PPPOE_SID \
+(NET_HEADER_FIELD_PPPOE_VER << 3)
+#define NET_HEADER_FIELD_PPPOE_LEN \
+(NET_HEADER_FIELD_PPPOE_VER << 4)
+#define NET_HEADER_FIELD_PPPOE_SESSION \
+(NET_HEADER_FIELD_PPPOE_VER << 5)
+#define NET_HEADER_FIELD_PPPOE_PID \
+(NET_HEADER_FIELD_PPPOE_VER << 6)
+#define NET_HEADER_FIELD_PPPOE_ALL_FIELDS \
+((NET_HEADER_FIELD_PPPOE_VER << 7) - 1)
+
+#define NET_HEADER_FIELD_PPPMUX_PID (1)
+#define NET_HEADER_FIELD_PPPMUX_CKSUM \
+(NET_HEADER_FIELD_PPPMUX_PID << 1)
+#define NET_HEADER_FIELD_PPPMUX_COMPRESSED \
+(NET_HEADER_FIELD_PPPMUX_PID << 2)
+#define NET_HEADER_FIELD_PPPMUX_ALL_FIELDS \
+((NET_HEADER_FIELD_PPPMUX_PID << 3) - 1)
+
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT \
+(NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN \
+(NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID \
+(NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID \
+(NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS \
+((NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1)
+
+#define NET_HEADER_FIELD_ETH_DA (1)
+#define NET_HEADER_FIELD_ETH_SA \
+(NET_HEADER_FIELD_ETH_DA << 1)
+#define NET_HEADER_FIELD_ETH_LENGTH \
+(NET_HEADER_FIELD_ETH_DA << 2)
+#define NET_HEADER_FIELD_ETH_TYPE \
+(NET_HEADER_FIELD_ETH_DA << 3)
+#define NET_HEADER_FIELD_ETH_FINAL_CKSUM \
+(NET_HEADER_FIELD_ETH_DA << 4)
+#define NET_HEADER_FIELD_ETH_PADDING \
+(NET_HEADER_FIELD_ETH_DA << 5)
+#define NET_HEADER_FIELD_ETH_ALL_FIELDS \
+((NET_HEADER_FIELD_ETH_DA << 6) - 1)
+
+#define NET_HEADER_FIELD_ETH_ADDR_SIZE 6
+
+#define NET_HEADER_FIELD_IP_VER (1)
+#define NET_HEADER_FIELD_IP_DSCP \
+(NET_HEADER_FIELD_IP_VER << 2)
+#define NET_HEADER_FIELD_IP_ECN \
+(NET_HEADER_FIELD_IP_VER << 3)
+#define NET_HEADER_FIELD_IP_PROTO \
+(NET_HEADER_FIELD_IP_VER << 4)
+
+#define NET_HEADER_FIELD_IP_PROTO_SIZE 1
+
+#define NET_HEADER_FIELD_IPV4_VER (1)
+#define NET_HEADER_FIELD_IPV4_HDR_LEN \
+(NET_HEADER_FIELD_IPV4_VER << 1)
+#define NET_HEADER_FIELD_IPV4_TOS \
+(NET_HEADER_FIELD_IPV4_VER << 2)
+#define NET_HEADER_FIELD_IPV4_TOTAL_LEN \
+(NET_HEADER_FIELD_IPV4_VER << 3)
+#define NET_HEADER_FIELD_IPV4_ID \
+(NET_HEADER_FIELD_IPV4_VER << 4)
+#define NET_HEADER_FIELD_IPV4_FLAG_D \
+(NET_HEADER_FIELD_IPV4_VER << 5)
+#define NET_HEADER_FIELD_IPV4_FLAG_M \
+(NET_HEADER_FIELD_IPV4_VER << 6)
+#define NET_HEADER_FIELD_IPV4_OFFSET \
+(NET_HEADER_FIELD_IPV4_VER << 7)
+#define NET_HEADER_FIELD_IPV4_TTL \
+(NET_HEADER_FIELD_IPV4_VER << 8)
+#define NET_HEADER_FIELD_IPV4_PROTO \
+(NET_HEADER_FIELD_IPV4_VER << 9)
+#define NET_HEADER_FIELD_IPV4_CKSUM \
+(NET_HEADER_FIELD_IPV4_VER << 10)
+#define NET_HEADER_FIELD_IPV4_SRC_IP \
+(NET_HEADER_FIELD_IPV4_VER << 11)
+#define NET_HEADER_FIELD_IPV4_DST_IP \
+(NET_HEADER_FIELD_IPV4_VER << 12)
+#define NET_HEADER_FIELD_IPV4_OPTS \
+(NET_HEADER_FIELD_IPV4_VER << 13)
+#define NET_HEADER_FIELD_IPV4_OPTS_COUNT \
+(NET_HEADER_FIELD_IPV4_VER << 14)
+#define NET_HEADER_FIELD_IPV4_ALL_FIELDS \
+((NET_HEADER_FIELD_IPV4_VER << 15) - 1)
+
+#define NET_HEADER_FIELD_IPV4_ADDR_SIZE 4
+#define NET_HEADER_FIELD_IPV4_PROTO_SIZE 1
+
+#define NET_HEADER_FIELD_IPV6_VER (1)
+#define NET_HEADER_FIELD_IPV6_TC \
+(NET_HEADER_FIELD_IPV6_VER << 1)
+#define NET_HEADER_FIELD_IPV6_SRC_IP \
+(NET_HEADER_FIELD_IPV6_VER << 2)
+#define NET_HEADER_FIELD_IPV6_DST_IP \
+(NET_HEADER_FIELD_IPV6_VER << 3)
+#define NET_HEADER_FIELD_IPV6_NEXT_HDR \
+(NET_HEADER_FIELD_IPV6_VER << 4)
+#define NET_HEADER_FIELD_IPV6_FL \
+(NET_HEADER_FIELD_IPV6_VER << 5)
+#define NET_HEADER_FIELD_IPV6_HOP_LIMIT \
+(NET_HEADER_FIELD_IPV6_VER << 6)
+#define NET_HEADER_FIELD_IPV6_ALL_FIELDS \
+((NET_HEADER_FIELD_IPV6_VER << 7) - 1)
+
+#define NET_HEADER_FIELD_IPV6_ADDR_SIZE 16
+#define NET_HEADER_FIELD_IPV6_NEXT_HDR_SIZE 1
+
+#define NET_HEADER_FIELD_ICMP_TYPE (1)
+#define NET_HEADER_FIELD_ICMP_CODE \
+(NET_HEADER_FIELD_ICMP_TYPE << 1)
+#define NET_HEADER_FIELD_ICMP_CKSUM \
+(NET_HEADER_FIELD_ICMP_TYPE << 2)
+#define NET_HEADER_FIELD_ICMP_ID \
+(NET_HEADER_FIELD_ICMP_TYPE << 3)
+#define NET_HEADER_FIELD_ICMP_SQ_NUM \
+(NET_HEADER_FIELD_ICMP_TYPE << 4)
+#define NET_HEADER_FIELD_ICMP_ALL_FIELDS \
+((NET_HEADER_FIELD_ICMP_TYPE << 5) - 1)
+
+#define NET_HEADER_FIELD_ICMP_CODE_SIZE 1
+#define NET_HEADER_FIELD_ICMP_TYPE_SIZE 1
+
+#define NET_HEADER_FIELD_IGMP_VERSION (1)
+#define NET_HEADER_FIELD_IGMP_TYPE \
+(NET_HEADER_FIELD_IGMP_VERSION << 1)
+#define NET_HEADER_FIELD_IGMP_CKSUM \
+(NET_HEADER_FIELD_IGMP_VERSION << 2)
+#define NET_HEADER_FIELD_IGMP_DATA \
+(NET_HEADER_FIELD_IGMP_VERSION << 3)
+#define NET_HEADER_FIELD_IGMP_ALL_FIELDS \
+((NET_HEADER_FIELD_IGMP_VERSION << 4) - 1)
+
+#define NET_HEADER_FIELD_TCP_PORT_SRC (1)
+#define NET_HEADER_FIELD_TCP_PORT_DST \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_TCP_SEQ \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_TCP_ACK \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_TCP_OFFSET \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 4)
+#define NET_HEADER_FIELD_TCP_FLAGS \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 5)
+#define NET_HEADER_FIELD_TCP_WINDOW \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 6)
+#define NET_HEADER_FIELD_TCP_CKSUM \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 7)
+#define NET_HEADER_FIELD_TCP_URGPTR \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 8)
+#define NET_HEADER_FIELD_TCP_OPTS \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 9)
+#define NET_HEADER_FIELD_TCP_OPTS_COUNT \
+(NET_HEADER_FIELD_TCP_PORT_SRC << 10)
+#define NET_HEADER_FIELD_TCP_ALL_FIELDS \
+((NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1)
+
+#define NET_HEADER_FIELD_TCP_PORT_SIZE 2
+
+#define NET_HEADER_FIELD_SCTP_PORT_SRC (1)
+#define NET_HEADER_FIELD_SCTP_PORT_DST \
+(NET_HEADER_FIELD_SCTP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_SCTP_VER_TAG \
+(NET_HEADER_FIELD_SCTP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_SCTP_CKSUM \
+(NET_HEADER_FIELD_SCTP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_SCTP_ALL_FIELDS \
+((NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1)
+
+#define NET_HEADER_FIELD_SCTP_PORT_SIZE 2
+
+#define NET_HEADER_FIELD_DCCP_PORT_SRC (1)
+#define NET_HEADER_FIELD_DCCP_PORT_DST \
+(NET_HEADER_FIELD_DCCP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_DCCP_ALL_FIELDS \
+((NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1)
+
+#define NET_HEADER_FIELD_DCCP_PORT_SIZE 2
+
+#define NET_HEADER_FIELD_UDP_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_PORT_DST \
+(NET_HEADER_FIELD_UDP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_LEN \
+(NET_HEADER_FIELD_UDP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_UDP_CKSUM \
+(NET_HEADER_FIELD_UDP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_UDP_ALL_FIELDS \
+((NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1)
+
+#define NET_HEADER_FIELD_UDP_PORT_SIZE 2
+
+#define NET_HEADER_FIELD_UDP_LITE_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_LITE_PORT_DST \
+(NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS \
+((NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1)
+
+#define NET_HEADER_FIELD_UDP_LITE_PORT_SIZE 2
+
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST \
+(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN \
+(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM \
+(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI \
+(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM \
+(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS \
+((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1)
+
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE 2
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE 4
+
+#define NET_HEADER_FIELD_IPHC_CID (1)
+#define NET_HEADER_FIELD_IPHC_CID_TYPE \
+(NET_HEADER_FIELD_IPHC_CID << 1)
+#define NET_HEADER_FIELD_IPHC_HCINDEX \
+(NET_HEADER_FIELD_IPHC_CID << 2)
+#define NET_HEADER_FIELD_IPHC_GEN \
+(NET_HEADER_FIELD_IPHC_CID << 3)
+#define NET_HEADER_FIELD_IPHC_D_BIT \
+(NET_HEADER_FIELD_IPHC_CID << 4)
+#define NET_HEADER_FIELD_IPHC_ALL_FIELDS \
+((NET_HEADER_FIELD_IPHC_CID << 5) - 1)
+
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_END \
+(NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS \
+((NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1)
+
+#define NET_HEADER_FIELD_L2TPV2_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPV2_LENGTH_BIT \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPV2_SEQUENCE_BIT \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPV2_OFFSET_BIT \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPV2_PRIORITY_BIT \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 4)
+#define NET_HEADER_FIELD_L2TPV2_VERSION \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 5)
+#define NET_HEADER_FIELD_L2TPV2_LEN \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 6)
+#define NET_HEADER_FIELD_L2TPV2_TUNNEL_ID \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 7)
+#define NET_HEADER_FIELD_L2TPV2_SESSION_ID \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 8)
+#define NET_HEADER_FIELD_L2TPV2_NS \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 9)
+#define NET_HEADER_FIELD_L2TPV2_NR \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 10)
+#define NET_HEADER_FIELD_L2TPV2_OFFSET_SIZE \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 11)
+#define NET_HEADER_FIELD_L2TPV2_FIRST_BYTE \
+(NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 12)
+#define NET_HEADER_FIELD_L2TPV2_ALL_FIELDS \
+((NET_HEADER_FIELD_L2TPV2_TYPE_BIT << 13) - 1)
+
+#define NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_LENGTH_BIT \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_SEQUENCE_BIT \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_VERSION \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_LENGTH \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 4)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_CONTROL \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 5)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_SENT \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 6)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_RECV \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 7)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_FIRST_BYTE \
+(NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 8)
+#define NET_HEADER_FIELD_L2TPV3_CTRL_ALL_FIELDS \
+((NET_HEADER_FIELD_L2TPV3_CTRL_TYPE_BIT << 9) - 1)
+
+#define NET_HEADER_FIELD_L2TPV3_SESS_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPV3_SESS_VERSION \
+(NET_HEADER_FIELD_L2TPV3_SESS_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPV3_SESS_ID \
+(NET_HEADER_FIELD_L2TPV3_SESS_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPV3_SESS_COOKIE \
+(NET_HEADER_FIELD_L2TPV3_SESS_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPV3_SESS_ALL_FIELDS \
+((NET_HEADER_FIELD_L2TPV3_SESS_TYPE_BIT << 4) - 1)
+
+#define NET_HEADER_FIELD_VLAN_VPRI (1)
+#define NET_HEADER_FIELD_VLAN_CFI \
+(NET_HEADER_FIELD_VLAN_VPRI << 1)
+#define NET_HEADER_FIELD_VLAN_VID \
+(NET_HEADER_FIELD_VLAN_VPRI << 2)
+#define NET_HEADER_FIELD_VLAN_LENGTH \
+(NET_HEADER_FIELD_VLAN_VPRI << 3)
+#define NET_HEADER_FIELD_VLAN_TYPE \
+(NET_HEADER_FIELD_VLAN_VPRI << 4)
+#define NET_HEADER_FIELD_VLAN_ALL_FIELDS \
+((NET_HEADER_FIELD_VLAN_VPRI << 5) - 1)
+
+#define NET_HEADER_FIELD_VLAN_TCI \
+(NET_HEADER_FIELD_VLAN_VPRI | \
+NET_HEADER_FIELD_VLAN_CFI | \
+NET_HEADER_FIELD_VLAN_VID)
+
+#define NET_HEADER_FIELD_LLC_DSAP (1)
+#define NET_HEADER_FIELD_LLC_SSAP \
+(NET_HEADER_FIELD_LLC_DSAP << 1)
+#define NET_HEADER_FIELD_LLC_CTRL \
+(NET_HEADER_FIELD_LLC_DSAP << 2)
+#define NET_HEADER_FIELD_LLC_ALL_FIELDS \
+((NET_HEADER_FIELD_LLC_DSAP << 3) - 1)
+
+#define NET_HEADER_FIELD_NLPID_NLPID (1)
+#define NET_HEADER_FIELD_NLPID_ALL_FIELDS \
+((NET_HEADER_FIELD_NLPID_NLPID << 1) - 1)
+
+#define NET_HEADER_FIELD_SNAP_OUI (1)
+#define NET_HEADER_FIELD_SNAP_PID \
+(NET_HEADER_FIELD_SNAP_OUI << 1)
+#define NET_HEADER_FIELD_SNAP_ALL_FIELDS \
+((NET_HEADER_FIELD_SNAP_OUI << 2) - 1)
+
+#define NET_HEADER_FIELD_LLC_SNAP_TYPE (1)
+#define NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS \
+((NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1)
+
+#define NET_HEADER_FIELD_ARP_HTYPE (1)
+#define NET_HEADER_FIELD_ARP_PTYPE \
+(NET_HEADER_FIELD_ARP_HTYPE << 1)
+#define NET_HEADER_FIELD_ARP_HLEN \
+(NET_HEADER_FIELD_ARP_HTYPE << 2)
+#define NET_HEADER_FIELD_ARP_PLEN \
+(NET_HEADER_FIELD_ARP_HTYPE << 3)
+#define NET_HEADER_FIELD_ARP_OPER \
+(NET_HEADER_FIELD_ARP_HTYPE << 4)
+#define NET_HEADER_FIELD_ARP_SHA \
+(NET_HEADER_FIELD_ARP_HTYPE << 5)
+#define NET_HEADER_FIELD_ARP_SPA \
+(NET_HEADER_FIELD_ARP_HTYPE << 6)
+#define NET_HEADER_FIELD_ARP_THA \
+(NET_HEADER_FIELD_ARP_HTYPE << 7)
+#define NET_HEADER_FIELD_ARP_TPA \
+(NET_HEADER_FIELD_ARP_HTYPE << 8)
+#define NET_HEADER_FIELD_ARP_ALL_FIELDS \
+((NET_HEADER_FIELD_ARP_HTYPE << 9) - 1)
+
+#define NET_HEADER_FIELD_RFC2684_LLC (1)
+#define NET_HEADER_FIELD_RFC2684_NLPID \
+(NET_HEADER_FIELD_RFC2684_LLC << 1)
+#define NET_HEADER_FIELD_RFC2684_OUI \
+(NET_HEADER_FIELD_RFC2684_LLC << 2)
+#define NET_HEADER_FIELD_RFC2684_PID \
+(NET_HEADER_FIELD_RFC2684_LLC << 3)
+#define NET_HEADER_FIELD_RFC2684_VPN_OUI \
+(NET_HEADER_FIELD_RFC2684_LLC << 4)
+#define NET_HEADER_FIELD_RFC2684_VPN_IDX \
+(NET_HEADER_FIELD_RFC2684_LLC << 5)
+#define NET_HEADER_FIELD_RFC2684_ALL_FIELDS \
+((NET_HEADER_FIELD_RFC2684_LLC << 6) - 1)
+
+#define NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1)
+#define NET_HEADER_FIELD_USER_DEFINED_PCDID \
+(NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1)
+#define NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS \
+((NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1)
+
+#define NET_HEADER_FIELD_PAYLOAD_BUFFER (1)
+#define NET_HEADER_FIELD_PAYLOAD_SIZE \
+(NET_HEADER_FIELD_PAYLOAD_BUFFER << 1)
+#define NET_HEADER_FIELD_MAX_FRM_SIZE \
+(NET_HEADER_FIELD_PAYLOAD_BUFFER << 2)
+#define NET_HEADER_FIELD_MIN_FRM_SIZE \
+(NET_HEADER_FIELD_PAYLOAD_BUFFER << 3)
+#define NET_HEADER_FIELD_PAYLOAD_TYPE \
+(NET_HEADER_FIELD_PAYLOAD_BUFFER << 4)
+#define NET_HEADER_FIELD_FRAME_SIZE \
+(NET_HEADER_FIELD_PAYLOAD_BUFFER << 5)
+#define NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS \
+((NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1)
+
+#define NET_HEADER_FIELD_GRE_TYPE (1)
+#define NET_HEADER_FIELD_GRE_ALL_FIELDS \
+((NET_HEADER_FIELD_GRE_TYPE << 1) - 1)
+
+#define NET_HEADER_FIELD_MINENCAP_SRC_IP (1)
+#define NET_HEADER_FIELD_MINENCAP_DST_IP \
+(NET_HEADER_FIELD_MINENCAP_SRC_IP << 1)
+#define NET_HEADER_FIELD_MINENCAP_TYPE \
+(NET_HEADER_FIELD_MINENCAP_SRC_IP << 2)
+#define NET_HEADER_FIELD_MINENCAP_ALL_FIELDS \
+((NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1)
+
+#define NET_HEADER_FIELD_IPSEC_AH_NH \
+(NET_HEADER_FIELD_IPSEC_AH_SPI << 1)
+#define NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS \
+((NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1)
+
+#define NET_HEADER_FIELD_IPSEC_ESP_SPI (1)
+#define NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM \
+(NET_HEADER_FIELD_IPSEC_ESP_SPI << 1)
+#define NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS \
+((NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1)
+
+#define NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE 4
+
+#define NET_HEADER_FIELD_MPLS_LABEL_STACK (1)
+#define NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS \
+((NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1)
+
+#define NET_HEADER_FIELD_MACSEC_SECTAG (1)
+#define NET_HEADER_FIELD_MACSEC_ALL_FIELDS \
+((NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1)
+
+enum net_header_type {
+ HEADER_TYPE_NONE = 0,
+ HEADER_TYPE_PAYLOAD,
+ HEADER_TYPE_ETH,
+ HEADER_TYPE_VLAN,
+ HEADER_TYPE_IPV4,
+ HEADER_TYPE_IPV6,
+ HEADER_TYPE_IP,
+ HEADER_TYPE_TCP,
+ HEADER_TYPE_UDP,
+ HEADER_TYPE_UDP_LITE,
+ HEADER_TYPE_IPHC,
+ HEADER_TYPE_SCTP,
+ HEADER_TYPE_SCTP_CHUNK_DATA,
+ HEADER_TYPE_PPPOE,
+ HEADER_TYPE_PPP,
+ HEADER_TYPE_PPPMUX,
+ HEADER_TYPE_PPPMUX_SUBFRAME,
+ HEADER_TYPE_L2TPV2,
+ HEADER_TYPE_L2TPV3_CTRL,
+ HEADER_TYPE_L2TPV3_SESS,
+ HEADER_TYPE_LLC,
+ HEADER_TYPE_LLC_SNAP,
+ HEADER_TYPE_NLPID,
+ HEADER_TYPE_SNAP,
+ HEADER_TYPE_MPLS,
+ HEADER_TYPE_IPSEC_AH,
+ HEADER_TYPE_IPSEC_ESP,
+ HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */
+ HEADER_TYPE_MACSEC,
+ HEADER_TYPE_GRE,
+ HEADER_TYPE_MINENCAP,
+ HEADER_TYPE_DCCP,
+ HEADER_TYPE_ICMP,
+ HEADER_TYPE_IGMP,
+ HEADER_TYPE_ARP,
+ HEADER_TYPE_CAPWAP,
+ HEADER_TYPE_CAPWAP_DTLS,
+ HEADER_TYPE_RFC2684,
+ HEADER_TYPE_USER_DEFINED_L2,
+ HEADER_TYPE_USER_DEFINED_L3,
+ HEADER_TYPE_USER_DEFINED_L4,
+ HEADER_TYPE_USER_DEFINED_SHIM1,
+ HEADER_TYPE_USER_DEFINED_SHIM2,
+ MAX_HEADER_TYPE_COUNT
+};
+
+#endif /* __NET_EXT_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..7311d10
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/service.h
@@ -0,0 +1,90 @@
+/*
+ * 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))
+
+/* Ceiling division - not the fastest way, but safer in terms of overflow */
+#define DIV_CEIL(x, y) \
+ ((div64_u64(x, y)) + (((((div64_u64(x, y))) * (y)) == (x)) ? 0 : 1))
+
+/* Round up a number to be a multiple of a second number */
+#define ROUND_UP(x, y) ((((x) + (y) - 1) / (y)) * (y))
+
+#define PTR_TO_UINT(_ptr) ((uintptr_t)(_ptr))
+#define UINT_TO_PTR(_val) ((void __iomem *)(uintptr_t)(_val))
+#define PTR_MOVE(_ptr, _offset) (void *)((uint8_t *)(_ptr) + (_offset))
+
+/* memory access macros */
+#define GET_UINT8(arg) in_be8(&(arg))
+#define GET_UINT16(arg) in_be16(&(arg))
+#define GET_UINT32(arg) in_be32(&(arg))
+#define GET_UINT64(arg) (*(__iomem uint64_t *)(&(arg)))
+
+#define WRITE_UINT8(arg, data) out_be8(&(arg), data)
+#define WRITE_UINT16(arg, data) out_be16(&(arg), data)
+#define WRITE_UINT32(arg, data) out_be32(&(arg), data)
+#define WRITE_UINT64(arg, data) (*(__iomem uint64_t *)(&(arg)) = (data))
+
+/* Timing macro for converting usec units to number of ticks
+ * (number of usec* clock_Hz) / 1,000,000) - since clk is in MHz units,
+ * no division needed.
+ */
+#define USEC_TO_CLK(usec, clk) ((usec) * (clk))
+#define CYCLES_TO_USEC(cycles, clk) ((cycles) / (clk))
+
+#define ILLEGAL_BASE (~0)
+
+/* Enumeration (bit flags) of communication modes (Transmit,
+ * receive or both).
+ */
+enum comm_mode {
+ COMM_MODE_NONE = 0, /* No transmit/receive communication */
+ COMM_MODE_RX = 1, /* Only receive communication */
+ COMM_MODE_TX = 2, /* Only transmit communication */
+ COMM_MODE_RX_AND_TX = 3 /*Both transmit and receive communication*/
+};
+
+#endif /* SERVICE */
--
1.7.11.7
From: Igal Liberman <[email protected]>
The FMan FLib provides the basic API used by the FMan drivers to
configure and control the FMan hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/Kconfig | 1 +
drivers/net/ethernet/freescale/Makefile | 2 +
drivers/net/ethernet/freescale/fman/Kconfig | 7 +
drivers/net/ethernet/freescale/fman/Makefile | 5 +
drivers/net/ethernet/freescale/fman/fman.c | 973 +++++++++++++++++++++++++++
5 files changed, 988 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/Kconfig
create mode 100644 drivers/net/ethernet/freescale/fman/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/fman.c
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 25e3425..24e938d 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -55,6 +55,7 @@ config FEC_MPC52xx_MDIO
If compiled as module, it will be called fec_mpc52xx_phy.
source "drivers/net/ethernet/freescale/fs_enet/Kconfig"
+source "drivers/net/ethernet/freescale/fman/Kconfig"
config FSL_PQ_MDIO
tristate "Freescale PQ MDIO"
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 71debd1..4097c58 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -17,3 +17,5 @@ gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
+
+obj-$(CONFIG_FSL_FMAN) += fman/
diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig
new file mode 100644
index 0000000..8aeae29
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -0,0 +1,7 @@
+config FSL_FMAN
+ bool "FMan support"
+ depends on FSL_SOC || COMPILE_TEST
+ default n
+ help
+ Freescale Data-Path Acceleration Architecture Frame Manager
+ (FMan) support
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
new file mode 100644
index 0000000..2799c6f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -0,0 +1,5 @@
+subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman/flib
+
+obj-y += fsl_fman.o
+
+fsl_fman-objs := fman.o
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
new file mode 100644
index 0000000..410c498
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -0,0 +1,973 @@
+/*
+ * 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 "fsl_fman.h"
+
+uint32_t fman_get_bmi_err_event(struct fman_bmi_regs __iomem *bmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&bmi_rg->fmbm_ievr);
+ mask = ioread32be(&bmi_rg->fmbm_ier);
+ event &= mask;
+ /* clear the forced events */
+ force = ioread32be(&bmi_rg->fmbm_ifr);
+ if (force & event)
+ iowrite32be(force & ~event, &bmi_rg->fmbm_ifr);
+ /* clear the acknowledged events */
+ iowrite32be(event, &bmi_rg->fmbm_ievr);
+ return event;
+}
+
+uint32_t fman_get_qmi_err_event(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&qmi_rg->fmqm_eie);
+ mask = ioread32be(&qmi_rg->fmqm_eien);
+ event &= mask;
+
+ /* clear the forced events */
+ force = ioread32be(&qmi_rg->fmqm_eif);
+ if (force & event)
+ iowrite32be(force & ~event, &qmi_rg->fmqm_eif);
+ /* clear the acknowledged events */
+ iowrite32be(event, &qmi_rg->fmqm_eie);
+ return event;
+}
+
+uint32_t fman_get_dma_com_id(struct fman_dma_regs __iomem *dma_rg)
+{
+ return ioread32be(&dma_rg->fmdmtcid);
+}
+
+uint64_t fman_get_dma_addr(struct fman_dma_regs __iomem *dma_rg)
+{
+ uint64_t addr;
+
+ addr = (uint64_t)ioread32be(&dma_rg->fmdmtal);
+ addr |= ((uint64_t)(ioread32be(&dma_rg->fmdmtah)) << 32);
+
+ return addr;
+}
+
+uint32_t fman_get_dma_err_event(struct fman_dma_regs __iomem *dma_rg)
+{
+ uint32_t status, mask;
+
+ status = ioread32be(&dma_rg->fmdmsr);
+ mask = ioread32be(&dma_rg->fmdmmr);
+
+ /* clear DMA_STATUS_BUS_ERR if mask has no DMA_MODE_BER */
+ if ((mask & DMA_MODE_BER) != DMA_MODE_BER)
+ status &= ~DMA_STATUS_BUS_ERR;
+
+ /* clear relevant bits if mask has no DMA_MODE_ECC */
+ if ((mask & DMA_MODE_ECC) != DMA_MODE_ECC)
+ status &= ~(DMA_STATUS_FM_SPDAT_ECC |
+ DMA_STATUS_READ_ECC |
+ DMA_STATUS_SYSTEM_WRITE_ECC |
+ DMA_STATUS_FM_WRITE_ECC);
+
+ /* clear set events */
+ iowrite32be(status, &dma_rg->fmdmsr);
+
+ return status;
+}
+
+uint32_t fman_get_fpm_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t event;
+
+ event = ioread32be(&fpm_rg->fmfp_ee);
+ /* clear the all occurred events */
+ iowrite32be(event, &fpm_rg->fmfp_ee);
+ return event;
+}
+
+uint32_t fman_get_muram_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t event, mask;
+
+ event = ioread32be(&fpm_rg->fm_rcr);
+ mask = ioread32be(&fpm_rg->fm_rie);
+
+ /* clear MURAM event bit (do not clear IRAM event) */
+ iowrite32be(event & ~FPM_RAM_IRAM_ECC, &fpm_rg->fm_rcr);
+
+ if ((mask & FPM_MURAM_ECC_ERR_EX_EN))
+ return event;
+ else
+ return 0;
+}
+
+uint32_t fman_get_iram_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t event, mask;
+
+ event = ioread32be(&fpm_rg->fm_rcr);
+ mask = ioread32be(&fpm_rg->fm_rie);
+ /* clear IRAM event bit (do not clear MURAM event) */
+ iowrite32be(event & ~FPM_RAM_MURAM_ECC, &fpm_rg->fm_rcr);
+
+ if ((mask & FPM_IRAM_ECC_ERR_EX_EN))
+ return event;
+ else
+ return 0;
+}
+
+uint32_t fman_get_qmi_event(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&qmi_rg->fmqm_ie);
+ mask = ioread32be(&qmi_rg->fmqm_ien);
+ event &= mask;
+ /* clear the forced events */
+ force = ioread32be(&qmi_rg->fmqm_if);
+ if (force & event)
+ iowrite32be(force & ~event, &qmi_rg->fmqm_if);
+ /* clear the acknowledged events */
+ iowrite32be(event, &qmi_rg->fmqm_ie);
+ return event;
+}
+
+void fman_enable_time_stamp(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t count1ubit, uint16_t fm_clk_freq)
+{
+ uint32_t tmp;
+ uint64_t frac;
+ uint32_t intgr;
+ uint32_t ts_freq = (uint32_t)(1 << count1ubit); /* in Mhz */
+
+ /* configure timestamp so that bit 8 will count 1 microsecond
+ * Find effective count rate at TIMESTAMP least significant bits:
+ * Effective_Count_Rate = 1MHz x 2^8 = 256MHz
+ * Find frequency ratio between effective count rate and the clock:
+ * Effective_Count_Rate / CLK e.g. for 600 MHz clock:
+ * 256/600 = 0.4266666...
+ */
+
+ intgr = ts_freq / fm_clk_freq;
+ /* we multiply by 2^16 to keep the fraction of the division
+ * we do not div back, since we write this value as a fraction
+ * see spec
+ */
+
+ frac = ((ts_freq << 16) - (intgr << 16) * fm_clk_freq) / fm_clk_freq;
+ /* we check remainder of the division in order to round up if not int */
+ if (((ts_freq << 16) - (intgr << 16) * fm_clk_freq) % fm_clk_freq)
+ frac++;
+
+ tmp = (intgr << FPM_TS_INT_SHIFT) | (uint16_t)frac;
+ iowrite32be(tmp, &fpm_rg->fmfp_tsc2);
+
+ /* enable timestamp with original clock */
+ iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1);
+}
+
+uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_epi);
+}
+
+int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ int timeout = 100;
+
+ iowrite32be(0x40000000, &fpm_rg->fmfp_extc);
+
+ while ((ioread32be(&fpm_rg->fmfp_extc) & 0x40000000) && --timeout)
+ usleep_range(10, 11);
+
+ if (!timeout)
+ return -EIO;
+ return 0;
+}
+
+void fman_set_order_restoration_per_port(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t port_id, bool is_rx_port)
+{
+ uint32_t tmp = 0;
+
+ tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT);
+
+ tmp |= (FPM_PRT_FM_CTL2 | FPM_PRT_FM_CTL1);
+
+ /* order restoration */
+ if (port_id % 2)
+ tmp |= (FPM_PRT_FM_CTL1 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
+ else
+ tmp |= (FPM_PRT_FM_CTL2 << FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
+
+ iowrite32be(tmp, &fpm_rg->fmfp_prc);
+}
+
+uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ return (uint8_t)ioread32be(&qmi_rg->fmqm_gc);
+}
+
+uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ return (uint8_t)(ioread32be(&qmi_rg->fmqm_gc) >> 8);
+}
+
+void fman_set_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg, uint8_t val)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_ENQ_MASK;
+ tmp_reg |= ((uint32_t)val << 8);
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_set_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg, uint8_t val)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_DEQ_MASK;
+ tmp_reg |= (uint32_t)val;
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_set_liodn_per_port(struct fman_rg *fman_rg, uint8_t port_id,
+ uint16_t liodn_base, uint16_t liodn_ofst)
+{
+ uint32_t tmp;
+
+ /* set LIODN base for this port */
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmplr[port_id / 2]);
+ if (port_id % 2) {
+ tmp &= ~FM_LIODN_BASE_MASK;
+ tmp |= (uint32_t)liodn_base;
+ } else {
+ tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT);
+ tmp |= (uint32_t)liodn_base << DMA_LIODN_SHIFT;
+ }
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]);
+ iowrite32be((uint32_t)liodn_ofst,
+ &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]);
+}
+
+int fman_reset_mac(struct fman_fpm_regs __iomem *fpm_rg, uint8_t mac_id)
+{
+ uint32_t msk, timeout = 100;
+
+ /* Get the relevant bit mask */
+ switch (mac_id) {
+ case 0:
+ msk = FPM_RSTC_MAC0_RESET;
+ break;
+ case 1:
+ msk = FPM_RSTC_MAC1_RESET;
+ break;
+ case 2:
+ msk = FPM_RSTC_MAC2_RESET;
+ break;
+ case 3:
+ msk = FPM_RSTC_MAC3_RESET;
+ break;
+ case 4:
+ msk = FPM_RSTC_MAC4_RESET;
+ break;
+ case 5:
+ msk = FPM_RSTC_MAC5_RESET;
+ break;
+ case 6:
+ msk = FPM_RSTC_MAC6_RESET;
+ break;
+ case 7:
+ msk = FPM_RSTC_MAC7_RESET;
+ break;
+ case 8:
+ msk = FPM_RSTC_MAC8_RESET;
+ break;
+ case 9:
+ msk = FPM_RSTC_MAC9_RESET;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* reset */
+ iowrite32be(msk, &fpm_rg->fm_rstc);
+ while ((ioread32be(&fpm_rg->fm_rstc) & msk) && --timeout)
+ usleep_range(10, 11);
+
+ if (!timeout)
+ return -EIO;
+ return 0;
+}
+
+uint16_t fman_get_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]);
+ return (uint16_t)((tmp_reg & BMI_FIFO_SIZE_MASK) + 1);
+}
+
+uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]);
+ return (uint16_t)((tmp_reg & BMI_EXTRA_FIFO_SIZE_MASK) >>
+ BMI_EXTRA_FIFO_SIZE_SHIFT);
+}
+
+void fman_set_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id, uint32_t sz_fifo,
+ uint32_t extra_sz_fifo)
+{
+ uint32_t tmp;
+
+ /* calculate reg */
+ tmp = (uint32_t)((sz_fifo / FMAN_BMI_FIFO_UNITS - 1) |
+ ((extra_sz_fifo / FMAN_BMI_FIFO_UNITS) <<
+ BMI_EXTRA_FIFO_SIZE_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pfs[port_id - 1]);
+}
+
+uint8_t fman_get_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >>
+ BMI_NUM_OF_TASKS_SHIFT) + 1);
+}
+
+uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >>
+ BMI_EXTRA_NUM_OF_TASKS_SHIFT);
+}
+
+void fman_set_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id, uint8_t num_tasks,
+ uint8_t num_extra_tasks)
+{
+ uint32_t tmp;
+
+ /* calculate reg */
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
+ ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK);
+ tmp |= ((uint32_t)((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) |
+ (uint32_t)(num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
+}
+
+uint8_t fman_get_num_of_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)(((tmp & BMI_NUM_OF_DMAS_MASK) >>
+ BMI_NUM_OF_DMAS_SHIFT) + 1);
+}
+
+uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_DMAS_MASK) >>
+ BMI_EXTRA_NUM_OF_DMAS_SHIFT);
+}
+
+void fman_set_num_of_open_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ uint8_t port_id, uint8_t num_open_dmas,
+ uint8_t num_extra_open_dmas,
+ uint8_t total_num_dmas)
+{
+ uint32_t tmp = 0;
+
+ /* calculate reg */
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
+ ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK);
+ tmp |= (uint32_t)(((num_open_dmas - 1) << BMI_NUM_OF_DMAS_SHIFT) |
+ (num_extra_open_dmas <<
+ BMI_EXTRA_NUM_OF_DMAS_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
+
+ /* update total num of DMA's with committed number of open DMAS,
+ * and max uncommitted pool.
+ */
+ if (total_num_dmas) {
+ tmp = ioread32be(&bmi_rg->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK;
+ tmp |= (uint32_t)(total_num_dmas - 1) << BMI_CFG2_DMAS_SHIFT;
+ iowrite32be(tmp, &bmi_rg->fmbm_cfg2);
+ }
+}
+
+/* API Init unit functions */
+
+void fman_defconfig(struct fman_cfg *cfg)
+{
+ memset(cfg, 0, sizeof(struct fman_cfg));
+
+ cfg->catastrophic_err = DEFAULT_CATASTROPHIC_ERR;
+ cfg->dma_err = DEFAULT_DMA_ERR;
+ cfg->halt_on_external_activ = DEFAULT_HALT_ON_EXTERNAL_ACTIVATION;
+ cfg->halt_on_unrecov_ecc_err = DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR;
+ cfg->en_iram_test_mode = false;
+ cfg->en_muram_test_mode = false;
+ cfg->external_ecc_rams_enable = DEFAULT_EXTERNAL_ECC_RAMS_ENABLE;
+
+ cfg->dma_aid_override = DEFAULT_AID_OVERRIDE;
+ cfg->dma_aid_mode = DEFAULT_AID_MODE;
+ cfg->dma_comm_qtsh_clr_emer = DEFAULT_DMA_COMM_Q_LOW;
+ cfg->dma_comm_qtsh_asrt_emer = DEFAULT_DMA_COMM_Q_HIGH;
+ cfg->dma_cache_override = DEFAULT_CACHE_OVERRIDE;
+ cfg->dma_cam_num_of_entries = DEFAULT_DMA_CAM_NUM_OF_ENTRIES;
+ cfg->dma_dbg_cnt_mode = DEFAULT_DMA_DBG_CNT_MODE;
+ cfg->dma_en_emergency = DEFAULT_DMA_EN_EMERGENCY;
+ cfg->dma_sos_emergency = DEFAULT_DMA_SOS_EMERGENCY;
+ cfg->dma_watchdog = DEFAULT_DMA_WATCHDOG;
+ cfg->dma_en_emergency_smoother = DEFAULT_DMA_EN_EMERGENCY_SMOOTHER;
+ cfg->dma_emergency_switch_counter =
+ DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER;
+ cfg->disp_limit_tsh = DEFAULT_DISP_LIMIT;
+ cfg->prs_disp_tsh = DEFAULT_PRS_DISP_TH;
+ cfg->plcr_disp_tsh = DEFAULT_PLCR_DISP_TH;
+ cfg->kg_disp_tsh = DEFAULT_KG_DISP_TH;
+ cfg->bmi_disp_tsh = DEFAULT_BMI_DISP_TH;
+ cfg->qmi_enq_disp_tsh = DEFAULT_QMI_ENQ_DISP_TH;
+ cfg->qmi_deq_disp_tsh = DEFAULT_QMI_DEQ_DISP_TH;
+ cfg->fm_ctl1_disp_tsh = DEFAULT_FM_CTL1_DISP_TH;
+ cfg->fm_ctl2_disp_tsh = DEFAULT_FM_CTL2_DISP_TH;
+
+ cfg->pedantic_dma = false;
+ cfg->tnum_aging_period = DEFAULT_TNUM_AGING_PERIOD;
+ cfg->dma_stop_on_bus_error = false;
+ cfg->qmi_deq_option_support = false;
+}
+
+int fman_dma_init(struct fman_dma_regs __iomem *dma_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+
+ /* Init DMA Registers */
+
+ /* clear status reg events */
+ tmp_reg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC |
+ DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC);
+ iowrite32be(ioread32be(&dma_rg->fmdmsr) | tmp_reg, &dma_rg->fmdmsr);
+
+ /* configure mode register */
+ tmp_reg = 0;
+ tmp_reg |= cfg->dma_cache_override << DMA_MODE_CACHE_OR_SHIFT;
+ if (cfg->dma_aid_override)
+ tmp_reg |= DMA_MODE_AID_OR;
+ if (cfg->exceptions & FMAN_EX_DMA_BUS_ERROR)
+ tmp_reg |= DMA_MODE_BER;
+ if ((cfg->exceptions & FMAN_EX_DMA_SYSTEM_WRITE_ECC) |
+ (cfg->exceptions & FMAN_EX_DMA_READ_ECC) |
+ (cfg->exceptions & FMAN_EX_DMA_FM_WRITE_ECC))
+ tmp_reg |= DMA_MODE_ECC;
+ if (cfg->dma_stop_on_bus_error)
+ tmp_reg |= DMA_MODE_SBER;
+ if (cfg->dma_axi_dbg_num_of_beats)
+ tmp_reg |= (uint32_t)(DMA_MODE_AXI_DBG_MASK &
+ ((cfg->dma_axi_dbg_num_of_beats -
+ 1) << DMA_MODE_AXI_DBG_SHIFT));
+
+ if (cfg->dma_en_emergency) {
+ tmp_reg |= cfg->dma_emergency_bus_select;
+ tmp_reg |= cfg->dma_emergency_level << DMA_MODE_EMER_LVL_SHIFT;
+ if (cfg->dma_en_emergency_smoother)
+ iowrite32be(cfg->dma_emergency_switch_counter,
+ &dma_rg->fmdmemsr);
+ }
+ tmp_reg |= ((cfg->dma_cam_num_of_entries / DMA_CAM_UNITS) - 1) <<
+ DMA_MODE_CEN_SHIFT;
+ tmp_reg |= DMA_MODE_SECURE_PROT;
+ tmp_reg |= cfg->dma_dbg_cnt_mode << DMA_MODE_DBG_SHIFT;
+ tmp_reg |= cfg->dma_aid_mode << DMA_MODE_AID_MODE_SHIFT;
+
+ if (cfg->pedantic_dma)
+ tmp_reg |= DMA_MODE_EMER_READ;
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmmr);
+
+ /* configure thresholds register */
+ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_asrt_emer <<
+ DMA_THRESH_COMMQ_SHIFT) |
+ ((uint32_t)cfg->dma_read_buf_tsh_asrt_emer <<
+ DMA_THRESH_READ_INT_BUF_SHIFT) |
+ ((uint32_t)cfg->dma_write_buf_tsh_asrt_emer);
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmtr);
+
+ /* configure hysteresis register */
+ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_clr_emer <<
+ DMA_THRESH_COMMQ_SHIFT) |
+ ((uint32_t)cfg->dma_read_buf_tsh_clr_emer <<
+ DMA_THRESH_READ_INT_BUF_SHIFT) |
+ ((uint32_t)cfg->dma_write_buf_tsh_clr_emer);
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmhy);
+
+ /* configure emergency threshold */
+ iowrite32be(cfg->dma_sos_emergency, &dma_rg->fmdmsetr);
+
+ /* configure Watchdog */
+ iowrite32be((cfg->dma_watchdog * cfg->clk_freq), &dma_rg->fmdmwcr);
+
+ iowrite32be(cfg->cam_base_addr, &dma_rg->fmdmebcr);
+
+ return 0;
+}
+
+int fman_fpm_init(struct fman_fpm_regs __iomem *fpm_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+ int i;
+
+ /* Init FPM Registers */
+
+ tmp_reg = (uint32_t)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT);
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd);
+
+ tmp_reg = (((uint32_t)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) |
+ ((uint32_t)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) |
+ ((uint32_t)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) |
+ ((uint32_t)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT));
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1);
+
+ tmp_reg =
+ (((uint32_t)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) |
+ ((uint32_t)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) |
+ ((uint32_t)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) |
+ ((uint32_t)cfg->fm_ctl2_disp_tsh << FPM_THR2_FM_CTL2_SHIFT));
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist2);
+
+ /* define exceptions and error behavior */
+ tmp_reg = 0;
+ /* Clear events */
+ tmp_reg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC |
+ FPM_EV_MASK_SINGLE_ECC);
+ /* enable interrupts */
+ if (cfg->exceptions & FMAN_EX_FPM_STALL_ON_TASKS)
+ tmp_reg |= FPM_EV_MASK_STALL_EN;
+ if (cfg->exceptions & FMAN_EX_FPM_SINGLE_ECC)
+ tmp_reg |= FPM_EV_MASK_SINGLE_ECC_EN;
+ if (cfg->exceptions & FMAN_EX_FPM_DOUBLE_ECC)
+ tmp_reg |= FPM_EV_MASK_DOUBLE_ECC_EN;
+ tmp_reg |= (cfg->catastrophic_err << FPM_EV_MASK_CAT_ERR_SHIFT);
+ tmp_reg |= (cfg->dma_err << FPM_EV_MASK_DMA_ERR_SHIFT);
+ if (!cfg->halt_on_external_activ)
+ tmp_reg |= FPM_EV_MASK_EXTERNAL_HALT;
+ if (!cfg->halt_on_unrecov_ecc_err)
+ tmp_reg |= FPM_EV_MASK_ECC_ERR_HALT;
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_ee);
+
+ /* clear all fmCtls event registers */
+ for (i = 0; i < cfg->num_of_fman_ctrl_evnt_regs; i++)
+ iowrite32be(0xFFFFFFFF, &fpm_rg->fmfp_cev[i]);
+
+ /* RAM ECC - enable and clear events */
+ /* first we need to clear all parser memory,
+ * as it is uninitialized and may cause ECC errors
+ */
+ /* event bits */
+ tmp_reg = (FPM_RAM_MURAM_ECC | FPM_RAM_IRAM_ECC);
+ /* Rams enable not effected by RCR bit,
+ * but by a COP configuration
+ */
+ if (cfg->external_ecc_rams_enable)
+ tmp_reg |= FPM_RAM_RAMS_ECC_EN_SRC_SEL;
+
+ /* enable test mode */
+ if (cfg->en_muram_test_mode)
+ tmp_reg |= FPM_RAM_MURAM_TEST_ECC;
+ if (cfg->en_iram_test_mode)
+ tmp_reg |= FPM_RAM_IRAM_TEST_ECC;
+ iowrite32be(tmp_reg, &fpm_rg->fm_rcr);
+
+ tmp_reg = 0;
+ if (cfg->exceptions & FMAN_EX_IRAM_ECC) {
+ tmp_reg |= FPM_IRAM_ECC_ERR_EX_EN;
+ fman_enable_rams_ecc(fpm_rg);
+ }
+ if (cfg->exceptions & FMAN_EX_NURAM_ECC) {
+ tmp_reg |= FPM_MURAM_ECC_ERR_EX_EN;
+ fman_enable_rams_ecc(fpm_rg);
+ }
+ iowrite32be(tmp_reg, &fpm_rg->fm_rie);
+
+ return 0;
+}
+
+int fman_bmi_init(struct fman_bmi_regs __iomem *bmi_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+
+ /* Init BMI Registers */
+
+ /* define common resources */
+ tmp_reg = cfg->fifo_base_addr;
+ tmp_reg = tmp_reg / BMI_FIFO_ALIGN;
+
+ tmp_reg |= ((cfg->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) <<
+ BMI_CFG1_FIFO_SIZE_SHIFT);
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg1);
+
+ tmp_reg = ((uint32_t)(cfg->total_num_of_tasks - 1) <<
+ BMI_CFG2_TASKS_SHIFT);
+ /* num of DMA's will be dynamically updated when each port is set */
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg2);
+
+ /* define unmaskable exceptions, enable and clear events */
+ tmp_reg = 0;
+ iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC |
+ BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC |
+ BMI_ERR_INTR_EN_STATISTICS_RAM_ECC |
+ BMI_ERR_INTR_EN_DISPATCH_RAM_ECC, &bmi_rg->fmbm_ievr);
+
+ if (cfg->exceptions & FMAN_EX_BMI_LIST_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_PIPELINE_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_STATISTICS_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_DISPATCH_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_ier);
+
+ return 0;
+}
+
+int fman_qmi_init(struct fman_qmi_regs __iomem *qmi_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+ uint16_t period_in_fm_clocks;
+ uint8_t remainder;
+
+ /* Init QMI Registers */
+
+ /* Clear error interrupt events */
+
+ iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF,
+ &qmi_rg->fmqm_eie);
+ tmp_reg = 0;
+ if (cfg->exceptions & FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)
+ tmp_reg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ if (cfg->exceptions & FMAN_EX_QMI_DOUBLE_ECC)
+ tmp_reg |= QMI_ERR_INTR_EN_DOUBLE_ECC;
+ /* enable events */
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_eien);
+
+ if (cfg->tnum_aging_period) {
+ /* tnum_aging_period is in units of usec,
+ * p_fmClockFreq in Mhz
+ */
+ period_in_fm_clocks = (uint16_t)
+ (cfg->tnum_aging_period * cfg->clk_freq);
+ /* period_in_fm_clocks must be a 64 multiple */
+ remainder = period_in_fm_clocks % 64;
+ if (remainder) {
+ tmp_reg = (uint32_t)((period_in_fm_clocks / 64) + 1);
+ } else {
+ tmp_reg = (uint32_t)(period_in_fm_clocks / 64);
+ if (!tmp_reg)
+ tmp_reg = 1;
+ }
+ tmp_reg <<= QMI_TAPC_TAP;
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_tapc);
+ }
+ tmp_reg = 0;
+ /* Clear interrupt events */
+ iowrite32be(QMI_INTR_EN_SINGLE_ECC, &qmi_rg->fmqm_ie);
+ if (cfg->exceptions & FMAN_EX_QMI_SINGLE_ECC)
+ tmp_reg |= QMI_INTR_EN_SINGLE_ECC;
+ /* enable events */
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_ien);
+
+ return 0;
+}
+
+int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg)
+{
+ uint32_t cfg_reg = 0;
+
+ /* Enable all modules */
+
+ /* clear&enable global counters - calculate reg and save for later,
+ * because it's the same reg for QMI enable
+ */
+ cfg_reg = QMI_CFG_EN_COUNTERS;
+ if (cfg->qmi_deq_option_support)
+ cfg_reg |= (uint32_t)(((cfg->qmi_def_tnums_thresh) << 8) |
+ cfg->qmi_def_tnums_thresh);
+
+ iowrite32be(BMI_INIT_START, &fman_rg->bmi_rg->fmbm_init);
+ iowrite32be(cfg_reg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN,
+ &fman_rg->qmi_rg->fmqm_gc);
+
+ return 0;
+}
+
+void fman_free_resources(struct fman_rg *fman_rg)
+{
+ /* disable BMI and QMI */
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_init);
+ iowrite32be(0, &fman_rg->qmi_rg->fmqm_gc);
+
+ /* release BMI resources */
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg2);
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg1);
+
+ /* disable ECC */
+ iowrite32be(0, &fman_rg->fpm_rg->fm_rcr);
+}
+
+/* API Run-time Control uint functions */
+
+uint32_t fman_get_normal_pending(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_npi);
+}
+
+uint32_t fman_get_error_pending(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_epi);
+}
+
+void fman_enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_rcr);
+ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
+ iowrite32be(tmp | FPM_RAM_IRAM_ECC_EN, &fpm_rg->fm_rcr);
+ else
+ iowrite32be(tmp | FPM_RAM_RAMS_ECC_EN |
+ FPM_RAM_IRAM_ECC_EN, &fpm_rg->fm_rcr);
+}
+
+void fman_disable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_rcr);
+ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
+ iowrite32be(tmp & ~FPM_RAM_IRAM_ECC_EN, &fpm_rg->fm_rcr);
+ else
+ iowrite32be(tmp & ~(FPM_RAM_RAMS_ECC_EN | FPM_RAM_IRAM_ECC_EN),
+ &fpm_rg->fm_rcr);
+}
+
+int fman_set_exception(struct fman_rg *fman_rg,
+ enum fman_exceptions exception, bool enable)
+{
+ uint32_t tmp;
+
+ switch (exception) {
+ case E_FMAN_EX_DMA_BUS_ERROR:
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
+ if (enable)
+ tmp |= DMA_MODE_BER;
+ else
+ tmp &= ~DMA_MODE_BER;
+ /* disable bus error */
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
+ break;
+ case E_FMAN_EX_DMA_READ_ECC:
+ case E_FMAN_EX_DMA_SYSTEM_WRITE_ECC:
+ case E_FMAN_EX_DMA_FM_WRITE_ECC:
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
+ if (enable)
+ tmp |= DMA_MODE_ECC;
+ else
+ tmp &= ~DMA_MODE_ECC;
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
+ break;
+ case E_FMAN_EX_FPM_STALL_ON_TASKS:
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_STALL_EN;
+ else
+ tmp &= ~FPM_EV_MASK_STALL_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case E_FMAN_EX_FPM_SINGLE_ECC:
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_SINGLE_ECC_EN;
+ else
+ tmp &= ~FPM_EV_MASK_SINGLE_ECC_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case E_FMAN_EX_FPM_DOUBLE_ECC:
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_DOUBLE_ECC_EN;
+ else
+ tmp &= ~FPM_EV_MASK_DOUBLE_ECC_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case E_FMAN_EX_QMI_SINGLE_ECC:
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_ien);
+ if (enable)
+ tmp |= QMI_INTR_EN_SINGLE_ECC;
+ else
+ tmp &= ~QMI_INTR_EN_SINGLE_ECC;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_ien);
+ break;
+ case E_FMAN_EX_QMI_DOUBLE_ECC:
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
+ if (enable)
+ tmp |= QMI_ERR_INTR_EN_DOUBLE_ECC;
+ else
+ tmp &= ~QMI_ERR_INTR_EN_DOUBLE_ECC;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
+ break;
+ case E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
+ if (enable)
+ tmp |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ else
+ tmp &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
+ break;
+ case E_FMAN_EX_BMI_LIST_RAM_ECC:
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case E_FMAN_EX_BMI_STORAGE_PROFILE_ECC:
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case E_FMAN_EX_BMI_STATISTICS_RAM_ECC:
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case E_FMAN_EX_BMI_DISPATCH_RAM_ECC:
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case E_FMAN_EX_IRAM_ECC:
+ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
+ if (enable) {
+ /* enable ECC if not enabled */
+ fman_enable_rams_ecc(fman_rg->fpm_rg);
+ /* enable ECC interrupts */
+ tmp |= FPM_IRAM_ECC_ERR_EX_EN;
+ } else {
+ /* ECC mechanism may be disabled,
+ * depending on driver status
+ */
+ fman_disable_rams_ecc(fman_rg->fpm_rg);
+ tmp &= ~FPM_IRAM_ECC_ERR_EX_EN;
+ }
+ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
+ break;
+ case E_FMAN_EX_MURAM_ECC:
+ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
+ if (enable) {
+ /* enable ECC if not enabled */
+ fman_enable_rams_ecc(fman_rg->fpm_rg);
+ /* enable ECC interrupts */
+ tmp |= FPM_MURAM_ECC_ERR_EX_EN;
+ } else {
+ /* ECC mechanism may be disabled,
+ * depending on driver status
+ */
+ fman_disable_rams_ecc(fman_rg->fpm_rg);
+ tmp &= ~FPM_MURAM_ECC_ERR_EX_EN;
+ }
+ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void fman_get_revision(struct fman_fpm_regs __iomem *fpm_rg,
+ uint8_t *major, uint8_t *minor)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_ip_rev_1);
+ *major =
+ (uint8_t)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT);
+ *minor =
+ (uint8_t)((tmp & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT);
+}
+
+bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ return !!(ioread32be(&qmi_rg->fmqm_gs) & QMI_GS_HALT_NOT_BUSY);
+}
+
+void fman_resume(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fmfp_ee);
+ /* clear tmp_reg event bits in order not to clear standing events */
+ tmp &= ~(FPM_EV_MASK_DOUBLE_ECC |
+ FPM_EV_MASK_STALL | FPM_EV_MASK_SINGLE_ECC);
+ tmp |= FPM_EV_MASK_RELEASE_FM;
+
+ iowrite32be(tmp, &fpm_rg->fmfp_ee);
+}
--
1.7.11.7
From: Igal Liberman <[email protected]>
Add Frame Manger MAC Driver support.
This patch adds The FMan MAC configuration, initialization and
runtime control routines.
This patch contains support for these types of MACs:
tGEC, dTSEC and mEMAC
Signed-off-by: Igal Liberman <[email protected]>
Signed-off-by: Madalin Bucur <[email protected]>
---
drivers/net/ethernet/freescale/fman/fm.c | 73 ++
drivers/net/ethernet/freescale/fman/fm.h | 3 +
drivers/net/ethernet/freescale/fman/fm_common.h | 41 +
.../ethernet/freescale/fman/inc/crc_mac_addr_ext.h | 343 ++++++
drivers/net/ethernet/freescale/fman/mac/Makefile | 4 +-
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c | 1089 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h | 227 ++++
.../ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c | 82 ++
.../ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h | 43 +
drivers/net/ethernet/freescale/fman/mac/fm_mac.h | 250 +++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.c | 741 +++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.h | 124 +++
.../ethernet/freescale/fman/mac/fm_memac_mii_acc.c | 66 ++
.../ethernet/freescale/fman/mac/fm_memac_mii_acc.h | 50 +
drivers/net/ethernet/freescale/fman/mac/fm_tgec.c | 652 ++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.h | 126 +++
16 files changed, 3913 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_mac.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_tgec.h
diff --git a/drivers/net/ethernet/freescale/fman/fm.c b/drivers/net/ethernet/freescale/fman/fm.c
index 5beb118..fd6de5a 100644
--- a/drivers/net/ethernet/freescale/fman/fm.c
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -703,6 +703,35 @@ static int fw_not_reset_erratum_bugzilla6173wa(struct fm_t *p_fm)
#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
/* Inter-Module functions */
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+int fm_10g_tx_ecc_workaround(struct fm_t *p_fm, uint8_t mac_id)
+{
+ uint8_t rx_port_id, tx_port_id;
+ struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+ if (!(is_fman_ctrl_code_loaded(p_fm)))
+ return -EINVAL;
+
+ SW_PORT_ID_TO_HW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev,
+ rx_port_id,
+ FM_PORT_TYPE_RX,
+ mac_id);
+ SW_PORT_ID_TO_HW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev,
+ tx_port_id,
+ FM_PORT_TYPE_TX,
+ mac_id);
+
+ if ((p_fm->p_fm_state_struct->ports_types[rx_port_id] !=
+ FM_PORT_TYPE_DUMMY) ||
+ (p_fm->p_fm_state_struct->ports_types[tx_port_id] !=
+ FM_PORT_TYPE_DUMMY)) {
+ pr_err("Initialize MAC prior to Rx & Tx ports!\n");
+ return -EINVAL;
+ }
+
+ return fman_set_erratum_10gmac_a004_wa(fpm_rg);
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
void fm_register_intr(struct fm_t *p_fm, enum fm_event_modules module,
uint8_t mod_id, enum fm_intr_type intr_type,
@@ -735,6 +764,50 @@ uint8_t fm_get_id(struct fm_t *p_fm)
return p_fm->p_fm_state_struct->fm_id;
}
+int fm_reset_mac(struct fm_t *p_fm, uint8_t mac_id)
+{
+ int err;
+ struct fman_fpm_regs __iomem *fpm_rg = p_fm->p_fm_fpm_regs;
+
+ if (p_fm->p_fm_state_struct->rev_info.major_rev >= 6) {
+ pr_warn("FMan MAC reset!\n");
+ return -EINVAL;
+ }
+ if (!p_fm->base_addr) {
+ pr_warn("'base_address' is required!\n");
+ return -EINVAL;
+ }
+ err =
+ (int)fman_reset_mac(fpm_rg, mac_id);
+
+ if (err == -EINVAL) {
+ pr_warn("Illegal MAC Id\n");
+ return -EINVAL;
+ } else if (err == EINVAL) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int fm_set_mac_max_frame(struct fm_t *p_fm, enum fm_mac_type type,
+ uint8_t mac_id,
+ uint16_t mtu)
+{
+ /* if port is already initialized, check that MaxFrameLength is smaller
+ * or equal to the port's max
+ */
+ if ((!p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id]) ||
+ (p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id] &&
+ (mtu <=
+ p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id]))) {
+ p_fm->p_fm_state_struct->mac_max_frame_lengths[mac_id] = mtu;
+ } else {
+ pr_warn("MAC max_frame_length is larger than Port max_frame_length\n");
+ return -EDOM;
+ }
+ return 0;
+}
+
uint16_t fm_get_clock_freq(struct fm_t *p_fm)
{
/* for multicore environment: this depends on the
diff --git a/drivers/net/ethernet/freescale/fman/fm.h b/drivers/net/ethernet/freescale/fman/fm.h
index f7f56e3..5a2a96b 100644
--- a/drivers/net/ethernet/freescale/fman/fm.h
+++ b/drivers/net/ethernet/freescale/fman/fm.h
@@ -313,6 +313,7 @@ struct fm_iram_regs_t {
struct fm_state_struct_t {
uint8_t fm_id;
+ enum fm_port_type ports_types[FM_MAX_NUM_OF_HW_PORT_IDS];
uint16_t fm_clk_freq;
struct fm_revision_info_t rev_info;
bool enabled_time_stamp;
@@ -334,6 +335,8 @@ struct fm_state_struct_t {
uint32_t extra_fifo_pool_size;
uint8_t extra_tasks_pool_size;
uint8_t extra_open_dmas_pool_size;
+ uint16_t port_max_frame_lengths[FM_MAX_NUM_OF_MACS];
+ uint16_t mac_max_frame_lengths[FM_MAX_NUM_OF_MACS];
};
struct fm_intg_t {
diff --git a/drivers/net/ethernet/freescale/fman/fm_common.h b/drivers/net/ethernet/freescale/fman/fm_common.h
index 125c057..45c450b 100644
--- a/drivers/net/ethernet/freescale/fman/fm_common.h
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -215,6 +215,30 @@ static inline bool TRY_LOCK(spinlock_t *spinlock, volatile bool *p_flag)
#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK 0x0000003f
+/* Description Port Id defines */
+#define BASE_OH_PORTID(major) (major >= 6 ? 2 : 1)
+#define BASE_RX_PORTID 0x08
+#define BASE_TX_PORTID 0x28
+
+#define SW_PORT_ID_TO_HW_PORT_ID(major, _port, type, mac_id) \
+do { \
+ switch (type) { \
+ case (FM_PORT_TYPE_OP): \
+ _port = (uint8_t)(BASE_OH_PORTID(major) + mac_id); \
+ break; \
+ case (FM_PORT_TYPE_RX): \
+ _port = (uint8_t)(BASE_RX_PORTID + mac_id); \
+ break; \
+ case (FM_PORT_TYPE_TX): \
+ _port = (uint8_t)(BASE_TX_PORTID + mac_id); \
+ break; \
+ default: \
+ pr_err("Illegal port type\n"); \
+ _port = 0; \
+ break; \
+ } \
+} while (0)
+
#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
#define BMI_FIFO_UNITS 0x100
@@ -329,6 +353,16 @@ 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);
+/* Function fm_reset_mac
+ * Description Used by MAC driver to reset the MAC registers
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in] type MAC type.
+ * Param[in] mac_id MAC id - according to type.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_init().
+ */
+int fm_reset_mac(struct fm_t *p_fm, uint8_t mac_id);
+
/* Function fm_get_clock_freq
* Description Used by MAC driver to get the FM clock frequency
* Param[in] h_fm A handle to an FM Module.
@@ -345,6 +379,10 @@ uint16_t fm_get_clock_freq(struct fm_t *p_fm);
*/
uint8_t fm_get_id(struct fm_t *p_fm);
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+int fm_10g_tx_ecc_workaround(struct fm_t *p_fm, uint8_t mac_id);
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
int fm_set_num_of_open_dmas(struct fm_t *p_fm,
uint8_t port_id,
uint8_t *p_num_of_open_dmas,
@@ -364,4 +402,7 @@ int fm_set_size_of_fifo(struct fm_t *p_fm,
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);
+int fm_set_mac_max_frame(struct fm_t *p_fm, enum fm_mac_type type,
+ uint8_t mac_id, uint16_t mtu);
+
#endif /* __FM_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.h b/drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.h
new file mode 100644
index 0000000..12468cb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.h
@@ -0,0 +1,343 @@
+/*
+ * 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 a macro that calculate the crc value of an Ethernet MAC address
+ * (48 bitd address)
+ */
+
+#ifndef __crc_mac_addr_ext_h
+#define __crc_mac_addr_ext_h
+
+#include <linux/bitrev.h>
+
+static uint32_t crc_table[256] = {
+ 0x00000000,
+ 0x77073096,
+ 0xee0e612c,
+ 0x990951ba,
+ 0x076dc419,
+ 0x706af48f,
+ 0xe963a535,
+ 0x9e6495a3,
+ 0x0edb8832,
+ 0x79dcb8a4,
+ 0xe0d5e91e,
+ 0x97d2d988,
+ 0x09b64c2b,
+ 0x7eb17cbd,
+ 0xe7b82d07,
+ 0x90bf1d91,
+ 0x1db71064,
+ 0x6ab020f2,
+ 0xf3b97148,
+ 0x84be41de,
+ 0x1adad47d,
+ 0x6ddde4eb,
+ 0xf4d4b551,
+ 0x83d385c7,
+ 0x136c9856,
+ 0x646ba8c0,
+ 0xfd62f97a,
+ 0x8a65c9ec,
+ 0x14015c4f,
+ 0x63066cd9,
+ 0xfa0f3d63,
+ 0x8d080df5,
+ 0x3b6e20c8,
+ 0x4c69105e,
+ 0xd56041e4,
+ 0xa2677172,
+ 0x3c03e4d1,
+ 0x4b04d447,
+ 0xd20d85fd,
+ 0xa50ab56b,
+ 0x35b5a8fa,
+ 0x42b2986c,
+ 0xdbbbc9d6,
+ 0xacbcf940,
+ 0x32d86ce3,
+ 0x45df5c75,
+ 0xdcd60dcf,
+ 0xabd13d59,
+ 0x26d930ac,
+ 0x51de003a,
+ 0xc8d75180,
+ 0xbfd06116,
+ 0x21b4f4b5,
+ 0x56b3c423,
+ 0xcfba9599,
+ 0xb8bda50f,
+ 0x2802b89e,
+ 0x5f058808,
+ 0xc60cd9b2,
+ 0xb10be924,
+ 0x2f6f7c87,
+ 0x58684c11,
+ 0xc1611dab,
+ 0xb6662d3d,
+ 0x76dc4190,
+ 0x01db7106,
+ 0x98d220bc,
+ 0xefd5102a,
+ 0x71b18589,
+ 0x06b6b51f,
+ 0x9fbfe4a5,
+ 0xe8b8d433,
+ 0x7807c9a2,
+ 0x0f00f934,
+ 0x9609a88e,
+ 0xe10e9818,
+ 0x7f6a0dbb,
+ 0x086d3d2d,
+ 0x91646c97,
+ 0xe6635c01,
+ 0x6b6b51f4,
+ 0x1c6c6162,
+ 0x856530d8,
+ 0xf262004e,
+ 0x6c0695ed,
+ 0x1b01a57b,
+ 0x8208f4c1,
+ 0xf50fc457,
+ 0x65b0d9c6,
+ 0x12b7e950,
+ 0x8bbeb8ea,
+ 0xfcb9887c,
+ 0x62dd1ddf,
+ 0x15da2d49,
+ 0x8cd37cf3,
+ 0xfbd44c65,
+ 0x4db26158,
+ 0x3ab551ce,
+ 0xa3bc0074,
+ 0xd4bb30e2,
+ 0x4adfa541,
+ 0x3dd895d7,
+ 0xa4d1c46d,
+ 0xd3d6f4fb,
+ 0x4369e96a,
+ 0x346ed9fc,
+ 0xad678846,
+ 0xda60b8d0,
+ 0x44042d73,
+ 0x33031de5,
+ 0xaa0a4c5f,
+ 0xdd0d7cc9,
+ 0x5005713c,
+ 0x270241aa,
+ 0xbe0b1010,
+ 0xc90c2086,
+ 0x5768b525,
+ 0x206f85b3,
+ 0xb966d409,
+ 0xce61e49f,
+ 0x5edef90e,
+ 0x29d9c998,
+ 0xb0d09822,
+ 0xc7d7a8b4,
+ 0x59b33d17,
+ 0x2eb40d81,
+ 0xb7bd5c3b,
+ 0xc0ba6cad,
+ 0xedb88320,
+ 0x9abfb3b6,
+ 0x03b6e20c,
+ 0x74b1d29a,
+ 0xead54739,
+ 0x9dd277af,
+ 0x04db2615,
+ 0x73dc1683,
+ 0xe3630b12,
+ 0x94643b84,
+ 0x0d6d6a3e,
+ 0x7a6a5aa8,
+ 0xe40ecf0b,
+ 0x9309ff9d,
+ 0x0a00ae27,
+ 0x7d079eb1,
+ 0xf00f9344,
+ 0x8708a3d2,
+ 0x1e01f268,
+ 0x6906c2fe,
+ 0xf762575d,
+ 0x806567cb,
+ 0x196c3671,
+ 0x6e6b06e7,
+ 0xfed41b76,
+ 0x89d32be0,
+ 0x10da7a5a,
+ 0x67dd4acc,
+ 0xf9b9df6f,
+ 0x8ebeeff9,
+ 0x17b7be43,
+ 0x60b08ed5,
+ 0xd6d6a3e8,
+ 0xa1d1937e,
+ 0x38d8c2c4,
+ 0x4fdff252,
+ 0xd1bb67f1,
+ 0xa6bc5767,
+ 0x3fb506dd,
+ 0x48b2364b,
+ 0xd80d2bda,
+ 0xaf0a1b4c,
+ 0x36034af6,
+ 0x41047a60,
+ 0xdf60efc3,
+ 0xa867df55,
+ 0x316e8eef,
+ 0x4669be79,
+ 0xcb61b38c,
+ 0xbc66831a,
+ 0x256fd2a0,
+ 0x5268e236,
+ 0xcc0c7795,
+ 0xbb0b4703,
+ 0x220216b9,
+ 0x5505262f,
+ 0xc5ba3bbe,
+ 0xb2bd0b28,
+ 0x2bb45a92,
+ 0x5cb36a04,
+ 0xc2d7ffa7,
+ 0xb5d0cf31,
+ 0x2cd99e8b,
+ 0x5bdeae1d,
+ 0x9b64c2b0,
+ 0xec63f226,
+ 0x756aa39c,
+ 0x026d930a,
+ 0x9c0906a9,
+ 0xeb0e363f,
+ 0x72076785,
+ 0x05005713,
+ 0x95bf4a82,
+ 0xe2b87a14,
+ 0x7bb12bae,
+ 0x0cb61b38,
+ 0x92d28e9b,
+ 0xe5d5be0d,
+ 0x7cdcefb7,
+ 0x0bdbdf21,
+ 0x86d3d2d4,
+ 0xf1d4e242,
+ 0x68ddb3f8,
+ 0x1fda836e,
+ 0x81be16cd,
+ 0xf6b9265b,
+ 0x6fb077e1,
+ 0x18b74777,
+ 0x88085ae6,
+ 0xff0f6a70,
+ 0x66063bca,
+ 0x11010b5c,
+ 0x8f659eff,
+ 0xf862ae69,
+ 0x616bffd3,
+ 0x166ccf45,
+ 0xa00ae278,
+ 0xd70dd2ee,
+ 0x4e048354,
+ 0x3903b3c2,
+ 0xa7672661,
+ 0xd06016f7,
+ 0x4969474d,
+ 0x3e6e77db,
+ 0xaed16a4a,
+ 0xd9d65adc,
+ 0x40df0b66,
+ 0x37d83bf0,
+ 0xa9bcae53,
+ 0xdebb9ec5,
+ 0x47b2cf7f,
+ 0x30b5ffe9,
+ 0xbdbdf21c,
+ 0xcabac28a,
+ 0x53b39330,
+ 0x24b4a3a6,
+ 0xbad03605,
+ 0xcdd70693,
+ 0x54de5729,
+ 0x23d967bf,
+ 0xb3667a2e,
+ 0xc4614ab8,
+ 0x5d681b02,
+ 0x2a6f2b94,
+ 0xb40bbe37,
+ 0xc30c8ea1,
+ 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+/* CRC calculation */
+#define GET_MAC_ADDR_CRC(addr, crc) \
+{ \
+ uint32_t i; \
+ uint8_t data; \
+ crc = 0xffffffff; \
+ for (i = 0; i < 6; i++) { \
+ data = (uint8_t)(addr >> ((5 - i) * 8)); \
+ crc = crc ^ data; \
+ crc = crc_table[crc & 0xff] ^ (crc >> 8); \
+ } \
+} \
+
+/* Define a macro for getting the mirrored value of */
+/* a byte size number. (0x11010011 --> 0x11001011) */
+/* Sometimes the mirrored value of the CRC is required */
+static inline uint8_t swab(uint8_t n)
+{
+ uint8_t mirror[16] = {
+ 0x00,
+ 0x08,
+ 0x04,
+ 0x0c,
+ 0x02,
+ 0x0a,
+ 0x06,
+ 0x0e,
+ 0x01,
+ 0x09,
+ 0x05,
+ 0x0d,
+ 0x03,
+ 0x0b,
+ 0x07,
+ 0x0f
+ };
+ return ((uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))));
+}
+
+#define MIRROR bitrev
+#define MIRROR_32 bitrev32
+
+#endif /* __crc_mac_addr_ext_h */
diff --git a/drivers/net/ethernet/freescale/fman/mac/Makefile b/drivers/net/ethernet/freescale/fman/mac/Makefile
index ce03e25..bfd04ea 100644
--- a/drivers/net/ethernet/freescale/fman/mac/Makefile
+++ b/drivers/net/ethernet/freescale/fman/mac/Makefile
@@ -1,5 +1,7 @@
obj-y += fsl_fman_mac.o
fsl_fman_mac-objs := fman_dtsec.o fman_dtsec_mii_acc.o \
+ fm_dtsec.o fm_dtsec_mii_acc.o \
fman_memac.o fman_memac_mii_acc.o \
- fman_tgec.o
+ fm_memac.o fm_memac_mii_acc.o \
+ fman_tgec.o fm_tgec.o
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c
new file mode 100644
index 0000000..3195b83
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c
@@ -0,0 +1,1089 @@
+/*
+ * 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.
+ */
+
+/* FMan dTSEC driver */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "service.h"
+#include "crc_mac_addr_ext.h"
+
+#include "fm_common.h"
+#include "fm_dtsec.h"
+#include "fsl_fman_dtsec.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/bitrev.h>
+
+/* Internal routines */
+
+static int check_init_parameters(struct dtsec_t *p_dtsec)
+{
+ if (ENET_SPEED_FROM_MODE(p_dtsec->enet_mode) >= ENET_SPEED_10000) {
+ pr_err("1G MAC driver supports 1G or lower speeds\n");
+ return -EDOM;
+ }
+ if (p_dtsec->addr == 0) {
+ pr_err("Ethernet MAC Must have a valid MAC Address\n");
+ return -EDOM;
+ }
+ if ((ENET_SPEED_FROM_MODE(p_dtsec->enet_mode) >= ENET_SPEED_1000) &&
+ p_dtsec->p_dtsec_drv_param->halfdup_on) {
+ pr_err("Ethernet MAC 1G can't work in half duplex\n");
+ return -EDOM;
+ }
+#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001
+ /* fixed for rev3 */
+ if (p_dtsec->fm_rev_info.major_rev <= 6)
+ if (p_dtsec->p_dtsec_drv_param->rx_preamble) {
+ pr_err("preambleRxEn\n");
+ return -EINVAL;
+ }
+#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */
+ if (((p_dtsec->p_dtsec_drv_param)->tx_preamble ||
+ (p_dtsec->p_dtsec_drv_param)->rx_preamble) &&
+ ((p_dtsec->p_dtsec_drv_param)->preamble_len != 0x7)) {
+ pr_err("Preamble length should be 0x7 bytes\n");
+ return -EDOM;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->halfdup_on &&
+ (p_dtsec->p_dtsec_drv_param->tx_time_stamp_en ||
+ p_dtsec->p_dtsec_drv_param->rx_time_stamp_en)) {
+ pr_err("1588 timeStamp disabled in half duplex mode\n");
+ return -EDOM;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->rx_flow &&
+ (p_dtsec->p_dtsec_drv_param)->rx_ctrl_acc) {
+ pr_err("Receive control frame can not be accepted\n");
+ return -EINVAL;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->rx_prepend >
+ MAX_PACKET_ALIGNMENT) {
+ pr_err("packetAlignmentPadding can't be > than %d\n",
+ MAX_PACKET_ALIGNMENT);
+ return -EINVAL;
+ }
+ if (((p_dtsec->p_dtsec_drv_param)->non_back_to_back_ipg1 >
+ MAX_INTER_PACKET_GAP) ||
+ ((p_dtsec->p_dtsec_drv_param)->non_back_to_back_ipg2 >
+ MAX_INTER_PACKET_GAP) ||
+ ((p_dtsec->p_dtsec_drv_param)->back_to_back_ipg >
+ MAX_INTER_PACKET_GAP)) {
+ pr_err("Inter packet gap can't be greater than %d\n",
+ MAX_INTER_PACKET_GAP);
+ return -EINVAL;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->halfdup_alt_backoff_val >
+ MAX_INTER_PALTERNATE_BEB) {
+ pr_err("alternateBackoffVal can't be greater than %d\n",
+ MAX_INTER_PALTERNATE_BEB);
+ return -EINVAL;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->halfdup_retransmit >
+ MAX_RETRANSMISSION) {
+ pr_err("maxRetransmission can't be greater than %d\n",
+ MAX_RETRANSMISSION);
+ return -EINVAL;
+ }
+ if ((p_dtsec->p_dtsec_drv_param)->halfdup_coll_window >
+ MAX_COLLISION_WINDOW) {
+ pr_err("collisionWindow can't be greater than %d\n",
+ MAX_COLLISION_WINDOW);
+ return -EINVAL;
+ /* If Auto negotiation process is disabled, need to */
+ /* Set up the PHY using the MII Management Interface */
+ }
+ if (p_dtsec->p_dtsec_drv_param->tbipa > MAX_PHYS) {
+ pr_err("PHY address (should be 0-%d)\n", MAX_PHYS);
+ return -ERANGE;
+ }
+ if (!p_dtsec->f_exception) {
+ pr_err("uninitialized f_exception\n");
+ return -EINVAL;
+ }
+ if (!p_dtsec->f_event) {
+ pr_err("uninitialized f_event\n");
+ return -EINVAL;
+ }
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (p_dtsec->fm_rev_info.major_rev != 4 &&
+ p_dtsec->p_dtsec_drv_param->rx_len_check) {
+ pr_warn("LengthCheck!\n");
+ return -EINVAL;
+ }
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ uint32_t bit_mask;
+
+ switch (exception) {
+ case FM_MAC_EX_1G_BAB_RX:
+ bit_mask = DTSEC_IMASK_BREN;
+ break;
+ case FM_MAC_EX_1G_RX_CTL:
+ bit_mask = DTSEC_IMASK_RXCEN;
+ break;
+ case FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET:
+ bit_mask = DTSEC_IMASK_GTSCEN;
+ break;
+ case FM_MAC_EX_1G_BAB_TX:
+ bit_mask = DTSEC_IMASK_BTEN;
+ break;
+ case FM_MAC_EX_1G_TX_CTL:
+ bit_mask = DTSEC_IMASK_TXCEN;
+ break;
+ case FM_MAC_EX_1G_TX_ERR:
+ bit_mask = DTSEC_IMASK_TXEEN;
+ break;
+ case FM_MAC_EX_1G_LATE_COL:
+ bit_mask = DTSEC_IMASK_LCEN;
+ break;
+ case FM_MAC_EX_1G_COL_RET_LMT:
+ bit_mask = DTSEC_IMASK_CRLEN;
+ break;
+ case FM_MAC_EX_1G_TX_FIFO_UNDRN:
+ bit_mask = DTSEC_IMASK_XFUNEN;
+ break;
+ case FM_MAC_EX_1G_MAG_PCKT:
+ bit_mask = DTSEC_IMASK_MAGEN;
+ break;
+ case FM_MAC_EX_1G_MII_MNG_RD_COMPLET:
+ bit_mask = DTSEC_IMASK_MMRDEN;
+ break;
+ case FM_MAC_EX_1G_MII_MNG_WR_COMPLET:
+ bit_mask = DTSEC_IMASK_MMWREN;
+ break;
+ case FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET:
+ bit_mask = DTSEC_IMASK_GRSCEN;
+ break;
+ case FM_MAC_EX_1G_DATA_ERR:
+ bit_mask = DTSEC_IMASK_TDPEEN;
+ break;
+ case FM_MAC_EX_1G_RX_MIB_CNT_OVFL:
+ bit_mask = DTSEC_IMASK_MSROEN;
+ break;
+ default:
+ bit_mask = 0;
+ break;
+ }
+
+ return bit_mask;
+}
+
+/* Checks if p_dtsec driver parameters were initialized
+ * returns 0 if success else returns error code
+ */
+static int is_init_done(struct dtsec_cfg *p_dtsec_drv_parameters)
+{
+ if (!p_dtsec_drv_parameters)
+ return 0;
+ return -EINVAL;
+}
+
+static uint32_t get_mac_addr_hash_code(uint64_t eth_addr)
+{
+ uint32_t crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(eth_addr, crc);
+
+ crc = bitrev32(crc);
+
+ return crc;
+}
+
+static uint16_t dtsec_get_max_frame_length(void *h_dtsec)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)h_dtsec;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return 0;
+
+ return fman_dtsec_get_max_frame_len(p_dtsec->p_mem_map);
+}
+
+static void dtsec_isr(void *h_dtsec)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)h_dtsec;
+ uint32_t event;
+ struct dtsec_regs __iomem *p_dtsec_mem_map = p_dtsec->p_mem_map;
+
+ /* do not handle MDIO events */
+ event =
+ fman_dtsec_get_event(p_dtsec_mem_map,
+ (uint32_t)(~
+ (DTSEC_IMASK_MMRDEN |
+ DTSEC_IMASK_MMWREN)));
+
+ event &= fman_dtsec_get_interrupt_mask(p_dtsec_mem_map);
+
+ fman_dtsec_ack_event(p_dtsec_mem_map, event);
+
+ if (event & DTSEC_IMASK_BREN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_BAB_RX);
+ if (event & DTSEC_IMASK_RXCEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_RX_CTL);
+ if (event & DTSEC_IMASK_GTSCEN)
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET);
+ if (event & DTSEC_IMASK_BTEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_BAB_TX);
+ if (event & DTSEC_IMASK_TXCEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_TX_CTL);
+ if (event & DTSEC_IMASK_TXEEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_TX_ERR);
+ if (event & DTSEC_IMASK_LCEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_LATE_COL);
+ if (event & DTSEC_IMASK_CRLEN)
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_COL_RET_LMT);
+ if (event & DTSEC_IMASK_XFUNEN) {
+#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6
+ if (p_dtsec->fm_rev_info.major_rev == 2) {
+ uint32_t tpkt1, tmp_reg1, tpkt2, tmp_reg2, i;
+ /* a. Write 0x00E0_0C00 to DTSEC_ID */
+ /* This is a read only regidter
+ */
+
+ /* b. Read and save the value of TPKT */
+ tpkt1 = GET_UINT32(p_dtsec_mem_map->tpkt);
+
+ /* c. Read the register at dTSEC address offset 0x32C */
+ tmp_reg1 =
+ GET_UINT32(*(uint32_t *)
+ ((uint8_t *)p_dtsec_mem_map + 0x32c));
+
+ /* d. Compare bits [9:15] to bits [25:31] of the
+ * register at address offset 0x32C.
+ */
+ if ((tmp_reg1 & 0x007F0000) !=
+ (tmp_reg1 & 0x0000007F)) {
+ /* If they are not equal, save the value of
+ * this register and wait for at least
+ * MAXFRM*16 ns
+ */
+ usleep_range((uint32_t)(min
+ (dtsec_get_max_frame_length(p_dtsec) *
+ 16 / 1000, 1)), (uint32_t)
+ (min(dtsec_get_max_frame_length
+ (p_dtsec) * 16 / 1000, 1) + 1));
+ }
+
+ /* e. Read and save TPKT again and read the register
+ * at dTSEC address offset 0x32C again
+ */
+ tpkt2 = GET_UINT32(p_dtsec_mem_map->tpkt);
+ tmp_reg2 =
+ GET_UINT32(*(uint32_t __iomem *)
+ ((uint8_t *)p_dtsec_mem_map + 0x32c));
+
+ /* f. Compare the value of TPKT saved in step b to
+ * value read in step e. Also compare bits [9:15] of
+ * the register at offset 0x32C saved in step d to the
+ * value of bits [9:15] saved in step e. If the two
+ * registers values are unchanged, then the transmit
+ * portion of the dTSEC controller is locked up and
+ * the user should proceed to the recover sequence.
+ */
+ if ((tpkt1 == tpkt2) && ((tmp_reg1 & 0x007F0000) ==
+ (tmp_reg2 & 0x007F0000))) {
+ /* recover sequence */
+
+ /* a.Write a 1 to RCTRL[GRS] */
+
+ WRITE_UINT32(p_dtsec_mem_map->rctrl,
+ GET_UINT32(p_dtsec_mem_map->
+ rctrl) | RCTRL_GRS);
+
+ /* b.Wait until IEVENT[GRSC]=1, or at least
+ * 100 us has elapsed.
+ */
+ for (i = 0; i < 100; i++) {
+ if (GET_UINT32(p_dtsec_mem_map->
+ ievent) &
+ DTSEC_IMASK_GRSCEN)
+ break;
+ udelay(1);
+ }
+ if (GET_UINT32(p_dtsec_mem_map->ievent) &
+ DTSEC_IMASK_GRSCEN)
+ WRITE_UINT32(p_dtsec_mem_map->ievent,
+ DTSEC_IMASK_GRSCEN);
+ else
+ pr_debug("Rx lockup due to Tx lockup\n");
+
+ /* c.Write a 1 to bit n of FM_RSTC
+ * (offset 0x0CC of FPM)
+ */
+ fm_reset_mac(p_dtsec->h_fm, p_dtsec->mac_id);
+
+ /* d.Wait 4 Tx clocks (32 ns) */
+ udelay(1);
+
+ /* e.Write a 0 to bit n of FM_RSTC. */
+ /* cleared by FMAN
+ */
+ }
+ }
+#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */
+
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_TX_FIFO_UNDRN);
+ }
+ if (event & DTSEC_IMASK_MAGEN)
+ p_dtsec->f_exception(p_dtsec->dev_id, FM_MAC_EX_1G_MAG_PCKT);
+ if (event & DTSEC_IMASK_GRSCEN)
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET);
+ if (event & DTSEC_IMASK_TDPEEN)
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_DATA_ERR);
+ if (event & DTSEC_IMASK_RDPEEN)
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_1G_RX_DATA_ERR);
+
+ /* - masked interrupts */
+ ASSERT(!(event & DTSEC_IMASK_ABRTEN));
+ ASSERT(!(event & DTSEC_IMASK_IFERREN));
+}
+
+static void dtsec_1588_isr(void *h_dtsec)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)h_dtsec;
+ uint32_t event;
+ struct dtsec_regs __iomem *p_dtsec_mem_map = p_dtsec->p_mem_map;
+
+ if (p_dtsec->ptp_tsu_enabled) {
+ event = fman_dtsec_check_and_clear_tmr_event(p_dtsec_mem_map);
+
+ if (event) {
+ ASSERT(event & TMR_PEVENT_TSRE);
+ p_dtsec->f_exception(p_dtsec->dev_id,
+ FM_MAC_EX_1G_1588_TS_RX_ERR);
+ }
+ }
+}
+
+static void free_init_resources(struct dtsec_t *p_dtsec)
+{
+ fm_unregister_intr(p_dtsec->h_fm, FM_MOD_MAC, p_dtsec->mac_id,
+ FM_INTR_TYPE_ERR);
+ fm_unregister_intr(p_dtsec->h_fm, FM_MOD_MAC, p_dtsec->mac_id,
+ FM_INTR_TYPE_NORMAL);
+
+ /* release the driver's group hash table */
+ free_hash_table(p_dtsec->p_multicast_addr_hash);
+ p_dtsec->p_multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(p_dtsec->p_unicast_addr_hash);
+ p_dtsec->p_unicast_addr_hash = NULL;
+}
+
+static int graceful_stop(struct dtsec_t *p_dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *p_mem_map;
+
+ p_mem_map = p_dtsec->p_mem_map;
+
+ /* Assert the graceful transmit stop bit */
+ if (mode & COMM_MODE_RX) {
+ fman_dtsec_stop_rx(p_mem_map);
+
+#ifdef FM_GRS_ERRATA_DTSEC_A002
+ if (p_dtsec->fm_rev_info.major_rev == 2)
+ usleep_range(100, 101);
+#else /* FM_GRS_ERRATA_DTSEC_A002 */
+#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
+ usleep_range(10, 11);
+#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */
+#endif /* FM_GRS_ERRATA_DTSEC_A002 */
+ }
+
+ if (mode & COMM_MODE_TX) {
+#if defined(FM_GTS_ERRATA_DTSEC_A004) || \
+defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012)
+ if (p_dtsec->fm_rev_info.major_rev == 2)
+ pr_debug("GTS not supported due to DTSEC_A004 errata.\n");
+#else /* not defined(FM_GTS_ERRATA_DTSEC_A004) ||..*/
+#ifdef FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014
+ if (p_dtsec->fm_rev_info.major_rev != 4)
+ pr_debug("GTS not supported due to DTSEC_A0014 errata.\n");
+#else /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
+ fman_dtsec_stop_tx(p_mem_map);
+#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */
+#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) ||... */
+ }
+ return 0;
+}
+
+static int graceful_restart(struct dtsec_t *p_dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *p_mem_map;
+
+ p_mem_map = p_dtsec->p_mem_map;
+ /* clear the graceful receive stop bit */
+ if (mode & COMM_MODE_TX)
+ fman_dtsec_start_tx(p_mem_map);
+
+ if (mode & COMM_MODE_RX)
+ fman_dtsec_start_rx(p_mem_map);
+
+ return 0;
+}
+
+/* dTSEC Configs modification functions */
+
+int dtsec_cfg_lb(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_dtsec->p_dtsec_drv_param->loopback = new_val;
+
+ return 0;
+}
+
+int dtsec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_dtsec->p_dtsec_drv_param->maximum_frame = new_val;
+
+ return 0;
+}
+
+int dtsec_cfg_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_dtsec->p_dtsec_drv_param->tx_pad_crc = new_val;
+
+ return 0;
+}
+
+/* dTSEC Run Time API functions */
+
+int dtsec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_dtsec_enable(p_dtsec->p_mem_map,
+ (bool)!!(mode & COMM_MODE_RX),
+ (bool)!!(mode & COMM_MODE_TX));
+
+ graceful_restart(p_dtsec, mode);
+
+ return 0;
+}
+
+int dtsec_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ graceful_stop(p_dtsec, mode);
+
+ fman_dtsec_disable(p_dtsec->p_mem_map,
+ (bool)!!(mode & COMM_MODE_RX),
+ (bool)!!(mode & COMM_MODE_TX));
+
+ return 0;
+}
+
+int dtsec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ uint8_t __maybe_unused priority,
+ uint16_t pause_time,
+ uint16_t __maybe_unused thresh_time)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003
+ if (p_dtsec->fm_rev_info.major_rev == 2)
+ if (0 < pause_time && pause_time <= 320) {
+ pr_warn("pause-time:%d illegal.Should be >320\n",
+ pause_time);
+ return -EDOM;
+ }
+#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */
+
+ fman_dtsec_set_tx_pause_frames(p_dtsec->p_mem_map, pause_time);
+ return 0;
+}
+
+int dtsec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_dtsec_handle_rx_pause(p_dtsec->p_mem_map, en);
+
+ return 0;
+}
+
+int dtsec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ /* Initialize MAC Station Address registers (1&2) */
+ /* Station address have to be swapped (big endian to little endian */
+ p_dtsec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
+ fman_dtsec_set_mac_address(p_dtsec->p_mem_map,
+ (uint8_t *)(*p_enet_addr));
+
+ return 0;
+}
+
+int dtsec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *p_hash_entry;
+ uint64_t eth_addr;
+ int32_t bucket;
+ uint32_t crc;
+ bool mcast, ghtx;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ENET_ADDR_TO_UINT64(*p_eth_addr);
+
+ ghtx = (bool)((fman_dtsec_get_rctrl(p_dtsec->p_mem_map) &
+ RCTRL_GHTX) ? true : false);
+ mcast = (bool)((eth_addr & MAC_GROUP_ADDRESS) ? true : false);
+
+ /* Cannot handle unicast mac addr when GHTX is on */
+ if (ghtx && !mcast) {
+ pr_err("Could not compute hash bucket\n");
+ return -EINVAL;
+ }
+ crc = get_mac_addr_hash_code(eth_addr);
+
+ /* considering the 9 highest order bits in crc H[8:0]:
+ *if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register
+ *and H[5:1] (next 5 bits) identify the hash bit
+ *if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register
+ *and H[4:0] (next 5 bits) identify the hash bit.
+ *
+ *In bucket index output the low 5 bits identify the hash register
+ *bit, while the higher 4 bits identify the hash register
+ */
+
+ if (ghtx) {
+ bucket = (int32_t)((crc >> 23) & 0x1ff);
+ } else {
+ bucket = (int32_t)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set in gaddr instead of
+ *igaddr.
+ */
+ if (mcast)
+ bucket += 0x100;
+ }
+
+ fman_dtsec_set_bucket(p_dtsec->p_mem_map, bucket, true);
+
+ /* Create element to be added to the driver hash table */
+ p_hash_entry = kmalloc(sizeof(*p_hash_entry), GFP_KERNEL);
+ if (!p_hash_entry)
+ return -ENOMEM;
+ p_hash_entry->addr = eth_addr;
+ INIT_LIST_HEAD(&p_hash_entry->node);
+
+ if (eth_addr & MAC_GROUP_ADDRESS)
+ /* Group Address */
+ list_add_tail(&p_hash_entry->node,
+ &(p_dtsec->p_multicast_addr_hash->p_lsts[bucket]
+ ));
+ else
+ list_add_tail(&p_hash_entry->node,
+ &p_dtsec->p_unicast_addr_hash->p_lsts[bucket]);
+
+ return 0;
+}
+
+int dtsec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct list_head *p_pos;
+ struct eth_hash_entry_t *p_hash_entry = NULL;
+ uint64_t eth_addr;
+ int32_t bucket;
+ uint32_t crc;
+ bool mcast, ghtx;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ENET_ADDR_TO_UINT64(*p_eth_addr);
+
+ ghtx =
+ (bool)((fman_dtsec_get_rctrl(p_dtsec->p_mem_map) & RCTRL_GHTX) ?
+ true : false);
+ mcast = (bool)((eth_addr & MAC_GROUP_ADDRESS) ? true : false);
+
+ /* Cannot handle unicast mac addr when GHTX is on */
+ if (ghtx && !mcast) {
+ pr_err("Could not compute hash bucket\n");
+ return -EINVAL;
+ }
+ crc = get_mac_addr_hash_code(eth_addr);
+
+ if (ghtx) {
+ bucket = (int32_t)((crc >> 23) & 0x1ff);
+ } else {
+ bucket = (int32_t)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set
+ * in gaddr instead of igaddr.
+ */
+ if (mcast)
+ bucket += 0x100;
+ }
+
+ if (eth_addr & MAC_GROUP_ADDRESS) {
+ /* Group Address */
+ list_for_each(p_pos,
+ &(p_dtsec->p_multicast_addr_hash->
+ p_lsts[bucket])) {
+ p_hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (p_hash_entry->addr == eth_addr) {
+ list_del_init(&p_hash_entry->node);
+ kfree(p_hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&p_dtsec->p_multicast_addr_hash->p_lsts[bucket]))
+ fman_dtsec_set_bucket(p_dtsec->p_mem_map, bucket,
+ false);
+ } else {
+ /* Individual Address */
+ list_for_each(p_pos,
+ &p_dtsec->p_unicast_addr_hash->p_lsts[bucket]) {
+ p_hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (p_hash_entry->addr == eth_addr) {
+ list_del_init(&p_hash_entry->node);
+ kfree(p_hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&p_dtsec->p_unicast_addr_hash->p_lsts[bucket]))
+ fman_dtsec_set_bucket(p_dtsec->p_mem_map, bucket,
+ false);
+ }
+
+ /* address does not exist */
+ ASSERT(p_hash_entry);
+
+ return 0;
+}
+
+int dtsec_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_dtsec_set_uc_promisc(p_dtsec->p_mem_map, new_val);
+ fman_dtsec_set_mc_promisc(p_dtsec->p_mem_map, new_val);
+
+ return 0;
+}
+
+int dtsec_adjust_link(struct fm_mac_dev *fm_mac_dev, enum ethernet_speed speed)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int err;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ int ret, full_duplex = true;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ p_dtsec->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_dtsec->enet_mode), speed);
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_dtsec->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_dtsec->enet_mode);
+
+ err =
+ (int)fman_dtsec_adjust_link(p_dtsec->p_mem_map, enet_interface,
+ enet_speed, full_duplex);
+
+ if (err == -EINVAL) {
+ pr_err("Ethernet doesn't support Half Duplex mode\n");
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+int dtsec_restart_autoneg(struct fm_mac_dev *fm_mac_dev)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ uint16_t tmp_reg16;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ dtsec_mii_read_phy_reg(p_dtsec, p_dtsec->tbi_phy_addr, 0, &tmp_reg16);
+
+ tmp_reg16 &= ~(PHY_CR_SPEED0 | PHY_CR_SPEED1);
+ tmp_reg16 |=
+ (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
+
+ dtsec_mii_write_phy_reg(p_dtsec, p_dtsec->tbi_phy_addr, 0, tmp_reg16);
+
+ return 0;
+}
+
+int dtsec_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *mac_version)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ *mac_version = fman_dtsec_get_revision(p_dtsec->p_mem_map);
+
+ return 0;
+}
+
+int dtsec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ uint32_t bit_mask = 0;
+ int ret;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (ret)
+ return ret;
+
+ if (exception != FM_MAC_EX_1G_1588_TS_RX_ERR) {
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ p_dtsec->exceptions |= bit_mask;
+ else
+ p_dtsec->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EDOM;
+ }
+ if (enable)
+ fman_dtsec_enable_interrupt(p_dtsec->p_mem_map,
+ bit_mask);
+ else
+ fman_dtsec_disable_interrupt(p_dtsec->p_mem_map,
+ bit_mask);
+ } else {
+ if (!p_dtsec->ptp_tsu_enabled) {
+ pr_err("Exception valid for 1588 only\n");
+ return -EDOM;
+ }
+ switch (exception) {
+ case (FM_MAC_EX_1G_1588_TS_RX_ERR):
+ if (enable) {
+ p_dtsec->en_tsu_err_exeption = true;
+ fman_dtsec_enable_tmr_interrupt(p_dtsec->
+ p_mem_map);
+ } else {
+ p_dtsec->en_tsu_err_exeption = false;
+ fman_dtsec_disable_tmr_interrupt(p_dtsec->
+ p_mem_map);
+ }
+ break;
+ default:
+ pr_err("Undefined exception\n");
+ return -EDOM;
+ }
+ }
+
+ return 0;
+}
+
+/* dTSEC Init&Free API */
+
+int dtsec_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct dtsec_cfg *p_dtsec_drv_param;
+ int err;
+ uint16_t max_frm_ln;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ enet_addr_t eth_addr;
+ int ret, ret_err;
+
+ ret = is_init_done(p_dtsec->p_dtsec_drv_param);
+ if (!ret)
+ return ret;
+
+ if (DEFAULT_RESET_ON_INIT &&
+ (fm_reset_mac(p_dtsec->h_fm, p_dtsec->mac_id) != 0)) {
+ pr_err("Can't reset MAC!\n");
+ return -EINVAL;
+ }
+
+ ret_err = check_init_parameters(p_dtsec);
+ if (ret_err)
+ return -ret_err;
+
+ p_dtsec_drv_param = p_dtsec->p_dtsec_drv_param;
+
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_dtsec->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_dtsec->enet_mode);
+ MAKE_ENET_ADDR_FROM_UINT64(p_dtsec->addr, eth_addr);
+
+ err = (int)fman_dtsec_init(p_dtsec->p_mem_map,
+ p_dtsec_drv_param,
+ enet_interface,
+ enet_speed,
+ (uint8_t *)eth_addr,
+ p_dtsec->fm_rev_info.major_rev,
+ p_dtsec->fm_rev_info.minor_rev,
+ p_dtsec->exceptions);
+ if (err) {
+ free_init_resources(p_dtsec);
+ pr_err("DTSEC version doesn't support this i/f mode\n");
+ return err;
+ }
+
+ if (ENET_INTERFACE_FROM_MODE(p_dtsec->enet_mode) == ENET_IF_SGMII) {
+ uint16_t tmp_reg16;
+
+ /* Configure the TBI PHY Control Register */
+ tmp_reg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET;
+ dtsec_mii_write_phy_reg(p_dtsec,
+ (uint8_t)p_dtsec_drv_param->tbipa,
+ 17, tmp_reg16);
+
+ tmp_reg16 = PHY_TBICON_CLK_SEL;
+ dtsec_mii_write_phy_reg(p_dtsec,
+ (uint8_t)p_dtsec_drv_param->tbipa,
+ 17, tmp_reg16);
+
+ tmp_reg16 =
+ (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX |
+ PHY_CR_SPEED1);
+ dtsec_mii_write_phy_reg(p_dtsec,
+ (uint8_t)p_dtsec_drv_param->tbipa,
+ 0, tmp_reg16);
+
+ if (p_dtsec->enet_mode & ENET_IF_SGMII_BASEX)
+ tmp_reg16 = PHY_TBIANA_1000X;
+ else
+ tmp_reg16 = PHY_TBIANA_SGMII;
+ dtsec_mii_write_phy_reg(p_dtsec,
+ (uint8_t)p_dtsec_drv_param->tbipa,
+ 4, tmp_reg16);
+
+ tmp_reg16 =
+ (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX |
+ PHY_CR_SPEED1);
+
+ dtsec_mii_write_phy_reg(p_dtsec,
+ (uint8_t)p_dtsec_drv_param->tbipa,
+ 0, tmp_reg16);
+ }
+
+ /* Max Frame Length */
+ max_frm_ln = fman_dtsec_get_max_frame_len(p_dtsec->p_mem_map);
+ err = fm_set_mac_max_frame(p_dtsec->h_fm, FM_MAC_1G, p_dtsec->mac_id,
+ max_frm_ln);
+ if (err) {
+ pr_err("Setting max frame length FAILED\n");
+ free_init_resources(p_dtsec);
+ return -EINVAL;
+ }
+
+ p_dtsec->p_multicast_addr_hash =
+ alloc_hash_table(EXTENDED_HASH_TABLE_SIZE);
+ if (!p_dtsec->p_multicast_addr_hash) {
+ free_init_resources(p_dtsec);
+ pr_err("MC hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ p_dtsec->p_unicast_addr_hash = alloc_hash_table(DTSEC_HASH_TABLE_SIZE);
+ if (!p_dtsec->p_unicast_addr_hash) {
+ free_init_resources(p_dtsec);
+ pr_err("UC hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ /* register err intr handler for dtsec to FPM (err) */
+ fm_register_intr(p_dtsec->h_fm, FM_MOD_MAC, p_dtsec->mac_id,
+ FM_INTR_TYPE_ERR, dtsec_isr, p_dtsec);
+ /* register 1588 intr handler for TMR to FPM (normal) */
+ fm_register_intr(p_dtsec->h_fm, FM_MOD_MAC, p_dtsec->mac_id,
+ FM_INTR_TYPE_NORMAL, dtsec_1588_isr, p_dtsec);
+
+ kfree(p_dtsec_drv_param);
+ p_dtsec->p_dtsec_drv_param = NULL;
+
+ return 0;
+}
+
+int dtsec_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ free_init_resources(p_dtsec);
+
+ kfree(p_dtsec->p_dtsec_drv_param);
+ p_dtsec->p_dtsec_drv_param = NULL;
+ kfree(p_dtsec);
+
+ return 0;
+}
+
+/* d_tsec config main entry */
+
+void *dtsec_config(struct fm_mac_params_t *p_fm_mac_param)
+{
+ struct dtsec_t *p_dtsec;
+ struct dtsec_cfg *p_dtsec_drv_param;
+ uintptr_t base_addr;
+
+ base_addr = p_fm_mac_param->base_addr;
+
+ /* allocate memory for the UCC GETH data structure. */
+ p_dtsec = kzalloc(sizeof(*p_dtsec), GFP_KERNEL);
+ if (!p_dtsec)
+ return ERR_PTR(-ENOMEM);
+
+ /* allocate memory for the d_tsec driver parameters data structure. */
+ p_dtsec_drv_param = kzalloc(sizeof(*p_dtsec_drv_param),
+ GFP_KERNEL);
+ if (!p_dtsec_drv_param) {
+ kfree(p_dtsec);
+ pr_err("dTSEC driver parameters");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Plant parameter structure pointer */
+ p_dtsec->p_dtsec_drv_param = p_dtsec_drv_param;
+
+ fman_dtsec_defconfig(p_dtsec_drv_param);
+
+ p_dtsec->p_mem_map = (struct dtsec_regs __iomem *)
+ UINT_TO_PTR(base_addr);
+ p_dtsec->p_mii_mem_map = (struct dtsec_mii_reg __iomem *)
+ UINT_TO_PTR(base_addr + DTSEC_TO_MII_OFFSET);
+ p_dtsec->addr = ENET_ADDR_TO_UINT64(p_fm_mac_param->addr);
+ p_dtsec->enet_mode = p_fm_mac_param->enet_mode;
+ p_dtsec->mac_id = p_fm_mac_param->mac_id;
+ p_dtsec->exceptions = DTSEC_DEFAULT_EXCEPTIONS;
+ p_dtsec->f_exception = p_fm_mac_param->f_exception;
+ p_dtsec->f_event = p_fm_mac_param->f_event;
+ p_dtsec->dev_id = p_fm_mac_param->dev_id;
+ p_dtsec->ptp_tsu_enabled = p_dtsec->p_dtsec_drv_param->ptp_tsu_en;
+ p_dtsec->en_tsu_err_exeption =
+ p_dtsec->p_dtsec_drv_param->ptp_exception_en;
+ p_dtsec->tbi_phy_addr = p_dtsec->p_dtsec_drv_param->tbi_phy_addr;
+
+ p_dtsec->h_fm = p_fm_mac_param->h_fm;
+ p_dtsec->clk_freq = fm_get_clock_freq(p_dtsec->h_fm);
+ if (p_dtsec->clk_freq == 0) {
+ pr_err("Can't get clock for MAC!\n");
+ kfree(p_dtsec);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Save FMan revision */
+ fm_get_revision(p_dtsec->h_fm, &p_dtsec->fm_rev_info);
+
+ return p_dtsec;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h
new file mode 100644
index 0000000..a955ad9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h
@@ -0,0 +1,227 @@
+/*
+ * 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 dTSEC ... */
+#ifndef __DTSEC_H
+#define __DTSEC_
+
+#include "service.h"
+#include "enet_ext.h"
+
+#include "fm_dtsec_mii_acc.h"
+#include "fm_mac.h"
+
+#define DTSEC_DEFAULT_EXCEPTIONS \
+ ((uint32_t)((DTSEC_IMASK_BREN) |\
+ (DTSEC_IMASK_RXCEN) |\
+ (DTSEC_IMASK_BTEN) |\
+ (DTSEC_IMASK_TXCEN) |\
+ (DTSEC_IMASK_TXEEN) |\
+ (DTSEC_IMASK_ABRTEN) |\
+ (DTSEC_IMASK_LCEN) |\
+ (DTSEC_IMASK_CRLEN) |\
+ (DTSEC_IMASK_XFUNEN) |\
+ (DTSEC_IMASK_IFERREN) |\
+ (DTSEC_IMASK_MAGEN) |\
+ (DTSEC_IMASK_TDPEEN) |\
+ (DTSEC_IMASK_RDPEEN)))
+
+#define MAX_PACKET_ALIGNMENT 31
+#define MAX_INTER_PACKET_GAP 0x7f
+#define MAX_INTER_PALTERNATE_BEB 0x0f
+#define MAX_RETRANSMISSION 0x0f
+#define MAX_COLLISION_WINDOW 0x03ff
+
+/*number of pattern match registers (entries) */
+#define DTSEC_NUM_OF_PADDRS 15
+
+/* Group address bit indication */
+#define GROUP_ADDRESS 0x0000010000000000LL
+
+/* Hash table size (32 bits*8 regs) */
+#define DTSEC_HASH_TABLE_SIZE 256
+/* Extended Hash table size (32 bits*16 regs) */
+#define EXTENDED_HASH_TABLE_SIZE 512
+
+/* number of pattern match registers (entries) */
+#define DTSEC_TO_MII_OFFSET 0x1000
+/* maximum number of phys */
+#define MAX_PHYS 32
+
+#define VAL32BIT 0x100000000LL
+#define VAL22BIT 0x00400000
+#define VAL16BIT 0x00010000
+#define VAL12BIT 0x00001000
+
+/* CAR1/2 bits */
+#define CAR1_TR64 0x80000000
+#define CAR1_TR127 0x40000000
+#define CAR1_TR255 0x20000000
+#define CAR1_TR511 0x10000000
+#define CAR1_TRK1 0x08000000
+#define CAR1_TRMAX 0x04000000
+#define CAR1_TRMGV 0x02000000
+
+#define CAR1_RBYT 0x00010000
+#define CAR1_RPKT 0x00008000
+#define CAR1_RMCA 0x00002000
+#define CAR1_RBCA 0x00001000
+#define CAR1_RXPF 0x00000400
+#define CAR1_RALN 0x00000100
+#define CAR1_RFLR 0x00000080
+#define CAR1_RCDE 0x00000040
+#define CAR1_RCSE 0x00000020
+#define CAR1_RUND 0x00000010
+#define CAR1_ROVR 0x00000008
+#define CAR1_RFRG 0x00000004
+#define CAR1_RJBR 0x00000002
+#define CAR1_RDRP 0x00000001
+
+#define CAR2_TFCS 0x00040000
+#define CAR2_TBYT 0x00002000
+#define CAR2_TPKT 0x00001000
+#define CAR2_TMCA 0x00000800
+#define CAR2_TBCA 0x00000400
+#define CAR2_TXPF 0x00000200
+#define CAR2_TDRP 0x00000001
+
+struct internal_statistics_t {
+ uint64_t tr64;
+ uint64_t tr127;
+ uint64_t tr255;
+ uint64_t tr511;
+ uint64_t tr1k;
+ uint64_t trmax;
+ uint64_t trmgv;
+ uint64_t rfrg;
+ uint64_t rjbr;
+ uint64_t rdrp;
+ uint64_t raln;
+ uint64_t rund;
+ uint64_t rovr;
+ uint64_t rxpf;
+ uint64_t txpf;
+ uint64_t rbyt;
+ uint64_t rpkt;
+ uint64_t rmca;
+ uint64_t rbca;
+ uint64_t rflr;
+ uint64_t rcde;
+ uint64_t rcse;
+ uint64_t tbyt;
+ uint64_t tpkt;
+ uint64_t tmca;
+ uint64_t tbca;
+ uint64_t tdrp;
+ uint64_t tfcs;
+};
+
+struct dtsec_t {
+ /* pointer to dTSEC memory mapped registers. */
+ struct dtsec_regs __iomem *p_mem_map;
+ /* pointer to dTSEC MII memory mapped registers. */
+ struct dtsec_mii_reg __iomem *p_mii_mem_map;
+ /* MAC address of device; */
+ uint64_t addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *f_exception;
+ fm_mac_exception_cb *f_event;
+ /* Whether a particular individual address recognition
+ * register is being used
+ */
+ bool ind_addr_reg_used[DTSEC_NUM_OF_PADDRS];
+ /* MAC address for particular individual
+ * address recognition register
+ */
+ uint64_t paddr[DTSEC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station. */
+ uint8_t num_of_ind_addr_in_regs;
+ struct internal_statistics_t internal_statistics;
+ /* pointer to driver's global address hash table */
+ struct eth_hash_t *p_multicast_addr_hash;
+ /* pointer to driver's individual address hash table */
+ struct eth_hash_t *p_unicast_addr_hash;
+ uint8_t mac_id;
+ uint8_t tbi_phy_addr;
+ uint32_t exceptions;
+ bool ptp_tsu_enabled;
+ bool en_tsu_err_exeption;
+ struct dtsec_cfg *p_dtsec_drv_param;
+ uint16_t clk_freq;
+ void *h_fm;
+ struct fm_revision_info_t fm_rev_info;
+};
+
+void *dtsec_config(struct fm_mac_params_t *p_fm_mac_param);
+int dtsec_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val);
+int dtsec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr);
+int dtsec_adjust_link(struct fm_mac_dev *fm_mac_dev,
+ enum ethernet_speed speed);
+int dtsec_restart_autoneg(struct fm_mac_dev *fm_mac_dev);
+int dtsec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val);
+int dtsec_cfg_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool new_val);
+int dtsec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int dtsec_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int dtsec_init(struct fm_mac_dev *fm_mac_dev);
+int dtsec_free(struct fm_mac_dev *fm_mac_dev);
+int dtsec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en);
+/* Function dtsec_set_tx_pause_frames
+ * Description Enable/Disable transmission of Pause-Frames.
+ * The routine changes the default configuration:
+ * pause-time - [DEFAULT_TX_PAUSE_TIME]
+ * threshold-time - [0]
+ * Param[in] fm_mac_dev - Pointer to MAC object
+ * Param[in] priority - the PFC class of service; use 'FM_MAC_NO_PFC'
+ * to indicate legacy pause support (i.e. no PFC).
+ * Param[in] pause_time - Pause quanta value used with transmitted pause
+ * frames. Each quanta represents a 512 bit-times;
+ * Note that '0' as an input here will be used as disabling the
+ * transmission of the pause-frames.
+ * Param[in] For legacy pause support (i.e. no PFC), thus
+ * value should be '0'.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following dtsec_init().
+ */
+int dtsec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, uint8_t priority,
+ uint16_t pause_time, uint16_t thresh_time);
+int dtsec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception, bool enable);
+int dtsec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+int dtsec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+int dtsec_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *mac_version);
+
+#endif /* __DTSEC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c
new file mode 100644
index 0000000..653c900
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.c
@@ -0,0 +1,82 @@
+/*
+ * 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 dtsec MII register access MAC ... */
+
+#include "service.h"
+#include "fm_mac.h"
+#include "fm_dtsec.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+int dtsec_mii_write_phy_reg(void *h_dtsec, uint8_t phy_addr, uint8_t reg,
+ uint16_t data)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)h_dtsec;
+ struct dtsec_mii_reg __iomem *miiregs;
+ uint16_t dtsec_freq;
+ int err;
+
+ dtsec_freq = (uint16_t)(p_dtsec->clk_freq >> 1);
+ miiregs = p_dtsec->p_mii_mem_map;
+
+ err =
+ (int)fman_dtsec_mii_write_reg(miiregs, phy_addr, reg, data,
+ dtsec_freq);
+
+ return err;
+}
+
+int dtsec_mii_read_phy_reg(void *h_dtsec, uint8_t phy_addr, uint8_t reg,
+ uint16_t *p_data)
+{
+ struct dtsec_t *p_dtsec = (struct dtsec_t *)h_dtsec;
+ struct dtsec_mii_reg __iomem *miiregs;
+ uint16_t dtsec_freq;
+ int err;
+
+ dtsec_freq = (uint16_t)(p_dtsec->clk_freq >> 1);
+ miiregs = p_dtsec->p_mii_mem_map;
+
+ err =
+ (int)fman_dtsec_mii_read_reg(miiregs, phy_addr, reg, p_data,
+ dtsec_freq);
+
+ if (*p_data == 0xffff) {
+ pr_warn("Read wrong data(0xffff):phy_addr 0x%x,reg 0x%x",
+ phy_addr, reg);
+ return -ENXIO;
+ }
+ if (err)
+ return err;
+
+ return err;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h
new file mode 100644
index 0000000..e599642
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec_mii_acc.h
@@ -0,0 +1,43 @@
+/*
+ * 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 __DTSEC_MII_ACC_H
+#define __DTSEC_MII_ACC_H
+
+#include "service.h"
+
+int dtsec_mii_write_phy_reg(void *h_dtsec, uint8_t phy_addr, uint8_t reg,
+ uint16_t data);
+int dtsec_mii_read_phy_reg(void *h_dtsec, uint8_t phy_addr, uint8_t reg,
+ uint16_t *p_data);
+
+#endif /* __DTSEC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_mac.h b/drivers/net/ethernet/freescale/fman/mac/fm_mac.h
new file mode 100644
index 0000000..b3c160a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_mac.h
@@ -0,0 +1,250 @@
+/*
+ * 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 MAC ... */
+#ifndef __FM_MAC_H
+#define __FM_MAC_H
+
+#include "enet_ext.h"
+#include "service.h"
+#include "fm_common.h"
+
+#include <linux/slab.h>
+
+struct fm_mac_dev;
+
+/* defaults */
+#define DEFAULT_RESET_ON_INIT false
+
+/* PFC defines */
+#define FSL_FM_PAUSE_TIME_ENABLE 0xf000
+#define FSL_FM_PAUSE_TIME_DISABLE 0
+#define FSL_FM_PAUSE_THRESH_DEFAULT 0
+
+#define FM_MAC_NO_PFC 0xff
+
+/* HASH defines */
+#define ETH_HASH_ENTRY_OBJ(ptr) list_object(ptr, struct eth_hash_entry_t, node)
+
+/* FM MAC Exceptions */
+enum fm_mac_exceptions {
+ FM_MAC_EX_10G_MDIO_SCAN_EVENT = 0
+ /* 10GEC MDIO scan event interrupt */
+ , FM_MAC_EX_10G_MDIO_CMD_CMPL
+ /* 10GEC MDIO command completion interrupt */
+ , FM_MAC_EX_10G_REM_FAULT
+ /* 10GEC, mEMAC Remote fault interrupt */
+ , FM_MAC_EX_10G_LOC_FAULT
+ /* 10GEC, mEMAC Local fault interrupt */
+ , FM_MAC_EX_10G_TX_ECC_ER
+ /* 10GEC, mEMAC Transmit frame ECC error interrupt */
+ , FM_MAC_EX_10G_TX_FIFO_UNFL
+ /* 10GEC, mEMAC Transmit FIFO underflow interrupt */
+ , FM_MAC_EX_10G_TX_FIFO_OVFL
+ /* 10GEC, mEMAC Transmit FIFO overflow interrupt */
+ , FM_MAC_EX_10G_TX_ER
+ /* 10GEC Transmit frame error interrupt */
+ , FM_MAC_EX_10G_RX_FIFO_OVFL
+ /* 10GEC, mEMAC Receive FIFO overflow interrupt */
+ , FM_MAC_EX_10G_RX_ECC_ER
+ /* 10GEC, mEMAC Receive frame ECC error interrupt */
+ , FM_MAC_EX_10G_RX_JAB_FRM
+ /* 10GEC Receive jabber frame interrupt */
+ , FM_MAC_EX_10G_RX_OVRSZ_FRM
+ /* 10GEC Receive oversized frame interrupt */
+ , FM_MAC_EX_10G_RX_RUNT_FRM
+ /* 10GEC Receive runt frame interrupt */
+ , FM_MAC_EX_10G_RX_FRAG_FRM
+ /* 10GEC Receive fragment frame interrupt */
+ , FM_MAC_EX_10G_RX_LEN_ER
+ /* 10GEC Receive payload length error interrupt */
+ , FM_MAC_EX_10G_RX_CRC_ER
+ /* 10GEC Receive CRC error interrupt */
+ , FM_MAC_EX_10G_RX_ALIGN_ER
+ /* 10GEC Receive alignment error interrupt */
+ , FM_MAC_EX_1G_BAB_RX
+ /* dTSEC Babbling receive error */
+ , FM_MAC_EX_1G_RX_CTL
+ /* dTSEC Receive control (pause frame) interrupt */
+ , FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET
+ /* dTSEC Graceful transmit stop complete */
+ , FM_MAC_EX_1G_BAB_TX
+ /* dTSEC Babbling transmit error */
+ , FM_MAC_EX_1G_TX_CTL
+ /* dTSEC Transmit control (pause frame) interrupt */
+ , FM_MAC_EX_1G_TX_ERR
+ /* dTSEC Transmit error */
+ , FM_MAC_EX_1G_LATE_COL
+ /* dTSEC Late collision */
+ , FM_MAC_EX_1G_COL_RET_LMT
+ /* dTSEC Collision retry limit */
+ , FM_MAC_EX_1G_TX_FIFO_UNDRN
+ /* dTSEC Transmit FIFO underrun */
+ , FM_MAC_EX_1G_MAG_PCKT
+ /* dTSEC Magic Packet detection */
+ , FM_MAC_EX_1G_MII_MNG_RD_COMPLET
+ /* dTSEC MII management read completion */
+ , FM_MAC_EX_1G_MII_MNG_WR_COMPLET
+ /* dTSEC MII management write completion */
+ , FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET
+ /* dTSEC Graceful receive stop complete */
+ , FM_MAC_EX_1G_DATA_ERR
+ /* dTSEC Internal data error on transmit */
+ , FM_MAC_1G_RX_DATA_ERR
+ /* dTSEC Internal data error on receive */
+ , FM_MAC_EX_1G_1588_TS_RX_ERR
+ /* dTSEC Time-Stamp Receive Error */
+ , FM_MAC_EX_1G_RX_MIB_CNT_OVFL
+ /* dTSEC MIB counter overflow */
+ , FM_MAC_EX_TS_FIFO_ECC_ERR
+ /* mEMAC Time-stamp FIFO ECC error interrupt;
+ * not supported on T4240/B4860 rev1 chips
+ */
+ , FM_MAC_EX_MAGIC_PACKET_INDICATION = FM_MAC_EX_1G_MAG_PCKT
+ /* mEMAC Magic Packet Indication Interrupt */
+};
+
+struct eth_hash_entry_t {
+ uint64_t addr; /* Ethernet Address */
+ struct list_head node;
+};
+
+typedef void (fm_mac_exception_cb) (void *dev_id,
+ enum fm_mac_exceptions exceptions);
+
+/* FM MAC config input */
+struct fm_mac_params_t {
+ /* Base of memory mapped FM MAC registers */
+ uintptr_t base_addr;
+ /* MAC address of device; First octet is sent first */
+ enet_addr_t addr;
+ /* MAC ID; numbering of dTSEC and 1G-mEMAC:
+ * 0 - FM_MAX_NUM_OF_1G_MACS;
+ * numbering of 10G-MAC (TGEC) and 10G-mEMAC:
+ * 0 - FM_MAX_NUM_OF_10G_MACS
+ */
+ uint8_t mac_id;
+ /* Ethernet operation mode (MAC-PHY interface and speed);
+ * Note that the speed should indicate the maximum rate that
+ * this MAC should support rather than the actual speed;
+ * i.e. user should use the FM_MAC_AdjustLink() routine to
+ * provide accurate speed;
+ * In case of mEMAC RGMII mode, the MAC is configured to RGMII
+ * automatic mode, where actual speed/duplex mode information
+ * is provided by PHY automatically in-band; FM_MAC_AdjustLink()
+ * function should be used to switch to manual RGMII speed/duplex mode
+ * configuration if RGMII PHY doesn't support in-band status signaling;
+ * In addition, in mEMAC, in case where user is using the higher MACs
+ * (i.e. the MACs that should support 10G), user should pass here
+ * speed=10000 even if the interface is not allowing that (e.g. SGMII).
+ */
+ enum e_enet_mode enet_mode;
+ /* A handle to the FM object this port related to */
+ void *h_fm;
+ /* MDIO exceptions interrupt source - not valid for all
+ * MACs; MUST be set to 'NO_IRQ' for MACs that don't have
+ * mdio-irq, or for polling
+ */
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *f_event; /* MDIO Events Callback Routine */
+ fm_mac_exception_cb *f_exception; /* Exception Callback Routine */
+};
+
+struct eth_hash_t {
+ uint16_t size;
+ struct list_head *p_lsts;
+};
+
+static inline struct eth_hash_entry_t
+*dequeue_addr_from_hash_entry(struct list_head *p_addr_lst)
+{
+ struct eth_hash_entry_t *p_hash_entry = NULL;
+
+ if (!list_empty(p_addr_lst)) {
+ p_hash_entry = ETH_HASH_ENTRY_OBJ(p_addr_lst->next);
+ list_del_init(&p_hash_entry->node);
+ }
+ return p_hash_entry;
+}
+
+static inline void free_hash_table(struct eth_hash_t *p_hash)
+{
+ struct eth_hash_entry_t *p_hash_entry;
+ int i = 0;
+
+ if (p_hash) {
+ if (p_hash->p_lsts) {
+ for (i = 0; i < p_hash->size; i++) {
+ p_hash_entry =
+ dequeue_addr_from_hash_entry(&p_hash->
+ p_lsts[i]);
+ while (p_hash_entry) {
+ kfree(p_hash_entry);
+ p_hash_entry =
+ dequeue_addr_from_hash_entry
+ (&p_hash->p_lsts[i]);
+ }
+ }
+
+ kfree(p_hash->p_lsts);
+ }
+
+ kfree(p_hash);
+ }
+}
+
+static inline struct eth_hash_t *alloc_hash_table(uint16_t size)
+{
+ uint32_t i;
+ struct eth_hash_t *p_hash;
+
+ /* Allocate address hash table */
+ p_hash = kmalloc_array(size, sizeof(struct eth_hash_t *), GFP_KERNEL);
+ if (!p_hash)
+ return NULL;
+
+ p_hash->size = size;
+
+ p_hash->p_lsts = kmalloc_array(p_hash->size, sizeof(struct list_head),
+ GFP_KERNEL);
+ if (!p_hash->p_lsts) {
+ kfree(p_hash);
+ return NULL;
+ }
+
+ for (i = 0; i < p_hash->size; i++)
+ INIT_LIST_HEAD(&p_hash->p_lsts[i]);
+
+ return p_hash;
+}
+
+#endif /* __FM_MAC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_memac.c b/drivers/net/ethernet/freescale/fman/mac/fm_memac.c
new file mode 100644
index 0000000..fcc70d7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac.c
@@ -0,0 +1,741 @@
+/*
+ * 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 mEMAC driver */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "service.h"
+
+#include "fm_common.h"
+#include "fm_memac.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/* Internal routine */
+static uint32_t get_mac_addr_hash_code(uint64_t eth_addr)
+{
+ uint64_t mask1, mask2;
+ uint32_t xor_val = 0;
+ uint8_t i, j;
+
+ for (i = 0; i < 6; i++) {
+ mask1 = eth_addr & (uint64_t)0x01;
+ eth_addr >>= 1;
+
+ for (j = 0; j < 7; j++) {
+ mask2 = eth_addr & (uint64_t)0x01;
+ mask1 ^= mask2;
+ eth_addr >>= 1;
+ }
+
+ xor_val |= (mask1 << (5 - i));
+ }
+
+ return xor_val;
+}
+
+static void setup_sgmii_internal_phy(struct memac_t *p_memac, uint8_t phy_addr)
+{
+ uint16_t tmp_reg16;
+ enum e_enet_mode enet_mode;
+
+ /* In case the higher MACs are used (i.e. the MACs that should
+ * support 10G), speed=10000 is provided for SGMII ports.
+ * Temporary modify enet mode to 1G one, so MII functions can
+ * work correctly.
+ */
+ enet_mode = p_memac->enet_mode;
+ p_memac->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_memac->enet_mode),
+ ENET_SPEED_1000);
+
+ /* SGMII mode + AN enable */
+ tmp_reg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x14, tmp_reg16);
+
+ /* Device ability according to SGMII specification */
+ tmp_reg16 = PHY_SGMII_DEV_ABILITY_SGMII;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x4, tmp_reg16);
+
+ /* Adjust link timer for SGMII -
+ * According to Cisco SGMII specification the timer should be 1.6 ms.
+ * The link_timer register is configured in units of the clock.
+ * - When running as 1G SGMII, Serdes clock is 125 MHz, so
+ * unit = 1 / (125*10^6 Hz) = 8 ns.
+ * 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2*10^5 = 0x30d40
+ * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
+ * unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
+ * 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5*10^5 = 0x7a120.
+ * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
+ * we always set up here a value of 2.5 SGMII.
+ */
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x13, 0x0007);
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x12, 0xa120);
+
+ /* Restart AN */
+ tmp_reg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x0, tmp_reg16);
+
+ /* Restore original enet mode */
+ p_memac->enet_mode = enet_mode;
+}
+
+static void setup_sgmii_internal_phy_base_x(struct memac_t *p_memac,
+ uint8_t phy_addr)
+{
+ uint16_t tmp_reg16;
+ enum e_enet_mode enet_mode;
+
+ /* In case the higher MACs are used (i.e. the MACs that
+ * should support 10G), speed=10000 is provided for SGMII ports.
+ * Temporary modify enet mode to 1G one, so MII functions can
+ * work correctly.
+ */
+ enet_mode = p_memac->enet_mode;
+ p_memac->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_memac->enet_mode),
+ ENET_SPEED_1000);
+
+ /* 1000BaseX mode */
+ tmp_reg16 = PHY_SGMII_IF_MODE_1000X;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x14, tmp_reg16);
+
+ /* AN Device capability */
+ tmp_reg16 = PHY_SGMII_DEV_ABILITY_1000X;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x4, tmp_reg16);
+
+ /* Adjust link timer for SGMII -
+ * For Serdes 1000BaseX auto-negotiation the timer should be 10 ms.
+ * The link_timer register is configured in units of the clock.
+ * - When running as 1G SGMII, Serdes clock is 125 MHz, so
+ * unit = 1 / (125*10^6 Hz) = 8 ns.
+ * 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0
+ * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
+ * unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
+ * 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08.
+ * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
+ * we always set up here a value of 2.5 SGMII.
+ */
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x13, 0x002f);
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x12, 0xaf08);
+
+ /* Restart AN */
+ tmp_reg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ memac_mii_write_phy_reg(p_memac, phy_addr, 0x0, tmp_reg16);
+
+ /* Restore original enet mode */
+ p_memac->enet_mode = enet_mode;
+}
+
+static int check_init_parameters(struct memac_t *p_memac)
+{
+ if (p_memac->addr == 0) {
+ pr_err("Ethernet MAC must have a valid MAC address\n");
+ return -EDOM;
+ }
+ if (!p_memac->f_exception) {
+ pr_err("Uninitialized f_exception\n");
+ return -EDOM;
+ }
+ if (!p_memac->f_event) {
+ pr_warn("Uninitialize f_event\n");
+ return -EDOM;
+ }
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (!p_memac->p_memac_drv_param->no_length_check_enable) {
+ pr_err("LengthCheck!\n");
+ return -EINVAL;
+ }
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ uint32_t bit_mask;
+
+ switch (exception) {
+ case FM_MAC_EX_10G_TX_ECC_ER:
+ bit_mask = MEMAC_IMASK_TECC_ER;
+ break;
+ case FM_MAC_EX_10G_RX_ECC_ER:
+ bit_mask = MEMAC_IMASK_RECC_ER;
+ break;
+ case FM_MAC_EX_TS_FIFO_ECC_ERR:
+ bit_mask = MEMAC_IMASK_TSECC_ER;
+ break;
+ case FM_MAC_EX_MAGIC_PACKET_INDICATION:
+ bit_mask = MEMAC_IMASK_MGI;
+ break;
+ default:
+ bit_mask = 0;
+ break;
+ }
+
+ return bit_mask;
+}
+
+static void memac_err_exception(void *h_memac)
+{
+ struct memac_t *p_memac = (struct memac_t *)h_memac;
+ uint32_t event, imask;
+
+ event = fman_memac_get_event(p_memac->p_mem_map, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(p_memac->p_mem_map);
+
+ /* Imask include both error and notification/event bits.
+ * Leaving only error bits enabled by imask.
+ * The imask error bits are shifted by 16 bits offset from
+ * their corresponding location in the ievent - hence the >> 16
+ */
+ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
+
+ fman_memac_ack_event(p_memac->p_mem_map, event);
+
+ if (event & MEMAC_IEVNT_TS_ECC_ER)
+ p_memac->f_exception(p_memac->dev_id,
+ FM_MAC_EX_TS_FIFO_ECC_ERR);
+ if (event & MEMAC_IEVNT_TX_ECC_ER)
+ p_memac->f_exception(p_memac->dev_id,
+ FM_MAC_EX_10G_TX_ECC_ER);
+ if (event & MEMAC_IEVNT_RX_ECC_ER)
+ p_memac->f_exception(p_memac->dev_id,
+ FM_MAC_EX_10G_RX_ECC_ER);
+}
+
+static void memac_exception(void *h_memac)
+{
+ struct memac_t *p_memac = (struct memac_t *)h_memac;
+ uint32_t event, imask;
+
+ event = fman_memac_get_event(p_memac->p_mem_map, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(p_memac->p_mem_map);
+
+ /* Imask include both error and notification/event bits.
+ * Leaving only error bits enabled by imask.
+ * The imask error bits are shifted by 16 bits offset from
+ * their corresponding location in the ievent - hence the >> 16
+ */
+ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
+
+ fman_memac_ack_event(p_memac->p_mem_map, event);
+
+ if (event & MEMAC_IEVNT_MGI)
+ p_memac->f_exception(p_memac->dev_id,
+ FM_MAC_EX_MAGIC_PACKET_INDICATION);
+}
+
+static void free_init_resources(struct memac_t *p_memac)
+{
+ fm_unregister_intr(p_memac->h_fm, FM_MOD_MAC, p_memac->mac_id,
+ FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ free_hash_table(p_memac->p_multicast_addr_hash);
+ p_memac->p_multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(p_memac->p_unicast_addr_hash);
+ p_memac->p_unicast_addr_hash = NULL;
+}
+
+/* Checks if p_memac driver parameters were initialized
+ * returns 0 if success else returns error code
+ */
+static int is_init_done(struct memac_cfg *p_memac_drv_parameters)
+{
+ if (!p_memac_drv_parameters)
+ return 0;
+ return -EINVAL;
+}
+
+/* mEMAC API routine */
+
+int memac_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_enable(p_memac->p_mem_map,
+ (mode & COMM_MODE_RX),
+ (mode & COMM_MODE_TX));
+
+ return 0;
+}
+
+int memac_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_disable(p_memac->p_mem_map,
+ (mode & COMM_MODE_RX),
+ (mode & COMM_MODE_TX));
+
+ return 0;
+}
+
+int memac_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_set_promiscuous(p_memac->p_mem_map, new_val);
+
+ return 0;
+}
+
+int memac_adjust_link(struct fm_mac_dev *fm_mac_dev, enum ethernet_speed speed)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret, full_duplex = true;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_adjust_link(p_memac->p_mem_map,
+ (enum enet_interface)
+ ENET_INTERFACE_FROM_MODE(p_memac->enet_mode),
+ (enum enet_speed)speed, full_duplex);
+ return 0;
+}
+
+/* memac configs modification function */
+
+int memac_cfg_lb(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_memac->p_memac_drv_param->loopback_enable = new_val;
+
+ return 0;
+}
+
+int memac_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_memac->p_memac_drv_param->max_frame_length = new_val;
+
+ return 0;
+}
+
+int memac_cfg_pad(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_memac->p_memac_drv_param->pad_enable = new_val;
+
+ return 0;
+}
+
+int memac_cfg_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_memac->p_memac_drv_param->reset_on_init = enable;
+
+ return 0;
+}
+
+/* memac run time api functions */
+
+int memac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ uint8_t __maybe_unused priority,
+ uint16_t pause_time,
+ uint16_t __maybe_unused thresh_time)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+
+ fman_memac_set_tx_pause_frames(p_memac->p_mem_map, FM_MAC_NO_PFC,
+ pause_time, 0);
+
+ return 0;
+}
+
+int memac_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_set_rx_ignore_pause_frames(p_memac->p_mem_map, !en);
+
+ return 0;
+}
+
+int memac_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ fman_memac_add_addr_in_paddr(p_memac->p_mem_map,
+ (uint8_t *)(*p_enet_addr), 0);
+
+ return 0;
+}
+
+int memac_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ struct eth_hash_entry_t *p_hash_entry;
+ uint32_t hash;
+ uint64_t eth_addr;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ENET_ADDR_TO_UINT64(*p_eth_addr);
+
+ if (!(eth_addr & GROUP_ADDRESS)) {
+ /* Unicast addresses not supported in hash */
+ pr_err("Unicast Address\n");
+ return -EINVAL;
+ }
+ hash = get_mac_addr_hash_code(eth_addr) & HASH_CTRL_ADDR_MASK;
+
+ /* Create element to be added to the driver hash table */
+ p_hash_entry = kmalloc(sizeof(*p_hash_entry), GFP_KERNEL);
+ if (!p_hash_entry)
+ return -ENOMEM;
+ p_hash_entry->addr = eth_addr;
+ INIT_LIST_HEAD(&p_hash_entry->node);
+
+ list_add_tail(&p_hash_entry->node,
+ &p_memac->p_multicast_addr_hash->p_lsts[hash]);
+ fman_memac_set_hash_table(p_memac->p_mem_map,
+ (hash | HASH_CTRL_MCAST_EN));
+
+ return 0;
+}
+
+int memac_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ struct eth_hash_entry_t *p_hash_entry = NULL;
+ struct list_head *p_pos;
+ uint32_t hash;
+ uint64_t eth_addr;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ENET_ADDR_TO_UINT64(*p_eth_addr);
+
+ hash = get_mac_addr_hash_code(eth_addr) & HASH_CTRL_ADDR_MASK;
+
+ list_for_each(p_pos, &p_memac->p_multicast_addr_hash->p_lsts[hash]) {
+ p_hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (p_hash_entry->addr == eth_addr) {
+ list_del_init(&p_hash_entry->node);
+ kfree(p_hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&p_memac->p_multicast_addr_hash->p_lsts[hash]))
+ fman_memac_set_hash_table(p_memac->p_mem_map,
+ (hash & ~HASH_CTRL_MCAST_EN));
+
+ return 0;
+}
+
+int memac_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ uint32_t bit_mask = 0;
+ int ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (ret)
+ return ret;
+
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ p_memac->exceptions |= bit_mask;
+ else
+ p_memac->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EDOM;
+ }
+ fman_memac_set_exception(p_memac->p_mem_map, bit_mask, enable);
+
+ return 0;
+}
+
+/* mEMAC Init & Free API */
+int memac_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+ struct memac_cfg *p_memac_drv_param;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ uint8_t i, phy_addr;
+ enet_addr_t eth_addr;
+ enum fm_mac_type port_type;
+ bool slow_10g_if = false;
+ int err, ret;
+
+ ret = is_init_done(p_memac->p_memac_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ err = check_init_parameters(p_memac);
+ if (err)
+ return err;
+
+ p_memac_drv_param = p_memac->p_memac_drv_param;
+
+ if (p_memac->fm_rev_info.major_rev == 6 &&
+ p_memac->fm_rev_info.minor_rev == 4)
+ slow_10g_if = true;
+
+ port_type =
+ ((ENET_SPEED_FROM_MODE(p_memac->enet_mode) <
+ ENET_SPEED_10000) ? FM_MAC_1G : FM_MAC_10G);
+
+ /* First, reset the MAC if desired. */
+ if (p_memac_drv_param->reset_on_init)
+ fman_memac_reset(p_memac->p_mem_map);
+
+ /* MAC Address */
+ MAKE_ENET_ADDR_FROM_UINT64(p_memac->addr, eth_addr);
+ fman_memac_add_addr_in_paddr(p_memac->p_mem_map,
+ (uint8_t *)eth_addr, 0);
+
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_memac->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_memac->enet_mode);
+
+ fman_memac_init(p_memac->p_mem_map,
+ p_memac->p_memac_drv_param,
+ enet_interface,
+ enet_speed,
+ slow_10g_if,
+ p_memac->exceptions);
+
+#ifdef FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
+ {
+ uint32_t tmp_reg = 0;
+
+ /* check the FMAN version - the bug exists only in rev1 */
+ if ((p_memac->fm_rev_info.major_rev == 6) &&
+ ((p_memac->fm_rev_info.minor_rev == 0) ||
+ (p_memac->fm_rev_info.minor_rev == 3))) {
+ /* MAC strips CRC from received frames - this
+ * workaround should decrease the likelihood of bug
+ * appearance
+ */
+ tmp_reg = GET_UINT32(p_memac->p_mem_map->
+ command_config);
+ tmp_reg &= ~CMD_CFG_CRC_FWD;
+ WRITE_UINT32(p_memac->p_mem_map->command_config,
+ tmp_reg);
+ }
+ }
+#endif /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 */
+
+ if (ENET_INTERFACE_FROM_MODE(p_memac->enet_mode) == ENET_IF_SGMII) {
+ /* Configure internal SGMII PHY */
+ if (p_memac->enet_mode & ENET_IF_SGMII_BASEX)
+ setup_sgmii_internal_phy_base_x(p_memac, PHY_MDIO_ADDR);
+ else
+ setup_sgmii_internal_phy(p_memac, PHY_MDIO_ADDR);
+ } else if (ENET_INTERFACE_FROM_MODE(p_memac->enet_mode) ==
+ ENET_IF_QSGMII) {
+ /* Configure 4 internal SGMII PHYs */
+ for (i = 0; i < 4; i++) {
+ /* QSGMII PHY address occupies 3 upper bits of 5-bit
+ * phy_address; the lower 2 bits are used to extend
+ * register address space and access each one of 4
+ * ports inside QSGMII.
+ */
+ phy_addr = (uint8_t)((PHY_MDIO_ADDR << 2) | i);
+ if (p_memac->enet_mode & ENET_IF_SGMII_BASEX)
+ setup_sgmii_internal_phy_base_x(p_memac,
+ phy_addr);
+ else
+ setup_sgmii_internal_phy(p_memac, phy_addr);
+ }
+ }
+
+ /* Max Frame Length */
+ err = fm_set_mac_max_frame(p_memac->h_fm,
+ port_type,
+ p_memac->mac_id,
+ p_memac_drv_param->max_frame_length);
+ if (err) {
+ pr_err("settings Mac max frame length is FAILED\n");
+ return err;
+ }
+
+ p_memac->p_multicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE);
+ if (!p_memac->p_multicast_addr_hash) {
+ free_init_resources(p_memac);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ p_memac->p_unicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE);
+ if (!p_memac->p_unicast_addr_hash) {
+ free_init_resources(p_memac);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ fm_register_intr(p_memac->h_fm,
+ FM_MOD_MAC,
+ p_memac->mac_id,
+ FM_INTR_TYPE_ERR,
+ memac_err_exception,
+ p_memac);
+
+ fm_register_intr(p_memac->h_fm, FM_MOD_MAC, p_memac->mac_id,
+ FM_INTR_TYPE_NORMAL, memac_exception, p_memac);
+
+ kfree(p_memac_drv_param);
+ p_memac->p_memac_drv_param = NULL;
+
+ return 0;
+}
+
+int memac_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct memac_t *p_memac = (struct memac_t *)fm_mac_dev;
+
+ free_init_resources(p_memac);
+
+ kfree(p_memac->p_memac_drv_param);
+ kfree(p_memac);
+
+ return 0;
+}
+
+/* m_emac config main entry */
+
+void *memac_config(struct fm_mac_params_t *p_fm_mac_param)
+{
+ struct memac_t *p_memac;
+ struct memac_cfg *p_memac_drv_param;
+ uintptr_t base_addr;
+
+ base_addr = p_fm_mac_param->base_addr;
+ /* allocate memory for the m_emac data structure */
+ p_memac = kzalloc(sizeof(*p_memac), GFP_KERNEL);
+ if (!p_memac)
+ return NULL;
+
+ /* allocate memory for the m_emac driver parameters data structure */
+ p_memac_drv_param = kzalloc(sizeof(*p_memac_drv_param),
+ GFP_KERNEL);
+ if (!p_memac_drv_param) {
+ memac_free((struct fm_mac_dev *)p_memac);
+ return NULL;
+ }
+
+ /* Plant parameter structure pointer */
+ p_memac->p_memac_drv_param = p_memac_drv_param;
+
+ fman_memac_defconfig(p_memac_drv_param);
+
+ p_memac->addr = ENET_ADDR_TO_UINT64(p_fm_mac_param->addr);
+
+ p_memac->p_mem_map =
+ (struct memac_regs __iomem *)UINT_TO_PTR(base_addr);
+ p_memac->p_mii_mem_map = (struct memac_mii_access_mem_map __iomem *)
+ UINT_TO_PTR(base_addr + MEMAC_TO_MII_OFFSET);
+
+ p_memac->enet_mode = p_fm_mac_param->enet_mode;
+ p_memac->mac_id = p_fm_mac_param->mac_id;
+ p_memac->exceptions = MEMAC_DEFAULT_EXCEPTIONS;
+ p_memac->f_exception = p_fm_mac_param->f_exception;
+ p_memac->f_event = p_fm_mac_param->f_event;
+ p_memac->dev_id = p_fm_mac_param->dev_id;
+ p_memac->h_fm = p_fm_mac_param->h_fm;
+
+ /* Save FMan revision */
+ fm_get_revision(p_memac->h_fm, &p_memac->fm_rev_info);
+
+ return p_memac;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_memac.h b/drivers/net/ethernet/freescale/fman/mac/fm_memac.h
new file mode 100644
index 0000000..b119855
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac.h
@@ -0,0 +1,124 @@
+/*
+ * 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 Multirate Ethernet MAC (mEMAC) */
+#ifndef __MEMAC_H
+#define __MEMAC_H
+
+#include "service.h"
+
+#include "fsl_fman_memac_mii_acc.h"
+#include "fm_mac.h"
+#include "fsl_fman_memac.h"
+
+#define MEMAC_DEFAULT_EXCEPTIONS \
+ ((uint32_t)(MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | \
+ MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI))
+
+struct memac_t {
+ /* Pointer to MAC memory mapped registers */
+ struct memac_regs __iomem *p_mem_map;
+ /* Pointer to MII memory mapped registers */
+ struct memac_mii_access_mem_map __iomem *p_mii_mem_map;
+ /* MAC address of device */
+ uint64_t addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *f_exception;
+ fm_mac_exception_cb *f_event;
+ /* Whether a particular individual address
+ * recognition register is being used
+ */
+ bool ind_addr_reg_used[MEMAC_NUM_OF_PADDRS];
+ /* MAC address for particular individual address
+ * recognition register
+ */
+ uint64_t paddr[MEMAC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station. */
+ uint8_t num_of_ind_addr_in_regs;
+ /* Pointer to driver's global address hash table */
+ struct eth_hash_t *p_multicast_addr_hash;
+ /* Pointer to driver's individual address hash table */
+ struct eth_hash_t *p_unicast_addr_hash;
+ bool debug_mode;
+ uint8_t mac_id;
+ uint32_t exceptions;
+ struct memac_cfg *p_memac_drv_param;
+ void *h_fm;
+ struct fm_revision_info_t fm_rev_info;
+};
+
+/* Internal PHY access */
+#define PHY_MDIO_ADDR 0
+
+/* Internal PHY Registers - SGMII */
+#define PHY_SGMII_CR_RESET_AN 0x0200
+#define PHY_SGMII_CR_DEF_VAL 0x1140
+#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001
+#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0
+#define PHY_SGMII_IF_MODE_AN 0x0002
+#define PHY_SGMII_IF_MODE_SGMII 0x0001
+#define PHY_SGMII_IF_MODE_1000X 0x0000
+
+/* Offset from the MEM map to the MDIO mem map */
+#define MEMAC_TO_MII_OFFSET 0x030
+
+int memac_mii_write_phy_reg(void *h_memac, uint8_t phy_addr, uint8_t reg,
+ uint16_t data);
+int memac_mii_read_phy_reg(void *h_memac, uint8_t phy_addr, uint8_t reg,
+ uint16_t *p_data);
+
+void *memac_config(struct fm_mac_params_t *p_fm_mac_param);
+int memac_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val);
+int memac_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr);
+int memac_adjust_link(struct fm_mac_dev *fm_mac_dev,
+ enum ethernet_speed speed);
+int memac_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val);
+int memac_cfg_pad(struct fm_mac_dev *fm_mac_dev, bool new_val);
+int memac_cfg_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable);
+int memac_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int memac_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int memac_init(struct fm_mac_dev *fm_mac_dev);
+int memac_free(struct fm_mac_dev *fm_mac_dev);
+int memac_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en);
+int memac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, uint8_t priority,
+ uint16_t pause_time, uint16_t thresh_time);
+int memac_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception, bool enable);
+int memac_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+int memac_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+
+#endif /* __MEMAC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.c b/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.c
new file mode 100644
index 0000000..3412248
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.c
@@ -0,0 +1,66 @@
+/*
+ * 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 "service.h"
+#include "fm_mac.h"
+#include "fm_memac.h"
+
+#include "fm_common.h"
+#include "fm_memac_mii_acc.h"
+
+int memac_mii_write_phy_reg(void *h_memac,
+ uint8_t phy_addr, uint8_t reg, uint16_t data)
+{
+ struct memac_t *p_memac = (struct memac_t *)h_memac;
+
+ return (int)fman_memac_mii_write_phy_reg(p_memac->p_mii_mem_map,
+ phy_addr,
+ reg,
+ data,
+ (enum enet_speed)
+ ENET_SPEED_FROM_MODE
+ (p_memac->enet_mode));
+}
+
+int memac_mii_read_phy_reg(void *h_memac,
+ uint8_t phy_addr, uint8_t reg, uint16_t *p_data)
+{
+ struct memac_t *p_memac = (struct memac_t *)h_memac;
+
+ return fman_memac_mii_read_phy_reg(p_memac->p_mii_mem_map,
+ phy_addr,
+ reg,
+ p_data,
+ (enum enet_speed)
+ ENET_SPEED_FROM_MODE(p_memac->
+ enet_mode));
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.h b/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.h
new file mode 100644
index 0000000..f38572c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac_mii_acc.h
@@ -0,0 +1,50 @@
+/*
+ * 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 __MEMAC_MII_ACC_H
+#define __MEMAC_MII_ACC_H
+
+#include "service.h"
+
+/* MII Management Registers */
+#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80
+#define MDIO_CFG_HOLD_MASK 0x0000001c
+#define MDIO_CFG_ENC45 0x00000040
+#define MDIO_CFG_READ_ERR 0x00000002
+#define MDIO_CFG_BSY 0x00000001
+
+#define MDIO_CTL_PHY_ADDR_SHIFT 5
+#define MDIO_CTL_READ 0x00008000
+
+#define MDIO_DATA_BSY 0x80000000
+
+#endif /* __MEMAC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_tgec.c b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
new file mode 100644
index 0000000..d6a9bec
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
@@ -0,0 +1,652 @@
+/*
+ * 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.
+ */
+
+/* TGEC MAC ... */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "service.h"
+#include "crc_mac_addr_ext.h"
+
+#include "fm_common.h"
+#include "fsl_fman_tgec.h"
+#include "fm_tgec.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/bitrev.h>
+
+/* Internal routines */
+
+static int check_init_parameters(struct tgec_t *p_tgec)
+{
+ if (ENET_SPEED_FROM_MODE(p_tgec->enet_mode) < ENET_SPEED_10000) {
+ pr_err("10G MAC driver only support 10G speed\n");
+ return -EDOM;
+ }
+ if (p_tgec->addr == 0) {
+ pr_err("Ethernet 10G MAC Must have valid MAC Address\n");
+ return -EDOM;
+ }
+ if (!p_tgec->f_exception) {
+ pr_err("uninitialized f_exception\n");
+ return -EDOM;
+ }
+ if (!p_tgec->f_event) {
+ pr_err("uninitialized f_event\n");
+ return -EDOM;
+ }
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (!p_tgec->p_tgec_drv_param->no_length_check_enable) {
+ pr_warn("LengthCheck!\n");
+ return -EDOM;
+ }
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ uint32_t bit_mask;
+
+ switch (exception) {
+ case FM_MAC_EX_10G_MDIO_SCAN_EVENT:
+ bit_mask = TGEC_IMASK_MDIO_SCAN_EVENT;
+ break;
+ case FM_MAC_EX_10G_MDIO_CMD_CMPL:
+ bit_mask = TGEC_IMASK_MDIO_CMD_CMPL;
+ break;
+ case FM_MAC_EX_10G_REM_FAULT:
+ bit_mask = TGEC_IMASK_REM_FAULT;
+ break;
+ case FM_MAC_EX_10G_LOC_FAULT:
+ bit_mask = TGEC_IMASK_LOC_FAULT;
+ break;
+ case FM_MAC_EX_10G_TX_ECC_ER:
+ bit_mask = TGEC_IMASK_TX_ECC_ER;
+ break;
+ case FM_MAC_EX_10G_TX_FIFO_UNFL:
+ bit_mask = TGEC_IMASK_TX_FIFO_UNFL;
+ break;
+ case FM_MAC_EX_10G_TX_FIFO_OVFL:
+ bit_mask = TGEC_IMASK_TX_FIFO_OVFL;
+ break;
+ case FM_MAC_EX_10G_TX_ER:
+ bit_mask = TGEC_IMASK_TX_ER;
+ break;
+ case FM_MAC_EX_10G_RX_FIFO_OVFL:
+ bit_mask = TGEC_IMASK_RX_FIFO_OVFL;
+ break;
+ case FM_MAC_EX_10G_RX_ECC_ER:
+ bit_mask = TGEC_IMASK_RX_ECC_ER;
+ break;
+ case FM_MAC_EX_10G_RX_JAB_FRM:
+ bit_mask = TGEC_IMASK_RX_JAB_FRM;
+ break;
+ case FM_MAC_EX_10G_RX_OVRSZ_FRM:
+ bit_mask = TGEC_IMASK_RX_OVRSZ_FRM;
+ break;
+ case FM_MAC_EX_10G_RX_RUNT_FRM:
+ bit_mask = TGEC_IMASK_RX_RUNT_FRM;
+ break;
+ case FM_MAC_EX_10G_RX_FRAG_FRM:
+ bit_mask = TGEC_IMASK_RX_FRAG_FRM;
+ break;
+ case FM_MAC_EX_10G_RX_LEN_ER:
+ bit_mask = TGEC_IMASK_RX_LEN_ER;
+ break;
+ case FM_MAC_EX_10G_RX_CRC_ER:
+ bit_mask = TGEC_IMASK_RX_CRC_ER;
+ break;
+ case FM_MAC_EX_10G_RX_ALIGN_ER:
+ bit_mask = TGEC_IMASK_RX_ALIGN_ER;
+ break;
+ default:
+ bit_mask = 0;
+ break;
+ }
+
+ return bit_mask;
+}
+
+static uint32_t get_mac_addr_hash_code(uint64_t eth_addr)
+{
+ uint32_t crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(eth_addr, crc);
+
+ crc = bitrev32(crc);
+
+ return crc;
+}
+
+static void tgec_err_exception(void *h_tgec)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)h_tgec;
+ uint32_t event;
+ struct tgec_regs __iomem *p_tgec_mem_map = p_tgec->p_mem_map;
+
+ /* do not handle MDIO events */
+ event =
+ fman_tgec_get_event(p_tgec_mem_map,
+ ~(TGEC_IMASK_MDIO_SCAN_EVENT |
+ TGEC_IMASK_MDIO_CMD_CMPL));
+ event &= fman_tgec_get_interrupt_mask(p_tgec_mem_map);
+
+ fman_tgec_ack_event(p_tgec_mem_map, event);
+
+ if (event & TGEC_IMASK_REM_FAULT)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_REM_FAULT);
+ if (event & TGEC_IMASK_LOC_FAULT)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_LOC_FAULT);
+ if (event & TGEC_IMASK_TX_ECC_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_TX_ECC_ER);
+ if (event & TGEC_IMASK_TX_FIFO_UNFL)
+ p_tgec->f_exception(p_tgec->dev_id,
+ FM_MAC_EX_10G_TX_FIFO_UNFL);
+ if (event & TGEC_IMASK_TX_FIFO_OVFL)
+ p_tgec->f_exception(p_tgec->dev_id,
+ FM_MAC_EX_10G_TX_FIFO_OVFL);
+ if (event & TGEC_IMASK_TX_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_TX_ER);
+ if (event & TGEC_IMASK_RX_FIFO_OVFL)
+ p_tgec->f_exception(p_tgec->dev_id,
+ FM_MAC_EX_10G_RX_FIFO_OVFL);
+ if (event & TGEC_IMASK_RX_ECC_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_ECC_ER);
+ if (event & TGEC_IMASK_RX_JAB_FRM)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_JAB_FRM);
+ if (event & TGEC_IMASK_RX_OVRSZ_FRM)
+ p_tgec->f_exception(p_tgec->dev_id,
+ FM_MAC_EX_10G_RX_OVRSZ_FRM);
+ if (event & TGEC_IMASK_RX_RUNT_FRM)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_RUNT_FRM);
+ if (event & TGEC_IMASK_RX_FRAG_FRM)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_FRAG_FRM);
+ if (event & TGEC_IMASK_RX_LEN_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_LEN_ER);
+ if (event & TGEC_IMASK_RX_CRC_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_CRC_ER);
+ if (event & TGEC_IMASK_RX_ALIGN_ER)
+ p_tgec->f_exception(p_tgec->dev_id, FM_MAC_EX_10G_RX_ALIGN_ER);
+}
+
+static void free_init_resources(struct tgec_t *p_tgec)
+{
+ fm_unregister_intr(p_tgec->h_fm, FM_MOD_MAC, p_tgec->mac_id,
+ FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ free_hash_table(p_tgec->p_multicast_addr_hash);
+ p_tgec->p_multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(p_tgec->p_unicast_addr_hash);
+ p_tgec->p_unicast_addr_hash = NULL;
+}
+
+/* Checks if p_tgec driver parameters were initialized
+ * returns 0 if success else returns error
+ */
+static int is_init_done(struct tgec_cfg *p_tgec_drv_parameters)
+{
+ if (!p_tgec_drv_parameters)
+ return 0;
+ return -EINVAL;
+}
+
+/* TGEC MAC API routines */
+int tgec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_tgec_enable(p_tgec->p_mem_map,
+ (mode & COMM_MODE_RX),
+ (mode & COMM_MODE_TX));
+
+ return 0;
+}
+
+int tgec_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_tgec_disable(p_tgec->p_mem_map,
+ (mode & COMM_MODE_RX),
+ (mode & COMM_MODE_TX));
+
+ return 0;
+}
+
+int tgec_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_tgec_set_promiscuous(p_tgec->p_mem_map, new_val);
+
+ return 0;
+}
+
+/* tgec configs modification functions */
+
+int tgec_cfg_lb(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_tgec->p_tgec_drv_param->loopback_enable = new_val;
+
+ return 0;
+}
+
+int tgec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_tgec->p_tgec_drv_param->max_frame_length = new_val;
+
+ return 0;
+}
+
+/* tgec run time api functions */
+
+int tgec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ uint8_t __maybe_unused priority,
+ uint16_t pause_time,
+ uint16_t __maybe_unused thresh_time)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_tgec_set_tx_pause_frames(p_tgec->p_mem_map, pause_time);
+
+ return 0;
+}
+
+int tgec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ fman_tgec_set_rx_ignore_pause_frames(p_tgec->p_mem_map, !en);
+
+ return 0;
+}
+
+int tgec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ p_tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
+ fman_tgec_set_mac_address(p_tgec->p_mem_map, (uint8_t *)(*p_enet_addr));
+
+ return 0;
+}
+
+int tgec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *p_hash_entry;
+ uint32_t crc;
+ uint32_t hash;
+ uint64_t eth_addr;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ENET_ADDR_TO_UINT64(*p_eth_addr);
+
+ if (!(eth_addr & GROUP_ADDRESS)) {
+ /* Unicast addresses not supported in hash */
+ pr_err("Unicast Address\n");
+ return -EINVAL;
+ }
+ /* CRC calculation */
+ crc = get_mac_addr_hash_code(eth_addr);
+
+ /* Take 9 MSB bits */
+ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
+
+ /* Create element to be added to the driver hash table */
+ p_hash_entry = kmalloc(sizeof(*p_hash_entry), GFP_KERNEL);
+ if (!p_hash_entry)
+ return -ENOMEM;
+ p_hash_entry->addr = eth_addr;
+ INIT_LIST_HEAD(&p_hash_entry->node);
+
+ list_add_tail(&p_hash_entry->node,
+ &p_tgec->p_multicast_addr_hash->p_lsts[hash]);
+ fman_tgec_set_hash_table(p_tgec->p_mem_map,
+ (hash | TGEC_HASH_MCAST_EN));
+
+ return 0;
+}
+
+int tgec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *p_hash_entry = NULL;
+ struct list_head *p_pos;
+ uint32_t crc;
+ uint32_t hash;
+ uint64_t eth_addr;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ eth_addr = ((*(uint64_t *)p_eth_addr) >> 16);
+
+ /* CRC calculation */
+ crc = get_mac_addr_hash_code(eth_addr);
+ /* Take 9 MSB bits */
+ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
+
+ list_for_each(p_pos, &p_tgec->p_multicast_addr_hash->p_lsts[hash]) {
+ p_hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (p_hash_entry->addr == eth_addr) {
+ list_del_init(&p_hash_entry->node);
+ kfree(p_hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&p_tgec->p_multicast_addr_hash->p_lsts[hash]))
+ fman_tgec_set_hash_table(p_tgec->p_mem_map,
+ (hash & ~TGEC_HASH_MCAST_EN));
+
+ return 0;
+}
+
+int tgec_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *mac_version)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ *mac_version = fman_tgec_get_revision(p_tgec->p_mem_map);
+
+ return 0;
+}
+
+int tgec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ uint32_t bit_mask = 0;
+ int ret;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (ret)
+ return ret;
+
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ p_tgec->exceptions |= bit_mask;
+ else
+ p_tgec->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EDOM;
+ }
+ if (enable)
+ fman_tgec_enable_interrupt(p_tgec->p_mem_map, bit_mask);
+ else
+ fman_tgec_disable_interrupt(p_tgec->p_mem_map, bit_mask);
+
+ return 0;
+}
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+static int tgec_tx_ecc_workaround(struct tgec_t *p_tgec)
+{
+ int err;
+
+ pr_info("Applying 10G TX ECC workaround (10GMAC-A004) ... ");
+
+ /* enable and set promiscuous */
+ fman_tgec_enable(p_tgec->p_mem_map, true, true);
+ fman_tgec_set_promiscuous(p_tgec->p_mem_map, true);
+ err = fm_10g_tx_ecc_workaround(p_tgec->h_fm, p_tgec->mac_id);
+ /* disable */
+ fman_tgec_set_promiscuous(p_tgec->p_mem_map, false);
+ fman_tgec_enable(p_tgec->p_mem_map, false, false);
+ fman_tgec_ack_event(p_tgec->p_mem_map, 0xffffffff);
+
+ if (err)
+ pr_err("FAILED!\n");
+ else
+ pr_info("done.\n");
+
+ return err;
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+/* FM Init&Free API */
+
+int tgec_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+ struct tgec_cfg *p_tgec_drv_param;
+ enet_addr_t eth_addr;
+ int err, ret, ret_err;
+
+ ret = is_init_done(p_tgec->p_tgec_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ if (DEFAULT_RESET_ON_INIT &&
+ (fm_reset_mac(p_tgec->h_fm, p_tgec->mac_id) != 0)) {
+ pr_err("Can't reset MAC!\n");
+ return -EINVAL;
+ }
+
+ fm_get_revision(p_tgec->h_fm, &p_tgec->fm_rev_info);
+ ret_err = check_init_parameters(p_tgec);
+ if (ret_err)
+ return ret_err;
+
+ p_tgec_drv_param = p_tgec->p_tgec_drv_param;
+
+ MAKE_ENET_ADDR_FROM_UINT64(p_tgec->addr, eth_addr);
+ fman_tgec_set_mac_address(p_tgec->p_mem_map, (uint8_t *)eth_addr);
+
+ /* interrupts */
+#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005
+ {
+ if (p_tgec->fm_rev_info.major_rev <= 2)
+ p_tgec->exceptions &=
+ ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT);
+ }
+#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ if (!p_tgec->p_tgec_drv_param->skip_fman11_workaround) {
+ err = tgec_tx_ecc_workaround(p_tgec);
+ if (err != 0) {
+ free_init_resources(p_tgec);
+ pr_warn("tgec_tx_ecc_workaround failed\n");
+ }
+ }
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+ err =
+ fman_tgec_init(p_tgec->p_mem_map, p_tgec_drv_param,
+ p_tgec->exceptions);
+ if (err) {
+ free_init_resources(p_tgec);
+ pr_err("TGEC version doesn't support this i/f mode\n");
+ return err;
+ }
+
+ /* Max Frame Length */
+ err = fm_set_mac_max_frame(p_tgec->h_fm, FM_MAC_10G, p_tgec->mac_id,
+ p_tgec_drv_param->max_frame_length);
+ if (err) {
+ pr_err("Setting max frame length FAILED\n");
+ free_init_resources(p_tgec);
+ return -EINVAL;
+ }
+
+#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007
+ if (p_tgec->fm_rev_info.major_rev == 2)
+ fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(p_tgec->
+ p_mem_map);
+#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */
+
+ p_tgec->p_multicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
+ if (!p_tgec->p_multicast_addr_hash) {
+ free_init_resources(p_tgec);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ p_tgec->p_unicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
+ if (!p_tgec->p_unicast_addr_hash) {
+ free_init_resources(p_tgec);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ fm_register_intr(p_tgec->h_fm, FM_MOD_MAC, p_tgec->mac_id,
+ FM_INTR_TYPE_ERR, tgec_err_exception, p_tgec);
+
+ kfree(p_tgec_drv_param);
+ p_tgec->p_tgec_drv_param = NULL;
+
+ return 0;
+}
+
+int tgec_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct tgec_t *p_tgec = (struct tgec_t *)fm_mac_dev;
+
+ free_init_resources(p_tgec);
+
+ if (p_tgec->p_tgec_drv_param)
+ p_tgec->p_tgec_drv_param = NULL;
+
+ kfree(p_tgec->p_tgec_drv_param);
+ kfree(p_tgec);
+
+ return 0;
+}
+
+/* tgec config main entry */
+
+void *tgec_config(struct fm_mac_params_t *p_fm_mac_param)
+{
+ struct tgec_t *p_tgec;
+ struct tgec_cfg *p_tgec_drv_param;
+ uintptr_t base_addr;
+
+ base_addr = p_fm_mac_param->base_addr;
+ /* allocate memory for the UCC GETH data structure. */
+ p_tgec = kzalloc(sizeof(*p_tgec), GFP_KERNEL);
+ if (!p_tgec)
+ return NULL;
+
+ /* allocate memory for the 10G MAC driver parameters data structure. */
+ p_tgec_drv_param = kzalloc(sizeof(*p_tgec_drv_param), GFP_KERNEL);
+ if (!p_tgec_drv_param) {
+ tgec_free((struct fm_mac_dev *)p_tgec);
+ return NULL;
+ }
+
+ /* Plant parameter structure pointer */
+ p_tgec->p_tgec_drv_param = p_tgec_drv_param;
+
+ fman_tgec_defconfig(p_tgec_drv_param);
+
+ p_tgec->p_mem_map = (struct tgec_regs __iomem *)UINT_TO_PTR(base_addr);
+ p_tgec->addr = ENET_ADDR_TO_UINT64(p_fm_mac_param->addr);
+ p_tgec->enet_mode = p_fm_mac_param->enet_mode;
+ p_tgec->mac_id = p_fm_mac_param->mac_id;
+ p_tgec->exceptions = TGEC_DEFAULT_EXCEPTIONS;
+ p_tgec->f_exception = p_fm_mac_param->f_exception;
+ p_tgec->f_event = p_fm_mac_param->f_event;
+ p_tgec->dev_id = p_fm_mac_param->dev_id;
+ p_tgec->h_fm = p_fm_mac_param->h_fm;
+
+ /* Save FMan revision */
+ fm_get_revision(p_tgec->h_fm, &p_tgec->fm_rev_info);
+
+ return p_tgec;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fm_tgec.h b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.h
new file mode 100644
index 0000000..7997143
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+/* TGEC MAC ... */
+#ifndef __TGEC_H
+#define __TGEC_H
+
+#include "service.h"
+#include "enet_ext.h"
+
+#include "fm_mac.h"
+
+#define TGEC_DEFAULT_EXCEPTIONS \
+ ((uint32_t)((TGEC_IMASK_MDIO_SCAN_EVENT) |\
+ (TGEC_IMASK_REM_FAULT) |\
+ (TGEC_IMASK_LOC_FAULT) |\
+ (TGEC_IMASK_TX_ECC_ER) |\
+ (TGEC_IMASK_TX_FIFO_UNFL) |\
+ (TGEC_IMASK_TX_FIFO_OVFL) |\
+ (TGEC_IMASK_TX_ER) |\
+ (TGEC_IMASK_RX_FIFO_OVFL) |\
+ (TGEC_IMASK_RX_ECC_ER) |\
+ (TGEC_IMASK_RX_JAB_FRM) |\
+ (TGEC_IMASK_RX_OVRSZ_FRM) |\
+ (TGEC_IMASK_RX_RUNT_FRM) |\
+ (TGEC_IMASK_RX_FRAG_FRM) |\
+ (TGEC_IMASK_RX_CRC_ER) |\
+ (TGEC_IMASK_RX_ALIGN_ER)))
+
+#define MAX_PACKET_ALIGNMENT 31
+#define MAX_INTER_PACKET_GAP 0x7f
+#define MAX_INTER_PALTERNATE_BEB 0x0f
+#define MAX_RETRANSMISSION 0x0f
+#define MAX_COLLISION_WINDOW 0x03ff
+
+/* number of pattern match registers (entries) */
+#define TGEC_NUM_OF_PADDRS 1
+
+/* Group address bit indication */
+#define GROUP_ADDRESS 0x0000010000000000LL
+
+/* Hash table size (= 32 bits*8 regs)*/
+#define TGEC_HASH_TABLE_SIZE 512
+
+struct tgec_t {
+ /* pointer to 10G memory mapped registers. */
+ struct tgec_regs __iomem *p_mem_map;
+ /* MAC address of device; */
+ uint64_t addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *f_exception;
+ fm_mac_exception_cb *f_event;
+ /* Whether a particular individual address recognition
+ * register is being used
+ */
+ bool ind_addr_reg_used[TGEC_NUM_OF_PADDRS];
+ /* MAC address for particular individual address
+ * recognition register
+ */
+ uint64_t paddr[TGEC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station. */
+ uint8_t num_of_ind_addr_in_regs;
+ /* pointer to driver's global address hash table */
+ struct eth_hash_t *p_multicast_addr_hash;
+ /* pointer to driver's individual address hash table */
+ struct eth_hash_t *p_unicast_addr_hash;
+ bool debug_mode;
+ uint8_t mac_id;
+ uint32_t exceptions;
+ struct tgec_cfg *p_tgec_drv_param;
+ void *h_fm;
+ struct fm_revision_info_t fm_rev_info;
+};
+
+void *tgec_config(struct fm_mac_params_t *p_fm_mac_params);
+int tgec_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val);
+int tgec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr);
+int tgec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, uint16_t new_val);
+int tgec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int tgec_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode);
+int tgec_init(struct fm_mac_dev *fm_mac_dev);
+int tgec_free(struct fm_mac_dev *fm_mac_dev);
+int tgec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en);
+int tgec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, uint8_t priority,
+ uint16_t pause_time, uint16_t thresh_time);
+int tgec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception, bool enable);
+int tgec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+int tgec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+int tgec_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *mac_version);
+
+#endif /* __TGEC_H */
--
1.7.11.7
From: Igal Liberman <[email protected]>
The FMan Port Flib provides basic API used by the drivers to
configure and control the FMan Port hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
.../net/ethernet/freescale/fman/flib/fman_common.h | 73 ++++
.../ethernet/freescale/fman/flib/fsl_fman_port.h | 427 +++++++++++++++++++++
.../net/ethernet/freescale/fman/flib/fsl_fman_sp.h | 54 +++
3 files changed, 554 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fman_common.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h
diff --git a/drivers/net/ethernet/freescale/fman/flib/fman_common.h b/drivers/net/ethernet/freescale/fman/flib/fman_common.h
new file mode 100644
index 0000000..e186ed9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fman_common.h
@@ -0,0 +1,73 @@
+/*
+ * 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 __FMAN_COMMON_H
+#define __FMAN_COMMON_H
+
+/* NIA Description */
+#define NIA_ORDER_RESTOR 0x00800000
+#define NIA_ENG_FM_CTL 0x00000000
+#define NIA_ENG_PRS 0x00440000
+#define NIA_ENG_KG 0x00480000
+#define NIA_ENG_PLCR 0x004C0000
+#define NIA_ENG_BMI 0x00500000
+#define NIA_ENG_QMI_ENQ 0x00540000
+#define NIA_ENG_QMI_DEQ 0x00580000
+#define NIA_ENG_MASK 0x007C0000
+
+#define NIA_FM_CTL_AC_CC 0x00000006
+#define NIA_FM_CTL_AC_HC 0x0000000C
+#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008
+#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A
+#define NIA_FM_CTL_AC_FRAG 0x0000000e
+#define NIA_FM_CTL_AC_PRE_FETCH 0x00000010
+#define NIA_FM_CTL_AC_POST_FETCH_PCD 0x00000012
+#define NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN 0x00000018
+#define NIA_FM_CTL_AC_POST_FETCH_NO_PCD 0x00000012
+#define NIA_FM_CTL_AC_FRAG_CHECK 0x00000014
+#define NIA_FM_CTL_AC_PRE_CC 0x00000020
+
+#define NIA_BMI_AC_ENQ_FRAME 0x00000002
+#define NIA_BMI_AC_TX_RELEASE 0x000002C0
+#define NIA_BMI_AC_RELEASE 0x000000C0
+#define NIA_BMI_AC_DISCARD 0x000000C1
+#define NIA_BMI_AC_TX 0x00000274
+#define NIA_BMI_AC_FETCH 0x00000208
+#define NIA_BMI_AC_MASK 0x000003FF
+
+#define NIA_KG_DIRECT 0x00000100
+#define NIA_KG_CC_EN 0x00000200
+#define NIA_PLCR_ABSOLUTE 0x00008000
+
+#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202
+#define NIA_BMI_AC_FETCH_ALL_FRAME 0x0000020c
+
+#endif /* __FMAN_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h
new file mode 100644
index 0000000..719d15e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h
@@ -0,0 +1,427 @@
+/*
+ * 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_PORT_H
+#define __FSL_FMAN_PORT_H
+
+#include "fsl_fman_sp.h"
+
+/* Registers bit fields */
+
+/* BMI defines */
+#define BMI_EBD_EN 0x80000000
+
+#define BMI_PORT_CFG_EN 0x80000000
+#define BMI_PORT_CFG_FDOVR 0x02000000
+
+#define BMI_PORT_STATUS_BSY 0x80000000
+
+#define BMI_DMA_ATTR_SWP_SHIFT FMAN_SP_DMA_ATTR_SWP_SHIFT
+#define BMI_DMA_ATTR_IC_STASH_ON 0x10000000
+#define BMI_DMA_ATTR_HDR_STASH_ON 0x04000000
+#define BMI_DMA_ATTR_SG_STASH_ON 0x01000000
+#define BMI_DMA_ATTR_WRITE_OPTIMIZE FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE
+
+#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16
+#define BMI_RX_FIFO_THRESHOLD_ETHE 0x80000000
+
+#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24
+#define BMI_RX_FRAME_END_CUT_SHIFT 16
+
+#define BMI_IC_TO_EXT_SHIFT FMAN_SP_IC_TO_EXT_SHIFT
+#define BMI_IC_FROM_INT_SHIFT FMAN_SP_IC_FROM_INT_SHIFT
+
+#define BMI_INT_BUF_MARG_SHIFT 28
+#define BMI_EXT_BUF_MARG_START_SHIFT FMAN_SP_EXT_BUF_MARG_START_SHIFT
+
+#define BMI_CMD_MR_LEAC 0x00200000
+#define BMI_CMD_MR_SLEAC 0x00100000
+#define BMI_CMD_MR_MA 0x00080000
+#define BMI_CMD_MR_DEAS 0x00040000
+#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \
+ BMI_CMD_MR_SLEAC | \
+ BMI_CMD_MR_MA | \
+ BMI_CMD_MR_DEAS)
+#define BMI_CMD_TX_MR_DEF 0
+#define BMI_CMD_OP_MR_DEF (BMI_CMD_MR_DEAS | \
+ BMI_CMD_MR_MA)
+
+#define BMI_CMD_ATTR_ORDER 0x80000000
+#define BMI_CMD_ATTR_SYNC 0x02000000
+#define BMI_CMD_ATTR_COLOR_SHIFT 26
+
+#define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12
+#define BMI_NEXT_ENG_FD_BITS_SHIFT 24
+#define BMI_FRAME_END_CS_IGNORE_SHIFT 24
+
+#define BMI_COUNTERS_EN 0x80000000
+
+#define BMI_EXT_BUF_POOL_VALID FMAN_SP_EXT_BUF_POOL_VALID
+#define BMI_EXT_BUF_POOL_EN_COUNTER FMAN_SP_EXT_BUF_POOL_EN_COUNTER
+#define BMI_EXT_BUF_POOL_BACKUP FMAN_SP_EXT_BUF_POOL_BACKUP
+#define BMI_EXT_BUF_POOL_ID_SHIFT 16
+#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000
+#define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT 16
+
+#define BMI_TX_FIFO_MIN_FILL_SHIFT 16
+
+#define BMI_SG_DISABLE FMAN_SP_SG_DISABLE
+
+/* QMI defines */
+#define QMI_PORT_CFG_EN 0x80000000
+#define QMI_PORT_CFG_EN_COUNTERS 0x10000000
+#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000
+
+#define QMI_DEQ_CFG_PRI 0x80000000
+#define QMI_DEQ_CFG_TYPE1 0x10000000
+#define QMI_DEQ_CFG_TYPE2 0x20000000
+#define QMI_DEQ_CFG_TYPE3 0x30000000
+#define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000
+#define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000
+#define QMI_DEQ_CFG_SP_MASK 0xf
+#define QMI_DEQ_CFG_SP_SHIFT 20
+
+/* General port defines */
+#define FMAN_PORT_MAX_EXT_POOLS_NUM 8
+#define FMAN_PORT_OBS_EXT_POOLS_NUM 2
+#define FMAN_PORT_CG_MAP_NUM 8
+#define FMAN_PORT_PRS_RESULT_WORDS_NUM 8
+#define FMAN_PORT_BMI_FIFO_UNITS 0x100
+#define FMAN_PORT_IC_OFFSET_UNITS 0x10
+
+/* FM Port Register Map */
+
+/* BMI Rx port register map */
+struct fman_port_rx_bmi_regs {
+ uint32_t fmbm_rcfg; /* Rx Configuration */
+ uint32_t fmbm_rst; /* Rx Status */
+ uint32_t fmbm_rda; /* Rx DMA attributes*/
+ uint32_t fmbm_rfp; /* Rx FIFO Parameters*/
+ uint32_t fmbm_rfed; /* Rx Frame End Data*/
+ uint32_t fmbm_ricp; /* Rx Internal Context Parameters*/
+ uint32_t fmbm_rim; /* Rx Internal Buffer Margins*/
+ uint32_t fmbm_rebm; /* Rx External Buffer Margins*/
+ uint32_t fmbm_rfne; /* Rx Frame Next Engine*/
+ uint32_t fmbm_rfca; /* Rx Frame Command Attributes.*/
+ uint32_t fmbm_rfpne; /* Rx Frame Parser Next Engine*/
+ uint32_t fmbm_rpso; /* Rx Parse Start Offset*/
+ uint32_t fmbm_rpp; /* Rx Policer Profile */
+ uint32_t fmbm_rccb; /* Rx Coarse Classification Base */
+ uint32_t fmbm_reth; /* Rx Excessive Threshold */
+ uint32_t reserved003c[1]; /* (0x03C 0x03F) */
+ uint32_t fmbm_rprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
+ /* Rx Parse Results Array Init*/
+ uint32_t fmbm_rfqid; /* Rx Frame Queue ID*/
+ uint32_t fmbm_refqid; /* Rx Error Frame Queue ID*/
+ uint32_t fmbm_rfsdm; /* Rx Frame Status Discard Mask*/
+ uint32_t fmbm_rfsem; /* Rx Frame Status Error Mask*/
+ uint32_t fmbm_rfene; /* Rx Frame Enqueue Next Engine */
+ uint32_t reserved0074[0x2]; /* (0x074-0x07C) */
+ uint32_t fmbm_rcmne; /* Rx Frame Continuous Mode Next Engine */
+ uint32_t reserved0080[0x20];/* (0x080 0x0FF) */
+ uint32_t fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM];
+ /* Buffer Manager pool Information-*/
+ uint32_t fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM];
+ /* Allocate Counter-*/
+ uint32_t reserved0130[8];
+ /* 0x130/0x140 - 0x15F reserved -*/
+ uint32_t fmbm_rcgm[FMAN_PORT_CG_MAP_NUM];
+ /* Congestion Group Map*/
+ uint32_t fmbm_mpd; /* BM Pool Depletion */
+ uint32_t reserved0184[0x1F]; /* (0x184 0x1FF) */
+ uint32_t fmbm_rstc; /* Rx Statistics Counters*/
+ uint32_t fmbm_rfrc; /* Rx Frame Counter*/
+ uint32_t fmbm_rfbc; /* Rx Bad Frames Counter*/
+ uint32_t fmbm_rlfc; /* Rx Large Frames Counter*/
+ uint32_t fmbm_rffc; /* Rx Filter Frames Counter*/
+ uint32_t fmbm_rfdc; /* Rx Frame Discard Counter*/
+ uint32_t fmbm_rfldec; /* Rx Frames List DMA Error Counter*/
+ uint32_t fmbm_rodc; /* Rx Out of Buffers Discard nntr*/
+ uint32_t fmbm_rbdc; /* Rx Buffers Deallocate Counter*/
+ uint32_t reserved0224[0x17]; /* (0x224 0x27F) */
+ uint32_t fmbm_rpc; /* Rx Performance Counters*/
+ uint32_t fmbm_rpcp; /* Rx Performance Count Parameters*/
+ uint32_t fmbm_rccn; /* Rx Cycle Counter*/
+ uint32_t fmbm_rtuc; /* Rx Tasks Utilization Counter*/
+ uint32_t fmbm_rrquc; /* Rx Receive Queue Utilization cntr*/
+ uint32_t fmbm_rduc; /* Rx DMA Utilization Counter*/
+ uint32_t fmbm_rfuc; /* Rx FIFO Utilization Counter*/
+ uint32_t fmbm_rpac; /* Rx Pause Activation Counter*/
+ uint32_t reserved02a0[0x18]; /* (0x2A0 0x2FF) */
+ uint32_t fmbm_rdbg; /* Rx Debug-*/
+};
+
+/* BMI Tx port register map */
+struct fman_port_tx_bmi_regs {
+ uint32_t fmbm_tcfg; /* Tx Configuration */
+ uint32_t fmbm_tst; /* Tx Status */
+ uint32_t fmbm_tda; /* Tx DMA attributes */
+ uint32_t fmbm_tfp; /* Tx FIFO Parameters */
+ uint32_t fmbm_tfed; /* Tx Frame End Data */
+ uint32_t fmbm_ticp; /* Tx Internal Context Parameters */
+ uint32_t fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */
+ uint32_t fmbm_tfca; /* Tx Frame Command attribute. */
+ uint32_t fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */
+ uint32_t fmbm_tefqid; /* Tx Frame Error Queue ID */
+ uint32_t fmbm_tfene; /* Tx Frame Enqueue Next Engine */
+ uint32_t fmbm_trlmts; /* Tx Rate Limiter Scale */
+ uint32_t fmbm_trlmt; /* Tx Rate Limiter */
+ uint32_t reserved0034[0x0e]; /* (0x034-0x6c) */
+ uint32_t fmbm_tccb; /* Tx Coarse Classification base */
+ uint32_t fmbm_tfne; /* Tx Frame Next Engine */
+ /* Tx Priority based Flow Control (PFC) Mapping */
+ uint32_t fmbm_tpfcm[0x02];
+ /* Tx Frame Continuous Mode Next Engine */
+ uint32_t fmbm_tcmne;
+ uint32_t reserved0080[0x60]; /* (0x080-0x200) */
+ uint32_t fmbm_tstc; /* Tx Statistics Counters */
+ uint32_t fmbm_tfrc; /* Tx Frame Counter */
+ uint32_t fmbm_tfdc; /* Tx Frames Discard Counter */
+ uint32_t fmbm_tfledc; /* Tx Frame len error discard cntr */
+ uint32_t fmbm_tfufdc; /* Tx Frame unsprt frmt discard cntr*/
+ uint32_t fmbm_tbdc; /* Tx Buffers Deallocate Counter */
+ uint32_t reserved0218[0x1A]; /* (0x218-0x280) */
+ uint32_t fmbm_tpc; /* Tx Performance Counters*/
+ uint32_t fmbm_tpcp; /* Tx Performance Count Parameters*/
+ uint32_t fmbm_tccn; /* Tx Cycle Counter*/
+ uint32_t fmbm_ttuc; /* Tx Tasks Utilization Counter*/
+ uint32_t fmbm_ttcquc; /* Tx Transmit conf Q util Counter*/
+ uint32_t fmbm_tduc; /* Tx DMA Utilization Counter*/
+ uint32_t fmbm_tfuc; /* Tx FIFO Utilization Counter*/
+};
+
+/* BMI O/H port register map */
+struct fman_port_oh_bmi_regs {
+ uint32_t fmbm_ocfg; /* O/H Configuration */
+ uint32_t fmbm_ost; /* O/H Status */
+ uint32_t fmbm_oda; /* O/H DMA attributes */
+ uint32_t fmbm_oicp; /* O/H Internal Context Parameters */
+ uint32_t fmbm_ofdne; /* O/H Frame Dequeue Next Engine */
+ uint32_t fmbm_ofne; /* O/H Frame Next Engine */
+ uint32_t fmbm_ofca; /* O/H Frame Command Attributes. */
+ uint32_t fmbm_ofpne; /* O/H Frame Parser Next Engine */
+ uint32_t fmbm_opso; /* O/H Parse Start Offset */
+ uint32_t fmbm_opp; /* O/H Policer Profile */
+ uint32_t fmbm_occb; /* O/H Coarse Classification base */
+ uint32_t fmbm_oim; /* O/H Internal margins*/
+ uint32_t fmbm_ofp; /* O/H Fifo Parameters*/
+ uint32_t fmbm_ofed; /* O/H Frame End Data*/
+ uint32_t reserved0030[2]; /* (0x038 - 0x03F) */
+ uint32_t fmbm_oprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
+ /* O/H Parse Results Array Initialization */
+ uint32_t fmbm_ofqid; /* O/H Frame Queue ID */
+ uint32_t fmbm_oefqid; /* O/H Error Frame Queue ID */
+ uint32_t fmbm_ofsdm; /* O/H Frame Status Discard Mask */
+ uint32_t fmbm_ofsem; /* O/H Frame Status Error Mask */
+ uint32_t fmbm_ofene; /* O/H Frame Enqueue Next Engine */
+ uint32_t fmbm_orlmts; /* O/H Rate Limiter Scale */
+ uint32_t fmbm_orlmt; /* O/H Rate Limiter */
+ uint32_t fmbm_ocmne; /* O/H Continuous Mode Next Engine */
+ uint32_t reserved0080[0x20]; /* 0x080 - 0x0FF Reserved */
+ uint32_t fmbm_oebmpi[2]; /* Buf Mngr Observed Pool Info */
+ uint32_t reserved0108[0x16]; /* 0x108 - 0x15F Reserved */
+ uint32_t fmbm_ocgm; /* Observed Congestion Group Map */
+ uint32_t reserved0164[0x7]; /* 0x164 - 0x17F Reserved */
+ uint32_t fmbm_ompd; /* Observed BMan Pool Depletion */
+ uint32_t reserved0184[0x1F]; /* 0x184 - 0x1FF Reserved */
+ uint32_t fmbm_ostc; /* O/H Statistics Counters */
+ uint32_t fmbm_ofrc; /* O/H Frame Counter */
+ uint32_t fmbm_ofdc; /* O/H Frames Discard Counter */
+ uint32_t fmbm_ofledc; /* O/H Frames Len Err Discard Cntr */
+ uint32_t fmbm_ofufdc; /* O/H Frames Unsprtd Discard Cutr */
+ uint32_t fmbm_offc; /* O/H Filter Frames Counter */
+ uint32_t fmbm_ofwdc; /* Rx Frames WRED Discard Counter */
+ uint32_t fmbm_ofldec; /* O/H Frames List DMA Error Cntr */
+ uint32_t fmbm_obdc; /* O/H Buffers Deallocate Counter */
+ uint32_t reserved0218[0x17]; /* (0x218 - 0x27F) */
+ uint32_t fmbm_opc; /* O/H Performance Counters */
+ uint32_t fmbm_opcp; /* O/H Performance Count Parameters */
+ uint32_t fmbm_occn; /* O/H Cycle Counter */
+ uint32_t fmbm_otuc; /* O/H Tasks Utilization Counter */
+ uint32_t fmbm_oduc; /* O/H DMA Utilization Counter */
+ uint32_t fmbm_ofuc; /* O/H FIFO Utilization Counter */
+};
+
+/* BMI port register map */
+union fman_port_bmi_regs {
+ struct fman_port_rx_bmi_regs rx;
+ struct fman_port_tx_bmi_regs tx;
+ struct fman_port_oh_bmi_regs oh;
+};
+
+/* QMI port register map */
+struct fman_port_qmi_regs {
+ uint32_t fmqm_pnc; /* PortID n Configuration Register */
+ uint32_t fmqm_pns; /* PortID n Status Register */
+ uint32_t fmqm_pnts; /* PortID n Task Status Register */
+ uint32_t reserved00c[4]; /* 0xn00C - 0xn01B */
+ uint32_t fmqm_pnen; /* PortID n Enqueue NIA Register */
+ uint32_t fmqm_pnetfc; /* PortID n Enq Total Frame Counter */
+ uint32_t reserved024[2]; /* 0xn024 - 0x02B */
+ uint32_t fmqm_pndn; /* PortID n Dequeue NIA Register */
+ uint32_t fmqm_pndc; /* PortID n Dequeue Config Register */
+ uint32_t fmqm_pndtfc; /* PortID n Dequeue tot Frame cntr */
+ uint32_t fmqm_pndfdc; /* PortID n Dequeue FQID Dflt Cntr */
+ uint32_t fmqm_pndcc; /* PortID n Dequeue Confirm Counter */
+};
+
+enum fman_port_dma_swap {
+ E_FMAN_PORT_DMA_NO_SWAP, /* No swap, transfer data as is */
+ E_FMAN_PORT_DMA_SWAP_LE,
+ /* The transferred data should be swapped in PPC Little Endian mode */
+ E_FMAN_PORT_DMA_SWAP_BE
+ /* The transferred data should be swapped in Big Endian mode */
+};
+
+/* Default port color */
+enum fman_port_color {
+ E_FMAN_PORT_COLOR_GREEN, /* Default port color is green */
+ E_FMAN_PORT_COLOR_YELLOW, /* Default port color is yellow */
+ E_FMAN_PORT_COLOR_RED, /* Default port color is red */
+ E_FMAN_PORT_COLOR_OVERRIDE /* Ignore color */
+};
+
+/* QMI dequeue from the SP channel - types */
+enum fman_port_deq_type {
+ E_FMAN_PORT_DEQ_BY_PRI,
+ /* Priority precedence and Intra-Class scheduling */
+ E_FMAN_PORT_DEQ_ACTIVE_FQ,
+ /* Active FQ precedence and Intra-Class scheduling */
+ E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS
+ /* Active FQ precedence and override Intra-Class scheduling */
+};
+
+/* QMI dequeue prefetch modes */
+enum fman_port_deq_prefetch {
+ E_FMAN_PORT_DEQ_NO_PREFETCH, /* No prefetch mode */
+ E_FMAN_PORT_DEQ_PART_PREFETCH, /* Partial prefetch mode */
+ E_FMAN_PORT_DEQ_FULL_PREFETCH /* Full prefetch mode */
+};
+
+/* FM Port configuration structure, used at init */
+struct fman_port_cfg {
+ /* BMI parameters */
+ enum fman_port_dma_swap dma_swap_data;
+ bool dma_ic_stash_on;
+ bool dma_header_stash_on;
+ bool dma_sg_stash_on;
+ bool dma_write_optimize;
+ uint16_t ic_ext_offset;
+ uint8_t ic_int_offset;
+ uint16_t ic_size;
+ enum fman_port_color color;
+ bool sync_req;
+ bool discard_override;
+ uint8_t checksum_bytes_ignore;
+ uint8_t rx_cut_end_bytes;
+ uint32_t rx_pri_elevation;
+ uint32_t rx_fifo_thr;
+ uint8_t rx_fd_bits;
+ uint8_t int_buf_start_margin;
+ uint16_t ext_buf_start_margin;
+ uint16_t ext_buf_end_margin;
+ uint32_t tx_fifo_min_level;
+ uint32_t tx_fifo_low_comf_level;
+ uint8_t tx_fifo_deq_pipeline_depth;
+ /* QMI parameters */
+ bool deq_high_pri;
+ enum fman_port_deq_type deq_type;
+ enum fman_port_deq_prefetch deq_prefetch_opt;
+ uint16_t deq_byte_cnt;
+ bool no_scatter_gather;
+ int errata_A006675;
+ int errata_A006320;
+ int excessive_threshold_register;
+ int fmbm_rebm_has_sgd;
+ int fmbm_tfne_has_features;
+ int qmi_deq_options_support;
+};
+
+enum fman_port_type {
+ E_FMAN_PORT_TYPE_OP = 0, /* Offline parsing port */
+ E_FMAN_PORT_TYPE_RX, /* 1G Rx port */
+ E_FMAN_PORT_TYPE_RX_10G, /* 10G Rx port */
+ E_FMAN_PORT_TYPE_TX, /* 1G Tx port */
+ E_FMAN_PORT_TYPE_TX_10G, /* 10G Tx port */
+ E_FMAN_PORT_TYPE_DUMMY
+};
+
+struct fman_port_params {
+ uint32_t discard_mask;
+ uint32_t err_mask;
+ uint32_t dflt_fqid;
+ uint32_t err_fqid;
+ uint8_t deq_sp;
+ bool dont_release_buf;
+};
+
+/* Port context - used by most API functions */
+struct fman_port {
+ enum fman_port_type type;
+ uint8_t fm_rev_maj;
+ uint8_t fm_rev_min;
+ union fman_port_bmi_regs __iomem *bmi_regs;
+ struct fman_port_qmi_regs __iomem *qmi_regs;
+ uint8_t ext_pools_num;
+};
+
+/* External buffer pools configuration */
+struct fman_port_bpools {
+ uint8_t count; /* Num of pools to set up */
+ bool counters_enable; /* Enable allocate counters */
+ uint8_t grp_bp_depleted_num;
+ /* Number of depleted pools - if reached the BMI indicates
+ * the MAC to send a pause frame
+ */
+ struct {
+ uint8_t bpid; /* BM pool ID */
+ uint16_t size;
+ /* Pool's size - must be in ascending order */
+ bool is_backup;
+ /* If this is a backup pool */
+ bool grp_bp_depleted;
+ /* Consider this buffer in multiple pools depletion criteria*/
+ bool single_bp_depleted;
+ /* Consider this buffer in single pool depletion criteria */
+ } bpool[FMAN_PORT_MAX_EXT_POOLS_NUM];
+};
+
+
+/* FM Port API */
+void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type);
+int fman_port_init(struct fman_port *port,
+ struct fman_port_cfg *cfg, struct fman_port_params *params);
+int fman_port_enable(struct fman_port *port);
+int fman_port_disable(const struct fman_port *port);
+int fman_port_set_bpools(const struct fman_port *port,
+ const struct fman_port_bpools *bp);
+
+#endif /* __FSL_FMAN_PORT_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h
new file mode 100644
index 0000000..42fa27b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h
@@ -0,0 +1,54 @@
+/*
+ * 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_SP_H
+#define __FSL_FMAN_SP_H
+
+#include "common/general.h"
+#include "fsl_fman.h"
+
+/* Registers bit fields */
+#define FMAN_SP_EXT_BUF_POOL_EN_COUNTER 0x40000000
+#define FMAN_SP_EXT_BUF_POOL_VALID 0x80000000
+#define FMAN_SP_EXT_BUF_POOL_BACKUP 0x20000000
+#define FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE 0x00100000
+#define FMAN_SP_SG_DISABLE 0x80000000
+
+/* shifts */
+#define FMAN_SP_EXT_BUF_MARG_START_SHIFT 16
+#define FMAN_SP_DMA_ATTR_SWP_SHIFT 30
+#define FMAN_SP_IC_TO_EXT_SHIFT 16
+#define FMAN_SP_IC_FROM_INT_SHIFT 8
+
+/* defaults */
+#define DEFAULT_FMAN_SP_NO_SCATTER_GATHER false
+
+#endif /* __FSL_FMAN_SP_H */
--
1.7.11.7
From: Igal Liberman <[email protected]>
Add Storage Profiles support.
The Storage Profiles contain parameters that are used by the FMan in
order to store frames being received on the Rx ports, or to
determine the parameters that affect writing the Internal Context
in the frame margin on Tx.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Makefile | 2 +
drivers/net/ethernet/freescale/fman/fm_sp_common.h | 104 ++++++
drivers/net/ethernet/freescale/fman/sp/Makefile | 3 +
drivers/net/ethernet/freescale/fman/sp/fm_sp.c | 398 +++++++++++++++++++++
4 files changed, 507 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/fm_sp_common.h
create mode 100644 drivers/net/ethernet/freescale/fman/sp/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/sp/fm_sp.c
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index f61d3a6..c6c3e24 100644
--- a/drivers/net/ethernet/freescale/fman/Makefile
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -8,3 +8,5 @@ fsl_fman-objs := fman.o fm_muram.o fm.o fm_drv.o
obj-y += port/
obj-y += mac/
+obj-y += sp/
+
diff --git a/drivers/net/ethernet/freescale/fman/fm_sp_common.h b/drivers/net/ethernet/freescale/fman/fm_sp_common.h
new file mode 100644
index 0000000..a99d795
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_sp_common.h
@@ -0,0 +1,104 @@
+/*
+ * 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 SP ... */
+#ifndef __FM_SP_COMMON_H
+#define __FM_SP_COMMON_H
+
+#include "service.h"
+#include "fm_ext.h"
+#include "fsl_fman.h"
+
+/* defaults */
+#define DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE 0
+#define DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_PASS_PRS_RESULT false
+#define DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_PASS_TIME_STAMP false
+#define DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN 64
+
+/* structure for defining internal context copying */
+struct fm_sp_int_context_data_copy_t {
+ /* < Offset in External buffer to which internal
+ * context is copied to (Rx) or taken from (Tx, Op).
+ */
+ uint16_t ext_buf_offset;
+ /* Offset within internal context to copy from
+ * (Rx) or to copy to (Tx, Op).
+ */
+ uint8_t int_context_offset;
+ /* Internal offset size to be copied */
+ uint16_t size;
+};
+
+/* struct for defining external buffer margins */
+struct fm_sp_buf_margins_t {
+ /* Number of bytes to be left at the beginning
+ * of the external buffer (must be divisible by 16)
+ */
+ uint16_t start_margins;
+ /* number of bytes to be left at the end
+ * of the external buffer(must be divisible by 16)
+ */
+ uint16_t end_margins;
+};
+
+struct fm_sp_buffer_offsets_t {
+ uint32_t data_offset;
+ uint32_t prs_result_offset;
+ uint32_t time_stamp_offset;
+ uint32_t hash_result_offset;
+};
+
+int fm_sp_build_buffer_structure(struct fm_sp_int_context_data_copy_t
+ *p_fm_port_int_context_data_copy,
+ struct fm_buffer_prefix_content_t
+ *p_buffer_prefix_content,
+ struct fm_sp_buf_margins_t
+ *p_fm_port_buf_margins,
+ struct fm_sp_buffer_offsets_t
+ *p_fm_port_buffer_offsets,
+ uint8_t *internal_buf_offset);
+
+int fm_sp_check_int_context_params(struct fm_sp_int_context_data_copy_t *
+ p_fm_sp_int_context_data_copy);
+int fm_sp_check_buf_pools_params(struct fm_ext_pools_t *p_fm_ext_pools,
+ struct fm_backup_bm_pools_t
+ *p_fm_backup_bm_pools,
+ struct fm_buf_pool_depletion_t
+ *p_fm_buf_pool_depletion,
+ uint32_t max_num_of_ext_pools,
+ uint32_t bm_max_num_of_pools);
+int fm_sp_check_buf_margins(struct fm_sp_buf_margins_t *p_fm_sp_buf_margins);
+void fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fm_ext_pools_t
+ *p_fm_ext_pools,
+ uint8_t *ordered_array,
+ uint16_t *sizes_array);
+#endif /* __FM_SP_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/fman/sp/Makefile b/drivers/net/ethernet/freescale/fman/sp/Makefile
new file mode 100644
index 0000000..545e686
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/sp/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FSL_FMAN) += fsl_fman_sp.o
+
+fsl_fman_sp-objs := fm_sp.o
diff --git a/drivers/net/ethernet/freescale/fman/sp/fm_sp.c b/drivers/net/ethernet/freescale/fman/sp/fm_sp.c
new file mode 100644
index 0000000..61b0bd2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/sp/fm_sp.c
@@ -0,0 +1,398 @@
+/*
+ * 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 PCD Storage profile ... */
+
+#include "service.h"
+#include "net_ext.h"
+
+#include "fm_sp_common.h"
+#include "fm_common.h"
+#include "fsl_fman_sp.h"
+
+#include <linux/string.h>
+
+/* Inter-module API routines */
+
+void fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fm_ext_pools_t
+ *p_fm_ext_pools,
+ uint8_t *ordered_array,
+ uint16_t *sizes_array)
+{
+ uint16_t buf_size = 0;
+ int i = 0, j = 0, k = 0;
+
+ /* First we copy the external buffers pools information
+ * to an ordered local array
+ */
+ for (i = 0; i < p_fm_ext_pools->num_of_pools_used; i++) {
+ /* get pool size */
+ buf_size = p_fm_ext_pools->ext_buf_pool[i].size;
+
+ /* keep sizes in an array according to poolId
+ * for direct access
+ */
+ sizes_array[p_fm_ext_pools->ext_buf_pool[i].id] = buf_size;
+
+ /* save poolId in an ordered array according to size */
+ for (j = 0; j <= i; j++) {
+ /* this is the next free place in the array */
+ if (j == i)
+ ordered_array[i] =
+ p_fm_ext_pools->ext_buf_pool[i].id;
+ else {
+ /* find the right place for this poolId */
+ if (buf_size < sizes_array[ordered_array[j]]) {
+ /* move the pool_ids one place ahead
+ * to make room for this poolId
+ */
+ for (k = i; k > j; k--)
+ ordered_array[k] =
+ ordered_array[k - 1];
+
+ /* now k==j, this is the place for
+ * the new size
+ */
+ ordered_array[k] =
+ p_fm_ext_pools->ext_buf_pool[i].id;
+ break;
+ }
+ }
+ }
+ }
+}
+
+int fm_sp_check_buf_pools_params(struct fm_ext_pools_t *p_fm_ext_pools,
+ struct fm_backup_bm_pools_t
+ *p_fm_backup_bm_pools,
+ struct fm_buf_pool_depletion_t
+ *p_fm_buf_pool_depletion,
+ uint32_t max_num_of_ext_pools,
+ uint32_t bm_max_num_of_pools)
+{
+ int i = 0, j = 0;
+ bool found;
+ uint8_t count = 0;
+
+ if (p_fm_ext_pools) {
+ if (p_fm_ext_pools->num_of_pools_used > max_num_of_ext_pools) {
+ pr_err("num_of_pools_used can't be larger than %d\n",
+ max_num_of_ext_pools);
+ return -EDOM;
+ }
+ for (i = 0; i < p_fm_ext_pools->num_of_pools_used; i++) {
+ if (p_fm_ext_pools->ext_buf_pool[i].id >=
+ bm_max_num_of_pools) {
+ pr_err("ext_buf_pools.ext_buf_pool[%d].id can't be larger than %d\n",
+ i, bm_max_num_of_pools);
+ return -EDOM;
+ }
+ if (!p_fm_ext_pools->ext_buf_pool[i].size) {
+ pr_err("ext_buf_pools.ext_buf_pool[%d].size is 0\n",
+ i);
+ return -EDOM;
+ }
+ }
+ }
+ if (!p_fm_ext_pools && (p_fm_backup_bm_pools ||
+ p_fm_buf_pool_depletion)) {
+ pr_err("backupBmPools ot buf_pool_depletion can not be defined without external pools\n");
+ return -EDOM;
+ }
+ /* backup BM pools indication is valid only for some chip derivatives
+ * (limited by the config routine)
+ */
+ if (p_fm_backup_bm_pools) {
+ if (p_fm_backup_bm_pools->num_of_backup_pools >=
+ p_fm_ext_pools->num_of_pools_used) {
+ pr_err("p_backup_bm_pools must be smaller than ext_buf_pools.num_of_pools_used\n");
+ return -EDOM;
+ }
+ found = false;
+ for (i = 0; i < p_fm_backup_bm_pools->
+ num_of_backup_pools; i++) {
+ for (j = 0; j < p_fm_ext_pools->
+ num_of_pools_used; j++) {
+ if (p_fm_backup_bm_pools->pool_ids[i] ==
+ p_fm_ext_pools->ext_buf_pool[j].id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("All p_backup_bm_pools.pool_ids must be included in ext_buf_pools.ext_buf_pool[n].id\n");
+ return -EDOM;
+ }
+ found = false;
+ }
+ }
+
+ /* up to ext_buf_pools.num_of_pools_used pools may be defined */
+ if (p_fm_buf_pool_depletion && p_fm_buf_pool_depletion->
+ pools_grp_mode_enable) {
+ if ((p_fm_buf_pool_depletion->num_of_pools >
+ p_fm_ext_pools->num_of_pools_used)) {
+ pr_err("buf_pool_depletion.num_of_pools can't be larger than %d and can't be larger than num_of_pools_used\n",
+ max_num_of_ext_pools);
+ return -EDOM;
+ }
+ if (!p_fm_buf_pool_depletion->num_of_pools) {
+ pr_err("buf_pool_depletion.num_of_pools_to_consider can not be 0 when pools_grp_mode_enable=true\n");
+ return -EDOM;
+ }
+ found = false;
+ count = 0;
+ /* for each pool that is in pools_to_consider, check if it
+ * is defined in ext_buf_pool
+ */
+ for (i = 0; i < bm_max_num_of_pools; i++) {
+ if (p_fm_buf_pool_depletion->pools_to_consider[i]) {
+ for (j = 0; j < p_fm_ext_pools->
+ num_of_pools_used; j++) {
+ if (i == p_fm_ext_pools->
+ ext_buf_pool[j].id) {
+ found = true;
+ count++;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("Pools selected for depletion are not used.\n");
+ return -EINVAL;
+ }
+ found = false;
+ }
+ }
+ /* check that the number of pools that we have checked is
+ * equal to the number announced by the user
+ */
+ if (count != p_fm_buf_pool_depletion->num_of_pools) {
+ pr_err("buf_pool_depletion.num_of_pools is larger than the number of pools defined.\n");
+ return -EDOM;
+ }
+ }
+
+ if (p_fm_buf_pool_depletion && p_fm_buf_pool_depletion->
+ single_pool_mode_enable) {
+ /* calculate vector for number of pools depletion */
+ found = false;
+ count = 0;
+ for (i = 0; i < bm_max_num_of_pools; i++) {
+ if (p_fm_buf_pool_depletion->
+ pools_to_consider_for_single_mode[i]) {
+ for (j = 0; j < p_fm_ext_pools->
+ num_of_pools_used;
+ j++) {
+ if (i == p_fm_ext_pools->
+ ext_buf_pool[j].id) {
+ found = true;
+ count++;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("Pools selected for depletion are not used.\n");
+ return -EINVAL;
+ }
+ found = false;
+ }
+ }
+ if (!count) {
+ pr_err("No pools defined for single buffer mode pool depletion.\n");
+ return -EDOM;
+ }
+ }
+
+ return 0;
+}
+
+int fm_sp_check_int_context_params(struct fm_sp_int_context_data_copy_t *
+ p_fm_sp_int_context_data_copy)
+{
+ /* Check that divisible by 16 and not larger than 240 */
+ if (p_fm_sp_int_context_data_copy->int_context_offset >
+ MAX_INT_OFFSET) {
+ pr_err("int_context.int_context_offset can't be larger than %d\n",
+ MAX_INT_OFFSET);
+ return -EDOM;
+ }
+ if (p_fm_sp_int_context_data_copy->int_context_offset %
+ OFFSET_UNITS) {
+ pr_err("int_context.int_context_offset has to be divisible by %d\n",
+ OFFSET_UNITS);
+ return -EDOM;
+
+ /* check that ic size+ic internal offset, does not exceed
+ * ic block size
+ */
+ }
+ if (p_fm_sp_int_context_data_copy->size +
+ p_fm_sp_int_context_data_copy->int_context_offset >
+ MAX_IC_SIZE) {
+ pr_err("int_context.size + int_context.int_context_offset has to be smaller than %d\n",
+ MAX_IC_SIZE);
+ return -EDOM;
+ /* Check that divisible by 16 and not larger than 256 */
+ }
+ if (p_fm_sp_int_context_data_copy->size % OFFSET_UNITS) {
+ pr_err("int_context.size has to be divisible by %d\n",
+ OFFSET_UNITS);
+ return -EDOM;
+
+ /* Check that divisible by 16 and not larger than 4K */
+ }
+ if (p_fm_sp_int_context_data_copy->ext_buf_offset > MAX_EXT_OFFSET) {
+ pr_err("int_context.ext_buf_offset can't be larger than %d\n",
+ MAX_EXT_OFFSET);
+ return -EDOM;
+ }
+ if (p_fm_sp_int_context_data_copy->ext_buf_offset % OFFSET_UNITS) {
+ pr_err("int_context.ext_buf_offset has to be divisible by %d\n",
+ OFFSET_UNITS);
+ return -EDOM;
+ }
+ return 0;
+}
+
+int fm_sp_check_buf_margins(struct fm_sp_buf_margins_t
+ *p_fm_sp_buf_margins)
+{
+ /* Check the margin definition */
+ if (p_fm_sp_buf_margins->start_margins > MAX_EXT_BUFFER_OFFSET) {
+ pr_err("buf_margins.start_margins can't be larger than %d\n",
+ MAX_EXT_BUFFER_OFFSET);
+ return -EDOM;
+ }
+ if (p_fm_sp_buf_margins->end_margins > MAX_EXT_BUFFER_OFFSET) {
+ pr_err("buf_margins.end_margins can't be larger than %d\n",
+ MAX_EXT_BUFFER_OFFSET);
+ return -EDOM;
+ }
+ return 0;
+}
+
+int fm_sp_build_buffer_structure(struct fm_sp_int_context_data_copy_t *
+ p_fm_sp_int_context_data_copy,
+ struct fm_buffer_prefix_content_t *
+ p_buffer_prefix_content,
+ struct fm_sp_buf_margins_t
+ *p_fm_sp_buf_margins,
+ struct fm_sp_buffer_offsets_t
+ *p_fm_sp_buffer_offsets,
+ uint8_t *internal_buf_offset)
+{
+ uint32_t tmp;
+
+ /* Align start of internal context data to 16 byte */
+ p_fm_sp_int_context_data_copy->ext_buf_offset = (uint16_t)
+ ((p_buffer_prefix_content->priv_data_size &
+ (OFFSET_UNITS - 1)) ?
+ ((p_buffer_prefix_content->priv_data_size + OFFSET_UNITS) &
+ ~(uint16_t)(OFFSET_UNITS - 1)) :
+ p_buffer_prefix_content->priv_data_size);
+
+ /* Translate margin and int_context params to FM parameters */
+ /* Initialize with illegal value. Later we'll set legal values. */
+ p_fm_sp_buffer_offsets->prs_result_offset = (uint32_t)ILLEGAL_BASE;
+ p_fm_sp_buffer_offsets->time_stamp_offset = (uint32_t)ILLEGAL_BASE;
+ p_fm_sp_buffer_offsets->hash_result_offset = (uint32_t)ILLEGAL_BASE;
+
+ /* Internally the driver supports 4 options
+ * 1. prsResult/timestamp/hashResult selection (in fact 8 options,
+ * but for simplicity we'll
+ * relate to it as 1).
+ * 2. All IC context (from AD) not including debug.
+ */
+
+ /* This case covers the options under 1 */
+ /* Copy size must be in 16-byte granularity. */
+ p_fm_sp_int_context_data_copy->size =
+ (uint16_t)((p_buffer_prefix_content->
+ pass_prs_result ? 32 : 0) +
+ ((p_buffer_prefix_content->pass_time_stamp ||
+ p_buffer_prefix_content->
+ pass_hash_result) ? 16 : 0));
+
+ /* Align start of internal context data to 16 byte */
+ p_fm_sp_int_context_data_copy->int_context_offset =
+ (uint8_t)(p_buffer_prefix_content->pass_prs_result ? 32 :
+ ((p_buffer_prefix_content->pass_time_stamp ||
+ p_buffer_prefix_content->
+ pass_hash_result) ? 64 : 0));
+
+ if (p_buffer_prefix_content->pass_prs_result)
+ p_fm_sp_buffer_offsets->prs_result_offset =
+ p_fm_sp_int_context_data_copy->ext_buf_offset;
+ if (p_buffer_prefix_content->pass_time_stamp)
+ p_fm_sp_buffer_offsets->time_stamp_offset =
+ p_buffer_prefix_content->
+ pass_prs_result ? (p_fm_sp_int_context_data_copy->
+ ext_buf_offset +
+ sizeof(struct fm_prs_result_t)) :
+ p_fm_sp_int_context_data_copy->ext_buf_offset;
+ if (p_buffer_prefix_content->pass_hash_result)
+ /* If PR is not requested, whether TS is
+ * requested or not, IC will be copied from TS
+ */
+ p_fm_sp_buffer_offsets->hash_result_offset =
+ p_buffer_prefix_content->
+ pass_prs_result ? (p_fm_sp_int_context_data_copy->
+ ext_buf_offset +
+ sizeof(struct fm_prs_result_t) + 8) :
+ p_fm_sp_int_context_data_copy->
+ ext_buf_offset + 8;
+
+ if (p_fm_sp_int_context_data_copy->size)
+ p_fm_sp_buf_margins->start_margins =
+ (uint16_t)(p_fm_sp_int_context_data_copy->ext_buf_offset +
+ p_fm_sp_int_context_data_copy->size);
+ else
+ /* No Internal Context passing, STartMargin is
+ * immediately after private_info
+ */
+ p_fm_sp_buf_margins->start_margins =
+ p_buffer_prefix_content->priv_data_size;
+
+ /* align data start */
+ tmp =
+ (uint32_t)(p_fm_sp_buf_margins->start_margins %
+ p_buffer_prefix_content->data_align);
+ if (tmp)
+ p_fm_sp_buf_margins->start_margins +=
+ (p_buffer_prefix_content->data_align - tmp);
+ p_fm_sp_buffer_offsets->data_offset = p_fm_sp_buf_margins->
+ start_margins;
+
+ return 0;
+}
+
+/* End of inter-module routines */
--
1.7.11.7
From: Igal Liberman <[email protected]>
The FMan Port FLib provides basic API used by the drivers to
configure and control the FMan Port hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Kconfig | 1 +
drivers/net/ethernet/freescale/fman/Makefile | 2 +
drivers/net/ethernet/freescale/fman/port/Makefile | 3 +
.../net/ethernet/freescale/fman/port/fman_port.c | 619 +++++++++++++++++++++
4 files changed, 625 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/port/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/port/fman_port.c
diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig
index 8aeae29..af42c3a 100644
--- a/drivers/net/ethernet/freescale/fman/Kconfig
+++ b/drivers/net/ethernet/freescale/fman/Kconfig
@@ -5,3 +5,4 @@ config FSL_FMAN
help
Freescale Data-Path Acceleration Architecture Frame Manager
(FMan) support
+
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index 2799c6f..50a4de2 100644
--- a/drivers/net/ethernet/freescale/fman/Makefile
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -3,3 +3,5 @@ subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman/flib
obj-y += fsl_fman.o
fsl_fman-objs := fman.o
+
+obj-y += port/
diff --git a/drivers/net/ethernet/freescale/fman/port/Makefile b/drivers/net/ethernet/freescale/fman/port/Makefile
new file mode 100644
index 0000000..54b1fa4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/Makefile
@@ -0,0 +1,3 @@
+obj-y += fsl_fman_port.o
+
+fsl_fman_port-objs := fman_port.o
diff --git a/drivers/net/ethernet/freescale/fman/port/fman_port.c b/drivers/net/ethernet/freescale/fman/port/fman_port.c
new file mode 100644
index 0000000..6754c35
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fman_port.c
@@ -0,0 +1,619 @@
+/*
+ * 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 "common/general.h"
+
+#include "fman_common.h"
+#include "fsl_fman_port.h"
+
+/* problem Eyal: the following should not be here*/
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+
+static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg)
+{
+ if (cfg->errata_A006675)
+ return NIA_ENG_FM_CTL |
+ NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME;
+ else
+ return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME;
+}
+
+static int init_bmi_rx(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_rx_bmi_regs __iomem *regs = &port->bmi_regs->rx;
+ uint32_t tmp;
+
+ /* Rx Configuration register */
+ tmp = 0;
+ if (cfg->discard_override)
+ tmp |= BMI_PORT_CFG_FDOVR;
+ iowrite32be(tmp, ®s->fmbm_rcfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ if (cfg->dma_write_optimize)
+ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
+ iowrite32be(tmp, ®s->fmbm_rda);
+
+ /* Rx FIFO parameters */
+ tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) <<
+ BMI_RX_FIFO_PRI_ELEVATION_SHIFT;
+ tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1;
+ iowrite32be(tmp, ®s->fmbm_rfp);
+
+ if (cfg->excessive_threshold_register)
+ /* always allow access to the extra resources */
+ iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, ®s->fmbm_reth);
+
+ /* Frame end data */
+ tmp = (uint32_t)cfg->checksum_bytes_ignore <<
+ BMI_RX_FRAME_END_CS_IGNORE_SHIFT;
+ tmp |= (uint32_t)cfg->rx_cut_end_bytes << BMI_RX_FRAME_END_CUT_SHIFT;
+ if (cfg->errata_A006320)
+ tmp &= 0xffe0ffff;
+ iowrite32be(tmp, ®s->fmbm_rfed);
+
+ /* Internal context parameters */
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, ®s->fmbm_ricp);
+
+ /* Internal buffer offset */
+ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
+ << BMI_INT_BUF_MARG_SHIFT;
+ iowrite32be(tmp, ®s->fmbm_rim);
+
+ /* External buffer margins */
+ tmp = (uint32_t)cfg->ext_buf_start_margin <<
+ BMI_EXT_BUF_MARG_START_SHIFT;
+ tmp |= (uint32_t)cfg->ext_buf_end_margin;
+ if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather)
+ tmp |= BMI_SG_DISABLE;
+ iowrite32be(tmp, ®s->fmbm_rebm);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_RX_MR_DEF;
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ if (cfg->sync_req)
+ tmp |= BMI_CMD_ATTR_SYNC;
+
+ iowrite32be(tmp, ®s->fmbm_rfca);
+
+ /* NIA */
+ tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
+ tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg);
+
+ iowrite32be(tmp, ®s->fmbm_rfne);
+
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene);
+
+ /* Default/error queues */
+ iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_rfqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_refqid);
+
+ /* Discard/error masks */
+ iowrite32be(params->discard_mask, ®s->fmbm_rfsdm);
+ iowrite32be(params->err_mask, ®s->fmbm_rfsem);
+
+ return 0;
+}
+
+static int init_bmi_tx(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_tx_bmi_regs __iomem *regs = &port->bmi_regs->tx;
+ uint32_t tmp;
+
+ /* Tx Configuration register */
+ tmp = 0;
+ iowrite32be(tmp, ®s->fmbm_tcfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ iowrite32be(tmp, ®s->fmbm_tda);
+
+ /* Tx FIFO parameters */
+ tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) <<
+ BMI_TX_FIFO_MIN_FILL_SHIFT;
+ tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
+ BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level /
+ FMAN_PORT_BMI_FIFO_UNITS - 1);
+ iowrite32be(tmp, ®s->fmbm_tfp);
+
+ /* Frame end data */
+ tmp = (uint32_t)cfg->checksum_bytes_ignore <<
+ BMI_FRAME_END_CS_IGNORE_SHIFT;
+ iowrite32be(tmp, ®s->fmbm_tfed);
+
+ /* Internal context parameters */
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, ®s->fmbm_ticp);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_TX_MR_DEF;
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ iowrite32be(tmp, ®s->fmbm_tfca);
+
+ /* Dequeue NIA + enqueue NIA */
+ iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_tfdne);
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_tfene);
+ if (cfg->fmbm_tfne_has_features)
+ iowrite32be(!params->dflt_fqid ?
+ BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME :
+ NIA_BMI_AC_FETCH_ALL_FRAME, ®s->fmbm_tfne);
+ if (!params->dflt_fqid && params->dont_release_buf) {
+ iowrite32be(0x00FFFFFF, ®s->fmbm_tcfqid);
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE,
+ ®s->fmbm_tfene);
+ if (cfg->fmbm_tfne_has_features)
+ iowrite32be(ioread32be(®s->fmbm_tfne) & ~BMI_EBD_EN,
+ ®s->fmbm_tfne);
+ }
+
+ /* Confirmation/error queues */
+ if (params->dflt_fqid || !params->dont_release_buf)
+ iowrite32be(params->dflt_fqid & 0x00FFFFFF, ®s->fmbm_tcfqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_tefqid);
+
+ return 0;
+}
+
+static int init_bmi_oh(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_oh_bmi_regs __iomem *regs = &port->bmi_regs->oh;
+ uint32_t tmp;
+
+ /* OP Configuration register */
+ tmp = 0;
+ if (cfg->discard_override)
+ tmp |= BMI_PORT_CFG_FDOVR;
+ iowrite32be(tmp, ®s->fmbm_ocfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ if (cfg->dma_write_optimize)
+ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
+ iowrite32be(tmp, ®s->fmbm_oda);
+
+ /* Tx FIFO parameters */
+ tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
+ BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ iowrite32be(tmp, ®s->fmbm_ofp);
+
+ /* Internal context parameters */
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, ®s->fmbm_oicp);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_OP_MR_DEF;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ if (cfg->sync_req)
+ tmp |= BMI_CMD_ATTR_SYNC;
+ if (port->type == E_FMAN_PORT_TYPE_OP)
+ tmp |= BMI_CMD_ATTR_ORDER;
+ iowrite32be(tmp, ®s->fmbm_ofca);
+
+ /* Internal buffer offset */
+ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
+ << BMI_INT_BUF_MARG_SHIFT;
+ iowrite32be(tmp, ®s->fmbm_oim);
+
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_ofdne);
+
+ /* NIA and Enqueue NIA */
+ iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg),
+ ®s->fmbm_ofne);
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR,
+ ®s->fmbm_ofene);
+
+ /* Default/error queues */
+ iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_ofqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_oefqid);
+
+ /* Discard/error masks */
+ if (port->type == E_FMAN_PORT_TYPE_OP) {
+ iowrite32be(params->discard_mask, ®s->fmbm_ofsdm);
+ iowrite32be(params->err_mask, ®s->fmbm_ofsem);
+ }
+
+ return 0;
+}
+
+static int init_qmi(struct fman_port *port,
+ struct fman_port_cfg *cfg, struct fman_port_params *params)
+{
+ struct fman_port_qmi_regs __iomem *regs = port->qmi_regs;
+ uint32_t tmp;
+
+ /* Rx port configuration */
+ if ((port->type == E_FMAN_PORT_TYPE_RX) ||
+ (port->type == E_FMAN_PORT_TYPE_RX_10G)) {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen);
+ return 0;
+ }
+
+ /* Continue with Tx and O/H port configuration */
+ if ((port->type == E_FMAN_PORT_TYPE_TX) ||
+ (port->type == E_FMAN_PORT_TYPE_TX_10G)) {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE,
+ ®s->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, ®s->fmqm_pndn);
+ } else {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, ®s->fmqm_pndn);
+ }
+
+ /* Dequeue Configuration register */
+ tmp = 0;
+ if (cfg->deq_high_pri)
+ tmp |= QMI_DEQ_CFG_PRI;
+
+ switch (cfg->deq_type) {
+ case E_FMAN_PORT_DEQ_BY_PRI:
+ tmp |= QMI_DEQ_CFG_TYPE1;
+ break;
+ case E_FMAN_PORT_DEQ_ACTIVE_FQ:
+ tmp |= QMI_DEQ_CFG_TYPE2;
+ break;
+ case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS:
+ tmp |= QMI_DEQ_CFG_TYPE3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cfg->qmi_deq_options_support) {
+ switch (cfg->deq_prefetch_opt) {
+ case E_FMAN_PORT_DEQ_NO_PREFETCH:
+ break;
+ case E_FMAN_PORT_DEQ_PART_PREFETCH:
+ tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL;
+ break;
+ case E_FMAN_PORT_DEQ_FULL_PREFETCH:
+ tmp |= QMI_DEQ_CFG_PREFETCH_FULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) <<
+ QMI_DEQ_CFG_SP_SHIFT;
+ tmp |= cfg->deq_byte_cnt;
+ iowrite32be(tmp, ®s->fmqm_pndc);
+
+ return 0;
+}
+
+void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type)
+{
+ cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP;
+ cfg->dma_ic_stash_on = false;
+ cfg->dma_header_stash_on = false;
+ cfg->dma_sg_stash_on = false;
+ cfg->dma_write_optimize = true;
+ cfg->color = E_FMAN_PORT_COLOR_GREEN;
+ cfg->discard_override = false;
+ cfg->checksum_bytes_ignore = 0;
+ cfg->rx_cut_end_bytes = 4;
+ cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
+ cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
+ cfg->rx_fd_bits = 0;
+ cfg->ic_ext_offset = 0;
+ cfg->ic_int_offset = 0;
+ cfg->ic_size = 0;
+ cfg->int_buf_start_margin = 0;
+ cfg->ext_buf_start_margin = 0;
+ cfg->ext_buf_end_margin = 0;
+ cfg->tx_fifo_min_level = 0;
+ cfg->tx_fifo_low_comf_level = (5 * 1024);
+ cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI;
+
+ cfg->sync_req = true;
+ cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH;
+
+ if (type == E_FMAN_PORT_TYPE_TX_10G) {
+ cfg->tx_fifo_deq_pipeline_depth = 4;
+ cfg->deq_high_pri = true;
+ cfg->deq_byte_cnt = 0x1400;
+ } else {
+ if (type == E_FMAN_PORT_TYPE_OP)
+ cfg->tx_fifo_deq_pipeline_depth = 2;
+ else
+ cfg->tx_fifo_deq_pipeline_depth = 1;
+
+ cfg->deq_high_pri = false;
+ cfg->deq_byte_cnt = 0x400;
+ }
+ cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER;
+}
+
+int fman_port_init(struct fman_port *port,
+ struct fman_port_cfg *cfg, struct fman_port_params *params)
+{
+ int err;
+
+ /* Init BMI registers */
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ err = init_bmi_rx(port, cfg, params);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ err = init_bmi_tx(port, cfg, params);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ err = init_bmi_oh(port, cfg, params);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (err)
+ return err;
+
+ /* Init QMI registers */
+ err = init_qmi(port, cfg, params);
+ return err;
+
+ return 0;
+}
+
+int fman_port_enable(struct fman_port *port)
+{
+ uint32_t __iomem *bmi_cfg_reg;
+ uint32_t tmp;
+ bool rx_port;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
+ rx_port = true;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
+ rx_port = false;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
+ rx_port = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Enable QMI */
+ if (!rx_port) {
+ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN;
+ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
+ }
+
+ /* Enable BMI */
+ tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN;
+ iowrite32be(tmp, bmi_cfg_reg);
+
+ return 0;
+}
+
+int fman_port_disable(const struct fman_port *port)
+{
+ uint32_t __iomem *bmi_cfg_reg, *bmi_status_reg;
+ uint32_t tmp;
+ bool rx_port, failure = false;
+ int count;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
+ bmi_status_reg = &port->bmi_regs->rx.fmbm_rst;
+ rx_port = true;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
+ bmi_status_reg = &port->bmi_regs->tx.fmbm_tst;
+ rx_port = false;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
+ bmi_status_reg = &port->bmi_regs->oh.fmbm_ost;
+ rx_port = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable QMI */
+ if (!rx_port) {
+ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN;
+ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
+
+ /* Wait for QMI to finish FD handling */
+ count = 100;
+ do {
+ usleep_range(10, 11);
+ tmp = ioread32be(&port->qmi_regs->fmqm_pns);
+ } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count);
+
+ if (count == 0) {
+ /* Timeout */
+ failure = true;
+ }
+ }
+
+ /* Disable BMI */
+ tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN;
+ iowrite32be(tmp, bmi_cfg_reg);
+
+ /* Wait for graceful stop end */
+ count = 500;
+ do {
+ usleep_range(10, 11);
+ tmp = ioread32be(bmi_status_reg);
+ } while ((tmp & BMI_PORT_STATUS_BSY) && --count);
+
+ if (count == 0) {
+ /* Timeout */
+ failure = true;
+ }
+
+ if (failure)
+ return -EBUSY;
+
+ return 0;
+}
+
+int fman_port_set_bpools(const struct fman_port *port,
+ const struct fman_port_bpools *bp)
+{
+ uint32_t __iomem *bp_reg, *bp_depl_reg;
+ uint32_t tmp;
+ uint8_t i, max_bp_num;
+ bool grp_depl_used = false, rx_port;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ max_bp_num = port->ext_pools_num;
+ rx_port = true;
+ bp_reg = port->bmi_regs->rx.fmbm_ebmpi;
+ bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ if (port->fm_rev_maj != 4)
+ return -EINVAL;
+ max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM;
+ rx_port = false;
+ bp_reg = port->bmi_regs->oh.fmbm_oebmpi;
+ bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rx_port) {
+ /* Check buffers are provided in ascending order */
+ for (i = 0; (i < (bp->count - 1) &&
+ (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1)); i++) {
+ if (bp->bpool[i].size > bp->bpool[i + 1].size)
+ return -EINVAL;
+ }
+ }
+
+ /* Set up external buffers pools */
+ for (i = 0; i < bp->count; i++) {
+ tmp = BMI_EXT_BUF_POOL_VALID;
+ tmp |= ((uint32_t)bp->bpool[i].bpid <<
+ BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK;
+
+ if (rx_port) {
+ if (bp->counters_enable)
+ tmp |= BMI_EXT_BUF_POOL_EN_COUNTER;
+
+ if (bp->bpool[i].is_backup)
+ tmp |= BMI_EXT_BUF_POOL_BACKUP;
+
+ tmp |= (uint32_t)bp->bpool[i].size;
+ }
+
+ iowrite32be(tmp, &bp_reg[i]);
+ }
+
+ /* Clear unused pools */
+ for (i = bp->count; i < max_bp_num; i++)
+ iowrite32be(0, &bp_reg[i]);
+
+ /* Pools depletion */
+ tmp = 0;
+ for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) {
+ if (bp->bpool[i].grp_bp_depleted) {
+ grp_depl_used = true;
+ tmp |= 0x80000000 >> i;
+ }
+
+ if (bp->bpool[i].single_bp_depleted)
+ tmp |= 0x80 >> i;
+ }
+
+ if (grp_depl_used)
+ tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) <<
+ BMI_POOL_DEP_NUM_OF_POOLS_SHIFT;
+
+ iowrite32be(tmp, bp_depl_reg);
+ return 0;
+}
--
1.7.11.7
From: Igal Liberman <[email protected]>
This patch adds The FMan Port configuration, initialization and
runtime control routines.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Makefile | 2 +-
drivers/net/ethernet/freescale/fman/fm.c | 487 ++++++-
drivers/net/ethernet/freescale/fman/fm_common.h | 168 +++
drivers/net/ethernet/freescale/fman/fm_drv.c | 108 +-
drivers/net/ethernet/freescale/fman/fm_drv.h | 2 +
drivers/net/ethernet/freescale/fman/fm_port_drv.c | 496 +++++++
.../net/ethernet/freescale/fman/inc/fm_port_ext.h | 376 +++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 101 ++
drivers/net/ethernet/freescale/fman/port/Makefile | 2 +-
drivers/net/ethernet/freescale/fman/port/fm_port.c | 1435 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/port/fm_port.h | 527 +++++++
11 files changed, 3700 insertions(+), 4 deletions(-)
create mode 100644 drivers/net/ethernet/freescale/fman/fm_port_drv.c
create mode 100644 drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h
create mode 100644 drivers/net/ethernet/freescale/fman/port/fm_port.c
create mode 100644 drivers/net/ethernet/freescale/fman/port/fm_port.h
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index c6c3e24..8d637e2 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 fm.o fm_drv.o
+fsl_fman-objs := fman.o fm_muram.o fm.o fm_drv.o fm_port_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
index fd6de5a..8bafab2 100644
--- a/drivers/net/ethernet/freescale/fman/fm.c
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -459,11 +459,36 @@ static void qmi_err_event(struct fm_t *p_fm)
static void dma_err_event(struct fm_t *p_fm)
{
- uint32_t status;
+ uint32_t status, com_id;
+ uint8_t tnum;
+ uint8_t port_id;
+ uint8_t relative_port_id;
+ uint16_t liodn;
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_BUS_ERR) {
+ com_id = fman_get_dma_com_id(dma_rg);
+ port_id = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >>
+ DMA_TRANSFER_PORTID_SHIFT));
+ HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info.
+ major_rev,
+ relative_port_id,
+ port_id);
+ tnum =
+ (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >>
+ DMA_TRANSFER_TNUM_SHIFT);
+ liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK);
+ ASSERT(p_fm->p_fm_state_struct->
+ ports_types[port_id] !=
+ FM_PORT_TYPE_DUMMY);
+ p_fm->f_bus_error(p_fm->h_app,
+ p_fm->p_fm_state_struct->
+ ports_types[port_id],
+ relative_port_id,
+ fman_get_dma_addr(dma_rg), tnum, liodn);
+ }
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)
@@ -764,6 +789,462 @@ uint8_t fm_get_id(struct fm_t *p_fm)
return p_fm->p_fm_state_struct->fm_id;
}
+int fm_get_set_port_params(struct fm_t *p_fm,
+ struct fm_inter_module_port_init_params_t
+ *p_port_params)
+{
+ int err;
+ unsigned long int_flags;
+ uint8_t port_id = p_port_params->port_id, mac_id;
+ 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;
+
+ ASSERT(IN_RANGE(1, port_id, 63));
+
+ spin_lock_irqsave(p_fm->spinlock, int_flags);
+
+ p_fm->p_fm_state_struct->ports_types[port_id] =
+ p_port_params->port_type;
+
+ err =
+ fm_set_num_of_tasks(p_fm, p_port_params->port_id,
+ &p_port_params->num_of_tasks,
+ &p_port_params->num_of_extra_tasks, true);
+ if (err) {
+ spin_unlock_irqrestore(p_fm->spinlock, int_flags);
+ return err;
+ }
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_fm->p_fm_state_struct->rev_info.major_rev != 4)
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+ /* for transmit&O/H ports */
+ if (p_port_params->port_type != FM_PORT_TYPE_RX) {
+ uint8_t enq_th;
+ uint8_t deq_th;
+
+ /* update qmi ENQ/DEQ threshold */
+ p_fm->p_fm_state_struct->accumulated_num_of_deq_tnums +=
+ p_port_params->deq_pipeline_depth;
+ enq_th = fman_get_qmi_enq_th(fman_rg.qmi_rg);
+ /* if enq_th is too big, we reduce it to the max value
+ * that is still 0
+ */
+ if (enq_th >=
+ (p_fm->intg->qmi_max_num_of_tnums -
+ p_fm->p_fm_state_struct->
+ accumulated_num_of_deq_tnums)) {
+ enq_th = (uint8_t)(
+ p_fm->intg->
+ qmi_max_num_of_tnums -
+ p_fm->p_fm_state_struct->
+ accumulated_num_of_deq_tnums - 1);
+ fman_set_qmi_enq_th(fman_rg.qmi_rg, enq_th);
+ }
+
+ deq_th = fman_get_qmi_deq_th(fman_rg.qmi_rg);
+ /* if deq_th is too small, we enlarge it to the min
+ * value that is still 0.
+ * depTh may not be larger than 63
+ * (p_fm->intg->qmi_max_num_of_tnums-1).
+ */
+ if ((deq_th <=
+ p_fm->p_fm_state_struct->
+ accumulated_num_of_deq_tnums) &&
+ (deq_th <
+ p_fm->intg->
+ qmi_max_num_of_tnums - 1)) {
+ deq_th = (uint8_t)(p_fm->
+ p_fm_state_struct->
+ accumulated_num_of_deq_tnums
+ + 1);
+ fman_set_qmi_deq_th(fman_rg.qmi_rg, deq_th);
+ }
+ }
+#ifdef FM_LOW_END_RESTRICTION
+ if (p_fm->p_fm_state_struct->rev_info.major_rev == 0x4) {
+ if ((port_id == 0x1) || (port_id == 0x29)) {
+ if (p_fm->p_fm_state_struct->low_end_restriction) {
+ spin_unlock_irqrestore(p_fm->spinlock,
+ int_flags);
+ pr_err("OP#0 can't work with Tx Port1\n");
+ return -EAGAIN;
+ }
+ p_fm->p_fm_state_struct->low_end_restriction = true;
+ }
+ }
+#endif /* FM_LOW_END_RESTRICTION */
+
+ err = fm_set_size_of_fifo(p_fm,
+ p_port_params->port_id,
+ &p_port_params->size_of_fifo,
+ &p_port_params->extra_size_of_fifo, true);
+ if (err) {
+ spin_unlock_irqrestore(p_fm->spinlock, int_flags);
+ return err;
+ }
+
+ err = fm_set_num_of_open_dmas(p_fm,
+ p_port_params->port_id,
+ &p_port_params->num_of_open_dmas,
+ &p_port_params->num_of_extra_open_dmas,
+ true);
+ if (err) {
+ spin_unlock_irqrestore(p_fm->spinlock,
+ (unsigned long)int_flags);
+ return err;
+ }
+
+ fman_set_liodn_per_port(&fman_rg,
+ port_id,
+ p_port_params->liodn_base,
+ p_port_params->liodn_offset);
+
+ if (p_fm->p_fm_state_struct->rev_info.major_rev < 6)
+ fman_set_order_restoration_per_port(fman_rg.fpm_rg,
+ port_id,
+ !!((p_port_params->
+ port_type ==
+ FM_PORT_TYPE_RX)));
+
+ HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev,
+ mac_id,
+ port_id);
+
+ if (p_port_params->max_frame_length >=
+ p_fm->p_fm_state_struct->mac_max_frame_lengths[mac_id]) {
+ p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id] =
+ p_port_params->max_frame_length;
+ } else {
+ pr_warn("Port max_frame_length is smaller than MAC current MTU\n");
+ spin_unlock_irqrestore(p_fm->spinlock,
+ (unsigned long)int_flags);
+ return -EDOM;
+ }
+
+ spin_unlock_irqrestore(p_fm->spinlock, (unsigned long)int_flags);
+
+ return 0;
+}
+
+void fm_free_port_params(struct fm_t *p_fm,
+ struct fm_inter_module_port_free_params_t
+ *p_port_params)
+{
+ unsigned long int_flags;
+ uint8_t port_id = p_port_params->port_id;
+ uint8_t num_of_tasks, num_of_dmas, mac_id;
+ uint16_t size_of_fifo;
+ struct fman_qmi_regs __iomem *qmi_rg = p_fm->p_fm_qmi_regs;
+ struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs;
+
+ ASSERT(IN_RANGE(1, port_id, 63));
+
+ spin_lock_irqsave(p_fm->spinlock, int_flags);
+
+ p_fm->p_fm_state_struct->ports_types[port_id] =
+ FM_PORT_TYPE_DUMMY;
+
+ /* free num_of_tasks */
+ num_of_tasks = fman_get_num_of_tasks(bmi_rg, port_id);
+ ASSERT(p_fm->p_fm_state_struct->accumulated_num_of_tasks >=
+ num_of_tasks);
+ p_fm->p_fm_state_struct->accumulated_num_of_tasks -= num_of_tasks;
+
+ /* free num_of_open_dmas */
+ num_of_dmas = fman_get_num_of_dmas(bmi_rg, port_id);
+ ASSERT(p_fm->p_fm_state_struct->accumulated_num_of_open_dmas >=
+ num_of_dmas);
+ p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -= num_of_dmas;
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if (p_fm->p_fm_state_struct->rev_info.major_rev < 6) {
+ /* update total num of DMA's with committed number
+ * of open DMAS, and max uncommitted pool.
+ */
+ fman_set_num_of_open_dmas(bmi_rg,
+ port_id,
+ 1,
+ 0,
+ (uint8_t)
+ (p_fm->p_fm_state_struct->
+ accumulated_num_of_open_dmas +
+ p_fm->p_fm_state_struct->
+ extra_open_dmas_pool_size
+ ));
+ }
+#endif /* FM_HAS_TOTAL_DMAS */
+
+ /* free size_of_fifo */
+ size_of_fifo = fman_get_size_of_fifo(bmi_rg, port_id);
+ ASSERT(p_fm->p_fm_state_struct->accumulated_fifo_size >=
+ (size_of_fifo * BMI_FIFO_UNITS));
+ p_fm->p_fm_state_struct->accumulated_fifo_size -=
+ (size_of_fifo * BMI_FIFO_UNITS);
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_fm->p_fm_state_struct->rev_info.major_rev != 4)
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+ /* for transmit&O/H ports */
+ if (p_port_params->port_type != FM_PORT_TYPE_RX) {
+ uint8_t enq_th;
+ uint8_t deq_th;
+
+ /* update qmi ENQ/DEQ threshold */
+ p_fm->p_fm_state_struct->accumulated_num_of_deq_tnums -=
+ p_port_params->deq_pipeline_depth;
+
+ /* p_fm->p_fm_state_struct->
+ * accumulated_num_of_deq_tnums is now smaller,
+ * so we can enlarge enq_th
+ */
+ enq_th =
+ (uint8_t)(p_fm->intg->qmi_max_num_of_tnums -
+ p_fm->p_fm_state_struct->
+ accumulated_num_of_deq_tnums - 1);
+
+ /* p_fm->p_fm_state_struct->
+ * accumulated_num_of_deq_tnums is now smaller,
+ * so we can reduce deq_th
+ */
+ deq_th =
+ (uint8_t)(p_fm->p_fm_state_struct->
+ accumulated_num_of_deq_tnums + 1);
+
+ fman_set_qmi_enq_th(qmi_rg, enq_th);
+ fman_set_qmi_deq_th(qmi_rg, deq_th);
+ }
+
+ HW_PORT_ID_TO_SW_PORT_ID(p_fm->p_fm_state_struct->rev_info.major_rev,
+ mac_id,
+ port_id);
+
+ p_fm->p_fm_state_struct->port_max_frame_lengths[mac_id] = 0;
+
+#ifdef FM_LOW_END_RESTRICTION
+ if (p_fm->p_fm_state_struct->rev_info.major_rev == 0x4) {
+ if ((port_id == 0x1) || (port_id == 0x29))
+ p_fm->p_fm_state_struct->low_end_restriction = false;
+ }
+#endif /* FM_LOW_END_RESTRICTION */
+ spin_unlock_irqrestore(p_fm->spinlock, int_flags);
+}
+
+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)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs;
+ uint32_t size_of_fifo = *p_size_of_fifo, extra_size_of_fifo =
+ *p_extra_size_of_fifo;
+ uint16_t current_val = 0, current_extra_val = 0;
+
+ ASSERT(IN_RANGE(1, port_id, 63));
+
+ if (!initial_config) {
+ /* !initial_config - runtime change of existing value.
+ * - read the current FIFO and extra FIFO size
+ */
+ current_extra_val =
+ fman_get_size_of_extra_fifo(bmi_rg, port_id);
+ current_val = fman_get_size_of_fifo(bmi_rg, port_id);
+ }
+
+ if (extra_size_of_fifo > current_extra_val) {
+ if (extra_size_of_fifo &&
+ !p_fm->p_fm_state_struct->extra_fifo_pool_size)
+ /* if this is the first time a port
+ * requires extra_fifo_pool_size,
+ * the total extra_fifo_pool_size
+ * must be initialized to 1 buffer per port
+ */
+ p_fm->p_fm_state_struct->extra_fifo_pool_size =
+ p_fm->intg->num_of_rx_ports * BMI_FIFO_UNITS;
+
+ p_fm->p_fm_state_struct->extra_fifo_pool_size =
+ max(p_fm->p_fm_state_struct->extra_fifo_pool_size,
+ extra_size_of_fifo);
+ }
+
+ /* check that there are enough uncommitted fifo size */
+ if ((p_fm->p_fm_state_struct->accumulated_fifo_size - current_val +
+ size_of_fifo) >
+ (p_fm->p_fm_state_struct->total_fifo_size -
+ p_fm->p_fm_state_struct->extra_fifo_pool_size)) {
+ pr_err("Requested fifo size and extra size exceed total FIFO size.\n");
+ return -EAGAIN;
+ }
+ /* update accumulated */
+ ASSERT(p_fm->p_fm_state_struct->accumulated_fifo_size >=
+ current_val);
+ p_fm->p_fm_state_struct->accumulated_fifo_size -= current_val;
+ p_fm->p_fm_state_struct->accumulated_fifo_size += size_of_fifo;
+ fman_set_size_of_fifo(bmi_rg, port_id, size_of_fifo,
+ extra_size_of_fifo);
+
+ return 0;
+}
+
+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)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs;
+ uint8_t current_val = 0, current_extra_val = 0, num_of_tasks =
+ *p_num_of_tasks, num_of_extra_tasks = *p_num_of_extra_tasks;
+
+ ASSERT(IN_RANGE(1, port_id, 63));
+
+ if (!initial_config) {
+ /* !initial_config - runtime change of existing value.
+ * - read the current number of tasks
+ */
+ current_val = fman_get_num_of_tasks(bmi_rg, port_id);
+ current_extra_val =
+ fman_get_num_extra_tasks(bmi_rg, port_id);
+ }
+
+ if (num_of_extra_tasks > current_extra_val)
+ p_fm->p_fm_state_struct->extra_tasks_pool_size =
+ (uint8_t)max(p_fm->p_fm_state_struct->extra_tasks_pool_size,
+ num_of_extra_tasks);
+
+ /* check that there are enough uncommitted tasks */
+ if ((p_fm->p_fm_state_struct->accumulated_num_of_tasks - current_val +
+ num_of_tasks) >
+ (p_fm->p_fm_state_struct->total_num_of_tasks -
+ p_fm->p_fm_state_struct->extra_tasks_pool_size)) {
+ pr_err("Requested num_of_tasks and extra tasks pool for fm%d exceed total num_of_tasks.\n",
+ p_fm->p_fm_state_struct->fm_id);
+ return -EAGAIN;
+ }
+ ASSERT(p_fm->p_fm_state_struct->
+ accumulated_num_of_tasks >=
+ current_val);
+ /* update accumulated */
+ p_fm->p_fm_state_struct->accumulated_num_of_tasks -=
+ current_val;
+ p_fm->p_fm_state_struct->accumulated_num_of_tasks +=
+ num_of_tasks;
+ fman_set_num_of_tasks(bmi_rg, port_id, num_of_tasks,
+ num_of_extra_tasks);
+
+ return 0;
+}
+
+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)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = p_fm->p_fm_bmi_regs;
+ uint8_t num_of_open_dmas = *p_num_of_open_dmas,
+ num_of_extra_open_dmas = *p_num_of_extra_open_dmas;
+ uint8_t total_num_dmas = 0, current_val = 0, current_extra_val = 0;
+
+ ASSERT(IN_RANGE(1, port_id, 63));
+
+ if (!initial_config) {
+ /* !initial_config - runtime change of existing value.
+ * - read the current number of open Dma's
+ */
+ current_extra_val =
+ fman_get_num_extra_dmas(bmi_rg, port_id);
+ current_val = fman_get_num_of_dmas(bmi_rg, port_id);
+ }
+
+ /* it's illegal to be in a state where this is
+ * not the first set and no value is specified
+ */
+ ASSERT(initial_config || num_of_open_dmas);
+ if (!num_of_open_dmas) {
+ /* !num_of_open_dmas - first configuration according
+ * to values in regs.- read the current number of
+ * open Dma's
+ */
+ current_extra_val =
+ fman_get_num_extra_dmas(bmi_rg, port_id);
+ current_val = fman_get_num_of_dmas(bmi_rg, port_id);
+ /* This is the first configuration and user did not
+ * specify value (!num_of_open_dmas), reset values will be used
+ * and we just save these values for resource management
+ */
+ p_fm->p_fm_state_struct->extra_open_dmas_pool_size =
+ (uint8_t)max(p_fm->p_fm_state_struct->
+ extra_open_dmas_pool_size,
+ current_extra_val);
+ p_fm->p_fm_state_struct->accumulated_num_of_open_dmas +=
+ current_val;
+ *p_num_of_open_dmas = current_val;
+ *p_num_of_extra_open_dmas = current_extra_val;
+ return 0;
+ }
+
+ if (num_of_extra_open_dmas > current_extra_val)
+ p_fm->p_fm_state_struct->extra_open_dmas_pool_size =
+ (uint8_t)max(p_fm->p_fm_state_struct->
+ extra_open_dmas_pool_size,
+ num_of_extra_open_dmas);
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if ((p_fm->p_fm_state_struct->rev_info.major_rev < 6) &&
+ (p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -
+ current_val + num_of_open_dmas >
+ p_fm->p_fm_state_struct->max_num_of_open_dmas)) {
+ pr_err("Requested num_of_open_dmas for fm%d exceeds total num_of_open_dmas.\n",
+ p_fm->p_fm_state_struct->fm_id);
+ return -EAGAIN;
+ }
+#else
+ if ((p_fm->p_fm_state_struct->rev_info.major_rev >= 6) &&
+ #ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+ !((p_fm->p_fm_state_struct->rev_info.major_rev == 6) &&
+ (p_fm->p_fm_state_struct->rev_info.minor_rev == 0)) &&
+#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
+ (p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -
+ current_val + num_of_open_dmas >
+ p_fm->intg->dma_thresh_max_commq + 1)) {
+ pr_err("Requested num_of_open_dmas for fm%d exceeds DMA Command queue (%d)\n",
+ p_fm->p_fm_state_struct->fm_id,
+ p_fm->intg->dma_thresh_max_commq + 1);
+ return -EAGAIN;
+ }
+#endif /* FM_HAS_TOTAL_DMAS */
+ else {
+ ASSERT(p_fm->p_fm_state_struct->
+ accumulated_num_of_open_dmas >=
+ current_val);
+ /* update acummulated */
+ p_fm->p_fm_state_struct->accumulated_num_of_open_dmas -=
+ current_val;
+ p_fm->p_fm_state_struct->accumulated_num_of_open_dmas +=
+ num_of_open_dmas;
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if (p_fm->p_fm_state_struct->rev_info.major_rev < 6)
+ total_num_dmas =
+ (uint8_t)(p_fm->p_fm_state_struct->
+ accumulated_num_of_open_dmas +
+ p_fm->p_fm_state_struct->
+ extra_open_dmas_pool_size);
+#endif /* FM_HAS_TOTAL_DMAS */
+ fman_set_num_of_open_dmas(bmi_rg,
+ port_id,
+ num_of_open_dmas,
+ num_of_extra_open_dmas,
+ total_num_dmas);
+ }
+
+ return 0;
+}
+
int fm_reset_mac(struct fm_t *p_fm, uint8_t mac_id)
{
int err;
@@ -908,6 +1389,7 @@ static int init_fm_qmi(struct fm_t *p_fm)
void *fm_config(struct fm_params_t *p_fm_param)
{
struct fm_t *p_fm;
+ uint8_t i;
uintptr_t base_addr;
if (!((p_fm_param->firmware.p_code && p_fm_param->firmware.size) ||
@@ -932,6 +1414,9 @@ void *fm_config(struct fm_params_t *p_fm_param)
/* Initialize FM parameters which will be kept by the driver */
p_fm->p_fm_state_struct->fm_id = p_fm_param->fm_id;
+ for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS; i++)
+ p_fm->p_fm_state_struct->ports_types[i] = FM_PORT_TYPE_DUMMY;
+
/* Allocate the FM driver's parameters structure */
p_fm->p_fm_drv_param = kzalloc(sizeof(*p_fm->p_fm_drv_param),
GFP_KERNEL);
diff --git a/drivers/net/ethernet/freescale/fman/fm_common.h b/drivers/net/ethernet/freescale/fman/fm_common.h
index 45c450b..af9ba6a 100644
--- a/drivers/net/ethernet/freescale/fman/fm_common.h
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -82,6 +82,14 @@
#define CLS_PLAN_NUM_PER_GRP 8
+/* Defines used for manipulation CC and BMI */
+#define UPDATE_NIA_PNEN 0x80000000
+#define UPDATE_NIA_PNDN 0x20000000
+#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000
+#define UPDATE_NIA_FENE 0x04000000
+#define UPDATE_NIA_CMNE 0x02000000
+#define UPDATE_NIA_FPNE 0x01000000
+
/* list_object
* Macro to get the struct (object) for this entry.
* type - The type of the struct (object) this list
@@ -94,6 +102,12 @@
#define list_object(p_list, type, member) \
((type *)((char *)(p_list) - member_offset(type, member)))
+#define FM_LIODN_OFFSET_MASK 0x3FF
+
+/* NIA Description */
+/* V3 only */
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+
/* Enum for inter-module interrupts registration */
enum fm_event_modules {
FM_MOD_PRS = 0, /* Parser event */
@@ -209,6 +223,59 @@ static inline bool TRY_LOCK(spinlock_t *spinlock, volatile bool *p_flag)
#define FM_LIODN_OFFSET_MASK 0x3FF
+/* NIA Description */
+#define NIA_ENG_MASK 0x007C0000
+#define NIA_AC_MASK 0x0003ffff
+
+#define NIA_ORDER_RESTOR 0x00800000
+#define NIA_ENG_FM_CTL 0x00000000
+#define NIA_ENG_PRS 0x00440000
+#define NIA_ENG_BMI 0x00500000
+#define NIA_ENG_QMI_ENQ 0x00540000
+#define NIA_ENG_QMI_DEQ 0x00580000
+
+#define NIA_FM_CTL_AC_HC 0x0000000C
+#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008
+#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A
+#define NIA_FM_CTL_AC_POP_TO_N_STEP 0x0000000e
+#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER 0x00000010
+#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME 0x00000018
+#define NIA_FM_CTL_AC_POST_BMI_FETCH 0x00000012
+#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME 0x0000001A
+#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME 0x0000001E
+#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR 0x00000014
+#define NIA_FM_CTL_AC_POST_BMI_ENQ 0x00000022
+#define NIA_FM_CTL_AC_POST_TX 0x00000024
+/* V3 only */
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME 0x0000002A
+#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP 0x0000002C
+
+#define NIA_BMI_AC_ENQ_FRAME 0x00000002
+#define NIA_BMI_AC_TX_RELEASE 0x000002C0
+#define NIA_BMI_AC_RELEASE 0x000000C0
+#define NIA_BMI_AC_DISCARD 0x000000C1
+#define NIA_BMI_AC_TX 0x00000274
+#define NIA_BMI_AC_FETCH 0x00000208
+#define NIA_BMI_AC_MASK 0x000003FF
+
+#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202
+
+#define GET_NIA_BMI_AC_ENQ_FRAME(GET_NIA_BMI_AC_ENQ_FRAME, errata_A006675)\
+ (errata_A006675 ? \
+ ((uint32_t)(NIA_ENG_FM_CTL | \
+ NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)) : \
+ ((uint32_t)(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+#define GET_NIA_BMI_AC_DISCARD_FRAME(h_fm_pcd, errata_A006675) \
+ (errata_A006675 ? \
+ ((uint32_t)(NIA_ENG_FM_CTL | \
+ NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME)) : \
+ ((uint32_t)(NIA_ENG_BMI | NIA_BMI_AC_DISCARD)))
+#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME(errata_A006675) \
+ (errata_A006675 ? \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME) :\
+ (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))
+
/* Description CTRL Parameters Page defines */
#define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000
#define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100
@@ -239,6 +306,20 @@ do { \
} \
} while (0)
+#define HW_PORT_ID_TO_SW_PORT_ID(major, _mac_id, port_id) \
+do { \
+ if (port_id >= BASE_TX_PORTID) \
+ _mac_id = (uint8_t)(port_id - BASE_TX_PORTID); \
+ else if (port_id >= BASE_RX_PORTID) \
+ _mac_id = (uint8_t)(port_id - BASE_RX_PORTID); \
+ else if (port_id >= BASE_OH_PORTID(major)) \
+ _mac_id = (uint8_t)(port_id - BASE_OH_PORTID(major)); \
+ else { \
+ _mac_id = (uint8_t)DUMMY_PORT_ID; \
+ ASSERT(true); \
+ } \
+} while (0)
+
#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
#define BMI_FIFO_UNITS 0x100
@@ -337,6 +418,53 @@ enum fm_mac_type {
FM_MAC_1G /* 1G MAC */
};
+/* Description Structure for port-FM communication
+ * during fm_port_init. Fields commented 'IN' are passed
+ * by the port module to be used by the FM module.
+ * Fields commented 'OUT' will be filled by FM before returning to port.
+ * Some fields are optional (depending on configuration) and
+ * will be analized by the port and FM modules accordingly.
+ */
+struct fm_inter_module_port_init_params_t {
+ uint8_t port_id;
+ /* IN. port Id */
+ enum fm_port_type port_type;
+ /* IN. Port type */
+ enum fm_port_speed port_speed;
+ /* IN. Port speed */
+ /* IN. Port's requested resource*/
+ uint16_t liodn_offset;
+ /* IN. Port's requested resource */
+ uint8_t num_of_tasks;
+ /* IN. Port's requested resource */
+ uint8_t num_of_extra_tasks;
+ /* IN. Port's requested resource */
+ uint8_t num_of_open_dmas;
+ /* IN. Port's requested resource */
+ uint8_t num_of_extra_open_dmas;
+ /* IN. Port's requested resource */
+ uint32_t size_of_fifo;
+ /* IN. Port's requested resource */
+ uint32_t extra_size_of_fifo;
+ /* IN. Port's requested resource */
+ uint8_t deq_pipeline_depth;
+ /* IN. Port's max frame length. */
+ uint16_t max_frame_length;
+ /* IN. Irrelevant for P4080 rev 1.
+ * LIODN base for this port, to be
+ * used together with LIODN offset.
+ */
+ uint16_t liodn_base;
+};
+
+/* Description Structure for port-FM communication during fm_port_free.*/
+struct fm_inter_module_port_free_params_t {
+ uint8_t port_id; /* IN. port Id */
+ enum fm_port_type port_type; /* IN. Port type */
+ enum fm_port_speed port_speed; /* IN. Port speed */
+ uint8_t deq_pipeline_depth; /* IN. Port's requested resource */
+};
+
/* Function fm_get_muram_pointer
* Description Get the pointer of the MURAM from the FM module
* Param[in] h_fm A handle to an FM Module.
@@ -379,6 +507,29 @@ uint16_t fm_get_clock_freq(struct fm_t *p_fm);
*/
uint8_t fm_get_id(struct fm_t *p_fm);
+/* Function fm_get_set_port_params
+ * Description Used by FM-PORT driver to pass and receive parameters between
+ * PORT and FM modules.
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in,out] p_port_params A structure of FM Port parameters.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_init().
+ */
+int fm_get_set_port_params(struct fm_t *p_fm,
+ struct fm_inter_module_port_init_params_t
+ *p_port_params);
+
+/* Function fm_free_port_params
+ * Description Used by FM-PORT driver to free port's resources within the FM.
+ * Param[in] h_fm A handle to an FM Module.
+ * Param[in,out] p_port_params A structure of FM Port parameters.
+ * Return None.
+ * Cautions Allowed only following fm_init().
+ */
+void fm_free_port_params(struct fm_t *p_fm,
+ struct fm_inter_module_port_free_params_t
+ *p_port_params);
+
#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
int fm_10g_tx_ecc_workaround(struct fm_t *p_fm, uint8_t mac_id);
#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
@@ -404,5 +555,22 @@ struct num_of_ports_info_t *fm_get_num_of_ports(struct fm_t *p_fm);
int fm_set_mac_max_frame(struct fm_t *p_fm, enum fm_mac_type type,
uint8_t mac_id, uint16_t mtu);
+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);
#endif /* __FM_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.c b/drivers/net/ethernet/freescale/fman/fm_drv.c
index 2c78829..c0a2c70 100644
--- a/drivers/net/ethernet/freescale/fman/fm_drv.c
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
@@ -217,6 +217,72 @@ static void destroy_fm_dev(struct fm_drv_t *p_fm_drv)
kfree(p_fm_drv);
}
+static int fill_rest_fm_info(struct fm_drv_t *p_fm_drv)
+{
+#define FM_BMI_PPIDS_OFFSET 0x00080304
+#define FM_DMA_PLR_OFFSET 0x000c2060
+#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4
+#define DMA_HIGH_LIODN_MASK 0x0FFF0000
+#define DMA_LOW_LIODN_MASK 0x00000FFF
+#define DMA_LIODN_SHIFT 16
+
+/* These need to be moved to FLib: */
+ struct plr_t {
+ uint32_t plr[32];
+ } __attribute__((__packed__));
+
+ struct ppids_t {
+ volatile uint32_t fmbm_ppid[63];
+ } __attribute__((__packed__));
+
+ struct plr_t *p_plr;
+ struct ppids_t *p_ppids;
+ int i;
+ uint32_t fm_rev;
+
+ fm_rev = (uint32_t)(*((volatile uint32_t *)
+ UINT_TO_PTR(p_fm_drv->fm_base_addr +
+ FM_FPM_IP_REV_1_OFFSET)));
+ fm_rev &= 0xffff;
+
+ p_plr =
+ (struct plr_t *)UINT_TO_PTR(p_fm_drv->fm_base_addr +
+ FM_DMA_PLR_OFFSET);
+#ifdef MODULE
+ for (i = 0; i < FM_MAX_NUM_OF_PARTITIONS / 2; i++)
+ p_plr->plr[i] = 0;
+#endif /* MODULE */
+
+ for (i = 0; i < FM_MAX_NUM_OF_PARTITIONS; i++) {
+ uint16_t liodn_base;
+
+ liodn_base = (uint16_t)((i % 2) ?
+ (p_plr->plr[i / 2] & DMA_LOW_LIODN_MASK) :
+ ((p_plr->plr[i / 2] & DMA_HIGH_LIODN_MASK) >>
+ DMA_LIODN_SHIFT));
+#ifdef FM_PARTITION_ARRAY
+ p_fm_drv->params.liodn_base_per_port[i] = liodn_base;
+#endif /* FM_PARTITION_ARRAY */
+
+ if (((i >= FIRST_RX_PORT) && (i <= LAST_RX_PORT)) ||
+ ((i >= FIRST_TX_PORT) && (i <= LAST_TX_PORT)) ||
+ ((i >= FIRST_OP_PORT(
+ p_fm_drv->fm_rev_info.major_rev)) &&
+ (i <= LAST_OP_PORT)))
+ p_fm_drv->ports[i].port_params.liodn_base =
+ liodn_base;
+ }
+
+ p_ppids = (struct ppids_t *)
+ UINT_TO_PTR(p_fm_drv->fm_base_addr + FM_BMI_PPIDS_OFFSET);
+
+ for (i = FIRST_RX_PORT; i <= LAST_RX_PORT; i++)
+ p_fm_drv->ports[i].port_params.specific_params.
+ rx_params.liodn_offset = (u16)(p_ppids->fmbm_ppid[i - 1]);
+
+ return 0;
+}
+
/**
*find_fman_microcode - find the Fman microcode
*
@@ -542,7 +608,7 @@ static int configure_fm_dev(struct fm_drv_t *p_fm_drv)
p_fm_drv->params.f_bus_error = fm_drv_bus_error_cb;
p_fm_drv->params.h_app = p_fm_drv;
- return 0;
+ return fill_rest_fm_info(p_fm_drv);
}
static int init_fm_dev(struct fm_drv_t *p_fm_drv)
@@ -791,6 +857,46 @@ void *fm_get_handle(struct fm *fm)
EXPORT_SYMBOL(fm_get_handle);
+struct fm_port_drv_t *fm_port_bind(struct device *fm_port_dev)
+{
+ return (struct fm_port_drv_t *)
+ (dev_get_drvdata(get_device(fm_port_dev)));
+}
+EXPORT_SYMBOL(fm_port_bind);
+
+void fm_port_unbind(struct fm_port_drv_t *p_port)
+{
+ put_device(p_port->dev);
+}
+EXPORT_SYMBOL(fm_port_unbind);
+
+struct fm_port_t *fm_port_drv_handle(const struct fm_port_drv_t *p_port)
+{
+ return p_port->h_dev;
+}
+EXPORT_SYMBOL(fm_port_drv_handle);
+
+void fm_port_get_base_addr(const struct fm_port_drv_t *p_port,
+ uint64_t *base_addr)
+{
+ *base_addr = p_port->port_params.base_addr;
+}
+EXPORT_SYMBOL(fm_port_get_base_addr);
+
+void fm_port_get_buff_layout_ext_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params)
+{
+ /* TODO - Should this function be removed? */
+ params->data_align = 0;
+}
+EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params);
+
+int fm_get_tx_port_channel(struct fm_port_drv_t *p_port)
+{
+ return p_port->tx_ch;
+}
+EXPORT_SYMBOL(fm_get_tx_port_channel);
+
void fm_mutex_lock(void)
{
mutex_lock(&fm_drv_mutex);
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.h b/drivers/net/ethernet/freescale/fman/fm_drv.h
index 2acd77b..c26836f 100644
--- a/drivers/net/ethernet/freescale/fman/fm_drv.h
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.h
@@ -35,6 +35,7 @@
#include "service.h"
#include "fsl_fman_drv.h"
+#include "fm_port_ext.h"
/* FMan Driver Errata */
#define FM_BCB_ERRATA_BMI_SW001 /* T/B */
@@ -75,6 +76,7 @@ struct fm_port_drv_t {
uint64_t phys_base_addr;
uint64_t base_addr; /* Port's *virtual* address */
resource_size_t mem_size;
+ struct fm_port_params_t port_params;
struct fm_buffer_prefix_content_t buff_prefix_content;
struct fm_port_t *h_dev;
struct fm_drv_t *p_fm;
diff --git a/drivers/net/ethernet/freescale/fman/fm_port_drv.c b/drivers/net/ethernet/freescale/fman/fm_port_drv.c
new file mode 100644
index 0000000..91a7353
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_port_drv.c
@@ -0,0 +1,496 @@
+/*
+ * 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.
+ */
+
+/*File fm_port_drv.c
+ *Description FMan driver - FMan port functions.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "fm_common.h"
+#include "fsl_fman_drv.h"
+#include "fm_port_ext.h"
+#include "fm_drv.h"
+
+static struct fm_port_drv_t
+*read_fm_port_dev_tree_node(struct platform_device *of_dev)
+{
+ struct fm_drv_t *p_fm;
+ struct fm_port_drv_t *p_port;
+ struct device_node *fm_node, *port_node;
+ struct resource res;
+ const uint32_t *uint32_prop;
+ int _errno = 0, lenp;
+ enum fm_port_type port_type;
+ enum fm_port_speed port_speed;
+ u8 cell_index;
+
+ port_node = of_node_get(of_dev->dev.of_node);
+
+ /* Get the FM node */
+ fm_node = of_get_parent(port_node);
+ if (unlikely(!fm_node)) {
+ pr_err("of_get_parent() = %d\n", _errno);
+ return NULL;
+ }
+
+ p_fm = dev_get_drvdata(&of_find_device_by_node(fm_node)->dev);
+ of_node_put(fm_node);
+
+ /* if fm_probe() failed, no point in going further with port probing */
+ if (!p_fm)
+ return NULL;
+
+ uint32_prop =
+ (uint32_t *)of_get_property(port_node, "cell-index", &lenp);
+ if (unlikely(!uint32_prop)) {
+ pr_err("of_get_property(%s, cell-index) failed\n",
+ port_node->full_name);
+ return NULL;
+ }
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ cell_index = (u8)*uint32_prop;
+
+ p_port = &p_fm->ports[cell_index];
+ p_port->id = cell_index;
+ p_port->port_params.port_id = p_port->id;
+
+ if (of_device_is_compatible(port_node, "fsl,fman-v2-port-oh") ||
+ of_device_is_compatible(port_node, "fsl,fman-v3-port-oh")) {
+ port_type = FM_PORT_TYPE_OP;
+ port_speed = FM_PORT_SPEED_OP;
+
+ } else if (of_device_is_compatible(port_node, "fsl,fman-v3-port-tx")) {
+ port_type = FM_PORT_TYPE_TX;
+ port_speed = FM_PORT_SPEED_1G;
+ uint32_prop = (uint32_t *)of_get_property(port_node,
+ "fsl,fman-10g-port",
+ &lenp);
+ if (uint32_prop)
+ port_speed = FM_PORT_SPEED_10G;
+
+ } else if (of_device_is_compatible(port_node, "fsl,fman-v2-port-tx")) {
+ if (cell_index >= TX_10G_PORT_BASE)
+ port_speed = FM_PORT_SPEED_10G;
+ else
+ port_speed = FM_PORT_SPEED_1G;
+ port_type = FM_PORT_TYPE_TX;
+
+ } else if (of_device_is_compatible(port_node, "fsl,fman-v3-port-rx")) {
+ port_type = FM_PORT_TYPE_RX;
+ port_speed = FM_PORT_SPEED_1G;
+ uint32_prop = (uint32_t *)of_get_property(port_node,
+ "fsl,fman-10g-port",
+ &lenp);
+ if (uint32_prop)
+ port_speed = FM_PORT_SPEED_10G;
+
+ } else if (of_device_is_compatible(port_node, "fsl,fman-v2-port-rx")) {
+ if (cell_index >= RX_10G_PORT_BASE)
+ port_speed = FM_PORT_SPEED_10G;
+ else
+ port_speed = FM_PORT_SPEED_1G;
+ port_type = FM_PORT_TYPE_RX;
+
+ } else {
+ pr_err("Illegal port type\n");
+ return NULL;
+ }
+
+ p_port->port_params.port_type = port_type;
+ p_port->port_params.port_speed = port_speed;
+
+ if (port_type == FM_PORT_TYPE_OP || port_type == FM_PORT_TYPE_TX) {
+ uint32_t qman_channel_id;
+
+ qman_channel_id = get_qman_channel_id(p_fm, cell_index,
+ port_type, port_speed);
+
+ if (qman_channel_id == 0) {
+ pr_err("incorrect qman-channel-id\n");
+ return NULL;
+ }
+ p_port->tx_ch = qman_channel_id;
+ p_port->port_params.specific_params.non_rx_params.qm_channel =
+ qman_channel_id;
+ }
+
+ _errno = of_address_to_resource(port_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ pr_err("of_address_to_resource() = %d\n", _errno);
+ return NULL;
+ }
+
+ p_port->dev = &of_dev->dev;
+ p_port->base_addr = 0;
+ p_port->phys_base_addr = res.start;
+ p_port->mem_size = res.end + 1 - res.start;
+ p_port->port_params.h_fm = p_fm->h_dev;
+ p_port->p_fm = (void *)p_fm;
+
+ of_node_put(port_node);
+
+ p_port->active = true;
+
+ return p_port;
+}
+
+static int configure_fm_port_dev(struct fm_port_drv_t *p_port)
+{
+ struct fm_drv_t *p_fm = (struct fm_drv_t *)p_port->p_fm;
+ struct resource *dev_res;
+
+ if (!p_port->active) {
+ pr_err("FM port not configured!!!\n");
+ return -EINVAL;
+ }
+
+ dev_res = __devm_request_region(p_fm->dev, p_fm->res,
+ p_port->phys_base_addr,
+ p_port->mem_size,
+ "fman-port-hc");
+ if (unlikely(!dev_res)) {
+ pr_err("__devm_request_region() failed\n");
+ return -EINVAL;
+ }
+ p_port->base_addr = PTR_TO_UINT(devm_ioremap(p_fm->dev,
+ p_port->phys_base_addr,
+ p_port->mem_size));
+ if (unlikely(p_port->base_addr == 0))
+ pr_err("devm_ioremap() failed\n");
+
+ p_port->port_params.base_addr = p_port->base_addr;
+
+ return 0;
+}
+
+static int init_fm_port_dev(struct fm_port_drv_t *p_port)
+{
+ struct fm_drv_t *p_fm = (struct fm_drv_t *)p_port->p_fm;
+
+ if (!p_port->active || p_port->h_dev)
+ return -EINVAL;
+
+ p_port->h_dev = fm_port_config(&p_port->port_params);
+ if (!p_port->h_dev) {
+ pr_err("FM-port\n");
+ return -EINVAL;
+ }
+
+ if (fm_get_revision(p_fm->h_dev, &p_port->fm_rev_info) != 0) {
+ pr_err("FM-port\n");
+ return -EINVAL;
+ }
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if ((p_port->fm_rev_info.major_rev != 4) &&
+ (p_port->port_params.port_type == FM_PORT_TYPE_TX)) {
+ int err_code = 0;
+
+ err_code = fm_port_cfg_deq_high_priority(p_port->h_dev, true);
+ if (err_code != 0)
+ return -err_code;
+ err_code =
+ fm_port_cfg_deq_prefetch_option(p_port->h_dev,
+ FM_PORT_DEQ_FULL_PREFETCH);
+ if (err_code != 0)
+ return -err_code;
+ }
+#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+#ifdef FM_BCB_ERRATA_BMI_SW001
+/* Configure BCB workaround on Rx ports, only for B4860 rev1 */
+#define SVR_SECURITY_MASK 0x00080000
+#define SVR_PERSONALITY_MASK 0x0000FF00
+#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
+#define SVR_B4860_REV1_VALUE 0x86800010
+
+ if ((p_port->fm_rev_info.major_rev >= 6) &&
+ (p_port->port_params.port_type == FM_PORT_TYPE_RX)) {
+ unsigned int svr;
+
+ svr = mfspr(SPRN_SVR);
+
+ if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE)
+ fm_port_cfg_bcb_wa(p_port->h_dev);
+ }
+#endif /* FM_BCB_ERRATA_BMI_SW001 */
+
+ fm_port_cfg_buf_prefix_content(p_port->h_dev,
+ &p_port->buff_prefix_content);
+
+ if (fm_port_init(p_port->h_dev) != 0)
+ return -EINVAL;
+
+/**
+ * FMan Fifo sizes behind the scene":
+ * Using the following formulae (*), under a set of simplifying assumptions (.):
+ * . all ports are configured in Normal Mode (rather than Independent Mode)
+ * . the DPAA Eth driver allocates buffers of size:
+ * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE
+ * + DPA_HASH_RESULTS_SIZE, i.e.:
+ * MAXFRM + 2 + 16 + sizeof(fm_prs_result_t) + 16, i.e.:
+ * MAXFRM + 66
+ * . excessive buffer pools not accounted for
+ *
+ **for Rx ports on P4080:
+ * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256)*256 + 7*256
+ * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise,
+ * add up to 256 to the above
+ *
+ **for Rx ports on P1023:
+ * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256))*256 + 7*256,
+ * if at least 2 bpools are configured
+ * . IFSZ = 8*256, if only a single bpool is configured
+ *
+ **for Tx ports:
+ * . IFSZ = ceil(frame_size / 256)*256 + 3*256
+ * + FMBM_TFP[DPDE]*256, i.e.:
+ * IFSZ = ceil(MAXFRM / 256)*256 + 3 x 256 + FMBM_TFP[DPDE]*256
+ *
+ **for OH ports on P4080:
+ * . IFSZ = ceil(frame_size / 256)*256 + 1*256 + FMBM_PP[MXT]*256
+ **for OH ports on P1023:
+ * . IFSZ = ceil(frame_size / 256)*256 + 3*256 + FMBM_TFP[DPDE]*256
+ **for both P4080 and P1023:
+ * . (conservative decisions, assuming that BMI must bring the entire
+ * frame, not only the frame header)
+ * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise,
+ * add up to 256 to the above
+ *
+ * . for P4080/P5020/P3041/P2040, DPDE is:
+ * > 0 or 1, for 1Gb ports, HW default: 0
+ * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3
+ * . for P1023, DPDE should be 1
+ *
+ * . for P1023, MXT is in range (0..31)
+ * . for P4080, MXT is in range (0..63)
+ *
+ */
+ return 0;
+}
+
+void fm_set_rx_port_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params)
+{
+ int i;
+
+ p_port->port_params.specific_params.rx_params.err_fqid = params->errq;
+ p_port->port_params.specific_params.rx_params.dflt_fqid = params->defq;
+ p_port->port_params.specific_params.rx_params.
+ ext_buf_pools.num_of_pools_used = params->num_pools;
+ for (i = 0; i < params->num_pools; i++) {
+ p_port->port_params.specific_params.rx_params.ext_buf_pools.
+ ext_buf_pool[i].id = params->pool_param[i].id;
+ p_port->port_params.specific_params.rx_params.ext_buf_pools.
+ ext_buf_pool[i].size = params->pool_param[i].size;
+ }
+
+ p_port->buff_prefix_content.priv_data_size = params->priv_data_size;
+ p_port->buff_prefix_content.pass_prs_result = params->parse_results;
+ p_port->buff_prefix_content.pass_hash_result = params->hash_results;
+ p_port->buff_prefix_content.pass_time_stamp = params->time_stamp;
+ p_port->buff_prefix_content.data_align = params->data_align;
+
+ init_fm_port_dev(p_port);
+}
+EXPORT_SYMBOL(fm_set_rx_port_params);
+
+/* this function is called from oh_probe as well, thus it contains oh port
+ * specific parameters (make sure everything is checked)
+ **/
+void fm_set_tx_port_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params)
+{
+ p_port->port_params.specific_params.non_rx_params.err_fqid =
+ params->errq;
+ p_port->port_params.specific_params.non_rx_params.dflt_fqid =
+ params->defq;
+
+ p_port->buff_prefix_content.priv_data_size = params->priv_data_size;
+ p_port->buff_prefix_content.pass_prs_result = params->parse_results;
+ p_port->buff_prefix_content.pass_hash_result = params->hash_results;
+ p_port->buff_prefix_content.pass_time_stamp = params->time_stamp;
+ p_port->buff_prefix_content.data_align = params->data_align;
+
+ init_fm_port_dev(p_port);
+}
+EXPORT_SYMBOL(fm_set_tx_port_params);
+
+static void free_fm_port_dev(struct fm_port_drv_t *p_port)
+{
+ struct fm_drv_t *p_fm = (struct fm_drv_t *)p_port->p_fm;
+
+ if (!p_port->active)
+ return;
+
+ if (p_port->h_dev)
+ fm_port_free(p_port->h_dev);
+
+ devm_iounmap(p_port->dev, UINT_TO_PTR(p_port->base_addr));
+ __devm_release_region(p_fm->dev, p_fm->res, p_port->phys_base_addr,
+ p_port->mem_size);
+}
+
+static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev)
+{
+ struct fm_port_drv_t *p_port;
+ struct fm_drv_t *p_fm;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+
+ p_port = read_fm_port_dev_tree_node(of_dev);
+ if (!p_port)
+ return -EIO;
+ /* Port can be inactive, thus will not be probed:
+ * - in performance mode, OH ports are disabled ...
+ **/
+ if (!p_port->active)
+ return 0;
+
+ if (configure_fm_port_dev(p_port) != 0)
+ return -EIO;
+
+ dev_set_drvdata(dev, p_port);
+
+ p_fm = (struct fm_drv_t *)p_port->p_fm;
+
+ if (p_port->port_params.port_type == FM_PORT_TYPE_RX) {
+ snprintf(p_port->name, sizeof(p_port->name),
+ "%s-port-rx%d", p_fm->name, p_port->id);
+ } else if (p_port->port_params.port_type == FM_PORT_TYPE_TX) {
+ snprintf(p_port->name, sizeof(p_port->name),
+ "%s-port-tx%d", p_fm->name, p_port->id);
+ } else if (p_port->port_params.port_type == FM_PORT_TYPE_OP) {
+ snprintf(p_port->name, sizeof(p_port->name),
+ "%s-port-oh%d", p_fm->name, p_port->id + 1);
+ }
+#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009
+ if (p_port->fm_rev_info.major_rev < 6 &&
+ p_port->fm_rev_info.major_rev != 4)
+ fm_disable_rams_ecc(p_fm->h_dev);
+#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */
+
+ pr_debug("%s probed\n", p_port->name);
+
+ return 0;
+}
+
+static int fm_port_remove(struct platform_device *of_dev)
+{
+ struct fm_port_drv_t *p_port;
+ struct fm_drv_t *p_fm;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+ p_port = dev_get_drvdata(dev);
+
+ p_fm = (struct fm_drv_t *)p_port->p_fm;
+
+ free_fm_port_dev(p_port);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id fm_port_match[] = {
+ {
+ .compatible = "fsl,fman-v3-port-oh"},
+ {
+ .compatible = "fsl,fman-v2-port-oh"},
+ {
+ .compatible = "fsl,fman-v3-port-rx"},
+ {
+ .compatible = "fsl,fman-v2-port-rx"},
+ {
+ .compatible = "fsl,fman-v3-port-tx"},
+ {
+ .compatible = "fsl,fman-v2-port-tx"},
+ {}
+};
+
+#ifndef MODULE
+MODULE_DEVICE_TABLE(of, fm_port_match);
+#endif /* !MODULE */
+
+static struct platform_driver fm_port_driver = {
+ .driver = {
+ .name = "fsl-fman-port",
+ .of_match_table = fm_port_match,
+ },
+ .probe = fm_port_probe,
+ .remove = fm_port_remove
+};
+
+int fm_port_drv_init(void)
+{
+ /* Register to the DTB for basic FM port API */
+ if (platform_driver_register(&fm_port_driver))
+ return -ENODEV;
+
+ return 0;
+}
+
+void fm_port_drv_free(void)
+{
+ platform_driver_unregister(&fm_port_driver);
+}
+
+static int __init __cold fm_port_load(void)
+{
+ if (fm_port_drv_init() != 0) {
+ pr_crit("Failed to init FM Ports wrapper!\n");
+ return -ENODEV;
+ }
+
+ pr_info("Freescale FM Ports module\n");
+
+ return 0;
+}
+
+static void __exit __cold fm_port_unload(void)
+{
+ fm_port_drv_free();
+}
+
+module_init(fm_port_load);
+module_exit(fm_port_unload);
diff --git a/drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h b/drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h
new file mode 100644
index 0000000..0de6801
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h
@@ -0,0 +1,376 @@
+/*
+ * 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.
+ */
+
+/*File fm_port_ext.h
+ *FM-Port Application Programming Interface.
+ */
+#ifndef __FM_PORT_EXT
+#define __FM_PORT_EXT
+
+#include "service.h"
+#include "fm_ext.h"
+#include "net_ext.h"
+
+/* FMan Port Errata */
+#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 /* T/B */
+
+/* FM Port API
+ * The FM uses a general module called "port" to represent a Tx port (MAC),
+ * an Rx port (MAC) or Offline Parsing port.
+ * The number of ports in an FM varies between SOCs.
+ * The SW driver manages these ports as sub-modules of the FM,i.e. after an
+ * FM is initialized, its ports may be initialized and operated upon.
+ * The port is initialized aware of its type, but other functions on a port
+ * may be indifferent to its type. When necessary, the driver verifies
+ * coherence and returns error if applicable.
+ * On initialization, user specifies the port type and it's index (relative
+ * to the port's type) - always starting at 0.
+ */
+
+/* General FM Port defines */
+/* Number of 4 bytes words in parser result */
+#define FM_PORT_PRS_RESULT_NUM_OF_WORDS 8
+/* @} */
+
+/* FM Frame error */
+/* Frame Descriptor errors */
+/* Not for Rx-Port! Unsupported Format */
+#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT FM_FD_ERR_UNSUPPORTED_FORMAT
+/* Not for Rx-Port! Length Error */
+#define FM_PORT_FRM_ERR_LENGTH FM_FD_ERR_LENGTH
+/* DMA Data error */
+#define FM_PORT_FRM_ERR_DMA FM_FD_ERR_DMA
+/* non Frame-Manager error; probably come from SEC that was chained to FM */
+#define FM_PORT_FRM_ERR_NON_FM FM_FD_RX_STATUS_ERR_NON_FM
+ /* IPR error */
+#define FM_PORT_FRM_ERR_IPRE (FM_FD_ERR_IPR & ~FM_FD_IPR)
+/* IPR non-consistent-sp */
+#define FM_PORT_FRM_ERR_IPR_NCSP (FM_FD_ERR_IPR_NCSP & \
+ ~FM_FD_IPR)
+
+/* Obsolete; will be removed in the future */
+#define FM_PORT_FRM_ERR_IPFE 0
+
+/* 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_PORT_FRM_ERR_PHYSICAL FM_FD_ERR_PHYSICAL
+/* Frame too long OR Frame size exceeds max_length_frame */
+#define FM_PORT_FRM_ERR_SIZE FM_FD_ERR_SIZE
+/* indicates a classifier "drop" operation */
+#define FM_PORT_FRM_ERR_CLS_DISCARD FM_FD_ERR_CLS_DISCARD
+/* Extract Out of Frame */
+#define FM_PORT_FRM_ERR_EXTRACTION FM_FD_ERR_EXTRACTION
+/* No Scheme Selected */
+#define FM_PORT_FRM_ERR_NO_SCHEME FM_FD_ERR_NO_SCHEME
+/* Keysize Overflow */
+#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW FM_FD_ERR_KEYSIZE_OVERFLOW
+/* Frame color is red */
+#define FM_PORT_FRM_ERR_COLOR_RED FM_FD_ERR_COLOR_RED
+/* Frame color is yellow */
+#define FM_PORT_FRM_ERR_COLOR_YELLOW FM_FD_ERR_COLOR_YELLOW
+/* Parser Time out Exceed */
+#define FM_PORT_FRM_ERR_PRS_TIMEOUT FM_FD_ERR_PRS_TIMEOUT
+/* Invalid Soft Parser instruction */
+#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT FM_FD_ERR_PRS_ILL_INSTRUCT
+/* Header error was identified during parsing */
+#define FM_PORT_FRM_ERR_PRS_HDR_ERR FM_FD_ERR_PRS_HDR_ERR
+/* Frame parsed beyind 256 first bytes */
+#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED FM_FD_ERR_BLOCK_LIMIT_EXCEEDED
+/* FPM Frame Processing Timeout Exceeded */
+#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001
+
+/* FM Port Initialization Unit */
+struct fm_port_t;
+
+/* A structure for additional Rx port parameters */
+struct fm_port_rx_params_t {
+ uint32_t err_fqid; /* Error Queue Id. */
+ uint32_t dflt_fqid; /* Default Queue Id. */
+ uint16_t liodn_offset; /* Port's LIODN offset. */
+ /* Which external buffer pools are used
+ * (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
+ */
+ struct fm_ext_pools_t ext_buf_pools;
+};
+
+/* A structure for additional non-Rx port parameters*/
+struct fm_port_non_rx_params_t {
+ /* Error Queue Id. */
+ uint32_t err_fqid;
+ /* For Tx - Default Confirmation queue, 0 means no Tx confirmation
+ * for processed frames. For OP port - default Rx queue.
+ */
+ uint32_t dflt_fqid;
+ /* QM-channel dedicated to this port; will be used
+ * by the FM for dequeue.
+ */
+ uint32_t qm_channel;
+};
+
+/* A union for additional parameters depending on port type*/
+union fm_port_specific_params_u {
+ /* Rx port parameters structure */
+ struct fm_port_rx_params_t rx_params;
+ /* Non-Rx port parameters structure */
+ struct fm_port_non_rx_params_t non_rx_params;
+};
+
+/* A structure representing FM initialization parameters*/
+struct fm_port_params_t {
+ uintptr_t base_addr;
+ /* Virtual Address of memory mapped FM Port registers.*/
+ void *h_fm;
+ /* A handle to the FM object this port related to */
+ enum fm_port_type port_type;
+ /* Port type */
+ enum fm_port_speed port_speed;
+ /* Port speed */
+ uint8_t port_id;
+ /* Port Id - relative to type;
+ * NOTE: When configuring Offline Parsing port for FMANv3 devices,
+ * it is highly recommended NOT to use port_id=0 due to lack of HW
+ * resources on port_id=0.
+ */
+ uint16_t liodn_base;
+ /* Irrelevant for P4080 rev 1. LIODN base for this port, to be
+ * used together with LIODN offset.
+ */
+ union fm_port_specific_params_u specific_params;
+ /* Additional parameters depending on port type. */
+};
+
+struct fm_port;
+
+/* Function fm_port_config
+ * Description Creates a descriptor for the FM PORT module.
+ * The routine returns a handle (descriptor) to the FM PORT object.
+ * This descriptor must be passed as first parameter to all other
+ * FM PORT function calls.
+ * No actual initialization or configuration of FM hardware is
+ * done by this routine.
+ * Param[in] p_fm_port_params - Pointer to data structure of parameters
+ * Retval Pointer to FM Port object, or NULL for Failure.
+ */
+struct fm_port_t *fm_port_config(struct fm_port_params_t *p_fm_port_params);
+
+/* Function fm_port_init
+ * Description Initializes the FM PORT module by defining the
+ * software structure
+ * and configuring the hardware registers.
+ * Param[in] port - A pointer to a FM Port module.
+ * Return 0 on success; Error code otherwise.
+ */
+int fm_port_init(struct fm_port_t *p_fm_port);
+
+/* Function fm_port_free
+ * Description Frees all resources that were assigned to FM PORT module.
+ * Calling this routine invalidates the descriptor.
+ * Param[in] port - A pointer to a FM Port module.
+ * Return 0 on success; Error code otherwise.
+ */
+int fm_port_free(struct fm_port_t *p_fm_port);
+
+/* Configuration functions used to change default values. */
+
+/* enum for defining QM frame dequeue*/
+enum fm_port_deq_type {
+ /* Dequeue from the SP channel - with priority precedence,
+ * and Intra-Class Scheduling respected.
+ */
+ FM_PORT_DEQ_TYPE1,
+ /* Dequeue from the SP channel - with active FQ precedence,
+ * and Intra-Class Scheduling respected.
+ */
+ FM_PORT_DEQ_TYPE2,
+ /* Dequeue from the SP channel - with active FQ precedence,
+ * and override Intra-Class Scheduling
+ */
+ FM_PORT_DEQ_TYPE3
+};
+
+/* enum for defining QM frame dequeue*/
+enum fm_port_deq_prefetch_option {
+ /* QMI preforms a dequeue action for a single frame only
+ * when a dedicated portID Tnum is waiting.
+ */
+ FM_PORT_DEQ_NO_PREFETCH,
+ /* QMI preforms a dequeue action for 3 frames when one
+ * dedicated port_id tnum is waiting.
+ */
+ FM_PORT_DEQ_PARTIAL_PREFETCH,
+ /* QMI preforms a dequeue action for 3 frames when
+ * no dedicated port_id tnums are waiting.
+ */
+ FM_PORT_DEQ_FULL_PREFETCH
+};
+
+/* enum for defining port default color*/
+enum fm_port_color {
+ FM_PORT_COLOR_GREEN, /* Default port color is green */
+ FM_PORT_COLOR_YELLOW, /* Default port color is yellow */
+ FM_PORT_COLOR_RED, /* Default port color is red */
+ FM_PORT_COLOR_OVERRIDE /* Ignore color */
+};
+
+/* A structure for defining FM port resources*/
+struct fm_port_rsrc_t {
+ uint32_t num; /* Committed required resource */
+ uint32_t extra; /* Extra (not committed) required resource */
+};
+
+/* Function fm_port_cfg_deq_high_priority
+ * Description Calling this routine changes the dequeue priority in the
+ * internal driver data base from its default configuration
+ * 1G: [DEFAULT_PORT_deq_high_priority_1G]
+ * 10G: [DEFAULT_PORT_deq_high_priority_10G]
+ * May be used for Non-Rx ports only
+ * Param[in] port - A pointer to a FM Port module.
+ * Param[in] high_pri - true to select high priority, false for
+ * normal operation.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_config() and before
+ * fm_port_init().
+ */
+int fm_port_cfg_deq_high_priority(struct fm_port_t *p_fm_port, bool high_pri);
+
+/* Function fm_port_cfg_deq_prefetch_option
+ * Description Calling this routine changes the dequeue prefetch option
+ * parameter in the
+ * internal driver data base from its default configuration
+ * [DEFAULT_PORT_deq_prefetch_option]
+ * Note: Available for some chips only
+ * May be used for Non-Rx ports only
+ * Param[in] port - A pointer to a FM Port module.
+ * Param[in] deq_prefetch_option - New option
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_config() and before
+ * fm_port_init().
+ */
+int fm_port_cfg_deq_prefetch_option(struct fm_port_t *p_fm_port,
+ enum fm_port_deq_prefetch_option
+ deq_prefetch_option);
+
+/* Function fm_port_cfg_buf_prefix_content
+ * Description Defines the structure, size and content of the application
+ * buffer.
+ * The prefix will
+ * In Tx ports, if 'pass_prs_result', the application
+ * should set a value to their offsets in the prefix of
+ * the FM will save the first 'priv_data_size', than,
+ * depending on 'pass_prs_result' and 'pass_time_stamp',
+ * copy parse result and timeStamp, and the packet itself
+ * (in this order), to the application buffer, and to offset.
+ * Calling this routine changes the buffer margins definitions
+ * in the internal driver data base from its default
+ * configuration:
+ * Data size: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE]
+ * Pass Parser result: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_
+ * PASS_PRS_RESULT].
+ * Pass timestamp: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_
+ * TIME_STAMP].
+ * May be used for all ports
+ * Param[in] port - A pointer to a FM Port module.
+ * Param[in,out] p_fm_buffer_prefix_content -
+ * A structure of parameters describing the
+ * structure of the buffer.
+ * Out parameter:
+ * Start margin - offset of data from start of external
+ * buffer.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_config() and before
+ * fm_port_init().
+ */
+int fm_port_cfg_buf_prefix_content(struct fm_port_t *p_fm_port,
+ struct fm_buffer_prefix_content_t
+ *p_fm_buffer_prefix_content);
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+/* Function fm_port_cfg_bcb_wa
+ * Description Configures BCB errata workaround.
+ * When BCB errata is applicable, the workaround is always
+ * performed by FM Controller. Thus, this functions doesn't
+ * actually enable errata workaround but rather allows driver
+ * to perform adjustments required due to errata workaround
+ * execution in FM controller.
+ * Applying BCB workaround also configures FM_PORT_FRM_ERR_PHYSICAL
+ * errors to be discarded. Thus FM_PORT_FRM_ERR_PHYSICAL can't be
+ * set by FM_PORT_SetErrorsRoute() function.
+ * Param[in] port - A pointer to a FM Port module.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_config() and before
+ * fm_port_init().
+ */
+int fm_port_cfg_bcb_wa(struct fm_port_t *p_fm_port);
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+/* FM Port Runtime control unit API functions, definitions and enums. */
+
+/* Function fm_port_get_buffer_time_stamp
+ * Description Returns the time stamp in the data buffer.
+ * Relevant for Rx ports for getting the buffer time stamp.
+ * See fm_port_cfg_buf_prefix_content for data buffer prefix
+ * configuration.
+ * Param[in] port - A pointer to a FM Port module.
+ * Param[in] p_data - A pointer to the data buffer.
+ * Return A pointer to the hash result on success, NULL otherwise.
+ * Cautions Allowed only following fm_port_init().
+ */
+u64 *fm_port_get_buffer_time_stamp(const struct fm_port_t *p_fm_port,
+ char *p_data);
+
+/* Function fm_port_disable
+ * Description Gracefully disable an FM port. The port will not start new
+ * tasks after all
+ * tasks associated with the port are terminated.
+ * Param[in] port - A pointer to a FM Port module.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_init().
+ * This is a blocking routine, it returns after port is
+ * gracefully stopped, i.e. the port will not except new frames,
+ * but it will finish all frames or tasks which were already began
+ */
+int fm_port_disable(struct fm_port_t *p_fm_port);
+
+int fm_port_suspend(struct fm_port_t *p_fm_port);
+/* Function fm_port_enable
+ * Description A runtime routine provided to allow disable/enable of port.
+ * Param[in] port - A pointer to a FM Port module.
+ * Return 0 on success; Error code otherwise.
+ * Cautions Allowed only following fm_port_init().
+ */
+int fm_port_enable(struct fm_port_t *p_fm_port);
+
+int fm_port_resume(struct fm_port_t *p_fm_port);
+
+#endif /* __FM_PORT_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
index cfbf462..b0b47b8 100644
--- a/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
+++ b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
@@ -37,10 +37,44 @@
#include <linux/types.h>
#include <linux/device.h> /* struct device */
+#include "fm_ext.h"
/* FM device opaque structure used for type checking */
struct fm;
+/* A structure .., */
+struct fm_port_t;
+
+/* A structure of information about each of the external
+ * buffer pools used by the port,
+ */
+struct fm_port_pool_param {
+ uint8_t id; /* External buffer pool id */
+ uint16_t size; /* External buffer pool buffer size*/
+};
+
+/* structure for additional port parameters */
+struct fm_port_params {
+ uint32_t errq; /* Error Queue Id. */
+ uint32_t defq; /* For Tx and HC - Default Confirmation queue,
+ * 0 means no Tx conf for processed frames.
+ * For Rx and OP - default Rx queue.
+ */
+ uint8_t num_pools; /* Number of pools use by this port */
+ struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /* Parameters for each pool */
+ uint16_t priv_data_size; /* Area that user may save for his own
+ * need (E.g. save the SKB)
+ */
+ bool parse_results; /* Put the parser-results in the Rx/Tx buffer */
+ bool hash_results; /* Put the hash-results in the Rx/Tx buffer */
+ bool time_stamp; /* Put the time-stamp in the Rx/Tx buffer */
+ uint16_t data_align; /* value for selecting a data alignment
+ * (must be a power of 2);
+ * if write optimization is used, must be >= 16.
+ */
+};
+
/* fm_bind
* Bind to a specific FM device.
*
@@ -60,6 +94,73 @@ void fm_unbind(struct fm *fm);
void *fm_get_handle(struct fm *fm);
struct resource *fm_get_mem_region(struct fm *fm);
+/* fm_port_bind
+ * Bind to a specific FM-port device (may be Rx or Tx port).
+ * fm_port_dev - the OF handle of the FM port device.
+ * Return A handle of the FM port device.
+ * Allowed only after the port was created.
+ */
+struct fm_port_drv_t *fm_port_bind(struct device *fm_port_dev);
+
+/* fm_port_unbind
+ * Un-bind from a specific FM-port device (may be Rx or Tx port).
+ * port - A handle of the FM port device.
+ * Allowed only after the port was created.
+ */
+void fm_port_unbind(struct fm_port_drv_t *p_port);
+
+/* fm_set_rx_port_params
+ * Configure parameters for a specific Rx FM-port device.
+ * port - A handle of the FM port device.
+ * params - Rx port parameters
+ * Allowed only after the port is binded.
+ */
+void fm_set_rx_port_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params);
+
+/* fm_port_get_buff_layout_ext_params
+ * Get data_align from the device tree chosen node if applied.
+ * This function will only update these two parameters.
+ * When this port has no such parameters in the device tree
+ * values will be set to 0.
+ * port - A handle of the FM port device.
+ * params - PCD port parameters
+ * Allowed only after the port is binded.
+ */
+void fm_port_get_buff_layout_ext_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params);
+
+/* fm_get_tx_port_channel
+ * Get qman-channel number for this Tx port.
+ * port - A handle of the FM port device.
+ * Return qman-channel number for this Tx port.
+ * Allowed only after the port is binded.
+ */
+int fm_get_tx_port_channel(struct fm_port_drv_t *p_port);
+
+/* fm_set_tx_port_params
+ * Configure parameters for a specific Tx FM-port device
+ * port - A handle of the FM port device.
+ * params - Tx port parameters
+ * Allowed only after the port is binded.
+ */
+void fm_set_tx_port_params(struct fm_port_drv_t *p_port,
+ struct fm_port_params *params);
+
+struct fm_port_t *fm_port_drv_handle(const struct fm_port_drv_t *p_port);
+
+/* fm_port_get_base_address
+ *
+ * Get base address of this port. Useful for accessing
+ * port-specific registers (i.e., not common ones).
+ *
+ * port - A handle of the FM port device.
+ *
+ * base_addr - The port's base addr (virtual address).
+ */
+void fm_port_get_base_addr(const struct fm_port_drv_t *p_port,
+ uint64_t *base_addr);
+
/* fm_mutex_lock
*
* Lock function required before any FMD/LLD call.
diff --git a/drivers/net/ethernet/freescale/fman/port/Makefile b/drivers/net/ethernet/freescale/fman/port/Makefile
index 54b1fa4..55825e3 100644
--- a/drivers/net/ethernet/freescale/fman/port/Makefile
+++ b/drivers/net/ethernet/freescale/fman/port/Makefile
@@ -1,3 +1,3 @@
obj-y += fsl_fman_port.o
-fsl_fman_port-objs := fman_port.o
+fsl_fman_port-objs := fman_port.o fm_port.o
diff --git a/drivers/net/ethernet/freescale/fman/port/fm_port.c b/drivers/net/ethernet/freescale/fman/port/fm_port.c
new file mode 100644
index 0000000..6ac4e55
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fm_port.c
@@ -0,0 +1,1435 @@
+/*
+ * 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.
+ */
+
+/* File fm_port.c
+ * Description FM driver routines implementation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "service.h"
+#include "fm_muram_ext.h"
+
+#include "fman_common.h"
+#include "fm_port.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/* static functions */
+
+static int check_init_parameters(struct fm_port_t *p_fm_port)
+{
+ struct fm_port_drv_param_t *p_params = p_fm_port->p_fm_port_drv_param;
+ struct fman_port_cfg *p_dflt_config = &p_params->dflt_cfg;
+ uint32_t unused_mask;
+
+ /* Rx only */
+ if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ /* external buffer pools */
+ if (!p_params->ext_buf_pools.num_of_pools_used) {
+ pr_err("ext_buf_pools.num_of_pools_used=0. At least one buffer pool must be defined\n");
+ return -EDOM;
+ }
+
+ if (fm_sp_check_buf_pools_params(&p_params->ext_buf_pools,
+ p_params->p_backup_bm_pools,
+ &p_params->buf_pool_depletion,
+ p_fm_port->port_intg->max_num_of_ext_pools,
+ p_fm_port->port_intg->bm_max_num_of_pools) != 0)
+ return -EDOM;
+ /* Check that part of IC that needs copying is small enough
+ * to enter start margin
+ */
+ if (p_params->int_context.size &&
+ (p_params->int_context.size +
+ p_params->int_context.ext_buf_offset >
+ p_params->buf_margins.start_margins)) {
+ pr_err("int_context.size is larger than start margins\n");
+ return -EDOM;
+ }
+
+ if ((p_params->liodn_offset != LIODN_DONT_OVERRIDE) &&
+ (p_params->liodn_offset & ~FM_LIODN_OFFSET_MASK)) {
+ pr_err("liodn_offset is larger than %d\n",
+ FM_LIODN_OFFSET_MASK + 1);
+ }
+#ifdef FM_NO_BACKUP_POOLS
+ if ((p_fm_port->fm_rev_info.major_rev != 4) &&
+ (p_fm_port->fm_rev_info.major_rev < 6))
+ if (p_fm_port->p_fm_port_drv_param->
+ p_backup_bm_pools) {
+ pr_err("BackupBmPools\n");
+ return -EINVAL;
+ }
+#endif /* FM_NO_BACKUP_POOLS */
+ }
+
+ /* Non Rx ports */
+ else {
+ if (p_params->deq_sub_portal >=
+ p_fm_port->port_intg->fm_max_num_of_sub_portals) {
+ pr_err("deq_sub_portal has to be in the range of 0 - %d\n",
+ p_fm_port->port_intg->fm_max_num_of_sub_portals);
+ return -EDOM;
+ }
+
+ /* to protect HW internal-context from overwrite */
+ if ((p_params->int_context.size) &&
+ (p_params->int_context.int_context_offset <
+ MIN_TX_INT_OFFSET)) {
+ pr_err("non-Rx int_context.int_context_offset can't be smaller than %d\n",
+ MIN_TX_INT_OFFSET);
+ return -EDOM;
+ }
+
+ if ((p_fm_port->port_type == FM_PORT_TYPE_TX) ||
+ /* in O/H DEFAULT_NOT_SUPPORTED indicates that
+ * it is not supported and should not be checked
+ */
+ (p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth != DEFAULT_NOT_SUPPORTED)) {
+ /* Check that not larger than 8 */
+ if ((!p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth) ||
+ (p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth >
+ MAX_FIFO_PIPELINE_DEPTH)) {
+ pr_err("fifoDeqPipelineDepth can't be larger than %d\n",
+ MAX_FIFO_PIPELINE_DEPTH);
+ return -EDOM;
+ }
+ }
+ }
+
+ /* Rx Or Offline Parsing */
+ if ((p_fm_port->port_type == FM_PORT_TYPE_RX) ||
+ (p_fm_port->port_type == FM_PORT_TYPE_OP)) {
+ if (!p_params->dflt_fqid) {
+ pr_err("dflt_fqid must be between 1 and 2^24-1\n");
+ return -EDOM;
+ }
+ }
+
+ /* All ports */
+ /* common BMI registers values */
+ /* Check that Queue Id is not larger than 2^24, and is not 0 */
+ if ((p_params->err_fqid & ~0x00FFFFFF) || !p_params->err_fqid) {
+ pr_err("err_fqid must be between 1 and 2^24-1\n");
+ return -EDOM;
+ }
+ if (p_params->dflt_fqid & ~0x00FFFFFF) {
+ pr_err("dflt_fqid must be between 1 and 2^24-1\n");
+ return -EDOM;
+ }
+
+ /* Rx only */
+ if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (p_dflt_config->rx_pri_elevation % BMI_FIFO_UNITS) {
+ pr_err("rx_fifo_pri_elevation_level has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+ if ((p_dflt_config->rx_pri_elevation < BMI_FIFO_UNITS) ||
+ (p_dflt_config->rx_pri_elevation >
+ p_fm_port->port_intg->max_port_fifo_size)) {
+ pr_err("rx_fifo_pri_elevation_level not in range of 256 - %d\n",
+ p_fm_port->port_intg->max_port_fifo_size);
+ return -EDOM;
+ }
+ if (p_dflt_config->rx_fifo_thr % BMI_FIFO_UNITS) {
+ pr_err("rx_fifo_threshold must be div by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+ if ((p_dflt_config->rx_fifo_thr < BMI_FIFO_UNITS) ||
+ (p_dflt_config->rx_fifo_thr >
+ p_fm_port->port_intg->max_port_fifo_size)) {
+ pr_err("rx_fifo_threshold has to be in the range of 256 - %d\n",
+ p_fm_port->port_intg->max_port_fifo_size);
+ return -EDOM;
+ }
+
+ /* Check that not larger than 16 */
+ if (p_dflt_config->rx_cut_end_bytes > FRAME_END_DATA_SIZE) {
+ pr_err("cut_bytes_from_end can't be larger than %d\n",
+ FRAME_END_DATA_SIZE);
+ return -EDOM;
+ }
+
+ if (fm_sp_check_buf_margins(&p_params->buf_margins) != 0)
+ return -EDOM;
+
+ /* extra FIFO size (allowed only to Rx ports) */
+ if (p_params->set_size_of_fifo &&
+ (p_fm_port->fifo_bufs.extra % BMI_FIFO_UNITS)) {
+ pr_err("fifo_bufs.extra has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+
+ if (p_params->buf_pool_depletion.pools_grp_mode_enable &&
+ !p_params->buf_pool_depletion.num_of_pools) {
+ pr_err("buf_pool_depletion.num_of_pools can not be 0 when pools_grp_mode_enable=true\n");
+ return -EDOM;
+ }
+#ifdef FM_CSI_CFED_LIMIT
+ if (p_fm_port->fm_rev_info.major_rev == 4) {
+ /* Check that not larger than 16 */
+ if (p_dflt_config->rx_cut_end_bytes +
+ p_dflt_config->checksum_bytes_ignore >
+ FRAME_END_DATA_SIZE) {
+ pr_err("cheksum_last_bytes_ignore + cut_bytes_from_end can't be larger than %d\n",
+ FRAME_END_DATA_SIZE);
+ return -EDOM;
+ }
+ }
+#endif /* FM_CSI_CFED_LIMIT */
+ }
+
+ /* Non Rx ports */
+ /* extra FIFO size (allowed only to Rx ports) */
+ else if (p_fm_port->fifo_bufs.extra) {
+ pr_err(" No fifo_bufs.extra for non Rx ports\n");
+ return -EDOM;
+ }
+
+ /* Tx only */
+ if (p_fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (p_dflt_config->tx_fifo_min_level % BMI_FIFO_UNITS) {
+ pr_err("tx_fifo_min_fill_level has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+ if (p_dflt_config->tx_fifo_min_level >
+ (p_fm_port->port_intg->max_port_fifo_size - 256)) {
+ pr_err("tx_fifo_min_fill_level has to be in the range of 0 - %d\n",
+ (p_fm_port->port_intg->max_port_fifo_size -
+ 256));
+ return -EDOM;
+ }
+ if (p_dflt_config->tx_fifo_low_comf_level % BMI_FIFO_UNITS) {
+ pr_err("tx_fifo_low_comf_level has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+ if ((p_dflt_config->tx_fifo_low_comf_level < BMI_FIFO_UNITS) ||
+ (p_dflt_config->tx_fifo_low_comf_level >
+ p_fm_port->port_intg->max_port_fifo_size)) {
+ pr_err("tx_fifo_low_comf_level has to be in the range of 256 - %d\n",
+ p_fm_port->port_intg->max_port_fifo_size);
+ return -EDOM;
+ }
+ if (p_fm_port->port_speed == FM_PORT_SPEED_1G)
+ if (p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth > 2) {
+ pr_err("fifoDeqPipelineDepth for 1G can't be larger than 2\n");
+ return -EDOM;
+ }
+ }
+
+ /* Non Tx Ports */
+ /* If discard override was selected , no frames may be discarded. */
+ else if (p_dflt_config->discard_override && p_params->
+ errors_to_discard) {
+ pr_err("errors_to_discard is not empty, but frm_discard_override selected (all discarded frames to be enqueued to error queue).\n");
+ return -EINVAL;
+ }
+
+ /* Rx and Offline parsing */
+ if ((p_fm_port->port_type == FM_PORT_TYPE_RX) ||
+ (p_fm_port->port_type == FM_PORT_TYPE_OP)) {
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP)
+ unused_mask = BMI_STATUS_OP_MASK_UNUSED;
+ else
+ unused_mask = BMI_STATUS_RX_MASK_UNUSED;
+
+ /* Check that no common bits with BMI_STATUS_MASK_UNUSED */
+ if (p_params->errors_to_discard & unused_mask) {
+ pr_err("errors_to_discard contains undefined bits\n");
+ return -EINVAL;
+ }
+ }
+
+ /* Offline Ports */
+#ifdef FM_OP_OPEN_DMA_MIN_LIMIT
+ if ((p_fm_port->fm_rev_info.major_rev >= 6) &&
+ (p_fm_port->port_type == FM_PORT_TYPE_OP) &&
+ p_params->set_num_of_open_dmas &&
+ (p_fm_port->open_dmas.num < MIN_NUM_OF_OP_DMAS)) {
+ pr_err("For Offline port, open_dmas.num can't be smaller than %d\n",
+ MIN_NUM_OF_OP_DMAS);
+ return -EDOM;
+ }
+#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */
+
+ /* Offline Ports */
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+#ifndef FM_FRAME_END_PARAMS_FOR_OP
+ if ((p_fm_port->fm_rev_info.major_rev < 6) &&
+ (p_fm_port->p_fm_port_drv_param->
+ cheksum_last_bytes_ignore !=
+ DEFAULT_NOT_SUPPORTED)) {
+ /* this is an indication that user called config
+ * for this mode which is not supported in this
+ * integration
+ */
+ pr_err("cheksum_last_bytes_ignore is available for Rx&Tx ports only\n");
+ return -EDOM;
+ }
+#endif /* !FM_FRAME_END_PARAMS_FOR_OP */
+
+#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
+ if ((!((p_fm_port->fm_rev_info.major_rev == 4) ||
+ (p_fm_port->fm_rev_info.major_rev >= 6))) &&
+ (p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth != DEFAULT_NOT_SUPPORTED)) {
+ /* this is an indication that user called config for
+ * this mode which is not supported in this integration
+ **/
+ pr_err("fifoDeqPipelineDepth is available for Tx ports only\n");
+ return -EINVAL;
+ }
+#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
+ }
+
+ /* All ports */
+
+ /* Check that not larger than 16 */
+ if ((p_params->cheksum_last_bytes_ignore > FRAME_END_DATA_SIZE) &&
+ ((p_params->cheksum_last_bytes_ignore != DEFAULT_NOT_SUPPORTED))) {
+ pr_err("cheksum_last_bytes_ignore can't be larger than %d\n",
+ FRAME_END_DATA_SIZE);
+ return -EDOM;
+ }
+
+ if (fm_sp_check_int_context_params(&p_params->int_context) != 0)
+ return -EDOM;
+
+ /* common BMI registers values */
+ if (p_params->set_num_of_tasks &&
+ ((!p_fm_port->tasks.num) ||
+ (p_fm_port->tasks.num > MAX_NUM_OF_TASKS))) {
+ pr_err("tasks.num can't be larger than %d\n",
+ MAX_NUM_OF_TASKS);
+ return -EDOM;
+ }
+ if (p_params->set_num_of_tasks &&
+ (p_fm_port->tasks.extra > MAX_NUM_OF_EXTRA_TASKS)) {
+ pr_err("tasks.extra can't be larger than %d\n",
+ MAX_NUM_OF_EXTRA_TASKS);
+ return -EDOM;
+ }
+ if (p_params->set_num_of_open_dmas &&
+ ((!p_fm_port->open_dmas.num) ||
+ (p_fm_port->open_dmas.num > MAX_NUM_OF_DMAS))) {
+ pr_err("open_dmas.num can't be larger than %d\n",
+ MAX_NUM_OF_DMAS);
+ return -EDOM;
+ }
+ if (p_params->set_num_of_open_dmas &&
+ (p_fm_port->open_dmas.extra > MAX_NUM_OF_EXTRA_DMAS)) {
+ pr_err("open_dmas.extra can't be larger than %d\n",
+ MAX_NUM_OF_EXTRA_DMAS);
+ return -EDOM;
+ }
+ if (p_params->set_size_of_fifo &&
+ (!p_fm_port->fifo_bufs.num || (p_fm_port->fifo_bufs.num >
+ p_fm_port->port_intg->max_port_fifo_size))) {
+ pr_err("fifo_bufs.num has to be in the range of 256 - %d\n",
+ p_fm_port->port_intg->max_port_fifo_size);
+ return -EDOM;
+ }
+ if (p_params->set_size_of_fifo &&
+ (p_fm_port->fifo_bufs.num % BMI_FIFO_UNITS)) {
+ pr_err("fifo_bufs.num has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EDOM;
+ }
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_fm_port->fm_rev_info.major_rev == 4)
+ if (p_fm_port->p_fm_port_drv_param->deq_prefetch_option !=
+ DEFAULT_NOT_SUPPORTED) {
+ /* this is an indication that user called config
+ * for this mode which is not supported in this
+ * integration
+ **/
+ pr_err("deq_prefetch_option\n");
+ return -EINVAL;
+ }
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ return 0;
+}
+
+/* Checks if p_fm_port driver parameters were initialized
+ * returns 0 if success else returns error code
+ */
+static int is_init_done(struct fm_port_drv_param_t *p_fm_port_drv_parameters)
+{
+ if (!p_fm_port_drv_parameters)
+ return 0;
+ return -EINVAL;
+}
+
+static int verify_size_of_fifo(struct fm_port_t *p_fm_port)
+{
+ uint32_t min_fifo_size_required = 0, opt_fifo_size_for_b2b = 0;
+
+ /* TX PORTS */
+ if (p_fm_port->port_type == FM_PORT_TYPE_TX) {
+ min_fifo_size_required = (uint32_t)
+ (ROUND_UP(p_fm_port->max_frame_length,
+ BMI_FIFO_UNITS) + (3 * BMI_FIFO_UNITS));
+
+ min_fifo_size_required +=
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.tx_fifo_deq_pipeline_depth * BMI_FIFO_UNITS;
+
+ opt_fifo_size_for_b2b = min_fifo_size_required;
+
+ /* Add some margin for back-to-back capability to improve
+ * performance, allows the hardware to pipeline new frame dma
+ * while the previous frame not yet transmitted.
+ */
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ opt_fifo_size_for_b2b += 3 * BMI_FIFO_UNITS;
+ else
+ opt_fifo_size_for_b2b += 2 * BMI_FIFO_UNITS;
+ }
+
+ /* RX PORTS */
+ else if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (p_fm_port->fm_rev_info.major_rev == 4) {
+ if (p_fm_port->rx_pools_params.num_of_pools == 1)
+ min_fifo_size_required = 8 * BMI_FIFO_UNITS;
+ else
+ min_fifo_size_required = (uint32_t)
+ (ROUND_UP
+ (p_fm_port->
+ rx_pools_params.second_largest_buf_size,
+ BMI_FIFO_UNITS) + (7 * BMI_FIFO_UNITS));
+ } else {
+ if (p_fm_port->fm_rev_info.major_rev >= 6)
+ min_fifo_size_required = (uint32_t)
+ (ROUND_UP(p_fm_port->max_frame_length,
+ BMI_FIFO_UNITS) + (5 * BMI_FIFO_UNITS));
+ /* 4 according to spec + 1 for FOF>0 */
+ else
+ min_fifo_size_required = (uint32_t)
+ (ROUND_UP(min(p_fm_port->max_frame_length,
+ p_fm_port->rx_pools_params.
+ largest_buf_size),
+ BMI_FIFO_UNITS) + (7 * BMI_FIFO_UNITS));
+ }
+
+ opt_fifo_size_for_b2b = min_fifo_size_required;
+
+ /* Add some margin for back-to-back capability to improve
+ * performance,allows the hardware to pipeline new frame dma
+ * while the previous frame not yet transmitted.
+ */
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ opt_fifo_size_for_b2b += 8 * BMI_FIFO_UNITS;
+ else
+ opt_fifo_size_for_b2b += 3 * BMI_FIFO_UNITS;
+ }
+
+ /* For O/H ports, check fifo size and update if necessary */
+ else if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+ if (p_fm_port->fm_rev_info.major_rev >= 6) {
+ opt_fifo_size_for_b2b = (uint32_t)(ROUND_UP(
+ p_fm_port->max_frame_length,
+ BMI_FIFO_UNITS) +
+ ((p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth + 5) *
+ BMI_FIFO_UNITS));
+ min_fifo_size_required = opt_fifo_size_for_b2b;
+ /* 4 according to spec + 1 for FOF>0 */
+ } else {
+ opt_fifo_size_for_b2b =
+ (uint32_t)((p_fm_port->tasks.num + 2) * BMI_FIFO_UNITS);
+ min_fifo_size_required = opt_fifo_size_for_b2b;
+ }
+ }
+
+ ASSERT(min_fifo_size_required > 0);
+ ASSERT(opt_fifo_size_for_b2b >= min_fifo_size_required);
+
+ /* Verify the size */
+ if (p_fm_port->fifo_bufs.num < min_fifo_size_required)
+ pr_debug("FIFO size should be enlarged to %d bytes\n",
+ min_fifo_size_required);
+ else if (p_fm_port->fifo_bufs.num < opt_fifo_size_for_b2b)
+ pr_debug("For b2b processing,FIFO may be enlarged to %d bytes\n",
+ opt_fifo_size_for_b2b);
+
+ return 0;
+}
+
+static void fm_port_drv_param_free(struct fm_port_t *p_fm_port)
+{
+ kfree(p_fm_port->p_fm_port_drv_param);
+ p_fm_port->p_fm_port_drv_param = NULL;
+}
+
+static int set_ext_buffer_pools(struct fm_port_t *p_fm_port)
+{
+ struct fm_ext_pools_t *p_ext_buf_pools =
+ &p_fm_port->p_fm_port_drv_param->ext_buf_pools;
+ struct fm_buf_pool_depletion_t *p_buf_pool_depletion =
+ &p_fm_port->p_fm_port_drv_param->buf_pool_depletion;
+ uint8_t ordered_array[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ uint16_t sizes_array[BM_MAX_NUM_OF_POOLS];
+ int i = 0, j = 0, err;
+ struct fman_port_bpools bpools;
+
+ memset(&ordered_array, 0,
+ sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
+ memset(&sizes_array, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS);
+ memcpy(&p_fm_port->ext_buf_pools, p_ext_buf_pools,
+ sizeof(struct fm_ext_pools_t));
+
+ fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(p_ext_buf_pools,
+ ordered_array,
+ sizes_array);
+
+ /* Prepare flibs bpools structure */
+ memset(&bpools, 0, sizeof(struct fman_port_bpools));
+ bpools.count = p_ext_buf_pools->num_of_pools_used;
+ bpools.counters_enable = true;
+ for (i = 0; i < p_ext_buf_pools->num_of_pools_used; i++) {
+ bpools.bpool[i].bpid = ordered_array[i];
+ bpools.bpool[i].size = sizes_array[ordered_array[i]];
+ /* functionality available only for some derivatives
+ * (limited by config)
+ */
+ if (p_fm_port->p_fm_port_drv_param->p_backup_bm_pools)
+ for (j = 0; j < p_fm_port->p_fm_port_drv_param->
+ p_backup_bm_pools->num_of_backup_pools; j++)
+ if (ordered_array[i] ==
+ p_fm_port->p_fm_port_drv_param->
+ p_backup_bm_pools->pool_ids[j]) {
+ bpools.bpool[i].is_backup = true;
+ break;
+ }
+ }
+
+ /* save pools parameters for later use */
+ p_fm_port->rx_pools_params.num_of_pools =
+ p_ext_buf_pools->num_of_pools_used;
+ p_fm_port->rx_pools_params.largest_buf_size =
+ sizes_array[ordered_array[p_ext_buf_pools->
+ num_of_pools_used - 1]];
+ p_fm_port->rx_pools_params.second_largest_buf_size =
+ sizes_array[ordered_array[p_ext_buf_pools->
+ num_of_pools_used - 2]];
+
+ /* FMBM_RMPD reg. - pool depletion */
+ if (p_buf_pool_depletion->pools_grp_mode_enable) {
+ bpools.grp_bp_depleted_num = p_buf_pool_depletion->
+num_of_pools;
+ for (i = 0; i < p_fm_port->port_intg->bm_max_num_of_pools;
+ i++) {
+ if (p_buf_pool_depletion->pools_to_consider[i]) {
+ for (j = 0; j < p_ext_buf_pools->
+ num_of_pools_used; j++) {
+ if (i == ordered_array[j]) {
+ bpools.bpool[j].
+ grp_bp_depleted = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (p_buf_pool_depletion->single_pool_mode_enable) {
+ for (i = 0; i < p_fm_port->port_intg->bm_max_num_of_pools;
+ i++) {
+ if (p_buf_pool_depletion->
+ pools_to_consider_for_single_mode[i]) {
+ for (j = 0; j < p_ext_buf_pools->
+ num_of_pools_used; j++) {
+ if (i == ordered_array[j]) {
+ bpools.bpool[j].
+ single_bp_depleted = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Issue flibs function */
+ err = fman_port_set_bpools(&p_fm_port->port, &bpools);
+ if (err != 0) {
+ pr_err("fman_port_set_bpools\n");
+ return -EDOM;
+ }
+
+ kfree(p_fm_port->p_fm_port_drv_param->p_backup_bm_pools);
+
+ return 0;
+}
+
+static int init_low_level_driver(struct fm_port_t *p_fm_port)
+{
+ struct fm_port_drv_param_t *p_drv_params = p_fm_port->
+ p_fm_port_drv_param;
+ struct fman_port_params port_params;
+ uint32_t tmp_val;
+
+ /* Set up flibs parameters and issue init function */
+
+ memset(&port_params, 0, sizeof(struct fman_port_params));
+ port_params.discard_mask = p_drv_params->errors_to_discard;
+ port_params.dflt_fqid = p_drv_params->dflt_fqid;
+ port_params.err_fqid = p_drv_params->err_fqid;
+ port_params.deq_sp = p_drv_params->deq_sub_portal;
+ port_params.dont_release_buf = p_drv_params->dont_release_buf;
+ switch (p_fm_port->port_type) {
+ case (FM_PORT_TYPE_RX):
+ port_params.err_mask =
+ (RX_ERRS_TO_ENQ & ~port_params.discard_mask);
+ if (p_drv_params->forward_reuse_int_context)
+ p_drv_params->dflt_cfg.rx_fd_bits =
+ (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24);
+ break;
+
+ case (FM_PORT_TYPE_OP):
+ port_params.err_mask =
+ (OP_ERRS_TO_ENQ & ~port_params.discard_mask);
+ break;
+ break;
+
+ default:
+ break;
+ }
+
+ tmp_val = (uint32_t)((p_fm_port->internal_buf_offset %
+ OFFSET_UNITS) ? (p_fm_port->
+ internal_buf_offset / OFFSET_UNITS +
+ 1) : (p_fm_port->internal_buf_offset /
+ OFFSET_UNITS));
+ p_fm_port->internal_buf_offset = (uint8_t)(tmp_val * OFFSET_UNITS);
+ p_drv_params->dflt_cfg.int_buf_start_margin =
+ p_fm_port->internal_buf_offset;
+
+ p_drv_params->dflt_cfg.ext_buf_start_margin =
+ p_drv_params->buf_margins.start_margins;
+ p_drv_params->dflt_cfg.ext_buf_end_margin =
+ p_drv_params->buf_margins.end_margins;
+
+ p_drv_params->dflt_cfg.ic_ext_offset =
+ p_drv_params->int_context.ext_buf_offset;
+ p_drv_params->dflt_cfg.ic_int_offset =
+ p_drv_params->int_context.int_context_offset;
+ p_drv_params->dflt_cfg.ic_size = p_drv_params->int_context.size;
+
+ if (0 !=
+ fman_port_init(&p_fm_port->port, &p_drv_params->dflt_cfg,
+ &port_params)) {
+ pr_err("fman_port_init\n");
+ return -ENODEV;
+ }
+
+ /* The code bellow is a trick so the FM will not release the buffer
+ * to BM nor will try to enqueue the frame to QM
+ */
+ if (p_fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (!p_drv_params->dflt_fqid && p_drv_params->
+ dont_release_buf) {
+ /* override fmbm_tcfqid 0 with a false non-0 value.
+ * This will force FM to act according to tfene.
+ * Otherwise, if fmbm_tcfqid is 0 the FM will release
+ * buffers to BM regardless of fmbm_tfene
+ */
+ WRITE_UINT32(p_fm_port->port.bmi_regs->tx.fmbm_tcfqid,
+ 0xFFFFFF);
+ WRITE_UINT32(p_fm_port->port.bmi_regs->tx.fmbm_tfene,
+ NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE);
+ }
+ }
+
+ return 0;
+}
+
+static struct fm_port_intg_t *set_port_intg_params(struct fm_port_t *p_fm_port)
+{
+ struct fm_port_intg_t *intg;
+ uint32_t bmi_max_fifo_size;
+
+ intg = kzalloc(sizeof(*intg), GFP_KERNEL);
+ if (!intg)
+ return NULL;
+
+ bmi_max_fifo_size = fm_get_bmi_max_fifo_size(p_fm_port->h_fm);
+
+ intg->max_port_fifo_size =
+ MAX_PORT_FIFO_SIZE(bmi_max_fifo_size);
+
+ switch (p_fm_port->fm_rev_info.major_rev) {
+ case FM_IP_BLOCK_P2_P3_P5:
+ case FM_IP_BLOCK_P4:
+ intg->max_num_of_ext_pools = 4;
+ intg->fm_max_num_of_sub_portals = 12;
+ intg->bm_max_num_of_pools = 64;
+ break;
+
+ case FM_IP_BLOCK_P1:
+ intg->max_num_of_ext_pools = 4;
+ intg->fm_max_num_of_sub_portals = 7;
+ intg->bm_max_num_of_pools = 8;
+ break;
+
+ case FM_IP_BLOCK_B_T:
+ intg->max_num_of_ext_pools = 8;
+ intg->fm_max_num_of_sub_portals = 16;
+ intg->bm_max_num_of_pools = 64;
+ break;
+
+ default:
+ pr_err("Unsupported FMan version\n");
+ kfree(intg);
+ return NULL;
+ }
+
+ return intg;
+}
+
+/* API Init unit functions */
+
+struct fm_port_t *fm_port_config(struct fm_port_params_t *p_fm_port_params)
+{
+ struct fm_port_t *p_fm_port;
+ uintptr_t base_addr = p_fm_port_params->base_addr;
+#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
+ uint32_t tmp_reg;
+#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */
+ enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY;
+
+ /* Allocate FM structure */
+ p_fm_port = kzalloc(sizeof(*p_fm_port), GFP_KERNEL);
+ if (!p_fm_port)
+ return NULL;
+
+ /* Allocate the FM driver's parameters structure */
+ p_fm_port->p_fm_port_drv_param =
+ kzalloc(sizeof(*p_fm_port->p_fm_port_drv_param),
+ GFP_KERNEL);
+ if (!p_fm_port->p_fm_port_drv_param) {
+ kfree(p_fm_port);
+ pr_err("FM Port driver parameters\n");
+ return NULL;
+ }
+
+ /* Initialize FM port parameters which will be kept by the driver */
+ p_fm_port->port_type = p_fm_port_params->port_type;
+ p_fm_port->port_speed = p_fm_port_params->port_speed;
+ p_fm_port->port_id = p_fm_port_params->port_id;
+ p_fm_port->h_fm = p_fm_port_params->h_fm;
+
+ /* get FM revision */
+ fm_get_revision(p_fm_port->h_fm, &p_fm_port->fm_rev_info);
+
+ p_fm_port->port_intg = set_port_intg_params(p_fm_port);
+ if (!p_fm_port->port_intg) {
+ kfree(p_fm_port->p_fm_port_drv_param);
+ kfree(p_fm_port);
+ return NULL;
+ }
+
+ if (p_fm_port->fm_rev_info.major_rev >= 6) {
+ if ((p_fm_port->port_type == FM_PORT_TYPE_OP) &&
+ (p_fm_port_params->port_id == FM_OH_PORT_ID))
+ pr_debug("Use nonzero portid for OP port\n");
+ }
+
+ /* Set up FM port parameters for initialization phase only */
+
+ /* First, fill in flibs struct */
+ /* In order to be aligned with flib port types, we need to translate
+ * the port type and speed to fman_port_type
+ */
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+ fman_port_type = E_FMAN_PORT_TYPE_OP;
+ } else if (p_fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ fman_port_type = E_FMAN_PORT_TYPE_TX_10G;
+ else
+ fman_port_type = E_FMAN_PORT_TYPE_TX;
+ } else if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ fman_port_type = E_FMAN_PORT_TYPE_RX_10G;
+ else
+ fman_port_type = E_FMAN_PORT_TYPE_RX;
+ }
+ fman_port_defconfig(&p_fm_port->p_fm_port_drv_param->dflt_cfg,
+ fman_port_type);
+ /* Overwrite some integration specific parameters */
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.rx_pri_elevation =
+ DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(
+ p_fm_port->port_intg->max_port_fifo_size);
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.rx_fifo_thr =
+ p_fm_port->p_fm_port_drv_param->rx_fifo_threshold =
+ DFLT_PORT_RX_FIFO_THRESHOLD(
+ p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_intg->max_port_fifo_size);
+
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006675 = false;
+
+#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || \
+defined(FM_ERROR_VSP_NO_MATCH_SW006)
+ if (p_fm_port->fm_rev_info.major_rev >= 6)
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006675 =
+ true;
+#endif
+ if ((p_fm_port->fm_rev_info.major_rev == 6) &&
+ ((p_fm_port->fm_rev_info.minor_rev == 0) ||
+ (p_fm_port->fm_rev_info.minor_rev == 3)))
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006320 =
+ true;
+ else
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.errata_A006320 =
+ false;
+
+ /* Excessive Threshold register - exists for pre-FMv3 chips only */
+ if (p_fm_port->fm_rev_info.major_rev < 6) {
+#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ excessive_threshold_register = true;
+#endif /* FM_NO_RESTRICT_ON_ACCESS_RSRC */
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd =
+ false;
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.fmbm_tfne_has_features =
+ false;
+ } else {
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ excessive_threshold_register = false;
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd =
+ true;
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.fmbm_tfne_has_features = true;
+ }
+ if (p_fm_port->fm_rev_info.major_rev == 4)
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.qmi_deq_options_support = false;
+ else
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.qmi_deq_options_support = true;
+
+ /* Continue with other parameters */
+ p_fm_port->p_fm_port_drv_param->base_addr = base_addr;
+ /* set memory map pointers */
+ p_fm_port->p_fm_port_qmi_regs =
+ (struct fm_port_qmi_regs_t __iomem *)UINT_TO_PTR(base_addr +
+ QMI_PORT_REGS_OFFSET);
+ p_fm_port->p_fm_port_bmi_regs =
+ (union fm_port_bmi_regs_u __iomem *)UINT_TO_PTR(base_addr +
+ BMI_PORT_REGS_OFFSET);
+
+ p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content.priv_data_size =
+ DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE;
+ p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content.pass_prs_result =
+ DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT;
+ p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content.pass_time_stamp =
+ DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP;
+ p_fm_port->p_fm_port_drv_param->buffer_prefix_content.data_align =
+ DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN;
+ p_fm_port->p_fm_port_drv_param->liodn_base =
+ p_fm_port_params->liodn_base;
+ p_fm_port->p_fm_port_drv_param->cheksum_last_bytes_ignore =
+ DEFAULT_PORT_CHECKSUM_LAST_BYTES_IGNORE;
+
+ p_fm_port->max_frame_length = DEFAULT_PORT_MAX_FRAME_LENGTH;
+ /* resource distribution. */
+
+ p_fm_port->fifo_bufs.num =
+ DFLT_PORT_NUM_OF_FIFO_BUFS(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed) * BMI_FIFO_UNITS;
+ p_fm_port->fifo_bufs.extra =
+ DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS * BMI_FIFO_UNITS;
+
+ p_fm_port->open_dmas.num =
+ DFLT_PORT_NUM_OF_OPEN_DMAS(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed);
+ p_fm_port->open_dmas.extra =
+ DFLT_PORT_EXTRA_NUM_OF_OPEN_DMAS(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed);
+ p_fm_port->tasks.num =
+ DFLT_PORT_NUM_OF_TASKS(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed);
+ p_fm_port->tasks.extra =
+ DFLT_PORT_EXTRA_NUM_OF_TASKS(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed);
+
+#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+ if ((p_fm_port->fm_rev_info.major_rev == 6) &&
+ (p_fm_port->fm_rev_info.minor_rev == 0) &&
+ ((p_fm_port->port_type == FM_PORT_TYPE_OP) ||
+ ((p_fm_port->port_type == FM_PORT_TYPE_TX) &&
+ (p_fm_port->port_speed == FM_PORT_SPEED_1G)))) {
+ p_fm_port->open_dmas.num = 16;
+ p_fm_port->open_dmas.extra = 0;
+ }
+#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
+
+ /* Port type specific initialization: */
+ switch (p_fm_port->port_type) {
+ case (FM_PORT_TYPE_RX):
+ /* Initialize FM port parameters for initialization phase only*/
+ p_fm_port->p_fm_port_drv_param->cut_bytes_from_end =
+ DEFAULT_PORT_CUT_BYTES_FROM_END;
+ p_fm_port->p_fm_port_drv_param->en_buf_pool_depletion = false;
+ p_fm_port->p_fm_port_drv_param->frm_discard_override =
+ DEFAULT_PORT_FRM_DISCARD_OVERRIDE;
+
+ p_fm_port->p_fm_port_drv_param->rx_fifo_pri_elevation_level =
+ DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(p_fm_port->port_intg->
+ max_port_fifo_size);
+ p_fm_port->p_fm_port_drv_param->rx_fifo_threshold =
+ DFLT_PORT_RX_FIFO_THRESHOLD(p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_intg->
+ max_port_fifo_size);
+
+ p_fm_port->p_fm_port_drv_param->buf_margins.end_margins =
+ DEFAULT_PORT_BUF_MARGINS_END_MAARGINS;
+ p_fm_port->p_fm_port_drv_param->errors_to_discard =
+ DEFAULT_PORT_ERRORS_TO_DISCARD;
+ p_fm_port->p_fm_port_drv_param->forward_reuse_int_context =
+ DEFAULT_PORT_FORWARD_INT_CONTENT_REUSE;
+ break;
+
+ case (FM_PORT_TYPE_TX):
+ if (p_fm_port->port_speed == FM_PORT_SPEED_1G) {
+ p_fm_port->p_fm_port_drv_param->dont_release_buf =
+ false;
+#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
+ if (p_fm_port->fm_rev_info.major_rev >= 6) {
+ tmp_reg = 0x00001013;
+ WRITE_UINT32(p_fm_port->p_fm_port_bmi_regs->
+ tx_port_bmi_regs.fmbm_tfp,
+ tmp_reg);
+ }
+#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */
+ }
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G) {
+ p_fm_port->p_fm_port_drv_param->tx_fifo_min_fill_level
+ = DFLT_PORT_TX_FIFO_MIN_FILL_LEVEL;
+ p_fm_port->p_fm_port_drv_param->tx_fifo_low_comf_level
+ = DFLT_PORT_TX_FIFO_LOW_COMF_LEVEL;
+
+ p_fm_port->p_fm_port_drv_param->deq_type =
+ DEFAULT_PORT_DEQ_TYPE;
+ p_fm_port->p_fm_port_drv_param->deq_prefetch_option =
+ DEFAULT_PORT_DEQ_PREFETCH_OPT;
+ }
+ p_fm_port->p_fm_port_drv_param->deq_high_priority =
+ DFLT_PORT_DEQ_HIGH_PRIORITY(p_fm_port->port_speed);
+ p_fm_port->p_fm_port_drv_param->deq_byte_cnt =
+ DFLT_PORT_DEQ_BYTE_CNT(p_fm_port->port_speed);
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth = (uint8_t)
+ DFLT_PORT_FIFO_DEQ_PIPELINE_DEPTH(
+ p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed);
+ break;
+ case (FM_PORT_TYPE_OP):
+ p_fm_port->p_fm_port_drv_param->errors_to_discard =
+ DEFAULT_PORT_ERRORS_TO_DISCARD;
+ break;
+
+ default:
+ kfree(p_fm_port->p_fm_port_drv_param);
+ kfree(p_fm_port);
+ pr_err("Invalid port type\n");
+ return NULL;
+ }
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_fm_port->fm_rev_info.major_rev == 4)
+ p_fm_port->p_fm_port_drv_param->deq_prefetch_option =
+ (enum fm_port_deq_prefetch_option)DEFAULT_NOT_SUPPORTED;
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ switch (p_fm_port->port_type) {
+ case (FM_PORT_TYPE_RX):
+ /* Initialize FM port parameters for initialization phase only*/
+ memcpy(&p_fm_port->p_fm_port_drv_param->ext_buf_pools,
+ &p_fm_port_params->
+ specific_params.rx_params.ext_buf_pools,
+ sizeof(struct fm_ext_pools_t));
+ p_fm_port->p_fm_port_drv_param->err_fqid
+ = p_fm_port_params->specific_params.rx_params.err_fqid;
+ p_fm_port->p_fm_port_drv_param->dflt_fqid
+ = p_fm_port_params->specific_params.rx_params.dflt_fqid;
+ p_fm_port->p_fm_port_drv_param->liodn_offset
+ = p_fm_port_params->specific_params.rx_params.liodn_offset;
+ break;
+ case (FM_PORT_TYPE_OP):
+ case (FM_PORT_TYPE_TX):
+ p_fm_port->p_fm_port_drv_param->err_fqid =
+ p_fm_port_params->specific_params.non_rx_params.err_fqid;
+ p_fm_port->p_fm_port_drv_param->deq_sub_portal =
+ (uint8_t)(p_fm_port_params->specific_params.non_rx_params.
+ qm_channel & QMI_DEQ_CFG_SUBPORTAL_MASK);
+ p_fm_port->p_fm_port_drv_param->dflt_fqid =
+ p_fm_port_params->specific_params.non_rx_params.dflt_fqid;
+ break;
+ default:
+ kfree(p_fm_port->p_fm_port_drv_param);
+ kfree(p_fm_port);
+ pr_err("Invalid port type\n");
+ return NULL;
+ }
+
+ memset(p_fm_port->name, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (snprintf(p_fm_port->name, MODULE_NAME_SIZE, "FM-%d-port-%s-%d",
+ fm_get_id(p_fm_port->h_fm),
+ ((p_fm_port->port_type == FM_PORT_TYPE_OP) ? "OP" :
+ ((p_fm_port->port_type == FM_PORT_TYPE_TX) ?
+ ((p_fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-TX" :
+ "1g-TX") :
+ ((p_fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-RX" :
+ "1g-RX"))),
+ p_fm_port->port_id) == 0) {
+ kfree(p_fm_port->p_fm_port_drv_param);
+ kfree(p_fm_port);
+ pr_err("sprintf failed\n");
+ return NULL;
+ }
+
+ p_fm_port->spinlock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+ if (!p_fm_port->spinlock) {
+ kfree(p_fm_port->p_fm_port_drv_param);
+ kfree(p_fm_port);
+ pr_err("Spin lock init failed\n");
+ return NULL;
+ }
+
+ spin_lock_init(p_fm_port->spinlock);
+
+ return p_fm_port;
+}
+
+int fm_port_init(struct fm_port_t *p_fm_port)
+{
+ struct fm_port_drv_param_t *p_drv_params;
+ int err_code;
+ struct fm_inter_module_port_init_params_t fm_params;
+ struct fm_revision_info_t rev_info;
+ int ret, ret_err;
+ enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ err_code =
+ fm_sp_build_buffer_structure(&p_fm_port->p_fm_port_drv_param->
+ int_context,
+ &p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content,
+ &p_fm_port->p_fm_port_drv_param->
+ buf_margins,
+ &p_fm_port->buffer_offsets,
+ &p_fm_port->internal_buf_offset);
+ if (err_code != 0)
+ return -err_code;
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+ if (p_fm_port->fm_rev_info.major_rev >= 6 &&
+ (p_fm_port->p_fm_port_drv_param->bcb_workaround) &&
+ ((p_fm_port->port_type == FM_PORT_TYPE_RX) &&
+ (p_fm_port->port_speed == FM_PORT_SPEED_1G))) {
+ p_fm_port->p_fm_port_drv_param->errors_to_discard |=
+ FM_PORT_FRM_ERR_PHYSICAL;
+ if (!p_fm_port->fifo_bufs.num)
+ p_fm_port->fifo_bufs.num =
+ DFLT_PORT_NUM_OF_FIFO_BUFS(
+ p_fm_port->fm_rev_info.major_rev,
+ p_fm_port->port_type,
+ p_fm_port->port_speed) *
+ BMI_FIFO_UNITS;
+ p_fm_port->fifo_bufs.num += 4 * 1024;
+ }
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+ ret_err = check_init_parameters(p_fm_port);
+ if (ret_err)
+ return ret_err;
+
+ p_drv_params = p_fm_port->p_fm_port_drv_param;
+
+ /* Set up flibs port structure */
+ memset(&p_fm_port->port, 0, sizeof(struct fman_port));
+ /* In order to be aligned with flib port types, we need to translate
+ * the port type and speed to fman_port_type
+ */
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+ fman_port_type = E_FMAN_PORT_TYPE_OP;
+ } else if (p_fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ fman_port_type = E_FMAN_PORT_TYPE_TX_10G;
+ else
+ fman_port_type = E_FMAN_PORT_TYPE_TX;
+ } else if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (p_fm_port->port_speed == FM_PORT_SPEED_10G)
+ fman_port_type = E_FMAN_PORT_TYPE_RX_10G;
+ else
+ fman_port_type = E_FMAN_PORT_TYPE_RX;
+ }
+ p_fm_port->port.type = fman_port_type;
+ fm_get_revision(p_fm_port->h_fm, &rev_info);
+ p_fm_port->port.fm_rev_maj = rev_info.major_rev;
+ p_fm_port->port.fm_rev_min = rev_info.minor_rev;
+ p_fm_port->port.bmi_regs = (union fman_port_bmi_regs __iomem *)
+ UINT_TO_PTR(p_drv_params->base_addr + BMI_PORT_REGS_OFFSET);
+ p_fm_port->port.qmi_regs = (struct fman_port_qmi_regs __iomem *)
+ UINT_TO_PTR(p_drv_params->base_addr + QMI_PORT_REGS_OFFSET);
+ p_fm_port->port.ext_pools_num =
+ (uint8_t)((rev_info.major_rev == 4) ? 4 : 8);
+
+ if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ /* Call the external Buffer routine which also checks fifo
+ * size and updates it if necessary
+ */
+ /* define external buffer pools and pool depletion */
+ err_code = set_ext_buffer_pools(p_fm_port);
+ if (err_code)
+ return -err_code;
+ /* check if the largest external buffer pool is large enough */
+ if (p_drv_params->buf_margins.start_margins +
+ MIN_EXT_BUF_SIZE +
+ p_drv_params->buf_margins.end_margins >
+ p_fm_port->rx_pools_params.largest_buf_size) {
+ pr_err("buf_margins.start_margins (%d) + minimum buf size (64) + buf_margins.end_margins (%d) is larger than maximum external buffer size (%d)\n",
+ p_drv_params->buf_margins.start_margins,
+ p_drv_params->buf_margins.end_margins,
+ p_fm_port->rx_pools_params.largest_buf_size);
+ return -EINVAL;
+ }
+ }
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+ {
+#ifdef FM_NO_OP_OBSERVED_POOLS
+ struct fm_revision_info_t rev_info;
+
+ fm_get_revision(p_fm_port->h_fm, &rev_info);
+ if ((rev_info.major_rev == 4) &&
+ (p_drv_params->en_buf_pool_depletion))
+#endif /* FM_NO_OP_OBSERVED_POOLS */
+ {
+ /* define external buffer pools */
+ err_code = set_ext_buffer_pools(p_fm_port);
+ if (err_code)
+ return -err_code;
+ }
+ }
+ }
+
+ /* Call FM module routine for communicating parameters */
+
+ memset(&fm_params, 0, sizeof(fm_params));
+ fm_params.port_id = p_fm_port->port_id;
+ fm_params.port_type = (enum fm_port_type)p_fm_port->port_type;
+ fm_params.port_speed = (enum fm_port_speed)p_fm_port->port_speed;
+ fm_params.num_of_tasks = (uint8_t)p_fm_port->tasks.num;
+ fm_params.num_of_extra_tasks = (uint8_t)p_fm_port->tasks.extra;
+ fm_params.num_of_open_dmas = (uint8_t)p_fm_port->open_dmas.num;
+ fm_params.num_of_extra_open_dmas = (uint8_t)p_fm_port->open_dmas.extra;
+
+ if (p_fm_port->fifo_bufs.num) {
+ err_code = verify_size_of_fifo(p_fm_port);
+ if (err_code != 0)
+ return -err_code;
+ }
+ fm_params.size_of_fifo = p_fm_port->fifo_bufs.num;
+ fm_params.extra_size_of_fifo = p_fm_port->fifo_bufs.extra;
+ fm_params.liodn_offset = p_drv_params->liodn_offset;
+ fm_params.liodn_base = p_drv_params->liodn_base;
+ fm_params.deq_pipeline_depth =
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.tx_fifo_deq_pipeline_depth;
+ fm_params.max_frame_length = p_fm_port->max_frame_length;
+#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
+ if (p_fm_port->port_type == FM_PORT_TYPE_OP) {
+ if (!((p_fm_port->fm_rev_info.major_rev == 4) ||
+ (p_fm_port->fm_rev_info.major_rev >= 6)))
+ /* OP ports do not have fifoDeqPipelineDepth,
+ * but it is needed only
+ *for deq threshold calculation.
+ */
+ fm_params.deq_pipeline_depth = 2;
+ }
+#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
+
+ err_code = fm_get_set_port_params(p_fm_port->h_fm, &fm_params);
+ if (err_code)
+ return -err_code;
+
+ err_code = init_low_level_driver(p_fm_port);
+ if (err_code != 0)
+ return -err_code;
+
+ fm_port_drv_param_free(p_fm_port);
+
+ return 0;
+}
+
+int fm_port_free(struct fm_port_t *p_fm_port)
+{
+ struct fm_inter_module_port_free_params_t fm_params;
+
+ if (p_fm_port->enabled) {
+ if (fm_port_disable(p_fm_port) != 0) {
+ pr_err("fm_port_disable FAILED\n");
+ return -EINVAL;
+ }
+ }
+
+ fm_port_drv_param_free(p_fm_port);
+
+ fm_params.port_id = p_fm_port->port_id;
+ fm_params.port_type = (enum fm_port_type)p_fm_port->port_type;
+ fm_params.deq_pipeline_depth =
+ p_fm_port->p_fm_port_drv_param->
+ dflt_cfg.tx_fifo_deq_pipeline_depth;
+
+ fm_free_port_params(p_fm_port->h_fm, &fm_params);
+
+ kfree(p_fm_port->spinlock);
+
+ kfree(p_fm_port);
+
+ return 0;
+}
+
+/* API Advanced Init unit functions */
+
+int fm_port_cfg_deq_high_priority(struct fm_port_t *p_fm_port, bool high_pri)
+{
+ int ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ pr_err("not available for Rx ports\n");
+ return -ENOMEM;
+ }
+
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.deq_high_pri = high_pri;
+
+ return 0;
+}
+
+int fm_port_cfg_deq_prefetch_option(struct fm_port_t *p_fm_port,
+ enum fm_port_deq_prefetch_option
+ deq_prefetch_option)
+{
+ int ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ if (p_fm_port->port_type == FM_PORT_TYPE_RX) {
+ pr_err("not available for Rx ports\n");
+ return -ENODEV;
+ }
+ p_fm_port->p_fm_port_drv_param->dflt_cfg.deq_prefetch_opt =
+ (enum fman_port_deq_prefetch)deq_prefetch_option;
+
+ return 0;
+}
+
+int fm_port_cfg_buf_prefix_content(struct fm_port_t *p_fm_port,
+ struct fm_buffer_prefix_content_t *
+ p_fm_buffer_prefix_content)
+{
+ int ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ memcpy(&p_fm_port->p_fm_port_drv_param->buffer_prefix_content,
+ p_fm_buffer_prefix_content,
+ sizeof(struct fm_buffer_prefix_content_t));
+ /* if data_align was not initialized by user,
+ * we return to driver's default
+ **/
+ if (!p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content.data_align)
+ p_fm_port->p_fm_port_drv_param->
+ buffer_prefix_content.data_align =
+ DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN;
+
+ return 0;
+}
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+int fm_port_cfg_bcb_wa(struct fm_port_t *p_fm_port)
+{
+ int ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (!ret)
+ return -EINVAL;
+
+ p_fm_port->p_fm_port_drv_param->bcb_workaround = true;
+
+ return 0;
+}
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+/* API Run-time Control unit functions */
+
+u64 *fm_port_get_buffer_time_stamp(const struct fm_port_t *p_fm_port,
+ char *p_data)
+{
+ int ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (ret)
+ return NULL;
+
+ if (p_fm_port->buffer_offsets.time_stamp_offset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint64_t *)PTR_MOVE(p_data,
+ p_fm_port->
+ buffer_offsets.time_stamp_offset);
+}
+EXPORT_SYMBOL(fm_port_get_buffer_time_stamp);
+
+int fm_port_disable(struct fm_port_t *p_fm_port)
+{
+ int err, ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (ret)
+ return ret;
+
+ err = fman_port_disable(&p_fm_port->port);
+ if (err == -EBUSY) {
+ pr_debug("%s: BMI or QMI is Busy. Port forced down\n",
+ p_fm_port->name);
+ err = 0;
+ }
+
+ p_fm_port->enabled = false;
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_disable);
+
+int fm_port_suspend(struct fm_port_t *p_fm_port)
+{
+ int err, ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (ret)
+ return ret;
+
+ err = fman_port_disable(&p_fm_port->port);
+ if (err == -EBUSY) {
+ pr_debug("%s: BMI or QMI is Busy. Port forced down\n",
+ p_fm_port->name);
+ err = 0;
+ }
+
+ p_fm_port->enabled = false;
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_suspend);
+
+int fm_port_enable(struct fm_port_t *p_fm_port)
+{
+ int err, ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (ret)
+ return ret;
+
+ /* Used by fm_port_free routine as indication
+ * if to disable port. Thus set it to true prior
+ * to enabling itself. This way if part of enable
+ * process fails there will be still things
+ * to disable during Free. For example, if BMI
+ * enable succeeded but QMI failed, still BMI
+ * needs to be disabled by Free.
+ */
+ p_fm_port->enabled = true;
+
+ err = fman_port_enable(&p_fm_port->port);
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_enable);
+
+int fm_port_resume(struct fm_port_t *p_fm_port)
+{
+ int err, ret;
+
+ ret = is_init_done(p_fm_port->p_fm_port_drv_param);
+ if (ret)
+ return ret;
+
+ /* Used by fm_port_free routine as indication
+ * if to disable port. Thus set it to true prior
+ * to enabling itself. This way if part of enable
+ * process fails there will be still things
+ * to disable during Free. For example, if BMI
+ * enable succeeded but QMI failed, still BMI
+ * needs to be disabled by Free.
+ */
+ p_fm_port->enabled = true;
+
+ err = fman_port_enable(&p_fm_port->port);
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_resume);
diff --git a/drivers/net/ethernet/freescale/fman/port/fm_port.h b/drivers/net/ethernet/freescale/fman/port/fm_port.h
new file mode 100644
index 0000000..449fce6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fm_port.h
@@ -0,0 +1,527 @@
+/*
+ * 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 Port internal structures and definitions. */
+#ifndef __FM_PORT_H
+#define __FM_PORT_H
+
+#include "service.h"
+
+#include "fm_common.h"
+#include "fm_sp_common.h"
+#include "fsl_fman_sp.h"
+#include "fm_port_ext.h"
+#include "fsl_fman_port.h"
+
+#define LIODN_DONT_OVERRIDE (-1)
+
+#define MIN_EXT_BUF_SIZE 64
+
+#define MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) \
+ min((u32)bmi_max_fifo_size, (u32)1024 * BMI_FIFO_UNITS)
+
+/* Memory Map defines */
+#define BMI_PORT_REGS_OFFSET 0
+#define QMI_PORT_REGS_OFFSET 0x400
+
+/* defaults */
+#define DFLT_PORT_DEQ_HIGH_PRIORITY(speed) \
+ ((speed == FM_PORT_SPEED_10G) ? true : false)
+#define DEFAULT_PORT_DEQ_TYPE FM_PORT_DEQ_TYPE1
+#define DEFAULT_PORT_DEQ_PREFETCH_OPT \
+ FM_PORT_DEQ_FULL_PREFETCH
+#define DFLT_PORT_DEQ_BYTE_CNT(speed) \
+ ((speed == FM_PORT_SPEED_10G) ? 0x1400 : 0x400)
+#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE
+#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_PASS_PRS_RESULT
+#define DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_PASS_TIME_STAMP
+#define DEFAULT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN
+#define DEFAULT_PORT_CHECKSUM_LAST_BYTES_IGNORE 0
+#define DEFAULT_PORT_CUT_BYTES_FROM_END 4
+
+#define DEFAULT_PORT_FRM_DISCARD_OVERRIDE false
+
+#define DEFAULT_PORT_FORWARD_INT_CONTENT_REUSE false
+#define DEFAULT_PORT_BUF_MARGINS_END_MAARGINS 0
+#define DEFAULT_PORT_ERRORS_TO_DISCARD \
+ FM_PORT_FRM_ERR_CLS_DISCARD
+#define DEFAULT_PORT_MAX_FRAME_LENGTH 9600
+
+#define DEFAULT_NOT_SUPPORTED 0xff
+
+#define DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(bmi_max_fifo_size) \
+ MAX_PORT_FIFO_SIZE(bmi_max_fifo_size)
+
+#define DFLT_PORT_RX_FIFO_THRESHOLD(major, bmi_max_fifo_size) \
+ (major == 6 ? \
+ MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) : \
+ (MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) * 3 / 4)) \
+
+#define DFLT_PORT_TX_FIFO_MIN_FILL_LEVEL 0
+#define DFLT_PORT_TX_FIFO_LOW_COMF_LEVEL (5 * 1024)
+
+/* OP - 2, 10G - 4, 1G (FMAN V3 - 2, FMAN V2 - 1) */
+#define DFLT_PORT_FIFO_DEQ_PIPELINE_DEPTH(major, type, speed) \
+ ((type == FM_PORT_TYPE_OP) ? 2 : \
+ ((speed == FM_PORT_SPEED_10G) ? 4 : \
+ ((major >= 6) ? 2 : 1)))
+
+#define DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS 0
+
+/* FMAN V3: OP - 6, 10G (RX/TX 16), 1G (RX/TX) 4
+ * FMAN V2: OP - 3, 10G (TX/TX 16), 1G (RX/TX) 3
+ */
+#define DFLT_PORT_NUM_OF_TASKS(major, type, speed) \
+ ((major >= 6) ? \
+ ((type == FM_PORT_TYPE_OP) ? 6 : \
+ ((speed == FM_PORT_SPEED_10G) ? 16 : 4)) : \
+ ((speed == FM_PORT_SPEED_10G) ? 16 : 3))
+
+/* FMAN V3: 0 for all ports
+ * FMAN V2: RX 10G - 8, RX 1G 2, TX/OP - 0
+ */
+#define DFLT_PORT_EXTRA_NUM_OF_TASKS(major, type, speed) \
+ ((major >= 6) ? 0 : \
+ ((type == FM_PORT_TYPE_RX) ? \
+ ((speed == FM_PORT_SPEED_10G) ? 8 : 2) : 0))
+
+/* FMAN V3: 10G RX - 8, 1G RX - 2, 10G TX - 12, 1G TX 3, OP - 6
+ * FMAN V2: 10G RX/TX - 8, 1G(TX/RX)/OP - 1
+ */
+#define DFLT_PORT_NUM_OF_OPEN_DMAS(major, type, speed) \
+ ((major >= 6) ? \
+ ((type == FM_PORT_TYPE_RX) ? \
+ ((speed == FM_PORT_SPEED_10G) ? 8 : 2) : \
+ ((type == FM_PORT_TYPE_TX) ? \
+ ((speed == FM_PORT_SPEED_10G) ? 12 : 3) : 4)) : \
+ ((speed == FM_PORT_SPEED_10G) ? 8 : 1))
+
+/* FMAN V3: 0 for all ports
+ * FMAN V2: RX 10G - 8, 1G RX/TX & OP - 1
+ */
+#define DFLT_PORT_EXTRA_NUM_OF_OPEN_DMAS(major, type, speed) \
+ ((major >= 6) ? 0 : \
+ ((speed == FM_PORT_SPEED_10G) ? 8 : 1))
+
+/* FMAN V3: 10G RX - 96, 10G TX 64, 1G/OP 50
+ * FMAN V2: 10G - 48, 1G RX 45, 1G TX 44, OP = 8
+ */
+#define DFLT_PORT_NUM_OF_FIFO_BUFS(major, type, speed) \
+ (major >= 6 ? \
+ (((speed == FM_PORT_SPEED_10G) ? \
+ ((type == FM_PORT_TYPE_RX) ? (96) : (64)) : (50))) : \
+ ((speed == FM_PORT_SPEED_10G) ? 48 : \
+ ((type == FM_PORT_TYPE_OP) ? 8 : \
+ ((type == FM_PORT_TYPE_RX) ? 45 : 44)))) \
+
+#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256
+
+#define FM_OH_PORT_ID 1
+
+/* Memory Mapped Registers */
+
+struct fm_port_rx_bmi_regs_t {
+ uint32_t fmbm_rcfg; /* Rx Configuration */
+ uint32_t fmbm_rst; /* Rx Status */
+ uint32_t fmbm_rda; /* Rx DMA attributes*/
+ uint32_t fmbm_rfp; /* Rx FIFO Parameters*/
+ uint32_t fmbm_rfed; /* Rx Frame End Data*/
+ uint32_t fmbm_ricp; /* Rx Internal Context Parameters*/
+ uint32_t fmbm_rim; /* Rx Internal Buffer Margins*/
+ uint32_t fmbm_rebm; /* Rx External Buffer Margins*/
+ uint32_t fmbm_rfne; /* Rx Frame Next Engine*/
+ uint32_t fmbm_rfca; /* Rx Frame Command Attributes.*/
+ uint32_t fmbm_rfpne; /* Rx Frame Parser Next Engine*/
+ uint32_t fmbm_rpso; /* Rx Parse Start Offset*/
+ uint32_t fmbm_rpp; /* Rx Policer Profile */
+ uint32_t fmbm_rccb; /* Rx Coarse Classification Base */
+ uint32_t fmbm_reth; /* Rx Excessive Threshold */
+ uint32_t reserved1[0x01];
+ /* (0x03C) */
+ uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
+ /* Rx Parse Results Array Initialization*/
+ uint32_t fmbm_rfqid; /* Rx Frame Queue ID*/
+ uint32_t fmbm_refqid; /* Rx Error Frame Queue ID*/
+ uint32_t fmbm_rfsdm; /* Rx Frame Status Discard Mask*/
+ uint32_t fmbm_rfsem; /* Rx Frame Status Error Mask*/
+ uint32_t fmbm_rfene; /* Rx Frame Enqueue Next Engine */
+ uint32_t reserved2[0x02];
+ /* (0x074-0x078) */
+ /* Rx Frame Continuous Mode Next Engine */
+ uint32_t fmbm_rcmne;
+ uint32_t reserved3[0x20];
+ /* (0x080 0x0FF) */
+ uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /* Buffer Manager pool Information-*/
+ uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /* Allocate Counter-*/
+ uint32_t reserved4[0x08];
+ /* 0x130/0x140 - 0x15F reserved -*/
+ uint32_t
+ fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS / 32];
+ /* Congestion Group Map*/
+ uint32_t fmbm_rmpd; /* BM Pool Depletion */
+ uint32_t reserved5[0x1F];
+ /* (0x184 0x1FF) */
+ uint32_t fmbm_rstc; /* Rx Statistics Counters*/
+ uint32_t fmbm_rfrc; /* Rx Frame Counter*/
+ uint32_t fmbm_rfbc; /* Rx Bad Frames Counter*/
+ uint32_t fmbm_rlfc; /* Rx Large Frames Counter*/
+ uint32_t fmbm_rffc; /* Rx Filter Frames Counter*/
+ uint32_t fmbm_rfcd; /* Rx Frame Discard Counter*/
+ uint32_t fmbm_rfldec; /* Rx Frames List DMA Error Counter*/
+ uint32_t fmbm_rodc;/* Rx Out of Buffers Discard Counter-*/
+ uint32_t fmbm_rbdc; /* Rx Buffers Deallocate Counter-*/
+ uint32_t fmbm_rpec; /* Rx RX Prepare to enqueue Counter-*/
+ uint32_t reserved6[0x16];
+ /* (0x228 0x27F) */
+ uint32_t fmbm_rpc; /* Rx Performance Counters*/
+ uint32_t fmbm_rpcp; /* Rx Performance Count Parameters*/
+ uint32_t fmbm_rccn; /* Rx Cycle Counter*/
+ uint32_t fmbm_rtuc; /* Rx Tasks Utilization Counter*/
+ uint32_t fmbm_rrquc;/* Rx Receive Queue Utilization Counter*/
+ uint32_t fmbm_rduc; /* Rx DMA Utilization Counter*/
+ uint32_t fmbm_rfuc; /* Rx FIFO Utilization Counter*/
+ uint32_t fmbm_rpac; /* Rx Pause Activation Counter*/
+ uint32_t reserved7[0x18];
+ /* (0x2A0-0x2FF) */
+ uint32_t fmbm_rdcfg[0x3];
+ /* Rx Debug-*/
+ uint32_t fmbm_rgpr; /* Rx General Purpose Register. */
+ uint32_t reserved8[0x3a];
+ /* (0x310-0x3FF) */
+} __attribute__((__packed__));
+
+struct fm_port_tx_bmi_regs_t {
+ uint32_t fmbm_tcfg; /* Tx Configuration */
+ uint32_t fmbm_tst; /* Tx Status */
+ uint32_t fmbm_tda; /* Tx DMA attributes */
+ uint32_t fmbm_tfp; /* Tx FIFO Parameters */
+ uint32_t fmbm_tfed; /* Tx Frame End Data */
+ uint32_t fmbm_ticp; /* Tx Internal Context Parameters */
+ uint32_t fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */
+ uint32_t fmbm_tfca; /* Tx Frame Command attribute. */
+ uint32_t fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */
+ uint32_t fmbm_tfeqid; /* Tx Frame Error Queue ID */
+ uint32_t fmbm_tfene; /* Tx Frame Enqueue Next Engine */
+ uint32_t fmbm_trlmts; /* Tx Rate Limiter Scale */
+ uint32_t fmbm_trlmt; /* Tx Rate Limiter */
+ uint32_t fmbm_tccb; /* Tx Coarse Classification Base */
+ uint32_t reserved0[0x0e];
+ /* (0x038-0x070) */
+ uint32_t fmbm_tfne; /* Tx Frame Next Engine */
+ uint32_t fmbm_tpfcm[0x02];
+ /* Tx Priority based Flow Control (PFC) Mapping */
+ /* Tx Frame Continuous Mode Next Engine */
+ uint32_t fmbm_tcmne;
+ uint32_t reserved2[0x60];
+ /* (0x080-0x200) */
+ uint32_t fmbm_tstc; /* Tx Statistics Counters */
+ uint32_t fmbm_tfrc; /* Tx Frame Counter */
+ uint32_t fmbm_tfdc; /* Tx Frames Discard Counter */
+ uint32_t fmbm_tfledc; /* Tx Frame Length error discard counter */
+ /* Tx Frame unsupported format discard Counter */
+ uint32_t fmbm_tfufdc;
+ uint32_t fmbm_tbdc; /* Tx Buffers Deallocate Counter */
+ uint32_t reserved3[0x1A];
+ /* (0x218-0x280) */
+ uint32_t fmbm_tpc; /* Tx Performance Counters*/
+ uint32_t fmbm_tpcp; /* Tx Performance Count Parameters*/
+ uint32_t fmbm_tccn; /* Tx Cycle Counter*/
+ uint32_t fmbm_ttuc; /* Tx Tasks Utilization Counter*/
+ /* Tx Transmit Confirm Queue Utilization Counter*/
+ uint32_t fmbm_ttcquc;
+ uint32_t fmbm_tduc; /* Tx DMA Utilization Counter*/
+ uint32_t fmbm_tfuc; /* Tx FIFO Utilization Counter*/
+ uint32_t reserved4[16];/* (0x29C-0x2FF) */
+ uint32_t fmbm_tdcfg[0x3];
+ /* Tx Debug-*/
+ uint32_t fmbm_tgpr; /* O/H General Purpose Register */
+ uint32_t reserved5[0x3a];
+ /* (0x310-0x3FF) */
+} __attribute__((__packed__));
+
+struct fm_port_oh_bmi_regs_t {
+ uint32_t fmbm_ocfg; /* O/H Configuration */
+ uint32_t fmbm_ost; /* O/H Status */
+ uint32_t fmbm_oda; /* O/H DMA attributes */
+ uint32_t fmbm_oicp; /* O/H Internal Context Parameters*/
+ uint32_t fmbm_ofdne; /* O/H Frame Dequeue Next Engine */
+ uint32_t fmbm_ofne; /* O/H Frame Next Engine */
+ uint32_t fmbm_ofca; /* O/H Frame Command Attributes. */
+ uint32_t fmbm_ofpne; /* O/H Frame Parser Next Engine */
+ uint32_t fmbm_opso; /* O/H Parse Start Offset */
+ uint32_t fmbm_opp; /* O/H Policer Profile */
+ uint32_t fmbm_occb; /* O/H Coarse Classification base */
+ uint32_t fmbm_oim; /* O/H Internal margins*/
+ uint32_t fmbm_ofp; /* O/H Fifo Parameters*/
+ uint32_t fmbm_ofed; /* O/H Frame End Data*/
+ uint32_t reserved0[2]; /* (0x038 - 0x03F) */
+ uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
+ /* O/H Parse Results Array Initialization */
+ uint32_t fmbm_ofqid; /* O/H Frame Queue ID */
+ uint32_t fmbm_oefqid; /* O/H Error Frame Queue ID */
+ uint32_t fmbm_ofsdm; /* O/H Frame Status Discard Mask */
+ uint32_t fmbm_ofsem; /* O/H Frame Status Error Mask */
+ uint32_t fmbm_ofene; /* O/H Frame Enqueue Next Engine */
+ uint32_t fmbm_orlmts; /* O/H Rate Limiter Scale */
+ uint32_t fmbm_orlmt; /* O/H Rate Limiter */
+ uint32_t fmbm_ocmne; /* O/H Continuous Mode Next Engine*/
+ uint32_t reserved1[0x20];
+ /* (0x080 - 0x0FF) */
+ /* Buffer Manager Observed Pool Information */
+ uint32_t fmbm_oebmpi[2];
+ uint32_t reserved2[0x16];
+ /* (0x108 - 0x15F) */
+ uint32_t fmbm_ocgm; /* Observed Congestion Group Map */
+ uint32_t reserved3[0x7];
+ /* (0x164 - 0x17F) */
+ uint32_t fmbm_ompd; /* Observed BMan Pool Depletion */
+ uint32_t reserved4[0x1F];
+ /* (0x184 - 0x1FF) */
+ uint32_t fmbm_ostc; /* O/H Statistics Counters */
+ uint32_t fmbm_ofrc; /* O/H Frame Counter */
+ uint32_t fmbm_ofdc; /* O/H Frames Discard Counter */
+ /* O/H Frames Length Error Discard Counter */
+ uint32_t fmbm_ofledc;
+ /* O/H Frames Unsupported Format Discard Counter */
+ uint32_t fmbm_ofufdc;
+ uint32_t fmbm_offc; /* O/H Filter Frames Counter */
+ uint32_t fmbm_ofwdc; /* - Rx Frames WRED Discard Counter*/
+ /* O/H Frames List DMA Error Counter */
+ uint32_t fmbm_ofldec;
+ /* O/H Buffers Deallocate Counter */
+ uint32_t fmbm_obdc;
+ /* O/H Out of Buffers Discard Counter */
+ uint32_t fmbm_oodc;
+ /* O/H Prepare to enqueue Counter */
+ uint32_t fmbm_opec;
+ uint32_t reserved5[0x15];
+ /* ( - 0x27F) */
+ uint32_t fmbm_opc; /* O/H Performance Counters */
+ uint32_t fmbm_opcp; /* O/H Performance Count Parameters*/
+ uint32_t fmbm_occn; /* O/H Cycle Counter */
+ uint32_t fmbm_otuc; /* O/H Tasks Utilization Counter */
+ uint32_t fmbm_oduc; /* O/H DMA Utilization Counter */
+ uint32_t fmbm_ofuc; /* O/H FIFO Utilization Counter */
+ uint32_t reserved6[26];/* (0x298-0x2FF) */
+ uint32_t fmbm_odcfg[0x3];
+ /* O/H Debug (only 1 in P1023) */
+ uint32_t fmbm_ogpr; /* O/H General Purpose Register. */
+ uint32_t reserved7[0x3a];
+ /* (0x310 0x3FF) */
+} __attribute__((__packed__));
+
+union fm_port_bmi_regs_u {
+ struct fm_port_rx_bmi_regs_t rx_port_bmi_regs;
+ struct fm_port_tx_bmi_regs_t tx_port_bmi_regs;
+ struct fm_port_oh_bmi_regs_t oh_port_bmi_regs;
+} __attribute__((__packed__));
+
+struct fm_port_non_rx_qmi_regs_t {
+ /* 0xn024 - 0x02B */
+ uint32_t reserved1[2];
+ /* PortID n Dequeue NIA Register */
+ uint32_t fmqm_pndn;
+ /* PortID n Dequeue Config Register */
+ uint32_t fmqm_pndc;
+ /* PortID n Dequeue Total Frame Counter */
+ uint32_t fmqm_pndtfc;
+ /* PortID n Dequeue FQID from Default Counter */
+ uint32_t fmqm_pndfdc;
+ /* PortID n Dequeue Confirm Counter */
+ uint32_t fmqm_pndcc;
+} __attribute__((__packed__));
+
+struct fm_port_qmi_regs_t {
+ /* PortID n Configuration Register */
+ uint32_t fmqm_pnc;
+ /* PortID n Status Register */
+ uint32_t fmqm_pns;
+ /* PortID n Task Status Register */
+ uint32_t fmqm_pnts;
+ /* 0xn00C - 0xn01B */
+ uint32_t reserved0[4];
+ /* PortID n Enqueue NIA Register */
+ uint32_t fmqm_pnen;
+ /* PortID n Enqueue Total Frame Counter */
+ uint32_t fmqm_pnetfc;
+ /* Registers for Tx Hc&Op ports */
+ struct fm_port_non_rx_qmi_regs_t non_rx_qmi_regs;
+} __attribute__((__packed__));
+
+/* BMI defines */
+#define BMI_PORT_RFNE_FRWD_RPD 0x40000000
+
+#define BMI_STATUS_RX_MASK_UNUSED \
+(uint32_t)(~(FM_PORT_FRM_ERR_DMA | \
+FM_PORT_FRM_ERR_PHYSICAL | \
+FM_PORT_FRM_ERR_SIZE | \
+FM_PORT_FRM_ERR_CLS_DISCARD | \
+FM_PORT_FRM_ERR_EXTRACTION | \
+FM_PORT_FRM_ERR_NO_SCHEME | \
+FM_PORT_FRM_ERR_COLOR_RED | \
+FM_PORT_FRM_ERR_COLOR_YELLOW | \
+FM_PORT_FRM_ERR_PRS_TIMEOUT | \
+FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \
+FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \
+FM_PORT_FRM_ERR_PRS_HDR_ERR | \
+FM_PORT_FRM_ERR_IPRE | \
+FM_PORT_FRM_ERR_IPR_NCSP | \
+FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW))
+
+#define BMI_STATUS_OP_MASK_UNUSED \
+ (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \
+ ~(FM_PORT_FRM_ERR_LENGTH | \
+ FM_PORT_FRM_ERR_NON_FM | \
+ FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT))
+
+#define RX_ERRS_TO_ENQ \
+(FM_PORT_FRM_ERR_DMA | \
+FM_PORT_FRM_ERR_PHYSICAL | \
+FM_PORT_FRM_ERR_SIZE | \
+FM_PORT_FRM_ERR_EXTRACTION | \
+FM_PORT_FRM_ERR_NO_SCHEME | \
+FM_PORT_FRM_ERR_PRS_TIMEOUT | \
+FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \
+FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \
+FM_PORT_FRM_ERR_PRS_HDR_ERR | \
+FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \
+FM_PORT_FRM_ERR_IPRE)
+
+#define OP_ERRS_TO_ENQ \
+(RX_ERRS_TO_ENQ | \
+FM_PORT_FRM_ERR_LENGTH | \
+FM_PORT_FRM_ERR_NON_FM | \
+FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)
+
+/* sizes */
+#define FRAME_END_DATA_SIZE 16
+#define MIN_TX_INT_OFFSET 16
+#define MAX_FIFO_PIPELINE_DEPTH 8
+#define MAX_NUM_OF_TASKS 64
+#define MAX_NUM_OF_EXTRA_TASKS 8
+#define MAX_NUM_OF_DMAS 16
+#define MAX_NUM_OF_EXTRA_DMAS 8
+#define MIN_NUM_OF_OP_DMAS 2
+
+/* QMI defines */
+#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f
+
+struct fm_port_drv_param_t {
+ struct fman_port_cfg dflt_cfg;
+ uint32_t dflt_fqid;
+ uint32_t err_fqid;
+ uintptr_t base_addr;
+ uint8_t deq_sub_portal;
+ bool deq_high_priority;
+ enum fm_port_deq_type deq_type;
+ enum fm_port_deq_prefetch_option deq_prefetch_option;
+ uint16_t deq_byte_cnt;
+ uint8_t cheksum_last_bytes_ignore;
+ uint8_t cut_bytes_from_end;
+ struct fm_buf_pool_depletion_t buf_pool_depletion;
+ bool frm_discard_override;
+ bool en_buf_pool_depletion;
+ uint16_t liodn_offset;
+ uint16_t liodn_base;
+ struct fm_ext_pools_t ext_buf_pools;
+ uint32_t tx_fifo_min_fill_level;
+ uint32_t tx_fifo_low_comf_level;
+ uint32_t rx_fifo_pri_elevation_level;
+ uint32_t rx_fifo_threshold;
+ struct fm_sp_buf_margins_t buf_margins;
+ struct fm_sp_int_context_data_copy_t int_context;
+ uint32_t errors_to_discard;
+ bool forward_reuse_int_context;
+ struct fm_buffer_prefix_content_t buffer_prefix_content;
+ struct fm_backup_bm_pools_t *p_backup_bm_pools;
+ bool dont_release_buf;
+ bool set_num_of_tasks;
+ bool set_num_of_open_dmas;
+ bool set_size_of_fifo;
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+ bool bcb_workaround;
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+};
+
+struct fm_port_rx_pools_params_t {
+ uint8_t num_of_pools;
+ uint16_t second_largest_buf_size;
+ uint16_t largest_buf_size;
+};
+
+struct fm_port_intg_t {
+ uint32_t max_port_fifo_size;
+ uint32_t max_num_of_ext_pools;
+ uint32_t fm_max_num_of_sub_portals;
+ uint32_t bm_max_num_of_pools;
+};
+
+/* No PCD Engine indicated */
+#define FM_PCD_NONE 0
+struct fm_port_t {
+ struct fman_port port;
+ void *h_fm;
+ struct fm_revision_info_t fm_rev_info;
+ uint8_t port_id;
+ enum fm_port_type port_type;
+ enum fm_port_speed port_speed;
+ int enabled;
+ char name[MODULE_NAME_SIZE];
+ struct fm_port_qmi_regs_t __iomem *p_fm_port_qmi_regs;
+
+ union fm_port_bmi_regs_u __iomem *p_fm_port_bmi_regs;
+ /* The optional engines are devined avobe */
+ struct fm_sp_buffer_offsets_t buffer_offsets;
+
+ /* Spinlock for port use */
+ spinlock_t *spinlock;
+ uint8_t internal_buf_offset;
+ struct fm_ext_pools_t ext_buf_pools;
+
+ uint16_t max_frame_length;
+ struct fm_port_rsrc_t open_dmas;
+ struct fm_port_rsrc_t tasks;
+ struct fm_port_rsrc_t fifo_bufs;
+ struct fm_port_rx_pools_params_t rx_pools_params;
+
+ struct fm_port_drv_param_t *p_fm_port_drv_param;
+ struct fm_port_intg_t *port_intg;
+};
+
+#endif /* __FM_PORT_H */
--
1.7.11.7
From: Igal Liberman <[email protected]>
The FMan MAC FLib provides basic API used by the drivers to
configure and control the FMan MAC hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
.../net/ethernet/freescale/fman/flib/fsl_enet.h | 275 +++++++
.../ethernet/freescale/fman/flib/fsl_fman_dtsec.h | 791 +++++++++++++++++++++
.../freescale/fman/flib/fsl_fman_dtsec_mii_acc.h | 103 +++
.../ethernet/freescale/fman/flib/fsl_fman_memac.h | 453 ++++++++++++
.../freescale/fman/flib/fsl_fman_memac_mii_acc.h | 76 ++
.../ethernet/freescale/fman/flib/fsl_fman_tgec.h | 409 +++++++++++
6 files changed, 2107 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h
create mode 100644 drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_enet.h b/drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
new file mode 100644
index 0000000..78e7d04
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
@@ -0,0 +1,275 @@
+/*
+ * 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_ENET_H
+#define __FSL_ENET_H
+
+/*Ethernet MAC-PHY Interface */
+
+enum enet_interface {
+ E_ENET_IF_MII = 0x00010000, /* MII interface */
+ E_ENET_IF_RMII = 0x00020000, /* RMII interface */
+ E_ENET_IF_SMII = 0x00030000, /* SMII interface */
+ E_ENET_IF_GMII = 0x00040000, /* GMII interface */
+ E_ENET_IF_RGMII = 0x00050000, /* RGMII interface */
+ E_ENET_IF_TBI = 0x00060000, /* TBI interface */
+ E_ENET_IF_RTBI = 0x00070000, /* RTBI interface */
+ E_ENET_IF_SGMII = 0x00080000, /* SGMII interface */
+ E_ENET_IF_XGMII = 0x00090000, /* XGMII interface */
+ E_ENET_IF_QSGMII = 0x000a0000, /* QSGMII interface */
+ E_ENET_IF_XFI = 0x000b0000 /* XFI interface */
+};
+
+/* Ethernet Speed (nominal data rate) */
+enum enet_speed {
+ E_ENET_SPEED_10 = 10, /* 10 Mbps */
+ E_ENET_SPEED_100 = 100, /* 100 Mbps */
+ E_ENET_SPEED_1000 = 1000, /* 1000 Mbps = 1 Gbps */
+ E_ENET_SPEED_10000 = 10000 /* 10000 Mbps = 10 Gbps */
+};
+
+enum mac_type {
+ E_MAC_DTSEC,
+ E_MAC_TGEC,
+ E_MAC_MEMAC
+};
+
+/* Enum for inter-module interrupts registration */
+enum fman_event_modules {
+ E_FMAN_MOD_PRS, /* Parser event */
+ E_FMAN_MOD_KG, /* Keygen event */
+ E_FMAN_MOD_PLCR, /* Policer event */
+ E_FMAN_MOD_10G_MAC, /* 10G MAC event */
+ E_FMAN_MOD_1G_MAC, /* 1G MAC event */
+ E_FMAN_MOD_TMR, /* Timer event */
+ E_FMAN_MOD_FMAN_CTRL, /* FMAN Controller Timer event */
+ E_FMAN_MOD_MACSEC,
+ E_FMAN_MOD_DUMMY_LAST
+};
+
+/* Enum for interrupts types */
+enum fman_intr_type {
+ E_FMAN_INTR_TYPE_ERR,
+ E_FMAN_INTR_TYPE_NORMAL
+};
+
+/* enum for defining MAC types */
+enum fman_mac_type {
+ E_FMAN_MAC_10G = 0, /* 10G MAC */
+ E_FMAN_MAC_1G /* 1G MAC */
+};
+
+enum fman_mac_exceptions {
+ E_FMAN_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0,
+ /* 10GEC MDIO scan event interrupt */
+ E_FMAN_MAC_EX_10G_MDIO_CMD_CMPL,
+ /* 10GEC MDIO command completion interrupt */
+ E_FMAN_MAC_EX_10G_REM_FAULT,
+ /* 10GEC, mEMAC Remote fault interrupt */
+ E_FMAN_MAC_EX_10G_LOC_FAULT,
+ /* 10GEC, mEMAC Local fault interrupt */
+ E_FMAN_MAC_EX_10G_1TX_ECC_ER,
+ /* 10GEC, mEMAC Transmit frame ECC error interrupt */
+ E_FMAN_MAC_EX_10G_TX_FIFO_UNFL,
+ /* 10GEC, mEMAC Transmit FIFO underflow interrupt */
+ E_FMAN_MAC_EX_10G_TX_FIFO_OVFL,
+ /* 10GEC, mEMAC Transmit FIFO overflow interrupt */
+ E_FMAN_MAC_EX_10G_TX_ER,
+ /* 10GEC Transmit frame error interrupt */
+ E_FMAN_MAC_EX_10G_RX_FIFO_OVFL,
+ /* 10GEC, mEMAC Receive FIFO overflow interrupt */
+ E_FMAN_MAC_EX_10G_RX_ECC_ER,
+ /* 10GEC, mEMAC Receive frame ECC error interrupt */
+ E_FMAN_MAC_EX_10G_RX_JAB_FRM,
+ /* 10GEC Receive jabber frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_OVRSZ_FRM,
+ /* 10GEC Receive oversized frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_RUNT_FRM,
+ /* 10GEC Receive runt frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_FRAG_FRM,
+ /* 10GEC Receive fragment frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_LEN_ER,
+ /* 10GEC Receive payload length error interrupt */
+ E_FMAN_MAC_EX_10G_RX_CRC_ER,
+ /* 10GEC Receive CRC error interrupt */
+ E_FMAN_MAC_EX_10G_RX_ALIGN_ER,
+ /* 10GEC Receive alignment error interrupt */
+ E_FMAN_MAC_EX_1G_BAB_RX,
+ /* dTSEC Babbling receive error */
+ E_FMAN_MAC_EX_1G_RX_CTL,
+ /* dTSEC Receive control (pause frame) interrupt */
+ E_FMAN_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET,
+ /* dTSEC Graceful transmit stop complete */
+ E_FMAN_MAC_EX_1G_BAB_TX,
+ /* dTSEC Babbling transmit error */
+ E_FMAN_MAC_EX_1G_TX_CTL,
+ /* dTSEC Transmit control (pause frame) interrupt */
+ E_FMAN_MAC_EX_1G_TX_ERR,
+ /* dTSEC Transmit error */
+ E_FMAN_MAC_EX_1G_LATE_COL,
+ /* dTSEC Late collision */
+ E_FMAN_MAC_EX_1G_COL_RET_LMT,
+ /* dTSEC Collision retry limit */
+ E_FMAN_MAC_EX_1G_TX_FIFO_UNDRN,
+ /* dTSEC Transmit FIFO underrun */
+ E_FMAN_MAC_EX_1G_MAG_PCKT,
+ /* dTSEC Magic Packet detection */
+ E_FMAN_MAC_EX_1G_MII_MNG_RD_COMPLET,
+ /* dTSEC MII management read completion */
+ E_FMAN_MAC_EX_1G_MII_MNG_WR_COMPLET,
+ /* dTSEC MII management write completion */
+ E_FMAN_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET,
+ /* dTSEC Graceful receive stop complete */
+ E_FMAN_MAC_EX_1G_TX_DATA_ERR,
+ /* dTSEC Internal data error on transmit */
+ E_FMAN_MAC_EX_1G_RX_DATA_ERR,
+ /* dTSEC Internal data error on receive */
+ E_FMAN_MAC_EX_1G_1588_TS_RX_ERR,
+ /* dTSEC Time-Stamp Receive Error */
+ E_FMAN_MAC_EX_1G_RX_MIB_CNT_OVFL,
+ /* dTSEC MIB counter overflow */
+ E_FMAN_MAC_EX_TS_FIFO_ECC_ERR,
+ /* < mEMAC Time-stamp FIFO ECC error interrupt;
+ * not supported on T4240/B4860 rev1 chips
+ */
+};
+
+/* 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
+
+enum enet_mode {
+ E_ENET_MODE_INVALID = 0,
+ /* Invalid Ethernet mode */
+ E_ENET_MODE_MII_10 = (E_ENET_IF_MII | E_ENET_SPEED_10),
+ /* 10 Mbps MII */
+ E_ENET_MODE_MII_100 = (E_ENET_IF_MII | E_ENET_SPEED_100),
+ /* 100 Mbps MII */
+ E_ENET_MODE_RMII_10 = (E_ENET_IF_RMII | E_ENET_SPEED_10),
+ /* 10 Mbps RMII */
+ E_ENET_MODE_RMII_100 = (E_ENET_IF_RMII | E_ENET_SPEED_100),
+ /* 100 Mbps RMII */
+ E_ENET_MODE_SMII_10 = (E_ENET_IF_SMII | E_ENET_SPEED_10),
+ /* 10 Mbps SMII */
+ E_ENET_MODE_SMII_100 = (E_ENET_IF_SMII | E_ENET_SPEED_100),
+ /* 100 Mbps SMII */
+ E_ENET_MODE_GMII_1000 = (E_ENET_IF_GMII | E_ENET_SPEED_1000),
+ /* 1000 Mbps GMII */
+ E_ENET_MODE_RGMII_10 = (E_ENET_IF_RGMII | E_ENET_SPEED_10),
+ /* 10 Mbps RGMII */
+ E_ENET_MODE_RGMII_100 = (E_ENET_IF_RGMII | E_ENET_SPEED_100),
+ /* 100 Mbps RGMII */
+ E_ENET_MODE_RGMII_1000 = (E_ENET_IF_RGMII | E_ENET_SPEED_1000),
+ /* 1000 Mbps RGMII */
+ E_ENET_MODE_TBI_1000 = (E_ENET_IF_TBI | E_ENET_SPEED_1000),
+ /* 1000 Mbps TBI */
+ E_ENET_MODE_RTBI_1000 = (E_ENET_IF_RTBI | E_ENET_SPEED_1000),
+ /* 1000 Mbps RTBI */
+ E_ENET_MODE_SGMII_10 = (E_ENET_IF_SGMII | E_ENET_SPEED_10),
+ /* 10 Mbps SGMII with auto-negotiation between MAC and
+ * SGMII phy according to Cisco SGMII specification
+ */
+ E_ENET_MODE_SGMII_100 = (E_ENET_IF_SGMII | E_ENET_SPEED_100),
+ /* 100 Mbps SGMII with auto-negotiation between MAC and
+ * SGMII phy according to Cisco SGMII specification
+ */
+ E_ENET_MODE_SGMII_1000 = (E_ENET_IF_SGMII | E_ENET_SPEED_1000),
+ /* 1000 Mbps SGMII with auto-negotiation between MAC and
+ * SGMII phy according to Cisco SGMII specification
+ */
+ E_ENET_MODE_SGMII_BASEX_10 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_10),
+ /* 10 Mbps SGMII with 1000BaseX auto-negotiation between
+ * MAC and SGMII phy or backplane
+ */
+ E_ENET_MODE_SGMII_BASEX_100 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_100),
+ /* 100 Mbps SGMII with 1000BaseX auto-negotiation between
+ * MAC and SGMII phy or backplane
+ */
+ E_ENET_MODE_SGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_1000),
+ /* 1000 Mbps SGMII with 1000BaseX auto-negotiation between
+ * MAC and SGMII phy or backplane
+ */
+ E_ENET_MODE_QSGMII_1000 = (E_ENET_IF_QSGMII | E_ENET_SPEED_1000),
+ /* 1000 Mbps QSGMII with auto-negotiation between MAC and
+ * QSGMII phy according to Cisco QSGMII specification
+ */
+ E_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_QSGMII
+ | E_ENET_SPEED_1000),
+ /* 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
+ * MAC and QSGMII phy or backplane
+ */
+ E_ENET_MODE_XGMII_10000 = (E_ENET_IF_XGMII | E_ENET_SPEED_10000),
+ /* 10000 Mbps XGMII */
+ E_ENET_MODE_XFI_10000 = (E_ENET_IF_XFI | E_ENET_SPEED_10000)
+ /* 10000 Mbps XFI */
+};
+
+enum fmam_mac_statistics_level {
+ E_FMAN_MAC_NONE_STATISTICS, /* No statistics */
+ E_FMAN_MAC_PARTIAL_STATISTICS, /* Only error counters are available;
+ * Optimized for performance
+ */
+ E_FMAN_MAC_FULL_STATISTICS /* All counters available; Not
+ * optimized for performance
+ */
+};
+
+#define _MAKE_ENET_MODE(_interface, _speed) (enum enet_mode)((_interface) \
+ | (_speed))
+
+#define _ENET_INTERFACE_FROM_MODE(mode) \
+ ((enum enet_interface)((mode) & 0x0FFF0000))
+
+#define _ENET_SPEED_FROM_MODE(mode) (enum enet_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 /* __FSL_ENET_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h
new file mode 100644
index 0000000..ef753b3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h
@@ -0,0 +1,791 @@
+/*
+ * 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_DTSEC_H
+#define __FSL_FMAN_DTSEC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+
+/* dTSEC Init sequence
+ *To prepare dTSEC block for transfer use the following call sequence:
+ *- fman_dtsec_defconfig() - This step is optional and yet recommended. Its
+ *use is to obtain the default dTSEC configuration parameters.
+ *- Change dtsec configuration in &dtsec_cfg. This structure will be used
+ *to customize the dTSEC behavior.
+ *- fman_dtsec_init() - Applies the configuration on dTSEC hardware. Note that
+ *dTSEC is initialized while both Tx and Rx are disabled.
+ *- fman_dtsec_set_mac_address() - Set the station address (mac address).
+ *This is used by dTSEC to match against received packets.
+ *
+ *- fman_dtsec_adjust_link() - Set the link speed and duplex parameters
+ *after the PHY establishes the link.
+ *- dtsec_enable_tx() and dtsec_enable_rx() to enable transmission and
+ *reception.
+ */
+
+/* dTSEC Graceful stop
+ *To temporary stop dTSEC activity use fman_dtsec_stop_tx() and
+ *fman_dtsec_stop_rx(). Note that these functions request dTSEC graceful stop
+ *but return before this stop is complete. To query for graceful stop
+ *completion use fman_dtsec_get_event() and check DTSEC_IEVENT_GTSC and
+ *DTSEC_IEVENT_GRSC bits. Alternatively the dTSEC interrupt mask can be set to
+ *enable graceful stop interrupts.
+ *To resume operation after graceful stop use fman_dtsec_start_tx() and
+ *fman_dtsec_start_rx().
+ */
+
+/* dTSEC interrupt handling
+ *
+ *This code does not provide an interrupt handler for dTSEC. Instead this
+ *handler should be implemented and registered to the operating system by the
+ *caller. Some primitives for accessing the event status and mask registers
+ *are provided.
+ *See "dTSEC Events" section for a list of events that dTSEC can generate.
+ */
+
+/*dTSEC Events
+ *Interrupt events cause dTSEC event bits to be set. Software may poll the
+ *event register at any time to check for pending interrupts. If an event
+ *occurs and its corresponding enable bit is set in the interrupt mask
+ *register, the event also causes a hardware interrupt at the PIC.
+ *To poll for event status use the fman_dtsec_get_event() function.
+ *To configure the interrupt mask use fman_dtsec_enable_interrupt() and
+ *fman_dtsec_disable_interrupt() functions.
+ *After servicing a dTSEC interrupt use fman_dtsec_ack_event to reset the
+ *serviced event bit.
+ *The following events may be signaled by dTSEC hardware:
+ *%DTSEC_IEVENT_BABR - Babbling receive error. This bit indicates that
+ *a frame was received with length in excess of the MAC's maximum frame length
+ *register.
+ *%DTSEC_IEVENT_RXC - Receive control (pause frame) interrupt. A pause
+ *control frame was received while Rx pause frame handling is enabled.
+ *Also see fman_dtsec_handle_rx_pause().
+ *%DTSEC_IEVENT_MSRO - MIB counter overflow. The count for one of the MIB
+ *counters has exceeded the size of its register.
+ *%DTSEC_IEVENT_GTSC - Graceful transmit stop complete. Graceful stop is now
+ *complete. The transmitter is in a stopped state, in which only pause frames
+ *can be transmitted.
+ *Also see fman_dtsec_stop_tx().
+ *%DTSEC_IEVENT_BABT - Babbling transmit error. The transmitted frame length
+ *has exceeded the value in the MAC's Maximum Frame Length register.
+ *%DTSEC_IEVENT_TXC - Transmit control (pause frame) interrupt. his bit
+ *indicates that a control frame was transmitted.
+ *%DTSEC_IEVENT_TXE - Transmit error. This bit indicates that an error
+ *occurred on the transmitted channel. This bit is set whenever any transmit
+ *error occurs which causes the dTSEC to discard all or part of a frame
+ *(LC, CRL, XFUN).
+ *%DTSEC_IEVENT_LC - Late collision. This bit indicates that a collision
+ *occurred beyond the collision window (slot time) in half-duplex mode.
+ *The frame is truncated with a bad CRC and the remainder of the frame
+ *is discarded.
+ *%DTSEC_IEVENT_CRL - Collision retry limit. is bit indicates that the number
+ *of successive transmission collisions has exceeded the MAC's half-duplex
+ *register's retransmission maximum count. The frame is discarded without
+ *being transmitted and transmission of the next frame commences. This only
+ *occurs while in half-duplex mode.
+ *The number of retransmit attempts can be set in
+ *&dtsec_halfdup_cfg.retransmit before calling fman_dtsec_init().
+ *%DTSEC_IEVENT_XFUN - Transmit FIFO underrun. This bit indicates that the
+ *transmit FIFO became empty before the complete frame was transmitted.
+ *The frame is truncated with a bad CRC and the remainder of the frame is
+ *discarded.
+ *%DTSEC_IEVENT_MAG - TBD
+ *%DTSEC_IEVENT_MMRD - MII management read completion.
+ *%DTSEC_IEVENT_MMWR - MII management write completion.
+ *%DTSEC_IEVENT_GRSC - Graceful receive stop complete. It allows the user to
+ *know if the system has completed the stop and it is safe to write to receive
+ *registers (status, control or configuration registers) that are used by the
+ *system during normal operation.
+ *%DTSEC_IEVENT_TDPE - Internal data error on transmit. This bit indicates
+ *that the dTSEC has detected a parity error on its stored transmit data, which
+ *is likely to compromise the validity of recently transferred frames.
+ *%DTSEC_IEVENT_RDPE - Internal data error on receive. This bit indicates that
+ *the dTSEC has detected a parity error on its stored receive data, which is
+ *likely to compromise the validity of recently transferred frames.
+ */
+/* Interrupt Mask Register (IMASK) */
+#define DTSEC_IMASK_BREN 0x80000000
+#define DTSEC_IMASK_RXCEN 0x40000000
+#define DTSEC_IMASK_MSROEN 0x04000000
+#define DTSEC_IMASK_GTSCEN 0x02000000
+#define DTSEC_IMASK_BTEN 0x01000000
+#define DTSEC_IMASK_TXCEN 0x00800000
+#define DTSEC_IMASK_TXEEN 0x00400000
+#define DTSEC_IMASK_LCEN 0x00040000
+#define DTSEC_IMASK_CRLEN 0x00020000
+#define DTSEC_IMASK_XFUNEN 0x00010000
+#define DTSEC_IMASK_ABRTEN 0x00008000
+#define DTSEC_IMASK_IFERREN 0x00004000
+#define DTSEC_IMASK_MAGEN 0x00000800
+#define DTSEC_IMASK_MMRDEN 0x00000400
+#define DTSEC_IMASK_MMWREN 0x00000200
+#define DTSEC_IMASK_GRSCEN 0x00000100
+#define DTSEC_IMASK_TDPEEN 0x00000002
+#define DTSEC_IMASK_RDPEEN 0x00000001
+
+#define DTSEC_EVENTS_MASK \
+ ((uint32_t)(DTSEC_IMASK_BREN | \
+ DTSEC_IMASK_RXCEN | \
+ DTSEC_IMASK_BTEN | \
+ DTSEC_IMASK_TXCEN | \
+ DTSEC_IMASK_TXEEN | \
+ DTSEC_IMASK_ABRTEN | \
+ DTSEC_IMASK_LCEN | \
+ DTSEC_IMASK_CRLEN | \
+ DTSEC_IMASK_XFUNEN | \
+ DTSEC_IMASK_IFERREN | \
+ DTSEC_IMASK_MAGEN | \
+ DTSEC_IMASK_TDPEEN | \
+ DTSEC_IMASK_RDPEEN))
+
+/* dtsec timestamp event bits */
+#define TMR_PEMASK_TSREEN 0x00010000
+#define TMR_PEVENT_TSRE 0x00010000
+
+/* Group address bit indication */
+#define MAC_GROUP_ADDRESS 0x0000010000000000ULL
+/* size in bytes of L2 address */
+#define MAC_ADDRLEN 6
+
+#define DEFAULT_HALFDUP_ON false
+#define DEFAULT_HALFDUP_RETRANSMIT 0xf
+#define DEFAULT_HALFDUP_COLL_WINDOW 0x37
+#define DEFAULT_HALFDUP_EXCESS_DEFER true
+#define DEFAULT_HALFDUP_NO_BACKOFF false
+#define DEFAULT_HALFDUP_BP_NO_BACKOFF false
+#define DEFAULT_HALFDUP_ALT_BACKOFF_VAL 0x0A
+#define DEFAULT_HALFDUP_ALT_BACKOFF_EN false
+#define DEFAULT_RX_DROP_BCAST false
+#define DEFAULT_RX_SHORT_FRM true
+#define DEFAULT_RX_LEN_CHECK false
+#define DEFAULT_TX_PAD_CRC true
+#define DEFAULT_TX_CRC false
+#define DEFAULT_RX_CTRL_ACC false
+#define DEFAULT_TX_PAUSE_TIME 0xf000
+#define DEFAULT_TBIPA 5
+#define DEFAULT_RX_PREPEND 0
+#define DEFAULT_PTP_TSU_EN true
+#define DEFAULT_PTP_EXCEPTION_EN true
+#define DEFAULT_PREAMBLE_LEN 7
+#define DEFAULT_RX_PREAMBLE false
+#define DEFAULT_TX_PREAMBLE false
+#define DEFAULT_LOOPBACK false
+#define DEFAULT_RX_TIME_STAMP_EN false
+#define DEFAULT_TX_TIME_STAMP_EN false
+#define DEFAULT_RX_FLOW true
+#define DEFAULT_TX_FLOW true
+#define DEFAULT_RX_GROUP_HASH_EXD false
+#define DEFAULT_TX_PAUSE_TIME_EXTD 0
+#define DEFAULT_RX_PROMISC false
+#define DEFAULT_NON_BACK_TO_BACK_IPG1 0x40
+#define DEFAULT_NON_BACK_TO_BACK_IPG2 0x60
+#define DEFAULT_MIN_IFG_ENFORCEMENT 0x50
+#define DEFAULT_BACK_TO_BACK_IPG 0x60
+#define DEFAULT_MAXIMUM_FRAME 0x600
+#define DEFAULT_TBI_PHY_ADDR 5
+#define DEFAULT_WAKE_ON_LAN false
+
+/* register related defines (bits, field offsets..) */
+#define DTSEC_ID1_ID 0xffff0000
+#define DTSEC_ID1_REV_MJ 0x0000FF00
+#define DTSEC_ID1_REV_MN 0x000000ff
+
+#define DTSEC_ID2_INT_REDUCED_OFF 0x00010000
+#define DTSEC_ID2_INT_NORMAL_OFF 0x00020000
+
+#define DTSEC_ECNTRL_CLRCNT 0x00004000
+#define DTSEC_ECNTRL_AUTOZ 0x00002000
+#define DTSEC_ECNTRL_STEN 0x00001000
+#define DTSEC_ECNTRL_CFG_RO 0x80000000
+#define DTSEC_ECNTRL_GMIIM 0x00000040
+#define DTSEC_ECNTRL_TBIM 0x00000020
+#define DTSEC_ECNTRL_SGMIIM 0x00000002
+#define DTSEC_ECNTRL_RPM 0x00000010
+#define DTSEC_ECNTRL_R100M 0x00000008
+#define DTSEC_ECNTRL_RMM 0x00000004
+#define DTSEC_ECNTRL_QSGMIIM 0x00000001
+
+#define DTSEC_TCTRL_THDF 0x00000800
+#define DTSEC_TCTRL_TTSE 0x00000040
+#define DTSEC_TCTRL_GTS 0x00000020
+#define DTSEC_TCTRL_TFC_PAUSE 0x00000010
+
+/* PTV offsets */
+#define PTV_PTE_OFST 16
+
+#define RCTRL_CFA 0x00008000
+#define RCTRL_GHTX 0x00000400
+#define RCTRL_RTSE 0x00000040
+#define RCTRL_GRS 0x00000020
+#define RCTRL_BC_REJ 0x00000010
+#define RCTRL_MPROM 0x00000008
+#define RCTRL_RSF 0x00000004
+#define RCTRL_UPROM 0x00000001
+#define RCTRL_PROM (RCTRL_UPROM | RCTRL_MPROM)
+
+#define TMR_CTL_ESFDP 0x00000800
+#define TMR_CTL_ESFDE 0x00000400
+
+#define MACCFG1_SOFT_RESET 0x80000000
+#define MACCFG1_LOOPBACK 0x00000100
+#define MACCFG1_RX_FLOW 0x00000020
+#define MACCFG1_TX_FLOW 0x00000010
+#define MACCFG1_TX_EN 0x00000001
+#define MACCFG1_RX_EN 0x00000004
+
+#define MACCFG2_NIBBLE_MODE 0x00000100
+#define MACCFG2_BYTE_MODE 0x00000200
+#define MACCFG2_PRE_AM_RX_EN 0x00000080
+#define MACCFG2_PRE_AM_TX_EN 0x00000040
+#define MACCFG2_LENGTH_CHECK 0x00000010
+#define MACCFG2_MAGIC_PACKET_EN 0x00000008
+#define MACCFG2_PAD_CRC_EN 0x00000004
+#define MACCFG2_CRC_EN 0x00000002
+#define MACCFG2_FULL_DUPLEX 0x00000001
+
+#define PREAMBLE_LENGTH_SHIFT 12
+
+#define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT 24
+#define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT 16
+#define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT 8
+
+#define IPGIFG_NON_BACK_TO_BACK_IPG_1 0x7F000000
+#define IPGIFG_NON_BACK_TO_BACK_IPG_2 0x007F0000
+#define IPGIFG_MIN_IFG_ENFORCEMENT 0x0000FF00
+#define IPGIFG_BACK_TO_BACK_IPG 0x0000007F
+
+#define HAFDUP_ALT_BEB 0x00080000
+#define HAFDUP_BP_NO_BACKOFF 0x00040000
+#define HAFDUP_NO_BACKOFF 0x00020000
+#define HAFDUP_EXCESS_DEFER 0x00010000
+#define HAFDUP_COLLISION_WINDOW 0x000003ff
+
+#define HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT 20
+#define HAFDUP_RETRANSMISSION_MAX_SHIFT 12
+#define HAFDUP_RETRANSMISSION_MAX 0x0000f000
+
+#define NUM_OF_HASH_REGS 8 /* Number of hash table registers */
+
+/* CAR1/2 bits */
+#define DTSEC_CAR1_TR64 0x80000000
+#define DTSEC_CAR1_TR127 0x40000000
+#define DTSEC_CAR1_TR255 0x20000000
+#define DTSEC_CAR1_TR511 0x10000000
+#define DTSEC_CAR1_TRK1 0x08000000
+#define DTSEC_CAR1_TRMAX 0x04000000
+#define DTSEC_CAR1_TRMGV 0x02000000
+
+#define DTSEC_CAR1_RBYT 0x00010000
+#define DTSEC_CAR1_RPKT 0x00008000
+#define DTSEC_CAR1_RFCS 0x00004000
+#define DTSEC_CAR1_RMCA 0x00002000
+#define DTSEC_CAR1_RBCA 0x00001000
+#define DTSEC_CAR1_RXCF 0x00000800
+#define DTSEC_CAR1_RXPF 0x00000400
+#define DTSEC_CAR1_RXUO 0x00000200
+#define DTSEC_CAR1_RALN 0x00000100
+#define DTSEC_CAR1_RFLR 0x00000080
+#define DTSEC_CAR1_RCDE 0x00000040
+#define DTSEC_CAR1_RCSE 0x00000020
+#define DTSEC_CAR1_RUND 0x00000010
+#define DTSEC_CAR1_ROVR 0x00000008
+#define DTSEC_CAR1_RFRG 0x00000004
+#define DTSEC_CAR1_RJBR 0x00000002
+#define DTSEC_CAR1_RDRP 0x00000001
+
+#define DTSEC_CAR2_TJBR 0x00080000
+#define DTSEC_CAR2_TFCS 0x00040000
+#define DTSEC_CAR2_TXCF 0x00020000
+#define DTSEC_CAR2_TOVR 0x00010000
+#define DTSEC_CAR2_TUND 0x00008000
+#define DTSEC_CAR2_TFRG 0x00004000
+#define DTSEC_CAR2_TBYT 0x00002000
+#define DTSEC_CAR2_TPKT 0x00001000
+#define DTSEC_CAR2_TMCA 0x00000800
+#define DTSEC_CAR2_TBCA 0x00000400
+#define DTSEC_CAR2_TXPF 0x00000200
+#define DTSEC_CAR2_TDFR 0x00000100
+#define DTSEC_CAR2_TEDF 0x00000080
+#define DTSEC_CAR2_TSCL 0x00000040
+#define DTSEC_CAR2_TMCL 0x00000020
+#define DTSEC_CAR2_TLCL 0x00000010
+#define DTSEC_CAR2_TXCL 0x00000008
+#define DTSEC_CAR2_TNCL 0x00000004
+#define DTSEC_CAR2_TDRP 0x00000001
+
+/* memory map */
+
+struct dtsec_regs {
+ /* dTSEC General Control and Status Registers */
+ uint32_t tsec_id; /* 0x000 ETSEC_ID register */
+ uint32_t tsec_id2; /* 0x004 ETSEC_ID2 register */
+ uint32_t ievent; /* 0x008 Interrupt event register */
+ uint32_t imask; /* 0x00C Interrupt mask register */
+ uint32_t reserved0010[1];
+ uint32_t ecntrl; /* 0x014 E control register */
+ uint32_t ptv; /* 0x018 Pause time value register */
+ uint32_t tbipa; /* 0x01C TBI PHY address register */
+ uint32_t tmr_ctrl; /* 0x020 Time-stamp Control register */
+ uint32_t tmr_pevent; /* 0x024 Time-stamp event register */
+ uint32_t tmr_pemask; /* 0x028 Timer event mask register */
+ uint32_t reserved002c[5];
+ uint32_t tctrl; /* 0x040 Transmit control register */
+ uint32_t reserved0044[3];
+ uint32_t rctrl; /* 0x050 Receive control register */
+ uint32_t reserved0054[11];
+ uint32_t igaddr[8]; /* 0x080-0x09C Individual/group address */
+ uint32_t gaddr[8]; /* 0x0A0-0x0BC Group address registers 0-7 */
+ uint32_t reserved00c0[16];
+ uint32_t maccfg1; /* 0x100 MAC configuration #1 */
+ uint32_t maccfg2; /* 0x104 MAC configuration #2 */
+ uint32_t ipgifg; /* 0x108 IPG/IFG */
+ uint32_t hafdup; /* 0x10C Half-duplex */
+ uint32_t maxfrm; /* 0x110 Maximum frame */
+ uint32_t reserved0114[10];
+ uint32_t ifstat; /* 0x13C Interface status */
+ uint32_t macstnaddr1; /* 0x140 Station Address,part 1 */
+ uint32_t macstnaddr2; /* 0x144 Station Address,part 2 */
+ struct {
+ uint32_t exact_match1; /* octets 1-4 */
+ uint32_t exact_match2; /* octets 5-6 */
+ } macaddr[15]; /* 0x148-0x1BC mac exact match addresses 1-15 */
+ uint32_t reserved01c0[16];
+ /* 0x200 transmit and receive 64 byte frame counter */
+ uint32_t tr64;
+ /* 0x204 transmit and receive 65 to 127 byte frame counter */
+ uint32_t tr127;
+ /* 0x208 transmit and receive 128 to 255 byte frame counter */
+ uint32_t tr255;
+ /* 0x20C transmit and receive 256 to 511 byte frame counter */
+ uint32_t tr511;
+ /* 0x210 transmit and receive 512 to 1023 byte frame counter */
+ uint32_t tr1k;
+ /* 0x214 transmit and receive 1024 to 1518 byte frame counter */
+ uint32_t trmax;
+ /* 0x218 transmit and receive 1519 to 1522 byte good VLAN frame count*/
+ uint32_t trmgv;
+ uint32_t rbyt; /* 0x21C receive byte counter */
+ uint32_t rpkt; /* 0x220 receive packet counter */
+ uint32_t rfcs; /* 0x224 receive FCS error counter */
+ /* 0x228 RMCA receive multicast packet counter */
+ uint32_t rmca;
+ uint32_t rbca; /* 0x22C receive broadcast packet counter */
+ uint32_t rxcf; /* 0x230 receive control frame packet counter */
+ uint32_t rxpf; /* 0x234 receive pause frame packet counter */
+ uint32_t rxuo; /* 0x238 receive unknown OP code counter */
+ uint32_t raln; /* 0x23C receive alignment error counter */
+ uint32_t rflr; /* 0x240 receive frame length error counter */
+ uint32_t rcde; /* 0x244 receive code error counter */
+ uint32_t rcse; /* 0x248 receive carrier sense error counter */
+ uint32_t rund; /* 0x24C receive undersize packet counter */
+ uint32_t rovr; /* 0x250 receive oversize packet counter */
+ uint32_t rfrg; /* 0x254 receive fragments counter */
+ uint32_t rjbr; /* 0x258 receive jabber counter */
+ uint32_t rdrp; /* 0x25C receive drop */
+ uint32_t tbyt; /* 0x260 transmit byte counter */
+ uint32_t tpkt; /* 0x264 transmit packet counter */
+ uint32_t tmca; /* 0x268 transmit multicast packet counter */
+ uint32_t tbca; /* 0x26C transmit broadcast packet counter */
+ uint32_t txpf; /* 0x270 transmit pause control frame counter */
+ uint32_t tdfr; /* 0x274 transmit deferral packet counter */
+ /* 0x278 transmit excessive deferral packet counter */
+ uint32_t tedf;
+ /* 0x27C transmit single collision packet counter */
+ uint32_t tscl;
+ /* 0x280 transmit multiple collision packet counter */
+ uint32_t tmcl;
+ /* 0x284 transmit late collision packet counter */
+ uint32_t tlcl;
+ /* 0x288 transmit excessive collision packet counter */
+ uint32_t txcl;
+ uint32_t tncl; /* 0x28C transmit total collision counter */
+ uint32_t reserved0290[1];
+ uint32_t tdrp; /* 0x294 transmit drop frame counter */
+ uint32_t tjbr; /* 0x298 transmit jabber frame counter */
+ uint32_t tfcs; /* 0x29C transmit FCS error counter */
+ uint32_t txcf; /* 0x2A0 transmit control frame counter */
+ uint32_t tovr; /* 0x2A4 transmit oversize frame counter */
+ uint32_t tund; /* 0x2A8 transmit undersize frame counter */
+ uint32_t tfrg; /* 0x2AC transmit fragments frame counter */
+ uint32_t car1; /* 0x2B0 carry register one register* */
+ uint32_t car2; /* 0x2B4 carry register two register* */
+ uint32_t cam1; /* 0x2B8 carry register one mask register */
+ uint32_t cam2; /* 0x2BC carry register two mask register */
+ uint32_t reserved02c0[848];
+};
+
+/* struct dtsec_cfg - dTSEC configuration
+ * Transmit half-duplex flow control, under software
+ * control for 10/100-Mbps half-duplex media. If set,
+ * back pressure is applied to media by raising carrier.
+ * halfdup_retransmit:
+ * Number of retransmission attempts following a collision.
+ * If this is exceeded dTSEC aborts transmission due to
+ * excessive collisions. The standard specifies the
+ * attempt limit to be 15.
+ * halfdup_coll_window:
+ * The number of bytes of the frame during which
+ * collisions may occur. The default value of 55
+ * corresponds to the frame byte at the end of the
+ * standard 512-bit slot time window. If collisions are
+ * detected after this byte, the late collision event is
+ * asserted and transmission of current frame is aborted.
+ * rx_drop_bcast:
+ * Discard broadcast frames. If set, all broadcast frames
+ * will be discarded by dTSEC.
+ * rx_short_frm:
+ * Accept short frames. If set, dTSEC will accept frames
+ * of length 14..63 bytes.
+ * rx_len_check:
+ * Length check for received frames. If set, the MAC
+ * checks the frame's length field on receive to ensure it
+ * matches the actual data field length. This only works
+ * for received frames with length field less than 1500.
+ * No check is performed for larger frames.
+ * tx_pad_crc:
+ * Pad and append CRC. If set, the MAC pads all
+ * transmitted short frames and appends a CRC to every
+ * frame regardless of padding requirement.
+ * tx_crc:
+ * Transmission CRC enable. If set, the MAC appends a CRC
+ * to all frames. If frames presented to the MAC have a
+ * valid length and contain a valid CRC, tx_crc should be
+ * reset.
+ * This field is ignored if tx_pad_crc is set.
+ * rx_ctrl_acc:
+ * Control frame accept. If set, this overrides 802.3
+ * standard control frame behavior, and all Ethernet frames
+ * that have an ethertype of 0x8808 are treated as normal
+ * Ethernet frames and passed up to the packet interface on
+ * a DA match. Received pause control frames are passed to
+ * the packet interface only if Rx flow control is also
+ * disabled. See fman_dtsec_handle_rx_pause() function.
+ * tx_pause_time:
+ * Transmit pause time value. This pause value is used as
+ * part of the pause frame to be sent when a transmit pause
+ * frame is initiated. If set to 0 this disables
+ * transmission of pause frames.
+ * rx_preamble:
+ * Receive preamble enable. If set, the MAC recovers the
+ * received Ethernet 7-byte preamble and passes it to the
+ * packet interface at the start of each received frame.
+ * This field should be reset for internal MAC loop-back
+ * mode.
+ * tx_preamble: User defined preamble enable for transmitted frames.
+ * If set, a user-defined preamble must passed to the MAC
+ * and it is transmitted instead of the standard preamble.
+ * preamble_len:
+ * Length, in bytes, of the preamble field preceding each
+ * Ethernet start-of-frame delimiter byte. The default
+ * value of 0x7 should be used in order to guarantee
+ * reliable operation with IEEE 802.3 compliant hardware.
+ * rx_prepend:
+ * Packet alignment padding length. The specified number
+ * of bytes (1-31) of zero padding are inserted before the
+ * start of each received frame. For Ethernet, where
+ * optional preamble extraction is enabled, the padding
+ * appears before the preamble, otherwise the padding
+ * precedes the layer 2 header.
+ *
+ * This structure contains basic dTSEC configuration and must be passed to
+ * fman_dtsec_init() function. A default set of configuration values can be
+ * obtained by calling fman_dtsec_defconfig().
+ */
+struct dtsec_cfg {
+ bool halfdup_on;
+ bool halfdup_alt_backoff_en;
+ bool halfdup_excess_defer;
+ bool halfdup_no_backoff;
+ bool halfdup_bp_no_backoff;
+ uint8_t halfdup_alt_backoff_val;
+ uint16_t halfdup_retransmit;
+ uint16_t halfdup_coll_window;
+ bool rx_drop_bcast;
+ bool rx_short_frm;
+ bool rx_len_check;
+ bool tx_pad_crc;
+ bool tx_crc;
+ bool rx_ctrl_acc;
+ unsigned short tx_pause_time;
+ unsigned short tbipa;
+ bool ptp_tsu_en;
+ bool ptp_exception_en;
+ bool rx_preamble;
+ bool tx_preamble;
+ unsigned char preamble_len;
+ unsigned char rx_prepend;
+ bool loopback;
+ bool rx_time_stamp_en;
+ bool tx_time_stamp_en;
+ bool rx_flow;
+ bool tx_flow;
+ bool rx_group_hash_exd;
+ bool rx_promisc;
+ uint8_t tbi_phy_addr;
+ uint16_t tx_pause_time_extd;
+ uint16_t maximum_frame;
+ uint32_t non_back_to_back_ipg1;
+ uint32_t non_back_to_back_ipg2;
+ uint32_t min_ifg_enforcement;
+ uint32_t back_to_back_ipg;
+ bool wake_on_lan;
+};
+
+/*fman_dtsec_defconfig() - Get default dTSEC configuration
+ *cfg: pointer to configuration structure.
+ *
+ *Call this function to obtain a default set of configuration values for
+ *initializing dTSEC. The user can overwrite any of the values before calling
+ *fman_dtsec_init(), if specific configuration needs to be applied.
+ */
+void fman_dtsec_defconfig(struct dtsec_cfg *cfg);
+
+/*fman_dtsec_init() - Init dTSEC hardware block
+ *regs: Pointer to dTSEC register block
+ *cfg: dTSEC configuration data
+ *iface_mode: dTSEC interface mode, the type of MAC - PHY interface.
+ *iface_speed: 1G or 10G
+ *macaddr: MAC station address to be assigned to the device
+ *fm_rev_maj: major rev number
+ *fm_rev_min: minor rev number
+ *exceptions_mask: initial exceptions mask
+ *This function initializes dTSEC and applies basic configuration.
+ *
+ *dTSEC initialization sequence:
+ *Before enabling Rx/Tx call dtsec_set_address() to set MAC address,
+ *fman_dtsec_adjust_link() to configure interface speed and duplex and finally
+ *dtsec_enable_tx()/dtsec_enable_rx() to start transmission and reception.
+ *
+ *Returns: 0 if successful, an error code otherwise.
+ */
+int fman_dtsec_init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
+ enum enet_interface iface_mode,
+ enum enet_speed iface_speed,
+ uint8_t *macaddr, uint8_t fm_rev_maj,
+ uint8_t fm_rev_min, uint32_t exception_mask);
+
+/*fman_dtsec_enable() - Enable dTSEC Tx and Tx
+ *regs: Pointer to dTSEC register block
+ *apply_rx: enable rx side
+ *apply_tx: enable tx side
+ *This function resets Tx and Rx graceful stop bit and enables dTSEC Tx and Rx.
+ */
+void fman_dtsec_enable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+/*fman_dtsec_disable() - Disable dTSEC Tx and Rx
+ *regs: Pointer to dTSEC register block
+ *apply_rx: disable rx side
+ *apply_tx: disable tx side
+ *This function disables Tx and Rx in dTSEC.
+ */
+void fman_dtsec_disable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+/*fman_dtsec_get_revision() - Get dTSEC hardware revision
+ *regs: Pointer to dTSEC register block
+ *Returns dtsec_id content
+ *Call this function to obtain the dTSEC hardware version.
+ */
+uint32_t fman_dtsec_get_revision(struct dtsec_regs __iomem *regs);
+
+/*fman_dtsec_set_mac_address() - Set MAC station address
+ *regs: Pointer to dTSEC register block
+ *macaddr: MAC address array
+ *This function sets MAC station address. To enable unicast reception call
+ *this after fman_dtsec_init(). While promiscuous mode is disabled dTSEC will
+ *match the destination address of received unicast frames against this
+ *address.
+ */
+void fman_dtsec_set_mac_address(struct dtsec_regs __iomem *regs,
+ uint8_t *macaddr);
+
+/*fman_dtsec_get_mac_address() - Query MAC station address
+ *regs: Pointer to dTSEC register block
+ *macaddr: MAC address array
+ */
+void fman_dtsec_get_mac_address(struct dtsec_regs __iomem *regs,
+ uint8_t *macaddr);
+
+/*fman_dtsec_set_uc_promisc() - Sets unicast promiscuous mode
+ *regs: Pointer to dTSEC register block
+ *enable: Enable unicast promiscuous mode
+ *Use this function to enable/disable dTSEC L2 address filtering. If the
+ *address filtering is disabled all unicast packets are accepted.
+ *To set dTSEC in promiscuous mode call both fman_dtsec_set_uc_promisc() and
+ *fman_dtsec_set_mc_promisc() to disable filtering for both unicast and
+ *multicast addresses.
+ */
+void fman_dtsec_set_uc_promisc(struct dtsec_regs __iomem *regs, bool enable);
+
+/*fman_dtsec_adjust_link() - Adjust dTSEC speed/duplex settings
+ *regs: Pointer to dTSEC register block
+ *iface_mode: dTSEC interface mode
+ *speed: Link speed
+ *full_dx: True for full-duplex, false for half-duplex.
+ *This function configures the MAC to function and the desired rates. Use it
+ *to configure dTSEC after fman_dtsec_init() and whenever the link speed
+ *changes (for instance following PHY auto-negociation).
+ *Returns: 0 if successful, an error code otherwise.
+ */
+int fman_dtsec_adjust_link(struct dtsec_regs __iomem *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx);
+
+/*fman_dtsec_set_max_frame_len() - Set max frame length
+ *regs: Pointer to dTSEC register block
+ *length: Max frame length.
+ *Sets maximum frame length for received and transmitted frames. Frames that
+ *exceeds this length are truncated.
+ */
+void fman_dtsec_set_max_frame_len(struct dtsec_regs __iomem *regs,
+ uint16_t length);
+
+/*fman_dtsec_get_max_frame_len() - Query max frame length
+ *regs: Pointer to dTSEC register block
+ *Returns: the current value of the maximum frame length.
+ */
+uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs __iomem *regs);
+
+/*fman_dtsec_handle_rx_pause() - Configure pause frame handling
+ *regs: Pointer to dTSEC register block
+ *en: Enable pause frame handling in dTSEC
+ *If enabled, dTSEC will handle pause frames internally. This must be disabled
+ *if dTSEC is set in half-duplex mode.
+ *If pause frame handling is disabled and &dtsec_cfg.rx_ctrl_acc is set, pause
+ *frames will be transferred to the packet interface just like regular Ethernet
+ *frames.
+ */
+void fman_dtsec_handle_rx_pause(struct dtsec_regs __iomem *regs, bool en);
+
+/*fman_dtsec_set_tx_pause_frames() - Configure Tx pause time
+ *regs: Pointer to dTSEC register block
+ *time: Time value included in pause frames
+ *Call this function to set the time value used in transmitted pause frames.
+ *If time is 0, transmission of pause frames is disabled
+ */
+void fman_dtsec_set_tx_pause_frames(struct dtsec_regs __iomem *regs,
+ uint16_t time);
+
+/*fman_dtsec_ack_event() - Acknowledge handled events
+ *regs: Pointer to dTSEC register block
+ *ev_mask: Events to acknowledge
+ *After handling events signaled by dTSEC in either polling or interrupt mode,
+ *call this function to reset the associated status bits in dTSEC event
+ *register.
+ */
+void fman_dtsec_ack_event(struct dtsec_regs __iomem *regs, uint32_t ev_mask);
+
+/*fman_dtsec_get_event() - Returns currently asserted events
+ *regs: Pointer to dTSEC register block
+ *ev_mask: Mask of relevant events
+ *Call this function to obtain a bit-mask of events that are currently asserted
+ *in dTSEC, taken from IEVENT register.
+ *Returns: a bit-mask of events asserted in dTSEC.
+ */
+uint32_t fman_dtsec_get_event(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask);
+
+/*fman_dtsec_get_interrupt_mask() - Returns a bit-mask of enabled interrupts
+ *regs: Pointer to dTSEC register block
+ *Call this function to obtain a bit-mask of enabled interrupts
+ *in dTSEC, taken from IMASK register.
+ *Returns: a bit-mask of enabled interrupts in dTSEC.
+ */
+uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs __iomem *regs);
+
+void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs __iomem *regs);
+
+void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs __iomem *regs);
+
+/*fman_dtsec_disable_interrupt() - Disables interrupts for the specified events
+ *regs: Pointer to dTSEC register block
+ *ev_mask: Mask of relevant events
+ *Call this function to disable interrupts in dTSEC for the specified events.
+ *To enable interrupts use fman_dtsec_enable_interrupt().
+ */
+void fman_dtsec_disable_interrupt(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask);
+
+/*fman_dtsec_enable_interrupt() - Enable interrupts for the specified events
+ *regs: Pointer to dTSEC register block
+ *ev_mask: Mask of relevant events
+ *Call this function to enable interrupts in dTSEC for the specified events.
+ *To disable interrupts use fman_dtsec_disable_interrupt().
+ */
+void fman_dtsec_enable_interrupt(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask);
+
+/*fman_dtsec_set_bucket() - Enables/disables a filter bucket
+ *regs: Pointer to dTSEC register block
+ *bucket: Bucket index
+ *enable: true/false to enable/disable this bucket
+ *This function enables or disables the specified bucket. Enabling a bucket
+ *associated with an address configures dTSEC to accept received packets
+ *with that destination address.
+ *Multiple addresses may be associated with the same bucket. Disabling a
+ *bucket will affect all addresses associated with that bucket. A bucket that
+ *is enabled requires further filtering and verification in the upper layers
+ */
+void fman_dtsec_set_bucket(struct dtsec_regs __iomem *regs, int bucket,
+ bool enable);
+
+/*fman_dtsec_set_mc_promisc() - Set multicast promiscuous mode
+ *regs: Pointer to dTSEC register block
+ *enable: Enable multicast promiscuous mode
+ *Call this to enable/disable L2 address filtering for multicast packets.
+ */
+void fman_dtsec_set_mc_promisc(struct dtsec_regs __iomem *regs, bool enable);
+
+/*fman_dtsec_get_clear_carry_regs() - Read and clear carry bits
+ * (CAR1-2 registers)
+ *regs: Pointer to dTSEC register block
+ *car1: car1 register value
+ *car2: car2 register value
+ *When set, the carry bits signal that an overflow occurred on the
+ *corresponding counters.
+ *Note that the carry bits (CAR1-2 registers) will assert the
+ *%DTSEC_IEVENT_MSRO interrupt if unmasked (via CAM1-2 regs).
+ *Returns: true if overflow occurred, otherwise - false
+ */
+bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs __iomem *regs,
+ uint32_t *car1, uint32_t *car2);
+
+uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs __iomem *regs);
+
+void fman_dtsec_start_tx(struct dtsec_regs __iomem *regs);
+void fman_dtsec_start_rx(struct dtsec_regs __iomem *regs);
+void fman_dtsec_stop_tx(struct dtsec_regs __iomem *regs);
+void fman_dtsec_stop_rx(struct dtsec_regs __iomem *regs);
+uint32_t fman_dtsec_get_rctrl(struct dtsec_regs __iomem *regs);
+
+#endif /* __FSL_FMAN_DTSEC_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h
new file mode 100644
index 0000000..4425910
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h
@@ -0,0 +1,103 @@
+/*
+ * 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_DTSEC_MII_ACC_H
+#define __FSL_FMAN_DTSEC_MII_ACC_H
+
+#include "common/general.h"
+
+/* MII Management Configuration Register */
+#define MIIMCFG_RESET_MGMT 0x80000000
+#define MIIMCFG_MGNTCLK_MASK 0x00000007
+#define MIIMCFG_MGNTCLK_SHIFT 0
+
+/* MII Management Command Register */
+#define MIIMCOM_SCAN_CYCLE 0x00000002
+#define MIIMCOM_READ_CYCLE 0x00000001
+
+/* MII Management Address Register */
+#define MIIMADD_PHY_ADDR_SHIFT 8
+#define MIIMADD_PHY_ADDR_MASK 0x00001f00
+
+#define MIIMADD_REG_ADDR_SHIFT 0
+#define MIIMADD_REG_ADDR_MASK 0x0000001f
+
+/* MII Management Indicator Register */
+#define MIIMIND_BUSY 0x00000001
+
+/* PHY Control Register */
+#define PHY_CR_PHY_RESET 0x8000
+#define PHY_CR_LOOPBACK 0x4000
+#define PHY_CR_SPEED0 0x2000
+#define PHY_CR_ANE 0x1000
+#define PHY_CR_RESET_AN 0x0200
+#define PHY_CR_FULLDUPLEX 0x0100
+#define PHY_CR_SPEED1 0x0040
+
+#define PHY_TBICON_SRESET 0x8000
+#define PHY_TBICON_SPEED2 0x0020
+#define PHY_TBICON_CLK_SEL 0x0020
+#define PHY_TBIANA_SGMII 0x4001
+#define PHY_TBIANA_1000X 0x01a0
+/* register map */
+
+/* MII Configuration Control Memory Map Registers */
+struct dtsec_mii_reg {
+ uint32_t reserved1[72];
+ uint32_t miimcfg; /* MII Mgmt:configuration */
+ uint32_t miimcom; /* MII Mgmt:command */
+ uint32_t miimadd; /* MII Mgmt:address */
+ uint32_t miimcon; /* MII Mgmt:control 3 */
+ uint32_t miimstat; /* MII Mgmt:status */
+ uint32_t miimind; /* MII Mgmt:indicators */
+};
+
+/* dTSEC MII API */
+
+/* functions to access the mii registers for phy configuration.
+ * this functionality may not be available for all dtsecs in the system.
+ * consult the reference manual for details
+ **/
+void fman_dtsec_mii_reset(struct dtsec_mii_reg __iomem *regs);
+/* frequency is in MHz.
+ * note that dtsec clock is 1/2 of fman clock
+ **/
+void fman_dtsec_mii_init(struct dtsec_mii_reg __iomem *regs,
+ uint16_t dtsec_freq);
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg __iomem *regs,
+ uint8_t addr,
+ uint8_t reg, uint16_t data, uint16_t dtsec_freq);
+
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg __iomem *regs,
+ uint8_t addr,
+ uint8_t reg, uint16_t *data, uint16_t dtsec_freq);
+
+#endif /* __FSL_FMAN_DTSEC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
new file mode 100644
index 0000000..c589025
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
@@ -0,0 +1,453 @@
+/*
+ * 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_MEMAC_H
+#define __FSL_FMAN_MEMAC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+/* Num of additional exact match MAC adr regs */
+#define MEMAC_NUM_OF_PADDRS 7
+
+/* Control and Configuration Register (COMMAND_CONFIG) */
+/* 00 Magic Packet detection */
+#define CMD_CFG_MG 0x80000000
+/* 07 Rx low power indication */
+#define CMD_CFG_REG_LOWP_RXETY 0x01000000
+/* 08 Tx Low Power Idle Enable */
+#define CMD_CFG_TX_LOWP_ENA 0x00800000
+/* 10 Disable SFD check */
+#define CMD_CFG_SFD_ANY 0x00200000
+/* 12 Enable PFC */
+#define CMD_CFG_PFC_MODE 0x00080000
+/* 14 Payload length check disable */
+#define CMD_CFG_NO_LEN_CHK 0x00020000
+/* 15 Force idle generation */
+#define CMD_CFG_SEND_IDLE 0x00010000
+/* 18 Control frame rx enable */
+#define CMD_CFG_CNT_FRM_EN 0x00002000
+/* 19 S/W Reset, self clearing bit */
+#define CMD_CFG_SW_RESET 0x00001000
+/* 20 Enable Tx padding of frames */
+#define CMD_CFG_TX_PAD_EN 0x00000800
+/* 21 XGMII/GMII loopback enable */
+#define CMD_CFG_LOOPBACK_EN 0x00000400
+/* 22 Tx source MAC addr insertion */
+#define CMD_CFG_TX_ADDR_INS 0x00000200
+/* 23 Ignore Pause frame quanta */
+#define CMD_CFG_PAUSE_IGNORE 0x00000100
+/* 24 Terminate/frwd Pause frames */
+#define CMD_CFG_PAUSE_FWD 0x00000080
+/* 25 Terminate/frwd CRC of frames */
+#define CMD_CFG_CRC_FWD 0x00000040
+/* 26 Frame padding removal */
+#define CMD_CFG_PAD_EN 0x00000020
+/* 27 Promiscuous operation enable */
+#define CMD_CFG_PROMIS_EN 0x00000010
+/* 28 WAN mode enable */
+#define CMD_CFG_WAN_MODE 0x00000008
+/* 30 MAC receive path enable */
+#define CMD_CFG_RX_EN 0x00000002
+/* 31 MAC transmit path enable */
+#define CMD_CFG_TX_EN 0x00000001
+
+/* Transmit FIFO Sections Register (TX_FIFO_SECTIONS) */
+#define TX_FIFO_SECTIONS_TX_EMPTY_MASK 0xFFFF0000
+#define TX_FIFO_SECTIONS_TX_AVAIL_MASK 0x0000FFFF
+#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G 0x00400000
+#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G 0x00100000
+#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G 0x00360000
+#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G 0x00040000
+#define TX_FIFO_SECTIONS_TX_AVAIL_10G 0x00000019
+#define TX_FIFO_SECTIONS_TX_AVAIL_1G 0x00000020
+#define TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G 0x00000060
+
+#define GET_TX_EMPTY_DEFAULT_VALUE(_val) \
+do { \
+ _val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \
+ ((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G) :\
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G));\
+} while (0)
+
+#define GET_TX_EMPTY_PFC_VALUE(_val) \
+do { \
+ _val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \
+ ((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G) : \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G)); \
+} while (0)
+
+/* Interface Mode Register (IF_MODE) */
+/* 30-31 Mask on i/f mode bits */
+#define IF_MODE_MASK 0x00000003
+/* 30-31 XGMII (10G) interface */
+#define IF_MODE_XGMII 0x00000000
+/* 30-31 GMII (1G) interface */
+#define IF_MODE_GMII 0x00000002
+#define IF_MODE_RGMII 0x00000004
+#define IF_MODE_RGMII_AUTO 0x00008000
+#define IF_MODE_RGMII_1000 0x00004000 /* 10 - 1000Mbps RGMII */
+#define IF_MODE_RGMII_100 0x00000000 /* 00 - 100Mbps RGMII */
+#define IF_MODE_RGMII_10 0x00002000 /* 01 - 10Mbps RGMII */
+#define IF_MODE_RGMII_SP_MASK 0x00006000 /* Setsp mask bits */
+#define IF_MODE_RGMII_FD 0x00001000 /* Full duplex RGMII */
+#define IF_MODE_HD 0x00000040 /* Half duplex operation */
+
+/* Hash table Control Register (HASHTABLE_CTRL) */
+#define HASH_CTRL_MCAST_SHIFT 26
+/* 23 Mcast frame rx for hash */
+#define HASH_CTRL_MCAST_EN 0x00000100
+/* 26-31 Hash table address code */
+#define HASH_CTRL_ADDR_MASK 0x0000003F
+/* MAC mcast indication */
+#define GROUP_ADDRESS 0x0000010000000000LL
+#define HASH_TABLE_SIZE 64 /* Hash tbl size */
+
+/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
+#define MEMAC_TX_IPG_LENGTH_MASK 0x0000003F
+
+/* Statistics Configuration Register (STATN_CONFIG) */
+#define STATS_CFG_CLR 0x00000004 /* 29 Reset all counters */
+#define STATS_CFG_CLR_ON_RD 0x00000002 /* 30 Clear on read */
+/* 31 Saturate at the maximum val */
+#define STATS_CFG_SATURATE 0x00000001
+
+/* Interrupt Mask Register (IMASK) */
+/* 1 Magic pkt detect indication */
+#define MEMAC_IMASK_MGI 0x40000000
+/* 2 Timestamp FIFO ECC error evnt */
+#define MEMAC_IMASK_TSECC_ER 0x20000000
+/* 6 Transmit frame ECC error evnt */
+#define MEMAC_IMASK_TECC_ER 0x02000000
+/* 7 Receive frame ECC error evnt */
+#define MEMAC_IMASK_RECC_ER 0x01000000
+
+#define MEMAC_ALL_ERRS_IMASK \
+ ((uint32_t)(MEMAC_IMASK_TSECC_ER | \
+ MEMAC_IMASK_TECC_ER | \
+ MEMAC_IMASK_RECC_ER | \
+ MEMAC_IMASK_MGI))
+
+/* PCS (XG). Link sync (G) */
+#define MEMAC_IEVNT_PCS 0x80000000
+/* Auto-negotiation */
+#define MEMAC_IEVNT_AN 0x40000000
+/* Link Training/New page */
+#define MEMAC_IEVNT_LT 0x20000000
+/* Magic pkt detection */
+#define MEMAC_IEVNT_MGI 0x00004000
+/* Timestamp FIFO ECC error */
+#define MEMAC_IEVNT_TS_ECC_ER 0x00002000
+/* Rx FIFO overflow */
+#define MEMAC_IEVNT_RX_FIFO_OVFL 0x00001000
+/* Tx FIFO underflow */
+#define MEMAC_IEVNT_TX_FIFO_UNFL 0x00000800
+/* Tx FIFO overflow */
+#define MEMAC_IEVNT_TX_FIFO_OVFL 0x00000400
+/* Tx frame ECC error */
+#define MEMAC_IEVNT_TX_ECC_ER 0x00000200
+/* Rx frame ECC error */
+#define MEMAC_IEVNT_RX_ECC_ER 0x00000100
+/* Link Interruption flt */
+#define MEMAC_IEVNT_LI_FAULT 0x00000080
+/* Rx FIFO empty */
+#define MEMAC_IEVNT_RX_EMPTY 0x00000040
+/* Tx FIFO empty */
+#define MEMAC_IEVNT_TX_EMPTY 0x00000020
+/* Low Power Idle */
+#define MEMAC_IEVNT_RX_LOWP 0x00000010
+/* Phy loss of signal */
+#define MEMAC_IEVNT_PHY_LOS 0x00000004
+/* Remote fault (XGMII) */
+#define MEMAC_IEVNT_REM_FAULT 0x00000002
+/* Local fault (XGMII) */
+#define MEMAC_IEVNT_LOC_FAULT 0x00000001
+
+#define DEFAULT_PAUSE_QUANTA 0xf000
+#define DEFAULT_FRAME_LENGTH 0x600
+#define DEFAULT_TX_IPG_LENGTH 12
+
+/**
+ * memory map
+ **/
+
+struct mac_addr {
+ /* Lower 32 bits of 48-bit MAC address */
+ uint32_t mac_addr_l;
+ /* Upper 16 bits of 48-bit MAC address */
+ uint32_t mac_addr_u;
+};
+
+struct memac_regs {
+ /* General Control and Status */
+ uint32_t res0000[2];
+ /* 0x008 Ctrl and cfg */
+ uint32_t command_config;
+ /* 0x00C-0x010 MAC_ADDR_0...1 */
+ struct mac_addr mac_addr0;
+ /* 0x014 Max frame length */
+ uint32_t maxfrm;
+ uint32_t res0018[1];
+ /* Receive FIFO configuration reg */
+ uint32_t rx_fifo_sections;
+ /* Transmit FIFO configuration reg */
+ uint32_t tx_fifo_sections;
+ uint32_t res0024[2];
+ /* 0x02C Hash table control */
+ uint32_t hashtable_ctrl;
+ uint32_t res0030[4];
+ /* 0x040 Interrupt event */
+ uint32_t ievent;
+ /* 0x044 Transmitter inter-packet-gap */
+ uint32_t tx_ipg_length;
+ uint32_t res0048;
+ /* 0x04C Interrupt mask */
+ uint32_t imask;
+ uint32_t res0050;
+ /* 0x054 Pause quanta */
+ uint32_t pause_quanta[4];
+ /* 0x064 Pause quanta threshold */
+ uint32_t pause_thresh[4];
+ /* 0x074 Receive pause status */
+ uint32_t rx_pause_status;
+ uint32_t res0078[2];
+ /* 0x80-0x0B4 mac padr */
+ struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS];
+ /* 0x0B8 Low Power Wakeup Timer */
+ uint32_t lpwake_timer;
+ /* 0x0BC Transmit EEE Low Power Timer */
+ uint32_t sleep_timer;
+ uint32_t res00c0[8];
+ /* 0x0E0 Statistics configuration */
+ uint32_t statn_config;
+ uint32_t res00e4[7];
+ /* Rx Statistics Counter */
+ uint32_t reoct_l;
+ uint32_t reoct_u;
+ uint32_t roct_l;
+ uint32_t roct_u;
+ uint32_t raln_l;
+ uint32_t raln_u;
+ uint32_t rxpf_l;
+ uint32_t rxpf_u;
+ uint32_t rfrm_l;
+ uint32_t rfrm_u;
+ uint32_t rfcs_l;
+ uint32_t rfcs_u;
+ uint32_t rvlan_l;
+ uint32_t rvlan_u;
+ uint32_t rerr_l;
+ uint32_t rerr_u;
+ uint32_t ruca_l;
+ uint32_t ruca_u;
+ uint32_t rmca_l;
+ uint32_t rmca_u;
+ uint32_t rbca_l;
+ uint32_t rbca_u;
+ uint32_t rdrp_l;
+ uint32_t rdrp_u;
+ uint32_t rpkt_l;
+ uint32_t rpkt_u;
+ uint32_t rund_l;
+ uint32_t rund_u;
+ uint32_t r64_l;
+ uint32_t r64_u;
+ uint32_t r127_l;
+ uint32_t r127_u;
+ uint32_t r255_l;
+ uint32_t r255_u;
+ uint32_t r511_l;
+ uint32_t r511_u;
+ uint32_t r1023_l;
+ uint32_t r1023_u;
+ uint32_t r1518_l;
+ uint32_t r1518_u;
+ uint32_t r1519x_l;
+ uint32_t r1519x_u;
+ uint32_t rovr_l;
+ uint32_t rovr_u;
+ uint32_t rjbr_l;
+ uint32_t rjbr_u;
+ uint32_t rfrg_l;
+ uint32_t rfrg_u;
+ uint32_t rcnp_l;
+ uint32_t rcnp_u;
+ uint32_t rdrntp_l;
+ uint32_t rdrntp_u;
+ uint32_t res01d0[12];
+ /* Tx Statistics Counter */
+ uint32_t teoct_l;
+ uint32_t teoct_u;
+ uint32_t toct_l;
+ uint32_t toct_u;
+ uint32_t res0210[2];
+ uint32_t txpf_l;
+ uint32_t txpf_u;
+ uint32_t tfrm_l;
+ uint32_t tfrm_u;
+ uint32_t tfcs_l;
+ uint32_t tfcs_u;
+ uint32_t tvlan_l;
+ uint32_t tvlan_u;
+ uint32_t terr_l;
+ uint32_t terr_u;
+ uint32_t tuca_l;
+ uint32_t tuca_u;
+ uint32_t tmca_l;
+ uint32_t tmca_u;
+ uint32_t tbca_l;
+ uint32_t tbca_u;
+ uint32_t res0258[2];
+ uint32_t tpkt_l;
+ uint32_t tpkt_u;
+ uint32_t tund_l;
+ uint32_t tund_u;
+ uint32_t t64_l;
+ uint32_t t64_u;
+ uint32_t t127_l;
+ uint32_t t127_u;
+ uint32_t t255_l;
+ uint32_t t255_u;
+ uint32_t t511_l;
+ uint32_t t511_u;
+ uint32_t t1023_l;
+ uint32_t t1023_u;
+ uint32_t t1518_l;
+ uint32_t t1518_u;
+ uint32_t t1519x_l;
+ uint32_t t1519x_u;
+ uint32_t res02a8[6];
+ uint32_t tcnp_l;
+ uint32_t tcnp_u;
+ uint32_t res02c8[14];
+ /* Line Interface Control */
+ uint32_t if_mode; /* 0x300 Interface Mode Control */
+ uint32_t if_status; /* 0x304 Interface Status */
+ uint32_t res0308[14];
+ /* HiGig/2 */
+ uint32_t hg_config; /* 0x340 Control and cfg */
+ uint32_t res0344[3];
+ uint32_t hg_pause_quanta; /* 0x350 Pause quanta */
+ uint32_t res0354[3];
+ uint32_t hg_pause_thresh; /* 0x360 Pause quanta threshold */
+ uint32_t res0364[3];
+ uint32_t hgrx_pause_status; /* 0x370 Receive pause status */
+ uint32_t hg_fifos_status; /* 0x374 fifos status */
+ uint32_t rhm; /* 0x378 rx messages counter */
+ uint32_t thm; /* 0x37C tx messages counter */
+};
+
+struct memac_cfg {
+ bool reset_on_init;
+ bool rx_error_discard;
+ bool pause_ignore;
+ bool pause_forward_enable;
+ bool no_length_check_enable;
+ bool cmd_frame_enable;
+ bool send_idle_enable;
+ bool wan_mode_enable;
+ bool promiscuous_mode_enable;
+ bool tx_addr_ins_enable;
+ bool loopback_enable;
+ bool lgth_check_nostdr;
+ bool time_stamp_enable;
+ bool pad_enable;
+ bool phy_tx_ena_on;
+ bool rx_sfd_any;
+ bool rx_pbl_fwd;
+ bool tx_pbl_fwd;
+ bool debug_mode;
+ bool wake_on_lan;
+ uint16_t max_frame_length;
+ uint16_t pause_quanta;
+ uint32_t tx_ipg_length;
+};
+
+/**
+*fman_memac_defconfig() - Get default MEMAC configuration
+*@cfg: pointer to configuration structure.
+ *
+*Call this function to obtain a default set of configuration values for
+*initializing MEMAC. The user can overwrite any of the values before calling
+*fman_memac_init(), if specific configuration needs to be applied.
+ */
+void fman_memac_defconfig(struct memac_cfg *cfg);
+
+int fman_memac_init(struct memac_regs __iomem *regs,
+ struct memac_cfg *cfg,
+ enum enet_interface enet_interface,
+ enum enet_speed enet_speed,
+ bool slow_10g_if,
+ uint32_t exceptions);
+
+void fman_memac_enable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+void fman_memac_disable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+void fman_memac_set_promiscuous(struct memac_regs __iomem *regs, bool val);
+
+void fman_memac_add_addr_in_paddr(struct memac_regs __iomem *regs,
+ uint8_t *adr, uint8_t paddr_num);
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs __iomem *regs,
+ uint8_t paddr_num);
+
+void fman_memac_set_tx_pause_frames(struct memac_regs __iomem *regs,
+ uint8_t priority, uint16_t pause_time,
+ uint16_t thresh_time);
+
+uint16_t fman_memac_get_max_frame_len(struct memac_regs __iomem *regs);
+
+void fman_memac_set_exception(struct memac_regs __iomem *regs, uint32_t val,
+ bool enable);
+
+void fman_memac_reset(struct memac_regs __iomem *regs);
+
+void fman_memac_set_hash_table(struct memac_regs __iomem *regs, uint32_t val);
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs __iomem *regs,
+ bool enable);
+
+uint32_t fman_memac_get_event(struct memac_regs __iomem *regs,
+ uint32_t ev_mask);
+
+void fman_memac_ack_event(struct memac_regs __iomem *regs, uint32_t ev_mask);
+
+uint32_t fman_memac_get_interrupt_mask(struct memac_regs __iomem *regs);
+
+void fman_memac_adjust_link(struct memac_regs __iomem *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx);
+
+#endif /*__FSL_FMAN_MEMAC_H*/
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h
new file mode 100644
index 0000000..ad18d6f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h
@@ -0,0 +1,76 @@
+/*
+ * 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_MEMAC_MII_ACC_H
+#define __FSL_FMAN_MEMAC_MII_ACC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+/* MII Management Registers */
+#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80
+#define MDIO_CFG_HOLD_MASK 0x0000001c
+#define MDIO_CFG_ENC45 0x00000040
+#define MDIO_CFG_READ_ERR 0x00000002
+#define MDIO_CFG_BSY 0x00000001
+
+#define MDIO_CTL_PHY_ADDR_SHIFT 5
+#define MDIO_CTL_READ 0x00008000
+
+#define MDIO_DATA_BSY 0x80000000
+
+/*MEMAC Internal PHY Registers - SGMII */
+#define PHY_SGMII_CR_PHY_RESET 0x8000
+#define PHY_SGMII_CR_RESET_AN 0x0200
+#define PHY_SGMII_CR_DEF_VAL 0x1140
+#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001
+#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0
+#define PHY_SGMII_IF_MODE_AN 0x0002
+#define PHY_SGMII_IF_MODE_SGMII 0x0001
+#define PHY_SGMII_IF_MODE_1000X 0x0000
+
+/*----------------------------------------------------*/
+/* MII Configuration Control Memory Map Registers */
+/*----------------------------------------------------*/
+struct memac_mii_access_mem_map {
+ uint32_t mdio_cfg; /* 0x030 */
+ uint32_t mdio_ctrl; /* 0x034 */
+ uint32_t mdio_data; /* 0x038 */
+ uint32_t mdio_addr; /* 0x03c */
+};
+
+int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t *data, enum enet_speed enet_speed);
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t data, enum enet_speed enet_speed);
+
+#endif /* __MAC_API_MEMAC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h
new file mode 100644
index 0000000..6f8d440
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h
@@ -0,0 +1,409 @@
+/*
+ * 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_TGEC_H
+#define __FSL_FMAN_TGEC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+
+/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
+#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
+
+/* Command and Configuration Register (COMMAND_CONFIG) */
+#define CMD_CFG_EN_TIMESTAMP 0x00100000
+#define CMD_CFG_TX_ADDR_INS_SEL 0x00080000
+#define CMD_CFG_NO_LEN_CHK 0x00020000
+#define CMD_CFG_SEND_IDLE 0x00010000
+#define CMD_CFG_RX_ER_DISC 0x00004000
+#define CMD_CFG_CMD_FRM_EN 0x00002000
+#define CMD_CFG_STAT_CLR 0x00001000
+#define CMD_CFG_LOOPBACK_EN 0x00000400
+#define CMD_CFG_TX_ADDR_INS 0x00000200
+#define CMD_CFG_PAUSE_IGNORE 0x00000100
+#define CMD_CFG_PAUSE_FWD 0x00000080
+#define CMD_CFG_PROMIS_EN 0x00000010
+#define CMD_CFG_WAN_MODE 0x00000008
+#define CMD_CFG_RX_EN 0x00000002
+#define CMD_CFG_TX_EN 0x00000001
+
+/* Interrupt Mask Register (IMASK) */
+#define TGEC_IMASK_MDIO_SCAN_EVENT 0x00010000
+#define TGEC_IMASK_MDIO_CMD_CMPL 0x00008000
+#define TGEC_IMASK_REM_FAULT 0x00004000
+#define TGEC_IMASK_LOC_FAULT 0x00002000
+#define TGEC_IMASK_TX_ECC_ER 0x00001000
+#define TGEC_IMASK_TX_FIFO_UNFL 0x00000800
+#define TGEC_IMASK_TX_FIFO_OVFL 0x00000400
+#define TGEC_IMASK_TX_ER 0x00000200
+#define TGEC_IMASK_RX_FIFO_OVFL 0x00000100
+#define TGEC_IMASK_RX_ECC_ER 0x00000080
+#define TGEC_IMASK_RX_JAB_FRM 0x00000040
+#define TGEC_IMASK_RX_OVRSZ_FRM 0x00000020
+#define TGEC_IMASK_RX_RUNT_FRM 0x00000010
+#define TGEC_IMASK_RX_FRAG_FRM 0x00000008
+#define TGEC_IMASK_RX_LEN_ER 0x00000004
+#define TGEC_IMASK_RX_CRC_ER 0x00000002
+#define TGEC_IMASK_RX_ALIGN_ER 0x00000001
+
+#define TGEC_EVENTS_MASK \
+ ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \
+ TGEC_IMASK_MDIO_CMD_CMPL | \
+ TGEC_IMASK_REM_FAULT | \
+ TGEC_IMASK_LOC_FAULT | \
+ TGEC_IMASK_TX_ECC_ER | \
+ TGEC_IMASK_TX_FIFO_UNFL | \
+ TGEC_IMASK_TX_FIFO_OVFL | \
+ TGEC_IMASK_TX_ER | \
+ TGEC_IMASK_RX_FIFO_OVFL | \
+ TGEC_IMASK_RX_ECC_ER | \
+ TGEC_IMASK_RX_JAB_FRM | \
+ TGEC_IMASK_RX_OVRSZ_FRM | \
+ TGEC_IMASK_RX_RUNT_FRM | \
+ TGEC_IMASK_RX_FRAG_FRM | \
+ TGEC_IMASK_RX_LEN_ER | \
+ TGEC_IMASK_RX_CRC_ER | \
+ TGEC_IMASK_RX_ALIGN_ER))
+
+/* Hashtable Control Register (HASHTABLE_CTRL) */
+#define TGEC_HASH_MCAST_SHIFT 23
+#define TGEC_HASH_MCAST_EN 0x00000200
+#define TGEC_HASH_ADR_MSK 0x000001ff
+
+#define DEFAULT_WAN_MODE_ENABLE false
+#define DEFAULT_PROMISCUOUS_MODE_ENABLE false
+#define DEFAULT_PAUSE_FORWARD_ENABLE false
+#define DEFAULT_PAUSE_IGNORE false
+#define DEFAULT_TX_ADDR_INS_ENABLE false
+#define DEFAULT_LOOPBACK_ENABLE false
+#define DEFAULT_CMD_FRAME_ENABLE false
+#define DEFAULT_RX_ERROR_DISCARD false
+#define DEFAULT_SEND_IDLE_ENABLE false
+#define DEFAULT_NO_LENGTH_CHECK_ENABLE true
+#define DEFAULT_LGTH_CHECK_NOSTDR false
+#define DEFAULT_TIME_STAMP_ENABLE false
+#define DEFAULT_TX_IPG_LENGTH 12
+#define DEFAULT_MAX_FRAME_LENGTH 0x600
+#define DEFAULT_PAUSE_QUANT 0xf000
+
+/**
+ * 10G memory map
+ **/
+struct tgec_regs {
+ uint32_t tgec_id; /* 0x000 Controller ID */
+ uint32_t reserved001[1]; /* 0x004 */
+ uint32_t command_config; /* 0x008 Control and configuration */
+ uint32_t mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */
+ uint32_t mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */
+ uint32_t maxfrm; /* 0x014 Maximum frame length */
+ uint32_t pause_quant; /* 0x018 Pause quanta */
+ uint32_t rx_fifo_sections; /* 0x01c */
+ uint32_t tx_fifo_sections; /* 0x020 */
+ uint32_t rx_fifo_almost_f_e; /* 0x024 */
+ uint32_t tx_fifo_almost_f_e; /* 0x028 */
+ uint32_t hashtable_ctrl; /* 0x02c Hash table control */
+ uint32_t mdio_cfg_status; /* 0x030 */
+ uint32_t mdio_command; /* 0x034 */
+ uint32_t mdio_data; /* 0x038 */
+ uint32_t mdio_regaddr; /* 0x03c */
+ uint32_t status; /* 0x040 */
+ uint32_t tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */
+ uint32_t mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */
+ uint32_t mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */
+ uint32_t rx_fifo_ptr_rd; /* 0x050 */
+ uint32_t rx_fifo_ptr_wr; /* 0x054 */
+ uint32_t tx_fifo_ptr_rd; /* 0x058 */
+ uint32_t tx_fifo_ptr_wr; /* 0x05c */
+ uint32_t imask; /* 0x060 Interrupt mask */
+ uint32_t ievent; /* 0x064 Interrupt event */
+ uint32_t udp_port; /* 0x068 Defines a UDP Port number */
+ uint32_t type_1588v2; /* 0x06c Type field for 1588v2 */
+ uint32_t reserved070[4]; /* 0x070 */
+ /*10Ge Statistics Counter */
+ uint32_t tfrm_u; /* 80 aFramesTransmittedOK */
+ uint32_t tfrm_l; /* 84 aFramesTransmittedOK */
+ uint32_t rfrm_u; /* 88 aFramesReceivedOK */
+ uint32_t rfrm_l; /* 8c aFramesReceivedOK */
+ uint32_t rfcs_u; /* 90 aFrameCheckSequenceErrors */
+ uint32_t rfcs_l; /* 94 aFrameCheckSequenceErrors */
+ uint32_t raln_u; /* 98 aAlignmentErrors */
+ uint32_t raln_l; /* 9c aAlignmentErrors */
+ uint32_t txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */
+ uint32_t txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */
+ uint32_t rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */
+ uint32_t rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */
+ uint32_t rlong_u; /* B0 aFrameTooLongErrors */
+ uint32_t rlong_l; /* B4 aFrameTooLongErrors */
+ uint32_t rflr_u; /* B8 aInRangeLengthErrors */
+ uint32_t rflr_l; /* Bc aInRangeLengthErrors */
+ uint32_t tvlan_u; /* C0 VLANTransmittedOK */
+ uint32_t tvlan_l; /* C4 VLANTransmittedOK */
+ uint32_t rvlan_u; /* C8 VLANReceivedOK */
+ uint32_t rvlan_l; /* Cc VLANReceivedOK */
+ uint32_t toct_u; /* D0 if_out_octets */
+ uint32_t toct_l; /* D4 if_out_octets */
+ uint32_t roct_u; /* D8 if_in_octets */
+ uint32_t roct_l; /* Dc if_in_octets */
+ uint32_t ruca_u; /* E0 if_in_ucast_pkts */
+ uint32_t ruca_l; /* E4 if_in_ucast_pkts */
+ uint32_t rmca_u; /* E8 ifInMulticastPkts */
+ uint32_t rmca_l; /* Ec ifInMulticastPkts */
+ uint32_t rbca_u; /* F0 ifInBroadcastPkts */
+ uint32_t rbca_l; /* F4 ifInBroadcastPkts */
+ uint32_t terr_u; /* F8 if_out_errors */
+ uint32_t terr_l; /* Fc if_out_errors */
+ uint32_t reserved100[2]; /* 100-108 */
+ uint32_t tuca_u; /* 108 if_out_ucast_pkts */
+ uint32_t tuca_l; /* 10c if_out_ucast_pkts */
+ uint32_t tmca_u; /* 110 ifOutMulticastPkts */
+ uint32_t tmca_l; /* 114 ifOutMulticastPkts */
+ uint32_t tbca_u; /* 118 ifOutBroadcastPkts */
+ uint32_t tbca_l; /* 11c ifOutBroadcastPkts */
+ uint32_t rdrp_u; /* 120 etherStatsDropEvents */
+ uint32_t rdrp_l; /* 124 etherStatsDropEvents */
+ uint32_t reoct_u; /* 128 etherStatsOctets */
+ uint32_t reoct_l; /* 12c etherStatsOctets */
+ uint32_t rpkt_u; /* 130 etherStatsPkts */
+ uint32_t rpkt_l; /* 134 etherStatsPkts */
+ uint32_t trund_u; /* 138 etherStatsUndersizePkts */
+ uint32_t trund_l; /* 13c etherStatsUndersizePkts */
+ uint32_t r64_u; /* 140 etherStatsPkts64Octets */
+ uint32_t r64_l; /* 144 etherStatsPkts64Octets */
+ uint32_t r127_u; /* 148 etherStatsPkts65to127Octets */
+ uint32_t r127_l; /* 14c etherStatsPkts65to127Octets */
+ uint32_t r255_u; /* 150 etherStatsPkts128to255Octets */
+ uint32_t r255_l; /* 154 etherStatsPkts128to255Octets */
+ uint32_t r511_u; /* 158 etherStatsPkts256to511Octets */
+ uint32_t r511_l; /* 15c etherStatsPkts256to511Octets */
+ uint32_t r1023_u; /* 160 etherStatsPkts512to1023Octets */
+ uint32_t r1023_l; /* 164 etherStatsPkts512to1023Octets */
+ uint32_t r1518_u; /* 168 etherStatsPkts1024to1518Octets */
+ uint32_t r1518_l; /* 16c etherStatsPkts1024to1518Octets */
+ uint32_t r1519x_u; /* 170 etherStatsPkts1519toX */
+ uint32_t r1519x_l; /* 174 etherStatsPkts1519toX */
+ uint32_t trovr_u; /* 178 etherStatsOversizePkts */
+ uint32_t trovr_l; /* 17c etherStatsOversizePkts */
+ uint32_t trjbr_u; /* 180 etherStatsJabbers */
+ uint32_t trjbr_l; /* 184 etherStatsJabbers */
+ uint32_t trfrg_u; /* 188 etherStatsFragments */
+ uint32_t trfrg_l; /* 18C etherStatsFragments */
+ uint32_t rerr_u; /* 190 if_in_errors */
+ uint32_t rerr_l; /* 194 if_in_errors */
+};
+
+/**
+*struct tgec_cfg - TGEC configuration
+ *
+*@rx_error_discard: Receive Erroneous Frame Discard Enable. When set to 1
+* any frame received with an error is discarded in the
+* Core and not forwarded to the Client interface.
+* When set to 0 (Reset value), erroneous Frames are
+* forwarded to the Client interface with ff_rx_err
+* asserted.
+*@pause_ignore: Ignore Pause Frame Quanta. If set to 1 received pause
+* frames are ignored by the MAC. When set to 0
+* (Reset value) the transmit process is stopped for the
+* amount of time specified in the pause quanta received
+* within a pause frame.
+*@pause_forward_enable:
+* Terminate / Forward Pause Frames. If set to 1 pause
+* frames are forwarded to the user application. When set
+* to 0 (Reset value) pause frames are terminated and
+* discarded within the MAC.
+*@no_length_check_enable:
+* Payload Length Check Disable. When set to 0
+* (Reset value), the Core checks the frame's payload
+* length with the Frame Length/Type field, when set to 1
+* the payload length check is disabled.
+*@cmd_frame_enable: Enables reception of all command frames. When set to 1
+* all Command Frames are accepted, when set to 0
+* (Reset Value) only Pause Frames are accepted and all
+* other Command Frames are rejected.
+*@send_idle_enable: Force Idle Generation. When set to 1, the MAC
+* permanently sends XGMII Idle sequences even when faults
+* are received.
+*@wan_mode_enable: WAN Mode Enable. Sets WAN mode (1) or LAN mode
+* (0, default) of operation.
+*@promiscuous_mode_enable:
+* Enables MAC promiscuous operation. When set to 1, all
+* frames are received without any MAC address filtering,
+* when set to 0 (Reset value) Unicast Frames with a
+* destination address not matching the Core MAC Address
+* (MAC Address programmed in Registers MAC_ADDR_0 and
+* MAC_ADDR_1 or the MAC address programmed in Registers
+* MAC_ADDR_2 and MAC_ADDR_3) are rejected.
+*@tx_addr_ins_enable: Set Source MAC Address on Transmit. If set to 1 the
+* MAC overwrites the source MAC address received from the
+* Client Interface with one of the MAC addresses. If set
+* to 0 (Reset value), the source MAC address from the
+* Client Interface is transmitted unmodified to the line.
+*@loopback_enable: PHY Interface Loopback. When set to 1, the signal
+* loop_ena is set to '1', when set to 0 (Reset value)
+* the signal loop_ena is set to 0.
+*@lgth_check_nostdr: The Core interprets the Length/Type field differently
+* depending on the value of this Bit
+*@time_stamp_enable: This bit selects between enabling and disabling the
+* IEEE 1588 functionality. 1: IEEE 1588 is enabled
+* 0: IEEE 1588 is disabled
+*@max_frame_length: Maximum supported received frame length.
+* The 10GEC MAC supports reception of any frame size up
+* to 16,352 bytes (0x3FE0). Typical settings are
+* 0x05EE (1,518 bytes) for standard frames.
+* Default setting is 0x0600 (1,536 bytes).
+* Received frames that exceed this stated maximum
+* are truncated.
+*@pause_quant: Pause quanta value used with transmitted pause frames.
+* Each quanta represents a 512 bit-times.
+*@tx_ipg_length: Transmit Inter-Packet-Gap (IPG) value. A 6-bit value:
+* Depending on LAN or WAN mode of operation the value has
+* the following meaning: - LAN Mode: Number of octets in
+* steps of 4. Valid values are 8, 12, 16, ... 100. DIC is
+* fully supported (see 10.6.1 page 49) for any setting. A
+* default of 12 (reset value) must be set to conform to
+* IEEE802.3ae. Warning: When set to 8, PCS layers may not
+* be able to perform clock rate compensation. - WAN Mode:
+* Stretch factor. Valid values are 4..15. The stretch
+* factor is calculated as (value+1)*8. A default of 12
+* (reset value) must be set to conform to IEEE 802.3ae
+* (i.e. 13*8=104). A larger value shrinks the IPG
+* (increasing bandwidth).
+ *
+*This structure contains basic TGEC configuration and must be passed to
+*fman_tgec_init() function. A default set of configuration values can be
+*obtained by calling fman_tgec_defconfig().
+ */
+struct tgec_cfg {
+ bool rx_error_discard;
+ bool pause_ignore;
+ bool pause_forward_enable;
+ bool no_length_check_enable;
+ bool cmd_frame_enable;
+ bool send_idle_enable;
+ bool wan_mode_enable;
+ bool promiscuous_mode_enable;
+ bool tx_addr_ins_enable;
+ bool loopback_enable;
+ bool lgth_check_nostdr;
+ bool time_stamp_enable;
+ uint16_t max_frame_length;
+ uint16_t pause_quant;
+ uint32_t tx_ipg_length;
+ bool skip_fman11_workaround;
+};
+
+void fman_tgec_defconfig(struct tgec_cfg *cfg);
+
+/**
+*fman_tgec_init() - Init tgec hardware block
+*@regs: Pointer to tgec register block
+*@cfg: tgec configuration data
+*@exceptions_mask: initial exceptions mask
+ *
+*This function initializes the tgec controller and applies its
+*basic configuration.
+ *
+*Returns: 0 if successful, an error code otherwise.
+ */
+
+int fman_tgec_init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
+ uint32_t exception_mask);
+
+void fman_tgec_enable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+void fman_tgec_disable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx);
+
+uint32_t fman_tgec_get_revision(struct tgec_regs __iomem *regs);
+
+void fman_tgec_set_mac_address(struct tgec_regs __iomem *regs,
+ uint8_t *macaddr);
+
+void fman_tgec_set_promiscuous(struct tgec_regs __iomem *regs, bool val);
+
+/**
+*fman_tgec_set_hash_table() - Sets the Hashtable Control Register
+*@regs: Pointer to TGEC register block
+*@value: Value to be written in Hashtable Control Register
+ */
+void fman_tgec_set_hash_table(struct tgec_regs __iomem *regs, uint32_t value);
+
+/**
+*fman_tgec_set_tx_pause_frames() - Sets the Pause Quanta Register
+*@regs: Pointer to TGEC register block
+*@pause_time: Pause quanta value used with transmitted pause frames.
+* Each quanta represents a 512 bit-times
+ */
+void fman_tgec_set_tx_pause_frames(struct tgec_regs __iomem *regs,
+ uint16_t pause_time);
+
+/**
+*fman_tgec_set_rx_ignore_pause_frames() - Changes the policy WRT pause frames
+*@regs: Pointer to TGEC register block
+*@en: Ignore/Respond to pause frame quanta
+ *
+*Sets the value of PAUSE_IGNORE field in the COMMAND_CONFIG Register
+*0 - MAC stops transmit process for the duration specified
+*in the Pause frame quanta of a received Pause frame.
+*1 - MAC ignores received Pause frames.
+ */
+void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs __iomem *regs,
+ bool en);
+
+uint32_t fman_tgec_get_event(struct tgec_regs __iomem *regs, uint32_t ev_mask);
+
+void fman_tgec_ack_event(struct tgec_regs __iomem *regs, uint32_t ev_mask);
+
+uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs __iomem *regs);
+
+void fman_tgec_enable_interrupt(struct tgec_regs __iomem *regs,
+ uint32_t ev_mask);
+
+void fman_tgec_disable_interrupt(struct tgec_regs __iomem *regs,
+ uint32_t ev_mask);
+
+/**
+*fman_tgec_get_max_frame_len() - Returns the maximum frame length value
+*@regs: Pointer to TGEC register block
+ */
+uint16_t fman_tgec_get_max_frame_len(struct tgec_regs __iomem *regs);
+
+/**
+*fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007() - Initialize the
+*main tgec configuration parameters
+*@regs: Pointer to TGEC register block
+ *
+*TODO
+ */
+void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs
+ __iomem *regs);
+
+#endif /* __FSL_FMAN_TGEC_H */
--
1.7.11.7
From: Igal Liberman <[email protected]>
This patch adds the Ethernet MAC driver support.
Signed-off-by: Igal Liberman <[email protected]>
Signed-off-by: Madalin Bucur <[email protected]>
---
drivers/net/ethernet/freescale/fman/inc/mac.h | 136 ++++
drivers/net/ethernet/freescale/fman/mac/Makefile | 3 +-
drivers/net/ethernet/freescale/fman/mac/mac-api.c | 765 ++++++++++++++++++++++
drivers/net/ethernet/freescale/fman/mac/mac.c | 526 +++++++++++++++
4 files changed, 1429 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/freescale/fman/inc/mac.h
create mode 100644 drivers/net/ethernet/freescale/fman/mac/mac-api.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/mac.c
diff --git a/drivers/net/ethernet/freescale/fman/inc/mac.h b/drivers/net/ethernet/freescale/fman/inc/mac.h
new file mode 100644
index 0000000..0111f4c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/mac.h
@@ -0,0 +1,136 @@
+/* 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 __MAC_H
+#define __MAC_H
+
+#include <linux/device.h> /* struct device, BUS_ID_SIZE */
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/phy.h> /* phy_interface_t, struct phy_device */
+#include <linux/list.h>
+
+#include "enet_ext.h"
+
+#include "fsl_fman_drv.h" /* struct port_device */
+#include "fm_port_ext.h"
+
+struct fm_mac_dev;
+enum fm_mac_exceptions;
+
+enum {DTSEC, XGMAC, MEMAC};
+
+struct mac_device {
+ struct device *dev;
+ void *priv;
+ u8 cell_index;
+ struct resource *res;
+ void __iomem *vaddr;
+ u8 addr[ETH_ALEN];
+ bool promisc;
+
+ struct fm *fm_dev;
+ struct fm_port_drv_t *port_dev[2];
+
+ phy_interface_t phy_if;
+ u32 if_support;
+ bool link;
+ u16 speed;
+ u16 max_speed;
+ struct device_node *phy_node;
+ char fixed_bus_id[MII_BUS_ID_SIZE + 3];
+ struct device_node *tbi_node;
+ struct phy_device *phy_dev;
+ void *fm;
+ /* List of multicast addresses */
+ struct list_head mc_addr_list;
+ struct platform_device *eth_dev;
+
+ bool autoneg_pause;
+ bool rx_pause_req;
+ bool tx_pause_req;
+ bool rx_pause_active;
+ bool tx_pause_active;
+
+ int (*init_phy)(struct net_device *net_dev, struct mac_device *mac_dev);
+ int (*init)(struct mac_device *mac_dev);
+ int (*start)(struct mac_device *mac_dev);
+ int (*stop)(struct mac_device *mac_dev);
+ int (*set_promisc)(struct fm_mac_dev *fm_mac_dev, bool enable);
+ int (*change_addr)(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr);
+ int (*set_multi)(struct net_device *net_dev,
+ struct mac_device *mac_dev);
+ int (*uninit)(struct fm_mac_dev *fm_mac_dev);
+ int (*set_rx_pause)(struct fm_mac_dev *fm_mac_dev, bool en);
+ int (*set_tx_pause)(struct fm_mac_dev *fm_mac_dev, u8 priority,
+ u16 pause_time, u16 thresh_time);
+ int (*set_exception)(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable);
+ int (*add_hash_mac_addr)(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+ int (*remove_hash_mac_addr)(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_eth_addr);
+};
+
+struct mac_address {
+ u8 addr[ETH_ALEN];
+ struct list_head list;
+};
+
+struct dpaa_eth_data {
+ struct device_node *mac_node;
+ struct mac_device *mac_dev;
+ int mac_hw_id;
+ int fman_hw_id;
+};
+
+#define get_fm_handle(net_dev) \
+ (((struct dpa_priv_s *)netdev_priv(net_dev))->mac_dev->fm_dev)
+
+#define for_each_port_device(i, port_dev) \
+ for (i = 0; i < ARRAY_SIZE(port_dev); i++)
+
+static inline __attribute((nonnull)) void *macdev_priv(
+ const struct mac_device *mac_dev)
+{
+ return (void *)mac_dev + sizeof(*mac_dev);
+}
+
+extern const char *mac_driver_description;
+extern const size_t mac_sizeof_priv[];
+extern void (*const mac_setup[])(struct mac_device *mac_dev);
+
+int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx);
+void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause);
+struct fm_mac_dev *get_mac_handle(struct mac_device *mac_dev);
+
+#endif /* __MAC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac/Makefile b/drivers/net/ethernet/freescale/fman/mac/Makefile
index bfd04ea..af3c82f 100644
--- a/drivers/net/ethernet/freescale/fman/mac/Makefile
+++ b/drivers/net/ethernet/freescale/fman/mac/Makefile
@@ -1,7 +1,8 @@
-obj-y += fsl_fman_mac.o
+obj-y += fsl_fman_mac.o fsl_mac.o
fsl_fman_mac-objs := fman_dtsec.o fman_dtsec_mii_acc.o \
fm_dtsec.o fm_dtsec_mii_acc.o \
fman_memac.o fman_memac_mii_acc.o \
fm_memac.o fm_memac_mii_acc.o \
fman_tgec.o fm_tgec.o
+fsl_mac-objs += mac.o mac-api.o
diff --git a/drivers/net/ethernet/freescale/fman/mac/mac-api.c b/drivers/net/ethernet/freescale/fman/mac/mac-api.c
new file mode 100644
index 0000000..bf8fa29
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/mac-api.c
@@ -0,0 +1,765 @@
+/* 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME ".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include "mac.h"
+#include "fsl_fman_drv.h"
+#include "fm_mac.h"
+#include "fm_dtsec.h"
+#include "fm_tgec.h"
+#include "fm_memac.h"
+
+#define MAC_DESCRIPTION "FSL FMan MAC API based driver"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_AUTHOR("Emil Medve <[email protected]>");
+
+MODULE_DESCRIPTION(MAC_DESCRIPTION);
+
+struct mac_priv_s {
+ struct fm_mac_dev *fm_mac;
+};
+
+const char *mac_driver_description __initconst = MAC_DESCRIPTION;
+const size_t mac_sizeof_priv[] = {
+ [DTSEC] = sizeof(struct mac_priv_s),
+ [XGMAC] = sizeof(struct mac_priv_s),
+ [MEMAC] = sizeof(struct mac_priv_s)
+};
+
+static const enet_mode_t _100[] = {
+ [PHY_INTERFACE_MODE_MII] = ENET_MODE_MII_100,
+ [PHY_INTERFACE_MODE_RMII] = ENET_MODE_RMII_100
+};
+
+static const enet_mode_t _1000[] = {
+ [PHY_INTERFACE_MODE_GMII] = ENET_MODE_GMII_1000,
+ [PHY_INTERFACE_MODE_SGMII] = ENET_MODE_SGMII_1000,
+ [PHY_INTERFACE_MODE_TBI] = ENET_MODE_TBI_1000,
+ [PHY_INTERFACE_MODE_RGMII] = ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_ID] = ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_RXID] = ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_TXID] = ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RTBI] = ENET_MODE_RTBI_1000
+};
+
+static enet_mode_t __cold __attribute__((nonnull))
+macdev2enetinterface(const struct mac_device *mac_dev)
+{
+ switch (mac_dev->max_speed) {
+ case SPEED_100:
+ return _100[mac_dev->phy_if];
+ case SPEED_1000:
+ return _1000[mac_dev->phy_if];
+ case SPEED_10000:
+ return ENET_MODE_XGMII_10000;
+ default:
+ return ENET_MODE_MII_100;
+ }
+}
+
+struct fm_mac_dev *get_mac_handle(struct mac_device *mac_dev)
+{
+ const struct mac_priv_s *priv;
+
+ priv = macdev_priv(mac_dev);
+
+ return priv->fm_mac;
+}
+
+static void mac_exception(void *_mac_dev, enum fm_mac_exceptions ex)
+{
+ struct mac_device *mac_dev;
+
+ mac_dev = (struct mac_device *)_mac_dev;
+
+ if (FM_MAC_EX_10G_RX_FIFO_OVFL == ex) {
+ /* don't flag RX FIFO after the first */
+ mac_dev->set_exception(get_mac_handle(mac_dev),
+ FM_MAC_EX_10G_RX_FIFO_OVFL, false);
+ dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n",
+ ex);
+ }
+
+ dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c",
+ __func__, ex);
+}
+
+static int __cold tgec_initialization(struct mac_device *mac_dev)
+{
+ int err;
+ struct mac_priv_s *priv;
+ struct fm_mac_params_t param;
+ u32 version;
+
+ priv = macdev_priv(mac_dev);
+
+ param.base_addr = (typeof(param.base_addr))(uintptr_t)devm_ioremap(
+ mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(¶m.addr, mac_dev->addr,
+ min(sizeof(param.addr), sizeof(mac_dev->addr)));
+ param.mac_id = mac_dev->cell_index;
+ param.h_fm = (void *)mac_dev->fm;
+ param.f_exception = mac_exception;
+ param.f_event = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = tgec_config(¶m);
+ if (unlikely(!priv->fm_mac)) {
+ err = -EINVAL;
+ goto _return;
+ }
+
+ err = tgec_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ err = tgec_init(priv->fm_mac);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ /* For 1G MAC, disable by default the MIB counters overflow interrupt */
+ if (macdev2enetinterface(mac_dev) != ENET_MODE_XGMII_10000) {
+ err = mac_dev->set_exception(get_mac_handle(mac_dev),
+ FM_MAC_EX_1G_RX_MIB_CNT_OVFL,
+ false);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+ }
+
+ /* For 10G MAC, disable Tx ECC exception */
+ if (macdev2enetinterface(mac_dev) == ENET_MODE_XGMII_10000) {
+ err = mac_dev->set_exception(get_mac_handle(mac_dev),
+ FM_MAC_EX_10G_TX_ECC_ER, false);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+ }
+
+ err = tgec_get_version(priv->fm_mac, &version);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n",
+ ((macdev2enetinterface(mac_dev) != ENET_MODE_XGMII_10000) ?
+ "dTSEC" : "XGEC"), version);
+
+ goto _return;
+
+_return_fm_mac_free:
+ tgec_free(get_mac_handle(mac_dev));
+
+_return:
+ return err;
+}
+
+static int __cold dtsec_initialization(struct mac_device *mac_dev)
+{
+ int err;
+ struct mac_priv_s *priv;
+ struct fm_mac_params_t param;
+ u32 version;
+
+ priv = macdev_priv(mac_dev);
+
+ param.base_addr = (typeof(param.base_addr))(uintptr_t)devm_ioremap(
+ mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(¶m.addr, mac_dev->addr,
+ min(sizeof(param.addr), sizeof(mac_dev->addr)));
+ param.mac_id = mac_dev->cell_index;
+ param.h_fm = (void *)mac_dev->fm;
+ param.f_exception = mac_exception;
+ param.f_event = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = dtsec_config(¶m);
+ if (unlikely(!priv->fm_mac)) {
+ err = -EINVAL;
+ goto _return;
+ }
+
+ err = dtsec_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ err = dtsec_cfg_pad_and_crc(priv->fm_mac, true);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ err = dtsec_init(priv->fm_mac);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ /* For 1G MAC, disable by default the MIB counters overflow interrupt */
+ if (macdev2enetinterface(mac_dev) != ENET_MODE_XGMII_10000) {
+ err = mac_dev->set_exception(get_mac_handle(mac_dev),
+ FM_MAC_EX_1G_RX_MIB_CNT_OVFL,
+ false);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+ }
+
+ /* For 10G MAC, disable Tx ECC exception */
+ if (macdev2enetinterface(mac_dev) == ENET_MODE_XGMII_10000) {
+ err = mac_dev->set_exception(get_mac_handle(mac_dev),
+ FM_MAC_EX_10G_TX_ECC_ER, false);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+ }
+
+ err = dtsec_get_version(priv->fm_mac, &version);
+ if (unlikely(err < 0))
+ goto _return_fm_mac_free;
+
+ dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n",
+ ((macdev2enetinterface(mac_dev) != ENET_MODE_XGMII_10000) ?
+ "dTSEC" : "XGEC"), version);
+
+ goto _return;
+
+_return_fm_mac_free:
+ dtsec_free(get_mac_handle(mac_dev));
+
+_return:
+ return err;
+}
+
+static int __cold memac_initialization(struct mac_device *mac_dev)
+{
+ int _errno;
+ struct mac_priv_s *priv;
+ struct fm_mac_params_t param;
+
+ priv = macdev_priv(mac_dev);
+
+ param.base_addr = (typeof(param.base_addr))(uintptr_t)devm_ioremap(
+ mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(¶m.addr, mac_dev->addr, sizeof(mac_dev->addr));
+ param.mac_id = mac_dev->cell_index;
+ param.h_fm = (void *)mac_dev->fm;
+ param.f_exception = mac_exception;
+ param.f_event = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = memac_config(¶m);
+ if (unlikely(!priv->fm_mac)) {
+ _errno = -EINVAL;
+ goto _return;
+ }
+
+ _errno = memac_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ _errno = memac_cfg_reset_on_init(priv->fm_mac, true);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ _errno = memac_init(priv->fm_mac);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ dev_info(mac_dev->dev, "FMan MEMAC\n");
+
+ goto _return;
+
+_return_fm_mac_free:
+ memac_free(priv->fm_mac);
+
+_return:
+ return _errno;
+}
+
+static int __cold dtsec_start(struct mac_device *mac_dev)
+{
+ int err;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+
+ err = dtsec_enable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+
+ if (!err && phy_dev)
+ phy_start(phy_dev);
+
+ return err;
+}
+
+static int __cold tgec_start(struct mac_device *mac_dev)
+{
+ int err;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+
+ err = tgec_enable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+
+ if (!err && phy_dev) {
+ if (phy_dev->drv->read_status)
+ phy_dev->drv->read_status(phy_dev);
+ }
+
+ return err;
+}
+
+static int __cold memac_start(struct mac_device *mac_dev)
+{
+ int err;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+
+ err = memac_enable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+
+ if (!err && phy_dev) {
+ if (macdev2enetinterface(mac_dev) != ENET_MODE_XGMII_10000)
+ phy_start(phy_dev);
+ else if (phy_dev->drv->read_status)
+ phy_dev->drv->read_status(phy_dev);
+ }
+
+ return err;
+}
+
+static int __cold dtsec_stop(struct mac_device *mac_dev)
+{
+ if (mac_dev->phy_dev)
+ phy_stop(mac_dev->phy_dev);
+
+ return dtsec_disable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+}
+
+static int __cold tgec_stop(struct mac_device *mac_dev)
+{
+ return tgec_disable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+}
+
+static int __cold memac_stop(struct mac_device *mac_dev)
+{
+ if (mac_dev->phy_dev && (macdev2enetinterface(mac_dev) !=
+ ENET_MODE_XGMII_10000))
+ phy_stop(mac_dev->phy_dev);
+
+ return memac_disable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+}
+
+static int __cold set_multi(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct mac_priv_s *mac_priv;
+ struct mac_address *old_addr, *tmp;
+ struct netdev_hw_addr *ha;
+ int err;
+ enet_addr_t *addr;
+
+ mac_priv = macdev_priv(mac_dev);
+
+ /* Clear previous address list */
+ list_for_each_entry_safe(old_addr, tmp, &mac_dev->mc_addr_list, list) {
+ addr = (enet_addr_t *)old_addr->addr;
+ err = mac_dev->remove_hash_mac_addr(mac_priv->fm_mac, addr);
+ if (err < 0)
+ return err;
+
+ list_del(&old_addr->list);
+ kfree(old_addr);
+ }
+
+ /* Add all the addresses from the new list */
+ netdev_for_each_mc_addr(ha, net_dev) {
+ addr = (enet_addr_t *)ha->addr;
+ err = mac_dev->add_hash_mac_addr(mac_priv->fm_mac, addr);
+ if (err < 0)
+ return err;
+
+ tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
+ if (!tmp)
+ return -ENOMEM;
+
+ ether_addr_copy(tmp->addr, ha->addr);
+ list_add(&tmp->list, &mac_dev->mc_addr_list);
+ }
+ return 0;
+}
+
+/* Avoid redundant calls to FMD, if the MAC driver already contains the desired
+ * active PAUSE settings. Otherwise, the new active settings should be reflected
+ * in FMan.
+ */
+int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
+{
+ struct fm_mac_dev *fm_mac_dev = get_mac_handle(mac_dev);
+ int _errno = 0;
+
+ if (unlikely(rx != mac_dev->rx_pause_active)) {
+ _errno = mac_dev->set_rx_pause(fm_mac_dev, rx);
+ if (likely(_errno == 0))
+ mac_dev->rx_pause_active = rx;
+ }
+
+ if (unlikely(tx != mac_dev->tx_pause_active)) {
+ u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE :
+ FSL_FM_PAUSE_TIME_DISABLE);
+
+ _errno = mac_dev->set_tx_pause(fm_mac_dev, 0,
+ pause_time, 0);
+
+ if (likely(_errno == 0))
+ mac_dev->tx_pause_active = tx;
+ }
+
+ return _errno;
+}
+EXPORT_SYMBOL(set_mac_active_pause);
+
+/* Determine the MAC RX/TX PAUSE frames settings based on PHY
+ * autonegotiation or values set by eththool.
+ */
+void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause)
+{
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+ u16 lcl_adv, rmt_adv;
+ u8 flowctrl;
+
+ *rx_pause = *tx_pause = false;
+
+ if (!phy_dev->duplex)
+ return;
+
+ /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings
+ * are those set by ethtool.
+ */
+ if (!mac_dev->autoneg_pause) {
+ *rx_pause = mac_dev->rx_pause_req;
+ *tx_pause = mac_dev->tx_pause_req;
+ return;
+ }
+
+ /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE
+ * settings depend on the result of the link negotiation.
+ */
+
+ /* get local capabilities */
+ lcl_adv = 0;
+ if (phy_dev->advertising & ADVERTISED_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
+ if (phy_dev->advertising & ADVERTISED_Asym_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+ /* get link partner capabilities */
+ rmt_adv = 0;
+ if (phy_dev->pause)
+ rmt_adv |= LPA_PAUSE_CAP;
+ if (phy_dev->asym_pause)
+ rmt_adv |= LPA_PAUSE_ASYM;
+
+ /* Calculate TX/RX settings based on local and peer advertised
+ * symmetric/asymmetric PAUSE capabilities.
+ */
+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+ if (flowctrl & FLOW_CTRL_RX)
+ *rx_pause = true;
+ if (flowctrl & FLOW_CTRL_TX)
+ *tx_pause = true;
+}
+EXPORT_SYMBOL(get_pause_cfg);
+
+static void adjust_link_dtsec(struct net_device *net_dev)
+{
+ struct device *dev = net_dev->dev.parent;
+ struct dpaa_eth_data *eth_data = dev->platform_data;
+ struct mac_device *mac_dev = eth_data->mac_dev;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+ struct fm_mac_dev *fm_mac_dev;
+ bool rx_pause, tx_pause;
+ int err;
+
+ fm_mac_dev = get_mac_handle(mac_dev);
+ if (!phy_dev->link) {
+ /* TODO: move in dtsec_an_errata() */
+ dtsec_restart_autoneg(fm_mac_dev);
+
+ return;
+ }
+
+ dtsec_adjust_link(fm_mac_dev, phy_dev->speed);
+
+ get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
+ err = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
+ if (unlikely(err < 0))
+ netdev_err(net_dev, "set_mac_active_pause() = %d\n", err);
+}
+
+static void adjust_link_memac(struct net_device *net_dev)
+{
+ struct device *dev = net_dev->dev.parent;
+ struct dpaa_eth_data *eth_data = dev->platform_data;
+ struct mac_device *mac_dev = eth_data->mac_dev;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+ struct fm_mac_dev *fm_mac_dev;
+ bool rx_pause, tx_pause;
+ int err;
+
+ fm_mac_dev = get_mac_handle(mac_dev);
+ memac_adjust_link(fm_mac_dev, phy_dev->speed);
+
+ get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
+ err = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
+ if (unlikely(err < 0))
+ netdev_err(net_dev, "set_mac_active_pause() = %d\n", err);
+}
+
+/* Initializes driver's PHY state, and attaches to the PHY.
+ * Returns 0 on success.
+ */
+static int dtsec_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+
+ if (!mac_dev->phy_node)
+ phy_dev = phy_connect(net_dev, mac_dev->fixed_bus_id,
+ &adjust_link_dtsec, mac_dev->phy_if);
+ else
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link_dtsec, 0,
+ mac_dev->phy_if);
+ if (unlikely(!phy_dev) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return (!phy_dev) ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ /* Remove any features not supported by the controller */
+ phy_dev->supported &= mac_dev->if_support;
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ phy_dev->advertising = phy_dev->supported;
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int xgmac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+
+ if (!mac_dev->phy_node)
+ phy_dev = phy_attach(net_dev, mac_dev->fixed_bus_id,
+ mac_dev->phy_if);
+ else
+ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node, 0,
+ mac_dev->phy_if);
+ if (unlikely(!phy_dev) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not attach to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return (!phy_dev) ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ phy_dev->supported &= mac_dev->if_support;
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ phy_dev->advertising = phy_dev->supported;
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int memac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+
+ if (macdev2enetinterface(mac_dev) == ENET_MODE_XGMII_10000) {
+ if (!mac_dev->phy_node) {
+ mac_dev->phy_dev = NULL;
+ return 0;
+ }
+
+ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node, 0,
+ mac_dev->phy_if);
+ } else {
+ if (!mac_dev->phy_node)
+ phy_dev = phy_connect(net_dev, mac_dev->fixed_bus_id,
+ &adjust_link_memac,
+ mac_dev->phy_if);
+ else
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link_memac, 0,
+ mac_dev->phy_if);
+ }
+
+ if (unlikely(!phy_dev) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return (!phy_dev) ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ /* Remove any features not supported by the controller */
+ phy_dev->supported &= mac_dev->if_support;
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ phy_dev->advertising = phy_dev->supported;
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int __cold dtsec_uninit(struct fm_mac_dev *fm_mac_dev)
+{
+ int err, err1;
+
+ err = dtsec_disable(fm_mac_dev, COMM_MODE_RX_AND_TX);
+ err1 = dtsec_free(fm_mac_dev);
+
+ if (unlikely(err1 < 0))
+ err = err1;
+
+ return err;
+}
+
+static int __cold tgec_uninit(struct fm_mac_dev *fm_mac_dev)
+{
+ int err, err1;
+
+ err = tgec_disable(fm_mac_dev, COMM_MODE_RX_AND_TX);
+ err1 = tgec_free(fm_mac_dev);
+
+ if (unlikely(err1 < 0))
+ err = err1;
+
+ return err;
+}
+
+static int __cold memac_uninit(struct fm_mac_dev *fm_mac_dev)
+{
+ int err, err1;
+
+ err = memac_disable(fm_mac_dev, COMM_MODE_RX_AND_TX);
+ err1 = memac_free(fm_mac_dev);
+
+ if (unlikely(err1 < 0))
+ err = err1;
+
+ return err;
+}
+
+static void __cold setup_dtsec(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = dtsec_init_phy;
+ mac_dev->init = dtsec_initialization;
+ mac_dev->start = dtsec_start;
+ mac_dev->stop = dtsec_stop;
+ mac_dev->set_promisc = dtsec_set_promiscuous;
+ mac_dev->change_addr = dtsec_modify_mac_address;
+ mac_dev->add_hash_mac_addr = dtsec_add_hash_mac_address;
+ mac_dev->remove_hash_mac_addr = dtsec_del_hash_mac_address;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = dtsec_uninit;
+ mac_dev->set_tx_pause = dtsec_set_tx_pause_frames;
+ mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames;
+ mac_dev->set_exception = dtsec_set_exception;
+}
+
+static void __cold setup_xgmac(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = xgmac_init_phy;
+ mac_dev->init = tgec_initialization;
+ mac_dev->start = tgec_start;
+ mac_dev->stop = tgec_stop;
+ mac_dev->set_promisc = tgec_set_promiscuous;
+ mac_dev->change_addr = tgec_modify_mac_address;
+ mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address;
+ mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = tgec_uninit;
+ mac_dev->set_tx_pause = tgec_set_tx_pause_frames;
+ mac_dev->set_rx_pause = tgec_accept_rx_pause_frames;
+ mac_dev->set_exception = tgec_set_exception;
+}
+
+static void __cold setup_memac(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = memac_init_phy;
+ mac_dev->init = memac_initialization;
+ mac_dev->start = memac_start;
+ mac_dev->stop = memac_stop;
+ mac_dev->set_promisc = memac_set_promiscuous;
+ mac_dev->change_addr = memac_modify_mac_address;
+ mac_dev->add_hash_mac_addr = memac_add_hash_mac_address;
+ mac_dev->remove_hash_mac_addr = memac_del_hash_mac_address;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = memac_uninit;
+ mac_dev->set_tx_pause = memac_set_tx_pause_frames;
+ mac_dev->set_rx_pause = memac_accept_rx_pause_frames;
+ mac_dev->set_exception = memac_set_exception;
+}
+
+void (*const mac_setup[])(struct mac_device *mac_dev) = {
+ [DTSEC] = setup_dtsec,
+ [XGMAC] = setup_xgmac,
+ [MEMAC] = setup_memac
+};
diff --git a/drivers/net/ethernet/freescale/fman/mac/mac.c b/drivers/net/ethernet/freescale/fman/mac/mac.c
new file mode 100644
index 0000000..d1f12092
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/mac.c
@@ -0,0 +1,526 @@
+/* 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME ".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/device.h>
+#include <linux/phy.h>
+
+#include "mac.h"
+
+#define DTSEC_SUPPORTED \
+ (SUPPORTED_10baseT_Half \
+ | SUPPORTED_10baseT_Full \
+ | SUPPORTED_100baseT_Half \
+ | SUPPORTED_100baseT_Full \
+ | SUPPORTED_Autoneg \
+ | SUPPORTED_Pause \
+ | SUPPORTED_Asym_Pause \
+ | SUPPORTED_MII)
+
+static DEFINE_MUTEX(eth_lock);
+
+static const char phy_str[][11] = {
+ [PHY_INTERFACE_MODE_MII] = "mii",
+ [PHY_INTERFACE_MODE_GMII] = "gmii",
+ [PHY_INTERFACE_MODE_SGMII] = "sgmii",
+ [PHY_INTERFACE_MODE_TBI] = "tbi",
+ [PHY_INTERFACE_MODE_RMII] = "rmii",
+ [PHY_INTERFACE_MODE_RGMII] = "rgmii",
+ [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
+ [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+ [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+ [PHY_INTERFACE_MODE_RTBI] = "rtbi",
+ [PHY_INTERFACE_MODE_XGMII] = "xgmii"
+};
+
+static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(phy_str); i++)
+ if (strcmp(str, phy_str[i]) == 0)
+ return (phy_interface_t)i;
+
+ return PHY_INTERFACE_MODE_MII;
+}
+
+static const u16 phy2speed[] = {
+ [PHY_INTERFACE_MODE_MII] = SPEED_100,
+ [PHY_INTERFACE_MODE_GMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_SGMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_TBI] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RMII] = SPEED_100,
+ [PHY_INTERFACE_MODE_RGMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RTBI] = SPEED_1000,
+ [PHY_INTERFACE_MODE_XGMII] = SPEED_10000
+};
+
+static struct mac_device * __cold
+alloc_macdev(struct device *dev, size_t sizeof_priv,
+ void (*setup)(struct mac_device *mac_dev))
+{
+ struct mac_device *mac_dev;
+
+ mac_dev = devm_kzalloc(dev, sizeof(*mac_dev) + sizeof_priv, GFP_KERNEL);
+ if (unlikely(!mac_dev)) {
+ mac_dev = ERR_PTR(-ENOMEM);
+ } else {
+ mac_dev->dev = dev;
+ dev_set_drvdata(dev, mac_dev);
+ setup(mac_dev);
+ }
+
+ return mac_dev;
+}
+
+static int __cold free_macdev(struct mac_device *mac_dev)
+{
+ dev_set_drvdata(mac_dev->dev, NULL);
+
+ return mac_dev->uninit(get_mac_handle(mac_dev));
+}
+
+static struct platform_device *dpaa_eth_add_device(int fman_id,
+ struct mac_device *mac_dev,
+ struct device_node *node)
+{
+ struct platform_device *pdev;
+ struct dpaa_eth_data data;
+ static int dpaa_eth_dev_cnt;
+ int ret;
+
+ data.mac_dev = mac_dev;
+ data.mac_hw_id = mac_dev->cell_index;
+ data.fman_hw_id = fman_id;
+ data.mac_node = node;
+
+ mutex_lock(ð_lock);
+
+ pdev = platform_device_alloc("dpaa-ethernet", dpaa_eth_dev_cnt);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto no_mem;
+ }
+
+ ret = platform_device_add_data(pdev, &data, sizeof(data));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto err;
+
+ dpaa_eth_dev_cnt++;
+ mutex_unlock(ð_lock);
+
+ return pdev;
+
+err:
+ platform_device_put(pdev);
+no_mem:
+ mutex_unlock(ð_lock);
+
+ return ERR_PTR(ret);
+}
+
+static void dpaa_eth_remove_device(struct platform_device *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static const struct of_device_id mac_match[] = {
+ [DTSEC] = {
+ .compatible = "fsl,fman-dtsec"
+ },
+ [XGMAC] = {
+ .compatible = "fsl,fman-xgec"
+ },
+ [MEMAC] = {
+ .compatible = "fsl,fman-memac"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mac_match);
+
+static int __cold mac_probe(struct platform_device *_of_dev)
+{
+ int _errno, i, lenp;
+ struct device *dev;
+ struct device_node *mac_node, *dev_node;
+ struct mac_device *mac_dev;
+ struct platform_device *of_dev;
+ struct resource res;
+ const u8 *mac_addr;
+ const char *char_prop;
+ const u32 *uint32_prop;
+ const struct of_device_id *match;
+ u8 fman_id;
+
+ const phandle *phandle_prop;
+
+ dev = &_of_dev->dev;
+ mac_node = dev->of_node;
+
+ match = of_match_device(mac_match, dev);
+ if (!match)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(mac_match) - 1 && match != mac_match + i;
+ i++)
+ ;
+ BUG_ON(i >= ARRAY_SIZE(mac_match) - 1);
+
+ mac_dev = alloc_macdev(dev, mac_sizeof_priv[i], mac_setup[i]);
+ if (IS_ERR(mac_dev)) {
+ _errno = PTR_ERR(mac_dev);
+ dev_err(dev, "alloc_macdev() = %d\n", _errno);
+ goto _return;
+ }
+
+ INIT_LIST_HEAD(&mac_dev->mc_addr_list);
+
+ /* Get the FM node */
+ dev_node = of_get_parent(mac_node);
+ if (unlikely(!dev_node)) {
+ dev_err(dev, "of_get_parent(%s) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (unlikely(!of_dev)) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ /* Get the FMan cell-index */
+ uint32_prop = of_get_property(dev_node, "cell-index", &lenp);
+ if (unlikely(!uint32_prop)) {
+ dev_err(dev, "of_get_property(%s, cell-index) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+ BUG_ON(lenp != sizeof(u32));
+ fman_id = (u8)*uint32_prop + 1; /* cell-index 0 => FMan id 1 */
+
+ mac_dev->fm_dev = fm_bind(&of_dev->dev);
+ if (unlikely(!mac_dev->fm_dev)) {
+ dev_err(dev, "fm_bind(%s) failed\n", dev_node->full_name);
+ _errno = -ENODEV;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->fm = (void *)fm_get_handle(mac_dev->fm_dev);
+ of_node_put(dev_node);
+
+ /* Get the address of the memory mapped registers */
+ _errno = of_address_to_resource(mac_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ dev_err(dev, "of_address_to_resource(%s) = %d\n",
+ mac_node->full_name, _errno);
+ goto _return_dev_set_drvdata;
+ }
+
+ mac_dev->res =
+ __devm_request_region(dev, fm_get_mem_region(mac_dev->fm_dev),
+ res.start, res.end + 1 - res.start,
+ "mac");
+ if (unlikely(!mac_dev->res)) {
+ dev_err(dev, "__devm_request_mem_region(mac) failed\n");
+ _errno = -EBUSY;
+ goto _return_dev_set_drvdata;
+ }
+
+ mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
+ mac_dev->res->end + 1
+ - mac_dev->res->start);
+ if (unlikely(!mac_dev->vaddr)) {
+ dev_err(dev, "devm_ioremap() failed\n");
+ _errno = -EIO;
+ goto _return_dev_set_drvdata;
+ }
+
+#define TBIPA_OFFSET 0x1c
+#define TBIPA_DEFAULT_ADDR 5 /* override if used as external PHY addr. */
+ mac_dev->tbi_node = of_parse_phandle(mac_node, "tbi-handle", 0);
+ if (mac_dev->tbi_node) {
+ u32 tbiaddr = TBIPA_DEFAULT_ADDR;
+
+ uint32_prop = of_get_property(mac_dev->tbi_node, "reg", NULL);
+ if (uint32_prop)
+ tbiaddr = *uint32_prop;
+ out_be32(mac_dev->vaddr + TBIPA_OFFSET, tbiaddr);
+ }
+
+ if (!of_device_is_available(mac_node)) {
+ devm_iounmap(dev, mac_dev->vaddr);
+ __devm_release_region(dev, fm_get_mem_region(mac_dev->fm_dev),
+ res.start, res.end + 1 - res.start);
+ fm_unbind(mac_dev->fm_dev);
+ devm_kfree(dev, mac_dev);
+ dev_set_drvdata(dev, NULL);
+ return -ENODEV;
+ }
+
+ /* Get the cell-index */
+ uint32_prop = of_get_property(mac_node, "cell-index", &lenp);
+ if (unlikely(!uint32_prop)) {
+ dev_err(dev, "of_get_property(%s, cell-index) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+ BUG_ON(lenp != sizeof(u32));
+ mac_dev->cell_index = (u8)*uint32_prop;
+
+ /* Get the MAC address */
+ mac_addr = of_get_mac_address(mac_node);
+ if (unlikely(!mac_addr)) {
+ dev_err(dev, "of_get_mac_address(%s) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+ memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr));
+
+ /* Get the port handles */
+ phandle_prop = of_get_property(mac_node, "fsl,fman-ports", &lenp);
+ if (unlikely(!phandle_prop)) {
+ dev_err(dev, "of_get_property(%s, fsl,fman-ports) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+ BUG_ON(lenp != sizeof(phandle) * ARRAY_SIZE(mac_dev->port_dev));
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ /* Find the port node */
+ dev_node = of_find_node_by_phandle(phandle_prop[i]);
+ if (unlikely(!dev_node)) {
+ dev_err(dev, "of_find_node_by_phandle() failed\n");
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (unlikely(!of_dev)) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev);
+ if (unlikely(!mac_dev->port_dev[i])) {
+ dev_err(dev, "dev_get_drvdata(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+ of_node_put(dev_node);
+ }
+
+ /* Get the PHY connection type */
+ char_prop = (const char *)of_get_property(mac_node,
+ "phy-connection-type", NULL);
+ if (unlikely(!char_prop)) {
+ dev_warn(dev,
+ "of_get_property(%s, phy-connection-type) failed. Defaulting to MII\n",
+ mac_node->full_name);
+ mac_dev->phy_if = PHY_INTERFACE_MODE_MII;
+ } else {
+ mac_dev->phy_if = str2phy(char_prop);
+ }
+
+ mac_dev->link = false;
+ mac_dev->speed = phy2speed[mac_dev->phy_if];
+ mac_dev->max_speed = mac_dev->speed;
+ mac_dev->if_support = DTSEC_SUPPORTED;
+ /* We don't support half-duplex in SGMII mode */
+ if (strstr(char_prop, "sgmii"))
+ mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
+ SUPPORTED_100baseT_Half);
+
+ /* Gigabit support (no half-duplex) */
+ if (mac_dev->max_speed == 1000)
+ mac_dev->if_support |= SUPPORTED_1000baseT_Full;
+
+ /* The 10G interface only supports one mode */
+ if (strstr(char_prop, "xgmii"))
+ mac_dev->if_support = SUPPORTED_10000baseT_Full;
+
+ /* Get the rest of the PHY information */
+ mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
+ if (!mac_dev->phy_node) {
+ int sz;
+ const u32 *phy_id = of_get_property(mac_node, "fixed-link",
+ &sz);
+ if (!phy_id || sz < sizeof(*phy_id)) {
+ dev_err(dev, "No PHY (or fixed link) found\n");
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+
+ sprintf(mac_dev->fixed_bus_id, PHY_ID_FMT, "fixed-0",
+ phy_id[0]);
+ }
+
+ _errno = mac_dev->init(mac_dev);
+ if (unlikely(_errno < 0)) {
+ dev_err(dev, "mac_dev->init() = %d\n", _errno);
+ goto _return_dev_set_drvdata;
+ }
+
+ /* pause frame autonegotiation enabled*/
+ mac_dev->autoneg_pause = true;
+
+ /* by intializing the values to false, force FMD to enable PAUSE frames
+ * on RX and TX
+ */
+ mac_dev->rx_pause_req = true;
+ mac_dev->tx_pause_req = true;
+ mac_dev->rx_pause_active = false;
+ mac_dev->tx_pause_active = false;
+ _errno = set_mac_active_pause(mac_dev, true, true);
+ if (unlikely(_errno < 0))
+ dev_err(dev, "set_mac_active_pause() = %d\n", _errno);
+
+ dev_info(dev,
+ "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
+ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
+ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]);
+
+ mac_dev->eth_dev = dpaa_eth_add_device(fman_id, mac_dev,
+ mac_node);
+ if (IS_ERR(mac_dev->eth_dev)) {
+ dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
+ mac_dev->cell_index);
+ mac_dev->eth_dev = NULL;
+ }
+
+ goto _return;
+
+_return_of_node_put:
+ of_node_put(dev_node);
+_return_dev_set_drvdata:
+ dev_set_drvdata(dev, NULL);
+_return:
+ return _errno;
+}
+
+static int __cold mac_remove(struct platform_device *of_dev)
+{
+ int i, _errno;
+ struct device *dev;
+ struct mac_device *mac_dev;
+
+ dev = &of_dev->dev;
+ mac_dev = (struct mac_device *)dev_get_drvdata(dev);
+
+ dpaa_eth_remove_device(mac_dev->eth_dev);
+
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_unbind(mac_dev->port_dev[i]);
+
+ fm_unbind(mac_dev->fm_dev);
+
+ _errno = free_macdev(mac_dev);
+
+ return _errno;
+}
+
+static struct platform_driver mac_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = mac_match,
+ },
+ .probe = mac_probe,
+ .remove = mac_remove
+};
+
+static int __init __cold mac_load(void)
+{
+ int _errno;
+
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME ".c", __func__);
+
+ pr_info(KBUILD_MODNAME ": %s\n",
+ mac_driver_description);
+
+ _errno = platform_driver_register(&mac_driver);
+ if (unlikely(_errno < 0)) {
+ pr_err(KBUILD_MODNAME ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
+ goto _return;
+ }
+
+ goto _return;
+
+_return:
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME ".c", __func__);
+
+ return _errno;
+}
+module_init(mac_load);
+
+static void __exit __cold mac_unload(void)
+{
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME ".c", __func__);
+
+ platform_driver_unregister(&mac_driver);
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME ".c", __func__);
+}
+module_exit(mac_unload);
--
1.7.11.7
From: Igal Liberman <[email protected]>
The FMan MAC FLib provides basic API used by the drivers to
configure and control the FMan MAC hardware.
Signed-off-by: Igal Liberman <[email protected]>
---
drivers/net/ethernet/freescale/fman/Makefile | 1 +
drivers/net/ethernet/freescale/fman/mac/Makefile | 5 +
.../net/ethernet/freescale/fman/mac/fman_dtsec.c | 571 +++++++++++++++++++++
.../freescale/fman/mac/fman_dtsec_mii_acc.c | 168 ++++++
.../net/ethernet/freescale/fman/mac/fman_memac.c | 365 +++++++++++++
.../freescale/fman/mac/fman_memac_mii_acc.c | 217 ++++++++
.../net/ethernet/freescale/fman/mac/fman_tgec.c | 217 ++++++++
7 files changed, 1544 insertions(+)
create mode 100644 drivers/net/ethernet/freescale/fman/mac/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_memac.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fman_tgec.c
diff --git a/drivers/net/ethernet/freescale/fman/Makefile b/drivers/net/ethernet/freescale/fman/Makefile
index 50a4de2..1841b03 100644
--- a/drivers/net/ethernet/freescale/fman/Makefile
+++ b/drivers/net/ethernet/freescale/fman/Makefile
@@ -5,3 +5,4 @@ obj-y += fsl_fman.o
fsl_fman-objs := fman.o
obj-y += port/
+obj-y += mac/
diff --git a/drivers/net/ethernet/freescale/fman/mac/Makefile b/drivers/net/ethernet/freescale/fman/mac/Makefile
new file mode 100644
index 0000000..ce03e25
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/Makefile
@@ -0,0 +1,5 @@
+obj-y += fsl_fman_mac.o
+
+fsl_fman_mac-objs := fman_dtsec.o fman_dtsec_mii_acc.o \
+ fman_memac.o fman_memac_mii_acc.o \
+ fman_tgec.o
diff --git a/drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c
new file mode 100644
index 0000000..290a037
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c
@@ -0,0 +1,571 @@
+/*
+ * 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 "fsl_fman_dtsec.h"
+
+void fman_dtsec_stop_rx(struct dtsec_regs __iomem *regs)
+{
+ /* Assert the graceful stop bit */
+ iowrite32be(ioread32be(®s->rctrl) | RCTRL_GRS, ®s->rctrl);
+}
+
+void fman_dtsec_stop_tx(struct dtsec_regs __iomem *regs)
+{
+ /* Assert the graceful stop bit */
+ iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_GTS, ®s->tctrl);
+}
+
+void fman_dtsec_start_tx(struct dtsec_regs __iomem *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_GTS, ®s->tctrl);
+}
+
+void fman_dtsec_start_rx(struct dtsec_regs __iomem *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_GRS, ®s->rctrl);
+}
+
+void fman_dtsec_defconfig(struct dtsec_cfg *cfg)
+{
+ cfg->halfdup_on = DEFAULT_HALFDUP_ON;
+ cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT;
+ cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW;
+ cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER;
+ cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF;
+ cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF;
+ cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL;
+ cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN;
+ cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST;
+ cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM;
+ cfg->rx_len_check = DEFAULT_RX_LEN_CHECK;
+ cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC;
+ cfg->tx_crc = DEFAULT_TX_CRC;
+ cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC;
+ cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME;
+ /* PHY address 0 is reserved (DPAA RM) */
+ cfg->tbipa = DEFAULT_TBIPA;
+ cfg->rx_prepend = DEFAULT_RX_PREPEND;
+ cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN;
+ cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN;
+ cfg->preamble_len = DEFAULT_PREAMBLE_LEN;
+ cfg->rx_preamble = DEFAULT_RX_PREAMBLE;
+ cfg->tx_preamble = DEFAULT_TX_PREAMBLE;
+ cfg->loopback = DEFAULT_LOOPBACK;
+ cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN;
+ cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN;
+ cfg->rx_flow = DEFAULT_RX_FLOW;
+ cfg->tx_flow = DEFAULT_TX_FLOW;
+ cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD;
+ cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD;
+ cfg->rx_promisc = DEFAULT_RX_PROMISC;
+ cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1;
+ cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2;
+ cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT;
+ cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG;
+ cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME;
+ cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR;
+ cfg->wake_on_lan = DEFAULT_WAKE_ON_LAN;
+}
+
+int fman_dtsec_init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
+ enum enet_interface iface_mode,
+ enum enet_speed iface_speed,
+ uint8_t *macaddr,
+ uint8_t __maybe_unused fm_rev_maj,
+ uint8_t __maybe_unused fm_rev_min, uint32_t exception_mask)
+{
+ bool is_rgmii, is_sgmii, is_qsgmii;
+ int i;
+ uint32_t tmp;
+
+ /* let's start with a soft reset */
+ iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1);
+ iowrite32be(0, ®s->maccfg1);
+
+ /*dtsec_id2*/
+ tmp = ioread32be(®s->tsec_id2);
+
+ /* check RGMII support */
+ if (iface_mode == E_ENET_IF_RGMII || iface_mode == E_ENET_IF_RMII)
+ if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
+ return -EINVAL;
+
+ if (iface_mode == E_ENET_IF_SGMII || iface_mode == E_ENET_IF_MII)
+ if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
+ return -EINVAL;
+
+ /*ECNTRL*/
+
+ is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? true : false);
+ is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? true : false);
+ is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? true : false);
+
+ tmp = 0;
+ if (is_rgmii || iface_mode == E_ENET_IF_GMII)
+ tmp |= DTSEC_ECNTRL_GMIIM;
+ if (is_sgmii)
+ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM);
+ if (is_qsgmii)
+ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM |
+ DTSEC_ECNTRL_QSGMIIM);
+ if (is_rgmii)
+ tmp |= DTSEC_ECNTRL_RPM;
+ if (iface_speed == E_ENET_SPEED_100)
+ tmp |= DTSEC_ECNTRL_R100M;
+
+ iowrite32be(tmp, ®s->ecntrl);
+ /*ECNTRL*/
+
+ /*TCTRL*/
+ tmp = 0;
+ if (cfg->halfdup_on)
+ tmp |= DTSEC_TCTRL_THDF;
+ if (cfg->tx_time_stamp_en)
+ tmp |= DTSEC_TCTRL_TTSE;
+
+ iowrite32be(tmp, ®s->tctrl);
+
+ /*TCTRL*/
+
+ /*PTV*/
+ tmp = 0;
+
+#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1
+ if ((fm_rev_maj == 1) && (fm_rev_min == 0))
+ cfg->tx_pause_time += 2;
+#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */
+
+ if (cfg->tx_pause_time)
+ tmp |= cfg->tx_pause_time;
+ if (cfg->tx_pause_time_extd)
+ tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST;
+ iowrite32be(tmp, ®s->ptv);
+
+ /*RCTRL*/
+ tmp = 0;
+ tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16;
+ if (cfg->rx_ctrl_acc)
+ tmp |= RCTRL_CFA;
+ if (cfg->rx_group_hash_exd)
+ tmp |= RCTRL_GHTX;
+ if (cfg->rx_time_stamp_en)
+ tmp |= RCTRL_RTSE;
+ if (cfg->rx_drop_bcast)
+ tmp |= RCTRL_BC_REJ;
+ if (cfg->rx_short_frm)
+ tmp |= RCTRL_RSF;
+ if (cfg->rx_promisc)
+ tmp |= RCTRL_PROM;
+
+ iowrite32be(tmp, ®s->rctrl);
+ /*RCTRL*/
+
+ /*Assign a Phy Address to the TBI (TBIPA).
+ *Done also in cases where TBI is not selected to avoid conflict with
+ *the external PHY's Physical address
+ */
+ iowrite32be(cfg->tbipa, ®s->tbipa);
+
+ /*TMR_CTL*/
+ iowrite32be(0, ®s->tmr_ctrl);
+
+ if (cfg->ptp_tsu_en) {
+ tmp = 0;
+ tmp |= TMR_PEVENT_TSRE;
+ iowrite32be(tmp, ®s->tmr_pevent);
+
+ if (cfg->ptp_exception_en) {
+ tmp = 0;
+ tmp |= TMR_PEMASK_TSREEN;
+ iowrite32be(tmp, ®s->tmr_pemask);
+ }
+ }
+
+ /*MACCFG1*/
+ tmp = 0;
+ if (cfg->loopback)
+ tmp |= MACCFG1_LOOPBACK;
+ if (cfg->rx_flow)
+ tmp |= MACCFG1_RX_FLOW;
+ if (cfg->tx_flow)
+ tmp |= MACCFG1_TX_FLOW;
+ iowrite32be(tmp, ®s->maccfg1);
+
+ /*MACCFG1*/
+
+ /*MACCFG2*/
+ tmp = 0;
+
+ if (iface_speed < E_ENET_SPEED_1000)
+ tmp |= MACCFG2_NIBBLE_MODE;
+ else if (iface_speed == E_ENET_SPEED_1000)
+ tmp |= MACCFG2_BYTE_MODE;
+
+ tmp |= ((uint32_t)cfg->preamble_len & 0x0000000f)
+ << PREAMBLE_LENGTH_SHIFT;
+
+ if (cfg->rx_preamble)
+ tmp |= MACCFG2_PRE_AM_RX_EN;
+ if (cfg->tx_preamble)
+ tmp |= MACCFG2_PRE_AM_TX_EN;
+ if (cfg->rx_len_check)
+ tmp |= MACCFG2_LENGTH_CHECK;
+ if (cfg->tx_pad_crc)
+ tmp |= MACCFG2_PAD_CRC_EN;
+ if (cfg->tx_crc)
+ tmp |= MACCFG2_CRC_EN;
+ if (!cfg->halfdup_on)
+ tmp |= MACCFG2_FULL_DUPLEX;
+ iowrite32be(tmp, ®s->maccfg2);
+
+ /*MACCFG2*/
+
+ /*IPGIFG*/
+ tmp = (((cfg->non_back_to_back_ipg1 <<
+ IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT)
+ & IPGIFG_NON_BACK_TO_BACK_IPG_1)
+ | ((cfg->non_back_to_back_ipg2 <<
+ IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT)
+ & IPGIFG_NON_BACK_TO_BACK_IPG_2)
+ | ((cfg->min_ifg_enforcement << IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT)
+ & IPGIFG_MIN_IFG_ENFORCEMENT)
+ | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG));
+ iowrite32be(tmp, ®s->ipgifg);
+
+ /*IPGIFG*/
+
+ /*HAFDUP*/
+ tmp = 0;
+
+ if (cfg->halfdup_alt_backoff_en)
+ tmp = (uint32_t)(HAFDUP_ALT_BEB |
+ ((cfg->halfdup_alt_backoff_val & 0x0000000f)
+ << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT));
+ if (cfg->halfdup_bp_no_backoff)
+ tmp |= HAFDUP_BP_NO_BACKOFF;
+ if (cfg->halfdup_no_backoff)
+ tmp |= HAFDUP_NO_BACKOFF;
+ if (cfg->halfdup_excess_defer)
+ tmp |= HAFDUP_EXCESS_DEFER;
+ tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT)
+ & HAFDUP_RETRANSMISSION_MAX);
+ tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW);
+
+ iowrite32be(tmp, ®s->hafdup);
+ /*HAFDUP*/
+
+ /*MAXFRM*/
+ /* Initialize MAXFRM */
+ iowrite32be(cfg->maximum_frame, ®s->maxfrm);
+
+ /*MAXFRM*/
+
+ /*CAM1*/
+ iowrite32be(0xffffffff, ®s->cam1);
+ iowrite32be(0xffffffff, ®s->cam2);
+
+ /*IMASK*/
+ iowrite32be(exception_mask, ®s->imask);
+ /*IMASK*/
+
+ /*IEVENT*/
+ iowrite32be(0xffffffff, ®s->ievent);
+
+ /*MACSTNADDR1/2*/
+
+ tmp = (uint32_t)((macaddr[5] << 24) |
+ (macaddr[4] << 16) | (macaddr[3] << 8) | macaddr[2]);
+ iowrite32be(tmp, ®s->macstnaddr1);
+
+ tmp = (uint32_t)((macaddr[1] << 24) | (macaddr[0] << 16));
+ iowrite32be(tmp, ®s->macstnaddr2);
+
+ /*MACSTNADDR1/2*/
+
+ /*HASH*/
+ for (i = 0; i < NUM_OF_HASH_REGS; i++) {
+ /* Initialize IADDRx */
+ iowrite32be(0, ®s->igaddr[i]);
+ /* Initialize GADDRx */
+ iowrite32be(0, ®s->gaddr[i]);
+ }
+
+ return 0;
+}
+
+uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs __iomem *regs)
+{
+ return (uint16_t)ioread32be(®s->maxfrm);
+}
+
+void fman_dtsec_set_max_frame_len(struct dtsec_regs __iomem *regs,
+ uint16_t length)
+{
+ iowrite32be(length, ®s->maxfrm);
+}
+
+void fman_dtsec_set_mac_address(struct dtsec_regs __iomem *regs, uint8_t *adr)
+{
+ uint32_t tmp;
+
+ tmp = (uint32_t)((adr[5] << 24) |
+ (adr[4] << 16) | (adr[3] << 8) | adr[2]);
+ iowrite32be(tmp, ®s->macstnaddr1);
+
+ tmp = (uint32_t)((adr[1] << 24) | (adr[0] << 16));
+ iowrite32be(tmp, ®s->macstnaddr2);
+}
+
+void fman_dtsec_get_mac_address(struct dtsec_regs __iomem *regs,
+ uint8_t *macaddr)
+{
+ uint32_t tmp1, tmp2;
+
+ tmp1 = ioread32be(®s->macstnaddr1);
+ tmp2 = ioread32be(®s->macstnaddr2);
+
+ macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16);
+ macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24);
+ macaddr[2] = (uint8_t)(tmp1 & 0x000000ff);
+ macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8);
+ macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16);
+ macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24);
+}
+
+void fman_dtsec_set_bucket(struct dtsec_regs __iomem *regs, int bucket,
+ bool enable)
+{
+ int reg_idx = (bucket >> 5) & 0xf;
+ int bit_idx = bucket & 0x1f;
+ uint32_t bit_mask = 0x80000000 >> bit_idx;
+ uint32_t __iomem *reg;
+
+ if (reg_idx > 7)
+ reg = ®s->gaddr[reg_idx - 8];
+ else
+ reg = ®s->igaddr[reg_idx];
+
+ if (enable)
+ iowrite32be(ioread32be(reg) | bit_mask, reg);
+ else
+ iowrite32be(ioread32be(reg) & (~bit_mask), reg);
+}
+
+int fman_dtsec_adjust_link(struct dtsec_regs __iomem *regs,
+ enum enet_interface __maybe_unused iface_mode,
+ enum enet_speed speed, bool full_dx)
+{
+ uint32_t tmp;
+
+ if ((speed == E_ENET_SPEED_1000) && !full_dx)
+ return -EINVAL;
+
+ tmp = ioread32be(®s->maccfg2);
+ if (!full_dx)
+ tmp &= ~MACCFG2_FULL_DUPLEX;
+ else
+ tmp |= MACCFG2_FULL_DUPLEX;
+
+ tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
+ if (speed < E_ENET_SPEED_1000)
+ tmp |= MACCFG2_NIBBLE_MODE;
+ else if (speed == E_ENET_SPEED_1000)
+ tmp |= MACCFG2_BYTE_MODE;
+ iowrite32be(tmp, ®s->maccfg2);
+
+ tmp = ioread32be(®s->ecntrl);
+ if (speed == E_ENET_SPEED_100)
+ tmp |= DTSEC_ECNTRL_R100M;
+ else
+ tmp &= ~DTSEC_ECNTRL_R100M;
+ iowrite32be(tmp, ®s->ecntrl);
+
+ return 0;
+}
+
+void fman_dtsec_set_uc_promisc(struct dtsec_regs __iomem *regs, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_UPROM;
+ else
+ tmp &= ~RCTRL_UPROM;
+
+ iowrite32be(tmp, ®s->rctrl);
+}
+
+void fman_dtsec_set_mc_promisc(struct dtsec_regs __iomem *regs, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_MPROM;
+ else
+ tmp &= ~RCTRL_MPROM;
+
+ iowrite32be(tmp, ®s->rctrl);
+}
+
+void fman_dtsec_enable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->maccfg1);
+
+ if (apply_rx)
+ tmp |= MACCFG1_RX_EN;
+
+ if (apply_tx)
+ tmp |= MACCFG1_TX_EN;
+
+ iowrite32be(tmp, ®s->maccfg1);
+}
+
+void fman_dtsec_disable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->maccfg1);
+
+ if (apply_rx)
+ tmp &= ~MACCFG1_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~MACCFG1_TX_EN;
+
+ iowrite32be(tmp, ®s->maccfg1);
+}
+
+void fman_dtsec_set_tx_pause_frames(struct dtsec_regs __iomem *regs,
+ uint16_t time)
+{
+ uint32_t ptv = 0;
+
+ /* fixme: don't enable tx pause for half-duplex */
+
+ if (time) {
+ ptv = ioread32be(®s->ptv);
+ ptv &= 0xffff0000;
+ ptv |= time & 0x0000ffff;
+ iowrite32be(ptv, ®s->ptv);
+
+ /* trigger the transmission of a flow-control pause frame */
+ iowrite32be(ioread32be(®s->maccfg1) | MACCFG1_TX_FLOW,
+ ®s->maccfg1);
+ } else
+ iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW,
+ ®s->maccfg1);
+}
+
+void fman_dtsec_handle_rx_pause(struct dtsec_regs __iomem *regs, bool en)
+{
+ uint32_t tmp;
+
+ /* todo: check if mac is set to full-duplex */
+
+ tmp = ioread32be(®s->maccfg1);
+ if (en)
+ tmp |= MACCFG1_RX_FLOW;
+ else
+ tmp &= ~MACCFG1_RX_FLOW;
+ iowrite32be(tmp, ®s->maccfg1);
+}
+
+uint32_t fman_dtsec_get_rctrl(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(®s->rctrl);
+}
+
+uint32_t fman_dtsec_get_revision(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(®s->tsec_id);
+}
+
+uint32_t fman_dtsec_get_event(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask)
+{
+ return ioread32be(®s->ievent) & ev_mask;
+}
+
+void fman_dtsec_ack_event(struct dtsec_regs __iomem *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, ®s->ievent);
+}
+
+uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(®s->imask);
+}
+
+uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs __iomem *regs)
+{
+ uint32_t event;
+
+ event = ioread32be(®s->tmr_pevent);
+ event &= ioread32be(®s->tmr_pemask);
+
+ if (event)
+ iowrite32be(event, ®s->tmr_pevent);
+ return event;
+}
+
+void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs __iomem *regs)
+{
+ iowrite32be(ioread32be(®s->tmr_pemask) | TMR_PEMASK_TSREEN,
+ ®s->tmr_pemask);
+}
+
+void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs __iomem *regs)
+{
+ iowrite32be(ioread32be(®s->tmr_pemask) & ~TMR_PEMASK_TSREEN,
+ ®s->tmr_pemask);
+}
+
+void fman_dtsec_enable_interrupt(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask);
+}
+
+void fman_dtsec_disable_interrupt(struct dtsec_regs __iomem *regs,
+ uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask);
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c
new file mode 100644
index 0000000..c393938
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c
@@ -0,0 +1,168 @@
+/*
+ * 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 "common/general.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+/*dtsec_mii_get_div() - calculates the value of the dtsec mii divider
+ *@dtsec_freq: dtsec clock frequency (in Mhz)
+ *This function calculates the dtsec mii clock divider that determines
+ *the MII MDC clock. MII MDC clock will be set to work in the range
+ *of 1.5 to 2.5Mhz
+ *The output of this function is the value of MIIMCFG[MgmtClk] which
+ *implicitly determines the divider value.
+ *Note: the dTSEC system clock is equal to 1/2 of the FMan clock.
+ *The table below which reflects dtsec_mii_get_div() functionality
+ *shows the relations among dtsec_freq, MgmtClk, actual divider
+ *and the MII frequency:
+ *dtsec freq MgmtClk div MII freq Mhz
+ *[0.....80] 1 (1/4)(1/8) [0 to 2.5]
+ *[81...120] 2 (1/6)(1/8) [1.6 to 2.5]
+ *[121..160] 3 (1/8)(1/8) [1.8 to 2.5]
+ *[161..200] 4 (1/10)(1/8) [2.0 to 2.5]
+ *[201..280] 5 (1/14)(1/8) [1.8 to 2.5]
+ *[281..400] 6 (1/20)(1/8) [1.1 to 2.5]
+ *[401..560] 7 (1/28)(1/8) [1.8 to 2.5]
+ *[560..frq] 7 (1/28)(1/8) [frq/224]
+ *Returns: the MIIMCFG[MgmtClk] appropriate value
+ */
+
+static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq)
+{
+ uint16_t mgmt_clk;
+
+ if (dtsec_freq < 80)
+ mgmt_clk = 1;
+ else if (dtsec_freq < 120)
+ mgmt_clk = 2;
+ else if (dtsec_freq < 160)
+ mgmt_clk = 3;
+ else if (dtsec_freq < 200)
+ mgmt_clk = 4;
+ else if (dtsec_freq < 280)
+ mgmt_clk = 5;
+ else if (dtsec_freq < 400)
+ mgmt_clk = 6;
+ else
+ mgmt_clk = 7;
+
+ return (uint8_t)mgmt_clk;
+}
+
+void fman_dtsec_mii_reset(struct dtsec_mii_reg __iomem *regs)
+{
+ /* Reset the management interface */
+ iowrite32be(ioread32be(®s->miimcfg) | MIIMCFG_RESET_MGMT,
+ ®s->miimcfg);
+ iowrite32be(ioread32be(®s->miimcfg) & ~MIIMCFG_RESET_MGMT,
+ ®s->miimcfg);
+}
+
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg __iomem *regs, uint8_t addr,
+ uint8_t reg, uint16_t data, uint16_t dtsec_freq)
+{
+ uint32_t tmp;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg);
+ /* Memory barrier */
+ wmb();
+
+ /* Stop the MII management read cycle */
+ iowrite32be(0, ®s->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(®s->miimcom);
+ /* Memory barrier */
+ wmb();
+
+ /* Setting up MII Management Address Register */
+ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, ®s->miimadd);
+ /* Memory barrier */
+ wmb();
+
+ /* Setting up MII Management Control Register with data */
+ iowrite32be((uint32_t)data, ®s->miimcon);
+ /* Dummy read to make sure MIIMCON is written */
+ tmp = ioread32be(®s->miimcon);
+ /* Memory barrier */
+ wmb();
+
+ /* Wait until MII management write is complete */
+ /* todo: a timeout could be useful here */
+ while ((ioread32be(®s->miimind)) & MIIMIND_BUSY)
+ ; /* busy wait */
+
+ return 0;
+}
+
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg __iomem *regs, uint8_t addr,
+ uint8_t reg, uint16_t *data, uint16_t dtsec_freq)
+{
+ uint32_t tmp;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg);
+ /* Memory barrier */
+ wmb();
+
+ /* Setting up the MII Management Address Register */
+ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, ®s->miimadd);
+ /* Memory barrier */
+ wmb();
+
+ /* Perform an MII management read cycle */
+ iowrite32be(MIIMCOM_READ_CYCLE, ®s->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(®s->miimcom);
+ /* Memory barrier */
+ wmb();
+
+ /* Wait until MII management read is complete */
+ /* todo: a timeout could be useful here */
+ while ((ioread32be(®s->miimind)) & MIIMIND_BUSY)
+ ; /* busy wait */
+
+ /* Read MII management status */
+ *data = (uint16_t)ioread32be(®s->miimstat);
+ /* Memory barrier */
+ wmb();
+
+ iowrite32be(0, ®s->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(®s->miimcom);
+
+ if (*data == 0xffff)
+ return -ENXIO;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fman_memac.c b/drivers/net/ethernet/freescale/fman/mac/fman_memac.c
new file mode 100644
index 0000000..e0bac5a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_memac.c
@@ -0,0 +1,365 @@
+/*
+ * 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 "fsl_fman_memac.h"
+
+uint32_t fman_memac_get_event(struct memac_regs __iomem *regs, uint32_t ev_mask)
+{
+ return ioread32be(®s->ievent) & ev_mask;
+}
+
+uint32_t fman_memac_get_interrupt_mask(struct memac_regs __iomem *regs)
+{
+ return ioread32be(®s->imask);
+}
+
+void fman_memac_ack_event(struct memac_regs __iomem *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, ®s->ievent);
+}
+
+void fman_memac_set_promiscuous(struct memac_regs __iomem *regs, bool val)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs __iomem *regs,
+ uint8_t paddr_num)
+{
+ if (paddr_num == 0) {
+ iowrite32be(0, ®s->mac_addr0.mac_addr_l);
+ iowrite32be(0, ®s->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_l);
+ iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_u);
+ }
+}
+
+void fman_memac_add_addr_in_paddr(struct memac_regs __iomem *regs,
+ uint8_t *adr, uint8_t paddr_num)
+{
+ uint32_t tmp0, tmp1;
+
+ tmp0 = (uint32_t)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24);
+ tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
+
+ if (paddr_num == 0) {
+ iowrite32be(tmp0, ®s->mac_addr0.mac_addr_l);
+ iowrite32be(tmp1, ®s->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(tmp0, ®s->mac_addr[paddr_num - 1].mac_addr_l);
+ iowrite32be(tmp1, ®s->mac_addr[paddr_num - 1].mac_addr_u);
+ }
+}
+
+void fman_memac_enable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_memac_disable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+
+ if (apply_rx)
+ tmp &= ~CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_memac_reset(struct memac_regs __iomem *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+
+ tmp |= CMD_CFG_SW_RESET;
+
+ iowrite32be(tmp, ®s->command_config);
+
+ while (ioread32be(®s->command_config) & CMD_CFG_SW_RESET)
+ ;
+}
+
+int fman_memac_init(struct memac_regs __iomem *regs,
+ struct memac_cfg *cfg,
+ enum enet_interface enet_interface,
+ enum enet_speed enet_speed,
+ bool slow_10g_if,
+ uint32_t exceptions)
+{
+ uint32_t tmp;
+
+ /* Config */
+ tmp = 0;
+ if (cfg->wan_mode_enable)
+ tmp |= CMD_CFG_WAN_MODE;
+ if (cfg->promiscuous_mode_enable)
+ tmp |= CMD_CFG_PROMIS_EN;
+ if (cfg->pause_forward_enable)
+ tmp |= CMD_CFG_PAUSE_FWD;
+ if (cfg->pause_ignore)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ if (cfg->tx_addr_ins_enable)
+ tmp |= CMD_CFG_TX_ADDR_INS;
+ if (cfg->loopback_enable)
+ tmp |= CMD_CFG_LOOPBACK_EN;
+ if (cfg->cmd_frame_enable)
+ tmp |= CMD_CFG_CNT_FRM_EN;
+ if (cfg->send_idle_enable)
+ tmp |= CMD_CFG_SEND_IDLE;
+ if (cfg->no_length_check_enable)
+ tmp |= CMD_CFG_NO_LEN_CHK;
+ if (cfg->rx_sfd_any)
+ tmp |= CMD_CFG_SFD_ANY;
+ if (cfg->pad_enable)
+ tmp |= CMD_CFG_TX_PAD_EN;
+ if (cfg->wake_on_lan)
+ tmp |= CMD_CFG_MG;
+
+ tmp |= CMD_CFG_CRC_FWD;
+
+ iowrite32be(tmp, ®s->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm);
+
+ /* Pause Time */
+ iowrite32be((uint32_t)cfg->pause_quanta, ®s->pause_quanta[0]);
+ iowrite32be((uint32_t)0, ®s->pause_thresh[0]);
+
+ /* IF_MODE */
+ tmp = 0;
+ switch (enet_interface) {
+ case E_ENET_IF_XGMII:
+ case E_ENET_IF_XFI:
+ tmp |= IF_MODE_XGMII;
+ break;
+ default:
+ tmp |= IF_MODE_GMII;
+ if (enet_interface == E_ENET_IF_RGMII && !cfg->loopback_enable)
+ tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO;
+ }
+ iowrite32be(tmp, ®s->if_mode);
+
+ /* TX_FIFO_SECTIONS */
+ tmp = 0;
+ if (enet_interface == E_ENET_IF_XGMII ||
+ enet_interface == E_ENET_IF_XFI) {
+ if (slow_10g_if) {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
+ } else {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
+ }
+ } else {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G);
+ }
+ iowrite32be(tmp, ®s->tx_fifo_sections);
+
+ /* clear all pending events and set-up interrupts */
+ fman_memac_ack_event(regs, 0xffffffff);
+ fman_memac_set_exception(regs, exceptions, true);
+
+ return 0;
+}
+
+void fman_memac_set_exception(struct memac_regs __iomem *regs, uint32_t val,
+ bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->imask);
+ if (enable)
+ tmp |= val;
+ else
+ tmp &= ~val;
+
+ iowrite32be(tmp, ®s->imask);
+}
+
+void fman_memac_set_hash_table(struct memac_regs __iomem *regs, uint32_t val)
+{
+ iowrite32be(val, ®s->hashtable_ctrl);
+}
+
+uint16_t fman_memac_get_max_frame_len(struct memac_regs __iomem *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->maxfrm);
+
+ return (uint16_t)tmp;
+}
+
+void fman_memac_set_tx_pause_frames(struct memac_regs __iomem *regs,
+ uint8_t priority,
+ uint16_t pause_time, uint16_t thresh_time)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->tx_fifo_sections);
+
+ GET_TX_EMPTY_DEFAULT_VALUE(tmp);
+ iowrite32be(tmp, ®s->tx_fifo_sections);
+
+ tmp = ioread32be(®s->command_config);
+ tmp &= ~CMD_CFG_PFC_MODE;
+ priority = 0;
+
+ iowrite32be(tmp, ®s->command_config);
+
+ tmp = ioread32be(®s->pause_quanta[priority / 2]);
+ if (priority % 2)
+ tmp &= 0x0000FFFF;
+ else
+ tmp &= 0xFFFF0000;
+ tmp |= ((uint32_t)pause_time << (16 * (priority % 2)));
+ iowrite32be(tmp, ®s->pause_quanta[priority / 2]);
+
+ tmp = ioread32be(®s->pause_thresh[priority / 2]);
+ if (priority % 2)
+ tmp &= 0x0000FFFF;
+ else
+ tmp &= 0xFFFF0000;
+ tmp |= ((uint32_t)thresh_time << (16 * (priority % 2)));
+ iowrite32be(tmp, ®s->pause_thresh[priority / 2]);
+}
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs __iomem *regs,
+ bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+ if (enable)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_memac_adjust_link(struct memac_regs __iomem *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->if_mode);
+
+ if (full_dx)
+ tmp &= ~IF_MODE_HD;
+ else
+ tmp |= IF_MODE_HD;
+
+ if (iface_mode == E_ENET_IF_RGMII) {
+ /* Configure RGMII in manual mode */
+ tmp &= ~IF_MODE_RGMII_AUTO;
+ tmp &= ~IF_MODE_RGMII_SP_MASK;
+
+ if (full_dx)
+ tmp |= IF_MODE_RGMII_FD;
+ else
+ tmp &= ~IF_MODE_RGMII_FD;
+
+ switch (speed) {
+ case E_ENET_SPEED_1000:
+ tmp |= IF_MODE_RGMII_1000;
+ break;
+ case E_ENET_SPEED_100:
+ tmp |= IF_MODE_RGMII_100;
+ break;
+ case E_ENET_SPEED_10:
+ tmp |= IF_MODE_RGMII_10;
+ break;
+ default:
+ break;
+ }
+ }
+
+ iowrite32be(tmp, ®s->if_mode);
+}
+
+void fman_memac_defconfig(struct memac_cfg *cfg)
+{
+ cfg->reset_on_init = false;
+ cfg->wan_mode_enable = false;
+ cfg->promiscuous_mode_enable = false;
+ cfg->pause_forward_enable = false;
+ cfg->pause_ignore = false;
+ cfg->tx_addr_ins_enable = false;
+ cfg->loopback_enable = false;
+ cfg->cmd_frame_enable = false;
+ cfg->rx_error_discard = false;
+ cfg->send_idle_enable = false;
+ cfg->no_length_check_enable = true;
+ cfg->lgth_check_nostdr = false;
+ cfg->time_stamp_enable = false;
+ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
+ cfg->max_frame_length = DEFAULT_FRAME_LENGTH;
+ cfg->pause_quanta = DEFAULT_PAUSE_QUANTA;
+ cfg->pad_enable = true;
+ cfg->phy_tx_ena_on = false;
+ cfg->rx_sfd_any = false;
+ cfg->rx_pbl_fwd = false;
+ cfg->tx_pbl_fwd = false;
+ cfg->debug_mode = false;
+ cfg->wake_on_lan = false;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c b/drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c
new file mode 100644
index 0000000..7addd6d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c
@@ -0,0 +1,217 @@
+/*
+ * 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 "fsl_fman_memac_mii_acc.h"
+
+static void write_phy_reg_10g(struct memac_mii_access_mem_map __iomem *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ /* Leave only MDIO_CLK_DIV bits set on */
+ tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
+ /* Set maximum MDIO_HOLD value to allow phy to see
+ * change of data signal
+ **/
+ tmp_reg |= MDIO_CFG_HOLD_MASK;
+ /* Add 10G interface mode */
+ tmp_reg |= MDIO_CFG_ENC45;
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Specify phy and register to be accessed */
+ iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
+ iowrite32be(reg, &mii_regs->mdio_addr);
+ /* memory barrier */
+ wmb();
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Write data */
+ iowrite32be(data, &mii_regs->mdio_data);
+ /* memory barrier */
+ wmb();
+
+ /* Wait for write transaction end */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+}
+
+static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t *data)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ /* Leave only MDIO_CLK_DIV bits set on */
+ tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
+ /* Set maximum MDIO_HOLD value to allow phy to see
+ * change of data signal
+ **/
+ tmp_reg |= MDIO_CFG_HOLD_MASK;
+ /* Add 10G interface mode */
+ tmp_reg |= MDIO_CFG_ENC45;
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Specify phy and register to be accessed */
+ iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
+ iowrite32be(reg, &mii_regs->mdio_addr);
+ /* memory barrier */
+ wmb();
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Read cycle */
+ tmp_reg = phy_addr;
+ tmp_reg |= MDIO_CTL_READ;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+ /* memory barrier */
+ wmb();
+
+ /* Wait for data to be available */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+
+ *data = (uint16_t)ioread32be(&mii_regs->mdio_data);
+
+ /* Check if there was an error */
+ return ioread32be(&mii_regs->mdio_cfg);
+}
+
+static void write_phy_reg_1g(struct memac_mii_access_mem_map __iomem *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data)
+{
+ uint32_t tmp_reg;
+
+ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Write transaction */
+ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
+ tmp_reg |= reg;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ iowrite32be(data, &mii_regs->mdio_data);
+
+ /* memory barrier */
+ wmb();
+
+ /* Wait for write transaction to end */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+}
+
+static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t *data)
+{
+ uint32_t tmp_reg;
+
+ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Read transaction */
+ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
+ tmp_reg |= reg;
+ tmp_reg |= MDIO_CTL_READ;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Wait for data to be available */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+
+ *data = (uint16_t)ioread32be(&mii_regs->mdio_data);
+
+ /* Check error */
+ return ioread32be(&mii_regs->mdio_cfg);
+}
+
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t data, enum enet_speed enet_speed)
+{
+ /* Figure out interface type - 10G vs 1G.
+ * In 10G interface both phy_addr and devAddr present.
+ **/
+ if (enet_speed == E_ENET_SPEED_10000)
+ write_phy_reg_10g(mii_regs, phy_addr, reg, data);
+ else
+ write_phy_reg_1g(mii_regs, phy_addr, reg, data);
+
+ return 0;
+}
+
+int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, uint8_t phy_addr, uint8_t reg,
+ uint16_t *data, enum enet_speed enet_speed)
+{
+ uint32_t ans;
+ /* Figure out interface type - 10G vs 1G.
+ * In 10G interface both phy_addr and devAddr present.
+ **/
+ if (enet_speed == E_ENET_SPEED_10000)
+ ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data);
+ else
+ ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data);
+
+ if (ans & MDIO_CFG_READ_ERR)
+ return -EINVAL;
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/fman/mac/fman_tgec.c b/drivers/net/ethernet/freescale/fman/mac/fman_tgec.c
new file mode 100644
index 0000000..11bcc1a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_tgec.c
@@ -0,0 +1,217 @@
+/*
+ * 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 "fsl_fman_tgec.h"
+
+void fman_tgec_set_mac_address(struct tgec_regs __iomem *regs, uint8_t *adr)
+{
+ uint32_t tmp0, tmp1;
+
+ tmp0 = (uint32_t)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24);
+ tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
+ iowrite32be(tmp0, ®s->mac_addr_0);
+ iowrite32be(tmp1, ®s->mac_addr_1);
+}
+
+void fman_tgec_enable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_tgec_disable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ uint32_t tmp_reg_32;
+
+ tmp_reg_32 = ioread32be(®s->command_config);
+ if (apply_rx)
+ tmp_reg_32 &= ~CMD_CFG_RX_EN;
+ if (apply_tx)
+ tmp_reg_32 &= ~CMD_CFG_TX_EN;
+ iowrite32be(tmp_reg_32, ®s->command_config);
+}
+
+void fman_tgec_set_promiscuous(struct tgec_regs __iomem *regs, bool val)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+ iowrite32be(tmp, ®s->command_config);
+}
+
+void fman_tgec_set_hash_table(struct tgec_regs __iomem *regs, uint32_t value)
+{
+ iowrite32be(value, ®s->hashtable_ctrl);
+}
+
+void fman_tgec_set_tx_pause_frames(struct tgec_regs __iomem *regs,
+ uint16_t pause_time)
+{
+ iowrite32be((uint32_t)pause_time, ®s->pause_quant);
+}
+
+void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs __iomem *regs,
+ bool en)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(®s->command_config);
+ if (en)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+ iowrite32be(tmp, ®s->command_config);
+}
+
+uint32_t fman_tgec_get_event(struct tgec_regs __iomem *regs, uint32_t ev_mask)
+{
+ return ioread32be(®s->ievent) & ev_mask;
+}
+
+void fman_tgec_ack_event(struct tgec_regs __iomem *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, ®s->ievent);
+}
+
+uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs __iomem *regs)
+{
+ return ioread32be(®s->imask);
+}
+
+uint32_t fman_tgec_get_revision(struct tgec_regs __iomem *regs)
+{
+ return ioread32be(®s->tgec_id);
+}
+
+void fman_tgec_enable_interrupt(struct tgec_regs __iomem *regs,
+ uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask);
+}
+
+void fman_tgec_disable_interrupt(struct tgec_regs __iomem *regs,
+ uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask);
+}
+
+uint16_t fman_tgec_get_max_frame_len(struct tgec_regs __iomem *regs)
+{
+ return (uint16_t)ioread32be(®s->maxfrm);
+}
+
+void fman_tgec_defconfig(struct tgec_cfg *cfg)
+{
+ cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE;
+ cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE;
+ cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE;
+ cfg->pause_ignore = DEFAULT_PAUSE_IGNORE;
+ cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE;
+ cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE;
+ cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE;
+ cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD;
+ cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE;
+ cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE;
+ cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR;
+ cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE;
+ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
+ cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH;
+ cfg->pause_quant = DEFAULT_PAUSE_QUANT;
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ cfg->skip_fman11_workaround = false;
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+}
+
+int fman_tgec_init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
+ uint32_t exception_mask)
+{
+ uint32_t tmp;
+
+ /* Config */
+ tmp = 0x40; /* CRC forward */
+ if (cfg->wan_mode_enable)
+ tmp |= CMD_CFG_WAN_MODE;
+ if (cfg->promiscuous_mode_enable)
+ tmp |= CMD_CFG_PROMIS_EN;
+ if (cfg->pause_forward_enable)
+ tmp |= CMD_CFG_PAUSE_FWD;
+ if (cfg->pause_ignore)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ if (cfg->tx_addr_ins_enable)
+ tmp |= CMD_CFG_TX_ADDR_INS;
+ if (cfg->loopback_enable)
+ tmp |= CMD_CFG_LOOPBACK_EN;
+ if (cfg->cmd_frame_enable)
+ tmp |= CMD_CFG_CMD_FRM_EN;
+ if (cfg->rx_error_discard)
+ tmp |= CMD_CFG_RX_ER_DISC;
+ if (cfg->send_idle_enable)
+ tmp |= CMD_CFG_SEND_IDLE;
+ if (cfg->no_length_check_enable)
+ tmp |= CMD_CFG_NO_LEN_CHK;
+ if (cfg->time_stamp_enable)
+ tmp |= CMD_CFG_EN_TIMESTAMP;
+ iowrite32be(tmp, ®s->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm);
+ /* Pause Time */
+ iowrite32be(cfg->pause_quant, ®s->pause_quant);
+
+ /* clear all pending events and set-up interrupts */
+ fman_tgec_ack_event(regs, 0xffffffff);
+ fman_tgec_enable_interrupt(regs, exception_mask);
+
+ return 0;
+}
+
+void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs
+ __iomem *regs)
+{
+ uint32_t tmp;
+
+ /* restore the default tx ipg Length */
+ tmp = (ioread32be(®s->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12;
+
+ iowrite32be(tmp, ®s->tx_ipg_len);
+}
--
1.7.11.7
On Wed, 2015-06-10 at 18:21 +0300, Madalin Bucur wrote:
> From: Igal Liberman <[email protected]>
>
> This patch presents the FMan Foundation Libraries (FLIB) headers.
> The FMan FLib provides the basic API used by the FMan drivers to
> configure and control the FMan hardware.
>
> Signed-off-by: Igal Liberman <[email protected]>
> ---
> .../ethernet/freescale/fman/flib/common/general.h | 41 ++
> .../net/ethernet/freescale/fman/flib/fsl_fman.h | 609
> +++++++++++++++++++++
> 2 files changed, 650 insertions(+)
> create mode 100644
> drivers/net/ethernet/freescale/fman/flib/common/general.h
> create mode 100644
> drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
Why do we need separate patches just for headers?
What does "common" refer to?
What does the flib directory mean, in the context of Linux? If
someone were to add code to this driver, how do they know if the code
should go into the flib directory or not?
>
> +#define iowrite32be(val, addr) out_be32(&(*addr), val)
> +#define ioread32be(addr) in_be32(&(*addr))
iowrite32be()/ioread32be() are already defined for all relevant
architectures. Why are you redefining them into something PPC-
specific?
> +/* do not change! if changed, must be disabled for rev1 ! */
> +#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION false
> +/* do not change! if changed, must be disabled for rev1 ! */
> +#define DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR false
rev1 of what chip?
-Scott
You should note that I started with scanning this patch for basic, say,
build system issues. Which I did find. But then I kept spotting all kind
of oddities. After a while I stopped looking closely. So, to note
something, I haven't yet looked into the 24 symbols this series exports.
There might be a reason for all 24 of them, but I just thought it a bit
suspect.
But, anyhow, my guess is this series needs a close look or two before
the people understanding ethernet drivers (I'm not one of them) will
consider reviewing it for more substantial issues.
On Wed, 2015-06-10 at 18:21 +0300, Madalin Bucur wrote:
> --- a/drivers/net/ethernet/freescale/fman/Kconfig
> +++ b/drivers/net/ethernet/freescale/fman/Kconfig
> +if FSL_FMAN
> +
> +config FSL_FM_MAX_FRAME_SIZE
> + int "Maximum L2 frame size"
> + depends on FSL_FMAN
This dependency is already provided through "if FSL_MAN" above.
> + 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"
> + depends on FSL_FMAN
Ditto.
> + 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
> --- a/drivers/net/ethernet/freescale/fman/Makefile
> +++ b/drivers/net/ethernet/freescale/fman/Makefile
>
> 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
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/fman/fm.c
> +/* static functions */
There's no need to tell us that.
> +static int check_fm_parameters(struct fm_t *p_fm)
> +{
> +#ifdef FM_AID_MODE_NO_TNUM_SW005
I think this is always defined (I already deleted that part of the
patch, so perhaps I'm missing some subtle issue).
> + 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;
> + }
> +#endif /* FM_AID_MODE_NO_TNUM_SW005 */
> +#ifdef FM_HAS_TOTAL_DMAS
Ditto.
> + 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;
> + }
> +#endif /* FM_HAS_TOTAL_DMAS */
> +#ifdef FM_NO_WATCHDOG
Ditto. I'll stop checking for this stuff now. Please clean them up (or
show me that I'm wrong).
> + 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;
> + }
> +#endif /* FM_NO_WATCHDOG */
> +/* fm_init
> + *
> + * Initializes the FM module
> + *
> + * @Param[in] p_fm - FM module descriptor
> + *
> + * @Return 0 on success; Error code otherwise.
> + */
I know little about kerneldoc, but this is not kerneldoc, right?
> +/* fm_free
> + * Frees all resources that were assigned to FM module.
> + * Calling this routine invalidates the descriptor.
> + * p_fm - FM module descriptor
> + *Return 0 on success; Error code otherwise.
> + */
Ditto.
> +void fm_event_isr(struct fm_t *p_fm)
> +{
> +#define FM_M_CALL_MAC_ISR(_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))
> + uint32_t pending;
> + int ret;
> + struct fman_fpm_regs __iomem *fpm_rg;
There must be a nicer way than to put a #define just before the local
variables.
> +int fm_error_isr(struct fm_t *p_fm)
> +{
> +#define FM_M_CALL_MAC_ERR_ISR(_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))
> + uint32_t pending;
> + struct fman_fpm_regs __iomem *fpm_rg;
> + int ret;
Ditto.
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/fman/fm.h
> +/* list_object
> + * Macro to get the struct (object) for this entry.
> + * type - The type of the struct (object) this list
> + * is embedded in.
> + * member - The name of the struct list_head object
> + * within the struct.
> + * Return The structure pointer for this entry.
> + */
> +#define member_offset(type, member) (PTR_TO_UINT(&((type *)0)->member))
> +#define list_object(p_list, type, member) \
> +((type *)((char *)(p_list) - member_offset(type, member)))
Aren't there any global #defines that already do (something like) this?
> +++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
> +static void destroy_fm_dev(struct fm_drv_t *p_fm_drv)
> +{
> + kfree(p_fm_drv);
> +}
Why do you wrap kfree() here?
> +/**
> +*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 Fmen use the same firmware.
> + */
/**
*new_style - a new comment style
*
*This is a new style of comment formatting.
*Do people like it?
*/
> +static int /*__devinit*/ fm_probe(struct platform_device *of_dev)
Please remove commented out code before submitting.
> +static const struct of_device_id fm_match[] = {
> + {
> + .compatible = "fsl,fman"},
> + {}
> +};
> +
> +#ifndef MODULE
> +MODULE_DEVICE_TABLE(of, fm_match);
> +#endif /* !MODULE */
include/linux/module.h reads (summarized):
#ifdef MODULE
#define MODULE_DEVICE_TABLE(type, name) \
extern const typeof(name) __mod_##type##__##name##_device_table \
__attribute__ ((unused, alias(__stringify(name))))
#else /* !MODULE */
#define MODULE_DEVICE_TABLE(type, name)
#endif
So please drop the #ifndef wrapper.
> +void *fm_drv_init(void)
static.
> +{
> + memset(&fm_drvs, 0, sizeof(fm_drvs));
> + mutex_init(&fm_drv_mutex);
> +
> + /* Register to the DTB for basic FM API */
> + platform_driver_register(&fm_driver);
> +
> + return &fm_drvs;
> +}
> +
> +int fm_drv_free(void *p_fm_drv)
static.
> +{
> + platform_driver_unregister(&fm_driver);
> + mutex_destroy(&fm_drv_mutex);
> +
> + return 0;
> +}
And p_fm_drv is unused in the function (and see below).
> +static void *p_fm_drv;
> +static int __init __cold fm_load(void)
> +{
> + p_fm_drv = fm_drv_init();
> + if (!p_fm_drv) {
> + pr_err("Failed to init FM wrapper!\n");
> + return -ENODEV;
> + }
> +
> + pr_info("Freescale FM module\n");
> + return 0;
> +}
> +
> +static void __exit __cold fm_unload(void)
> +{
> + if (p_fm_drv)
> + fm_drv_free(p_fm_drv);
> +}
How can p_fm_drv be NULL if fm_load() succeeded? If think that variable
isn't needed at all.
And by the way: p_, because it's a pointer? Don't do that, that's
silly.
> +module_init(fm_load);
> +module_exit(fm_unload);
FSL_FMAN is bool (see 7/12) and fm_drv.o can only be built-in, as far as
I could (quickly) see. But the code is using a few module specific
constructs. Was FSL_FMAN perhaps meant to be tristate?
Thanks,
Paul Bolle
So I couldn't help having yet another look at the code, just to drive
home my point.
On Thu, 2015-06-11 at 10:55 +0200, Paul Bolle wrote:
> > +void *fm_drv_init(void)
>
> static.
>
> > +{
> > + memset(&fm_drvs, 0, sizeof(fm_drvs));
fm_drvs is an external variable. It is guaranteed to be zero, isn't it?
> > + mutex_init(&fm_drv_mutex);
> > +
> > + /* Register to the DTB for basic FM API */
> > + platform_driver_register(&fm_driver);
> > +
> > + return &fm_drvs;
You're returning a pointer to external variable. How's that useful?
And note this is the last time we'll ever see fm_drvs. So I think that
all this variable does for the code is getting initialized to zero,
twice.
> > +}
> > +
> > +int fm_drv_free(void *p_fm_drv)
>
> static.
>
> > +{
> > + platform_driver_unregister(&fm_driver);
> > + mutex_destroy(&fm_drv_mutex);
> > +
> > + return 0;
This function has one caller, which doesn't check the return value. So
this should be a function returning void. Of course, a wrapper of two
lines called only once means you should actually not put this into a
separate function.
> > +}
> > +static void *p_fm_drv;
>
> > +static int __init __cold fm_load(void)
> > +{
> > + p_fm_drv = fm_drv_init();
> > + if (!p_fm_drv) {
fm_drv_init() returns a pointer to an external variable. So how can this
happen?
> > + pr_err("Failed to init FM wrapper!\n");
> > + return -ENODEV;
> > + }
> > +
> > + pr_info("Freescale FM module\n");
> > + return 0;
> > +}
This is all rather basic. It must be, otherwise I wouldn't spot it.
So I keep spotting these basic oddities, with every cup of coffee I
treat myself to while reading through this, wherever I look. By now I'm
sure there's no need for the netdev people to look at this, not yet.
Paul Bolle
Hi Paul,
Thank you very much for your feedback.
I'm planning to address the issues you've raised in the next submission.
Regards,
Igal Liberman.
> -----Original Message-----
> From: Paul Bolle [mailto:[email protected]]
> Sent: Thursday, June 11, 2015 12:38 PM
> To: Bucur Madalin-Cristian-B32716
> Cc: [email protected]; [email protected]; linuxppc-
> [email protected]; Wood Scott-B07421; Liberman Igal-B31950
> Subject: Re: [PATCH 08/12] fsl/fman: Add Frame Manager support
>
> So I couldn't help having yet another look at the code, just to drive home my
> point.
>
> On Thu, 2015-06-11 at 10:55 +0200, Paul Bolle wrote:
> > > +void *fm_drv_init(void)
> >
> > static.
> >
> > > +{
> > > + memset(&fm_drvs, 0, sizeof(fm_drvs));
>
> fm_drvs is an external variable. It is guaranteed to be zero, isn't it?
>
> > > + mutex_init(&fm_drv_mutex);
> > > +
> > > + /* Register to the DTB for basic FM API */
> > > + platform_driver_register(&fm_driver);
> > > +
> > > + return &fm_drvs;
>
> You're returning a pointer to external variable. How's that useful?
>
> And note this is the last time we'll ever see fm_drvs. So I think that all this
> variable does for the code is getting initialized to zero, twice.
>
> > > +}
> > > +
> > > +int fm_drv_free(void *p_fm_drv)
> >
> > static.
> >
> > > +{
> > > + platform_driver_unregister(&fm_driver);
> > > + mutex_destroy(&fm_drv_mutex);
> > > +
> > > + return 0;
>
> This function has one caller, which doesn't check the return value. So this
> should be a function returning void. Of course, a wrapper of two lines called
> only once means you should actually not put this into a separate function.
>
> > > +}
>
> > > +static void *p_fm_drv;
> >
> > > +static int __init __cold fm_load(void) {
> > > + p_fm_drv = fm_drv_init();
> > > + if (!p_fm_drv) {
>
> fm_drv_init() returns a pointer to an external variable. So how can this
> happen?
>
> > > + pr_err("Failed to init FM wrapper!\n");
> > > + return -ENODEV;
> > > + }
> > > +
> > > + pr_info("Freescale FM module\n");
> > > + return 0;
> > > +}
>
> This is all rather basic. It must be, otherwise I wouldn't spot it.
>
> So I keep spotting these basic oddities, with every cup of coffee I treat
> myself to while reading through this, wherever I look. By now I'm sure
> there's no need for the netdev people to look at this, not yet.
>
>
> Paul Bolle
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
Regards,
Igal Liberman.
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Wednesday, June 10, 2015 9:54 PM
> To: Bucur Madalin-Cristian-B32716
> Cc: [email protected]; [email protected]; linuxppc-
> [email protected]; Liberman Igal-B31950
> Subject: Re: [PATCH 01/12] fsl/fman: Add the FMan FLIB headers
>
> On Wed, 2015-06-10 at 18:21 +0300, Madalin Bucur wrote:
> > From: Igal Liberman <[email protected]>
> >
> > This patch presents the FMan Foundation Libraries (FLIB) headers.
> > The FMan FLib provides the basic API used by the FMan drivers to
> > configure and control the FMan hardware.
> >
> > Signed-off-by: Igal Liberman <[email protected]>
> > ---
> > .../ethernet/freescale/fman/flib/common/general.h | 41 ++
> > .../net/ethernet/freescale/fman/flib/fsl_fman.h | 609
> > +++++++++++++++++++++
> > 2 files changed, 650 insertions(+)
> > create mode 100644
> > drivers/net/ethernet/freescale/fman/flib/common/general.h
> > create mode 100644
> > drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
>
> Why do we need separate patches just for headers?
>
We wanted to make the patches smaller, it's the main reason for this separation.
> What does "common" refer to?
>
I removed ./flib/common.
> What does the flib directory mean, in the context of Linux? If someone were
> to add code to this driver, how do they know if the code should go into the
> flib directory or not?
>
> >
> > +#define iowrite32be(val, addr) out_be32(&(*addr), val)
> > +#define ioread32be(addr) in_be32(&(*addr))
>
> iowrite32be()/ioread32be() are already defined for all relevant architectures.
> Why are you redefining them into something PPC- specific?
>
Removed those.
> > +/* do not change! if changed, must be disabled for rev1 ! */ #define
> > +DEFAULT_HALT_ON_EXTERNAL_ACTIVATION false
> > +/* do not change! if changed, must be disabled for rev1 ! */ #define
> > +DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR false
>
> rev1 of what chip?
>
P4080. I'll update the comments.
> -Scott
Igal.
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
On Wed, 2015-06-17 at 09:59 -0500, Liberman Igal-B31950 wrote:
>
> Regards,
> Igal Liberman.
>
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Wednesday, June 10, 2015 9:54 PM
> > To: Bucur Madalin-Cristian-B32716
> > Cc: [email protected]; [email protected]; linuxppc-
> > [email protected]; Liberman Igal-B31950
> > Subject: Re: [PATCH 01/12] fsl/fman: Add the FMan FLIB headers
> >
> > On Wed, 2015-06-10 at 18:21 +0300, Madalin Bucur wrote:
> > > From: Igal Liberman <[email protected]>
> > >
> > > This patch presents the FMan Foundation Libraries (FLIB) headers.
> > > The FMan FLib provides the basic API used by the FMan drivers to
> > > configure and control the FMan hardware.
> > >
> > > Signed-off-by: Igal Liberman <[email protected]>
> > > ---
> > > .../ethernet/freescale/fman/flib/common/general.h | 41 ++
> > > .../net/ethernet/freescale/fman/flib/fsl_fman.h | 609
> > > +++++++++++++++++++++
> > > 2 files changed, 650 insertions(+)
> > > create mode 100644
> > > drivers/net/ethernet/freescale/fman/flib/common/general.h
> > > create mode 100644
> > > drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
> >
> > Why do we need separate patches just for headers?
> >
>
> We wanted to make the patches smaller, it's the main reason for this
> separation.
Patches should be divided by function, not arbitrarily in order to
decrease size. Splitting like this makes it harder to see the whole
picture, to search for identifiers, etc.
The right way to make these patches smaller is to remove unnecessary
features.
> > What does the flib directory mean, in the context of Linux? If
> > someone were
> > to add code to this driver, how do they know if the code should go
> > into the
> > flib directory or not?
> >
> > >
> > > +#define iowrite32be(val, addr) out_be32(&(*addr),
> > > val)
> > > +#define ioread32be(addr) in_be32(&(*addr))
> >
> > iowrite32be()/ioread32be() are already defined for all relevant
> > architectures.
> > Why are you redefining them into something PPC- specific?
> >
>
> Removed those.
Please don't stop at the specific things I'm pointing out.
> > > +/* do not change! if changed, must be disabled for rev1 ! */
> > > #define
> > > +DEFAULT_HALT_ON_EXTERNAL_ACTIVATION false
> > > +/* do not change! if changed, must be disabled for rev1 ! */
> > > #define
> > > +DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR false
> >
> > rev1 of what chip?
> >
>
> P4080. I'll update the comments.
No. p4080rev1 is not supported, and in any case this is not the right
way to select different errata for different chips.
-Scott