2015-08-05 13:29:15

by Liberman Igal

[permalink] [raw]
Subject: [v4, 0/9] Freescale DPAA FMan

From: Igal Liberman <[email protected]>

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 introduce the FMan drivers. Each driver configures
and initializes the corresponding FMan hardware module (described above).
The MAC driver offers support for three different types of
MACs (eTSEC, TGEC, MEMAC).

The driver structure and a hint on file naming:
----------------------------------
| FMan driver/MAC driver | fm_drv*, mac* files
----------------------------------
| FMan | Port | MAC | MURAM | SP | fm_* files
----------------------------------
| FLib | fman_*.c, fsl_fman_.*h files
----------------------------------

The first 3 patches present the FMan Foundation Libraries (FLIBs).
The FLIBs provide basic internal API for the FMan hardware
configuration and control.
Header files are located in fman/flib directory.
Source files are located in each module directory.

The upper layer of the FMan driver makes use of the basic API which is
provided by the Flibs.

The remaining patches present the required FMan hardware module drivers.

v3 --> v4:
- Remove device_initcall call in driver registration (redundant)
- Remove hot/cold labels
- Minor update in FMan Clock read from device-tree
- Update fixed-link support
- Addressed feedback from Stephen Hemminger
- Remove bogus blank line

v2 --> v3:
- Addressed feedback from Scott:
- Remove typedefs
- Remove unnecessary memory barriers
- Remove unnecessary casting
- Remove KConfig options
- Remove early_params
- Remove Hungarian notation
- Remove __packed__ attribute and padding from structures
- Remove unlikely attribute (where it's not needed)
- Use proper error codes and remove unnecessary prints
- Use proper values for sleep routines
- Replace complex Macros with functions
- Improve device tree processing code
- Use symbolic defines
- Add time-out in busy-wait loops
- Removed exit code (loadable module support will be added later)
- Fixed "fixed-link" issue raised by Joakim Tjernlund

v1 --> v2:
- Addressed feedback from Paul Bolle:
- General feedback of FMan Driver layer
- Remove Errata defines
- Aligned comments to Kernel Doc
- Remove Loadable Module support (not yet supported)
- Removed not needed KConfig dependencies
- Addressed feedback from Scott Wood
- Use Kernel ioread/iowrite services
- Squash FLIB source and header patches together


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 (9):
fsl/fman: Add the FMan FLIB
fsl/fman: Add the FMan port FLIB
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 | 8 +
drivers/net/ethernet/freescale/fman/Makefile | 12 +
.../net/ethernet/freescale/fman/flib/fsl_enet.h | 135 ++
.../net/ethernet/freescale/fman/flib/fsl_fman.h | 590 +++++++++
.../ethernet/freescale/fman/flib/fsl_fman_dtsec.h | 809 ++++++++++++
.../freescale/fman/flib/fsl_fman_dtsec_mii_acc.h | 89 ++
.../ethernet/freescale/fman/flib/fsl_fman_memac.h | 429 ++++++
.../freescale/fman/flib/fsl_fman_memac_mii_acc.h | 72 ++
.../ethernet/freescale/fman/flib/fsl_fman_port.h | 409 ++++++
.../net/ethernet/freescale/fman/flib/fsl_fman_sp.h | 53 +
.../ethernet/freescale/fman/flib/fsl_fman_tgec.h | 393 ++++++
drivers/net/ethernet/freescale/fman/fm.c | 1366 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/fm.h | 279 ++++
drivers/net/ethernet/freescale/fman/fm_common.h | 178 +++
drivers/net/ethernet/freescale/fman/fm_drv.c | 621 +++++++++
drivers/net/ethernet/freescale/fman/fm_drv.h | 111 ++
drivers/net/ethernet/freescale/fman/fm_muram.c | 115 ++
drivers/net/ethernet/freescale/fman/fm_port_drv.c | 372 ++++++
drivers/net/ethernet/freescale/fman/fm_sp_common.h | 105 ++
drivers/net/ethernet/freescale/fman/fman.c | 911 +++++++++++++
.../ethernet/freescale/fman/inc/crc_mac_addr_ext.h | 314 +++++
drivers/net/ethernet/freescale/fman/inc/enet_ext.h | 199 +++
drivers/net/ethernet/freescale/fman/inc/fm_ext.h | 446 +++++++
.../net/ethernet/freescale/fman/inc/fm_muram_ext.h | 102 ++
.../net/ethernet/freescale/fman/inc/fm_port_ext.h | 340 +++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 203 +++
drivers/net/ethernet/freescale/fman/inc/mac.h | 135 ++
drivers/net/ethernet/freescale/fman/mac/Makefile | 8 +
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c | 1012 +++++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h | 207 +++
drivers/net/ethernet/freescale/fman/mac/fm_mac.h | 259 ++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.c | 700 ++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.h | 122 ++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.c | 552 ++++++++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.h | 124 ++
.../net/ethernet/freescale/fman/mac/fman_dtsec.c | 503 +++++++
.../freescale/fman/mac/fman_dtsec_mii_acc.c | 153 +++
.../net/ethernet/freescale/fman/mac/fman_memac.c | 374 ++++++
.../freescale/fman/mac/fman_memac_mii_acc.c | 151 +++
.../net/ethernet/freescale/fman/mac/fman_tgec.c | 207 +++
drivers/net/ethernet/freescale/fman/mac/mac-api.c | 688 ++++++++++
drivers/net/ethernet/freescale/fman/mac/mac.c | 445 +++++++
drivers/net/ethernet/freescale/fman/port/Makefile | 3 +
drivers/net/ethernet/freescale/fman/port/fm_port.c | 1081 ++++++++++++++++
drivers/net/ethernet/freescale/fman/port/fm_port.h | 502 +++++++
.../net/ethernet/freescale/fman/port/fman_port.c | 510 ++++++++
drivers/net/ethernet/freescale/fman/sp/Makefile | 3 +
drivers/net/ethernet/freescale/fman/sp/fm_sp.c | 371 ++++++
50 files changed, 16774 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/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/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_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_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.9.5


2015-08-05 13:29:31

by Liberman Igal

[permalink] [raw]
Subject: [v4, 1/9] fsl/fman: Add the FMan FLIB

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 +
.../net/ethernet/freescale/fman/flib/fsl_fman.h | 590 +++++++++++++
drivers/net/ethernet/freescale/fman/fman.c | 911 ++++++++++++++++++++
6 files changed, 1516 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/fsl_fman.h
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 ff76d4e..f3f89cc 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -53,6 +53,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/flib/fsl_fman.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
new file mode 100644
index 0000000..7bd5ca6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman.h
@@ -0,0 +1,590 @@
+/*
+ * 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 <linux/delay.h>
+
+struct fman_revision_info {
+ u8 major_rev; /* Major revision */
+ u8 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 {
+ u32 fmfp_tnc; /* FPM TNUM Control 0x00 */
+ u32 fmfp_prc; /* FPM Port_ID FmCtl Association 0x04 */
+ u32 fmfp_brkc; /* FPM Breakpoint Control 0x08 */
+ u32 fmfp_mxd; /* FPM Flush Control 0x0c */
+ u32 fmfp_dist1; /* FPM Dispatch Thresholds1 0x10 */
+ u32 fmfp_dist2; /* FPM Dispatch Thresholds2 0x14 */
+ u32 fm_epi; /* FM Error Pending Interrupts 0x18 */
+ u32 fm_rie; /* FM Error Interrupt Enable 0x1c */
+ u32 fmfp_fcev[4]; /* FPM FMan-Controller Event 1-4 0x20-0x2f */
+ u32 res0030[4]; /* res 0x30 - 0x3f */
+ u32 fmfp_cee[4]; /* PM FMan-Controller Event 1-4 0x40-0x4f */
+ u32 res0050[4]; /* res 0x50-0x5f */
+ u32 fmfp_tsc1; /* FPM TimeStamp Control1 0x60 */
+ u32 fmfp_tsc2; /* FPM TimeStamp Control2 0x64 */
+ u32 fmfp_tsp; /* FPM Time Stamp 0x68 */
+ u32 fmfp_tsf; /* FPM Time Stamp Fraction 0x6c */
+ u32 fm_rcr; /* FM Rams Control 0x70 */
+ u32 fmfp_extc; /* FPM External Requests Control 0x74 */
+ u32 fmfp_ext1; /* FPM External Requests Config1 0x78 */
+ u32 fmfp_ext2; /* FPM External Requests Config2 0x7c */
+ u32 fmfp_drd[16]; /* FPM Data_Ram Data 0-15 0x80 - 0xbf */
+ u32 fmfp_dra; /* FPM Data Ram Access 0xc0 */
+ u32 fm_ip_rev_1; /* FM IP Block Revision 1 0xc4 */
+ u32 fm_ip_rev_2; /* FM IP Block Revision 2 0xc8 */
+ u32 fm_rstc; /* FM Reset Command 0xcc */
+ u32 fm_cld; /* FM Classifier Debug 0xd0 */
+ u32 fm_npi; /* FM Normal Pending Interrupts 0xd4 */
+ u32 fmfp_exte; /* FPM External Requests Enable 0xd8 */
+ u32 fmfp_ee; /* FPM Event&Mask 0xdc */
+ u32 fmfp_cev[4]; /* FPM CPU Event 1-4 0xe0-0xef */
+ u32 res00f0[4]; /* res 0xf0-0xff */
+ u32 fmfp_ps[50]; /* FPM Port Status 0x100-0x1c7 */
+ u32 res01c8[14]; /* res 0x1c8-0x1ff */
+ u32 fmfp_clfabc; /* FPM CLFABC 0x200 */
+ u32 fmfp_clfcc; /* FPM CLFCC 0x204 */
+ u32 fmfp_clfaval; /* FPM CLFAVAL 0x208 */
+ u32 fmfp_clfbval; /* FPM CLFBVAL 0x20c */
+ u32 fmfp_clfcval; /* FPM CLFCVAL 0x210 */
+ u32 fmfp_clfamsk; /* FPM CLFAMSK 0x214 */
+ u32 fmfp_clfbmsk; /* FPM CLFBMSK 0x218 */
+ u32 fmfp_clfcmsk; /* FPM CLFCMSK 0x21c */
+ u32 fmfp_clfamc; /* FPM CLFAMC 0x220 */
+ u32 fmfp_clfbmc; /* FPM CLFBMC 0x224 */
+ u32 fmfp_clfcmc; /* FPM CLFCMC 0x228 */
+ u32 fmfp_decceh; /* FPM DECCEH 0x22c */
+ u32 res0230[116]; /* res 0x230 - 0x3ff */
+ u32 fmfp_ts[128]; /* 0x400: FPM Task Status 0x400 - 0x5ff */
+ u32 res0600[0x400 - 384];
+};
+
+struct fman_bmi_regs {
+ u32 fmbm_init; /* BMI Initialization 0x00 */
+ u32 fmbm_cfg1; /* BMI Configuration 1 0x04 */
+ u32 fmbm_cfg2; /* BMI Configuration 2 0x08 */
+ u32 res000c[5]; /* 0x0c - 0x1f */
+ u32 fmbm_ievr; /* Interrupt Event Register 0x20 */
+ u32 fmbm_ier; /* Interrupt Enable Register 0x24 */
+ u32 fmbm_ifr; /* Interrupt Force Register 0x28 */
+ u32 res002c[5]; /* 0x2c - 0x3f */
+ u32 fmbm_arb[8]; /* BMI Arbitration 0x40 - 0x5f */
+ u32 res0060[12]; /* 0x60 - 0x8f */
+ u32 fmbm_dtc[3]; /* Debug Trap Counter 0x90 - 0x9b */
+ u32 res009c; /* 0x9c */
+ u32 fmbm_dcv[3][4]; /* Debug Compare val 0xa0-0xcf */
+ u32 fmbm_dcm[3][4]; /* Debug Compare Mask 0xd0-0xff */
+ u32 fmbm_gde; /* BMI Global Debug Enable 0x100 */
+ u32 fmbm_pp[63]; /* BMI Port Parameters 0x104 - 0x1ff */
+ u32 res0200; /* 0x200 */
+ u32 fmbm_pfs[63]; /* BMI Port FIFO Size 0x204 - 0x2ff */
+ u32 res0300; /* 0x300 */
+ u32 fmbm_spliodn[63]; /* Port Partition ID 0x304 - 0x3ff */
+};
+
+struct fman_qmi_regs {
+ u32 fmqm_gc; /* General Configuration Register 0x00 */
+ u32 res0004; /* 0x04 */
+ u32 fmqm_eie; /* Error Interrupt Event Register 0x08 */
+ u32 fmqm_eien; /* Error Interrupt Enable Register 0x0c */
+ u32 fmqm_eif; /* Error Interrupt Force Register 0x10 */
+ u32 fmqm_ie; /* Interrupt Event Register 0x14 */
+ u32 fmqm_ien; /* Interrupt Enable Register 0x18 */
+ u32 fmqm_if; /* Interrupt Force Register 0x1c */
+ u32 fmqm_gs; /* Global Status Register 0x20 */
+ u32 fmqm_ts; /* Task Status Register 0x24 */
+ u32 fmqm_etfc; /* Enqueue Total Frame Counter 0x28 */
+ u32 fmqm_dtfc; /* Dequeue Total Frame Counter 0x2c */
+ u32 fmqm_dc0; /* Dequeue Counter 0 0x30 */
+ u32 fmqm_dc1; /* Dequeue Counter 1 0x34 */
+ u32 fmqm_dc2; /* Dequeue Counter 2 0x38 */
+ u32 fmqm_dc3; /* Dequeue Counter 3 0x3c */
+ u32 fmqm_dfdc; /* Dequeue FQID from Default Counter 0x40 */
+ u32 fmqm_dfcc; /* Dequeue FQID from Context Counter 0x44 */
+ u32 fmqm_dffc; /* Dequeue FQID from FD Counter 0x48 */
+ u32 fmqm_dcc; /* Dequeue Confirm Counter 0x4c */
+ u32 res0050[7]; /* 0x50 - 0x6b */
+ u32 fmqm_tapc; /* Tnum Aging Period Control 0x6c */
+ u32 fmqm_dmcvc; /* Dequeue MAC Command Valid Counter 0x70 */
+ u32 fmqm_difdcc; /* Dequeue Invalid FD Command Counter 0x74 */
+ u32 fmqm_da1v; /* Dequeue A1 Valid Counter 0x78 */
+ u32 res007c; /* 0x7c */
+ u32 fmqm_dtc; /* 0x80 Debug Trap Counter 0x80 */
+ u32 fmqm_efddd; /* 0x84 Enqueue Frame desc Dynamic dbg 0x84 */
+ u32 res0088[2]; /* 0x88 - 0x8f */
+ struct {
+ u32 fmqm_dtcfg1; /* 0x90 dbg trap cfg 1 Register 0x00 */
+ u32 fmqm_dtval1; /* Debug Trap Value 1 Register 0x04 */
+ u32 fmqm_dtm1; /* Debug Trap Mask 1 Register 0x08 */
+ u32 fmqm_dtc1; /* Debug Trap Counter 1 Register 0x0c */
+ u32 fmqm_dtcfg2; /* dbg Trap cfg 2 Register 0x10 */
+ u32 fmqm_dtval2; /* Debug Trap Value 2 Register 0x14 */
+ u32 fmqm_dtm2; /* Debug Trap Mask 2 Register 0x18 */
+ u32 res001c; /* 0x1c */
+ } dbg_traps[3]; /* 0x90 - 0xef */
+ u8 res00f0[0x400 - 0xf0]; /* 0xf0 - 0x3ff */
+};
+
+struct fman_dma_regs {
+ u32 fmdmsr; /* FM DMA status register 0x00 */
+ u32 fmdmmr; /* FM DMA mode register 0x04 */
+ u32 fmdmtr; /* FM DMA bus threshold register 0x08 */
+ u32 fmdmhy; /* FM DMA bus hysteresis register 0x0c */
+ u32 fmdmsetr; /* FM DMA SOS emergency Threshold Register 0x10 */
+ u32 fmdmtah; /* FM DMA transfer bus address high reg 0x14 */
+ u32 fmdmtal; /* FM DMA transfer bus address low reg 0x18 */
+ u32 fmdmtcid; /* FM DMA transfer bus communication ID reg 0x1c */
+ u32 fmdmra; /* FM DMA bus internal ram address register 0x20 */
+ u32 fmdmrd; /* FM DMA bus internal ram data register 0x24 */
+ u32 fmdmwcr; /* FM DMA CAM watchdog counter value 0x28 */
+ u32 fmdmebcr; /* FM DMA CAM base in MURAM register 0x2c */
+ u32 fmdmccqdr; /* FM DMA CAM and CMD Queue Debug reg 0x30 */
+ u32 fmdmccqvr1; /* FM DMA CAM and CMD Queue Value reg #1 0x34 */
+ u32 fmdmccqvr2; /* FM DMA CAM and CMD Queue Value reg #2 0x38 */
+ u32 fmdmcqvr3; /* FM DMA CMD Queue Value register #3 0x3c */
+ u32 fmdmcqvr4; /* FM DMA CMD Queue Value register #4 0x40 */
+ u32 fmdmcqvr5; /* FM DMA CMD Queue Value register #5 0x44 */
+ u32 fmdmsefrc; /* FM DMA Semaphore Entry Full Reject Cntr 0x48 */
+ u32 fmdmsqfrc; /* FM DMA Semaphore Queue Full Reject Cntr 0x4c */
+ u32 fmdmssrc; /* FM DMA Semaphore SYNC Reject Counter 0x50 */
+ u32 fmdmdcr; /* FM DMA Debug Counter 0x54 */
+ u32 fmdmemsr; /* FM DMA Emergency Smoother Register 0x58 */
+ u32 res005c; /* 0x5c */
+ u32 fmdmplr[FMAN_LIODN_TBL / 2]; /* DMA LIODN regs 0x60-0xdf */
+ u32 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 {
+ u8 disp_limit_tsh;
+ u8 prs_disp_tsh;
+ u8 plcr_disp_tsh;
+ u8 kg_disp_tsh;
+ u8 bmi_disp_tsh;
+ u8 qmi_enq_disp_tsh;
+ u8 qmi_deq_disp_tsh;
+ u8 fm_ctl1_disp_tsh;
+ u8 fm_ctl2_disp_tsh;
+ enum fman_dma_cache_override dma_cache_override;
+ enum fman_dma_aid_mode dma_aid_mode;
+ bool dma_aid_override;
+ u32 dma_axi_dbg_num_of_beats;
+ u32 dma_cam_num_of_entries;
+ u32 dma_watchdog;
+ u8 dma_comm_qtsh_asrt_emer;
+ u32 dma_write_buf_tsh_asrt_emer;
+ u32 dma_read_buf_tsh_asrt_emer;
+ u8 dma_comm_qtsh_clr_emer;
+ u32 dma_write_buf_tsh_clr_emer;
+ u32 dma_read_buf_tsh_clr_emer;
+ u32 dma_sos_emergency;
+ enum fman_dma_dbg_cnt_mode dma_dbg_cnt_mode;
+ bool dma_stop_on_bus_error;
+ bool dma_en_emergency;
+ u32 dma_emergency_bus_select;
+ enum fman_dma_emergency_level dma_emergency_level;
+ bool dma_en_emergency_smoother;
+ u32 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;
+ u16 tnum_aging_period;
+ u32 exceptions;
+ u16 clk_freq;
+ bool pedantic_dma;
+ u32 cam_base_addr;
+ u32 fifo_base_addr;
+ u32 total_fifo_size;
+ u32 total_num_of_tasks;
+ bool qmi_deq_option_support;
+ u32 qmi_def_tnums_thresh;
+ u8 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
+
+/* DMA mask and shifts */
+#define DMA_MODE_CACHE_OR_SHIFT 30
+#define DMA_MODE_AXI_DBG_SHIFT 24
+#define DMA_MODE_CEN_SHIFT 13
+#define DMA_MODE_CEN_MASK 0x00000007
+#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_THRESH_READ_INT_BUF_MASK 0x0000003f
+#define DMA_THRESH_WRITE_INT_BUF_MASK 0x0000003f
+
+#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
+#define BMI_CFG2_TASKS_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_CFG_ENQ_SHIFT 8
+
+#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
+
+u32 fman_get_bmi_err_event(struct fman_bmi_regs __iomem *bmi_rg);
+u32 fman_get_qmi_err_event(struct fman_qmi_regs __iomem *qmi_rg);
+u32 fman_get_dma_com_id(struct fman_dma_regs __iomem *dma_rg);
+u64 fman_get_dma_addr(struct fman_dma_regs __iomem *dma_rg);
+u32 fman_get_dma_err_event(struct fman_dma_regs __iomem *dma_rg);
+u32 fman_get_fpm_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+u32 fman_get_muram_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+u32 fman_get_iram_err_event(struct fman_fpm_regs __iomem *fpm_rg);
+u32 fman_get_qmi_event(struct fman_qmi_regs __iomem *qmi_rg);
+u32 fman_get_fpm_error_interrupts(struct fman_fpm_regs __iomem *fpm_rg);
+u32 fman_get_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg);
+u32 fman_get_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg);
+u8 fman_get_num_of_dmas(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id);
+u8 fman_get_num_extra_dmas(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id);
+u32 fman_get_normal_pending(struct fman_fpm_regs __iomem *fpm_rg);
+u32 fman_get_controller_event(struct fman_fpm_regs __iomem *fpm_rg, u8 reg_id);
+void fman_get_revision(struct fman_fpm_regs __iomem *fpm_rg, u8 *major,
+ u8 *minor);
+
+void fman_set_order_restoration_per_port(struct fman_fpm_regs __iomem *fpm_rg,
+ u8 port_id, bool is_rx_port);
+void fman_set_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg, u32 val);
+void fman_set_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg, u32 val);
+void fman_set_liodn_per_port(struct fman_rg *fman_rg, u8 port_id,
+ u16 liodn_base, u16 liodn_offset);
+void fman_set_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id,
+ u32 size_of_fifo, u32 extra_size_of_fifo);
+void fman_set_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg,
+ u8 port_id,
+ u8 num_of_tasks, u8 num_of_extra_tasks);
+void fman_set_num_of_open_dmas(struct fman_bmi_regs __iomem *bmi_rg,
+ u8 port_id, u8 num_of_open_dmas,
+ u8 num_of_extra_open_dmas, u8 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);
+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,
+ u8 count1ubit, u16 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, u8 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
+#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION false
+#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 */
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
new file mode 100644
index 0000000..3af8d29
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -0,0 +1,911 @@
+/*
+ * 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/io.h>
+
+#include "fsl_fman.h"
+
+u32 fman_get_bmi_err_event(struct fman_bmi_regs __iomem *bmi_rg)
+{
+ u32 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;
+}
+
+u32 fman_get_qmi_err_event(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ u32 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;
+}
+
+u32 fman_get_dma_com_id(struct fman_dma_regs __iomem *dma_rg)
+{
+ return ioread32be(&dma_rg->fmdmtcid);
+}
+
+u64 fman_get_dma_addr(struct fman_dma_regs __iomem *dma_rg)
+{
+ u64 addr;
+
+ addr = (u64)ioread32be(&dma_rg->fmdmtal);
+ addr |= ((u64)(ioread32be(&dma_rg->fmdmtah)) << 32);
+
+ return addr;
+}
+
+u32 fman_get_dma_err_event(struct fman_dma_regs __iomem *dma_rg)
+{
+ u32 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;
+}
+
+u32 fman_get_fpm_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ u32 event;
+
+ event = ioread32be(&fpm_rg->fmfp_ee);
+ /* clear the all occurred events */
+ iowrite32be(event, &fpm_rg->fmfp_ee);
+ return event;
+}
+
+u32 fman_get_muram_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ u32 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;
+}
+
+u32 fman_get_iram_err_event(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ u32 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;
+}
+
+u32 fman_get_qmi_event(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ u32 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,
+ u8 count1ubit, u16 fm_clk_freq)
+{
+ u32 tmp;
+ u64 frac;
+ u32 intgr;
+ u32 ts_freq = (u32)(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) | (u16)frac;
+ iowrite32be(tmp, &fpm_rg->fmfp_tsc2);
+
+ /* enable timestamp with original clock */
+ iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1);
+}
+
+u32 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)
+ udelay(10);
+
+ if (!timeout)
+ return -EIO;
+ return 0;
+}
+
+void fman_set_order_restoration_per_port(struct fman_fpm_regs __iomem *fpm_rg,
+ u8 port_id, bool is_rx_port)
+{
+ u32 tmp = 0;
+
+ tmp = (u32)(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);
+}
+
+u32 fman_get_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ return (ioread32be(&qmi_rg->fmqm_gc) & QMI_CFG_DEQ_MASK);
+}
+
+u32 fman_get_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg)
+{
+ return ((ioread32be(&qmi_rg->fmqm_gc) & QMI_CFG_ENQ_MASK) >>
+ QMI_CFG_ENQ_SHIFT);
+}
+
+void fman_set_qmi_enq_th(struct fman_qmi_regs __iomem *qmi_rg, u32 val)
+{
+ u32 tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_ENQ_MASK;
+ tmp_reg |= (val << QMI_CFG_ENQ_SHIFT);
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_set_qmi_deq_th(struct fman_qmi_regs __iomem *qmi_rg, u32 val)
+{
+ u32 tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_DEQ_MASK;
+ tmp_reg |= val;
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_set_liodn_per_port(struct fman_rg *fman_rg, u8 port_id,
+ u16 liodn_base, u16 liodn_ofst)
+{
+ u32 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 |= (u32)liodn_base;
+ } else {
+ tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT);
+ tmp |= (u32)liodn_base << DMA_LIODN_SHIFT;
+ }
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]);
+ iowrite32be((u32)liodn_ofst,
+ &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]);
+}
+
+int fman_reset_mac(struct fman_fpm_regs __iomem *fpm_rg, u8 mac_id)
+{
+ u32 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)
+ udelay(10);
+
+ if (!timeout)
+ return -EIO;
+ return 0;
+}
+
+void fman_set_size_of_fifo(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id,
+ u32 sz_fifo, u32 extra_sz_fifo)
+{
+ u32 tmp;
+
+ /* calculate reg */
+ tmp = (u32)((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]);
+}
+
+void fman_set_num_of_tasks(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id,
+ u8 num_tasks, u8 num_extra_tasks)
+{
+ u32 tmp;
+
+ /* calculate reg */
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
+ ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK);
+ tmp |= ((u32)((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) |
+ (u32)(num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
+}
+
+u8 fman_get_num_of_dmas(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (u8)(((tmp & BMI_NUM_OF_DMAS_MASK) >>
+ BMI_NUM_OF_DMAS_SHIFT) + 1);
+}
+
+u8 fman_get_num_extra_dmas(struct fman_bmi_regs __iomem *bmi_rg, u8 port_id)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (u8)((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,
+ u8 port_id, u8 num_open_dmas,
+ u8 num_extra_open_dmas, u8 total_num_dmas)
+{
+ u32 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 |= (u32)(((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 |= (u32)(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)
+{
+ u32 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 |= (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_MASK) << 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 = ((u32)cfg->dma_comm_qtsh_asrt_emer <<
+ DMA_THRESH_COMMQ_SHIFT);
+ tmp_reg |= (cfg->dma_read_buf_tsh_asrt_emer &
+ DMA_THRESH_READ_INT_BUF_MASK) << DMA_THRESH_READ_INT_BUF_SHIFT;
+ tmp_reg |= cfg->dma_write_buf_tsh_asrt_emer &
+ DMA_THRESH_WRITE_INT_BUF_MASK;
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmtr);
+
+ /* configure hysteresis register */
+ tmp_reg = ((u32)cfg->dma_comm_qtsh_clr_emer <<
+ DMA_THRESH_COMMQ_SHIFT);
+ tmp_reg |= (cfg->dma_read_buf_tsh_clr_emer &
+ DMA_THRESH_READ_INT_BUF_MASK) << DMA_THRESH_READ_INT_BUF_SHIFT;
+ tmp_reg |= cfg->dma_write_buf_tsh_clr_emer &
+ DMA_THRESH_WRITE_INT_BUF_MASK;
+
+ 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)
+{
+ u32 tmp_reg;
+ int i;
+
+ /* Init FPM Registers */
+
+ tmp_reg = (u32)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT);
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd);
+
+ tmp_reg = (((u32)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) |
+ ((u32)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) |
+ ((u32)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) |
+ ((u32)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT));
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1);
+
+ tmp_reg =
+ (((u32)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) |
+ ((u32)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) |
+ ((u32)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) |
+ ((u32)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)
+{
+ u32 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 = ((cfg->total_num_of_tasks - 1) & BMI_CFG2_TASKS_MASK) <<
+ 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)
+{
+ u32 tmp_reg;
+ u16 period_in_fm_clocks;
+ u8 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, clk_freq in Mhz */
+ period_in_fm_clocks = (u16)
+ (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 = (u32)((period_in_fm_clocks / 64) + 1);
+ } else {
+ tmp_reg = (u32)(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)
+{
+ u32 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 |= (u32)(((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;
+}
+
+/* API Run-time Control uint functions */
+
+u32 fman_get_normal_pending(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_npi);
+}
+
+void fman_enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
+{
+ u32 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)
+{
+ u32 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)
+{
+ u32 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,
+ u8 *major, u8 *minor)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_ip_rev_1);
+ *major = (u8)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT);
+ *minor = (u8)((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)
+{
+ u32 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.9.5

2015-08-05 13:54:16

by Liberman Igal

[permalink] [raw]
Subject: [v4, 2/9] fsl/fman: Add the FMan port FLIB

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/Makefile | 2 +
.../ethernet/freescale/fman/flib/fsl_fman_port.h | 409 ++++++++++++++++
.../net/ethernet/freescale/fman/flib/fsl_fman_sp.h | 53 ++
drivers/net/ethernet/freescale/fman/port/Makefile | 3 +
.../net/ethernet/freescale/fman/port/fman_port.c | 510 ++++++++++++++++++++
5 files changed, 977 insertions(+)
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/port/Makefile
create mode 100644 drivers/net/ethernet/freescale/fman/port/fman_port.c

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/flib/fsl_fman_port.h b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.h
new file mode 100644
index 0000000..6de0719
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_port.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_PORT_H
+#define __FSL_FMAN_PORT_H
+
+#include <linux/io.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_FRAME_END_CS_IGNORE_SHIFT 24
+#define BMI_FRAME_END_CS_IGNORE_MASK 0x0000001f
+
+#define BMI_RX_FRAME_END_CUT_SHIFT 16
+#define BMI_RX_FRAME_END_CUT_MASK 0x0000001f
+
+#define BMI_IC_TO_EXT_SHIFT FMAN_SP_IC_TO_EXT_SHIFT
+#define BMI_IC_TO_EXT_MASK 0x0000001f
+#define BMI_IC_FROM_INT_SHIFT FMAN_SP_IC_FROM_INT_SHIFT
+#define BMI_IC_FROM_INT_MASK 0x0000000f
+#define BMI_IC_SIZE_MASK 0x0000001f
+
+#define BMI_INT_BUF_MARG_SHIFT 28
+#define BMI_INT_BUF_MARG_MASK 0x0000000f
+#define BMI_EXT_BUF_MARG_START_SHIFT FMAN_SP_EXT_BUF_MARG_START_SHIFT
+#define BMI_EXT_BUF_MARG_START_MASK 0x000001ff
+#define BMI_EXT_BUF_MARG_END_MASK 0x000001ff
+
+#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_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_FIFO_PIPELINE_DEPTH_MASK 0x0000000f
+#define BMI_NEXT_ENG_FD_BITS_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
+
+#define BMI_PRIORITY_ELEVATION_LEVEL \
+ ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS)
+#define BMI_FIFO_THRESHOLD \
+ ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS)
+
+#define BMI_DEQUEUE_PIPELINE_DEPTH(_type) \
+ (_type == E_FMAN_PORT_TYPE_TX_10G ? 4 : 1)
+
+/* 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
+
+#define QMI_HIGH_PRIORITY(_type) \
+ (_type == E_FMAN_PORT_TYPE_TX_10G ? true : false)
+#define QMI_BYTE_COUNT_LEVEL_CONTROL(_type) \
+ (_type == E_FMAN_PORT_TYPE_TX_10G ? 0x1400 : 0x400)
+
+/* 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
+
+/* NIA Description */
+#define NIA_ORDER_RESTOR 0x00800000
+#define NIA_ENG_FM_CTL 0x00000000
+#define NIA_ENG_BMI 0x00500000
+#define NIA_ENG_QMI_ENQ 0x00540000
+#define NIA_ENG_QMI_DEQ 0x00580000
+
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+#define NIA_BMI_AC_ENQ_FRAME 0x00000002
+#define NIA_BMI_AC_TX_RELEASE 0x000002C0
+#define NIA_BMI_AC_RELEASE 0x000000C0
+#define NIA_BMI_AC_TX 0x00000274
+#define NIA_BMI_AC_FETCH 0x00000208
+#define NIA_BMI_AC_FETCH_ALL_FRAME 0x0000020c
+
+#define DEFAULT_FRAME_QUEUE_ID 0x00FFFFFF
+#define ERROR_FRAME_QUEUE_ID 0x00FFFFFF
+#define DEFAULT_CONF_FRAME_QUEUE_ID 0x00FFFFFF
+
+/* FM Port Register Map */
+
+/* BMI Rx port register map */
+struct fman_port_rx_bmi_regs {
+ u32 fmbm_rcfg; /* Rx Configuration */
+ u32 fmbm_rst; /* Rx Status */
+ u32 fmbm_rda; /* Rx DMA attributes */
+ u32 fmbm_rfp; /* Rx FIFO Parameters */
+ u32 fmbm_rfed; /* Rx Frame End Data */
+ u32 fmbm_ricp; /* Rx Internal Context Parameters */
+ u32 fmbm_rim; /* Rx Internal Buffer Margins */
+ u32 fmbm_rebm; /* Rx External Buffer Margins */
+ u32 fmbm_rfne; /* Rx Frame Next Engine */
+ u32 fmbm_rfca; /* Rx Frame Command Attributes. */
+ u32 fmbm_rfpne; /* Rx Frame Parser Next Engine */
+ u32 fmbm_rpso; /* Rx Parse Start Offset */
+ u32 fmbm_rpp; /* Rx Policer Profile */
+ u32 fmbm_rccb; /* Rx Coarse Classification Base */
+ u32 fmbm_reth; /* Rx Excessive Threshold */
+ u32 reserved003c[1]; /* (0x03C 0x03F) */
+ u32 fmbm_rprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
+ /* Rx Parse Results Array Init */
+ u32 fmbm_rfqid; /* Rx Frame Queue ID */
+ u32 fmbm_refqid; /* Rx Error Frame Queue ID */
+ u32 fmbm_rfsdm; /* Rx Frame Status Discard Mask */
+ u32 fmbm_rfsem; /* Rx Frame Status Error Mask */
+ u32 fmbm_rfene; /* Rx Frame Enqueue Next Engine */
+ u32 reserved0074[0x2]; /* (0x074-0x07C) */
+ u32 fmbm_rcmne; /* Rx Frame Continuous Mode Next Engine */
+ u32 reserved0080[0x20];/* (0x080 0x0FF) */
+ u32 fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM];
+ /* Buffer Manager pool Information- */
+ u32 fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM]; /* Allocate Counter- */
+ u32 reserved0130[8]; /* 0x130/0x140 - 0x15F reserved - */
+ u32 fmbm_rcgm[FMAN_PORT_CG_MAP_NUM]; /* Congestion Group Map */
+ u32 fmbm_mpd; /* BM Pool Depletion */
+ u32 reserved0184[0x1F]; /* (0x184 0x1FF) */
+ u32 fmbm_rstc; /* Rx Statistics Counters */
+ u32 fmbm_rfrc; /* Rx Frame Counter */
+ u32 fmbm_rfbc; /* Rx Bad Frames Counter */
+ u32 fmbm_rlfc; /* Rx Large Frames Counter */
+ u32 fmbm_rffc; /* Rx Filter Frames Counter */
+ u32 fmbm_rfdc; /* Rx Frame Discard Counter */
+ u32 fmbm_rfldec; /* Rx Frames List DMA Error Counter */
+ u32 fmbm_rodc; /* Rx Out of Buffers Discard nntr */
+ u32 fmbm_rbdc; /* Rx Buffers Deallocate Counter */
+ u32 reserved0224[0x17]; /* (0x224 0x27F) */
+ u32 fmbm_rpc; /* Rx Performance Counters */
+ u32 fmbm_rpcp; /* Rx Performance Count Parameters */
+ u32 fmbm_rccn; /* Rx Cycle Counter */
+ u32 fmbm_rtuc; /* Rx Tasks Utilization Counter */
+ u32 fmbm_rrquc; /* Rx Receive Queue Utilization cntr */
+ u32 fmbm_rduc; /* Rx DMA Utilization Counter */
+ u32 fmbm_rfuc; /* Rx FIFO Utilization Counter */
+ u32 fmbm_rpac; /* Rx Pause Activation Counter */
+ u32 reserved02a0[0x18]; /* (0x2A0 0x2FF) */
+ u32 fmbm_rdbg; /* Rx Debug- */
+};
+
+/* BMI Tx port register map */
+struct fman_port_tx_bmi_regs {
+ u32 fmbm_tcfg; /* Tx Configuration */
+ u32 fmbm_tst; /* Tx Status */
+ u32 fmbm_tda; /* Tx DMA attributes */
+ u32 fmbm_tfp; /* Tx FIFO Parameters */
+ u32 fmbm_tfed; /* Tx Frame End Data */
+ u32 fmbm_ticp; /* Tx Internal Context Parameters */
+ u32 fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */
+ u32 fmbm_tfca; /* Tx Frame Command attribute. */
+ u32 fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */
+ u32 fmbm_tefqid; /* Tx Frame Error Queue ID */
+ u32 fmbm_tfene; /* Tx Frame Enqueue Next Engine */
+ u32 fmbm_trlmts; /* Tx Rate Limiter Scale */
+ u32 fmbm_trlmt; /* Tx Rate Limiter */
+ u32 reserved0034[0x0e]; /* (0x034-0x6c) */
+ u32 fmbm_tccb; /* Tx Coarse Classification base */
+ u32 fmbm_tfne; /* Tx Frame Next Engine */
+ u32 fmbm_tpfcm[0x02];
+ /* Tx Priority based Flow Control (PFC) Mapping */
+ u32 fmbm_tcmne; /* Tx Frame Continuous Mode Next Engine */
+ u32 reserved0080[0x60]; /* (0x080-0x200) */
+ u32 fmbm_tstc; /* Tx Statistics Counters */
+ u32 fmbm_tfrc; /* Tx Frame Counter */
+ u32 fmbm_tfdc; /* Tx Frames Discard Counter */
+ u32 fmbm_tfledc; /* Tx Frame len error discard cntr */
+ u32 fmbm_tfufdc; /* Tx Frame unsprt frmt discard cntr */
+ u32 fmbm_tbdc; /* Tx Buffers Deallocate Counter */
+ u32 reserved0218[0x1A]; /* (0x218-0x280) */
+ u32 fmbm_tpc; /* Tx Performance Counters */
+ u32 fmbm_tpcp; /* Tx Performance Count Parameters */
+ u32 fmbm_tccn; /* Tx Cycle Counter */
+ u32 fmbm_ttuc; /* Tx Tasks Utilization Counter */
+ u32 fmbm_ttcquc; /* Tx Transmit conf Q util Counter */
+ u32 fmbm_tduc; /* Tx DMA Utilization Counter */
+ u32 fmbm_tfuc; /* Tx 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;
+};
+
+/* QMI port register map */
+struct fman_port_qmi_regs {
+ u32 fmqm_pnc; /* PortID n Configuration Register */
+ u32 fmqm_pns; /* PortID n Status Register */
+ u32 fmqm_pnts; /* PortID n Task Status Register */
+ u32 reserved00c[4]; /* 0xn00C - 0xn01B */
+ u32 fmqm_pnen; /* PortID n Enqueue NIA Register */
+ u32 fmqm_pnetfc; /* PortID n Enq Total Frame Counter */
+ u32 reserved024[2]; /* 0xn024 - 0x02B */
+ u32 fmqm_pndn; /* PortID n Dequeue NIA Register */
+ u32 fmqm_pndc; /* PortID n Dequeue Config Register */
+ u32 fmqm_pndtfc; /* PortID n Dequeue tot Frame cntr */
+ u32 fmqm_pndfdc; /* PortID n Dequeue FQID Dflt Cntr */
+ u32 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;
+ u32 ic_ext_offset;
+ u32 ic_int_offset;
+ u32 ic_size;
+ enum fman_port_color color;
+ bool sync_req;
+ bool discard_override;
+ u32 checksum_bytes_ignore;
+ u32 rx_cut_end_bytes;
+ u32 rx_pri_elevation;
+ u32 rx_fifo_thr;
+ u8 rx_fd_bits;
+ u32 int_buf_start_margin;
+ u32 ext_buf_start_margin;
+ u32 ext_buf_end_margin;
+ u32 tx_fifo_min_level;
+ u32 tx_fifo_low_comf_level;
+ u32 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;
+ u16 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_RX = 0, /* 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 {
+ u32 discard_mask;
+ u32 err_mask;
+ u32 dflt_fqid;
+ u32 err_fqid;
+ u32 deq_sp;
+ bool dont_release_buf;
+};
+
+/* Port context - used by most API functions */
+struct fman_port {
+ enum fman_port_type type;
+ u8 fm_rev_maj;
+ u8 fm_rev_min;
+ union fman_port_bmi_regs __iomem *bmi_regs;
+ struct fman_port_qmi_regs __iomem *qmi_regs;
+ u8 ext_pools_num;
+};
+
+/* External buffer pools configuration */
+struct fman_port_bpools {
+ u8 count; /* Num of pools to set up */
+ bool counters_enable; /* Enable allocate counters */
+ u8 grp_bp_depleted_num;
+ /* Number of depleted pools - if reached the BMI indicates
+ * the MAC to send a pause frame
+ */
+ struct {
+ u8 bpid; /* BM pool ID */
+ u16 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..651d98e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_sp.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "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 */
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..9c9e6f9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fman_port.c
@@ -0,0 +1,510 @@
+/*
+ * 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_port.h"
+
+static u32 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;
+ u32 tmp;
+
+ /* Rx Configuration register */
+ tmp = 0;
+ if (cfg->discard_override)
+ tmp |= BMI_PORT_CFG_FDOVR;
+ iowrite32be(tmp, &regs->fmbm_rcfg);
+
+ /* DMA attributes */
+ tmp = (u32)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, &regs->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, &regs->fmbm_rfp);
+
+ if (cfg->excessive_threshold_register)
+ /* always allow access to the extra resources */
+ iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, &regs->fmbm_reth);
+
+ /* Frame end data */
+ tmp = (cfg->checksum_bytes_ignore & BMI_FRAME_END_CS_IGNORE_MASK) <<
+ BMI_FRAME_END_CS_IGNORE_SHIFT;
+ tmp |= (cfg->rx_cut_end_bytes & BMI_RX_FRAME_END_CUT_MASK) <<
+ BMI_RX_FRAME_END_CUT_SHIFT;
+ if (cfg->errata_A006320)
+ tmp &= 0xffe0ffff;
+ iowrite32be(tmp, &regs->fmbm_rfed);
+
+ /* Internal context parameters */
+ tmp = ((cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) &
+ BMI_IC_TO_EXT_MASK) << BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) &
+ BMI_IC_FROM_INT_MASK) << BMI_IC_FROM_INT_SHIFT;
+ tmp |= (cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS) & BMI_IC_SIZE_MASK;
+ iowrite32be(tmp, &regs->fmbm_ricp);
+
+ /* Internal buffer offset */
+ tmp = ((cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) &
+ BMI_INT_BUF_MARG_MASK) << BMI_INT_BUF_MARG_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_rim);
+
+ /* External buffer margins */
+ tmp = (cfg->ext_buf_start_margin & BMI_EXT_BUF_MARG_START_MASK) <<
+ BMI_EXT_BUF_MARG_START_SHIFT;
+ tmp |= cfg->ext_buf_end_margin & BMI_EXT_BUF_MARG_END_MASK;
+ if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather)
+ tmp |= BMI_SG_DISABLE;
+ iowrite32be(tmp, &regs->fmbm_rebm);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_RX_MR_DEF;
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (u32)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ if (cfg->sync_req)
+ tmp |= BMI_CMD_ATTR_SYNC;
+
+ iowrite32be(tmp, &regs->fmbm_rfca);
+
+ /* NIA */
+ tmp = (u32)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
+ tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg);
+ iowrite32be(tmp, &regs->fmbm_rfne);
+
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->fmbm_rfene);
+
+ /* Default/error queues */
+ iowrite32be((params->dflt_fqid & DEFAULT_FRAME_QUEUE_ID),
+ &regs->fmbm_rfqid);
+ iowrite32be((params->err_fqid & ERROR_FRAME_QUEUE_ID),
+ &regs->fmbm_refqid);
+
+ /* Discard/error masks */
+ iowrite32be(params->discard_mask, &regs->fmbm_rfsdm);
+ iowrite32be(params->err_mask, &regs->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;
+ u32 tmp;
+
+ /* Tx Configuration register */
+ tmp = 0;
+ iowrite32be(tmp, &regs->fmbm_tcfg);
+
+ /* DMA attributes */
+ tmp = (u32)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, &regs->fmbm_tda);
+
+ /* Tx FIFO parameters */
+ tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) <<
+ BMI_TX_FIFO_MIN_FILL_SHIFT;
+ tmp |= ((cfg->tx_fifo_deq_pipeline_depth - 1) &
+ BMI_FIFO_PIPELINE_DEPTH_MASK) << BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ tmp |= (cfg->tx_fifo_low_comf_level / FMAN_PORT_BMI_FIFO_UNITS) - 1;
+ iowrite32be(tmp, &regs->fmbm_tfp);
+
+ /* Frame end data */
+ tmp = (cfg->checksum_bytes_ignore & BMI_FRAME_END_CS_IGNORE_MASK) <<
+ BMI_FRAME_END_CS_IGNORE_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_tfed);
+
+ /* Internal context parameters */
+ tmp = ((cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) &
+ BMI_IC_TO_EXT_MASK) << BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) &
+ BMI_IC_FROM_INT_MASK) << BMI_IC_FROM_INT_SHIFT;
+ tmp |= (cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS) & BMI_IC_SIZE_MASK;
+ iowrite32be(tmp, &regs->fmbm_ticp);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_TX_MR_DEF;
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (u32)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_tfca);
+
+ /* Dequeue NIA + enqueue NIA */
+ iowrite32be(NIA_ENG_QMI_DEQ, &regs->fmbm_tfdne);
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->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, &regs->fmbm_tfne);
+ if (!params->dflt_fqid && params->dont_release_buf) {
+ iowrite32be(DEFAULT_CONF_FRAME_QUEUE_ID, &regs->fmbm_tcfqid);
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE,
+ &regs->fmbm_tfene);
+ if (cfg->fmbm_tfne_has_features)
+ iowrite32be(ioread32be(&regs->fmbm_tfne) & ~BMI_EBD_EN,
+ &regs->fmbm_tfne);
+ }
+
+ /* Confirmation/error queues */
+ if (params->dflt_fqid || !params->dont_release_buf)
+ iowrite32be(params->dflt_fqid & DEFAULT_CONF_FRAME_QUEUE_ID,
+ &regs->fmbm_tcfqid);
+ iowrite32be((params->err_fqid & ERROR_FRAME_QUEUE_ID),
+ &regs->fmbm_tefqid);
+
+ 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;
+ u32 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, &regs->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,
+ &regs->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, &regs->fmqm_pndn);
+ } else {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, &regs->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, &regs->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 |= (params->deq_sp & QMI_DEQ_CFG_SP_MASK) << QMI_DEQ_CFG_SP_SHIFT;
+ tmp |= cfg->deq_byte_cnt;
+ iowrite32be(tmp, &regs->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 = BMI_PRIORITY_ELEVATION_LEVEL;
+ cfg->rx_fifo_thr = BMI_FIFO_THRESHOLD;
+ 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;
+
+ cfg->tx_fifo_deq_pipeline_depth = BMI_DEQUEUE_PIPELINE_DEPTH(type);
+ cfg->deq_high_pri = QMI_HIGH_PRIORITY(type);
+ cfg->deq_byte_cnt = QMI_BYTE_COUNT_LEVEL_CONTROL(type);
+}
+
+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;
+ 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)
+{
+ u32 __iomem *bmi_cfg_reg;
+ u32 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;
+ 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)
+{
+ u32 __iomem *bmi_cfg_reg, *bmi_status_reg;
+ u32 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;
+ 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 {
+ udelay(10);
+ 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 {
+ udelay(10);
+ 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)
+{
+ u32 __iomem *bp_reg, *bp_depl_reg;
+ u32 tmp;
+ u8 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;
+ 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 |= ((u32)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 |= (u32)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 |= ((u32)bp->grp_bp_depleted_num - 1) <<
+ BMI_POOL_DEP_NUM_OF_POOLS_SHIFT;
+
+ iowrite32be(tmp, bp_depl_reg);
+ return 0;
+}
--
1.7.9.5

2015-08-05 13:31:02

by Liberman Igal

[permalink] [raw]
Subject: [v4, 3/9] fsl/fman: Add the FMan MAC FLIB

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 +
.../net/ethernet/freescale/fman/flib/fsl_enet.h | 135 ++++
.../ethernet/freescale/fman/flib/fsl_fman_dtsec.h | 809 ++++++++++++++++++++
.../freescale/fman/flib/fsl_fman_dtsec_mii_acc.h | 89 +++
.../ethernet/freescale/fman/flib/fsl_fman_memac.h | 428 +++++++++++
.../freescale/fman/flib/fsl_fman_memac_mii_acc.h | 72 ++
.../ethernet/freescale/fman/flib/fsl_fman_tgec.h | 393 ++++++++++
drivers/net/ethernet/freescale/fman/mac/Makefile | 5 +
.../net/ethernet/freescale/fman/mac/fman_dtsec.c | 503 ++++++++++++
.../freescale/fman/mac/fman_dtsec_mii_acc.c | 153 ++++
.../net/ethernet/freescale/fman/mac/fman_memac.c | 374 +++++++++
.../freescale/fman/mac/fman_memac_mii_acc.c | 151 ++++
.../net/ethernet/freescale/fman/mac/fman_tgec.c | 207 +++++
13 files changed, 3320 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
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/flib/fsl_enet.h b/drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
new file mode 100644
index 0000000..4b79e83
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_enet.h
@@ -0,0 +1,135 @@
+/*
+ * 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 */
+};
+
+/* 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 */
+};
+
+#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..2608a06
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec.h
@@ -0,0 +1,809 @@
+/*
+ * 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 <linux/io.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
+ * Tx graceful stop is not supported due to the following errata:
+ * P4080 - DTSEC_A004
+ * All other devices - DTSEC_A0014
+ * To temporary stop dTSEC activity use fman_dtsec_stop_rx().
+ * Note that this function requests 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_GRSC bis.
+ * 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 \
+ ((u32)(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
+
+#define RCTRL_PAL_MASK 0x001f0000
+#define RCTRL_PAL_SHIFT 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 MACCFG2_PREAMBLE_LENGTH_MASK 0x0000f000
+#define MACCFG2_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_MASK 0x00f00000
+#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 */
+
+#define PTV_PTE_MASK 0xffff0000
+#define PTV_PT_MASK 0x0000ffff
+#define PTV_PTE_SHIFT 16
+
+/* 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 */
+ u32 tsec_id; /* 0x000 ETSEC_ID register */
+ u32 tsec_id2; /* 0x004 ETSEC_ID2 register */
+ u32 ievent; /* 0x008 Interrupt event register */
+ u32 imask; /* 0x00C Interrupt mask register */
+ u32 reserved0010[1];
+ u32 ecntrl; /* 0x014 E control register */
+ u32 ptv; /* 0x018 Pause time value register */
+ u32 tbipa; /* 0x01C TBI PHY address register */
+ u32 tmr_ctrl; /* 0x020 Time-stamp Control register */
+ u32 tmr_pevent; /* 0x024 Time-stamp event register */
+ u32 tmr_pemask; /* 0x028 Timer event mask register */
+ u32 reserved002c[5];
+ u32 tctrl; /* 0x040 Transmit control register */
+ u32 reserved0044[3];
+ u32 rctrl; /* 0x050 Receive control register */
+ u32 reserved0054[11];
+ u32 igaddr[8]; /* 0x080-0x09C Individual/group address */
+ u32 gaddr[8]; /* 0x0A0-0x0BC Group address registers 0-7 */
+ u32 reserved00c0[16];
+ u32 maccfg1; /* 0x100 MAC configuration #1 */
+ u32 maccfg2; /* 0x104 MAC configuration #2 */
+ u32 ipgifg; /* 0x108 IPG/IFG */
+ u32 hafdup; /* 0x10C Half-duplex */
+ u32 maxfrm; /* 0x110 Maximum frame */
+ u32 reserved0114[10];
+ u32 ifstat; /* 0x13C Interface status */
+ u32 macstnaddr1; /* 0x140 Station Address,part 1 */
+ u32 macstnaddr2; /* 0x144 Station Address,part 2 */
+ struct {
+ u32 exact_match1; /* octets 1-4 */
+ u32 exact_match2; /* octets 5-6 */
+ } macaddr[15]; /* 0x148-0x1BC mac exact match addresses 1-15 */
+ u32 reserved01c0[16];
+ u32 tr64; /* 0x200 Tx and Rx 64 byte frame counter */
+ u32 tr127; /* 0x204 Tx and Rx 65 to 127 byte frame counter */
+ u32 tr255; /* 0x208 Tx and Rx 128 to 255 byte frame counter */
+ u32 tr511; /* 0x20C Tx and Rx 256 to 511 byte frame counter */
+ u32 tr1k; /* 0x210 Tx and Rx 512 to 1023 byte frame counter */
+ u32 trmax; /* 0x214 Tx and Rx 1024 to 1518 byte frame counter */
+ u32 trmgv;
+ /* 0x218 Tx and Rx 1519 to 1522 byte good VLAN frame count */
+ u32 rbyt; /* 0x21C receive byte counter */
+ u32 rpkt; /* 0x220 receive packet counter */
+ u32 rfcs; /* 0x224 receive FCS error counter */
+ u32 rmca; /* 0x228 RMCA Rx multicast packet counter */
+ u32 rbca; /* 0x22C Rx broadcast packet counter */
+ u32 rxcf; /* 0x230 Rx control frame packet counter */
+ u32 rxpf; /* 0x234 Rx pause frame packet counter */
+ u32 rxuo; /* 0x238 Rx unknown OP code counter */
+ u32 raln; /* 0x23C Rx alignment error counter */
+ u32 rflr; /* 0x240 Rx frame length error counter */
+ u32 rcde; /* 0x244 Rx code error counter */
+ u32 rcse; /* 0x248 Rx carrier sense error counter */
+ u32 rund; /* 0x24C Rx undersize packet counter */
+ u32 rovr; /* 0x250 Rx oversize packet counter */
+ u32 rfrg; /* 0x254 Rx fragments counter */
+ u32 rjbr; /* 0x258 Rx jabber counter */
+ u32 rdrp; /* 0x25C Rx drop */
+ u32 tbyt; /* 0x260 Tx byte counter */
+ u32 tpkt; /* 0x264 Tx packet counter */
+ u32 tmca; /* 0x268 Tx multicast packet counter */
+ u32 tbca; /* 0x26C Tx broadcast packet counter */
+ u32 txpf; /* 0x270 Tx pause control frame counter */
+ u32 tdfr; /* 0x274 Tx deferral packet counter */
+ u32 tedf; /* 0x278 Tx excessive deferral packet counter */
+ u32 tscl; /* 0x27C Tx single collision packet counter */
+ u32 tmcl; /* 0x280 Tx multiple collision packet counter */
+ u32 tlcl; /* 0x284 Tx late collision packet counter */
+ u32 txcl; /* 0x288 Tx excessive collision packet counter */
+ u32 tncl; /* 0x28C Tx total collision counter */
+ u32 reserved0290[1];
+ u32 tdrp; /* 0x294 Tx drop frame counter */
+ u32 tjbr; /* 0x298 Tx jabber frame counter */
+ u32 tfcs; /* 0x29C Tx FCS error counter */
+ u32 txcf; /* 0x2A0 Tx control frame counter */
+ u32 tovr; /* 0x2A4 Tx oversize frame counter */
+ u32 tund; /* 0x2A8 Tx undersize frame counter */
+ u32 tfrg; /* 0x2AC Tx fragments frame counter */
+ u32 car1; /* 0x2B0 carry register one register* */
+ u32 car2; /* 0x2B4 carry register two register* */
+ u32 cam1; /* 0x2B8 carry register one mask register */
+ u32 cam2; /* 0x2BC carry register two mask register */
+ u32 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;
+ u32 halfdup_alt_backoff_val;
+ u16 halfdup_retransmit;
+ u16 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;
+ u16 tx_pause_time;
+ u16 tbipa;
+ bool ptp_tsu_en;
+ bool ptp_exception_en;
+ bool rx_preamble;
+ bool tx_preamble;
+ u32 preamble_len;
+ u32 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;
+ u8 tbi_phy_addr;
+ u16 tx_pause_time_extd;
+ u16 maximum_frame;
+ u32 non_back_to_back_ipg1;
+ u32 non_back_to_back_ipg2;
+ u32 min_ifg_enforcement;
+ u32 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.
+ *
+ * Return: 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,
+ u8 *macaddr, u8 fm_rev_maj,
+ u8 fm_rev_min, u32 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
+ *
+ * Call this function to obtain the dTSEC hardware version.
+ * Return: dtsec_id content
+ */
+u32 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, u8 *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, u16 length);
+
+/**
+ * fman_dtsec_get_max_frame_len() - Query max frame length
+ * @regs: Pointer to dTSEC register block
+ *
+ * Return: the current value of the maximum frame length.
+ */
+u16 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, u16 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, u32 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.
+ */
+u32 fman_dtsec_get_event(struct dtsec_regs __iomem *regs, u32 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.
+ */
+u32 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, u32 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, u32 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
+ * @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).
+ * Return: true if overflow occurred, otherwise - false
+ */
+bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs __iomem *regs,
+ u32 *car1, u32 *car2);
+
+u32 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_rx(struct dtsec_regs __iomem *regs);
+u32 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..73e3c16
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_dtsec_mii_acc.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <linux/io.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 {
+ u32 reserved1[72];
+ u32 miimcfg; /* MII Mgmt:configuration */
+ u32 miimcom; /* MII Mgmt:command */
+ u32 miimadd; /* MII Mgmt:address */
+ u32 miimcon; /* MII Mgmt:control 3 */
+ u32 miimstat; /* MII Mgmt:status */
+ u32 miimind; /* MII Mgmt:indicators */
+};
+
+void fman_dtsec_mii_init(struct dtsec_mii_reg __iomem *regs, u16 dtsec_freq);
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg __iomem *regs, u8 addr,
+ u8 reg, u16 data, u16 dtsec_freq);
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg __iomem *regs, u8 addr,
+ u8 reg, u16 *data, u16 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..f8641d4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
@@ -0,0 +1,428 @@
+/*
+ * 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 <linux/io.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 \
+ ((u32)(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
+
+#define CLXY_PAUSE_QUANTA_CLX_PQNT 0x0000FFFF
+#define CLXY_PAUSE_QUANTA_CLY_PQNT 0xFFFF0000
+#define CLXY_PAUSE_THRESH_CLX_QTH 0x0000FFFF
+#define CLXY_PAUSE_THRESH_CLY_QTH 0xFFFF0000
+
+struct mac_addr {
+ /* Lower 32 bits of 48-bit MAC address */
+ u32 mac_addr_l;
+ /* Upper 16 bits of 48-bit MAC address */
+ u32 mac_addr_u;
+};
+
+/* memory map */
+struct memac_regs {
+ u32 res0000[2]; /* General Control and Status */
+ u32 command_config; /* 0x008 Ctrl and cfg */
+ struct mac_addr mac_addr0; /* 0x00C-0x010 MAC_ADDR_0...1 */
+ u32 maxfrm; /* 0x014 Max frame length */
+ u32 res0018[1];
+ u32 rx_fifo_sections; /* Receive FIFO configuration reg */
+ u32 tx_fifo_sections; /* Transmit FIFO configuration reg */
+ u32 res0024[2];
+ u32 hashtable_ctrl; /* 0x02C Hash table control */
+ u32 res0030[4];
+ u32 ievent; /* 0x040 Interrupt event */
+ u32 tx_ipg_length; /* 0x044 Transmitter inter-packet-gap */
+ u32 res0048;
+ u32 imask; /* 0x04C Interrupt mask */
+ u32 res0050;
+ u32 pause_quanta[4]; /* 0x054 Pause quanta */
+ u32 pause_thresh[4]; /* 0x064 Pause quanta threshold */
+ u32 rx_pause_status; /* 0x074 Receive pause status */
+ u32 res0078[2];
+ struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS];/* 0x80-0x0B4 mac padr */
+ u32 lpwake_timer; /* 0x0B8 Low Power Wakeup Timer */
+ u32 sleep_timer; /* 0x0BC Transmit EEE Low Power Timer */
+ u32 res00c0[8];
+ u32 statn_config; /* 0x0E0 Statistics configuration */
+ u32 res00e4[7];
+ /* Rx Statistics Counter */
+ u32 reoct_l;
+ u32 reoct_u;
+ u32 roct_l;
+ u32 roct_u;
+ u32 raln_l;
+ u32 raln_u;
+ u32 rxpf_l;
+ u32 rxpf_u;
+ u32 rfrm_l;
+ u32 rfrm_u;
+ u32 rfcs_l;
+ u32 rfcs_u;
+ u32 rvlan_l;
+ u32 rvlan_u;
+ u32 rerr_l;
+ u32 rerr_u;
+ u32 ruca_l;
+ u32 ruca_u;
+ u32 rmca_l;
+ u32 rmca_u;
+ u32 rbca_l;
+ u32 rbca_u;
+ u32 rdrp_l;
+ u32 rdrp_u;
+ u32 rpkt_l;
+ u32 rpkt_u;
+ u32 rund_l;
+ u32 rund_u;
+ u32 r64_l;
+ u32 r64_u;
+ u32 r127_l;
+ u32 r127_u;
+ u32 r255_l;
+ u32 r255_u;
+ u32 r511_l;
+ u32 r511_u;
+ u32 r1023_l;
+ u32 r1023_u;
+ u32 r1518_l;
+ u32 r1518_u;
+ u32 r1519x_l;
+ u32 r1519x_u;
+ u32 rovr_l;
+ u32 rovr_u;
+ u32 rjbr_l;
+ u32 rjbr_u;
+ u32 rfrg_l;
+ u32 rfrg_u;
+ u32 rcnp_l;
+ u32 rcnp_u;
+ u32 rdrntp_l;
+ u32 rdrntp_u;
+ u32 res01d0[12];
+ /* Tx Statistics Counter */
+ u32 teoct_l;
+ u32 teoct_u;
+ u32 toct_l;
+ u32 toct_u;
+ u32 res0210[2];
+ u32 txpf_l;
+ u32 txpf_u;
+ u32 tfrm_l;
+ u32 tfrm_u;
+ u32 tfcs_l;
+ u32 tfcs_u;
+ u32 tvlan_l;
+ u32 tvlan_u;
+ u32 terr_l;
+ u32 terr_u;
+ u32 tuca_l;
+ u32 tuca_u;
+ u32 tmca_l;
+ u32 tmca_u;
+ u32 tbca_l;
+ u32 tbca_u;
+ u32 res0258[2];
+ u32 tpkt_l;
+ u32 tpkt_u;
+ u32 tund_l;
+ u32 tund_u;
+ u32 t64_l;
+ u32 t64_u;
+ u32 t127_l;
+ u32 t127_u;
+ u32 t255_l;
+ u32 t255_u;
+ u32 t511_l;
+ u32 t511_u;
+ u32 t1023_l;
+ u32 t1023_u;
+ u32 t1518_l;
+ u32 t1518_u;
+ u32 t1519x_l;
+ u32 t1519x_u;
+ u32 res02a8[6];
+ u32 tcnp_l;
+ u32 tcnp_u;
+ u32 res02c8[14];
+ /* Line Interface Control */
+ u32 if_mode; /* 0x300 Interface Mode Control */
+ u32 if_status; /* 0x304 Interface Status */
+ u32 res0308[14];
+ /* HiGig/2 */
+ u32 hg_config; /* 0x340 Control and cfg */
+ u32 res0344[3];
+ u32 hg_pause_quanta; /* 0x350 Pause quanta */
+ u32 res0354[3];
+ u32 hg_pause_thresh; /* 0x360 Pause quanta threshold */
+ u32 res0364[3];
+ u32 hgrx_pause_status; /* 0x370 Receive pause status */
+ u32 hg_fifos_status; /* 0x374 fifos status */
+ u32 rhm; /* 0x378 rx messages counter */
+ u32 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;
+ u16 max_frame_length;
+ u16 pause_quanta;
+ u32 tx_ipg_length;
+};
+
+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,
+ u32 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,
+ u8 *adr, u8 paddr_num);
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs __iomem *regs,
+ u8 paddr_num);
+
+void fman_memac_set_tx_pause_frames(struct memac_regs __iomem *regs,
+ u8 priority, u16 pause_time,
+ u16 thresh_time);
+
+u16 fman_memac_get_max_frame_len(struct memac_regs __iomem *regs);
+
+void fman_memac_set_exception(struct memac_regs __iomem *regs, u32 val,
+ bool enable);
+
+int fman_memac_reset(struct memac_regs __iomem *regs);
+
+void fman_memac_set_hash_table(struct memac_regs __iomem *regs, u32 val);
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs __iomem *regs,
+ bool enable);
+
+u32 fman_memac_get_event(struct memac_regs __iomem *regs, u32 ev_mask);
+
+void fman_memac_ack_event(struct memac_regs __iomem *regs, u32 ev_mask);
+
+u32 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..66ecc1e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac_mii_acc.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <linux/io.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 {
+ u32 mdio_cfg; /* 0x030 */
+ u32 mdio_ctrl; /* 0x034 */
+ u32 mdio_data; /* 0x038 */
+ u32 mdio_addr; /* 0x03c */
+};
+
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, u8 phy_addr, u8 reg, u16 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..7b63ec0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_tgec.h
@@ -0,0 +1,393 @@
+/*
+ * 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 <linux/io.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 CMF_CFG_CRC_FWD 0x00000040
+#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 \
+ ((u32)(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 {
+ u32 tgec_id; /* 0x000 Controller ID */
+ u32 reserved001[1]; /* 0x004 */
+ u32 command_config; /* 0x008 Control and configuration */
+ u32 mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */
+ u32 mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */
+ u32 maxfrm; /* 0x014 Maximum frame length */
+ u32 pause_quant; /* 0x018 Pause quanta */
+ u32 rx_fifo_sections; /* 0x01c */
+ u32 tx_fifo_sections; /* 0x020 */
+ u32 rx_fifo_almost_f_e; /* 0x024 */
+ u32 tx_fifo_almost_f_e; /* 0x028 */
+ u32 hashtable_ctrl; /* 0x02c Hash table control */
+ u32 mdio_cfg_status; /* 0x030 */
+ u32 mdio_command; /* 0x034 */
+ u32 mdio_data; /* 0x038 */
+ u32 mdio_regaddr; /* 0x03c */
+ u32 status; /* 0x040 */
+ u32 tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */
+ u32 mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */
+ u32 mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */
+ u32 rx_fifo_ptr_rd; /* 0x050 */
+ u32 rx_fifo_ptr_wr; /* 0x054 */
+ u32 tx_fifo_ptr_rd; /* 0x058 */
+ u32 tx_fifo_ptr_wr; /* 0x05c */
+ u32 imask; /* 0x060 Interrupt mask */
+ u32 ievent; /* 0x064 Interrupt event */
+ u32 udp_port; /* 0x068 Defines a UDP Port number */
+ u32 type_1588v2; /* 0x06c Type field for 1588v2 */
+ u32 reserved070[4]; /* 0x070 */
+ /* 10Ge Statistics Counter */
+ u32 tfrm_u; /* 80 aFramesTransmittedOK */
+ u32 tfrm_l; /* 84 aFramesTransmittedOK */
+ u32 rfrm_u; /* 88 aFramesReceivedOK */
+ u32 rfrm_l; /* 8c aFramesReceivedOK */
+ u32 rfcs_u; /* 90 aFrameCheckSequenceErrors */
+ u32 rfcs_l; /* 94 aFrameCheckSequenceErrors */
+ u32 raln_u; /* 98 aAlignmentErrors */
+ u32 raln_l; /* 9c aAlignmentErrors */
+ u32 txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */
+ u32 txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */
+ u32 rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */
+ u32 rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */
+ u32 rlong_u; /* B0 aFrameTooLongErrors */
+ u32 rlong_l; /* B4 aFrameTooLongErrors */
+ u32 rflr_u; /* B8 aInRangeLengthErrors */
+ u32 rflr_l; /* Bc aInRangeLengthErrors */
+ u32 tvlan_u; /* C0 VLANTransmittedOK */
+ u32 tvlan_l; /* C4 VLANTransmittedOK */
+ u32 rvlan_u; /* C8 VLANReceivedOK */
+ u32 rvlan_l; /* Cc VLANReceivedOK */
+ u32 toct_u; /* D0 if_out_octets */
+ u32 toct_l; /* D4 if_out_octets */
+ u32 roct_u; /* D8 if_in_octets */
+ u32 roct_l; /* Dc if_in_octets */
+ u32 ruca_u; /* E0 if_in_ucast_pkts */
+ u32 ruca_l; /* E4 if_in_ucast_pkts */
+ u32 rmca_u; /* E8 ifInMulticastPkts */
+ u32 rmca_l; /* Ec ifInMulticastPkts */
+ u32 rbca_u; /* F0 ifInBroadcastPkts */
+ u32 rbca_l; /* F4 ifInBroadcastPkts */
+ u32 terr_u; /* F8 if_out_errors */
+ u32 terr_l; /* Fc if_out_errors */
+ u32 reserved100[2]; /* 100-108 */
+ u32 tuca_u; /* 108 if_out_ucast_pkts */
+ u32 tuca_l; /* 10c if_out_ucast_pkts */
+ u32 tmca_u; /* 110 ifOutMulticastPkts */
+ u32 tmca_l; /* 114 ifOutMulticastPkts */
+ u32 tbca_u; /* 118 ifOutBroadcastPkts */
+ u32 tbca_l; /* 11c ifOutBroadcastPkts */
+ u32 rdrp_u; /* 120 etherStatsDropEvents */
+ u32 rdrp_l; /* 124 etherStatsDropEvents */
+ u32 reoct_u; /* 128 etherStatsOctets */
+ u32 reoct_l; /* 12c etherStatsOctets */
+ u32 rpkt_u; /* 130 etherStatsPkts */
+ u32 rpkt_l; /* 134 etherStatsPkts */
+ u32 trund_u; /* 138 etherStatsUndersizePkts */
+ u32 trund_l; /* 13c etherStatsUndersizePkts */
+ u32 r64_u; /* 140 etherStatsPkts64Octets */
+ u32 r64_l; /* 144 etherStatsPkts64Octets */
+ u32 r127_u; /* 148 etherStatsPkts65to127Octets */
+ u32 r127_l; /* 14c etherStatsPkts65to127Octets */
+ u32 r255_u; /* 150 etherStatsPkts128to255Octets */
+ u32 r255_l; /* 154 etherStatsPkts128to255Octets */
+ u32 r511_u; /* 158 etherStatsPkts256to511Octets */
+ u32 r511_l; /* 15c etherStatsPkts256to511Octets */
+ u32 r1023_u; /* 160 etherStatsPkts512to1023Octets */
+ u32 r1023_l; /* 164 etherStatsPkts512to1023Octets */
+ u32 r1518_u; /* 168 etherStatsPkts1024to1518Octets */
+ u32 r1518_l; /* 16c etherStatsPkts1024to1518Octets */
+ u32 r1519x_u; /* 170 etherStatsPkts1519toX */
+ u32 r1519x_l; /* 174 etherStatsPkts1519toX */
+ u32 trovr_u; /* 178 etherStatsOversizePkts */
+ u32 trovr_l; /* 17c etherStatsOversizePkts */
+ u32 trjbr_u; /* 180 etherStatsJabbers */
+ u32 trjbr_l; /* 184 etherStatsJabbers */
+ u32 trfrg_u; /* 188 etherStatsFragments */
+ u32 trfrg_l; /* 18C etherStatsFragments */
+ u32 rerr_u; /* 190 if_in_errors */
+ u32 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;
+ u16 max_frame_length;
+ u16 pause_quant;
+ u32 tx_ipg_length;
+};
+
+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.
+ *
+ * Return: 0 if successful, an error code otherwise.
+ */
+int fman_tgec_init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
+ u32 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);
+
+u32 fman_tgec_get_revision(struct tgec_regs __iomem *regs);
+
+void fman_tgec_set_mac_address(struct tgec_regs __iomem *regs, u8 *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, u32 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,
+ u16 pause_time);
+
+/**
+ * fman_tgec_set_rx_ignore_pause_frames()
+ * @regs: Pointer to TGEC register block
+ * @en: Ignore/Respond to pause frame quanta
+ *
+ * Changes the policy WRT pause frames
+ * 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);
+
+u32 fman_tgec_get_event(struct tgec_regs __iomem *regs, u32 ev_mask);
+
+void fman_tgec_ack_event(struct tgec_regs __iomem *regs, u32 ev_mask);
+
+u32 fman_tgec_get_interrupt_mask(struct tgec_regs __iomem *regs);
+
+void fman_tgec_enable_interrupt(struct tgec_regs __iomem *regs, u32 ev_mask);
+
+void fman_tgec_disable_interrupt(struct tgec_regs __iomem *regs, u32 ev_mask);
+
+void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs
+ __iomem *regs);
+
+#endif /* __FSL_FMAN_TGEC_H */
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..610ca45
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec.c
@@ -0,0 +1,503 @@
+/*
+ * 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(&regs->rctrl) | RCTRL_GRS, &regs->rctrl);
+}
+
+void fman_dtsec_start_tx(struct dtsec_regs __iomem *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS, &regs->tctrl);
+}
+
+void fman_dtsec_start_rx(struct dtsec_regs __iomem *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS, &regs->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,
+ u8 *macaddr,
+ u8 __maybe_unused fm_rev_maj,
+ u8 __maybe_unused fm_rev_min, u32 exception_mask)
+{
+ bool is_rgmii, is_sgmii, is_qsgmii;
+ int i;
+ u32 tmp;
+
+ /* Soft reset */
+ iowrite32be(MACCFG1_SOFT_RESET, &regs->maccfg1);
+ iowrite32be(0, &regs->maccfg1);
+
+ /* dtsec_id2 */
+ tmp = ioread32be(&regs->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;
+
+ 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, &regs->ecntrl);
+
+ tmp = 0;
+ if (cfg->halfdup_on)
+ tmp |= DTSEC_TCTRL_THDF;
+ if (cfg->tx_time_stamp_en)
+ tmp |= DTSEC_TCTRL_TTSE;
+
+ iowrite32be(tmp, &regs->tctrl);
+
+ tmp = 0;
+
+ if (cfg->tx_pause_time)
+ tmp |= cfg->tx_pause_time;
+ if (cfg->tx_pause_time_extd)
+ tmp |= cfg->tx_pause_time_extd << PTV_PTE_SHIFT;
+ iowrite32be(tmp, &regs->ptv);
+
+ tmp = 0;
+ tmp |= (cfg->rx_prepend << RCTRL_PAL_SHIFT) & RCTRL_PAL_MASK;
+ 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, &regs->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, &regs->tbipa);
+
+ iowrite32be(0, &regs->tmr_ctrl);
+
+ if (cfg->ptp_tsu_en) {
+ tmp = 0;
+ tmp |= TMR_PEVENT_TSRE;
+ iowrite32be(tmp, &regs->tmr_pevent);
+
+ if (cfg->ptp_exception_en) {
+ tmp = 0;
+ tmp |= TMR_PEMASK_TSREEN;
+ iowrite32be(tmp, &regs->tmr_pemask);
+ }
+ }
+
+ 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, &regs->maccfg1);
+
+ 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 |= (cfg->preamble_len << MACCFG2_PREAMBLE_LENGTH_SHIFT) &
+ MACCFG2_PREAMBLE_LENGTH_MASK;
+ 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, &regs->maccfg2);
+
+ 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, &regs->ipgifg);
+
+ tmp = 0;
+
+ if (cfg->halfdup_alt_backoff_en)
+ tmp = HAFDUP_ALT_BEB;
+ tmp |= (cfg->halfdup_alt_backoff_val <<
+ HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT) &
+ HAFDUP_ALTERNATE_BEB_TRUNCATION_MASK;
+ 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, &regs->hafdup);
+
+ /* Initialize Maximum frame length */
+ iowrite32be(cfg->maximum_frame, &regs->maxfrm);
+
+ iowrite32be(0xffffffff, &regs->cam1);
+ iowrite32be(0xffffffff, &regs->cam2);
+
+ iowrite32be(exception_mask, &regs->imask);
+
+ iowrite32be(0xffffffff, &regs->ievent);
+
+ tmp = (u32)((macaddr[5] << 24) |
+ (macaddr[4] << 16) | (macaddr[3] << 8) | macaddr[2]);
+ iowrite32be(tmp, &regs->macstnaddr1);
+
+ tmp = (u32)((macaddr[1] << 24) | (macaddr[0] << 16));
+ iowrite32be(tmp, &regs->macstnaddr2);
+
+ /* HASH */
+ for (i = 0; i < NUM_OF_HASH_REGS; i++) {
+ /* Initialize IADDRx */
+ iowrite32be(0, &regs->igaddr[i]);
+ /* Initialize GADDRx */
+ iowrite32be(0, &regs->gaddr[i]);
+ }
+
+ return 0;
+}
+
+u16 fman_dtsec_get_max_frame_len(struct dtsec_regs __iomem *regs)
+{
+ return (u16)ioread32be(&regs->maxfrm);
+}
+
+void fman_dtsec_set_max_frame_len(struct dtsec_regs __iomem *regs, u16 length)
+{
+ iowrite32be(length, &regs->maxfrm);
+}
+
+void fman_dtsec_set_mac_address(struct dtsec_regs __iomem *regs, u8 *adr)
+{
+ u32 tmp;
+
+ tmp = (u32)((adr[5] << 24) |
+ (adr[4] << 16) | (adr[3] << 8) | adr[2]);
+ iowrite32be(tmp, &regs->macstnaddr1);
+
+ tmp = (u32)((adr[1] << 24) | (adr[0] << 16));
+ iowrite32be(tmp, &regs->macstnaddr2);
+}
+
+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;
+ u32 bit_mask = 0x80000000 >> bit_idx;
+ u32 __iomem *reg;
+
+ if (reg_idx > 7)
+ reg = &regs->gaddr[reg_idx - 8];
+ else
+ reg = &regs->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)
+{
+ u32 tmp;
+
+ if ((speed == E_ENET_SPEED_1000) && !full_dx)
+ return -EINVAL;
+
+ tmp = ioread32be(&regs->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, &regs->maccfg2);
+
+ tmp = ioread32be(&regs->ecntrl);
+ if (speed == E_ENET_SPEED_100)
+ tmp |= DTSEC_ECNTRL_R100M;
+ else
+ tmp &= ~DTSEC_ECNTRL_R100M;
+ iowrite32be(tmp, &regs->ecntrl);
+
+ return 0;
+}
+
+void fman_dtsec_set_uc_promisc(struct dtsec_regs __iomem *regs, bool enable)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_UPROM;
+ else
+ tmp &= ~RCTRL_UPROM;
+
+ iowrite32be(tmp, &regs->rctrl);
+}
+
+void fman_dtsec_set_mc_promisc(struct dtsec_regs __iomem *regs, bool enable)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_MPROM;
+ else
+ tmp &= ~RCTRL_MPROM;
+
+ iowrite32be(tmp, &regs->rctrl);
+}
+
+void fman_dtsec_enable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->maccfg1);
+
+ if (apply_rx)
+ tmp |= MACCFG1_RX_EN;
+
+ if (apply_tx)
+ tmp |= MACCFG1_TX_EN;
+
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+void fman_dtsec_disable(struct dtsec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->maccfg1);
+
+ if (apply_rx)
+ tmp &= ~MACCFG1_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~MACCFG1_TX_EN;
+
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+void fman_dtsec_set_tx_pause_frames(struct dtsec_regs __iomem *regs, u16 time)
+{
+ u32 ptv = 0;
+
+ if (time) {
+ ptv = ioread32be(&regs->ptv);
+ ptv &= PTV_PTE_MASK;
+ ptv |= time & PTV_PT_MASK;
+ iowrite32be(ptv, &regs->ptv);
+
+ /* trigger the transmission of a flow-control pause frame */
+ iowrite32be(ioread32be(&regs->maccfg1) | MACCFG1_TX_FLOW,
+ &regs->maccfg1);
+ } else
+ iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
+ &regs->maccfg1);
+}
+
+void fman_dtsec_handle_rx_pause(struct dtsec_regs __iomem *regs, bool en)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->maccfg1);
+ if (en)
+ tmp |= MACCFG1_RX_FLOW;
+ else
+ tmp &= ~MACCFG1_RX_FLOW;
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+u32 fman_dtsec_get_rctrl(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(&regs->rctrl);
+}
+
+u32 fman_dtsec_get_revision(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(&regs->tsec_id);
+}
+
+u32 fman_dtsec_get_event(struct dtsec_regs __iomem *regs, u32 ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+void fman_dtsec_ack_event(struct dtsec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+u32 fman_dtsec_get_interrupt_mask(struct dtsec_regs __iomem *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+u32 fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs __iomem *regs)
+{
+ u32 event;
+
+ event = ioread32be(&regs->tmr_pevent);
+ event &= ioread32be(&regs->tmr_pemask);
+
+ if (event)
+ iowrite32be(event, &regs->tmr_pevent);
+ return event;
+}
+
+void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs __iomem *regs)
+{
+ iowrite32be(ioread32be(&regs->tmr_pemask) | TMR_PEMASK_TSREEN,
+ &regs->tmr_pemask);
+}
+
+void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs __iomem *regs)
+{
+ iowrite32be(ioread32be(&regs->tmr_pemask) & ~TMR_PEMASK_TSREEN,
+ &regs->tmr_pemask);
+}
+
+void fman_dtsec_enable_interrupt(struct dtsec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
+}
+
+void fman_dtsec_disable_interrupt(struct dtsec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->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..3461adf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_dtsec_mii_acc.c
@@ -0,0 +1,153 @@
+/*
+ * 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_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 u8 dtsec_mii_get_div(u16 dtsec_freq)
+{
+ u16 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 (u8)mgmt_clk;
+}
+
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg __iomem *regs, u8 addr,
+ u8 reg, u16 data, u16 dtsec_freq)
+{
+ u32 tmp;
+ int count;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((u32)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
+
+ /* Stop the MII management read cycle */
+ iowrite32be(0, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->miimcom);
+
+ /* Setting up MII Management Address Register */
+ tmp = (u32)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, &regs->miimadd);
+
+ /* Setting up MII Management Control Register with data */
+ iowrite32be((u32)data, &regs->miimcon);
+ /* Dummy read to make sure MIIMCON is written */
+ tmp = ioread32be(&regs->miimcon);
+
+ /* Wait until MII management write is complete */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&regs->miimind)) & MIIMIND_BUSY) && count--);
+
+ if (count == 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg __iomem *regs, u8 addr,
+ u8 reg, u16 *data, u16 dtsec_freq)
+{
+ u32 tmp;
+ int count;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((u32)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
+
+ /* Setting up the MII Management Address Register */
+ tmp = (u32)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, &regs->miimadd);
+
+ /* Perform an MII management read cycle */
+ iowrite32be(MIIMCOM_READ_CYCLE, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->miimcom);
+
+ /* Wait until MII management write is complete */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&regs->miimind)) & MIIMIND_BUSY) && count--);
+
+ if (count == 0)
+ return -EBUSY;
+
+ /* Read MII management status */
+ *data = (u16)ioread32be(&regs->miimstat);
+
+ iowrite32be(0, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->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..7ea219a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_memac.c
@@ -0,0 +1,374 @@
+/*
+ * 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"
+
+u32 fman_memac_get_event(struct memac_regs __iomem *regs, u32 ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+u32 fman_memac_get_interrupt_mask(struct memac_regs __iomem *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+void fman_memac_ack_event(struct memac_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+void fman_memac_set_promiscuous(struct memac_regs __iomem *regs, bool val)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs __iomem *regs,
+ u8 paddr_num)
+{
+ if (paddr_num == 0) {
+ iowrite32be(0, &regs->mac_addr0.mac_addr_l);
+ iowrite32be(0, &regs->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_l);
+ iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_u);
+ }
+}
+
+void fman_memac_add_addr_in_paddr(struct memac_regs __iomem *regs,
+ u8 *adr, u8 paddr_num)
+{
+ u32 tmp0, tmp1;
+
+ tmp0 = (u32)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24);
+ tmp1 = (u32)(adr[4] | adr[5] << 8);
+
+ if (paddr_num == 0) {
+ iowrite32be(tmp0, &regs->mac_addr0.mac_addr_l);
+ iowrite32be(tmp1, &regs->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(tmp0, &regs->mac_addr[paddr_num - 1].mac_addr_l);
+ iowrite32be(tmp1, &regs->mac_addr[paddr_num - 1].mac_addr_u);
+ }
+}
+
+void fman_memac_enable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_disable(struct memac_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (apply_rx)
+ tmp &= ~CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+int fman_memac_reset(struct memac_regs __iomem *regs)
+{
+ u32 tmp;
+ int count;
+
+ tmp = ioread32be(&regs->command_config);
+
+ tmp |= CMD_CFG_SW_RESET;
+
+ iowrite32be(tmp, &regs->command_config);
+
+ count = 100;
+ do {
+ udelay(1);
+ } while ((ioread32be(&regs->command_config) & CMD_CFG_SW_RESET) &&
+ --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+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,
+ u32 exceptions)
+{
+ u32 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, &regs->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((u32)cfg->max_frame_length, &regs->maxfrm);
+
+ /* Pause Time */
+ iowrite32be((u32)cfg->pause_quanta, &regs->pause_quanta[0]);
+ iowrite32be((u32)0, &regs->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, &regs->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, &regs->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, u32 val,
+ bool enable)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->imask);
+ if (enable)
+ tmp |= val;
+ else
+ tmp &= ~val;
+
+ iowrite32be(tmp, &regs->imask);
+}
+
+void fman_memac_set_hash_table(struct memac_regs __iomem *regs, u32 val)
+{
+ iowrite32be(val, &regs->hashtable_ctrl);
+}
+
+u16 fman_memac_get_max_frame_len(struct memac_regs __iomem *regs)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->maxfrm);
+
+ return (u16)tmp;
+}
+
+void fman_memac_set_tx_pause_frames(struct memac_regs __iomem *regs,
+ u8 priority, u16 pause_time,
+ u16 thresh_time)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->tx_fifo_sections);
+
+ GET_TX_EMPTY_DEFAULT_VALUE(tmp);
+ iowrite32be(tmp, &regs->tx_fifo_sections);
+
+ tmp = ioread32be(&regs->command_config);
+ tmp &= ~CMD_CFG_PFC_MODE;
+ priority = 0;
+
+ iowrite32be(tmp, &regs->command_config);
+
+ tmp = ioread32be(&regs->pause_quanta[priority / 2]);
+ if (priority % 2)
+ tmp &= CLXY_PAUSE_QUANTA_CLX_PQNT;
+ else
+ tmp &= CLXY_PAUSE_QUANTA_CLY_PQNT;
+ tmp |= ((u32)pause_time << (16 * (priority % 2)));
+ iowrite32be(tmp, &regs->pause_quanta[priority / 2]);
+
+ tmp = ioread32be(&regs->pause_thresh[priority / 2]);
+ if (priority % 2)
+ tmp &= CLXY_PAUSE_THRESH_CLX_QTH;
+ else
+ tmp &= CLXY_PAUSE_THRESH_CLY_QTH;
+ tmp |= ((u32)thresh_time << (16 * (priority % 2)));
+ iowrite32be(tmp, &regs->pause_thresh[priority / 2]);
+}
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs __iomem *regs,
+ bool enable)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (enable)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_adjust_link(struct memac_regs __iomem *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->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, &regs->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..f59bc79
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_memac_mii_acc.c
@@ -0,0 +1,151 @@
+/*
+ * 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 int write_phy_reg_10g(struct memac_mii_access_mem_map __iomem *mii_regs,
+ u8 phy_addr, u8 reg, u16 data)
+{
+ u32 tmp_reg;
+ int count;
+
+ 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 */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) && --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ /* Specify phy and register to be accessed */
+ iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
+ iowrite32be(reg, &mii_regs->mdio_addr);
+
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) && --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ /* Write data */
+ iowrite32be(data, &mii_regs->mdio_data);
+
+ /* Wait for write transaction end */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) &&
+ --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int write_phy_reg_1g(struct memac_mii_access_mem_map __iomem *mii_regs,
+ u8 phy_addr, u8 reg, u16 data)
+{
+ u32 tmp_reg;
+ int count;
+
+ /* 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 */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) && --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ /* Write transaction */
+ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
+ tmp_reg |= reg;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+
+ /* Wait for command completion */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) && --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ iowrite32be(data, &mii_regs->mdio_data);
+
+ /* Wait for write transaction to end */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) &&
+ --count);
+
+ if (count == 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map __iomem
+ *mii_regs, u8 phy_addr, u8 reg, u16 data,
+ enum enet_speed enet_speed)
+{
+ int err = 0;
+ /* Figure out interface type - 10G vs 1G.
+ * In 10G interface both phy_addr and devAddr present.
+ */
+ if (enet_speed == E_ENET_SPEED_10000)
+ err = write_phy_reg_10g(mii_regs, phy_addr, reg, data);
+ else
+ err = write_phy_reg_1g(mii_regs, phy_addr, reg, data);
+
+ return err;
+}
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..92ac11a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fman_tgec.c
@@ -0,0 +1,207 @@
+/*
+ * 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, u8 *adr)
+{
+ u32 tmp0, tmp1;
+
+ tmp0 = (u32)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24);
+ tmp1 = (u32)(adr[4] | adr[5] << 8);
+ iowrite32be(tmp0, &regs->mac_addr_0);
+ iowrite32be(tmp1, &regs->mac_addr_1);
+}
+
+void fman_tgec_enable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_tgec_disable(struct tgec_regs __iomem *regs, bool apply_rx,
+ bool apply_tx)
+{
+ u32 tmp_reg_32;
+
+ tmp_reg_32 = ioread32be(&regs->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, &regs->command_config);
+}
+
+void fman_tgec_set_promiscuous(struct tgec_regs __iomem *regs, bool val)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_tgec_set_hash_table(struct tgec_regs __iomem *regs, u32 value)
+{
+ iowrite32be(value, &regs->hashtable_ctrl);
+}
+
+void fman_tgec_set_tx_pause_frames(struct tgec_regs __iomem *regs,
+ u16 pause_time)
+{
+ iowrite32be((u32)pause_time, &regs->pause_quant);
+}
+
+void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs __iomem *regs,
+ bool en)
+{
+ u32 tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (en)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+u32 fman_tgec_get_event(struct tgec_regs __iomem *regs, u32 ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+void fman_tgec_ack_event(struct tgec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+u32 fman_tgec_get_interrupt_mask(struct tgec_regs __iomem *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+u32 fman_tgec_get_revision(struct tgec_regs __iomem *regs)
+{
+ return ioread32be(&regs->tgec_id);
+}
+
+void fman_tgec_enable_interrupt(struct tgec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
+}
+
+void fman_tgec_disable_interrupt(struct tgec_regs __iomem *regs, u32 ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->imask);
+}
+
+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;
+}
+
+int fman_tgec_init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
+ u32 exception_mask)
+{
+ u32 tmp;
+
+ /* Config */
+ tmp = CMF_CFG_CRC_FWD;
+ 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, &regs->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((u32)cfg->max_frame_length, &regs->maxfrm);
+ /* Pause Time */
+ iowrite32be(cfg->pause_quant, &regs->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)
+{
+ u32 tmp;
+
+ /* restore the default tx ipg Length */
+ tmp = (ioread32be(&regs->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12;
+
+ iowrite32be(tmp, &regs->tx_ipg_len);
+}
--
1.7.9.5

2015-08-05 13:45:35

by Liberman Igal

[permalink] [raw]
Subject: [v4, 4/9] fsl/fman: Add FMan MURAM support

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 | 115 ++++++++++++++++++++
.../net/ethernet/freescale/fman/inc/fm_muram_ext.h | 102 +++++++++++++++++
4 files changed, 222 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 8aeae29..66b7296 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..9d74bd9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_muram.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "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;
+ size_t size;
+ phys_addr_t pbase;
+};
+
+struct muram_info *fm_muram_init(phys_addr_t base, size_t size)
+{
+ struct muram_info *muram;
+ void __iomem *vaddr;
+ int ret;
+
+ muram = kzalloc(sizeof(*muram), GFP_KERNEL);
+ if (!muram)
+ return NULL;
+
+ muram->pool = gen_pool_create(ilog2(64), -1);
+ if (!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(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);
+
+ muram->vbase = vaddr;
+ muram->pbase = base;
+ return muram;
+}
+
+unsigned long fm_muram_vbase_to_offset(struct muram_info *muram,
+ unsigned long vaddr)
+{
+ return vaddr - (unsigned long)muram->vbase;
+}
+
+unsigned long fm_muram_offset_to_vbase(struct muram_info *muram,
+ unsigned long offset)
+{
+ return offset + (unsigned long)muram->vbase;
+}
+
+int fm_muram_alloc(struct muram_info *muram, size_t size)
+{
+ unsigned long vaddr;
+
+ vaddr = gen_pool_alloc(muram->pool, size);
+ if (!vaddr)
+ return -ENOMEM;
+
+ memset_io((void __iomem *)vaddr, 0, size);
+
+ return fm_muram_vbase_to_offset(muram, vaddr);
+}
+
+void fm_muram_free_mem(struct muram_info *muram, u32 offset, size_t size)
+{
+ unsigned long addr = fm_muram_offset_to_vbase(muram, offset);
+
+ gen_pool_free(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..d027b16
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_muram_ext.h
@@ -0,0 +1,102 @@
+/*
+ * 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_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_init
+ * @base: Pointer to base of memory mapped FM-MURAM.
+ * @size: Size of the FM-MURAM partition.
+ *
+ * Creates partition in the MURAM.
+ * The routine returns a pointer to the MURAM partition.
+ * This pointer must be passed as to all other FM-MURAM function calls.
+ * No actual initialization or configuration of FM_MURAM hardware is done by
+ * this routine.
+ *
+ * Return: pointer to FM-MURAM object, or NULL for Failure.
+ */
+struct muram_info *fm_muram_init(phys_addr_t base, size_t size);
+
+/**
+ * fm_muram_vbase_to_offset
+ * @muram: FM-MURAM module pointer.
+ * @vaddr: The virtual address of the memory block
+ *
+ * Gives the offset of the memory region in the MURAM
+ *
+ * Return: The offset of the memory block
+ */
+unsigned long fm_muram_vbase_to_offset(struct muram_info *muram,
+ unsigned long vaddr);
+
+/**
+ * fm_muram_vbase_to_offset
+ * @muram: FM-MURAM module pointer.
+ * @offset: the offset of the memory block
+ *
+ * Gives the address of the memory region from specific oddset
+ *
+ * Return: The address of the memory blocl
+ */
+unsigned long fm_muram_offset_to_vbase(struct muram_info *muram,
+ unsigned long offset);
+
+/**
+ * fm_muram_alloc
+ * @muram: FM-MURAM module pointer.
+ * @size: Size of the memory to be allocated.
+ *
+ * Allocate some memory from FM-MURAM partition.
+ *
+ * Return: address of the allocated memory; NULL otherwise.
+ */
+int fm_muram_alloc(struct muram_info *muram, size_t size);
+
+/**
+ * fm_muram_free_mem
+ * muram: FM-MURAM module pointer.
+ * offset: offset of the memory region to be freed.
+ * size: size of the memory to be freed.
+ *
+ * Free an allocated memory from FM-MURAM partition.
+ */
+void fm_muram_free_mem(struct muram_info *muram, u32 offset, size_t size);
+
+#endif /* __FM_MURAM_EXT */
--
1.7.9.5

2015-08-05 13:45:47

by Liberman Igal

[permalink] [raw]
Subject: [v4, 5/9] fsl/fman: Add Frame Manager support

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/Makefile | 2 +-
drivers/net/ethernet/freescale/fman/fm.c | 1076 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/fm.h | 276 +++++
drivers/net/ethernet/freescale/fman/fm_common.h | 114 +++
drivers/net/ethernet/freescale/fman/fm_drv.c | 551 ++++++++++
drivers/net/ethernet/freescale/fman/fm_drv.h | 109 ++
drivers/net/ethernet/freescale/fman/inc/enet_ext.h | 199 ++++
drivers/net/ethernet/freescale/fman/inc/fm_ext.h | 446 ++++++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 99 ++
9 files changed, 2871 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

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..7e5fa53
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -0,0 +1,1076 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "fm_common.h"
+#include "fm.h"
+#include "fm_muram_ext.h"
+#include <asm/mpc85xx.h>
+#include "fsl_fman.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+static struct fm_intg_t *fill_intg_params(u8 major, u8 minor)
+{
+ 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_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");
+ goto not_supported;
+ }
+
+ break;
+ default:
+ pr_err("Unsupported FMan version\n");
+ goto not_supported;
+ }
+
+ intg->bmi_max_fifo_size = intg->fm_muram_size;
+
+ return intg;
+
+not_supported:
+ kfree(intg);
+ return NULL;
+}
+
+static bool is_init_done(struct fman_cfg *fm_drv_params)
+{
+ /* Checks if FMan driver parameters were initialized */
+ if (!fm_drv_params)
+ return true;
+
+ return false;
+}
+
+static void free_init_resources(struct fm_t *fm)
+{
+ if (fm->cam_offset)
+ fm_muram_free_mem(fm->muram, fm->cam_offset, fm->cam_size);
+ if (fm->fifo_offset)
+ fm_muram_free_mem(fm->muram, fm->fifo_offset, fm->fifo_size);
+}
+
+static int check_fm_parameters(struct fm_t *fm)
+{
+ if (fm->fm_state->rev_info.major_rev < 6) {
+ if (!fm->fm_drv_param->dma_axi_dbg_num_of_beats ||
+ (fm->fm_drv_param->dma_axi_dbg_num_of_beats >
+ DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) {
+ pr_err("axi_dbg_num_of_beats has to be in the range 1 - %d\n",
+ DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS);
+ return -EINVAL;
+ }
+ }
+ if (fm->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 -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_comm_qtsh_asrt_emer >
+ fm->intg->dma_thresh_max_commq) {
+ pr_err("dma_comm_qtsh_asrt_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_commq);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_comm_qtsh_clr_emer >
+ fm->intg->dma_thresh_max_commq) {
+ pr_err("dma_comm_qtsh_clr_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_commq);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_comm_qtsh_clr_emer >=
+ fm->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 -EINVAL;
+ }
+ if (fm->fm_state->rev_info.major_rev < 6) {
+ if (fm->fm_drv_param->dma_read_buf_tsh_asrt_emer >
+ fm->intg->dma_thresh_max_buf) {
+ pr_err("dma_read_buf_tsh_asrt_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_buf);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_read_buf_tsh_clr_emer >
+ fm->intg->dma_thresh_max_buf) {
+ pr_err("dma_read_buf_tsh_clr_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_buf);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_read_buf_tsh_clr_emer >=
+ fm->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 -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_write_buf_tsh_asrt_emer >
+ fm->intg->dma_thresh_max_buf) {
+ pr_err("dma_write_buf_tsh_asrt_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_buf);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_write_buf_tsh_clr_emer >
+ fm->intg->dma_thresh_max_buf) {
+ pr_err("dma_write_buf_tsh_clr_emer can not be larger than %d\n",
+ fm->intg->dma_thresh_max_buf);
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_write_buf_tsh_clr_emer >=
+ fm->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 -EINVAL;
+ }
+ } else {
+ if ((fm->fm_drv_param->dma_dbg_cnt_mode ==
+ E_FMAN_DMA_DBG_CNT_INT_READ_EM) ||
+ (fm->fm_drv_param->dma_dbg_cnt_mode ==
+ E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
+ (fm->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 SoC.\n");
+ return -EINVAL;
+ }
+ if ((fm->fm_drv_param->dma_emergency_bus_select ==
+ FM_DMA_MURAM_READ_EMERGENCY) ||
+ (fm->fm_drv_param->dma_emergency_bus_select ==
+ FM_DMA_MURAM_WRITE_EMERGENCY)) {
+ pr_err("emergency_bus_select value not supported by this SoC.\n");
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_stop_on_bus_error) {
+ pr_err("dma_stop_on_bus_error not supported by this SoC.\n");
+ return -EINVAL;
+ }
+ /* FM_AID_MODE_NO_TNUM_SW005 Errata workaround */
+ if (fm->fm_state->rev_info.major_rev >= 6 &&
+ fm->fm_drv_param->dma_aid_mode !=
+ E_FMAN_DMA_AID_OUT_PORT_ID) {
+ pr_err("dma_aid_mode not supported by this SoC.\n");
+ return -EINVAL;
+ }
+ if (fm->fm_drv_param->dma_axi_dbg_num_of_beats) {
+ pr_err("dma_axi_dbg_num_of_beats not supported by this SoC.\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!fm->fm_state->fm_clk_freq) {
+ pr_err("fm_clk_freq must be set.\n");
+ return -EINVAL;
+ }
+ if ((fm->fm_drv_param->dma_watchdog *
+ fm->fm_state->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 -EINVAL;
+ }
+ if (fm->fm_state->total_fifo_size % BMI_FIFO_UNITS) {
+ pr_err("total_fifo_size number has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ }
+ if (!fm->fm_state->total_fifo_size ||
+ (fm->fm_state->total_fifo_size > fm->intg->bmi_max_fifo_size)) {
+ pr_err("total_fifo_size (curr - %d) has to be in the range 256 - %d\n",
+ fm->fm_state->total_fifo_size,
+ fm->intg->bmi_max_fifo_size);
+ return -EINVAL;
+ }
+ if (!fm->fm_state->total_num_of_tasks ||
+ (fm->fm_state->total_num_of_tasks >
+ fm->intg->bmi_max_num_of_tasks)) {
+ pr_err("total_num_of_tasks number has to be in the range 1 - %d\n",
+ fm->intg->bmi_max_num_of_tasks);
+ return -EINVAL;
+ }
+
+ if ((fm->fm_state->rev_info.major_rev < 6) &&
+ (!fm->fm_state->max_num_of_open_dmas ||
+ (fm->fm_state->max_num_of_open_dmas >
+ fm->intg->bmi_max_num_of_dmas))) {
+ pr_err("max_num_of_open_dmas number has to be in the range 1 - %d\n",
+ fm->intg->bmi_max_num_of_dmas);
+ return -EINVAL;
+ }
+
+ if (fm->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 -EINVAL;
+ }
+ if (!fm->exception_cb) {
+ pr_err("Exceptions callback not provided\n");
+ return -EINVAL;
+ }
+ if (!fm->bus_error_cb) {
+ pr_err("Error exceptions callback not provided\n");
+ return -EINVAL;
+ }
+ if ((fm->fm_state->rev_info.major_rev == 2) &&
+ (fm->fm_drv_param->dma_watchdog)) {
+ pr_err("watchdog not supported\n");
+ return -EINVAL;
+ }
+
+ /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 Errata workaround */
+ if ((fm->fm_state->rev_info.major_rev < 6) &&
+ (fm->fm_drv_param->halt_on_unrecov_ecc_err)) {
+ pr_err("Halt on ecc error not supported\n");
+ return -EINVAL;
+ }
+
+ if (fm->fm_state->rev_info.major_rev < 6)
+ if (fm->fm_drv_param->tnum_aging_period) {
+ pr_err("Tnum aging not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void bmi_err_event(struct fm_t *fm)
+{
+ u32 event;
+ struct fman_bmi_regs __iomem *bmi_rg = fm->bmi_regs;
+
+ event = fman_get_bmi_err_event(bmi_rg);
+
+ if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_BMI_STORAGE_PROFILE_ECC);
+ if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_BMI_LIST_RAM_ECC);
+ if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_BMI_STATISTICS_RAM_ECC);
+ if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_BMI_DISPATCH_RAM_ECC);
+}
+
+static void qmi_err_event(struct fm_t *fm)
+{
+ u32 event;
+ struct fman_qmi_regs __iomem *qmi_rg = fm->qmi_regs;
+
+ event = fman_get_qmi_err_event(qmi_rg);
+
+ if (event & QMI_ERR_INTR_EN_DOUBLE_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_QMI_DOUBLE_ECC);
+ if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF)
+ fm->exception_cb(fm->dev_id, FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID);
+}
+
+static void dma_err_event(struct fm_t *fm)
+{
+ u32 status;
+ struct fman_dma_regs __iomem *dma_rg = fm->dma_regs;
+
+ status = fman_get_dma_err_event(dma_rg);
+
+ if (status & DMA_STATUS_FM_SPDAT_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_DMA_SINGLE_PORT_ECC);
+ if (status & DMA_STATUS_READ_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_DMA_READ_ECC);
+ if (status & DMA_STATUS_SYSTEM_WRITE_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_DMA_SYSTEM_WRITE_ECC);
+ if (status & DMA_STATUS_FM_WRITE_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_DMA_FM_WRITE_ECC);
+}
+
+static void fpm_err_event(struct fm_t *fm)
+{
+ u32 event;
+ struct fman_fpm_regs __iomem *fpm_rg = 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))
+ fm->exception_cb(fm->dev_id, FM_EX_FPM_DOUBLE_ECC);
+ if ((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN))
+ fm->exception_cb(fm->dev_id, FM_EX_FPM_STALL_ON_TASKS);
+ if ((event & FPM_EV_MASK_SINGLE_ECC) &&
+ (event & FPM_EV_MASK_SINGLE_ECC_EN))
+ fm->exception_cb(fm->dev_id, FM_EX_FPM_SINGLE_ECC);
+}
+
+static void muram_err_intr(struct fm_t *fm)
+{
+ u32 event;
+ struct fman_fpm_regs __iomem *fpm_rg = fm->fpm_regs;
+
+ event = fman_get_muram_err_event(fpm_rg);
+
+ if (event & FPM_RAM_MURAM_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_MURAM_ECC);
+}
+
+static void qmi_event(struct fm_t *fm)
+{
+ u32 event;
+ struct fman_qmi_regs __iomem *qmi_rg = fm->qmi_regs;
+
+ event = fman_get_qmi_event(qmi_rg);
+
+ if (event & QMI_INTR_EN_SINGLE_ECC)
+ fm->exception_cb(fm->dev_id, FM_EX_QMI_SINGLE_ECC);
+}
+
+static void enable_time_stamp(struct fm_t *fm)
+{
+ struct fman_fpm_regs __iomem *fpm_rg = fm->fpm_regs;
+
+ WARN_ON(!fm->fm_state->count1_micro_bit);
+
+ fman_enable_time_stamp(fpm_rg,
+ fm->fm_state->count1_micro_bit,
+ fm->fm_state->fm_clk_freq);
+
+ fm->fm_state->enabled_time_stamp = true;
+}
+
+static int clear_iram(struct fm_t *fm)
+{
+ struct fm_iram_regs_t __iomem *iram;
+ int i;
+
+ iram = (struct fm_iram_regs_t __iomem *)(fm->base_addr + FM_MM_IMEM);
+
+ /* Enable the auto-increment */
+ out_be32(&iram->iadd, IRAM_IADD_AIE);
+ while (in_be32(&iram->iadd) != IRAM_IADD_AIE)
+ ;
+
+ for (i = 0; i < (fm->intg->fm_iram_size / 4); i++)
+ out_be32(&iram->idata, 0xffffffff);
+
+ out_be32(&iram->iadd, fm->intg->fm_iram_size - 4);
+ /* Memory barrier */
+ mb();
+ while (in_be32(&iram->idata) != 0xffffffff)
+ ;
+
+ return 0;
+}
+
+static u32 fm_get_exception_flag(enum fm_exceptions exception)
+{
+ u32 bit_mask;
+
+ switch (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_MURAM_ECC:
+ bit_mask = FM_EX_MURAM_ECC;
+ break;
+ default:
+ bit_mask = 0;
+ break;
+ }
+
+ return bit_mask;
+}
+
+static int fm_get_module_event(enum fm_event_modules module, u8 mod_id,
+ enum fm_intr_type intr_type)
+{
+ int event;
+
+ switch (module) {
+ case FM_MOD_MAC:
+ event = (intr_type == FM_INTR_TYPE_ERR) ?
+ (FM_EV_ERR_MAC0 + mod_id) :
+ (FM_EV_MAC0 + mod_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 + mod_id);
+ break;
+ case FM_MOD_DUMMY_LAST:
+ event = FM_EV_DUMMY_LAST;
+ break;
+ default:
+ event = FM_EV_DUMMY_LAST;
+ break;
+ }
+
+ return event;
+}
+
+void fm_register_intr(struct fm_t *fm, enum fm_event_modules module,
+ u8 mod_id, enum fm_intr_type intr_type,
+ void (*isr_cb)(void *src_arg), void *src_arg)
+{
+ int event = 0;
+
+ event = fm_get_module_event(module, mod_id, intr_type);
+ WARN_ON(!(event < FM_EV_DUMMY_LAST));
+
+ /* register in local FM structure */
+ fm->intr_mng[event].isr_cb = isr_cb;
+ fm->intr_mng[event].src_handle = src_arg;
+}
+
+void fm_unregister_intr(struct fm_t *fm, enum fm_event_modules module,
+ u8 mod_id, enum fm_intr_type intr_type)
+{
+ int event = 0;
+
+ event = fm_get_module_event(module, mod_id, intr_type);
+ WARN_ON(!(event < FM_EV_DUMMY_LAST));
+
+ fm->intr_mng[event].isr_cb = NULL;
+ fm->intr_mng[event].src_handle = NULL;
+}
+
+u8 fm_get_id(struct fm_t *fm)
+{
+ return fm->fm_state->fm_id;
+}
+
+u16 fm_get_clock_freq(struct fm_t *fm)
+{
+ return fm->fm_state->fm_clk_freq;
+}
+
+u32 fm_get_bmi_max_fifo_size(struct fm_t *fm)
+{
+ return fm->intg->bmi_max_fifo_size;
+}
+
+static int init_fm_dma(struct fm_t *fm)
+{
+ int err;
+
+ err = fman_dma_init(fm->dma_regs, fm->fm_drv_param);
+ if (err != 0)
+ return err;
+
+ /* Allocate MURAM for CAM */
+ fm->cam_size = (u32)(fm->fm_drv_param->dma_cam_num_of_entries *
+ DMA_CAM_SIZEOF_ENTRY);
+ fm->cam_offset = fm_muram_alloc(fm->muram, fm->cam_size);
+ if (IS_ERR_VALUE(fm->cam_offset)) {
+ pr_err("MURAM alloc for DMA CAM failed\n");
+ return -ENOMEM;
+ }
+
+ if (fm->fm_state->rev_info.major_rev == 2) {
+ u32 __iomem *cam_base_addr;
+
+ fm_muram_free_mem(fm->muram, fm->cam_offset, fm->cam_size);
+
+ fm->cam_size =
+ fm->fm_drv_param->dma_cam_num_of_entries * 72 + 128;
+ fm->cam_offset = fm_muram_alloc(fm->muram, fm->cam_size);
+ if (IS_ERR_VALUE(fm->cam_offset)) {
+ pr_err("MURAM alloc for DMA CAM failed\n");
+ return -ENOMEM;
+ }
+
+ if (fm->fm_drv_param->dma_cam_num_of_entries % 8 ||
+ fm->fm_drv_param->dma_cam_num_of_entries > 32) {
+ pr_err("wrong dma_cam_num_of_entries\n");
+ return -EINVAL;
+ }
+
+ cam_base_addr = (u32 __iomem *)
+ fm_muram_offset_to_vbase(fm->muram,
+ fm->cam_offset);
+ out_be32(cam_base_addr,
+ ~((1 <<
+ (32 - fm->fm_drv_param->dma_cam_num_of_entries)) - 1));
+ }
+
+ fm->fm_drv_param->cam_base_addr = fm->cam_offset;
+
+ return 0;
+}
+
+void *fm_config(struct fm_params_t *fm_param)
+{
+ struct fm_t *fm;
+ void __iomem *base_addr;
+
+ base_addr = fm_param->base_addr;
+
+ /* Allocate FM structure */
+ fm = kzalloc(sizeof(*fm), GFP_KERNEL);
+ if (!fm)
+ return NULL;
+
+ fm->fm_state = kzalloc(sizeof(*fm->fm_state), GFP_KERNEL);
+ if (!fm->fm_state)
+ goto err_fm_state;
+
+ /* Initialize FM parameters which will be kept by the driver */
+ fm->fm_state->fm_id = fm_param->fm_id;
+
+ /* Allocate the FM driver's parameters structure */
+ fm->fm_drv_param = kzalloc(sizeof(*fm->fm_drv_param), GFP_KERNEL);
+ if (!fm->fm_drv_param)
+ goto err_fm_drv;
+
+ /* Initialize FM parameters which will be kept by the driver */
+ fm->fm_state->fm_id = fm_param->fm_id;
+ fm->muram = fm_param->muram;
+ fm->dev_id = fm_param->dev_id;
+ fm->fm_state->fm_clk_freq = fm_param->fm_clk_freq;
+ fm->exception_cb = fm_param->exception_cb;
+ fm->bus_error_cb = fm_param->bus_error_cb;
+ fm->fpm_regs = (struct fman_fpm_regs __iomem *)(base_addr + FM_MM_FPM);
+ fm->bmi_regs = (struct fman_bmi_regs __iomem *)(base_addr + FM_MM_BMI);
+ fm->qmi_regs = (struct fman_qmi_regs __iomem *)(base_addr + FM_MM_QMI);
+ fm->dma_regs = (struct fman_dma_regs __iomem *)(base_addr + FM_MM_DMA);
+ fm->base_addr = base_addr;
+
+ spin_lock_init(&fm->spinlock);
+ fman_defconfig(fm->fm_drv_param);
+
+ fm->fm_drv_param->qmi_deq_option_support = true;
+
+ fm->fm_state->rams_ecc_enable = false;
+ fm->fm_state->extra_fifo_pool_size = 0;
+ fm->fm_state->exceptions = DFLT_EXCEPTIONS;
+ fm->reset_on_init = DFLT_RESET_ON_INIT;
+
+ /* read revision */
+ /* Chip dependent, will be configured in Init */
+ fman_get_revision(fm->fpm_regs, &fm->fm_state->rev_info.major_rev,
+ &fm->fm_state->rev_info.minor_rev);
+
+ fm->intg = fill_intg_params(fm->fm_state->rev_info.major_rev,
+ fm->fm_state->rev_info.minor_rev);
+ if (!fm->intg)
+ goto err_fm_intg;
+
+ /* FM_AID_MODE_NO_TNUM_SW005 Errata workaround */
+ if (fm->fm_state->rev_info.major_rev >= 6)
+ fm->fm_drv_param->dma_aid_mode = FM_DMA_AID_OUT_PORT_ID;
+
+ fm->fm_drv_param->qmi_def_tnums_thresh =
+ fm->intg->qmi_def_tnums_thresh;
+
+ fm->fm_state->total_fifo_size = 0;
+ fm->fm_state->total_num_of_tasks =
+ DFLT_TOTAL_NUM_OF_TASKS(fm->fm_state->rev_info.major_rev,
+ fm->fm_state->rev_info.minor_rev,
+ fm->intg->bmi_max_num_of_tasks);
+
+ if (fm->fm_state->rev_info.major_rev < 6) {
+ fm->fm_state->max_num_of_open_dmas =
+ fm->intg->bmi_max_num_of_dmas;
+ fm->fm_drv_param->dma_comm_qtsh_clr_emer =
+ (u8)DFLT_DMA_COMM_Q_LOW(fm->fm_state->rev_info.major_rev,
+ fm->intg->dma_thresh_max_commq);
+
+ fm->fm_drv_param->dma_comm_qtsh_asrt_emer =
+ (u8)DFLT_DMA_COMM_Q_HIGH(fm->fm_state->rev_info.major_rev,
+ fm->intg->dma_thresh_max_commq);
+
+ fm->fm_drv_param->dma_cam_num_of_entries =
+ DFLT_DMA_CAM_NUM_OF_ENTRIES(fm->fm_state->rev_info.major_rev);
+
+ fm->fm_drv_param->dma_read_buf_tsh_clr_emer =
+ DFLT_DMA_READ_INT_BUF_LOW(fm->intg->dma_thresh_max_buf);
+
+ fm->fm_drv_param->dma_read_buf_tsh_asrt_emer =
+ DFLT_DMA_READ_INT_BUF_HIGH(fm->intg->dma_thresh_max_buf);
+
+ fm->fm_drv_param->dma_write_buf_tsh_clr_emer =
+ DFLT_DMA_WRITE_INT_BUF_LOW(fm->intg->dma_thresh_max_buf);
+
+ fm->fm_drv_param->dma_write_buf_tsh_asrt_emer =
+ DFLT_DMA_WRITE_INT_BUF_HIGH(fm->intg->dma_thresh_max_buf);
+
+ fm->fm_drv_param->dma_axi_dbg_num_of_beats =
+ DFLT_AXI_DBG_NUM_OF_BEATS;
+ }
+
+ fm->fm_drv_param->tnum_aging_period = 0;
+ fm->tnum_aging_period = fm->fm_drv_param->tnum_aging_period;
+
+ return fm;
+
+err_fm_intg:
+ kfree(fm->fm_drv_param);
+err_fm_drv:
+ kfree(fm->fm_state);
+err_fm_state:
+ kfree(fm);
+ return NULL;
+}
+
+int fm_init(struct fm_t *fm)
+{
+ struct fman_cfg *fm_drv_param = NULL;
+ int err = 0;
+ struct fm_revision_info_t rev_info;
+ struct fman_rg fman_rg;
+
+ if (is_init_done(fm->fm_drv_param))
+ return -EINVAL;
+
+ fman_rg.bmi_rg = fm->bmi_regs;
+ fman_rg.qmi_rg = fm->qmi_regs;
+ fman_rg.fpm_rg = fm->fpm_regs;
+ fman_rg.dma_rg = fm->dma_regs;
+
+ fm->fm_state->count1_micro_bit = FM_TIMESTAMP_1_USEC_BIT;
+ fm->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 (fm->fm_state->total_fifo_size == 0) {
+ fm->fm_state->total_fifo_size =
+ fm_dflt_total_fifo_size(fm->fm_state->rev_info.major_rev,
+ fm->fm_state->rev_info.minor_rev);
+ if (fm->fm_state->total_fifo_size == 0)
+ return -EINVAL;
+ }
+
+ err = check_fm_parameters(fm);
+ if (err)
+ return err;
+
+ fm_drv_param = fm->fm_drv_param;
+
+ fm_get_revision(fm, &rev_info);
+
+ /* clear revision-dependent non existing exception */
+ if (rev_info.major_rev < 6)
+ fm->fm_state->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC;
+
+ if (rev_info.major_rev >= 6)
+ fm->fm_state->exceptions &= ~FM_EX_QMI_SINGLE_ECC;
+
+ /* clear CPG */
+ memset_io((void __iomem *)(fm->base_addr + FM_MM_CGP), 0,
+ fm->intg->fm_port_num_of_cg);
+
+ /* Reset the FM if required. */
+ if (fm->reset_on_init) {
+ if (rev_info.major_rev >= 6) {
+ /* Errata A007273 */
+ pr_debug("FManV3 reset is not supported!\n");
+ } else {
+ out_be32(&fm->fpm_regs->fm_rstc, FPM_RSTC_FM_RESET);
+ /* Memory barrier */
+ mb();
+ usleep_range(100, 300);
+ }
+
+ if (fman_is_qmi_halt_not_busy_state(fm->qmi_regs)) {
+ fman_resume(fm->fpm_regs);
+ usleep_range(100, 300);
+ }
+ }
+
+ if (clear_iram(fm) != 0)
+ return -EINVAL;
+
+ fm_drv_param->exceptions = fm->fm_state->exceptions;
+
+ /* Init DMA Registers */
+
+ err = init_fm_dma(fm);
+ if (err != 0) {
+ free_init_resources(fm);
+ return err;
+ }
+
+ /* Init FPM Registers */
+
+ err = fman_fpm_init(fm->fpm_regs, fm->fm_drv_param);
+ if (err != 0) {
+ free_init_resources(fm);
+ return err;
+ }
+
+ /* define common resources */
+ /* allocate MURAM for FIFO according to total size */
+ fm->fifo_offset = fm_muram_alloc(fm->muram,
+ fm->fm_state->total_fifo_size);
+ if (IS_ERR_VALUE(fm->cam_offset)) {
+ free_init_resources(fm);
+ pr_err("MURAM alloc for BMI FIFO failed\n");
+ return -ENOMEM;
+ }
+
+ fm_drv_param->fifo_base_addr = fm->fifo_offset;
+ fm_drv_param->total_fifo_size = fm->fm_state->total_fifo_size;
+ fm_drv_param->total_num_of_tasks = fm->fm_state->total_num_of_tasks;
+ fm_drv_param->clk_freq = fm->fm_state->fm_clk_freq;
+
+ /* Init BMI Registers */
+ err = fman_bmi_init(fm->bmi_regs, fm->fm_drv_param);
+ if (err != 0) {
+ free_init_resources(fm);
+ return err;
+ }
+
+ /* Init QMI Registers */
+ err = fman_qmi_init(fm->qmi_regs, fm->fm_drv_param);
+ if (err != 0) {
+ free_init_resources(fm);
+ return err;
+ }
+
+ err = fman_enable(&fman_rg, fm_drv_param);
+ if (err != 0)
+ return err;
+
+ enable_time_stamp(fm);
+
+ kfree(fm->fm_drv_param);
+ fm->fm_drv_param = NULL;
+
+ return 0;
+}
+
+int fm_cfg_reset_on_init(struct fm_t *fm, bool enable)
+{
+ if (is_init_done(fm->fm_drv_param))
+ return -EINVAL;
+
+ fm->reset_on_init = enable;
+
+ return 0;
+}
+
+int fm_cfg_total_fifo_size(struct fm_t *fm, u32 total_fifo_size)
+{
+ if (is_init_done(fm->fm_drv_param))
+ return -EINVAL;
+
+ fm->fm_state->total_fifo_size = total_fifo_size;
+
+ return 0;
+}
+
+void fm_event_isr(struct fm_t *fm)
+{
+ u32 pending;
+ struct fman_fpm_regs __iomem *fpm_rg;
+
+ if (!is_init_done(fm->fm_drv_param))
+ return;
+
+ fpm_rg = fm->fpm_regs;
+
+ /* normal interrupts */
+ pending = fman_get_normal_pending(fpm_rg);
+ if (!pending)
+ return;
+
+ if (pending & INTR_EN_QMI)
+ qmi_event(fm);
+
+ /* MAC interrupts */
+ if (pending & INTR_EN_MAC0)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 0);
+ if (pending & INTR_EN_MAC1)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 1);
+ if (pending & INTR_EN_MAC2)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 2);
+ if (pending & INTR_EN_MAC3)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 3);
+ if (pending & INTR_EN_MAC4)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 4);
+ if (pending & INTR_EN_MAC5)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 5);
+ if (pending & INTR_EN_MAC6)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 6);
+ if (pending & INTR_EN_MAC7)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 7);
+ if (pending & INTR_EN_MAC8)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 8);
+ if (pending & INTR_EN_MAC9)
+ fm_call_mac_isr(fm, FM_EV_MAC0 + 9);
+}
+
+int fm_error_isr(struct fm_t *fm)
+{
+ u32 pending;
+ struct fman_fpm_regs __iomem *fpm_rg;
+
+ if (!is_init_done(fm->fm_drv_param))
+ return -EINVAL;
+
+ fpm_rg = 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(fm);
+ if (pending & ERR_INTR_EN_QMI)
+ qmi_err_event(fm);
+ if (pending & ERR_INTR_EN_FPM)
+ fpm_err_event(fm);
+ if (pending & ERR_INTR_EN_DMA)
+ dma_err_event(fm);
+ if (pending & ERR_INTR_EN_MURAM)
+ muram_err_intr(fm);
+
+ /* MAC error interrupts */
+ if (pending & ERR_INTR_EN_MAC0)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 0);
+ if (pending & ERR_INTR_EN_MAC1)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 1);
+ if (pending & ERR_INTR_EN_MAC2)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 2);
+ if (pending & ERR_INTR_EN_MAC3)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 3);
+ if (pending & ERR_INTR_EN_MAC4)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 4);
+ if (pending & ERR_INTR_EN_MAC5)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 5);
+ if (pending & ERR_INTR_EN_MAC6)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 6);
+ if (pending & ERR_INTR_EN_MAC7)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 7);
+ if (pending & ERR_INTR_EN_MAC8)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 8);
+ if (pending & ERR_INTR_EN_MAC9)
+ fm_call_mac_isr(fm, FM_EV_ERR_MAC0 + 9);
+
+ return 0;
+}
+
+int fm_disable_rams_ecc(struct fm_t *fm)
+{
+ bool explicit_disable = false;
+ struct fman_fpm_regs __iomem *fpm_rg;
+ int ret;
+
+ if (!is_init_done(fm->fm_drv_param))
+ return ret;
+
+ fpm_rg = fm->fpm_regs;
+
+ if (!fm->fm_state->internal_call)
+ explicit_disable = true;
+ fm->fm_state->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 (!fm->fm_state->rams_ecc_enable ||
+ (fm->fm_state->explicit_enable && !explicit_disable))
+ return 0;
+ if (fm->fm_state->explicit_enable)
+ /* This is the case were both explicit are true.
+ * Turn off this flag for cases were following
+ * ramsEnable routines are called
+ */
+ fm->fm_state->explicit_enable = false;
+
+ fman_enable_rams_ecc(fpm_rg);
+ fm->fm_state->rams_ecc_enable = false;
+
+ return 0;
+}
+
+int fm_set_exception(struct fm_t *fm, enum fm_exceptions exception,
+ bool enable)
+{
+ u32 bit_mask = 0;
+ struct fman_rg fman_rg;
+
+ if (!is_init_done(fm->fm_drv_param))
+ return -EINVAL;
+
+ fman_rg.bmi_rg = fm->bmi_regs;
+ fman_rg.qmi_rg = fm->qmi_regs;
+ fman_rg.fpm_rg = fm->fpm_regs;
+ fman_rg.dma_rg = fm->dma_regs;
+
+ bit_mask = fm_get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ fm->fm_state->exceptions |= bit_mask;
+ else
+ fm->fm_state->exceptions &= ~bit_mask;
+
+ return fman_set_exception(&fman_rg,
+ (enum fman_exceptions)exception,
+ enable);
+ } else {
+ pr_err("Undefined exception\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void fm_get_revision(struct fm_t *fm,
+ struct fm_revision_info_t *fm_rev)
+{
+ fm_rev->major_rev = fm->fm_state->rev_info.major_rev;
+ fm_rev->minor_rev = fm->fm_state->rev_info.minor_rev;
+}
diff --git a/drivers/net/ethernet/freescale/fman/fm.h b/drivers/net/ethernet/freescale/fman/fm.h
new file mode 100644
index 0000000..d7eca90
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_H
+#define __FM_H
+
+#include "fm_ext.h"
+
+#include "fsl_fman.h"
+
+#include <linux/io.h>
+
+/* 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
+
+/* 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_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
+
+#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 DMA_COMM_Q_LOW_FMAN_V3 0x2A
+#define DMA_COMM_Q_LOW_FMAN_V2(dma_thresh_max_commq) \
+ ((dma_thresh_max_commq + 1) / 2)
+#define DFLT_DMA_COMM_Q_LOW(major, dma_thresh_max_commq) \
+ ((major == 6) ? DMA_COMM_Q_LOW_FMAN_V3 : \
+ DMA_COMM_Q_LOW_FMAN_V2(dma_thresh_max_commq))
+
+#define DMA_COMM_Q_HIGH_FMAN_V3 0x3f
+#define DMA_COMM_Q_HIGH_FMAN_V2(dma_thresh_max_commq) \
+ ((dma_thresh_max_commq + 1) * 3 / 4)
+#define DFLT_DMA_COMM_Q_HIGH(major, dma_thresh_max_commq) \
+ ((major == 6) ? DMA_COMM_Q_HIGH_FMAN_V3 : \
+ DMA_COMM_Q_HIGH_FMAN_V2(dma_thresh_max_commq))
+
+#define TOTAL_NUM_OF_TASKS_FMAN_V3L 59
+#define TOTAL_NUM_OF_TASKS_FMAN_V3H 124
+#define DFLT_TOTAL_NUM_OF_TASKS(major, minor, bmi_max_num_of_tasks) \
+ ((major == 6) ? ((minor == 1 || minor == 4) ? \
+ TOTAL_NUM_OF_TASKS_FMAN_V3L : TOTAL_NUM_OF_TASKS_FMAN_V3H) : \
+ bmi_max_num_of_tasks)
+
+#define DMA_CAM_NUM_OF_ENTRIES_FMAN_V3 64
+#define DMA_CAM_NUM_OF_ENTRIES_FMAN_V2 32
+#define DFLT_DMA_CAM_NUM_OF_ENTRIES(major) \
+ (major == 6 ? DMA_CAM_NUM_OF_ENTRIES_FMAN_V3 : \
+ DMA_CAM_NUM_OF_ENTRIES_FMAN_V2)
+
+#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_MURAM 0x00040000
+#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 ERR_INTR_EN_MAC8 0x00008000
+#define ERR_INTR_EN_MAC9 0x00000040
+
+#define INTR_EN_QMI 0x40000000
+#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_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 {
+ u32 iadd; /* FM IRAM instruction address register */
+ u32 idata;/* FM IRAM instruction data register */
+ u32 itcfg;/* FM IRAM timing config register */
+ u32 iready;/* FM IRAM ready register */
+};
+
+/* General defines */
+#define FM_FW_DEBUG_INSTRUCTION 0x6ffff805UL
+
+struct fm_state_struct_t {
+ u8 fm_id;
+ u16 fm_clk_freq;
+ struct fm_revision_info_t rev_info;
+ bool enabled_time_stamp;
+ u8 count1_micro_bit;
+ u8 total_num_of_tasks;
+ u32 total_fifo_size;
+ u8 max_num_of_open_dmas;
+ u8 accumulated_num_of_tasks;
+ u32 accumulated_fifo_size;
+ u8 accumulated_num_of_open_dmas;
+ u8 accumulated_num_of_deq_tnums;
+ bool low_end_restriction;
+ u32 exceptions;
+ bool rams_ecc_enable;
+ bool explicit_enable;
+ bool internal_call;
+ u32 extra_fifo_pool_size;
+ u8 extra_tasks_pool_size;
+ u8 extra_open_dmas_pool_size;
+};
+
+struct fm_intg_t {
+ /* Ram defines */
+ u32 fm_muram_size;
+ u32 fm_iram_size;
+ u32 fm_num_of_ctrl;
+
+ /* DMA defines */
+ u32 dma_thresh_max_commq;
+ u32 dma_thresh_max_buf;
+
+ /* QMI defines */
+ u32 qmi_max_num_of_tnums;
+ u32 qmi_def_tnums_thresh;
+
+ /* BMI defines */
+ u32 bmi_max_num_of_tasks;
+ u32 bmi_max_num_of_dmas;
+ u32 bmi_max_fifo_size;
+ u32 port_max_weight;
+
+ u32 fm_port_num_of_cg;
+ u32 num_of_rx_ports;
+};
+
+struct fm_t {
+ void __iomem *base_addr;
+ char fm_module_name[MODULE_NAME_SIZE];
+ struct fm_intr_src_t intr_mng[FM_EV_DUMMY_LAST];
+
+ struct fman_fpm_regs __iomem *fpm_regs;
+ struct fman_bmi_regs __iomem *bmi_regs;
+ struct fman_qmi_regs __iomem *qmi_regs;
+ struct fman_dma_regs __iomem *dma_regs;
+ fm_exceptions_cb *exception_cb;
+ fm_bus_error_cb *bus_error_cb;
+ void *dev_id;
+ /* Spinlock for FMan use */
+ spinlock_t spinlock;
+ struct fm_state_struct_t *fm_state;
+ u16 tnum_aging_period;
+
+ struct fman_cfg *fm_drv_param;
+ struct muram_info *muram;
+ /* cam section in muram */
+ int cam_offset;
+ size_t cam_size;
+ /* Fifo in MURAM */
+ int fifo_offset;
+ size_t fifo_size;
+ bool reset_on_init;
+
+ struct fm_intg_t *intg;
+};
+
+static inline int fm_dflt_total_fifo_size(u8 major, u8 minor)
+{
+ /* The total FIFO size values are calculation for each FMan version,
+ * taking into account the available resources.
+ */
+ switch (major) {
+ case 2:
+ /* P4080 */
+ return 100 * 1024;
+ case 3:
+ /* P2, P3, P5 */
+ return 122 * 1024;
+ case 4:
+ /* P1023 */
+ return 46 * 1024;
+ case 6:
+ /* FMan V3L (T1024, T1040) */
+ if (minor == 1 || minor == 4)
+ return 156 * 1024;
+ /* FMan V3H (B4, T4, T2080) */
+ else
+ return 295 * 1024;
+ default:
+ pr_err("Default total fifo size calculation failed\n");
+ return 0;
+ }
+}
+
+static inline void fm_call_mac_isr(struct fm_t *fm, u8 id)
+{
+ if (fm->intr_mng[id].isr_cb)
+ fm->intr_mng[id].isr_cb(fm->intr_mng[id].src_handle);
+}
+
+#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..1cde270
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __FM_COMMON_H
+#define __FM_COMMON_H
+
+#include "fm_ext.h"
+
+/* Enum for inter-module interrupts registration */
+enum fm_event_modules {
+ FM_MOD_MAC = 0, /* MAC event */
+ FM_MOD_FMAN_CTRL, /* FMAN Controller */
+ 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_ERR_MAC0 = 0, /* 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_ERR_MAC8, /* MAC 8 error event */
+ FM_EV_ERR_MAC9, /* MAC 9 error event */
+ 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_MAC8, /* MAC 8 event (Magic packet detection) */
+ FM_EV_MAC9, /* MAC 9 event (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_P2_P3_P5 3
+#define FM_IP_BLOCK_P4 2
+#define FM_IP_BLOCK_B_T 6
+
+#define MODULE_NAME_SIZE 30
+#define DUMMY_PORT_ID 0
+
+#define FM_LIODN_OFFSET_MASK 0x3FF
+
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define BMI_FIFO_UNITS 0x100
+
+struct fm_intr_src_t {
+ void (*isr_cb)(void *src_arg);
+ void *src_handle;
+};
+
+void fm_register_intr(struct fm_t *fm, enum fm_event_modules mod, u8 mod_id,
+ enum fm_intr_type intr_type,
+ void (*f_isr)(void *h_src_arg), void *h_src_arg);
+
+void fm_unregister_intr(struct fm_t *fm, enum fm_event_modules mod, u8 mod_id,
+ enum fm_intr_type intr_type);
+
+struct muram_info *fm_get_muram_pointer(struct fm_t *fm);
+
+int fm_reset_mac(struct fm_t *fm, u8 mac_id);
+
+u16 fm_get_clock_freq(struct fm_t *fm);
+
+u8 fm_get_id(struct fm_t *fm);
+
+u32 fm_get_bmi_max_fifo_size(struct fm_t *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..63b5ae1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/errno.h>
+#include <sysdev/fsl_soc.h>
+
+#include "fm_ext.h"
+#include "fm_drv.h"
+#include "fm_muram_ext.h"
+
+/* Bootargs defines */
+/* Extra headroom for RX buffers - Default, min and max */
+#define FSL_FM_RX_EXTRA_HEADROOM 64
+#define FSL_FM_RX_EXTRA_HEADROOM_MIN 16
+#define FSL_FM_RX_EXTRA_HEADROOM_MAX 384
+
+/* Maximum frame length */
+#define FSL_FM_MAX_FRAME_SIZE 1522
+#define FSL_FM_MAX_POSSIBLE_FRAME_SIZE 9600
+#define FSL_FM_MIN_POSSIBLE_FRAME_SIZE 64
+
+/* 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 bootargs. 64 by default, it's needed on
+ * particular forwarding scenarios that add extra headers to the
+ * forwarded frame.
+ */
+int fsl_fm_rx_extra_headroom = FSL_FM_RX_EXTRA_HEADROOM;
+module_param(fsl_fm_rx_extra_headroom, int, 0);
+MODULE_PARM_DESC(fsl_fm_rx_extra_headroom, "Extra headroom for Rx buffers");
+
+/* Max frame size, across all interfaces.
+ * Configurable from 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 = FSL_FM_MAX_FRAME_SIZE;
+module_param(fsl_fm_max_frm, int, 0);
+MODULE_PARM_DESC(fsl_fm_max_frm, "Maximum frame size, across all interfaces");
+
+u16 fm_get_max_frm(void)
+{
+ static bool fm_check_mfl;
+
+ if (!fm_check_mfl) {
+ if (fsl_fm_max_frm > FSL_FM_MAX_POSSIBLE_FRAME_SIZE ||
+ fsl_fm_max_frm < FSL_FM_MIN_POSSIBLE_FRAME_SIZE) {
+ pr_warn("Invalid fsl_fm_max_frm value (%d) in bootargs, valid range is %d-%d. Falling back to the default (%d)\n",
+ fsl_fm_max_frm,
+ FSL_FM_MIN_POSSIBLE_FRAME_SIZE,
+ FSL_FM_MAX_POSSIBLE_FRAME_SIZE,
+ FSL_FM_MAX_FRAME_SIZE);
+ fsl_fm_max_frm = FSL_FM_MAX_FRAME_SIZE;
+ }
+ fm_check_mfl = true;
+ }
+
+ return fsl_fm_max_frm;
+}
+EXPORT_SYMBOL(fm_get_max_frm);
+
+int fm_get_rx_extra_headroom(void)
+{
+ static bool fm_check_rx_extra_headroom;
+
+ if (!fm_check_rx_extra_headroom) {
+ if (fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX ||
+ fsl_fm_rx_extra_headroom < FSL_FM_RX_EXTRA_HEADROOM_MIN) {
+ pr_warn("Invalid fsl_fm_rx_extra_headroom value (%d) in bootargs, valid range is %d-%d. Falling back to the default (%d)\n",
+ fsl_fm_rx_extra_headroom,
+ FSL_FM_RX_EXTRA_HEADROOM_MIN,
+ FSL_FM_RX_EXTRA_HEADROOM_MAX,
+ FSL_FM_RX_EXTRA_HEADROOM);
+ fsl_fm_rx_extra_headroom = FSL_FM_RX_EXTRA_HEADROOM;
+ }
+
+ fsl_fm_rx_extra_headroom = true;
+ fsl_fm_rx_extra_headroom = ALIGN(fsl_fm_rx_extra_headroom, 16);
+ }
+
+ return fsl_fm_rx_extra_headroom;
+}
+EXPORT_SYMBOL(fm_get_rx_extra_headroom);
+
+static irqreturn_t fm_irq(int irq, void *fm_dev)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm_dev;
+
+ fm_event_isr(fm_drv->fm_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fm_err_irq(int irq, void *fm_dev)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm_dev;
+
+ if (fm_error_isr(fm_drv->fm_dev) == 0)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+static int fill_qman_channels_info(struct fm_drv_t *fm_drv)
+{
+ fm_drv->qman_channels = kcalloc(fm_drv->num_of_qman_channels,
+ sizeof(u32), GFP_KERNEL);
+ if (!fm_drv->qman_channels)
+ return -ENOMEM;
+
+ if (fm_drv->fm_rev_info.major_rev >= 6) {
+ fm_drv->qman_channels[0] = 0x30;
+ fm_drv->qman_channels[1] = 0x31;
+ fm_drv->qman_channels[2] = 0x28;
+ fm_drv->qman_channels[3] = 0x29;
+ fm_drv->qman_channels[4] = 0x2a;
+ fm_drv->qman_channels[5] = 0x2b;
+ fm_drv->qman_channels[6] = 0x2c;
+ fm_drv->qman_channels[7] = 0x2d;
+ fm_drv->qman_channels[8] = 0x2;
+ fm_drv->qman_channels[9] = 0x3;
+ fm_drv->qman_channels[10] = 0x4;
+ fm_drv->qman_channels[11] = 0x5;
+ fm_drv->qman_channels[12] = 0x6;
+ fm_drv->qman_channels[13] = 0x7;
+ } else {
+ fm_drv->qman_channels[0] = 0x30;
+ fm_drv->qman_channels[1] = 0x28;
+ fm_drv->qman_channels[2] = 0x29;
+ fm_drv->qman_channels[3] = 0x2a;
+ fm_drv->qman_channels[4] = 0x2b;
+ fm_drv->qman_channels[5] = 0x2c;
+ fm_drv->qman_channels[6] = 0x1;
+ fm_drv->qman_channels[7] = 0x2;
+ fm_drv->qman_channels[8] = 0x3;
+ fm_drv->qman_channels[9] = 0x4;
+ fm_drv->qman_channels[10] = 0x5;
+ fm_drv->qman_channels[11] = 0x6;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id fm_muram_match[] = {
+ {
+ .compatible = "fsl,fman-muram"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, fm_muram_match);
+
+static struct fm_drv_t *read_fm_dev_tree_node(struct platform_device *of_dev)
+{
+ struct fm_drv_t *fm_drv;
+ struct device_node *fm_node, *muram_node;
+ struct resource *res;
+ const u32 *u32_prop;
+ int lenp, err;
+ struct clk *clk;
+ u32 clk_rate;
+
+ fm_node = of_node_get(of_dev->dev.of_node);
+
+ u32_prop = (const u32 *)of_get_property(fm_node, "cell-index", &lenp);
+ if (!u32_prop) {
+ pr_err("of_get_property(%s, cell-index) failed\n",
+ fm_node->full_name);
+ goto _return_null;
+ }
+ if (WARN_ON(lenp != sizeof(u32)))
+ return NULL;
+
+ fm_drv = kzalloc(sizeof(*fm_drv), GFP_KERNEL);
+ if (!fm_drv)
+ goto _return_null;
+
+ fm_drv->dev = &of_dev->dev;
+ fm_drv->id = (u8)*u32_prop;
+
+ /* Get the FM interrupt */
+ res = platform_get_resource(of_dev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("Can't get FMan IRQ resource\n");
+ goto _return_null;
+ }
+ fm_drv->irq = res->start;
+
+ /* Get the FM error interrupt */
+ res = platform_get_resource(of_dev, IORESOURCE_IRQ, 1);
+ if (!res) {
+ pr_err("Can't get FMan Error IRQ resource\n");
+ goto _return_null;
+ }
+ fm_drv->err_irq = res->start;
+
+ /* Get the FM address */
+ res = platform_get_resource(of_dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("Can't get FMan memory resouce\n");
+ goto _return_null;
+ }
+
+ fm_drv->fm_base_addr = 0;
+ fm_drv->fm_phys_base_addr = res->start;
+ fm_drv->fm_mem_size = res->end + 1 - res->start;
+
+ clk = of_clk_get_by_name(fm_node, NULL);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to get FM%d clock structure\n", fm_drv->id);
+ goto _return_null;
+ }
+
+ clk_rate = clk_get_rate(clk);
+ if (!clk_rate) {
+ pr_err("Failed to determine FM%d clock rate\n", fm_drv->id);
+ goto _return_null;
+ }
+ /* Rounding to MHz */
+ clk_rate = (clk_rate + 500000) / 1000000;
+ fm_drv->params.fm_clk_freq = (u16)clk_rate;
+
+ u32_prop = (const u32 *)of_get_property(fm_node,
+ "fsl,qman-channel-range",
+ &lenp);
+ if (!u32_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(u32) * 2))
+ goto _return_null;
+ fm_drv->qman_channel_base = u32_prop[0];
+ fm_drv->num_of_qman_channels = u32_prop[1];
+
+ /* Get the MURAM base address and size */
+ muram_node = of_find_matching_node(fm_node, fm_muram_match);
+ if (!muram_node) {
+ pr_err("could not find MURAM node\n");
+ goto _return_null;
+ }
+
+ err = of_address_to_resource(muram_node, 0, res);
+ if (err) {
+ of_node_put(muram_node);
+ pr_err("of_address_to_resource() = %d\n", err);
+ goto _return_null;
+ }
+
+ fm_drv->fm_muram_phys_base_addr = res->start;
+ fm_drv->fm_muram_mem_size = res->end + 1 - res->start;
+
+ {
+ /* In B4 rev 2.0 (and above) the MURAM size is 512KB.
+ * Check the SVR and update MURAM size if required.
+ */
+ u32 svr;
+
+ svr = mfspr(SPRN_SVR);
+
+ if ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_MAJ(svr) >= 2))
+ fm_drv->fm_muram_mem_size = 0x80000;
+ }
+
+ of_node_put(muram_node);
+ of_node_put(fm_node);
+
+ fm_drv->active = true;
+
+ goto _return;
+
+_return_null:
+ of_node_put(fm_node);
+ return NULL;
+_return:
+ return fm_drv;
+}
+
+static void fm_drv_exceptions_cb(void *dev_id,
+ enum fm_exceptions __maybe_unused exception)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)dev_id;
+
+ WARN_ON(!fm_drv);
+
+ pr_debug("got fm exception %d\n", exception);
+}
+
+static void fm_drv_bus_error_cb(void *dev_id,
+ enum fm_port_type __maybe_unused port_type,
+ u8 __maybe_unused port_id,
+ u64 __maybe_unused addr,
+ u8 __maybe_unused tnum,
+ u16 __maybe_unused liodn)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)dev_id;
+
+ WARN_ON(!fm_drv);
+
+ pr_debug("got fm bus error: port_id[%d]\n", port_id);
+}
+
+u32 get_qman_channel_id(struct fm_drv_t *fm_drv, u32 port_id)
+{
+ u32 qman_channel = 0;
+ int i;
+
+ for (i = 0; i < fm_drv->num_of_qman_channels; i++) {
+ if (fm_drv->qman_channels[i] == port_id)
+ break;
+ }
+
+ if (i == fm_drv->num_of_qman_channels)
+ return 0;
+
+ qman_channel = fm_drv->qman_channel_base + i;
+
+ return qman_channel;
+}
+
+static int configure_fm_dev(struct fm_drv_t *fm_drv)
+{
+ int err;
+
+ if (!fm_drv->active) {
+ pr_err("FMan not configured\n");
+ return -EINVAL;
+ }
+
+ err = devm_request_irq(fm_drv->dev, fm_drv->irq, fm_irq,
+ IRQF_NO_SUSPEND, "fman", fm_drv);
+ if (err < 0) {
+ pr_err("Error: allocating irq %d (error = %d)\n",
+ fm_drv->irq, err);
+ return -EINVAL;
+ }
+
+ if (fm_drv->err_irq != 0) {
+ err = devm_request_irq(fm_drv->dev, fm_drv->err_irq,
+ fm_err_irq,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "fman-err", fm_drv);
+ if (err < 0) {
+ pr_err("Error: allocating irq %d (error = %d)\n",
+ fm_drv->err_irq, err);
+ return -EINVAL;
+ }
+ }
+
+ fm_drv->res = devm_request_mem_region(fm_drv->dev,
+ fm_drv->fm_phys_base_addr,
+ fm_drv->fm_mem_size, "fman");
+ if (!fm_drv->res) {
+ pr_err("request_mem_region() failed\n");
+ return -EINVAL;
+ }
+
+ fm_drv->fm_base_addr = devm_ioremap(fm_drv->dev,
+ fm_drv->fm_phys_base_addr,
+ fm_drv->fm_mem_size);
+ if (fm_drv->fm_base_addr == 0) {
+ pr_err("devm_ioremap() failed\n");
+ return -EINVAL;
+ }
+
+ fm_drv->params.base_addr = fm_drv->fm_base_addr;
+ fm_drv->params.fm_id = fm_drv->id;
+ fm_drv->params.exception_cb = fm_drv_exceptions_cb;
+ fm_drv->params.bus_error_cb = fm_drv_bus_error_cb;
+ fm_drv->params.dev_id = fm_drv;
+
+ return 0;
+}
+
+static int init_fm_dev(struct fm_drv_t *fm_drv)
+{
+ if (!fm_drv->active) {
+ pr_err("FMan not configured\n");
+ return -EINVAL;
+ }
+
+ fm_drv->muram = fm_muram_init(fm_drv->fm_muram_phys_base_addr,
+ fm_drv->fm_muram_mem_size);
+ if (!fm_drv->muram) {
+ pr_err("FMan MURAM initalization failed\n");
+ return -EINVAL;
+ }
+
+ fm_drv->params.muram = fm_drv->muram;
+
+ fm_drv->fm_dev = fm_config(&fm_drv->params);
+ if (!fm_drv->fm_dev) {
+ pr_err("FMan config failed\n");
+ return -EINVAL;
+ }
+
+ fm_get_revision(fm_drv->fm_dev, &fm_drv->fm_rev_info);
+
+ if (fm_cfg_reset_on_init(fm_drv->fm_dev, true) != 0) {
+ pr_err("fm_cfg_reset_on_init() failed\n");
+ return -EINVAL;
+ }
+
+ /* Config total fifo size for FManV3H */
+ if ((fm_drv->fm_rev_info.major_rev >= 6) &&
+ (fm_drv->fm_rev_info.minor_rev != 1 &&
+ fm_drv->fm_rev_info.minor_rev != 4))
+ fm_cfg_total_fifo_size(fm_drv->fm_dev, 295 * 1024);
+
+ if (fm_init(fm_drv->fm_dev) != 0) {
+ pr_err("fm_init() failed\n");
+ return -EINVAL;
+ }
+
+ if (fm_drv->err_irq == 0) {
+ fm_set_exception(fm_drv->fm_dev, FM_EX_DMA_BUS_ERROR, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_DMA_READ_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_DMA_SYSTEM_WRITE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_DMA_FM_WRITE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_DMA_SINGLE_PORT_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_FPM_STALL_ON_TASKS, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_FPM_SINGLE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_FPM_DOUBLE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_QMI_SINGLE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_QMI_DOUBLE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID, false);
+ fm_set_exception(fm_drv->fm_dev, FM_EX_BMI_LIST_RAM_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_BMI_STORAGE_PROFILE_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_BMI_STATISTICS_RAM_ECC, false);
+ fm_set_exception(fm_drv->fm_dev,
+ FM_EX_BMI_DISPATCH_RAM_ECC, false);
+ }
+
+ if (fill_qman_channels_info(fm_drv) < 0) {
+ pr_err("can't fill qman channel info\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fm_probe(struct platform_device *of_dev)
+{
+ struct fm_drv_t *fm_drv;
+
+ fm_drv = read_fm_dev_tree_node(of_dev);
+ if (!fm_drv)
+ return -EIO;
+ if (configure_fm_dev(fm_drv) != 0)
+ return -EIO;
+ if (init_fm_dev(fm_drv) != 0)
+ return -EIO;
+
+ dev_set_drvdata(fm_drv->dev, fm_drv);
+
+ pr_debug("FM%d probed\n", fm_drv->id);
+
+ return 0;
+}
+
+struct fm *fm_bind(struct device *fm_dev)
+{
+ return (struct fm *)(dev_get_drvdata(get_device(fm_dev)));
+}
+
+void fm_unbind(struct fm *fm)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+ put_device(fm_drv->dev);
+}
+
+struct resource *fm_get_mem_region(struct fm *fm)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+ return fm_drv->res;
+}
+
+void *fm_get_handle(struct fm *fm)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)fm;
+
+ return (void *)fm_drv->fm_dev;
+}
+
+static const struct of_device_id fm_match[] = {
+ {
+ .compatible = "fsl,fman"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, fm_match);
+
+static struct platform_driver fm_driver = {
+ .driver = {
+ .name = "fsl-fman",
+ .of_match_table = fm_match,
+ },
+ .probe = fm_probe,
+};
+
+builtin_platform_driver(fm_driver);
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..73d9eff
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_DRV_H__
+#define __FM_DRV_H__
+
+#include <asm/mpc85xx.h>
+
+#include "fsl_fman_drv.h"
+
+#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE
+#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0
+#endif
+
+#ifndef CONFIG_FSL_FM_RX_EXTRA_HEADROOM
+#define CONFIG_FSL_FM_RX_EXTRA_HEADROOM 16
+#endif
+
+/* SoC info */
+#define SOC_VERSION(svr) (((svr) & 0xFFF7FF00) >> 8)
+#define SOC_MAJOR_REV(svr) (((svr) & 0x000000F0) >> 4)
+#define SOC_MINOR_REV(svr) ((svr) & 0x0000000F)
+
+/* Port defines */
+#define NUM_OF_FM_PORTS 63
+#define FIRST_RX_PORT 0x08
+#define FIRST_TX_PORT 0x28
+#define LAST_RX_PORT 0x11
+#define LAST_TX_PORT 0x31
+
+#define TX_10G_PORT_BASE 0x30
+#define RX_10G_PORT_BASE 0x10
+
+struct fm_port_t;
+
+struct fm_port_drv_t {
+ u8 id;
+ char name[20];
+ bool active;
+ phys_addr_t phys_base_addr;
+ void __iomem *base_addr; /* Port's *virtual* address */
+ resource_size_t mem_size;
+ struct fm_buffer_prefix_content_t buff_prefix_content;
+ struct fm_port_t *fm_port;
+ struct fm_drv_t *fm;
+ u16 tx_ch;
+ struct device *dev;
+ struct fm_revision_info_t fm_rev_info;
+};
+
+struct fm_drv_t {
+ u8 id;
+ char name[10];
+ bool active;
+ phys_addr_t fm_phys_base_addr;
+ void __iomem *fm_base_addr;
+ resource_size_t fm_mem_size;
+ phys_addr_t fm_muram_phys_base_addr;
+ resource_size_t fm_muram_mem_size;
+ int irq;
+ int err_irq;
+ struct fm_params_t params;
+ void *fm_dev;
+ struct muram_info *muram;
+
+ struct fm_port_drv_t ports[NUM_OF_FM_PORTS];
+
+ struct device *dev;
+ struct resource *res;
+
+ struct fm_revision_info_t fm_rev_info;
+ u32 qman_channel_base;
+ u32 num_of_qman_channels;
+ u32 *qman_channels;
+
+};
+
+u32 get_qman_channel_id(struct fm_drv_t *fm_drv, u32 port_id);
+
+#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..e7d5c05
--- /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 u8 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) \
+ (u64)(((u64)(_enet_addr)[0] << 40) | \
+ ((u64)(_enet_addr)[1] << 32) | \
+ ((u64)(_enet_addr)[2] << 24) | \
+ ((u64)(_enet_addr)[3] << 16) | \
+ ((u64)(_enet_addr)[4] << 8) | \
+ ((u64)(_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] = \
+ (u8)((_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..607f331
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_ext.h
@@ -0,0 +1,446 @@
+/*
+ * 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 "fsl_fman_sp.h"
+
+/* Enum for defining port types */
+enum fm_port_type {
+ FM_PORT_TYPE_TX = 0, /* 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_DUMMY
+};
+
+/* 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
+
+/* Parse results memory layout */
+struct fm_prs_result_t {
+ u8 lpid; /* Logical port id */
+ u8 shimr; /* Shim header result */
+ u16 l2r; /* Layer 2 result */
+ u16 l3r; /* Layer 3 result */
+ u8 l4r; /* Layer 4 result */
+ u8 cplan; /* Classification plan id */
+ u16 nxthdr; /* Next Header */
+ u16 cksum; /* Running-sum */
+ /* Flags&fragment-offset field of the last IP-header */
+ u16 flags_frag_off;
+ /* Routing type field of a IPV6 routing extension header */
+ u8 route_type;
+ /* Routing Extension Header Present; last bit is IP valid */
+ u8 rhp_ip_valid;
+ u8 shim_off[2]; /* Shim offset */
+ u8 ip_pid_off; /* IP PID (last IP-proto) offset */
+ u8 eth_off; /* ETH offset */
+ u8 llc_snap_off; /* LLC_SNAP offset */
+ u8 vlan_off[2]; /* VLAN offset */
+ u8 etype_off; /* ETYPE offset */
+ u8 pppoe_off; /* PPP offset */
+ u8 mpls_off[2]; /* MPLS offset */
+ u8 ip_off[2]; /* IP offset */
+ u8 gre_off; /* GRE offset */
+ u8 l4_off; /* Layer 4 offset */
+ u8 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_MURAM_ECC /* Double bit ECC occurred on MURAM */
+};
+
+/** fm_exceptions_cb
+ * dev_id - Pointer to the device
+ * exception - The exception.
+ *
+ * Exceptions user callback routine, will be called upon an exception
+ * passing the exception identification.
+ */
+typedef void (fm_exceptions_cb)(void *dev_id,
+ enum fm_exceptions exception);
+
+/** fm_bus_error_cb
+ * dev_id - Pointer to the device
+ * port_type - Port type (enum fm_port_type)
+ * port_id - Port id
+ * addr - Address that caused the error
+ * tnum - Owner of error
+ * liodn - Logical IO device number
+ *
+ * Bus error user callback routine, will be called upon bus error,
+ * passing parameters describing the errors and the owner.
+ */
+typedef void (fm_bus_error_cb)(void *dev_id, enum fm_port_type port_type,
+ u8 port_id, u64 addr, u8 tnum, u16 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.
+ */
+ u16 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 */
+ 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.
+ */
+ u16 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 {
+ u8 id; /* External buffer pool id */
+ u16 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 {
+ u8 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.
+ */
+ u8 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.
+ */
+ u8 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.
+ */
+ u8 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 FM initialization parameters */
+struct fm_params_t {
+ u8 fm_id;
+ /* Index of the FM */
+ void __iomem *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 *muram;
+ /* A pointer to an initialized MURAM object, to be used by the FM. */
+ u16 fm_clk_freq;
+ /* In Mhz; */
+ fm_exceptions_cb *exception_cb;
+ /* An application callback routine to handle exceptions; */
+ fm_bus_error_cb *bus_error_cb;
+ /* An application callback routine to handle exceptions; */
+ void *dev_id;
+ /* Device cookie used by the exception cbs */
+};
+
+struct fm_t; /* FMan data */
+
+/**
+ * fm_config
+ * @fm_params A pointer to a data structure of mandatory FM
+ * parameters
+ *
+ * Creates the FM module and returns its handle (descriptor).
+ * This descriptor must be passed as first parameter to all other
+ * FM function calls.
+ * No actual initialization or configuration of FM hardware is
+ * done by this routine. All FM parameters get default values that
+ * may be changed by calling one or more of the advance config
+ * routines.
+ *
+ * Return: A handle to the FM object, or NULL for Failure.
+ */
+void *fm_config(struct fm_params_t *fm_params);
+
+/**
+ * fm_init
+ * @fm Pointer to the FMan module
+ *
+ * Initializes the FM module by defining the software structure
+ * and configuring the hardware registers.
+ *
+ * Return 0 on success; Error code otherwise.
+ */
+int fm_init(struct fm_t *fm);
+
+/**
+ * fm_free
+ * @fm Pointer to the FMan module
+ *
+ * Frees all resources that were assigned to FM module.
+ * Calling this routine invalidates the descriptor.
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_free(struct fm_t *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
+ * @fm Pointer to the FMan module
+ * @enable When true, FM will be reset before any
+ *
+ * Define whether to reset the FM before initialization.
+ * Change the default configuration [DEFAULT_RESET_ON_INIT].
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_cfg_reset_on_init(struct fm_t *fm, bool enable);
+
+/**
+ * fm_cfg_total_fifo_size
+ * @fm Pointer to the FMan module
+ * @total_fifo_size The selected new value.
+ *
+ * Define Total FIFO size for the whole FM.
+ * Calling this routine changes the total Fifo size in the internal driver
+ * data base from its default configuration [DEFAULT_total_fifo_size]
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_cfg_total_fifo_size(struct fm_t *fm, u32 total_fifo_size);
+
+/* A Structure for returning FM revision information */
+struct fm_revision_info_t {
+ u8 major_rev; /* Major revision */
+ u8 minor_rev; /* Minor revision */
+};
+
+/**
+ * fm_set_exception
+ * fm Pointer to the FMan module
+ * exception The exception to be selected.
+ * enable True to enable interrupt, false to mask it.
+ *
+ * Calling this routine enables/disables the specified exception.
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_set_exception(struct fm_t *fm, enum fm_exceptions exception,
+ bool enable);
+
+/**
+ * fm_disable_rams_ecc
+ * @fm Pointer to the FMan module
+ * Disables ECC mechanism for all the different FM RAM's; E.g. IRAM,
+ * MURAM, etc. Note:
+ * In opposed to fm_enable_rams_ecc, this routine must be called
+ * explicitly to disable all Rams ECC.
+ *
+ * Allowed only following fm_config() and before fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_disable_rams_ecc(struct fm_t *fm);
+
+/**
+ * fm_get_revision
+ * @fm - Pointer to the FMan module
+ * fm_rev - A structure of revision information parameters.
+ * Returns the FM revision
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+void fm_get_revision(struct fm_t *fm, struct fm_revision_info_t *fm_rev);
+
+/**
+ * fm_error_isr
+ * @fm Pointer to the FMan module
+ * FM interrupt-service-routine for errors.
+ *
+ * Allowed only following fm_init().
+ *
+ * Return: 0 on success; EMPTY if no errors found in register, other
+ * error code otherwise.
+ */
+int fm_error_isr(struct fm_t *fm);
+
+/**
+ * fm_event_isr
+ * @fm Pointer to the FMan module
+ *
+ * FM interrupt-service-routine for normal events.
+ * Allowed only following fm_init().
+ */
+void fm_event_isr(struct fm_t *fm);
+
+#endif /* __FM_EXT */
diff --git a/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
new file mode 100644
index 0000000..c96cfd1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FSL_FMAN_DRV_H
+#define __FSL_FMAN_DRV_H
+
+#include <linux/types.h>
+#include <linux/device.h> /* struct device */
+#include "fm_ext.h"
+
+/* FM device opaque structure used for type checking */
+struct fm;
+
+/**
+ * fm_bind
+ * @fm_dev: the OF handle of the FM device.
+ *
+ * Bind to a specific FM device.
+ *
+ * Allowed only after the port was created.
+ *
+ * Return: A handle of the FM device.
+ */
+struct fm *fm_bind(struct device *fm_dev);
+
+/**
+ * fm_unbind
+ * @fm: A handle of the FM device.
+ *
+ * Un-bind from a specific FM device.
+ *
+ * Allowed only after the port was created.
+ */
+void fm_unbind(struct fm *fm);
+
+/**
+ * fm_get_handle
+ * @fm: A handle of the FM device
+ *
+ * Get pointer to internal FM strcuture
+ *
+ * Return: A pointer to internal FM structure
+ */
+void *fm_get_handle(struct fm *fm);
+
+/**
+ * fm_get_mem_region
+ * @fm: A handle of the FM device
+ *
+ * Get FM memory region
+ *
+ * Return: A structure with FM memory region information
+ */
+
+struct resource *fm_get_mem_region(struct fm *fm);
+/**
+ * fm_get_max_frm
+ *
+ * Return: Max frame length configured in the FM driver
+ */
+u16 fm_get_max_frm(void);
+
+/**
+ * fm_get_rx_extra_headroom
+ *
+ * Return: Extra headroom size configured in the FM driver
+ */
+int fm_get_rx_extra_headroom(void);
+
+#endif /* __FSL_FMAN_DRV_H */
--
1.7.9.5

2015-08-05 13:30:29

by Liberman Igal

[permalink] [raw]
Subject: [v4, 6/9] fsl/fman: Add FMan MAC support

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]>
---
.../ethernet/freescale/fman/flib/fsl_fman_memac.h | 1 +
drivers/net/ethernet/freescale/fman/fm.c | 41 +
drivers/net/ethernet/freescale/fman/fm.h | 3 +
drivers/net/ethernet/freescale/fman/fm_common.h | 29 +
.../ethernet/freescale/fman/inc/crc_mac_addr_ext.h | 314 ++++++
drivers/net/ethernet/freescale/fman/mac/Makefile | 4 +-
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c | 1012 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h | 207 ++++
drivers/net/ethernet/freescale/fman/mac/fm_mac.h | 259 +++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.c | 700 ++++++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_memac.h | 122 +++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.c | 552 +++++++++++
drivers/net/ethernet/freescale/fman/mac/fm_tgec.h | 124 +++
13 files changed, 3367 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_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_tgec.c
create mode 100644 drivers/net/ethernet/freescale/fman/mac/fm_tgec.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
index f8641d4..ebf7989 100644
--- a/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
+++ b/drivers/net/ethernet/freescale/fman/flib/fsl_fman_memac.h
@@ -373,6 +373,7 @@ struct memac_cfg {
bool tx_pbl_fwd;
bool debug_mode;
bool wake_on_lan;
+ bool fixed_link;
u16 max_frame_length;
u16 pause_quanta;
u32 tx_ipg_length;
diff --git a/drivers/net/ethernet/freescale/fman/fm.c b/drivers/net/ethernet/freescale/fman/fm.c
index 7e5fa53..450ee6b 100644
--- a/drivers/net/ethernet/freescale/fman/fm.c
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -587,6 +587,47 @@ u8 fm_get_id(struct fm_t *fm)
return fm->fm_state->fm_id;
}

+int fm_reset_mac(struct fm_t *fm, u8 mac_id)
+{
+ int err;
+ struct fman_fpm_regs __iomem *fpm_rg = fm->fpm_regs;
+
+ if (fm->fm_state->rev_info.major_rev >= 6) {
+ pr_warn("FMan MAC reset!\n");
+ return -EINVAL;
+ }
+ if (!fm->base_addr) {
+ pr_warn("'base_address' is required!\n");
+ return -EINVAL;
+ }
+ err = 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 *fm, enum fm_mac_type type,
+ u8 mac_id, u16 mtu)
+{
+ /* if port is already initialized, check that MaxFrameLength is smaller
+ * or equal to the port's max
+ */
+ if ((!fm->fm_state->port_mfl[mac_id]) ||
+ (fm->fm_state->port_mfl[mac_id] &&
+ (mtu <= fm->fm_state->port_mfl[mac_id]))) {
+ fm->fm_state->mac_mfl[mac_id] = mtu;
+ } else {
+ pr_warn("MAC max_frame_length is larger than Port max_frame_length\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
u16 fm_get_clock_freq(struct fm_t *fm)
{
return fm->fm_state->fm_clk_freq;
diff --git a/drivers/net/ethernet/freescale/fman/fm.h b/drivers/net/ethernet/freescale/fman/fm.h
index d7eca90..c205357 100644
--- a/drivers/net/ethernet/freescale/fman/fm.h
+++ b/drivers/net/ethernet/freescale/fman/fm.h
@@ -164,6 +164,7 @@ struct fm_iram_regs_t {

struct fm_state_struct_t {
u8 fm_id;
+ enum fm_port_type ports_types[FM_MAX_NUM_OF_HW_PORT_IDS];
u16 fm_clk_freq;
struct fm_revision_info_t rev_info;
bool enabled_time_stamp;
@@ -183,6 +184,8 @@ struct fm_state_struct_t {
u32 extra_fifo_pool_size;
u8 extra_tasks_pool_size;
u8 extra_open_dmas_pool_size;
+ u16 port_mfl[FM_MAX_NUM_OF_MACS];
+ u16 mac_mfl[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 1cde270..abe89a7 100644
--- a/drivers/net/ethernet/freescale/fman/fm_common.h
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -86,6 +86,26 @@ enum fm_inter_module_event {

#define FM_LIODN_OFFSET_MASK 0x3FF

+/* Port Id defines */
+#define BASE_RX_PORTID 0x08
+#define BASE_TX_PORTID 0x28
+
+static inline u8 hw_port_id_to_sw_port_id(u8 major, u8 hw_port_id)
+{
+ u8 sw_port_id = 0;
+
+ if (hw_port_id >= BASE_TX_PORTID) {
+ sw_port_id = hw_port_id - BASE_TX_PORTID;
+ } else if (hw_port_id >= BASE_RX_PORTID) {
+ sw_port_id = hw_port_id - BASE_RX_PORTID;
+ } else {
+ sw_port_id = DUMMY_PORT_ID;
+ BUG_ON(false);
+ }
+
+ return sw_port_id;
+}
+
#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
#define BMI_FIFO_UNITS 0x100

@@ -94,6 +114,12 @@ struct fm_intr_src_t {
void *src_handle;
};

+/* enum for defining MAC types */
+enum fm_mac_type {
+ FM_MAC_10G = 0, /* 10G MAC */
+ FM_MAC_1G /* 1G MAC */
+};
+
void fm_register_intr(struct fm_t *fm, enum fm_event_modules mod, u8 mod_id,
enum fm_intr_type intr_type,
void (*f_isr)(void *h_src_arg), void *h_src_arg);
@@ -111,4 +137,7 @@ u8 fm_get_id(struct fm_t *fm);

u32 fm_get_bmi_max_fifo_size(struct fm_t *fm);

+int fm_set_mac_max_frame(struct fm_t *fm, enum fm_mac_type type, u8 mac_id,
+ u16 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..190f739
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/crc_mac_addr_ext.h
@@ -0,0 +1,314 @@
+/*
+ * 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 u32 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) \
+{ \
+ u32 i; \
+ u8 data; \
+ crc = 0xffffffff; \
+ for (i = 0; i < 6; i++) { \
+ data = (u8)(addr >> ((5 - i) * 8)); \
+ crc = crc ^ data; \
+ crc = crc_table[crc & 0xff] ^ (crc >> 8); \
+ } \
+} \
+
+#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..26e35e1 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 \
fman_memac.o fman_memac_mii_acc.o \
- fman_tgec.o
+ fm_memac.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..941a264
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "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>
+
+static int check_init_parameters(struct dtsec_t *dtsec)
+{
+ if (ENET_SPEED_FROM_MODE(dtsec->enet_mode) >= ENET_SPEED_10000) {
+ pr_err("1G MAC driver supports 1G or lower speeds\n");
+ return -EINVAL;
+ }
+ if (dtsec->addr == 0) {
+ pr_err("Ethernet MAC Must have a valid MAC Address\n");
+ return -EINVAL;
+ }
+ if ((ENET_SPEED_FROM_MODE(dtsec->enet_mode) >= ENET_SPEED_1000) &&
+ dtsec->dtsec_drv_param->halfdup_on) {
+ pr_err("Ethernet MAC 1G can't work in half duplex\n");
+ return -EINVAL;
+ }
+
+ /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 Errata workaround */
+ if (dtsec->dtsec_drv_param->rx_preamble) {
+ pr_err("preamble_rx_en\n");
+ return -EINVAL;
+ }
+
+ if (((dtsec->dtsec_drv_param)->tx_preamble ||
+ (dtsec->dtsec_drv_param)->rx_preamble) &&
+ ((dtsec->dtsec_drv_param)->preamble_len != 0x7)) {
+ pr_err("Preamble length should be 0x7 bytes\n");
+ return -EINVAL;
+ }
+ if ((dtsec->dtsec_drv_param)->halfdup_on &&
+ (dtsec->dtsec_drv_param->tx_time_stamp_en ||
+ dtsec->dtsec_drv_param->rx_time_stamp_en)) {
+ pr_err("1588 timeStamp disabled in half duplex mode\n");
+ return -EINVAL;
+ }
+ if ((dtsec->dtsec_drv_param)->rx_flow &&
+ (dtsec->dtsec_drv_param)->rx_ctrl_acc) {
+ pr_err("Receive control frame can not be accepted\n");
+ return -EINVAL;
+ }
+ if ((dtsec->dtsec_drv_param)->rx_prepend >
+ MAX_PACKET_ALIGNMENT) {
+ pr_err("packetAlignmentPadding can't be > than %d\n",
+ MAX_PACKET_ALIGNMENT);
+ return -EINVAL;
+ }
+ if (((dtsec->dtsec_drv_param)->non_back_to_back_ipg1 >
+ MAX_INTER_PACKET_GAP) ||
+ ((dtsec->dtsec_drv_param)->non_back_to_back_ipg2 >
+ MAX_INTER_PACKET_GAP) ||
+ ((dtsec->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 ((dtsec->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 ((dtsec->dtsec_drv_param)->halfdup_retransmit >
+ MAX_RETRANSMISSION) {
+ pr_err("maxRetransmission can't be greater than %d\n",
+ MAX_RETRANSMISSION);
+ return -EINVAL;
+ }
+ if ((dtsec->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 (dtsec->dtsec_drv_param->tbipa > MAX_PHYS) {
+ pr_err("PHY address (should be 0-%d)\n", MAX_PHYS);
+ return -ERANGE;
+ }
+ if (!dtsec->exception_cb) {
+ pr_err("uninitialized exception_cb\n");
+ return -EINVAL;
+ }
+ if (!dtsec->event_cb) {
+ pr_err("uninitialized event_cb\n");
+ return -EINVAL;
+ }
+
+ /* FM_LEN_CHECK_ERRATA_FMAN_SW002 Errata workaround */
+ if (dtsec->dtsec_drv_param->rx_len_check) {
+ pr_warn("Length Check!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ u32 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;
+}
+
+static bool is_init_done(struct dtsec_cfg *dtsec_drv_params)
+{
+ /* Checks if dTSEC driver parameters were initialized */
+ if (!dtsec_drv_params)
+ return true;
+
+ return false;
+}
+
+static u32 get_mac_addr_hash_code(u64 eth_addr)
+{
+ u32 crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(eth_addr, crc);
+
+ crc = bitrev32(crc);
+
+ return crc;
+}
+
+static u16 dtsec_get_max_frame_length(struct dtsec_t *dtsec)
+{
+ if (is_init_done(dtsec->dtsec_drv_param))
+ return 0;
+
+ return fman_dtsec_get_max_frame_len(dtsec->regs);
+}
+
+static void dtsec_isr(void *handle)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)handle;
+ u32 event;
+ struct dtsec_regs __iomem *dtsec_regs = dtsec->regs;
+
+ /* do not handle MDIO events */
+ event = fman_dtsec_get_event(dtsec_regs,
+ (u32)(~(DTSEC_IMASK_MMRDEN |
+ DTSEC_IMASK_MMWREN)));
+
+ event &= fman_dtsec_get_interrupt_mask(dtsec_regs);
+
+ fman_dtsec_ack_event(dtsec_regs, event);
+
+ if (event & DTSEC_IMASK_BREN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_BAB_RX);
+ if (event & DTSEC_IMASK_RXCEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_RX_CTL);
+ if (event & DTSEC_IMASK_GTSCEN)
+ dtsec->exception_cb(dtsec->dev_id,
+ FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET);
+ if (event & DTSEC_IMASK_BTEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_BAB_TX);
+ if (event & DTSEC_IMASK_TXCEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_CTL);
+ if (event & DTSEC_IMASK_TXEEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_ERR);
+ if (event & DTSEC_IMASK_LCEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_LATE_COL);
+ if (event & DTSEC_IMASK_CRLEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_COL_RET_LMT);
+ if (event & DTSEC_IMASK_XFUNEN) {
+ /* FM_TX_LOCKUP_ERRATA_DTSEC6 Errata workaround */
+ if (dtsec->fm_rev_info.major_rev == 2) {
+ u32 tpkt1, tmp_reg1, tpkt2, tmp_reg2, i;
+ /* a. Write 0x00E0_0C00 to DTSEC_ID
+ * This is a read only register
+ * b. Read and save the value of TPKT
+ */
+ tpkt1 = in_be32(&dtsec_regs->tpkt);
+
+ /* c. Read the register at dTSEC address offset 0x32C */
+ tmp_reg1 = in_be32(&dtsec_regs->reserved02c0[27]);
+
+ /* 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((u32)(min
+ (dtsec_get_max_frame_length(dtsec) *
+ 16 / 1000, 1)), (u32)
+ (min(dtsec_get_max_frame_length
+ (dtsec) * 16 / 1000, 1) + 1));
+ }
+
+ /* e. Read and save TPKT again and read the register
+ * at dTSEC address offset 0x32C again
+ */
+ tpkt2 = in_be32(&dtsec_regs->tpkt);
+ tmp_reg2 = in_be32(&dtsec_regs->reserved02c0[27]);
+
+ /* 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] */
+
+ out_be32(&dtsec_regs->rctrl,
+ in_be32(&dtsec_regs->rctrl) |
+ RCTRL_GRS);
+
+ /* b.Wait until IEVENT[GRSC]=1, or at least
+ * 100 us has elapsed.
+ */
+ for (i = 0; i < 100; i++) {
+ if (in_be32(&dtsec_regs->ievent) &
+ DTSEC_IMASK_GRSCEN)
+ break;
+ udelay(1);
+ }
+ if (in_be32(&dtsec_regs->ievent) &
+ DTSEC_IMASK_GRSCEN)
+ out_be32(&dtsec_regs->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(dtsec->fm, 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
+ */
+ }
+ }
+
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_FIFO_UNDRN);
+ }
+ if (event & DTSEC_IMASK_MAGEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_MAG_PCKT);
+ if (event & DTSEC_IMASK_GRSCEN)
+ dtsec->exception_cb(dtsec->dev_id,
+ FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET);
+ if (event & DTSEC_IMASK_TDPEEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_DATA_ERR);
+ if (event & DTSEC_IMASK_RDPEEN)
+ dtsec->exception_cb(dtsec->dev_id, FM_MAC_1G_RX_DATA_ERR);
+
+ /* masked interrupts */
+ WARN_ON(event & DTSEC_IMASK_ABRTEN);
+ WARN_ON(event & DTSEC_IMASK_IFERREN);
+}
+
+static void dtsec_1588_isr(void *handle)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)handle;
+ u32 event;
+ struct dtsec_regs __iomem *dtsec_regs = dtsec->regs;
+
+ if (dtsec->ptp_tsu_enabled) {
+ event = fman_dtsec_check_and_clear_tmr_event(dtsec_regs);
+
+ if (event) {
+ WARN_ON(event & TMR_PEVENT_TSRE);
+ dtsec->exception_cb(dtsec->dev_id,
+ FM_MAC_EX_1G_1588_TS_RX_ERR);
+ }
+ }
+}
+
+static void free_init_resources(struct dtsec_t *dtsec)
+{
+ fm_unregister_intr(dtsec->fm, FM_MOD_MAC, dtsec->mac_id,
+ FM_INTR_TYPE_ERR);
+ fm_unregister_intr(dtsec->fm, FM_MOD_MAC, dtsec->mac_id,
+ FM_INTR_TYPE_NORMAL);
+
+ /* release the driver's group hash table */
+ free_hash_table(dtsec->multicast_addr_hash);
+ dtsec->multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(dtsec->unicast_addr_hash);
+ dtsec->unicast_addr_hash = NULL;
+}
+
+static int graceful_stop(struct dtsec_t *dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *regs;
+
+ regs = dtsec->regs;
+
+ /* Assert the graceful transmit stop bit */
+ if (mode & COMM_MODE_RX) {
+ fman_dtsec_stop_rx(regs);
+
+ if (dtsec->fm_rev_info.major_rev == 2)
+ usleep_range(100, 200);
+ else
+ udelay(10);
+ }
+
+ if (mode & COMM_MODE_TX) {
+ if (dtsec->fm_rev_info.major_rev == 2)
+ pr_debug("GTS not supported due to DTSEC_A004 errata.\n");
+ else
+ pr_debug("GTS not supported due to DTSEC_A0014 errata.\n");
+ }
+ return 0;
+}
+
+static int graceful_restart(struct dtsec_t *dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *regs;
+
+ regs = dtsec->regs;
+ /* clear the graceful receive stop bit */
+ if (mode & COMM_MODE_TX)
+ fman_dtsec_start_tx(regs);
+
+ if (mode & COMM_MODE_RX)
+ fman_dtsec_start_rx(regs);
+
+ return 0;
+}
+
+static int dtsec_mii_write_phy_reg(struct dtsec_t *dtsec, u8 phy_addr,
+ u8 reg, u16 data)
+{
+ u16 dtsec_freq;
+
+ dtsec_freq = (u16)(dtsec->clk_freq >> 1);
+
+ return fman_dtsec_mii_write_reg(dtsec->mii_regs, phy_addr, reg,
+ data, dtsec_freq);
+}
+
+static int dtsec_mii_read_phy_reg(struct dtsec_t *dtsec, u8 phy_addr,
+ u8 reg, u16 *data)
+{
+ u16 dtsec_freq;
+ int err;
+
+ dtsec_freq = (u16)(dtsec->clk_freq >> 1);
+
+ err = fman_dtsec_mii_read_reg(dtsec->mii_regs, phy_addr, reg,
+ data, dtsec_freq);
+
+ if (*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;
+}
+
+int dtsec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, u16 new_val)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ dtsec->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 *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ dtsec->dtsec_drv_param->tx_pad_crc = new_val;
+
+ return 0;
+}
+
+int dtsec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ fman_dtsec_enable(dtsec->regs,
+ (bool)!!(mode & COMM_MODE_RX),
+ (bool)!!(mode & COMM_MODE_TX));
+
+ graceful_restart(dtsec, mode);
+
+ return 0;
+}
+
+int dtsec_disable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ graceful_stop(dtsec, mode);
+
+ fman_dtsec_disable(dtsec->regs,
+ (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,
+ u8 __maybe_unused priority,
+ u16 pause_time, u16 __maybe_unused thresh_time)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
+ if (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 -EINVAL;
+ }
+
+ fman_dtsec_set_tx_pause_frames(dtsec->regs, pause_time);
+ return 0;
+}
+
+int dtsec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ fman_dtsec_handle_rx_pause(dtsec->regs, en);
+
+ return 0;
+}
+
+int dtsec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *enet_addr)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ /* Initialize MAC Station Address registers (1 & 2)
+ * Station address have to be swapped (big endian to little endian
+ */
+ dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr);
+ fman_dtsec_set_mac_address(dtsec->regs, (u8 *)(*enet_addr));
+
+ return 0;
+}
+
+int dtsec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *hash_entry;
+ u64 addr;
+ s32 bucket;
+ u32 crc;
+ bool mcast, ghtx;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ addr = ENET_ADDR_TO_UINT64(*eth_addr);
+
+ ghtx = (bool)((fman_dtsec_get_rctrl(dtsec->regs) &
+ RCTRL_GHTX) ? true : false);
+ mcast = (bool)((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(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 = (s32)((crc >> 23) & 0x1ff);
+ } else {
+ bucket = (s32)((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(dtsec->regs, bucket, true);
+
+ /* Create element to be added to the driver hash table */
+ hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+ if (!hash_entry)
+ return -ENOMEM;
+ hash_entry->addr = addr;
+ INIT_LIST_HEAD(&hash_entry->node);
+
+ if (addr & MAC_GROUP_ADDRESS)
+ /* Group Address */
+ list_add_tail(&hash_entry->node,
+ &dtsec->multicast_addr_hash->lsts[bucket]);
+ else
+ list_add_tail(&hash_entry->node,
+ &dtsec->unicast_addr_hash->lsts[bucket]);
+
+ return 0;
+}
+
+int dtsec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct list_head *pos;
+ struct eth_hash_entry_t *hash_entry = NULL;
+ u64 addr;
+ s32 bucket;
+ u32 crc;
+ bool mcast, ghtx;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ addr = ENET_ADDR_TO_UINT64(*eth_addr);
+
+ ghtx = (bool)((fman_dtsec_get_rctrl(dtsec->regs) &
+ RCTRL_GHTX) ? true : false);
+ mcast = (bool)((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(addr);
+
+ if (ghtx) {
+ bucket = (s32)((crc >> 23) & 0x1ff);
+ } else {
+ bucket = (s32)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set
+ * in gaddr instead of igaddr.
+ */
+ if (mcast)
+ bucket += 0x100;
+ }
+
+ if (addr & MAC_GROUP_ADDRESS) {
+ /* Group Address */
+ list_for_each(pos,
+ &dtsec->multicast_addr_hash->lsts[bucket]) {
+ hash_entry = ETH_HASH_ENTRY_OBJ(pos);
+ if (hash_entry->addr == addr) {
+ list_del_init(&hash_entry->node);
+ kfree(hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&dtsec->multicast_addr_hash->lsts[bucket]))
+ fman_dtsec_set_bucket(dtsec->regs, bucket, false);
+ } else {
+ /* Individual Address */
+ list_for_each(pos,
+ &dtsec->unicast_addr_hash->lsts[bucket]) {
+ hash_entry = ETH_HASH_ENTRY_OBJ(pos);
+ if (hash_entry->addr == addr) {
+ list_del_init(&hash_entry->node);
+ kfree(hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&dtsec->unicast_addr_hash->lsts[bucket]))
+ fman_dtsec_set_bucket(dtsec->regs, bucket, false);
+ }
+
+ /* address does not exist */
+ WARN_ON(!hash_entry);
+
+ return 0;
+}
+
+int dtsec_set_promiscuous(struct fm_mac_dev *fm_mac_dev, bool new_val)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ fman_dtsec_set_uc_promisc(dtsec->regs, new_val);
+ fman_dtsec_set_mc_promisc(dtsec->regs, new_val);
+
+ return 0;
+}
+
+int dtsec_adjust_link(struct fm_mac_dev *fm_mac_dev, enum ethernet_speed speed)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+ int err;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ int full_duplex = true;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ dtsec->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(dtsec->enet_mode), speed);
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(dtsec->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(dtsec->enet_mode);
+
+ err = fman_dtsec_adjust_link(dtsec->regs, 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 *dtsec = (struct dtsec_t *)fm_mac_dev;
+ u16 tmp_reg16;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ dtsec_mii_read_phy_reg(dtsec, 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(dtsec, dtsec->tbi_phy_addr, 0, tmp_reg16);
+
+ return 0;
+}
+
+int dtsec_get_version(struct fm_mac_dev *fm_mac_dev, u32 *mac_version)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ *mac_version = fman_dtsec_get_revision(dtsec->regs);
+
+ return 0;
+}
+
+int dtsec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+ u32 bit_mask = 0;
+
+ if (!is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ if (exception != FM_MAC_EX_1G_1588_TS_RX_ERR) {
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ dtsec->exceptions |= bit_mask;
+ else
+ dtsec->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EINVAL;
+ }
+ if (enable)
+ fman_dtsec_enable_interrupt(dtsec->regs, bit_mask);
+ else
+ fman_dtsec_disable_interrupt(dtsec->regs, bit_mask);
+ } else {
+ if (!dtsec->ptp_tsu_enabled) {
+ pr_err("Exception valid for 1588 only\n");
+ return -EINVAL;
+ }
+ switch (exception) {
+ case FM_MAC_EX_1G_1588_TS_RX_ERR:
+ if (enable) {
+ dtsec->en_tsu_err_exeption = true;
+ fman_dtsec_enable_tmr_interrupt(dtsec->regs);
+ } else {
+ dtsec->en_tsu_err_exeption = false;
+ fman_dtsec_disable_tmr_interrupt(dtsec->regs);
+ }
+ break;
+ default:
+ pr_err("Undefined exception\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int dtsec_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+ struct dtsec_cfg *dtsec_drv_param;
+ int err;
+ u16 max_frm_ln;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ enet_addr_t eth_addr;
+
+ if (is_init_done(dtsec->dtsec_drv_param))
+ return -EINVAL;
+
+ if (DEFAULT_RESET_ON_INIT &&
+ (fm_reset_mac(dtsec->fm, dtsec->mac_id) != 0)) {
+ pr_err("Can't reset MAC!\n");
+ return -EINVAL;
+ }
+
+ err = check_init_parameters(dtsec);
+ if (err)
+ return err;
+
+ dtsec_drv_param = dtsec->dtsec_drv_param;
+
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(dtsec->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(dtsec->enet_mode);
+ MAKE_ENET_ADDR_FROM_UINT64(dtsec->addr, eth_addr);
+
+ err = fman_dtsec_init(dtsec->regs, dtsec_drv_param, enet_interface,
+ enet_speed, (u8 *)eth_addr,
+ dtsec->fm_rev_info.major_rev,
+ dtsec->fm_rev_info.minor_rev,
+ dtsec->exceptions);
+ if (err) {
+ free_init_resources(dtsec);
+ pr_err("DTSEC version doesn't support this i/f mode\n");
+ return err;
+ }
+
+ if (ENET_INTERFACE_FROM_MODE(dtsec->enet_mode) == ENET_IF_SGMII) {
+ u16 tmp_reg16;
+
+ /* Configure the TBI PHY Control Register */
+ tmp_reg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET;
+ dtsec_mii_write_phy_reg(dtsec, (u8)dtsec_drv_param->tbipa,
+ 17, tmp_reg16);
+
+ tmp_reg16 = PHY_TBICON_CLK_SEL;
+ dtsec_mii_write_phy_reg(dtsec, (u8)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(dtsec, (u8)dtsec_drv_param->tbipa,
+ 0, tmp_reg16);
+
+ if (dtsec->enet_mode & ENET_IF_SGMII_BASEX)
+ tmp_reg16 = PHY_TBIANA_1000X;
+ else
+ tmp_reg16 = PHY_TBIANA_SGMII;
+ dtsec_mii_write_phy_reg(dtsec, (u8)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(dtsec, (u8)dtsec_drv_param->tbipa,
+ 0, tmp_reg16);
+ }
+
+ /* Max Frame Length */
+ max_frm_ln = fman_dtsec_get_max_frame_len(dtsec->regs);
+ err = fm_set_mac_max_frame(dtsec->fm, FM_MAC_1G, dtsec->mac_id,
+ max_frm_ln);
+ if (err) {
+ pr_err("Setting max frame length failed\n");
+ free_init_resources(dtsec);
+ return -EINVAL;
+ }
+
+ dtsec->multicast_addr_hash =
+ alloc_hash_table(EXTENDED_HASH_TABLE_SIZE);
+ if (!dtsec->multicast_addr_hash) {
+ free_init_resources(dtsec);
+ pr_err("MC hash table is failed\n");
+ return -ENOMEM;
+ }
+
+ dtsec->unicast_addr_hash = alloc_hash_table(DTSEC_HASH_TABLE_SIZE);
+ if (!dtsec->unicast_addr_hash) {
+ free_init_resources(dtsec);
+ pr_err("UC hash table is failed\n");
+ return -ENOMEM;
+ }
+
+ /* register err intr handler for dtsec to FPM (err) */
+ fm_register_intr(dtsec->fm, FM_MOD_MAC, dtsec->mac_id,
+ FM_INTR_TYPE_ERR, dtsec_isr, dtsec);
+ /* register 1588 intr handler for TMR to FPM (normal) */
+ fm_register_intr(dtsec->fm, FM_MOD_MAC, dtsec->mac_id,
+ FM_INTR_TYPE_NORMAL, dtsec_1588_isr, dtsec);
+
+ kfree(dtsec_drv_param);
+ dtsec->dtsec_drv_param = NULL;
+
+ return 0;
+}
+
+int dtsec_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct dtsec_t *dtsec = (struct dtsec_t *)fm_mac_dev;
+
+ free_init_resources(dtsec);
+
+ kfree(dtsec->dtsec_drv_param);
+ dtsec->dtsec_drv_param = NULL;
+ kfree(dtsec);
+
+ return 0;
+}
+
+void *dtsec_config(struct fm_mac_params_t *fm_mac_param)
+{
+ struct dtsec_t *dtsec;
+ struct dtsec_cfg *dtsec_drv_param;
+ void __iomem *base_addr;
+
+ base_addr = fm_mac_param->base_addr;
+
+ /* allocate memory for the UCC GETH data structure. */
+ dtsec = kzalloc(sizeof(*dtsec), GFP_KERNEL);
+ if (!dtsec)
+ return NULL;
+
+ /* allocate memory for the d_tsec driver parameters data structure. */
+ dtsec_drv_param = kzalloc(sizeof(*dtsec_drv_param), GFP_KERNEL);
+ if (!dtsec_drv_param)
+ goto err_dtsec;
+
+ /* Plant parameter structure pointer */
+ dtsec->dtsec_drv_param = dtsec_drv_param;
+
+ fman_dtsec_defconfig(dtsec_drv_param);
+
+ dtsec->regs = (struct dtsec_regs __iomem *)(base_addr);
+ dtsec->mii_regs = (struct dtsec_mii_reg __iomem *)
+ (base_addr + DTSEC_TO_MII_OFFSET);
+ dtsec->addr = ENET_ADDR_TO_UINT64(fm_mac_param->addr);
+ dtsec->enet_mode = fm_mac_param->enet_mode;
+ dtsec->mac_id = fm_mac_param->mac_id;
+ dtsec->exceptions = DTSEC_DEFAULT_EXCEPTIONS;
+ dtsec->exception_cb = fm_mac_param->exception_cb;
+ dtsec->event_cb = fm_mac_param->event_cb;
+ dtsec->dev_id = fm_mac_param->dev_id;
+ dtsec->ptp_tsu_enabled = dtsec->dtsec_drv_param->ptp_tsu_en;
+ dtsec->en_tsu_err_exeption = dtsec->dtsec_drv_param->ptp_exception_en;
+ dtsec->tbi_phy_addr = dtsec->dtsec_drv_param->tbi_phy_addr;
+
+ dtsec->fm = fm_mac_param->fm;
+ dtsec->clk_freq = fm_get_clock_freq(dtsec->fm);
+ if (dtsec->clk_freq == 0) {
+ pr_err("Can't get clock for MAC!\n");
+ goto err_dtsec;
+ }
+
+ /* Save FMan revision */
+ fm_get_revision(dtsec->fm, &dtsec->fm_rev_info);
+
+ return dtsec;
+
+err_dtsec:
+ kfree(dtsec);
+ return NULL;
+}
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..1ed7295
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_dtsec.h
@@ -0,0 +1,207 @@
+/*
+ * 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_H
+#define __DTSEC_H
+
+#include "enet_ext.h"
+
+#include "fm_mac.h"
+
+#define DTSEC_DEFAULT_EXCEPTIONS \
+ ((u32)((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 {
+ u64 tr64;
+ u64 tr127;
+ u64 tr255;
+ u64 tr511;
+ u64 tr1k;
+ u64 trmax;
+ u64 trmgv;
+ u64 rfrg;
+ u64 rjbr;
+ u64 rdrp;
+ u64 raln;
+ u64 rund;
+ u64 rovr;
+ u64 rxpf;
+ u64 txpf;
+ u64 rbyt;
+ u64 rpkt;
+ u64 rmca;
+ u64 rbca;
+ u64 rflr;
+ u64 rcde;
+ u64 rcse;
+ u64 tbyt;
+ u64 tpkt;
+ u64 tmca;
+ u64 tbca;
+ u64 tdrp;
+ u64 tfcs;
+};
+
+struct dtsec_t {
+ /* pointer to dTSEC memory mapped registers */
+ struct dtsec_regs __iomem *regs;
+ /* pointer to dTSEC MII memory mapped registers */
+ struct dtsec_mii_reg __iomem *mii_regs;
+ /* MAC address of device */
+ u64 addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *exception_cb;
+ fm_mac_exception_cb *event_cb;
+ /* 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
+ */
+ u64 paddr[DTSEC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station */
+ u8 num_of_ind_addr_in_regs;
+ struct internal_statistics_t internal_statistics;
+ /* pointer to driver's global address hash table */
+ struct eth_hash_t *multicast_addr_hash;
+ /* pointer to driver's individual address hash table */
+ struct eth_hash_t *unicast_addr_hash;
+ u8 mac_id;
+ u8 tbi_phy_addr;
+ u32 exceptions;
+ bool ptp_tsu_enabled;
+ bool en_tsu_err_exeption;
+ struct dtsec_cfg *dtsec_drv_param;
+ u16 clk_freq;
+ void *fm;
+ struct fm_revision_info_t fm_rev_info;
+};
+
+void *dtsec_config(struct fm_mac_params_t *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 *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, u16 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);
+int dtsec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, u8 priority,
+ u16 pause_time, u16 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 *eth_addr);
+int dtsec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr);
+int dtsec_get_version(struct fm_mac_dev *fm_mac_dev, u32 *mac_version);
+
+#endif /* __DTSEC_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..6004e2d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_mac.h
@@ -0,0 +1,259 @@
+/*
+ * 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 "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) \
+ hlist_entry_safe(ptr, struct eth_hash_entry_t, node)
+
+/* 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 */
+};
+
+/* 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 {
+ u64 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 */
+ void __iomem *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
+ */
+ u8 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 *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 *event_cb; /* MDIO Events Callback Routine */
+ fm_mac_exception_cb *exception_cb; /* Exception Callback Routine */
+};
+
+struct eth_hash_t {
+ u16 size;
+ struct list_head *lsts;
+};
+
+static inline struct eth_hash_entry_t
+*dequeue_addr_from_hash_entry(struct list_head *addr_lst)
+{
+ struct eth_hash_entry_t *hash_entry = NULL;
+
+ if (!list_empty(addr_lst)) {
+ hash_entry = ETH_HASH_ENTRY_OBJ(addr_lst->next);
+ list_del_init(&hash_entry->node);
+ }
+ return hash_entry;
+}
+
+static inline void free_hash_table(struct eth_hash_t *hash)
+{
+ struct eth_hash_entry_t *hash_entry;
+ int i = 0;
+
+ if (hash) {
+ if (hash->lsts) {
+ for (i = 0; i < hash->size; i++) {
+ hash_entry =
+ dequeue_addr_from_hash_entry(&hash->lsts[i]);
+ while (hash_entry) {
+ kfree(hash_entry);
+ hash_entry =
+ dequeue_addr_from_hash_entry(&hash->
+ lsts[i]);
+ }
+ }
+
+ kfree(hash->lsts);
+ }
+
+ kfree(hash);
+ }
+}
+
+static inline struct eth_hash_t *alloc_hash_table(u16 size)
+{
+ u32 i;
+ struct eth_hash_t *hash;
+
+ /* Allocate address hash table */
+ hash = kmalloc_array(size, sizeof(struct eth_hash_t *), GFP_KERNEL);
+ if (!hash)
+ return NULL;
+
+ hash->size = size;
+
+ hash->lsts = kmalloc_array(hash->size, sizeof(struct list_head),
+ GFP_KERNEL);
+ if (!hash->lsts) {
+ kfree(hash);
+ return NULL;
+ }
+
+ for (i = 0; i < hash->size; i++)
+ INIT_LIST_HEAD(&hash->lsts[i]);
+
+ return 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..becbb88
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "fm_common.h"
+#include "fm_memac.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+static u32 get_mac_addr_hash_code(u64 eth_addr)
+{
+ u64 mask1, mask2;
+ u32 xor_val = 0;
+ u8 i, j;
+
+ for (i = 0; i < 6; i++) {
+ mask1 = eth_addr & (u64)0x01;
+ eth_addr >>= 1;
+
+ for (j = 0; j < 7; j++) {
+ mask2 = eth_addr & (u64)0x01;
+ mask1 ^= mask2;
+ eth_addr >>= 1;
+ }
+
+ xor_val |= (mask1 << (5 - i));
+ }
+
+ return xor_val;
+}
+
+static int memac_mii_write_phy_reg(struct memac_t *memac, u8 phy_addr,
+ u8 reg, u16 data)
+{
+ return fman_memac_mii_write_phy_reg(memac->mii_regs,
+ phy_addr, reg, data,
+ (enum enet_speed)
+ ENET_SPEED_FROM_MODE(memac->
+ enet_mode));
+}
+
+static void setup_sgmii_internal_phy(struct memac_t *memac, u8 phy_addr,
+ bool fixed_link)
+{
+ u16 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 = memac->enet_mode;
+ memac->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(memac->enet_mode),
+ ENET_SPEED_1000);
+
+ /* SGMII mode */
+ tmp_reg16 = PHY_SGMII_IF_MODE_SGMII;
+ if (!fixed_link)
+ /* AN enable */
+ tmp_reg16 |= PHY_SGMII_IF_MODE_AN;
+ else
+ /* Fixed link 1Gb FD */
+ tmp_reg16 |= PHY_SGMII_IF_MODE_SPEED_GB |
+ PHY_SGMII_IF_MODE_DUPLEX_FULL;
+ memac_mii_write_phy_reg(memac, phy_addr, 0x14, tmp_reg16);
+
+ /* Device ability according to SGMII specification */
+ tmp_reg16 = PHY_SGMII_DEV_ABILITY_SGMII;
+ memac_mii_write_phy_reg(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(memac, phy_addr, 0x13, 0x0007);
+ memac_mii_write_phy_reg(memac, phy_addr, 0x12, 0xa120);
+
+ if (!fixed_link)
+ /* Restart AN */
+ tmp_reg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ else
+ tmp_reg16 = PHY_SGMII_CR_DEF_VAL & ~PHY_SGMII_CR_AN_ENABLE;
+ memac_mii_write_phy_reg(memac, phy_addr, 0x0, tmp_reg16);
+
+ /* Restore original enet mode */
+ memac->enet_mode = enet_mode;
+}
+
+static void setup_sgmii_internal_phy_base_x(struct memac_t *memac,
+ u8 phy_addr)
+{
+ u16 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 = memac->enet_mode;
+ memac->enet_mode =
+ MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(memac->enet_mode),
+ ENET_SPEED_1000);
+
+ /* 1000BaseX mode */
+ tmp_reg16 = PHY_SGMII_IF_MODE_1000X;
+ memac_mii_write_phy_reg(memac, phy_addr, 0x14, tmp_reg16);
+
+ /* AN Device capability */
+ tmp_reg16 = PHY_SGMII_DEV_ABILITY_1000X;
+ memac_mii_write_phy_reg(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(memac, phy_addr, 0x13, 0x002f);
+ memac_mii_write_phy_reg(memac, phy_addr, 0x12, 0xaf08);
+
+ /* Restart AN */
+ tmp_reg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ memac_mii_write_phy_reg(memac, phy_addr, 0x0, tmp_reg16);
+
+ /* Restore original enet mode */
+ memac->enet_mode = enet_mode;
+}
+
+static int check_init_parameters(struct memac_t *memac)
+{
+ if (memac->addr == 0) {
+ pr_err("Ethernet MAC must have a valid MAC address\n");
+ return -EINVAL;
+ }
+ if (!memac->exception_cb) {
+ pr_err("Uninitialized exception handler\n");
+ return -EINVAL;
+ }
+ if (!memac->event_cb) {
+ pr_warn("Uninitialize event handler\n");
+ return -EINVAL;
+ }
+
+ /* FM_LEN_CHECK_ERRATA_FMAN_SW002 Errata workaround */
+ if (!memac->memac_drv_param->no_length_check_enable) {
+ pr_err("Length Check!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ u32 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 *handle)
+{
+ struct memac_t *memac = (struct memac_t *)handle;
+ u32 event, imask;
+
+ event = fman_memac_get_event(memac->regs, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(memac->regs);
+
+ /* 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(memac->regs, event);
+
+ if (event & MEMAC_IEVNT_TS_ECC_ER)
+ memac->exception_cb(memac->dev_id, FM_MAC_EX_TS_FIFO_ECC_ERR);
+ if (event & MEMAC_IEVNT_TX_ECC_ER)
+ memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_TX_ECC_ER);
+ if (event & MEMAC_IEVNT_RX_ECC_ER)
+ memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_RX_ECC_ER);
+}
+
+static void memac_exception(void *handle)
+{
+ struct memac_t *memac = (struct memac_t *)handle;
+ u32 event, imask;
+
+ event = fman_memac_get_event(memac->regs, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(memac->regs);
+
+ /* 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(memac->regs, event);
+
+ if (event & MEMAC_IEVNT_MGI)
+ memac->exception_cb(memac->dev_id,
+ FM_MAC_EX_MAGIC_PACKET_INDICATION);
+}
+
+static void free_init_resources(struct memac_t *memac)
+{
+ fm_unregister_intr(memac->fm, FM_MOD_MAC, memac->mac_id,
+ FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ free_hash_table(memac->multicast_addr_hash);
+ memac->multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(memac->unicast_addr_hash);
+ memac->unicast_addr_hash = NULL;
+}
+
+static bool is_init_done(struct memac_cfg *memac_drv_params)
+{
+ /* Checks if mEMAC driver parameters were initialized */
+ if (!memac_drv_params)
+ return true;
+
+ return false;
+}
+
+int memac_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_enable(memac->regs,
+ (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 *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_disable(memac->regs,
+ (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 *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_set_promiscuous(memac->regs, new_val);
+
+ return 0;
+}
+
+int memac_adjust_link(struct fm_mac_dev *fm_mac_dev, enum ethernet_speed speed)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+ int full_duplex = true;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_adjust_link(memac->regs,
+ (enum enet_interface)
+ ENET_INTERFACE_FROM_MODE(memac->enet_mode),
+ (enum enet_speed)speed, full_duplex);
+ return 0;
+}
+
+int memac_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, u16 new_val)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ memac->memac_drv_param->max_frame_length = new_val;
+
+ return 0;
+}
+
+int memac_cfg_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ memac->memac_drv_param->reset_on_init = enable;
+
+ return 0;
+}
+
+int memac_cfg_fixed_link(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ memac->memac_drv_param->fixed_link = enable;
+
+ return 0;
+}
+
+int memac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ u8 __maybe_unused priority,
+ u16 pause_time,
+ u16 __maybe_unused thresh_time)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_set_tx_pause_frames(memac->regs, 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 *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_set_rx_ignore_pause_frames(memac->regs, !en);
+
+ return 0;
+}
+
+int memac_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ fman_memac_add_addr_in_paddr(memac->regs, (u8 *)(*p_enet_addr), 0);
+
+ return 0;
+}
+
+int memac_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+ struct eth_hash_entry_t *hash_entry;
+ u32 hash;
+ u64 addr;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ addr = ENET_ADDR_TO_UINT64(*eth_addr);
+
+ if (!(addr & GROUP_ADDRESS)) {
+ /* Unicast addresses not supported in hash */
+ pr_err("Unicast Address\n");
+ return -EINVAL;
+ }
+ hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK;
+
+ /* Create element to be added to the driver hash table */
+ hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+ if (!hash_entry)
+ return -ENOMEM;
+ hash_entry->addr = addr;
+ INIT_LIST_HEAD(&hash_entry->node);
+
+ list_add_tail(&hash_entry->node,
+ &memac->multicast_addr_hash->lsts[hash]);
+ fman_memac_set_hash_table(memac->regs,
+ (hash | HASH_CTRL_MCAST_EN));
+
+ return 0;
+}
+
+int memac_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+ struct eth_hash_entry_t *hash_entry = NULL;
+ struct list_head *p_pos;
+ u32 hash;
+ u64 addr;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ addr = ENET_ADDR_TO_UINT64(*eth_addr);
+
+ hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK;
+
+ list_for_each(p_pos, &memac->multicast_addr_hash->lsts[hash]) {
+ hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (hash_entry->addr == addr) {
+ list_del_init(&hash_entry->node);
+ kfree(hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&memac->multicast_addr_hash->lsts[hash]))
+ fman_memac_set_hash_table(memac->regs,
+ (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 *memac = (struct memac_t *)fm_mac_dev;
+ u32 bit_mask = 0;
+
+ if (!is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ memac->exceptions |= bit_mask;
+ else
+ memac->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EINVAL;
+ }
+ fman_memac_set_exception(memac->regs, bit_mask, enable);
+
+ return 0;
+}
+
+int memac_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+ struct memac_cfg *memac_drv_param;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ u8 i, phy_addr;
+ enet_addr_t eth_addr;
+ enum fm_mac_type port_type;
+ bool slow_10g_if = false;
+ bool fixed_link;
+ int err;
+ u32 reg32 = 0;
+
+ if (is_init_done(memac->memac_drv_param))
+ return -EINVAL;
+
+ err = check_init_parameters(memac);
+ if (err)
+ return err;
+
+ memac_drv_param = memac->memac_drv_param;
+
+ if (memac->fm_rev_info.major_rev == 6 &&
+ memac->fm_rev_info.minor_rev == 4)
+ slow_10g_if = true;
+
+ port_type =
+ ((ENET_SPEED_FROM_MODE(memac->enet_mode) < ENET_SPEED_10000) ?
+ FM_MAC_1G : FM_MAC_10G);
+
+ /* First, reset the MAC if desired. */
+ if (memac_drv_param->reset_on_init) {
+ err = fman_memac_reset(memac->regs);
+ if (err) {
+ pr_err("fman_memac_reset() failed\n");
+ return err;
+ }
+ }
+
+ /* MAC Address */
+ MAKE_ENET_ADDR_FROM_UINT64(memac->addr, eth_addr);
+ fman_memac_add_addr_in_paddr(memac->regs, (u8 *)eth_addr, 0);
+
+ enet_interface =
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(memac->enet_mode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(memac->enet_mode);
+ fixed_link = memac_drv_param->fixed_link;
+
+ fman_memac_init(memac->regs,
+ memac->memac_drv_param,
+ enet_interface,
+ enet_speed,
+ slow_10g_if,
+ memac->exceptions);
+
+ /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 errata workaround
+ * Exists only in FMan 6.0 and 6.3.
+ */
+ if ((memac->fm_rev_info.major_rev == 6) &&
+ ((memac->fm_rev_info.minor_rev == 0) ||
+ (memac->fm_rev_info.minor_rev == 3))) {
+ /* MAC strips CRC from received frames - this workaround
+ * should decrease the likelihood of bug appearance
+ */
+ reg32 = in_be32(&memac->regs->command_config);
+ reg32 &= ~CMD_CFG_CRC_FWD;
+ out_be32(&memac->regs->command_config, reg32);
+ }
+
+ if (ENET_INTERFACE_FROM_MODE(memac->enet_mode) == ENET_IF_SGMII) {
+ /* Configure internal SGMII PHY */
+ if (memac->enet_mode & ENET_IF_SGMII_BASEX)
+ setup_sgmii_internal_phy_base_x(memac, PHY_MDIO_ADDR);
+ else
+ setup_sgmii_internal_phy(memac, PHY_MDIO_ADDR,
+ fixed_link);
+ } else if (ENET_INTERFACE_FROM_MODE(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 = (u8)((PHY_MDIO_ADDR << 2) | i);
+ if (memac->enet_mode & ENET_IF_SGMII_BASEX)
+ setup_sgmii_internal_phy_base_x(memac,
+ phy_addr);
+ else
+ setup_sgmii_internal_phy(memac, phy_addr,
+ fixed_link);
+ }
+ }
+
+ /* Max Frame Length */
+ err = fm_set_mac_max_frame(memac->fm, port_type, memac->mac_id,
+ memac_drv_param->max_frame_length);
+ if (err) {
+ pr_err("settings Mac max frame length is FAILED\n");
+ return err;
+ }
+
+ memac->multicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE);
+ if (!memac->multicast_addr_hash) {
+ free_init_resources(memac);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ memac->unicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE);
+ if (!memac->unicast_addr_hash) {
+ free_init_resources(memac);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ fm_register_intr(memac->fm, FM_MOD_MAC, memac->mac_id,
+ FM_INTR_TYPE_ERR, memac_err_exception, memac);
+
+ fm_register_intr(memac->fm, FM_MOD_MAC, memac->mac_id,
+ FM_INTR_TYPE_NORMAL, memac_exception, memac);
+
+ kfree(memac_drv_param);
+ memac->memac_drv_param = NULL;
+
+ return 0;
+}
+
+int memac_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct memac_t *memac = (struct memac_t *)fm_mac_dev;
+
+ free_init_resources(memac);
+
+ kfree(memac->memac_drv_param);
+ kfree(memac);
+
+ return 0;
+}
+
+void *memac_config(struct fm_mac_params_t *fm_mac_param)
+{
+ struct memac_t *memac;
+ struct memac_cfg *memac_drv_param;
+ void __iomem *base_addr;
+
+ base_addr = fm_mac_param->base_addr;
+ /* allocate memory for the m_emac data structure */
+ memac = kzalloc(sizeof(*memac), GFP_KERNEL);
+ if (!memac)
+ return NULL;
+
+ /* allocate memory for the m_emac driver parameters data structure */
+ memac_drv_param = kzalloc(sizeof(*memac_drv_param), GFP_KERNEL);
+ if (!memac_drv_param) {
+ memac_free((struct fm_mac_dev *)memac);
+ return NULL;
+ }
+
+ /* Plant parameter structure pointer */
+ memac->memac_drv_param = memac_drv_param;
+
+ fman_memac_defconfig(memac_drv_param);
+
+ memac->addr = ENET_ADDR_TO_UINT64(fm_mac_param->addr);
+
+ memac->regs = (struct memac_regs __iomem *)(base_addr);
+ memac->mii_regs = (struct memac_mii_access_mem_map __iomem *)
+ (base_addr + MEMAC_TO_MII_OFFSET);
+ memac->enet_mode = fm_mac_param->enet_mode;
+ memac->mac_id = fm_mac_param->mac_id;
+ memac->exceptions = MEMAC_DEFAULT_EXCEPTIONS;
+ memac->exception_cb = fm_mac_param->exception_cb;
+ memac->event_cb = fm_mac_param->event_cb;
+ memac->dev_id = fm_mac_param->dev_id;
+ memac->fm = fm_mac_param->fm;
+
+ /* Save FMan revision */
+ fm_get_revision(memac->fm, &memac->fm_rev_info);
+
+ return 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..8fcbd64
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_memac.h
@@ -0,0 +1,122 @@
+/*
+ * 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_H
+#define __MEMAC_H
+
+#include "fsl_fman_memac_mii_acc.h"
+#include "fm_mac.h"
+#include "fsl_fman_memac.h"
+
+#define MEMAC_DEFAULT_EXCEPTIONS \
+ ((u32)(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 *regs;
+ /* Pointer to MII memory mapped registers */
+ struct memac_mii_access_mem_map __iomem *mii_regs;
+ /* MAC address of device */
+ u64 addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *exception_cb;
+ fm_mac_exception_cb *event_cb;
+ /* 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
+ */
+ u64 paddr[MEMAC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station. */
+ u8 num_of_ind_addr_in_regs;
+ /* Pointer to driver's global address hash table */
+ struct eth_hash_t *multicast_addr_hash;
+ /* Pointer to driver's individual address hash table */
+ struct eth_hash_t *unicast_addr_hash;
+ bool debug_mode;
+ u8 mac_id;
+ u32 exceptions;
+ struct memac_cfg *memac_drv_param;
+ void *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_AN_ENABLE 0x1000
+#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_DUPLEX_FULL 0x0000
+#define PHY_SGMII_IF_MODE_DUPLEX_HALF 0x0010
+#define PHY_SGMII_IF_MODE_SPEED_GB 0x0008
+#define PHY_SGMII_IF_MODE_SPEED_100M 0x0004
+#define PHY_SGMII_IF_MODE_SPEED_10M 0x0000
+#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
+
+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, u16 new_val);
+int memac_cfg_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable);
+int memac_cfg_fixed_link(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, u8 priority,
+ u16 pause_time, u16 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_tgec.c b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
new file mode 100644
index 0000000..3ba0608
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "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>
+
+static int check_init_parameters(struct tgec_t *tgec)
+{
+ if (ENET_SPEED_FROM_MODE(tgec->enet_mode) < ENET_SPEED_10000) {
+ pr_err("10G MAC driver only support 10G speed\n");
+ return -EINVAL;
+ }
+ if (tgec->addr == 0) {
+ pr_err("Ethernet 10G MAC Must have valid MAC Address\n");
+ return -EINVAL;
+ }
+ if (!tgec->exception_cb) {
+ pr_err("uninitialized exception_cb\n");
+ return -EINVAL;
+ }
+ if (!tgec->event_cb) {
+ pr_err("uninitialized event_cb\n");
+ return -EINVAL;
+ }
+
+ /* FM_LEN_CHECK_ERRATA_FMAN_SW002 Errata workaround */
+ if (!tgec->tgec_drv_param->no_length_check_enable) {
+ pr_warn("Length Check!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_exception_flag(enum fm_mac_exceptions exception)
+{
+ u32 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 u32 get_mac_addr_hash_code(u64 eth_addr)
+{
+ u32 crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(eth_addr, crc);
+
+ crc = bitrev32(crc);
+
+ return crc;
+}
+
+static void tgec_err_exception(void *handle)
+{
+ struct tgec_t *tgec = (struct tgec_t *)handle;
+ u32 event;
+ struct tgec_regs __iomem *regs = tgec->regs;
+
+ /* do not handle MDIO events */
+ event = fman_tgec_get_event(regs,
+ ~(TGEC_IMASK_MDIO_SCAN_EVENT |
+ TGEC_IMASK_MDIO_CMD_CMPL));
+ event &= fman_tgec_get_interrupt_mask(regs);
+
+ fman_tgec_ack_event(regs, event);
+
+ if (event & TGEC_IMASK_REM_FAULT)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_REM_FAULT);
+ if (event & TGEC_IMASK_LOC_FAULT)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_LOC_FAULT);
+ if (event & TGEC_IMASK_TX_ECC_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ECC_ER);
+ if (event & TGEC_IMASK_TX_FIFO_UNFL)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_UNFL);
+ if (event & TGEC_IMASK_TX_FIFO_OVFL)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_OVFL);
+ if (event & TGEC_IMASK_TX_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ER);
+ if (event & TGEC_IMASK_RX_FIFO_OVFL)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FIFO_OVFL);
+ if (event & TGEC_IMASK_RX_ECC_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ECC_ER);
+ if (event & TGEC_IMASK_RX_JAB_FRM)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_JAB_FRM);
+ if (event & TGEC_IMASK_RX_OVRSZ_FRM)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_OVRSZ_FRM);
+ if (event & TGEC_IMASK_RX_RUNT_FRM)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_RUNT_FRM);
+ if (event & TGEC_IMASK_RX_FRAG_FRM)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FRAG_FRM);
+ if (event & TGEC_IMASK_RX_LEN_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_LEN_ER);
+ if (event & TGEC_IMASK_RX_CRC_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_CRC_ER);
+ if (event & TGEC_IMASK_RX_ALIGN_ER)
+ tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ALIGN_ER);
+}
+
+static void free_init_resources(struct tgec_t *tgec)
+{
+ fm_unregister_intr(tgec->fm, FM_MOD_MAC, tgec->mac_id,
+ FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ free_hash_table(tgec->multicast_addr_hash);
+ tgec->multicast_addr_hash = NULL;
+
+ /* release the driver's individual hash table */
+ free_hash_table(tgec->unicast_addr_hash);
+ tgec->unicast_addr_hash = NULL;
+}
+
+static bool is_init_done(struct tgec_cfg *tgec_drv_parameters)
+{
+ /* Checks if tGEC driver parameters were initialized */
+ if (!tgec_drv_parameters)
+ return true;
+
+ return false;
+}
+
+int tgec_enable(struct fm_mac_dev *fm_mac_dev, enum comm_mode mode)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ fman_tgec_enable(tgec->regs,
+ (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 *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ fman_tgec_disable(tgec->regs,
+ (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 *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ fman_tgec_set_promiscuous(tgec->regs, new_val);
+
+ return 0;
+}
+
+int tgec_cfg_max_frame_len(struct fm_mac_dev *fm_mac_dev, u16 new_val)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ tgec->tgec_drv_param->max_frame_length = new_val;
+
+ return 0;
+}
+
+int tgec_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ u8 __maybe_unused priority,
+ u16 pause_time,
+ u16 __maybe_unused thresh_time)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ fman_tgec_set_tx_pause_frames(tgec->regs, pause_time);
+
+ return 0;
+}
+
+int tgec_accept_rx_pause_frames(struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ fman_tgec_set_rx_ignore_pause_frames(tgec->regs, !en);
+
+ return 0;
+}
+
+int tgec_modify_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *p_enet_addr)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
+ fman_tgec_set_mac_address(tgec->regs, (u8 *)(*p_enet_addr));
+
+ return 0;
+}
+
+int tgec_add_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *hash_entry;
+ u32 crc;
+ u32 hash;
+ u64 addr;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ addr = ENET_ADDR_TO_UINT64(*eth_addr);
+
+ if (!(addr & GROUP_ADDRESS)) {
+ /* Unicast addresses not supported in hash */
+ pr_err("Unicast Address\n");
+ return -EINVAL;
+ }
+ /* CRC calculation */
+ crc = get_mac_addr_hash_code(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 */
+ hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+ if (!hash_entry)
+ return -ENOMEM;
+ hash_entry->addr = addr;
+ INIT_LIST_HEAD(&hash_entry->node);
+
+ list_add_tail(&hash_entry->node,
+ &tgec->multicast_addr_hash->lsts[hash]);
+ fman_tgec_set_hash_table(tgec->regs, (hash | TGEC_HASH_MCAST_EN));
+
+ return 0;
+}
+
+int tgec_del_hash_mac_address(struct fm_mac_dev *fm_mac_dev,
+ enet_addr_t *eth_addr)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+ struct eth_hash_entry_t *hash_entry = NULL;
+ struct list_head *p_pos;
+ u32 crc;
+ u32 hash;
+ u64 addr;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ addr = ((*(u64 *)eth_addr) >> 16);
+
+ /* CRC calculation */
+ crc = get_mac_addr_hash_code(addr);
+ /* Take 9 MSB bits */
+ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
+
+ list_for_each(p_pos, &tgec->multicast_addr_hash->lsts[hash]) {
+ hash_entry = ETH_HASH_ENTRY_OBJ(p_pos);
+ if (hash_entry->addr == addr) {
+ list_del_init(&hash_entry->node);
+ kfree(hash_entry);
+ break;
+ }
+ }
+ if (list_empty(&tgec->multicast_addr_hash->lsts[hash]))
+ fman_tgec_set_hash_table(tgec->regs,
+ (hash & ~TGEC_HASH_MCAST_EN));
+
+ return 0;
+}
+
+int tgec_get_version(struct fm_mac_dev *fm_mac_dev, u32 *mac_version)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ *mac_version = fman_tgec_get_revision(tgec->regs);
+
+ return 0;
+}
+
+int tgec_set_exception(struct fm_mac_dev *fm_mac_dev,
+ enum fm_mac_exceptions exception,
+ bool enable)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+ u32 bit_mask = 0;
+
+ if (!is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ bit_mask = get_exception_flag(exception);
+ if (bit_mask) {
+ if (enable)
+ tgec->exceptions |= bit_mask;
+ else
+ tgec->exceptions &= ~bit_mask;
+ } else {
+ pr_err("Undefined exception\n");
+ return -EINVAL;
+ }
+ if (enable)
+ fman_tgec_enable_interrupt(tgec->regs, bit_mask);
+ else
+ fman_tgec_disable_interrupt(tgec->regs, bit_mask);
+
+ return 0;
+}
+
+int tgec_init(struct fm_mac_dev *fm_mac_dev)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+ struct tgec_cfg *tgec_drv_param;
+ enet_addr_t eth_addr;
+ int err;
+
+ if (is_init_done(tgec->tgec_drv_param))
+ return -EINVAL;
+
+ if (DEFAULT_RESET_ON_INIT &&
+ (fm_reset_mac(tgec->fm, tgec->mac_id) != 0)) {
+ pr_err("Can't reset MAC!\n");
+ return -EINVAL;
+ }
+
+ fm_get_revision(tgec->fm, &tgec->fm_rev_info);
+ err = check_init_parameters(tgec);
+ if (err)
+ return err;
+
+ tgec_drv_param = tgec->tgec_drv_param;
+
+ MAKE_ENET_ADDR_FROM_UINT64(tgec->addr, eth_addr);
+ fman_tgec_set_mac_address(tgec->regs, (u8 *)eth_addr);
+
+ /* interrupts */
+ /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 Errata workaround */
+ if (tgec->fm_rev_info.major_rev <= 2)
+ tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT |
+ TGEC_IMASK_LOC_FAULT);
+
+ err = fman_tgec_init(tgec->regs, tgec_drv_param, tgec->exceptions);
+ if (err) {
+ free_init_resources(tgec);
+ pr_err("TGEC version doesn't support this i/f mode\n");
+ return err;
+ }
+
+ /* Max Frame Length */
+ err = fm_set_mac_max_frame(tgec->fm, FM_MAC_10G, tgec->mac_id,
+ tgec_drv_param->max_frame_length);
+ if (err) {
+ pr_err("Setting max frame length FAILED\n");
+ free_init_resources(tgec);
+ return -EINVAL;
+ }
+
+ /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 Errata workaround */
+ if (tgec->fm_rev_info.major_rev == 2)
+ fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(tgec->
+ regs);
+
+ tgec->multicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
+ if (!tgec->multicast_addr_hash) {
+ free_init_resources(tgec);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ tgec->unicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
+ if (!tgec->unicast_addr_hash) {
+ free_init_resources(tgec);
+ pr_err("allocation hash table is FAILED\n");
+ return -ENOMEM;
+ }
+
+ fm_register_intr(tgec->fm, FM_MOD_MAC, tgec->mac_id,
+ FM_INTR_TYPE_ERR, tgec_err_exception, tgec);
+
+ kfree(tgec_drv_param);
+ tgec->tgec_drv_param = NULL;
+
+ return 0;
+}
+
+int tgec_free(struct fm_mac_dev *fm_mac_dev)
+{
+ struct tgec_t *tgec = (struct tgec_t *)fm_mac_dev;
+
+ free_init_resources(tgec);
+
+ if (tgec->tgec_drv_param)
+ tgec->tgec_drv_param = NULL;
+
+ kfree(tgec->tgec_drv_param);
+ kfree(tgec);
+
+ return 0;
+}
+
+void *tgec_config(struct fm_mac_params_t *fm_mac_param)
+{
+ struct tgec_t *tgec;
+ struct tgec_cfg *tgec_drv_param;
+ void __iomem *base_addr;
+
+ base_addr = fm_mac_param->base_addr;
+ /* allocate memory for the UCC GETH data structure. */
+ tgec = kzalloc(sizeof(*tgec), GFP_KERNEL);
+ if (!tgec)
+ return NULL;
+
+ /* allocate memory for the 10G MAC driver parameters data structure. */
+ tgec_drv_param = kzalloc(sizeof(*tgec_drv_param), GFP_KERNEL);
+ if (!tgec_drv_param) {
+ tgec_free((struct fm_mac_dev *)tgec);
+ return NULL;
+ }
+
+ /* Plant parameter structure pointer */
+ tgec->tgec_drv_param = tgec_drv_param;
+
+ fman_tgec_defconfig(tgec_drv_param);
+
+ tgec->regs = (struct tgec_regs __iomem *)(base_addr);
+ tgec->addr = ENET_ADDR_TO_UINT64(fm_mac_param->addr);
+ tgec->enet_mode = fm_mac_param->enet_mode;
+ tgec->mac_id = fm_mac_param->mac_id;
+ tgec->exceptions = TGEC_DEFAULT_EXCEPTIONS;
+ tgec->exception_cb = fm_mac_param->exception_cb;
+ tgec->event_cb = fm_mac_param->event_cb;
+ tgec->dev_id = fm_mac_param->dev_id;
+ tgec->fm = fm_mac_param->fm;
+
+ /* Save FMan revision */
+ fm_get_revision(tgec->fm, &tgec->fm_rev_info);
+
+ return 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..764a465
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/fm_tgec.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.
+ */
+
+#ifndef __TGEC_H
+#define __TGEC_H
+
+#include "enet_ext.h"
+
+#include "fm_mac.h"
+
+#define TGEC_DEFAULT_EXCEPTIONS \
+ ((u32)((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 *regs;
+ /* MAC address of device; */
+ u64 addr;
+ /* Ethernet physical interface */
+ enum e_enet_mode enet_mode;
+ void *dev_id; /* device cookie used by the exception cbs */
+ fm_mac_exception_cb *exception_cb;
+ fm_mac_exception_cb *event_cb;
+ /* 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
+ */
+ u64 paddr[TGEC_NUM_OF_PADDRS];
+ /* Number of individual addresses in registers for this station. */
+ u8 num_of_ind_addr_in_regs;
+ /* pointer to driver's global address hash table */
+ struct eth_hash_t *multicast_addr_hash;
+ /* pointer to driver's individual address hash table */
+ struct eth_hash_t *unicast_addr_hash;
+ bool debug_mode;
+ u8 mac_id;
+ u32 exceptions;
+ struct tgec_cfg *tgec_drv_param;
+ void *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, u16 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, u8 priority,
+ u16 pause_time, u16 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, u32 *mac_version);
+
+#endif /* __TGEC_H */
--
1.7.9.5

2015-08-05 13:44:04

by Liberman Igal

[permalink] [raw]
Subject: [v4, 7/9] fsl/fman: Add FMan SP support

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 | 105 ++++++
drivers/net/ethernet/freescale/fman/sp/Makefile | 3 +
drivers/net/ethernet/freescale/fman/sp/fm_sp.c | 371 ++++++++++++++++++++
4 files changed, 481 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..56bd749
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_sp_common.h
@@ -0,0 +1,105 @@
+/*
+ * 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 "fm_ext.h"
+#include "fsl_fman.h"
+
+#define ILLEGAL_BASE (~0)
+
+/* 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).
+ */
+ u16 ext_buf_offset;
+ /* Offset within internal context to copy from
+ * (Rx) or to copy to (Tx, Op).
+ */
+ u8 int_context_offset;
+ /* Internal offset size to be copied */
+ u16 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)
+ */
+ u16 start_margins;
+ /* number of bytes to be left at the end
+ * of the external buffer(must be divisible by 16)
+ */
+ u16 end_margins;
+};
+
+struct fm_sp_buffer_offsets_t {
+ u32 data_offset;
+ u32 prs_result_offset;
+ u32 time_stamp_offset;
+ u32 hash_result_offset;
+};
+
+int fm_sp_build_buffer_structure(struct fm_sp_int_context_data_copy_t
+ *fm_port_int_context_data_copy,
+ struct fm_buffer_prefix_content_t
+ *buffer_prefix_content,
+ struct fm_sp_buf_margins_t
+ *fm_port_buf_margins,
+ struct fm_sp_buffer_offsets_t
+ *fm_port_buffer_offsets,
+ u8 *internal_buf_offset);
+
+int fm_sp_check_int_context_params(struct fm_sp_int_context_data_copy_t *
+ fm_sp_int_context_data_copy);
+int fm_sp_check_buf_pools_params(struct fm_ext_pools_t *fm_ext_pools,
+ struct fm_backup_bm_pools_t
+ *fm_backup_bm_pools,
+ struct fm_buf_pool_depletion_t
+ *fm_buf_pool_depletion,
+ u32 max_num_of_ext_pools,
+ u32 bm_max_num_of_pools);
+int fm_sp_check_buf_margins(struct fm_sp_buf_margins_t *fm_sp_buf_margins);
+void fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fm_ext_pools_t
+ *fm_ext_pools,
+ u8 *ordered_array,
+ u16 *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..773dcbd
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/sp/fm_sp.c
@@ -0,0 +1,371 @@
+/*
+ * 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 "fm_sp_common.h"
+#include "fm_common.h"
+#include "fsl_fman_sp.h"
+
+#include <linux/string.h>
+
+void fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fm_ext_pools_t
+ *fm_ext_pools,
+ u8 *ordered_array,
+ u16 *sizes_array)
+{
+ u16 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 < fm_ext_pools->num_of_pools_used; i++) {
+ /* get pool size */
+ buf_size = fm_ext_pools->ext_buf_pool[i].size;
+
+ /* keep sizes in an array according to poolId
+ * for direct access
+ */
+ sizes_array[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] =
+ 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] =
+ fm_ext_pools->ext_buf_pool[i].id;
+ break;
+ }
+ }
+ }
+ }
+}
+
+int fm_sp_check_buf_pools_params(struct fm_ext_pools_t *fm_ext_pools,
+ struct fm_backup_bm_pools_t
+ *fm_backup_bm_pools,
+ struct fm_buf_pool_depletion_t
+ *fm_buf_pool_depletion,
+ u32 max_num_of_ext_pools,
+ u32 bm_max_num_of_pools)
+{
+ int i = 0, j = 0;
+ bool found;
+ u8 count = 0;
+
+ if (fm_ext_pools) {
+ if (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 -EINVAL;
+ }
+ for (i = 0; i < fm_ext_pools->num_of_pools_used; i++) {
+ if (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 -EINVAL;
+ }
+ if (!fm_ext_pools->ext_buf_pool[i].size) {
+ pr_err("ext_buf_pools.ext_buf_pool[%d].size is 0\n",
+ i);
+ return -EINVAL;
+ }
+ }
+ }
+ if (!fm_ext_pools && (fm_backup_bm_pools || fm_buf_pool_depletion)) {
+ pr_err("backup_bm_pools ot buf_pool_depletion can not be defined without external pools\n");
+ return -EINVAL;
+ }
+ /* backup BM pools indication is valid only for some chip derivatives
+ * (limited by the config routine)
+ */
+ if (fm_backup_bm_pools) {
+ if (fm_backup_bm_pools->num_of_backup_pools >=
+ fm_ext_pools->num_of_pools_used) {
+ pr_err("backup_bm_pools must be smaller than ext_buf_pools.num_of_pools_used\n");
+ return -EINVAL;
+ }
+ found = false;
+ for (i = 0; i < fm_backup_bm_pools->num_of_backup_pools; i++) {
+ for (j = 0; j < fm_ext_pools->num_of_pools_used; j++) {
+ if (fm_backup_bm_pools->pool_ids[i] ==
+ fm_ext_pools->ext_buf_pool[j].id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("All backup_bm_pools.pool_ids must be included in ext_buf_pools.ext_buf_pool[n].id\n");
+ return -EINVAL;
+ }
+ found = false;
+ }
+ }
+
+ /* up to ext_buf_pools.num_of_pools_used pools may be defined */
+ if (fm_buf_pool_depletion && fm_buf_pool_depletion->
+ pools_grp_mode_enable) {
+ if ((fm_buf_pool_depletion->num_of_pools >
+ 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 -EINVAL;
+ }
+ if (!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 -EINVAL;
+ }
+ 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 (fm_buf_pool_depletion->pools_to_consider[i]) {
+ for (j = 0; j < fm_ext_pools->num_of_pools_used;
+ j++) {
+ if (i == 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 != 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 -EINVAL;
+ }
+ }
+
+ if (fm_buf_pool_depletion && 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 (fm_buf_pool_depletion->
+ pools_to_consider_for_single_mode[i]) {
+ for (j = 0; j < fm_ext_pools->num_of_pools_used;
+ j++) {
+ if (i == 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 -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int fm_sp_check_int_context_params(struct fm_sp_int_context_data_copy_t *
+ fm_sp_int_context_data_copy)
+{
+ /* Check that divisible by 16 and not larger than 240 */
+ if (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 -EINVAL;
+ }
+ if (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 -EINVAL;
+ }
+ /* check that ic size+ic internal offset, does not exceed
+ * ic block size
+ */
+ if (fm_sp_int_context_data_copy->size +
+ 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 -EINVAL;
+ }
+ /* Check that divisible by 16 and not larger than 256 */
+ if (fm_sp_int_context_data_copy->size % OFFSET_UNITS) {
+ pr_err("int_context.size has to be divisible by %d\n",
+ OFFSET_UNITS);
+ return -EINVAL;
+ }
+ /* Check that divisible by 16 and not larger than 4K */
+ if (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 -EINVAL;
+ }
+ if (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 -EINVAL;
+ }
+ return 0;
+}
+
+int fm_sp_check_buf_margins(struct fm_sp_buf_margins_t *fm_sp_buf_margins)
+{
+ /* Check the margin definition */
+ if (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 -EINVAL;
+ }
+ if (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 -EINVAL;
+ }
+ return 0;
+}
+
+int fm_sp_build_buffer_structure(struct fm_sp_int_context_data_copy_t *
+ fm_sp_int_context_data_copy,
+ struct fm_buffer_prefix_content_t *
+ buffer_prefix_content,
+ struct fm_sp_buf_margins_t
+ *fm_sp_buf_margins,
+ struct fm_sp_buffer_offsets_t
+ *fm_sp_buffer_offsets,
+ u8 *internal_buf_offset)
+{
+ u32 tmp;
+
+ /* Align start of internal context data to 16 byte */
+ fm_sp_int_context_data_copy->ext_buf_offset = (u16)
+ ((buffer_prefix_content->priv_data_size & (OFFSET_UNITS - 1)) ?
+ ((buffer_prefix_content->priv_data_size + OFFSET_UNITS) &
+ ~(u16)(OFFSET_UNITS - 1)) :
+ 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. */
+ fm_sp_buffer_offsets->prs_result_offset = (u32)ILLEGAL_BASE;
+ fm_sp_buffer_offsets->time_stamp_offset = (u32)ILLEGAL_BASE;
+ fm_sp_buffer_offsets->hash_result_offset = (u32)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. */
+ fm_sp_int_context_data_copy->size =
+ (u16)((buffer_prefix_content->pass_prs_result ? 32 : 0) +
+ ((buffer_prefix_content->pass_time_stamp ||
+ buffer_prefix_content->pass_hash_result) ? 16 : 0));
+
+ /* Align start of internal context data to 16 byte */
+ fm_sp_int_context_data_copy->int_context_offset =
+ (u8)(buffer_prefix_content->pass_prs_result ? 32 :
+ ((buffer_prefix_content->pass_time_stamp ||
+ buffer_prefix_content->pass_hash_result) ? 64 : 0));
+
+ if (buffer_prefix_content->pass_prs_result)
+ fm_sp_buffer_offsets->prs_result_offset =
+ fm_sp_int_context_data_copy->ext_buf_offset;
+ if (buffer_prefix_content->pass_time_stamp)
+ fm_sp_buffer_offsets->time_stamp_offset =
+ buffer_prefix_content->pass_prs_result ?
+ (fm_sp_int_context_data_copy->ext_buf_offset +
+ sizeof(struct fm_prs_result_t)) :
+ fm_sp_int_context_data_copy->ext_buf_offset;
+ if (buffer_prefix_content->pass_hash_result)
+ /* If PR is not requested, whether TS is
+ * requested or not, IC will be copied from TS
+ */
+ fm_sp_buffer_offsets->hash_result_offset =
+ buffer_prefix_content->pass_prs_result ?
+ (fm_sp_int_context_data_copy->ext_buf_offset +
+ sizeof(struct fm_prs_result_t) + 8) :
+ fm_sp_int_context_data_copy->ext_buf_offset + 8;
+
+ if (fm_sp_int_context_data_copy->size)
+ fm_sp_buf_margins->start_margins =
+ (u16)(fm_sp_int_context_data_copy->ext_buf_offset +
+ fm_sp_int_context_data_copy->size);
+ else
+ /* No Internal Context passing, STartMargin is
+ * immediately after private_info
+ */
+ fm_sp_buf_margins->start_margins =
+ buffer_prefix_content->priv_data_size;
+
+ /* align data start */
+ tmp = (u32)(fm_sp_buf_margins->start_margins %
+ buffer_prefix_content->data_align);
+ if (tmp)
+ fm_sp_buf_margins->start_margins +=
+ (buffer_prefix_content->data_align - tmp);
+ fm_sp_buffer_offsets->data_offset = fm_sp_buf_margins->start_margins;
+
+ return 0;
+}
+
--
1.7.9.5

2015-08-05 13:45:07

by Liberman Igal

[permalink] [raw]
Subject: [v4, 8/9] fsl/fman: Add FMan Port Support

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 | 251 ++++-
drivers/net/ethernet/freescale/fman/fm_common.h | 35 +
drivers/net/ethernet/freescale/fman/fm_drv.c | 72 +-
drivers/net/ethernet/freescale/fman/fm_drv.h | 2 +
drivers/net/ethernet/freescale/fman/fm_port_drv.c | 372 +++++++
.../net/ethernet/freescale/fman/inc/fm_port_ext.h | 340 ++++++
.../net/ethernet/freescale/fman/inc/fsl_fman_drv.h | 104 ++
drivers/net/ethernet/freescale/fman/port/Makefile | 2 +-
drivers/net/ethernet/freescale/fman/port/fm_port.c | 1081 ++++++++++++++++++++
drivers/net/ethernet/freescale/fman/port/fm_port.h | 502 +++++++++
11 files changed, 2759 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 450ee6b..a8ecf0b 100644
--- a/drivers/net/ethernet/freescale/fman/fm.c
+++ b/drivers/net/ethernet/freescale/fman/fm.c
@@ -376,11 +376,29 @@ static void qmi_err_event(struct fm_t *fm)

static void dma_err_event(struct fm_t *fm)
{
- u32 status;
+ u32 status, com_id;
+ u8 tnum, port_id, relative_port_id;
+ u16 liodn;
struct fman_dma_regs __iomem *dma_rg = 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 = (u8)(((com_id & DMA_TRANSFER_PORTID_MASK) >>
+ DMA_TRANSFER_PORTID_SHIFT));
+ relative_port_id =
+ hw_port_id_to_sw_port_id(fm->fm_state->rev_info.major_rev,
+ port_id);
+ tnum = (u8)((com_id & DMA_TRANSFER_TNUM_MASK) >>
+ DMA_TRANSFER_TNUM_SHIFT);
+ liodn = (u16)(com_id & DMA_TRANSFER_LIODN_MASK);
+ WARN_ON(fm->fm_state->ports_types[port_id] ==
+ FM_PORT_TYPE_DUMMY);
+ fm->bus_error_cb(fm->dev_id, fm->fm_state->ports_types[port_id],
+ relative_port_id,
+ fman_get_dma_addr(dma_rg), tnum, liodn);
+ }
if (status & DMA_STATUS_FM_SPDAT_ECC)
fm->exception_cb(fm->dev_id, FM_EX_DMA_SINGLE_PORT_ECC);
if (status & DMA_STATUS_READ_ECC)
@@ -587,6 +605,233 @@ u8 fm_get_id(struct fm_t *fm)
return fm->fm_state->fm_id;
}

+int fm_get_set_port_params(struct fm_t *fm,
+ struct fm_inter_module_port_init_params_t
+ *port_params)
+{
+ int err;
+ unsigned long int_flags;
+ u8 port_id = port_params->port_id, mac_id;
+ struct fman_rg fman_rg;
+
+ fman_rg.bmi_rg = fm->bmi_regs;
+ fman_rg.qmi_rg = fm->qmi_regs;
+ fman_rg.fpm_rg = fm->fpm_regs;
+ fman_rg.dma_rg = fm->dma_regs;
+
+ spin_lock_irqsave(&fm->spinlock, int_flags);
+
+ fm->fm_state->ports_types[port_id] = port_params->port_type;
+
+ err = fm_set_num_of_tasks(fm, port_params->port_id,
+ &port_params->num_of_tasks,
+ &port_params->num_of_extra_tasks);
+ if (err) {
+ spin_unlock_irqrestore(&fm->spinlock, int_flags);
+ return err;
+ }
+
+ /* TX Ports */
+ if (port_params->port_type != FM_PORT_TYPE_RX) {
+ u32 enq_th;
+ u32 deq_th;
+
+ /* update qmi ENQ/DEQ threshold */
+ fm->fm_state->accumulated_num_of_deq_tnums +=
+ 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 >= (fm->intg->qmi_max_num_of_tnums -
+ fm->fm_state->accumulated_num_of_deq_tnums)) {
+ enq_th =
+ fm->intg->qmi_max_num_of_tnums -
+ fm->fm_state->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
+ * (fm->intg->qmi_max_num_of_tnums-1).
+ */
+ if ((deq_th <= fm->fm_state->accumulated_num_of_deq_tnums) &&
+ (deq_th < fm->intg->qmi_max_num_of_tnums - 1)) {
+ deq_th =
+ fm->fm_state->accumulated_num_of_deq_tnums + 1;
+ fman_set_qmi_deq_th(fman_rg.qmi_rg, deq_th);
+ }
+ }
+
+ err = fm_set_size_of_fifo(fm, port_params->port_id,
+ &port_params->size_of_fifo,
+ &port_params->extra_size_of_fifo);
+ if (err) {
+ spin_unlock_irqrestore(&fm->spinlock, int_flags);
+ return err;
+ }
+
+ err = fm_set_num_of_open_dmas(fm, port_params->port_id,
+ &port_params->num_of_open_dmas,
+ &port_params->num_of_extra_open_dmas);
+ if (err) {
+ spin_unlock_irqrestore(&fm->spinlock, int_flags);
+ return err;
+ }
+
+ fman_set_liodn_per_port(&fman_rg, port_id, port_params->liodn_base,
+ port_params->liodn_offset);
+
+ if (fm->fm_state->rev_info.major_rev < 6)
+ fman_set_order_restoration_per_port(fman_rg.fpm_rg,
+ port_id,
+ !!((port_params->
+ port_type ==
+ FM_PORT_TYPE_RX)));
+
+ mac_id = hw_port_id_to_sw_port_id(fm->fm_state->rev_info.
+ major_rev,
+ port_id);
+
+ if (port_params->max_frame_length >= fm->fm_state->mac_mfl[mac_id]) {
+ fm->fm_state->port_mfl[mac_id] = port_params->max_frame_length;
+ } else {
+ pr_warn("Port max_frame_length is smaller than MAC current MTU\n");
+ spin_unlock_irqrestore(&fm->spinlock, int_flags);
+ return -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&fm->spinlock, int_flags);
+
+ return 0;
+}
+
+int fm_set_size_of_fifo(struct fm_t *fm, u8 port_id, u32 *size_of_fifo,
+ u32 *extra_size_of_fifo)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = fm->bmi_regs;
+ u32 fifo = *size_of_fifo;
+ u32 extra_fifo = *extra_size_of_fifo;
+
+ /* 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
+ */
+ if (extra_fifo && !fm->fm_state->extra_fifo_pool_size)
+ fm->fm_state->extra_fifo_pool_size =
+ fm->intg->num_of_rx_ports * BMI_FIFO_UNITS;
+
+ fm->fm_state->extra_fifo_pool_size =
+ max(fm->fm_state->extra_fifo_pool_size, extra_fifo);
+
+ /* check that there are enough uncommitted fifo size */
+ if ((fm->fm_state->accumulated_fifo_size + fifo) >
+ (fm->fm_state->total_fifo_size -
+ fm->fm_state->extra_fifo_pool_size)) {
+ pr_err("Requested fifo size and extra size exceed total FIFO size.\n");
+ return -EAGAIN;
+ }
+ /* update accumulated */
+ fm->fm_state->accumulated_fifo_size += fifo;
+ fman_set_size_of_fifo(bmi_rg, port_id, fifo, extra_fifo);
+
+ return 0;
+}
+
+int fm_set_num_of_tasks(struct fm_t *fm, u8 port_id, u8 *num_of_tasks,
+ u8 *num_of_extra_tasks)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = fm->bmi_regs;
+ u8 tasks = *num_of_tasks;
+ u8 extra_tasks = *num_of_extra_tasks;
+
+ if (extra_tasks)
+ fm->fm_state->extra_tasks_pool_size =
+ (u8)max(fm->fm_state->extra_tasks_pool_size, extra_tasks);
+
+ /* check that there are enough uncommitted tasks */
+ if ((fm->fm_state->accumulated_num_of_tasks + tasks) >
+ (fm->fm_state->total_num_of_tasks -
+ fm->fm_state->extra_tasks_pool_size)) {
+ pr_err("Requested num_of_tasks and extra tasks pool for fm%d exceed total num_of_tasks.\n",
+ fm->fm_state->fm_id);
+ return -EAGAIN;
+ }
+ /* update accumulated */
+ fm->fm_state->accumulated_num_of_tasks += tasks;
+ fman_set_num_of_tasks(bmi_rg, port_id, tasks, extra_tasks);
+
+ return 0;
+}
+
+int fm_set_num_of_open_dmas(struct fm_t *fm, u8 port_id, u8 *num_of_open_dmas,
+ u8 *num_of_extra_open_dmas)
+{
+ struct fman_bmi_regs __iomem *bmi_rg = fm->bmi_regs;
+ u8 open_dmas = *num_of_open_dmas;
+ u8 extra_open_dmas = *num_of_extra_open_dmas;
+ u8 total_num_dmas = 0, current_val = 0, current_extra_val = 0;
+
+ if (!open_dmas) {
+ /* !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 (!open_dmas), reset values will be used
+ * and we just save these values for resource management
+ */
+ fm->fm_state->extra_open_dmas_pool_size =
+ (u8)max(fm->fm_state->extra_open_dmas_pool_size,
+ current_extra_val);
+ fm->fm_state->accumulated_num_of_open_dmas += current_val;
+ *num_of_open_dmas = current_val;
+ *num_of_extra_open_dmas = current_extra_val;
+ return 0;
+ }
+
+ if (extra_open_dmas > current_extra_val)
+ fm->fm_state->extra_open_dmas_pool_size =
+ (u8)max(fm->fm_state->extra_open_dmas_pool_size,
+ extra_open_dmas);
+
+ if ((fm->fm_state->rev_info.major_rev < 6) &&
+ (fm->fm_state->accumulated_num_of_open_dmas - current_val +
+ open_dmas > fm->fm_state->max_num_of_open_dmas)) {
+ pr_err("Requested num_of_open_dmas for fm%d exceeds total num_of_open_dmas.\n",
+ fm->fm_state->fm_id);
+ return -EAGAIN;
+ } else if ((fm->fm_state->rev_info.major_rev >= 6) &&
+ !((fm->fm_state->rev_info.major_rev == 6) &&
+ (fm->fm_state->rev_info.minor_rev == 0)) &&
+ (fm->fm_state->accumulated_num_of_open_dmas -
+ current_val + open_dmas >
+ fm->intg->dma_thresh_max_commq + 1)) {
+ pr_err("Requested num_of_open_dmas for fm%d exceeds DMA Command queue (%d)\n",
+ fm->fm_state->fm_id, fm->intg->dma_thresh_max_commq + 1);
+ return -EAGAIN;
+ }
+
+ WARN_ON(fm->fm_state->accumulated_num_of_open_dmas < current_val);
+ /* update acummulated */
+ fm->fm_state->accumulated_num_of_open_dmas -= current_val;
+ fm->fm_state->accumulated_num_of_open_dmas += open_dmas;
+
+ if (fm->fm_state->rev_info.major_rev < 6)
+ total_num_dmas =
+ (u8)(fm->fm_state->accumulated_num_of_open_dmas +
+ fm->fm_state->extra_open_dmas_pool_size);
+
+ fman_set_num_of_open_dmas(bmi_rg, port_id, open_dmas,
+ extra_open_dmas, total_num_dmas);
+
+ return 0;
+}
+
int fm_reset_mac(struct fm_t *fm, u8 mac_id)
{
int err;
@@ -690,6 +935,7 @@ static int init_fm_dma(struct fm_t *fm)
void *fm_config(struct fm_params_t *fm_param)
{
struct fm_t *fm;
+ u8 i;
void __iomem *base_addr;

base_addr = fm_param->base_addr;
@@ -706,6 +952,9 @@ void *fm_config(struct fm_params_t *fm_param)
/* Initialize FM parameters which will be kept by the driver */
fm->fm_state->fm_id = fm_param->fm_id;

+ for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS; i++)
+ fm->fm_state->ports_types[i] = FM_PORT_TYPE_DUMMY;
+
/* Allocate the FM driver's parameters structure */
fm->fm_drv_param = kzalloc(sizeof(*fm->fm_drv_param), GFP_KERNEL);
if (!fm->fm_drv_param)
diff --git a/drivers/net/ethernet/freescale/fman/fm_common.h b/drivers/net/ethernet/freescale/fman/fm_common.h
index abe89a7..ae51553 100644
--- a/drivers/net/ethernet/freescale/fman/fm_common.h
+++ b/drivers/net/ethernet/freescale/fman/fm_common.h
@@ -120,6 +120,30 @@ enum fm_mac_type {
FM_MAC_1G /* 1G MAC */
};

+/* 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 {
+ u8 port_id; /* IN. port Id */
+ enum fm_port_type port_type; /* IN. Port type */
+ enum fm_port_speed port_speed; /* IN. Port speed */
+ u16 liodn_offset; /* IN. Port's requested resource */
+ u8 num_of_tasks; /* IN. Port's requested resource */
+ u8 num_of_extra_tasks; /* IN. Port's requested resource */
+ u8 num_of_open_dmas; /* IN. Port's requested resource */
+ u8 num_of_extra_open_dmas; /* IN. Port's requested resource */
+ u32 size_of_fifo; /* IN. Port's requested resource */
+ u32 extra_size_of_fifo; /* IN. Port's requested resource */
+ u8 deq_pipeline_depth; /* IN. Port's requested resource */
+ u16 max_frame_length; /* IN. Port's max frame length. */
+ u16 liodn_base;
+ /* LIODN base for this port, to be used together with LIODN offset. */
+};
+
void fm_register_intr(struct fm_t *fm, enum fm_event_modules mod, u8 mod_id,
enum fm_intr_type intr_type,
void (*f_isr)(void *h_src_arg), void *h_src_arg);
@@ -135,6 +159,17 @@ u16 fm_get_clock_freq(struct fm_t *fm);

u8 fm_get_id(struct fm_t *fm);

+int fm_get_set_port_params(struct fm_t *fm,
+ struct fm_inter_module_port_init_params_t
+ *port_params);
+
+int fm_set_num_of_open_dmas(struct fm_t *fm, u8 port_id, u8 *num_of_open_dmas,
+ u8 *num_of_extra_open_dmas);
+int fm_set_num_of_tasks(struct fm_t *fm, u8 port_id, u8 *num_of_tasks,
+ u8 *num_of_extra_tasks);
+int fm_set_size_of_fifo(struct fm_t *fm, u8 port_id, u32 *size_of_fifo,
+ u32 *extra_size_of_fifo);
+
u32 fm_get_bmi_max_fifo_size(struct fm_t *fm);

int fm_set_mac_max_frame(struct fm_t *fm, enum fm_mac_type type, u8 mac_id,
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.c b/drivers/net/ethernet/freescale/fman/fm_drv.c
index 63b5ae1..424068a 100644
--- a/drivers/net/ethernet/freescale/fman/fm_drv.c
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.c
@@ -144,6 +144,51 @@ static irqreturn_t fm_err_irq(int irq, void *fm_dev)
return IRQ_NONE;
}

+static int fill_rest_fm_info(struct fm_drv_t *fm_drv)
+{
+#define FM_BMI_PPIDS_OFFSET 0x00080304
+#define FM_DMA_PLR_OFFSET 0x000c2060
+#define DMA_HIGH_LIODN_MASK 0x0FFF0000
+#define DMA_LOW_LIODN_MASK 0x00000FFF
+#define DMA_LIODN_SHIFT 16
+
+ struct plr_t {
+ u32 plr[32];
+ };
+
+ struct ppids_t {
+ u32 fmbm_ppid[63];
+ };
+
+ struct plr_t *p_plr;
+ struct ppids_t __iomem *p_ppids;
+ int i;
+
+ p_plr = (struct plr_t *)(fm_drv->fm_base_addr + FM_DMA_PLR_OFFSET);
+
+ for (i = 0; i < FM_MAX_NUM_OF_PARTITIONS; i++) {
+ u16 liodn_base;
+
+ liodn_base = (u16)((i % 2) ?
+ (p_plr->plr[i / 2] & DMA_LOW_LIODN_MASK) :
+ ((p_plr->plr[i / 2] & DMA_HIGH_LIODN_MASK) >>
+ DMA_LIODN_SHIFT));
+
+ if (((i >= FIRST_RX_PORT) && (i <= LAST_RX_PORT)) ||
+ ((i >= FIRST_TX_PORT) && (i <= LAST_TX_PORT)))
+ fm_drv->ports[i].port_params.liodn_base = liodn_base;
+ }
+
+ p_ppids = (struct ppids_t __iomem *)
+ (fm_drv->fm_base_addr + FM_BMI_PPIDS_OFFSET);
+
+ for (i = FIRST_RX_PORT; i <= LAST_RX_PORT; i++)
+ fm_drv->ports[i].port_params.specific_params.rx_params.
+ liodn_offset = (u16)ioread32be(&p_ppids->fmbm_ppid[i - 1]);
+
+ return 0;
+}
+
static int fill_qman_channels_info(struct fm_drv_t *fm_drv)
{
fm_drv->qman_channels = kcalloc(fm_drv->num_of_qman_channels,
@@ -410,7 +455,7 @@ static int configure_fm_dev(struct fm_drv_t *fm_drv)
fm_drv->params.bus_error_cb = fm_drv_bus_error_cb;
fm_drv->params.dev_id = fm_drv;

- return 0;
+ return fill_rest_fm_info(fm_drv);
}

static int init_fm_dev(struct fm_drv_t *fm_drv)
@@ -532,6 +577,31 @@ void *fm_get_handle(struct fm *fm)
return (void *)fm_drv->fm_dev;
}

+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)));
+}
+
+struct fm_port_t *fm_port_drv_handle(const struct fm_port_drv_t *port)
+{
+ return port->fm_port;
+}
+EXPORT_SYMBOL(fm_port_drv_handle);
+
+void fm_port_get_buff_layout_ext_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params)
+{
+ params->data_align = 0;
+}
+EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params);
+
+int fm_get_tx_port_channel(struct fm_port_drv_t *port)
+{
+ return port->tx_ch;
+}
+EXPORT_SYMBOL(fm_get_tx_port_channel);
+
static const struct of_device_id fm_match[] = {
{
.compatible = "fsl,fman"},
diff --git a/drivers/net/ethernet/freescale/fman/fm_drv.h b/drivers/net/ethernet/freescale/fman/fm_drv.h
index 73d9eff..298a9b96 100644
--- a/drivers/net/ethernet/freescale/fman/fm_drv.h
+++ b/drivers/net/ethernet/freescale/fman/fm_drv.h
@@ -36,6 +36,7 @@
#include <asm/mpc85xx.h>

#include "fsl_fman_drv.h"
+#include "fm_port_ext.h"

#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE
#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0
@@ -69,6 +70,7 @@ struct fm_port_drv_t {
phys_addr_t phys_base_addr;
void __iomem *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 *fm_port;
struct fm_drv_t *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..30d78cc
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/fm_port_drv.c
@@ -0,0 +1,372 @@
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/io.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 *fm_drv;
+ struct fm_port_drv_t *port;
+ struct device_node *fm_node, *port_node;
+ struct resource res;
+ const u32 *u32_prop;
+ int err = 0, lenp;
+ enum fm_port_type port_type;
+ enum fm_port_speed port_speed = FM_PORT_SPEED_DUMMY;
+ 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 (!fm_node) {
+ pr_err("of_get_parent() = %d\n", err);
+ return NULL;
+ }
+
+ fm_drv = 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 (!fm_drv)
+ return NULL;
+
+ u32_prop = (u32 *)of_get_property(port_node, "cell-index", &lenp);
+ if (!u32_prop) {
+ pr_err("of_get_property(%s, cell-index) failed\n",
+ port_node->full_name);
+ return NULL;
+ }
+ if (WARN_ON(lenp != sizeof(u32)))
+ return NULL;
+ cell_index = (u8)*u32_prop;
+
+ port = &fm_drv->ports[cell_index];
+ port->id = cell_index;
+ port->port_params.port_id = port->id;
+
+ if (of_device_is_compatible(port_node, "fsl,fman-v3-port-tx")) {
+ port_type = FM_PORT_TYPE_TX;
+ port_speed = FM_PORT_SPEED_1G;
+ u32_prop = (u32 *)of_get_property(port_node,
+ "fsl,fman-10g-port", &lenp);
+ if (u32_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;
+ u32_prop = (u32 *)of_get_property(port_node,
+ "fsl,fman-10g-port", &lenp);
+ if (u32_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;
+ }
+
+ port->port_params.port_type = port_type;
+ port->port_params.port_speed = port_speed;
+
+ if (port_type == FM_PORT_TYPE_TX) {
+ u32 qman_channel_id;
+
+ qman_channel_id = get_qman_channel_id(fm_drv, cell_index);
+
+ if (qman_channel_id == 0) {
+ pr_err("incorrect qman-channel-id\n");
+ return NULL;
+ }
+ port->tx_ch = qman_channel_id;
+ port->port_params.specific_params.non_rx_params.qm_channel =
+ qman_channel_id;
+ }
+
+ err = of_address_to_resource(port_node, 0, &res);
+ if (err < 0) {
+ pr_err("of_address_to_resource() = %d\n", err);
+ return NULL;
+ }
+
+ port->dev = &of_dev->dev;
+ port->base_addr = 0;
+ port->phys_base_addr = res.start;
+ port->mem_size = res.end + 1 - res.start;
+ port->port_params.fm = fm_drv->fm_dev;
+ port->fm = (void *)fm_drv;
+
+ of_node_put(port_node);
+
+ port->active = true;
+
+ return port;
+}
+
+static int configure_fm_port_dev(struct fm_port_drv_t *port)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)port->fm;
+ struct resource *dev_res;
+
+ if (!port->active) {
+ pr_err("FM port not configured!!!\n");
+ return -EINVAL;
+ }
+
+ dev_res = __devm_request_region(fm_drv->dev, fm_drv->res,
+ port->phys_base_addr,
+ port->mem_size,
+ "fman-port-hc");
+ if (!dev_res) {
+ pr_err("__devm_request_region() failed\n");
+ return -EINVAL;
+ }
+ port->base_addr = devm_ioremap(fm_drv->dev, port->phys_base_addr,
+ port->mem_size);
+ if (port->base_addr == 0)
+ pr_err("devm_ioremap() failed\n");
+
+ port->port_params.base_addr = port->base_addr;
+
+ return 0;
+}
+
+static int init_fm_port_dev(struct fm_port_drv_t *port)
+{
+ struct fm_drv_t *fm_drv = (struct fm_drv_t *)port->fm;
+
+ if (!port->active || port->fm_port)
+ return -EINVAL;
+
+ port->fm_port = fm_port_config(&port->port_params);
+ if (!port->fm_port) {
+ pr_err("fm_port_config() failed\n");
+ return -EINVAL;
+ }
+
+ fm_get_revision(fm_drv->fm_dev, &port->fm_rev_info);
+
+ /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT Errata workaround */
+ if (port->port_params.port_type == FM_PORT_TYPE_TX) {
+ int err = 0;
+
+ err = fm_port_cfg_deq_high_priority(port->fm_port, true);
+ if (err)
+ return err;
+ err =
+ fm_port_cfg_deq_prefetch_option(port->fm_port,
+ FM_PORT_DEQ_FULL_PREFETCH);
+ if (err)
+ return err;
+ }
+
+ /* Configure BCB workaround on Rx ports, only for B4860 rev1 */
+ if ((port->fm_rev_info.major_rev >= 6) &&
+ (port->port_params.port_type == FM_PORT_TYPE_RX)) {
+ unsigned int svr;
+
+ svr = mfspr(SPRN_SVR);
+ if ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_MAJ(svr) == 1))
+ fm_port_cfg_bcb_wa(port->fm_port);
+ }
+
+ fm_port_cfg_buf_prefix_content(port->fm_port,
+ &port->buff_prefix_content);
+
+ if (fm_port_init(port->fm_port) != 0) {
+ pr_err("fm_port_init() failed\n");
+ 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 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 P4080:
+ * . (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 P4080, MXT is in range (0..63)
+ *
+ */
+ return 0;
+}
+
+void fm_set_rx_port_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params)
+{
+ int i;
+
+ port->port_params.specific_params.rx_params.err_fqid = params->errq;
+ port->port_params.specific_params.rx_params.dflt_fqid = params->defq;
+ 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++) {
+ port->port_params.specific_params.rx_params.ext_buf_pools.
+ ext_buf_pool[i].id = params->pool_param[i].id;
+ port->port_params.specific_params.rx_params.ext_buf_pools.
+ ext_buf_pool[i].size = params->pool_param[i].size;
+ }
+
+ port->buff_prefix_content.priv_data_size = params->priv_data_size;
+ port->buff_prefix_content.pass_prs_result = params->parse_results;
+ port->buff_prefix_content.pass_hash_result = params->hash_results;
+ port->buff_prefix_content.pass_time_stamp = params->time_stamp;
+ port->buff_prefix_content.data_align = params->data_align;
+
+ init_fm_port_dev(port);
+}
+EXPORT_SYMBOL(fm_set_rx_port_params);
+
+void fm_set_tx_port_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params)
+{
+ port->port_params.specific_params.non_rx_params.err_fqid =
+ params->errq;
+ port->port_params.specific_params.non_rx_params.dflt_fqid =
+ params->defq;
+
+ port->buff_prefix_content.priv_data_size = params->priv_data_size;
+ port->buff_prefix_content.pass_prs_result = params->parse_results;
+ port->buff_prefix_content.pass_hash_result = params->hash_results;
+ port->buff_prefix_content.pass_time_stamp = params->time_stamp;
+ port->buff_prefix_content.data_align = params->data_align;
+
+ init_fm_port_dev(port);
+}
+EXPORT_SYMBOL(fm_set_tx_port_params);
+
+static int fm_port_probe(struct platform_device *of_dev)
+{
+ struct fm_port_drv_t *port;
+ struct fm_drv_t *fm_drv;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+
+ port = read_fm_port_dev_tree_node(of_dev);
+ if (!port)
+ return -EIO;
+
+ if (!port->active)
+ return 0;
+
+ if (configure_fm_port_dev(port) != 0)
+ return -EIO;
+
+ dev_set_drvdata(dev, port);
+
+ fm_drv = (struct fm_drv_t *)port->fm;
+
+ if (port->port_params.port_type == FM_PORT_TYPE_RX) {
+ snprintf(port->name, sizeof(port->name),
+ "%s-port-rx%d", fm_drv->name, port->id);
+ } else if (port->port_params.port_type == FM_PORT_TYPE_TX) {
+ snprintf(port->name, sizeof(port->name),
+ "%s-port-tx%d", fm_drv->name, port->id);
+ }
+
+ /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 Errata workaround */
+ if (port->fm_rev_info.major_rev < 6)
+ fm_disable_rams_ecc(fm_drv->fm_dev);
+
+ pr_debug("%s probed\n", port->name);
+
+ return 0;
+}
+
+static const struct of_device_id fm_port_match[] = {
+ {.compatible = "fsl,fman-v3-port-rx"},
+ {.compatible = "fsl,fman-v2-port-rx"},
+ {.compatible = "fsl,fman-v3-port-tx"},
+ {.compatible = "fsl,fman-v2-port-tx"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, fm_port_match);
+
+static struct platform_driver fm_port_driver = {
+ .driver = {
+ .name = "fsl-fman-port",
+ .of_match_table = fm_port_match,
+ },
+ .probe = fm_port_probe,
+};
+
+builtin_platform_driver(fm_port_driver);
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..56c83b5
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/fm_port_ext.h
@@ -0,0 +1,340 @@
+/*
+ * 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_PORT_EXT
+#define __FM_PORT_EXT
+
+#include "fm_ext.h"
+
+/* 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)
+
+/* 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 {
+ u32 err_fqid; /* Error Queue Id. */
+ u32 dflt_fqid; /* Default Queue Id. */
+ u16 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. */
+ u32 err_fqid;
+ /* For Tx - Default Confirmation queue, 0 means no Tx confirmation
+ * for processed frames. For OP port - default Rx queue.
+ */
+ u32 dflt_fqid;
+ /* QM-channel dedicated to this port; will be used
+ * by the FM for dequeue.
+ */
+ u32 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 {
+ void __iomem *base_addr;
+ /* Virtual Address of memory mapped FM Port registers. */
+ void *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 */
+ u8 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.
+ */
+ u16 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;
+
+/**
+ * fm_port_config
+ * @fm_port_params: Pointer to data structure of parameters
+ *
+ * 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.
+ *
+ * Return: Pointer to FM Port object, or NULL for Failure.
+ */
+struct fm_port_t *fm_port_config(struct fm_port_params_t *fm_port_params);
+
+/**
+ * fm_port_init
+ * fm_port: A pointer to a FM Port module.
+ * Initializes the FM PORT module by defining the software structure and
+ * configuring the hardware registers.
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_init(struct fm_port_t *fm_port);
+
+/* 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 {
+ u32 num; /* Committed required resource */
+ u32 extra; /* Extra (not committed) required resource */
+};
+
+/**
+ * fm_port_cfg_deq_high_priority
+ * fm_port: A pointer to a FM Port module.
+ * @high_pri: True to select high priority, false for normal operation.
+ *
+ * Calling this routine changes the dequeue priority in the internal driver
+ * data base from its default configuration (DFLT_PORT_DEQ_HIGH_PRIORITY)
+ * May be used for Non-Rx ports only
+ *
+ * Allowed only following fm_port_config() and before fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_cfg_deq_high_priority(struct fm_port_t *fm_port, bool high_pri);
+
+/**
+ * fm_port_cfg_deq_prefetch_option
+ * fm_port: A pointer to a FM Port module.
+ * @deq_prefetch_option: New option
+ * Calling this routine changes the dequeue prefetch option parameter in the
+ * internal driver data base from its default configuration:
+ * [DEFAULT_PORT_DEQ_PREFETCH_OPT]
+ * Note: Available for some chips only May be used for Non-Rx ports only
+ *
+ * Allowed only following fm_port_config() and before fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_cfg_deq_prefetch_option(struct fm_port_t *fm_port,
+ enum fm_port_deq_prefetch_option
+ deq_prefetch_option);
+
+/**
+ * fm_port_cfg_buf_prefix_content
+ * fm_port A pointer to a FM Port module.
+ * @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.
+ * Defines the structure, size and content of the application buffer.
+ * The prefix, 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
+ *
+ * Allowed only following fm_port_config() and before fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_cfg_buf_prefix_content(struct fm_port_t *fm_port,
+ struct fm_buffer_prefix_content_t
+ *fm_buffer_prefix_content);
+
+/**
+ * fm_port_cfg_bcb_wa
+ * fm_port A pointer to a FM Port module.
+ *
+ * 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.
+ *
+ * Allowed only following fm_port_config() and before fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_cfg_bcb_wa(struct fm_port_t *fm_port);
+
+/**
+ * fm_port_disable
+ * fm_port A pointer to a FM Port module.
+ *
+ * Gracefully disable an FM port. The port will not start new tasks after all
+ * tasks associated with the port are terminated.
+ *
+ * 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.
+ * Allowed only following fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_disable(struct fm_port_t *fm_port);
+
+/**
+ * fm_port_enable
+ * fm_port: A pointer to a FM Port module.
+ *
+ * A runtime routine provided to allow disable/enable of port.
+ *
+ * Allowed only following fm_port_init().
+ *
+ * Return: 0 on success; Error code otherwise.
+ */
+int fm_port_enable(struct fm_port_t *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 c96cfd1..d849bc2 100644
--- a/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
+++ b/drivers/net/ethernet/freescale/fman/inc/fsl_fman_drv.h
@@ -40,6 +40,40 @@
/* FM device opaque structure used for type checking */
struct fm;

+/* FMan Port 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 {
+ u8 id; /* External buffer pool id */
+ u16 size; /* External buffer pool buffer size */
+};
+
+/* structure for additional port parameters */
+struct fm_port_params {
+ u32 errq; /* Error Queue Id. */
+ u32 defq; /* For Tx and HC - Default Confirmation queue,
+ * 0 means no Tx conf for processed frames.
+ * For Rx and OP - default Rx queue.
+ */
+ u8 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 */
+ u16 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 */
+ u16 data_align;
+ /* value for selecting a data alignment (must be a power of 2);
+ * if write optimization is used, must be >= 16.
+ */
+};
+
/**
* fm_bind
* @fm_dev: the OF handle of the FM device.
@@ -82,6 +116,76 @@ void *fm_get_handle(struct fm *fm);
*/

struct resource *fm_get_mem_region(struct fm *fm);
+
+/**
+ * fm_port_bind
+ * @fm_port_dev: The OF handle of the FM port device.
+ *
+ * Bind to a specific FM-port device (may be Rx or Tx port).
+ *
+ * Allowed only after the port was created.
+ *
+ * Return: A handle of the FM port device.
+ */
+struct fm_port_drv_t *fm_port_bind(struct device *fm_port_dev);
+
+/**
+ * fm_set_rx_port_params
+ * @port: A handle of the FM port device.
+ * @params: Rx port parameters
+ *
+ * Configure parameters for a specific Rx FM-port device.
+ *
+ * Allowed only after the port is binded.
+ */
+void fm_set_rx_port_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params);
+
+/**
+ * fm_port_get_buff_layout_ext_params
+ * @port: A handle of the FM port device.
+ * @params: PCD port parameters
+ *
+ * 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.
+ *
+ * Allowed only after the port is binded.
+ */
+void fm_port_get_buff_layout_ext_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params);
+
+/**
+ * fm_get_tx_port_channel
+ * @port: A handle of the FM port device.
+ *
+ * Get qman-channel number for this Tx port.
+ * Allowed only after the port is binded.
+ *
+ * Return: qman-channel number for this Tx port.
+ */
+int fm_get_tx_port_channel(struct fm_port_drv_t *port);
+
+/**
+ * fm_set_tx_port_params
+ * @port: A handle of the FM port device.
+ * @params: Tx port parameters
+ *
+ * Configure parameters for a specific Tx FM-port device
+ *
+ * Allowed only after the port is binded.
+ */
+void fm_set_tx_port_params(struct fm_port_drv_t *port,
+ struct fm_port_params *params);
+/**
+ * fm_port_drv_handle
+ * @port: A handle of the FM port device.
+ *
+ * Return: A pointer to the internal FM Port structure
+ */
+struct fm_port_t *fm_port_drv_handle(const struct fm_port_drv_t *port);
+
/**
* fm_get_max_frm
*
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..ff32cd9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fm_port.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright 2008 - 2015 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "fm_muram_ext.h"
+
+#include "fm_port.h"
+
+#include <linux/string.h>
+#include <linux/slab.h>
+
+static int check_init_parameters(struct fm_port_t *fm_port)
+{
+ struct fm_port_drv_param_t *params = fm_port->fm_port_drv_param;
+ struct fman_port_cfg *dflt_config = &params->dflt_cfg;
+ u32 unused_mask;
+
+ /* Rx only */
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ /* external buffer pools */
+ if (!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 -EINVAL;
+ }
+
+ if (fm_sp_check_buf_pools_params(&params->ext_buf_pools,
+ params->backup_bm_pools,
+ &params->buf_pool_depletion,
+ fm_port->port_intg->max_num_of_ext_pools,
+ fm_port->port_intg->bm_max_num_of_pools) != 0)
+ return -EINVAL;
+ /* Check that part of IC that needs copying is small enough
+ * to enter start margin
+ */
+ if (params->int_context.size &&
+ (params->int_context.size +
+ params->int_context.ext_buf_offset >
+ params->buf_margins.start_margins)) {
+ pr_err("int_context.size is larger than start margins\n");
+ return -EINVAL;
+ }
+
+ if ((params->liodn_offset != LIODN_DONT_OVERRIDE) &&
+ (params->liodn_offset & ~FM_LIODN_OFFSET_MASK)) {
+ pr_err("liodn_offset is larger than %d\n",
+ FM_LIODN_OFFSET_MASK + 1);
+ }
+
+ if (fm_port->fm_rev_info.major_rev < 6)
+ if (fm_port->fm_port_drv_param->backup_bm_pools) {
+ pr_err("Backup Bm Pools\n");
+ return -EINVAL;
+ }
+ } else {
+ /* Non Rx ports */
+ if (params->deq_sub_portal >=
+ 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",
+ fm_port->port_intg->fm_max_num_of_sub_portals);
+ return -EINVAL;
+ }
+
+ /* to protect HW internal-context from overwrite */
+ if ((params->int_context.size) &&
+ (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 -EINVAL;
+ }
+
+ if ((fm_port->port_type == FM_PORT_TYPE_TX) ||
+ /* in O/H DFLT_NOT_SUPPORTED indicates that
+ * it is not supported and should not be checked
+ */
+ (fm_port->fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth != DFLT_NOT_SUPPORTED)) {
+ /* Check that not larger than 8 */
+ if ((!fm_port->fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth) ||
+ (fm_port->fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth >
+ MAX_FIFO_PIPELINE_DEPTH)) {
+ pr_err("fifo_deq_pipeline_depth can't be larger than %d\n",
+ MAX_FIFO_PIPELINE_DEPTH);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Rx */
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (!params->dflt_fqid) {
+ pr_err("dflt_fqid must be between 1 and 2^24-1\n");
+ return -EINVAL;
+ }
+ }
+
+ /* All ports */
+ /* common BMI registers values */
+ /* Check that Queue Id is not larger than 2^24, and is not 0 */
+ if ((params->err_fqid & ~0x00FFFFFF) || !params->err_fqid) {
+ pr_err("err_fqid must be between 1 and 2^24-1\n");
+ return -EINVAL;
+ }
+ if (params->dflt_fqid & ~0x00FFFFFF) {
+ pr_err("dflt_fqid must be between 1 and 2^24-1\n");
+ return -EINVAL;
+ }
+
+ /* Rx only */
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (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 -EINVAL;
+ }
+ if ((dflt_config->rx_pri_elevation < BMI_FIFO_UNITS) ||
+ (dflt_config->rx_pri_elevation >
+ fm_port->port_intg->max_port_fifo_size)) {
+ pr_err("rx_fifo_pri_elevation_level not in range of 256 - %d\n",
+ fm_port->port_intg->max_port_fifo_size);
+ return -EINVAL;
+ }
+ if (dflt_config->rx_fifo_thr % BMI_FIFO_UNITS) {
+ pr_err("rx_fifo_threshold must be div by %d\n",
+ BMI_FIFO_UNITS);
+ return -EINVAL;
+ }
+ if ((dflt_config->rx_fifo_thr < BMI_FIFO_UNITS) ||
+ (dflt_config->rx_fifo_thr >
+ fm_port->port_intg->max_port_fifo_size)) {
+ pr_err("rx_fifo_threshold has to be in the range of 256 - %d\n",
+ fm_port->port_intg->max_port_fifo_size);
+ return -EINVAL;
+ }
+
+ /* Check that not larger than 16 */
+ if (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 -EINVAL;
+ }
+
+ if (fm_sp_check_buf_margins(&params->buf_margins) != 0)
+ return -EINVAL;
+
+ /* extra FIFO size (allowed only to Rx ports) */
+ if (params->set_size_of_fifo &&
+ (fm_port->fifo_bufs.extra % BMI_FIFO_UNITS)) {
+ pr_err("fifo_bufs.extra has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EINVAL;
+ }
+
+ if (params->buf_pool_depletion.pools_grp_mode_enable &&
+ !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 -EINVAL;
+ }
+ }
+
+ /* Non Rx ports */
+ /* extra FIFO size (allowed only to Rx ports) */
+ else if (fm_port->fifo_bufs.extra) {
+ pr_err(" No fifo_bufs.extra for non Rx ports\n");
+ return -EINVAL;
+ }
+
+ /* Tx only */
+ if (fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (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 -EINVAL;
+ }
+ if (dflt_config->tx_fifo_min_level >
+ (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",
+ (fm_port->port_intg->max_port_fifo_size - 256));
+ return -EINVAL;
+ }
+ if (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 -EINVAL;
+ }
+ if ((dflt_config->tx_fifo_low_comf_level < BMI_FIFO_UNITS) ||
+ (dflt_config->tx_fifo_low_comf_level >
+ 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",
+ fm_port->port_intg->max_port_fifo_size);
+ return -EINVAL;
+ }
+ if (fm_port->port_speed == FM_PORT_SPEED_1G)
+ if (fm_port->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 -EINVAL;
+ }
+ }
+
+ /* Non Tx Ports */
+ /* If discard override was selected , no frames may be discarded. */
+ else if (dflt_config->discard_override && 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 */
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ unused_mask = BMI_STATUS_RX_MASK_UNUSED;
+
+ /* Check that no common bits with BMI_STATUS_MASK_UNUSED */
+ if (params->errors_to_discard & unused_mask) {
+ pr_err("errors_to_discard contains undefined bits\n");
+ return -EINVAL;
+ }
+ }
+
+ /* All ports */
+ /* Check that not larger than 16 */
+ if ((params->cheksum_last_bytes_ignore > FRAME_END_DATA_SIZE) &&
+ ((params->cheksum_last_bytes_ignore != DFLT_NOT_SUPPORTED))) {
+ pr_err("cheksum_last_bytes_ignore can't be larger than %d\n",
+ FRAME_END_DATA_SIZE);
+ return -EINVAL;
+ }
+
+ if (fm_sp_check_int_context_params(&params->int_context) != 0)
+ return -EINVAL;
+
+ /* common BMI registers values */
+ if (params->set_num_of_tasks &&
+ ((!fm_port->tasks.num) ||
+ (fm_port->tasks.num > MAX_NUM_OF_TASKS))) {
+ pr_err("tasks.num can't be larger than %d\n",
+ MAX_NUM_OF_TASKS);
+ return -EINVAL;
+ }
+ if (params->set_num_of_tasks &&
+ (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 -EINVAL;
+ }
+ if (params->set_num_of_open_dmas &&
+ ((!fm_port->open_dmas.num) ||
+ (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 -EINVAL;
+ }
+ if (params->set_num_of_open_dmas &&
+ (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 -EINVAL;
+ }
+ if (params->set_size_of_fifo &&
+ (!fm_port->fifo_bufs.num || (fm_port->fifo_bufs.num >
+ fm_port->port_intg->max_port_fifo_size))) {
+ pr_err("fifo_bufs.num has to be in the range of 256 - %d\n",
+ fm_port->port_intg->max_port_fifo_size);
+ return -EINVAL;
+ }
+ if (params->set_size_of_fifo &&
+ (fm_port->fifo_bufs.num % BMI_FIFO_UNITS)) {
+ pr_err("fifo_bufs.num has to be divisible by %d\n",
+ BMI_FIFO_UNITS);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool is_init_done(struct fm_port_drv_param_t *fm_port_drv_params)
+{
+ /* Checks if FMan port driver parameters were initialized */
+ if (!fm_port_drv_params)
+ return true;
+
+ return false;
+}
+
+static int verify_size_of_fifo(struct fm_port_t *fm_port)
+{
+ u32 min_fifo_size_required = 0, opt_fifo_size_for_b2b = 0;
+
+ /* TX Ports */
+ if (fm_port->port_type == FM_PORT_TYPE_TX) {
+ min_fifo_size_required = (u32)
+ (roundup(fm_port->max_frame_length,
+ BMI_FIFO_UNITS) + (3 * BMI_FIFO_UNITS));
+
+ min_fifo_size_required +=
+ fm_port->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 (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 (fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (fm_port->fm_rev_info.major_rev >= 6)
+ min_fifo_size_required = (u32)
+ (roundup(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 = (u32)
+ (roundup(min(fm_port->max_frame_length,
+ 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 (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;
+ }
+
+ BUG_ON(min_fifo_size_required <= 0);
+ BUG_ON(opt_fifo_size_for_b2b < min_fifo_size_required);
+
+ /* Verify the size */
+ if (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 (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 *fm_port)
+{
+ kfree(fm_port->fm_port_drv_param);
+ fm_port->fm_port_drv_param = NULL;
+}
+
+static int set_ext_buffer_pools(struct fm_port_t *fm_port)
+{
+ struct fm_ext_pools_t *ext_buf_pools =
+ &fm_port->fm_port_drv_param->ext_buf_pools;
+ struct fm_buf_pool_depletion_t *buf_pool_depletion =
+ &fm_port->fm_port_drv_param->buf_pool_depletion;
+ u8 ordered_array[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ u16 sizes_array[BM_MAX_NUM_OF_POOLS];
+ int i = 0, j = 0, err;
+ struct fman_port_bpools bpools;
+
+ memset(&ordered_array, 0, sizeof(u8) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
+ memset(&sizes_array, 0, sizeof(u16) * BM_MAX_NUM_OF_POOLS);
+ memcpy(&fm_port->ext_buf_pools, ext_buf_pools,
+ sizeof(struct fm_ext_pools_t));
+
+ fm_sp_set_buf_pools_in_asc_order_of_buf_sizes(ext_buf_pools,
+ ordered_array,
+ sizes_array);
+
+ /* Prepare flibs bpools structure */
+ memset(&bpools, 0, sizeof(struct fman_port_bpools));
+ bpools.count = ext_buf_pools->num_of_pools_used;
+ bpools.counters_enable = true;
+ for (i = 0; i < 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 (fm_port->fm_port_drv_param->backup_bm_pools)
+ for (j = 0; j < fm_port->fm_port_drv_param->
+ backup_bm_pools->num_of_backup_pools; j++)
+ if (ordered_array[i] ==
+ fm_port->fm_port_drv_param->
+ backup_bm_pools->pool_ids[j]) {
+ bpools.bpool[i].is_backup = true;
+ break;
+ }
+ }
+
+ /* save pools parameters for later use */
+ fm_port->rx_pools_params.num_of_pools =
+ ext_buf_pools->num_of_pools_used;
+ fm_port->rx_pools_params.largest_buf_size =
+ sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 1]];
+ fm_port->rx_pools_params.second_largest_buf_size =
+ sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 2]];
+
+ /* FMBM_RMPD reg. - pool depletion */
+ if (buf_pool_depletion->pools_grp_mode_enable) {
+ bpools.grp_bp_depleted_num = buf_pool_depletion->num_of_pools;
+ for (i = 0; i < fm_port->port_intg->bm_max_num_of_pools;
+ i++) {
+ if (buf_pool_depletion->pools_to_consider[i]) {
+ for (j = 0; j < ext_buf_pools->
+ num_of_pools_used; j++) {
+ if (i == ordered_array[j]) {
+ bpools.bpool[j].
+ grp_bp_depleted = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (buf_pool_depletion->single_pool_mode_enable) {
+ for (i = 0; i < fm_port->port_intg->bm_max_num_of_pools; i++) {
+ if (buf_pool_depletion->
+ pools_to_consider_for_single_mode[i]) {
+ for (j = 0; j < 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(&fm_port->port, &bpools);
+ if (err != 0) {
+ pr_err("fman_port_set_bpools\n");
+ return -EINVAL;
+ }
+
+ kfree(fm_port->fm_port_drv_param->backup_bm_pools);
+
+ return 0;
+}
+
+static int init_low_level_driver(struct fm_port_t *fm_port)
+{
+ struct fm_port_drv_param_t *drv_params = fm_port->fm_port_drv_param;
+ struct fman_port_params port_params;
+ u32 tmp_val;
+
+ /* Set up flibs parameters and issue init function */
+ memset(&port_params, 0, sizeof(struct fman_port_params));
+ port_params.discard_mask = drv_params->errors_to_discard;
+ port_params.dflt_fqid = drv_params->dflt_fqid;
+ port_params.err_fqid = drv_params->err_fqid;
+ port_params.deq_sp = drv_params->deq_sub_portal;
+ port_params.dont_release_buf = drv_params->dont_release_buf;
+ switch (fm_port->port_type) {
+ case FM_PORT_TYPE_RX:
+ port_params.err_mask =
+ (RX_ERRS_TO_ENQ & ~port_params.discard_mask);
+ if (drv_params->forward_reuse_int_context)
+ drv_params->dflt_cfg.rx_fd_bits =
+ (u8)(BMI_PORT_RFNE_FRWD_RPD >> 24);
+ break;
+ default:
+ break;
+ }
+
+ tmp_val = (u32)((fm_port->internal_buf_offset % OFFSET_UNITS) ?
+ (fm_port->internal_buf_offset / OFFSET_UNITS + 1) :
+ (fm_port->internal_buf_offset / OFFSET_UNITS));
+ fm_port->internal_buf_offset = (u8)(tmp_val * OFFSET_UNITS);
+ drv_params->dflt_cfg.int_buf_start_margin =
+ fm_port->internal_buf_offset;
+ drv_params->dflt_cfg.ext_buf_start_margin =
+ drv_params->buf_margins.start_margins;
+ drv_params->dflt_cfg.ext_buf_end_margin =
+ drv_params->buf_margins.end_margins;
+
+ drv_params->dflt_cfg.ic_ext_offset =
+ drv_params->int_context.ext_buf_offset;
+ drv_params->dflt_cfg.ic_int_offset =
+ drv_params->int_context.int_context_offset;
+ drv_params->dflt_cfg.ic_size = drv_params->int_context.size;
+
+ if (0 !=
+ fman_port_init(&fm_port->port, &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 (fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (!drv_params->dflt_fqid && 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
+ */
+ out_be32(&fm_port->port.bmi_regs->tx.fmbm_tcfqid,
+ 0xFFFFFF);
+ out_be32(&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 *fm_port)
+{
+ struct fm_port_intg_t *intg;
+ u32 bmi_max_fifo_size;
+
+ intg = kzalloc(sizeof(*intg), GFP_KERNEL);
+ if (!intg)
+ return NULL;
+
+ bmi_max_fifo_size = fm_get_bmi_max_fifo_size(fm_port->fm);
+
+ intg->max_port_fifo_size =
+ MAX_PORT_FIFO_SIZE(bmi_max_fifo_size);
+
+ switch (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_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;
+}
+
+struct fm_port_t *fm_port_config(struct fm_port_params_t *fm_port_params)
+{
+ struct fm_port_t *fm_port;
+ void __iomem *base_addr = fm_port_params->base_addr;
+ enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY;
+ u32 tmp_reg;
+
+ /* Allocate FM structure */
+ fm_port = kzalloc(sizeof(*fm_port), GFP_KERNEL);
+ if (!fm_port)
+ return NULL;
+
+ /* Allocate the FM driver's parameters structure */
+ fm_port->fm_port_drv_param =
+ kzalloc(sizeof(*fm_port->fm_port_drv_param), GFP_KERNEL);
+ if (!fm_port->fm_port_drv_param)
+ goto err_fm_port_params;
+
+ /* Initialize FM port parameters which will be kept by the driver */
+ fm_port->port_type = fm_port_params->port_type;
+ fm_port->port_speed = fm_port_params->port_speed;
+ fm_port->port_id = fm_port_params->port_id;
+ fm_port->fm = fm_port_params->fm;
+
+ /* get FM revision */
+ fm_get_revision(fm_port->fm, &fm_port->fm_rev_info);
+
+ fm_port->port_intg = set_port_intg_params(fm_port);
+ if (!fm_port->port_intg)
+ goto err_fm_port_intg;
+
+ /* Set up FM port parameters for initialization phase only */
+
+ /* In order to be aligned with flib port types, we need to translate
+ * the port type and speed to fman_port_type
+ */
+ if (fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (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 (fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (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(&fm_port->fm_port_drv_param->dflt_cfg,
+ fman_port_type);
+ /* Overwrite some integration specific parameters */
+ fm_port->fm_port_drv_param->dflt_cfg.rx_pri_elevation =
+ DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(
+ fm_port->port_intg->max_port_fifo_size);
+ fm_port->fm_port_drv_param->dflt_cfg.rx_fifo_thr =
+ fm_port->fm_port_drv_param->rx_fifo_threshold =
+ DFLT_PORT_RX_FIFO_THRESHOLD(fm_port->fm_rev_info.major_rev,
+ fm_port->port_intg->max_port_fifo_size);
+
+ fm_port->fm_port_drv_param->dflt_cfg.errata_A006675 = false;
+
+ if ((fm_port->fm_rev_info.major_rev == 6) &&
+ ((fm_port->fm_rev_info.minor_rev == 0) ||
+ (fm_port->fm_rev_info.minor_rev == 3)))
+ fm_port->fm_port_drv_param->dflt_cfg.errata_A006320 = true;
+ else
+ fm_port->fm_port_drv_param->dflt_cfg.errata_A006320 = false;
+
+ /* Excessive Threshold register - exists for pre-FMv3 chips only */
+ if (fm_port->fm_rev_info.major_rev < 6) {
+ fm_port->fm_port_drv_param->dflt_cfg.
+ excessive_threshold_register = true;
+
+ fm_port->fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd =
+ false;
+ fm_port->fm_port_drv_param->dflt_cfg.fmbm_tfne_has_features =
+ false;
+ } else {
+ fm_port->fm_port_drv_param->dflt_cfg.
+ excessive_threshold_register = false;
+ fm_port->fm_port_drv_param->dflt_cfg.fmbm_rebm_has_sgd =
+ true;
+ fm_port->fm_port_drv_param->dflt_cfg.fmbm_tfne_has_features =
+ true;
+ }
+
+ fm_port->fm_port_drv_param->dflt_cfg.qmi_deq_options_support = true;
+
+ /* Continue with other parameters */
+ fm_port->fm_port_drv_param->base_addr = base_addr;
+ /* set memory map pointers */
+ fm_port->fm_port_bmi_regs = (union fm_port_bmi_regs_u __iomem *)
+ (base_addr + BMI_PORT_REGS_OFFSET);
+
+ fm_port->fm_port_drv_param->buffer_prefix_content.priv_data_size =
+ DFLT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE;
+ fm_port->fm_port_drv_param->buffer_prefix_content.pass_prs_result =
+ DFLT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT;
+ fm_port->fm_port_drv_param->buffer_prefix_content.pass_time_stamp =
+ DFLT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP;
+ fm_port->fm_port_drv_param->buffer_prefix_content.data_align =
+ DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN;
+ fm_port->fm_port_drv_param->liodn_base = fm_port_params->liodn_base;
+ fm_port->fm_port_drv_param->cheksum_last_bytes_ignore =
+ DFLT_PORT_CHECKSUM_LAST_BYTES_IGNORE;
+
+ fm_port->max_frame_length = DFLT_PORT_MAX_FRAME_LENGTH;
+ /* resource distribution. */
+
+ fm_port->fifo_bufs.num =
+ fm_port_dflt_num_of_fifo_bufs(fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed) * BMI_FIFO_UNITS;
+ fm_port->fifo_bufs.extra =
+ DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS * BMI_FIFO_UNITS;
+
+ fm_port->open_dmas.num =
+ fm_port_dflt_num_of_open_dmas(fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed);
+ fm_port->open_dmas.extra =
+ fm_port_dflt_extra_num_of_open_dmas(fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed);
+ fm_port->tasks.num =
+ fm_port_dflt_num_of_tasks(fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed);
+ fm_port->tasks.extra =
+ fm_port_dflt_extra_num_of_tasks(fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed);
+
+ /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 errata
+ * workaround
+ */
+ if ((fm_port->fm_rev_info.major_rev == 6) &&
+ (fm_port->fm_rev_info.minor_rev == 0) &&
+ (((fm_port->port_type == FM_PORT_TYPE_TX) &&
+ (fm_port->port_speed == FM_PORT_SPEED_1G)))) {
+ fm_port->open_dmas.num = 16;
+ fm_port->open_dmas.extra = 0;
+ }
+
+ /* Port type specific initialization: */
+ switch (fm_port->port_type) {
+ case FM_PORT_TYPE_RX:
+ /* Initialize FM port parameters for initialization
+ * phase only
+ */
+ fm_port->fm_port_drv_param->cut_bytes_from_end =
+ DFLT_PORT_CUT_BYTES_FROM_END;
+ fm_port->fm_port_drv_param->en_buf_pool_depletion = false;
+ fm_port->fm_port_drv_param->frm_discard_override =
+ DFLT_PORT_FRM_DISCARD_OVERRIDE;
+
+ fm_port->fm_port_drv_param->rx_fifo_pri_elevation_level =
+ DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(fm_port->port_intg->
+ max_port_fifo_size);
+ fm_port->fm_port_drv_param->rx_fifo_threshold =
+ DFLT_PORT_RX_FIFO_THRESHOLD(fm_port->fm_rev_info.major_rev,
+ fm_port->port_intg->
+ max_port_fifo_size);
+
+ fm_port->fm_port_drv_param->buf_margins.end_margins =
+ DFLT_PORT_BUF_MARGINS_END_MAARGINS;
+ fm_port->fm_port_drv_param->errors_to_discard =
+ DFLT_PORT_ERRORS_TO_DISCARD;
+ fm_port->fm_port_drv_param->forward_reuse_int_context =
+ DFLT_PORT_FORWARD_INT_CONTENT_REUSE;
+ break;
+
+ case FM_PORT_TYPE_TX:
+ if (fm_port->port_speed == FM_PORT_SPEED_1G) {
+ fm_port->fm_port_drv_param->dont_release_buf = false;
+ /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 Errata
+ * workaround
+ */
+ if (fm_port->fm_rev_info.major_rev >= 6) {
+ tmp_reg = 0x00001013;
+ out_be32(&fm_port->fm_port_bmi_regs->
+ tx_port_bmi_regs.fmbm_tfp,
+ tmp_reg);
+ }
+ }
+ if (fm_port->port_speed == FM_PORT_SPEED_10G) {
+ fm_port->fm_port_drv_param->tx_fifo_min_fill_level =
+ DFLT_PORT_TX_FIFO_MIN_FILL_LEVEL;
+ fm_port->fm_port_drv_param->tx_fifo_low_comf_level =
+ DFLT_PORT_TX_FIFO_LOW_COMF_LEVEL;
+
+ fm_port->fm_port_drv_param->deq_type =
+ DFLT_PORT_DEQ_TYPE;
+ fm_port->fm_port_drv_param->deq_prefetch_option =
+ DFLT_PORT_DEQ_PREFETCH_OPT;
+ }
+ fm_port->fm_port_drv_param->deq_high_priority =
+ DFLT_PORT_DEQ_HIGH_PRIORITY(fm_port->port_speed);
+ fm_port->fm_port_drv_param->deq_byte_cnt =
+ DFLT_PORT_DEQ_BYTE_CNT(fm_port->port_speed);
+ fm_port->fm_port_drv_param->dflt_cfg.
+ tx_fifo_deq_pipeline_depth =
+ fm_port_dflt_fifo_deq_pipeline_depth(
+ fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed);
+ break;
+ default:
+ pr_err("Invalid port type\n");
+ goto err_fm_port;
+ }
+
+ switch (fm_port->port_type) {
+ case FM_PORT_TYPE_RX:
+ /* Initialize FM port parameters for initialization
+ * phase only
+ */
+ memcpy(&fm_port->fm_port_drv_param->ext_buf_pools,
+ &fm_port_params->
+ specific_params.rx_params.ext_buf_pools,
+ sizeof(struct fm_ext_pools_t));
+ fm_port->fm_port_drv_param->err_fqid =
+ fm_port_params->specific_params.rx_params.err_fqid;
+ fm_port->fm_port_drv_param->dflt_fqid =
+ fm_port_params->specific_params.rx_params.dflt_fqid;
+ fm_port->fm_port_drv_param->liodn_offset =
+ fm_port_params->specific_params.rx_params.liodn_offset;
+ break;
+ case FM_PORT_TYPE_TX:
+ fm_port->fm_port_drv_param->err_fqid =
+ fm_port_params->specific_params.non_rx_params.err_fqid;
+ fm_port->fm_port_drv_param->deq_sub_portal =
+ (u8)(fm_port_params->specific_params.non_rx_params.
+ qm_channel & QMI_DEQ_CFG_SUBPORTAL_MASK);
+ fm_port->fm_port_drv_param->dflt_fqid =
+ fm_port_params->specific_params.non_rx_params.dflt_fqid;
+ break;
+ default:
+ pr_err("Invalid port type\n");
+ goto err_fm_port;
+ }
+
+ memset(fm_port->name, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (snprintf(fm_port->name, MODULE_NAME_SIZE, "FM-%d-port-%s-%d",
+ fm_get_id(fm_port->fm),
+ ((fm_port->port_type == FM_PORT_TYPE_TX) ?
+ ((fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-TX" :
+ "1g-TX") :
+ ((fm_port->port_speed == FM_PORT_SPEED_10G) ? "10g-RX" :
+ "1g-RX")),
+ fm_port->port_id) == 0) {
+ pr_err("sprintf failed\n");
+ goto err_fm_port;
+ }
+
+ return fm_port;
+
+err_fm_port:
+ kfree(fm_port->port_intg);
+err_fm_port_intg:
+ kfree(fm_port->fm_port_drv_param);
+err_fm_port_params:
+ kfree(fm_port);
+ return NULL;
+}
+
+int fm_port_init(struct fm_port_t *fm_port)
+{
+ struct fm_port_drv_param_t *drv_params;
+ int err;
+ struct fm_inter_module_port_init_params_t fm_params;
+ struct fm_revision_info_t rev_info;
+ enum fman_port_type fman_port_type = E_FMAN_PORT_TYPE_DUMMY;
+
+ if (is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ err = fm_sp_build_buffer_structure(&fm_port->fm_port_drv_param->
+ int_context,
+ &fm_port->fm_port_drv_param->
+ buffer_prefix_content,
+ &fm_port->fm_port_drv_param->
+ buf_margins,
+ &fm_port->buffer_offsets,
+ &fm_port->internal_buf_offset);
+ if (err)
+ return err;
+
+ /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 Errata workaround */
+ if (fm_port->fm_rev_info.major_rev >= 6 &&
+ (fm_port->fm_port_drv_param->bcb_workaround) &&
+ ((fm_port->port_type == FM_PORT_TYPE_RX) &&
+ (fm_port->port_speed == FM_PORT_SPEED_1G))) {
+ fm_port->fm_port_drv_param->errors_to_discard |=
+ FM_PORT_FRM_ERR_PHYSICAL;
+ if (!fm_port->fifo_bufs.num)
+ fm_port->fifo_bufs.num =
+ fm_port_dflt_num_of_fifo_bufs(
+ fm_port->fm_rev_info.major_rev,
+ fm_port->port_type,
+ fm_port->port_speed) *
+ BMI_FIFO_UNITS;
+ fm_port->fifo_bufs.num += 4 * 1024;
+ }
+
+ err = check_init_parameters(fm_port);
+ if (err)
+ return err;
+
+ drv_params = fm_port->fm_port_drv_param;
+
+ memset(&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 (fm_port->port_type == FM_PORT_TYPE_TX) {
+ if (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 (fm_port->port_type == FM_PORT_TYPE_RX) {
+ if (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;
+ }
+ fm_port->port.type = fman_port_type;
+ fm_get_revision(fm_port->fm, &rev_info);
+ fm_port->port.fm_rev_maj = rev_info.major_rev;
+ fm_port->port.fm_rev_min = rev_info.minor_rev;
+ fm_port->port.bmi_regs = (union fman_port_bmi_regs __iomem *)
+ (drv_params->base_addr + BMI_PORT_REGS_OFFSET);
+ fm_port->port.qmi_regs = (struct fman_port_qmi_regs __iomem *)
+ (drv_params->base_addr + QMI_PORT_REGS_OFFSET);
+ fm_port->port.ext_pools_num = (u8)8;
+
+ if (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 = set_ext_buffer_pools(fm_port);
+ if (err)
+ return err;
+ /* check if the largest external buffer pool is large enough */
+ if (drv_params->buf_margins.start_margins + MIN_EXT_BUF_SIZE +
+ drv_params->buf_margins.end_margins >
+ 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",
+ drv_params->buf_margins.start_margins,
+ drv_params->buf_margins.end_margins,
+ fm_port->rx_pools_params.largest_buf_size);
+ return -EINVAL;
+ }
+ }
+
+ /* Call FM module routine for communicating parameters */
+ memset(&fm_params, 0, sizeof(fm_params));
+ fm_params.port_id = fm_port->port_id;
+ fm_params.port_type = (enum fm_port_type)fm_port->port_type;
+ fm_params.port_speed = (enum fm_port_speed)fm_port->port_speed;
+ fm_params.num_of_tasks = (u8)fm_port->tasks.num;
+ fm_params.num_of_extra_tasks = (u8)fm_port->tasks.extra;
+ fm_params.num_of_open_dmas = (u8)fm_port->open_dmas.num;
+ fm_params.num_of_extra_open_dmas = (u8)fm_port->open_dmas.extra;
+
+ if (fm_port->fifo_bufs.num) {
+ err = verify_size_of_fifo(fm_port);
+ if (err != 0)
+ return -err;
+ }
+ fm_params.size_of_fifo = fm_port->fifo_bufs.num;
+ fm_params.extra_size_of_fifo = fm_port->fifo_bufs.extra;
+ fm_params.liodn_offset = drv_params->liodn_offset;
+ fm_params.liodn_base = drv_params->liodn_base;
+ fm_params.deq_pipeline_depth =
+ fm_port->fm_port_drv_param->dflt_cfg.tx_fifo_deq_pipeline_depth;
+ fm_params.max_frame_length = fm_port->max_frame_length;
+
+ err = fm_get_set_port_params(fm_port->fm, &fm_params);
+ if (err)
+ return -err;
+
+ err = init_low_level_driver(fm_port);
+ if (err != 0)
+ return -err;
+
+ fm_port_drv_param_free(fm_port);
+
+ return 0;
+}
+
+int fm_port_cfg_deq_high_priority(struct fm_port_t *fm_port, bool high_pri)
+{
+ if (is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ pr_err("cfg_deq_high_priority() not available for Rx ports\n");
+ return -ENOMEM;
+ }
+
+ fm_port->fm_port_drv_param->dflt_cfg.deq_high_pri = high_pri;
+
+ return 0;
+}
+
+int fm_port_cfg_deq_prefetch_option(struct fm_port_t *fm_port,
+ enum fm_port_deq_prefetch_option
+ deq_prefetch_option)
+{
+ if (is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ if (fm_port->port_type == FM_PORT_TYPE_RX) {
+ pr_err("fm_port_cfg_deq_prefetch_option not available for Rx ports\n");
+ return -ENODEV;
+ }
+ fm_port->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 *fm_port,
+ struct fm_buffer_prefix_content_t *
+ fm_buffer_prefix_content)
+{
+ if (is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ memcpy(&fm_port->fm_port_drv_param->buffer_prefix_content,
+ 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 (!fm_port->fm_port_drv_param->buffer_prefix_content.data_align)
+ fm_port->fm_port_drv_param->buffer_prefix_content.data_align =
+ DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN;
+
+ return 0;
+}
+
+int fm_port_cfg_bcb_wa(struct fm_port_t *fm_port)
+{
+ if (is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ fm_port->fm_port_drv_param->bcb_workaround = true;
+
+ return 0;
+}
+
+int fm_port_disable(struct fm_port_t *fm_port)
+{
+ int err;
+
+ if (!is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ err = fman_port_disable(&fm_port->port);
+ if (err == -EBUSY) {
+ pr_debug("%s: BMI or QMI is Busy. Port forced down\n",
+ fm_port->name);
+ err = 0;
+ }
+
+ fm_port->enabled = false;
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_disable);
+
+int fm_port_enable(struct fm_port_t *fm_port)
+{
+ int err;
+
+ if (!is_init_done(fm_port->fm_port_drv_param))
+ return -EINVAL;
+
+ /* Used by fm_port_free routine as indicationif 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.
+ */
+ fm_port->enabled = true;
+
+ err = fman_port_enable(&fm_port->port);
+
+ return err;
+}
+EXPORT_SYMBOL(fm_port_enable);
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..4ac24c1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/port/fm_port.h
@@ -0,0 +1,502 @@
+/*
+ * 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_PORT_H
+#define __FM_PORT_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 DFLT_PORT_DEQ_TYPE FM_PORT_DEQ_TYPE1
+#define DFLT_PORT_DEQ_PREFETCH_OPT FM_PORT_DEQ_FULL_PREFETCH
+#define DFLT_PORT_DEQ_BYTE_CNT(speed) \
+ ((speed == FM_PORT_SPEED_10G) ? 0x1400 : 0x400)
+#define DFLT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE
+#define DFLT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTENT_PRIV_PASS_PRS_RESULT
+#define DFLT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_PASS_TIME_STAMP
+#define DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN \
+ DEFAULT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN
+#define DFLT_PORT_CHECKSUM_LAST_BYTES_IGNORE 0
+#define DFLT_PORT_CUT_BYTES_FROM_END 4
+
+#define DFLT_PORT_FRM_DISCARD_OVERRIDE false
+
+#define DFLT_PORT_FORWARD_INT_CONTENT_REUSE false
+#define DFLT_PORT_BUF_MARGINS_END_MAARGINS 0
+#define DFLT_PORT_ERRORS_TO_DISCARD FM_PORT_FRM_ERR_CLS_DISCARD
+#define DFLT_PORT_MAX_FRAME_LENGTH 9600
+
+#define DFLT_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)
+
+#define DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS 0
+
+#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256
+
+/* Memory Mapped Registers */
+struct fm_port_rx_bmi_regs_t {
+ u32 fmbm_rcfg; /* Rx Configuration */
+ u32 fmbm_rst; /* Rx Status */
+ u32 fmbm_rda; /* Rx DMA attributes */
+ u32 fmbm_rfp; /* Rx FIFO Parameters */
+ u32 fmbm_rfed; /* Rx Frame End Data */
+ u32 fmbm_ricp; /* Rx Internal Context Parameters */
+ u32 fmbm_rim; /* Rx Internal Buffer Margins */
+ u32 fmbm_rebm; /* Rx External Buffer Margins */
+ u32 fmbm_rfne; /* Rx Frame Next Engine */
+ u32 fmbm_rfca; /* Rx Frame Command Attributes. */
+ u32 fmbm_rfpne; /* Rx Frame Parser Next Engine */
+ u32 fmbm_rpso; /* Rx Parse Start Offset */
+ u32 fmbm_rpp; /* Rx Policer Profile */
+ u32 fmbm_rccb; /* Rx Coarse Classification Base */
+ u32 fmbm_reth; /* Rx Excessive Threshold */
+ u32 reserved1[0x01]; /* (0x03C) */
+ u32 fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
+ /* Rx Parse Results Array Initialization */
+ u32 fmbm_rfqid; /* Rx Frame Queue ID */
+ u32 fmbm_refqid; /* Rx Error Frame Queue ID */
+ u32 fmbm_rfsdm; /* Rx Frame Status Discard Mask */
+ u32 fmbm_rfsem; /* Rx Frame Status Error Mask */
+ u32 fmbm_rfene; /* Rx Frame Enqueue Next Engine */
+ u32 reserved2[0x02]; /* (0x074-0x078) */
+ /* Rx Frame Continuous Mode Next Engine */
+ u32 fmbm_rcmne;
+ u32 reserved3[0x20]; /* (0x080 0x0FF) */
+ u32 fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /* Buffer Manager pool Information- */
+ u32 fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS]; /* Allocate Counter- */
+ u32 reserved4[0x08]; /* 0x130/0x140 - 0x15F reserved - */
+ u32 fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS / 32];
+ /* Congestion Group Map */
+ u32 fmbm_rmpd; /* BM Pool Depletion */
+ u32 reserved5[0x1F]; /* (0x184 0x1FF) */
+ u32 fmbm_rstc; /* Rx Statistics Counters */
+ u32 fmbm_rfrc; /* Rx Frame Counter */
+ u32 fmbm_rfbc; /* Rx Bad Frames Counter */
+ u32 fmbm_rlfc; /* Rx Large Frames Counter */
+ u32 fmbm_rffc; /* Rx Filter Frames Counter */
+ u32 fmbm_rfcd; /* Rx Frame Discard Counter */
+ u32 fmbm_rfldec; /* Rx Frames List DMA Error Counter */
+ u32 fmbm_rodc;/* Rx Out of Buffers Discard Counter- */
+ u32 fmbm_rbdc; /* Rx Buffers Deallocate Counter- */
+ u32 fmbm_rpec; /* Rx RX Prepare to enqueue Counter- */
+ u32 reserved6[0x16]; /* (0x228 0x27F) */
+ u32 fmbm_rpc; /* Rx Performance Counters */
+ u32 fmbm_rpcp; /* Rx Performance Count Parameters */
+ u32 fmbm_rccn; /* Rx Cycle Counter */
+ u32 fmbm_rtuc; /* Rx Tasks Utilization Counter */
+ u32 fmbm_rrquc;/* Rx Receive Queue Utilization Counter */
+ u32 fmbm_rduc; /* Rx DMA Utilization Counter */
+ u32 fmbm_rfuc; /* Rx FIFO Utilization Counter */
+ u32 fmbm_rpac; /* Rx Pause Activation Counter */
+ u32 reserved7[0x18]; /* (0x2A0-0x2FF) */
+ u32 fmbm_rdcfg[0x3]; /* Rx Debug- */
+ u32 fmbm_rgpr; /* Rx General Purpose Register. */
+ u32 reserved8[0x3a];
+ /* (0x310-0x3FF) */
+};
+
+struct fm_port_tx_bmi_regs_t {
+ u32 fmbm_tcfg; /* Tx Configuration */
+ u32 fmbm_tst; /* Tx Status */
+ u32 fmbm_tda; /* Tx DMA attributes */
+ u32 fmbm_tfp; /* Tx FIFO Parameters */
+ u32 fmbm_tfed; /* Tx Frame End Data */
+ u32 fmbm_ticp; /* Tx Internal Context Parameters */
+ u32 fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */
+ u32 fmbm_tfca; /* Tx Frame Command attribute. */
+ u32 fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */
+ u32 fmbm_tfeqid; /* Tx Frame Error Queue ID */
+ u32 fmbm_tfene; /* Tx Frame Enqueue Next Engine */
+ u32 fmbm_trlmts; /* Tx Rate Limiter Scale */
+ u32 fmbm_trlmt; /* Tx Rate Limiter */
+ u32 fmbm_tccb; /* Tx Coarse Classification Base */
+ u32 reserved0[0x0e]; /* (0x038-0x070) */
+ u32 fmbm_tfne; /* Tx Frame Next Engine */
+ u32 fmbm_tpfcm[0x02];
+ /* Tx Priority based Flow Control (PFC) Mapping */
+ u32 fmbm_tcmne; /* Tx Frame Continuous Mode Next Engine */
+ u32 reserved2[0x60]; /* (0x080-0x200) */
+ u32 fmbm_tstc; /* Tx Statistics Counters */
+ u32 fmbm_tfrc; /* Tx Frame Counter */
+ u32 fmbm_tfdc; /* Tx Frames Discard Counter */
+ u32 fmbm_tfledc; /* Tx Frame Length error discard counter */
+ /* Tx Frame unsupported format discard Counter */
+ u32 fmbm_tfufdc;
+ u32 fmbm_tbdc; /* Tx Buffers Deallocate Counter */
+ u32 reserved3[0x1A]; /* (0x218-0x280) */
+ u32 fmbm_tpc; /* Tx Performance Counters */
+ u32 fmbm_tpcp; /* Tx Performance Count Parameters */
+ u32 fmbm_tccn; /* Tx Cycle Counter */
+ u32 fmbm_ttuc; /* Tx Tasks Utilization Counter */
+ u32 fmbm_ttcquc; /* Tx Transmit Confirm Queue Utilization Counter */
+ u32 fmbm_tduc; /* Tx DMA Utilization Counter */
+ u32 fmbm_tfuc; /* Tx FIFO Utilization Counter */
+ u32 reserved4[16];/* (0x29C-0x2FF) */
+ u32 fmbm_tdcfg[0x3];
+ /* Tx Debug- */
+ u32 fmbm_tgpr; /* O/H General Purpose Register */
+ u32 reserved5[0x3a]; /* (0x310-0x3FF) */
+};
+
+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;
+};
+
+/* BMI defines */
+#define BMI_PORT_RFNE_FRWD_RPD 0x40000000
+
+#define BMI_STATUS_RX_MASK_UNUSED \
+(u32)(~(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 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)
+
+/* 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
+
+/* QMI defines */
+#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f
+
+struct fm_port_drv_param_t {
+ struct fman_port_cfg dflt_cfg;
+ u32 dflt_fqid;
+ u32 err_fqid;
+ void __iomem *base_addr;
+ u8 deq_sub_portal;
+ bool deq_high_priority;
+ enum fm_port_deq_type deq_type;
+ enum fm_port_deq_prefetch_option deq_prefetch_option;
+ u16 deq_byte_cnt;
+ u8 cheksum_last_bytes_ignore;
+ u8 cut_bytes_from_end;
+ struct fm_buf_pool_depletion_t buf_pool_depletion;
+ bool frm_discard_override;
+ bool en_buf_pool_depletion;
+ u16 liodn_offset;
+ u16 liodn_base;
+ struct fm_ext_pools_t ext_buf_pools;
+ u32 tx_fifo_min_fill_level;
+ u32 tx_fifo_low_comf_level;
+ u32 rx_fifo_pri_elevation_level;
+ u32 rx_fifo_threshold;
+ struct fm_sp_buf_margins_t buf_margins;
+ struct fm_sp_int_context_data_copy_t int_context;
+ u32 errors_to_discard;
+ bool forward_reuse_int_context;
+ struct fm_buffer_prefix_content_t buffer_prefix_content;
+ struct fm_backup_bm_pools_t *backup_bm_pools;
+ bool dont_release_buf;
+ bool set_num_of_tasks;
+ bool set_num_of_open_dmas;
+ bool set_size_of_fifo;
+ bool bcb_workaround;
+};
+
+struct fm_port_rx_pools_params_t {
+ u8 num_of_pools;
+ u16 second_largest_buf_size;
+ u16 largest_buf_size;
+};
+
+struct fm_port_intg_t {
+ u32 max_port_fifo_size;
+ u32 max_num_of_ext_pools;
+ u32 fm_max_num_of_sub_portals;
+ u32 bm_max_num_of_pools;
+};
+
+/* No PCD Engine indicated */
+#define FM_PCD_NONE 0
+
+struct fm_port_t {
+ struct fman_port port;
+ void *fm;
+ struct fm_revision_info_t fm_rev_info;
+ u8 port_id;
+ enum fm_port_type port_type;
+ enum fm_port_speed port_speed;
+ int enabled;
+ char name[MODULE_NAME_SIZE];
+
+ union fm_port_bmi_regs_u __iomem *fm_port_bmi_regs;
+ /* The optional engines are devined avobe */
+ struct fm_sp_buffer_offsets_t buffer_offsets;
+
+ u8 internal_buf_offset;
+ struct fm_ext_pools_t ext_buf_pools;
+
+ u16 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 *fm_port_drv_param;
+ struct fm_port_intg_t *port_intg;
+};
+
+static inline int fm_port_dflt_fifo_deq_pipeline_depth(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ switch (type) {
+ case FM_PORT_TYPE_RX:
+ case FM_PORT_TYPE_TX:
+ switch (speed) {
+ case FM_PORT_SPEED_10G:
+ return 4;
+ case FM_PORT_SPEED_1G:
+ if (major >= 6)
+ return 2;
+ else
+ return 1;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+static inline int fm_port_dflt_num_of_tasks(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ switch (type) {
+ case FM_PORT_TYPE_RX:
+ case FM_PORT_TYPE_TX:
+ switch (speed) {
+ case FM_PORT_SPEED_10G:
+ return 16;
+ case FM_PORT_SPEED_1G:
+ if (major >= 6)
+ return 4;
+ else
+ return 3;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+static inline int fm_port_dflt_extra_num_of_tasks(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ switch (type) {
+ case FM_PORT_TYPE_RX:
+ /* FMan V3 */
+ if (major >= 6)
+ return 0;
+
+ /* FMan V2 */
+ if (speed == FM_PORT_SPEED_10G)
+ return 8;
+ else
+ return 2;
+ case FM_PORT_TYPE_TX:
+ default:
+ return 0;
+ }
+}
+
+static inline int fm_port_dflt_num_of_open_dmas(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ int val;
+
+ if (major >= 6) {
+ switch (type) {
+ case FM_PORT_TYPE_TX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 12;
+ else
+ val = 3;
+ break;
+ case FM_PORT_TYPE_RX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 8;
+ else
+ val = 2;
+ break;
+ default:
+ return 0;
+ }
+ } else {
+ switch (type) {
+ case FM_PORT_TYPE_TX:
+ case FM_PORT_TYPE_RX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 8;
+ else
+ val = 1;
+ break;
+ default:
+ val = 0;
+ }
+ }
+
+ return val;
+}
+
+static inline int fm_port_dflt_extra_num_of_open_dmas(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ /* FMan V3 */
+ if (major >= 6)
+ return 0;
+
+ /* FMan V2 */
+ switch (type) {
+ case FM_PORT_TYPE_RX:
+ case FM_PORT_TYPE_TX:
+ if (speed == FM_PORT_SPEED_10G)
+ return 8;
+ else
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int fm_port_dflt_num_of_fifo_bufs(u8 major,
+ enum fm_port_type type,
+ enum fm_port_speed speed)
+{
+ int val;
+
+ if (major >= 6) {
+ switch (type) {
+ case FM_PORT_TYPE_TX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 64;
+ else
+ val = 50;
+ break;
+ case FM_PORT_TYPE_RX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 96;
+ else
+ val = 50;
+ break;
+ default:
+ val = 0;
+ }
+ } else {
+ switch (type) {
+ case FM_PORT_TYPE_TX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 48;
+ else
+ val = 44;
+ break;
+ case FM_PORT_TYPE_RX:
+ if (speed == FM_PORT_SPEED_10G)
+ val = 48;
+ else
+ val = 45;
+ break;
+ default:
+ val = 0;
+ }
+ }
+
+ return val;
+}
+
+#endif /* __FM_PORT_H */
--
1.7.9.5

2015-08-05 13:56:14

by Liberman Igal

[permalink] [raw]
Subject: [v4, 9/9] fsl/fman: Add FMan MAC driver

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 | 135 ++++
drivers/net/ethernet/freescale/fman/mac/Makefile | 3 +-
drivers/net/ethernet/freescale/fman/mac/mac-api.c | 688 +++++++++++++++++++++
drivers/net/ethernet/freescale/fman/mac/mac.c | 445 +++++++++++++
4 files changed, 1270 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..f86d0bc
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/inc/mac.h
@@ -0,0 +1,135 @@
+/* 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;
+ bool fixed_link;
+ u16 speed;
+ u16 max_speed;
+ struct device_node *phy_node;
+ 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 (*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 26e35e1..909abec 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 \
fman_memac.o fman_memac_mii_acc.o \
fm_memac.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..e7cac9f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/mac-api.c
@@ -0,0 +1,688 @@
+/* Copyright 2008-2015 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <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 enum e_enet_mode _100[] = {
+ [PHY_INTERFACE_MODE_MII] = ENET_MODE_MII_100,
+ [PHY_INTERFACE_MODE_RMII] = ENET_MODE_RMII_100
+};
+
+static const enum e_enet_mode _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 enum e_enet_mode __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;
+}
+EXPORT_SYMBOL(get_mac_handle);
+
+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 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))
+ devm_ioremap(mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(&param.addr, mac_dev->addr,
+ min(sizeof(param.addr), sizeof(mac_dev->addr)));
+ param.mac_id = mac_dev->cell_index;
+ param.fm = (void *)mac_dev->fm;
+ param.exception_cb = mac_exception;
+ param.event_cb = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = tgec_config(&param);
+ if (!priv->fm_mac) {
+ err = -EINVAL;
+ goto _return;
+ }
+
+ err = tgec_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = tgec_init(priv->fm_mac);
+ if (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 (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 (err < 0)
+ goto _return_fm_mac_free;
+ }
+
+ err = tgec_get_version(priv->fm_mac, &version);
+ if (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 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))
+ devm_ioremap(mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(&param.addr, mac_dev->addr,
+ min(sizeof(param.addr), sizeof(mac_dev->addr)));
+ param.mac_id = mac_dev->cell_index;
+ param.fm = (void *)mac_dev->fm;
+ param.exception_cb = mac_exception;
+ param.event_cb = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = dtsec_config(&param);
+ if (!priv->fm_mac) {
+ err = -EINVAL;
+ goto _return;
+ }
+
+ err = dtsec_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = dtsec_cfg_pad_and_crc(priv->fm_mac, true);
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = dtsec_init(priv->fm_mac);
+ if (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 (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 (err < 0)
+ goto _return_fm_mac_free;
+ }
+
+ err = dtsec_get_version(priv->fm_mac, &version);
+ if (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 memac_initialization(struct mac_device *mac_dev)
+{
+ int err;
+ struct mac_priv_s *priv;
+ struct fm_mac_params_t param;
+
+ priv = macdev_priv(mac_dev);
+
+ param.base_addr = (typeof(param.base_addr))
+ devm_ioremap(mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enet_mode = macdev2enetinterface(mac_dev);
+ memcpy(&param.addr, mac_dev->addr, sizeof(mac_dev->addr));
+ param.mac_id = mac_dev->cell_index;
+ param.fm = (void *)mac_dev->fm;
+ param.exception_cb = mac_exception;
+ param.event_cb = mac_exception;
+ param.dev_id = mac_dev;
+
+ priv->fm_mac = memac_config(&param);
+ if (!priv->fm_mac) {
+ err = -EINVAL;
+ goto _return;
+ }
+
+ err = memac_cfg_max_frame_len(priv->fm_mac, fm_get_max_frm());
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = memac_cfg_reset_on_init(priv->fm_mac, true);
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = memac_cfg_fixed_link(priv->fm_mac, mac_dev->fixed_link);
+ if (err < 0)
+ goto _return_fm_mac_free;
+
+ err = memac_init(priv->fm_mac);
+ if (err < 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 err;
+}
+
+static int 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 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)
+ phy_start(phy_dev);
+
+ return err;
+}
+
+static int 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)
+ phy_start(phy_dev);
+
+ return err;
+}
+
+static int 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 tgec_stop(struct mac_device *mac_dev)
+{
+ return tgec_disable(get_mac_handle(mac_dev),
+ COMM_MODE_RX_AND_TX);
+}
+
+static int 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 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 err = 0;
+
+ if (rx != mac_dev->rx_pause_active) {
+ err = mac_dev->set_rx_pause(fm_mac_dev, rx);
+ if (likely(err == 0))
+ mac_dev->rx_pause_active = rx;
+ }
+
+ if (tx != mac_dev->tx_pause_active) {
+ u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE :
+ FSL_FM_PAUSE_TIME_DISABLE);
+
+ err = mac_dev->set_tx_pause(fm_mac_dev, 0,
+ pause_time, 0);
+
+ if (likely(err == 0))
+ mac_dev->tx_pause_active = tx;
+ }
+
+ return err;
+}
+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_void(struct net_device *net_dev)
+{
+}
+
+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 (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 (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;
+
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link_dtsec, 0,
+ mac_dev->phy_if);
+ if (!phy_dev) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node->full_name);
+ return -ENODEV;
+ }
+
+ /* 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;
+
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, &adjust_link_void,
+ 0, mac_dev->phy_if);
+ if (!phy_dev) {
+ netdev_err(net_dev, "Could not attach to PHY %s\n",
+ mac_dev->phy_node->full_name);
+ return -ENODEV;
+ }
+
+ 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;
+
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link_memac, 0,
+ mac_dev->phy_if);
+
+ if (!phy_dev) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node->full_name);
+ return -ENODEV;
+ }
+
+ /* 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 void 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->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 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->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 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->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..c44544b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fman/mac/mac.c
@@ -0,0 +1,445 @@
+/* Copyright 2008-2015 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.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 *
+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 (!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 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(&eth_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(&eth_lock);
+
+ return pdev;
+
+err:
+ platform_device_put(pdev);
+no_mem:
+ mutex_unlock(&eth_lock);
+
+ return ERR_PTR(ret);
+}
+
+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 mac_probe(struct platform_device *_of_dev)
+{
+ int err, 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 *u32_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)) {
+ err = PTR_ERR(mac_dev);
+ dev_err(dev, "alloc_macdev() = %d\n", err);
+ goto _return;
+ }
+
+ INIT_LIST_HEAD(&mac_dev->mc_addr_list);
+
+ /* Get the FM node */
+ dev_node = of_get_parent(mac_node);
+ if (!dev_node) {
+ dev_err(dev, "of_get_parent(%s) failed\n",
+ mac_node->full_name);
+ err = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (!of_dev) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ err = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ /* Get the FMan cell-index */
+ u32_prop = of_get_property(dev_node, "cell-index", &lenp);
+ if (!u32_prop) {
+ dev_err(dev, "of_get_property(%s, cell-index) failed\n",
+ dev_node->full_name);
+ err = -EINVAL;
+ goto _return_of_node_put;
+ }
+ BUG_ON(lenp != sizeof(u32));
+ fman_id = (u8)*u32_prop + 1; /* cell-index 0 => FMan id 1 */
+
+ mac_dev->fm_dev = fm_bind(&of_dev->dev);
+ if (!mac_dev->fm_dev) {
+ dev_err(dev, "fm_bind(%s) failed\n", dev_node->full_name);
+ err = -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 */
+ err = of_address_to_resource(mac_node, 0, &res);
+ if (err < 0) {
+ dev_err(dev, "of_address_to_resource(%s) = %d\n",
+ mac_node->full_name, err);
+ 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 (!mac_dev->res) {
+ dev_err(dev, "__devm_request_mem_region(mac) failed\n");
+ err = -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 (!mac_dev->vaddr) {
+ dev_err(dev, "devm_ioremap() failed\n");
+ err = -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;
+
+ u32_prop = of_get_property(mac_dev->tbi_node, "reg", NULL);
+ if (u32_prop)
+ tbiaddr = *u32_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 */
+ u32_prop = of_get_property(mac_node, "cell-index", &lenp);
+ if (!u32_prop) {
+ dev_err(dev, "of_get_property(%s, cell-index) failed\n",
+ mac_node->full_name);
+ err = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+ BUG_ON(lenp != sizeof(u32));
+ mac_dev->cell_index = (u8)*u32_prop;
+
+ /* Get the MAC address */
+ mac_addr = of_get_mac_address(mac_node);
+ if (!mac_addr) {
+ dev_err(dev, "of_get_mac_address(%s) failed\n",
+ mac_node->full_name);
+ err = -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 (!phandle_prop) {
+ dev_err(dev, "of_get_property(%s, fsl,fman-ports) failed\n",
+ mac_node->full_name);
+ err = -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 (!dev_node) {
+ dev_err(dev, "of_find_node_by_phandle() failed\n");
+ err = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (!of_dev) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ err = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev);
+ if (!mac_dev->port_dev[i]) {
+ dev_err(dev, "dev_get_drvdata(%s) failed\n",
+ dev_node->full_name);
+ err = -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 (!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->fixed_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 && of_phy_is_fixed_link(mac_node)) {
+ err = of_phy_register_fixed_link(mac_node);
+ if (err)
+ goto _return_dev_set_drvdata;
+ mac_dev->fixed_link = true;
+ mac_dev->phy_node = of_node_get(mac_node);
+ }
+
+ err = mac_dev->init(mac_dev);
+ if (err < 0) {
+ dev_err(dev, "mac_dev->init() = %d\n", err);
+ of_node_put(mac_dev->phy_node);
+ 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;
+ err = set_mac_active_pause(mac_dev, true, true);
+ if (err < 0)
+ dev_err(dev, "set_mac_active_pause() = %d\n", err);
+
+ 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 err;
+}
+
+static struct platform_driver mac_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = mac_match,
+ },
+ .probe = mac_probe,
+};
+
+builtin_platform_driver(mac_driver);
--
1.7.9.5

2015-08-07 22:31:05

by David Miller

[permalink] [raw]
Subject: Re: [v4, 0/9] Freescale DPAA FMan

From: <[email protected]>
Date: Wed, 5 Aug 2015 12:25:16 +0300

> 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.

I think the directory and code structure of this new driver is
quite excessive.

Because you've split things up _so_ much, you have to have
all of these directories, and even worse and much more important
to me you have to export so many functions from one source file
to another.

I think this is way too much.

For example, in one file you have a bunch of initialization routines.
init_a(), init_b(), init_c(), and you export them all. Then they
are always called in sequence:

init_a();
init_b();
init_c();

This is completely pointless. You just needed to export one
function which calls all three functions.

The namespace pollution of this driver is out of control.

You really need to completely rework the architecture and
layout of this driver before I will even begin to review it
again.

And the lack of review interest by other developers should be an
indication to you how undesirable this code submission is to read.

Thanks.

2015-08-10 19:55:40

by Liberman Igal

[permalink] [raw]
Subject: RE: [v4, 0/9] Freescale DPAA FMan

Hello David,

Thank you for your feedback.

I understand your concerns regarding the FMan driver, we've come a long way from where we started but still there are issues.
The community support is critical for getting the code to the desired quality level and I appreciate the support I receive from you and from the other previous reviewers.

In order to reduce the code scattering I plan to put together all the code for a certain IP block in one file.
For example FMan port in his current state in /drivers/net/freescale/fman/:
flib (directory)
---- fsl_fman_port.h
inc (directory)
---- fm_port_ext.h (API for other drivers/modules)
port (directory)
---- fman_port.c (flib)
---- fm_port.c
---- fm_port.h
---- Makefile
fm_port_drv.c (file)

New proposed structure in /drivers/net/freescale/fman/:
fman_port_drv.c (includes simplified code from fm_port.c, fman_port.c and fm_port_drv.c)
fman_port_drv.h (exported structures and API, minimal)

Of-course, I'll do the same for other modules (MAC, FMan itself).

After this structure change we get:
- Subdirectories completely removed
- Layering reduced, each module becomes much flatter, with one source and header file
- Fewer number of files (sources and headers)
- Namespace pollution drastically reduced
- General complexity of the driver reduced.

I would appreciate your comments about the steps described above.

Regards,
Igal

> -----Original Message-----
> From: David Miller [mailto:[email protected]]
> Sent: Saturday, August 08, 2015 1:31 AM
> To: Liberman Igal-B31950 <[email protected]>
> Cc: [email protected]; [email protected]; linux-
> [email protected]; Wood Scott-B07421 <[email protected]>;
> Bucur Madalin-Cristian-B32716 <[email protected]>;
> [email protected]; [email protected]; [email protected];
> [email protected]
> Subject: Re: [v4, 0/9] Freescale DPAA FMan
>
> From: <[email protected]>
> Date: Wed, 5 Aug 2015 12:25:16 +0300
>
> > 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.
>
> I think the directory and code structure of this new driver is quite excessive.
>
> Because you've split things up _so_ much, you have to have all of these
> directories, and even worse and much more important to me you have to
> export so many functions from one source file to another.
>
> I think this is way too much.
>
> For example, in one file you have a bunch of initialization routines.
> init_a(), init_b(), init_c(), and you export them all. Then they are always
> called in sequence:
>
> init_a();
> init_b();
> init_c();
>
> This is completely pointless. You just needed to export one function which
> calls all three functions.
>
> The namespace pollution of this driver is out of control.
>
> You really need to completely rework the architecture and layout of this
> driver before I will even begin to review it again.
>
> And the lack of review interest by other developers should be an indication
> to you how undesirable this code submission is to read.
>
> Thanks.