Merge branch 'fsl-fmain'

Igal Liberman says:

====================
Freescale DPAA FMan

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

v9 --> v10:
	- Addressed feedback from David Miller
		Remove private CRC implementation
	- Addressed feedback from Kenneth Klette Jonassen:
		- Use Kernel PHY API to configure dTSEC TBI
		- Use Kernel PHY API to configure mEMAC PCS
		  This patchset requires device tree update:
		  https://patchwork.ozlabs.org/patch/559501/
	- Addressed feedback from Andy Fleming

v8 --> v9:
	No changes

v7 --> v8:
	- Addressed feedback from David Miller
	- Support for ARM:
		- Device tree parsing
		- IO Accessors
		- Addressed compilation issue on non-PPC targets

v6 --> v7:
	- Addressed compilation issue on non-PPC targets
	- Removed B4860 rev 1 support

v5 --> v6:
	- Addressed feedback from Scott:
		- Moved kernel doc to source files
		- Removed a series of configurable settings
		- Miscellaneous code updates

v4 --> v5:
	- Addressed feedback from David Miller:
		- Removed driver layering
		- Reduce namespace pollution
		- Reduce code complexity and size

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

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-12-27 20:51:40 -05:00
commit 7b752fd3d0
21 changed files with 10557 additions and 0 deletions

View File

@ -54,6 +54,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"

View File

@ -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/

View File

@ -0,0 +1,8 @@
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
(FMan) support

View File

@ -0,0 +1,7 @@
subdir-ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/fman
obj-y += fsl_fman.o fsl_fman_mac.o fsl_mac.o
fsl_fman-objs := fman_muram.o fman.o fman_sp.o fman_port.o
fsl_fman_mac-objs := fman_dtsec.o fman_memac.o fman_tgec.o
fsl_mac-objs += mac.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,325 @@
/*
* 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 <linux/io.h>
/* 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 */
/* TX-Port: Unsupported Format */
#define FM_FD_ERR_UNSUPPORTED_FORMAT 0x04000000
/* TX 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)
/* TX Port: Length Error */
#define FM_FD_ERR_IPRE (FM_FD_ERR_IPR & ~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
/* FMan driver defines */
#define FMAN_BMI_FIFO_UNITS 0x100
#define OFFSET_UNITS 16
/* BMan defines */
#define BM_MAX_NUM_OF_POOLS 64 /* Buffers pools */
#define FMAN_PORT_MAX_EXT_POOLS_NUM 8 /* External BM pools per Rx port */
struct fman; /* FMan data */
/* Enum for defining port types */
enum fman_port_type {
FMAN_PORT_TYPE_TX = 0, /* TX Port */
FMAN_PORT_TYPE_RX, /* RX Port */
};
struct fman_rev_info {
u8 major; /* Major revision */
u8 minor; /* Minor revision */
};
enum fman_exceptions {
FMAN_EX_DMA_BUS_ERROR = 0, /* DMA bus error. */
FMAN_EX_DMA_READ_ECC, /* Read Buffer ECC error */
FMAN_EX_DMA_SYSTEM_WRITE_ECC, /* Write Buffer ECC err on sys side */
FMAN_EX_DMA_FM_WRITE_ECC, /* Write Buffer ECC error on FM side */
FMAN_EX_DMA_SINGLE_PORT_ECC, /* Single Port ECC error on FM side */
FMAN_EX_FPM_STALL_ON_TASKS, /* Stall of tasks on FPM */
FMAN_EX_FPM_SINGLE_ECC, /* Single ECC on FPM. */
FMAN_EX_FPM_DOUBLE_ECC, /* Double ECC error on FPM ram access */
FMAN_EX_QMI_SINGLE_ECC, /* Single ECC on QMI. */
FMAN_EX_QMI_DOUBLE_ECC, /* Double bit ECC occurred on QMI */
FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/* DeQ from unknown port id */
FMAN_EX_BMI_LIST_RAM_ECC, /* Linked List RAM ECC error */
FMAN_EX_BMI_STORAGE_PROFILE_ECC,/* storage profile */
FMAN_EX_BMI_STATISTICS_RAM_ECC,/* Statistics RAM ECC Err Enable */
FMAN_EX_BMI_DISPATCH_RAM_ECC, /* Dispatch RAM ECC Error Enable */
FMAN_EX_IRAM_ECC, /* Double bit ECC occurred on IRAM */
FMAN_EX_MURAM_ECC /* Double bit ECC occurred on MURAM */
};
/* Parse results memory layout */
struct fman_prs_result {
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 */
};
/* A structure for defining buffer prefix area content. */
struct fman_buffer_prefix_content {
/* 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 fman_ext_pool_params {
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 fman_ext_pools {
u8 num_of_pools_used; /* Number of pools use by this port */
struct fman_ext_pool_params ext_buf_pool[FMAN_PORT_MAX_EXT_POOLS_NUM];
/* Parameters for each port */
};
/* A structure for defining BM pool depletion criteria */
struct fman_buf_pool_depletion {
/* 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];
};
/* Enum for inter-module interrupts registration */
enum fman_event_modules {
FMAN_MOD_MAC = 0, /* MAC event */
FMAN_MOD_FMAN_CTRL, /* FMAN Controller */
FMAN_MOD_DUMMY_LAST
};
/* Enum for interrupts types */
enum fman_intr_type {
FMAN_INTR_TYPE_ERR,
FMAN_INTR_TYPE_NORMAL
};
/* Enum for inter-module interrupts registration */
enum fman_inter_module_event {
FMAN_EV_ERR_MAC0 = 0, /* MAC 0 error event */
FMAN_EV_ERR_MAC1, /* MAC 1 error event */
FMAN_EV_ERR_MAC2, /* MAC 2 error event */
FMAN_EV_ERR_MAC3, /* MAC 3 error event */
FMAN_EV_ERR_MAC4, /* MAC 4 error event */
FMAN_EV_ERR_MAC5, /* MAC 5 error event */
FMAN_EV_ERR_MAC6, /* MAC 6 error event */
FMAN_EV_ERR_MAC7, /* MAC 7 error event */
FMAN_EV_ERR_MAC8, /* MAC 8 error event */
FMAN_EV_ERR_MAC9, /* MAC 9 error event */
FMAN_EV_MAC0, /* MAC 0 event (Magic packet detection) */
FMAN_EV_MAC1, /* MAC 1 event (Magic packet detection) */
FMAN_EV_MAC2, /* MAC 2 (Magic packet detection) */
FMAN_EV_MAC3, /* MAC 3 (Magic packet detection) */
FMAN_EV_MAC4, /* MAC 4 (Magic packet detection) */
FMAN_EV_MAC5, /* MAC 5 (Magic packet detection) */
FMAN_EV_MAC6, /* MAC 6 (Magic packet detection) */
FMAN_EV_MAC7, /* MAC 7 (Magic packet detection) */
FMAN_EV_MAC8, /* MAC 8 event (Magic packet detection) */
FMAN_EV_MAC9, /* MAC 9 event (Magic packet detection) */
FMAN_EV_FMAN_CTRL_0, /* Fman controller event 0 */
FMAN_EV_FMAN_CTRL_1, /* Fman controller event 1 */
FMAN_EV_FMAN_CTRL_2, /* Fman controller event 2 */
FMAN_EV_FMAN_CTRL_3, /* Fman controller event 3 */
FMAN_EV_CNT
};
struct fman_intr_src {
void (*isr_cb)(void *src_arg);
void *src_handle;
};
/* Structure for port-FM communication during fman_port_init. */
struct fman_port_init_params {
u8 port_id; /* port Id */
enum fman_port_type port_type; /* Port type */
u16 port_speed; /* Port speed */
u16 liodn_offset; /* Port's requested resource */
u8 num_of_tasks; /* Port's requested resource */
u8 num_of_extra_tasks; /* Port's requested resource */
u8 num_of_open_dmas; /* Port's requested resource */
u8 num_of_extra_open_dmas; /* Port's requested resource */
u32 size_of_fifo; /* Port's requested resource */
u32 extra_size_of_fifo; /* Port's requested resource */
u8 deq_pipeline_depth; /* Port's requested resource */
u16 max_frame_length; /* Port's max frame length. */
u16 liodn_base;
/* LIODN base for this port, to be used together with LIODN offset. */
};
void fman_get_revision(struct fman *fman, struct fman_rev_info *rev_info);
void fman_register_intr(struct fman *fman, enum fman_event_modules mod,
u8 mod_id, enum fman_intr_type intr_type,
void (*f_isr)(void *h_src_arg), void *h_src_arg);
void fman_unregister_intr(struct fman *fman, enum fman_event_modules mod,
u8 mod_id, enum fman_intr_type intr_type);
int fman_set_port_params(struct fman *fman,
struct fman_port_init_params *port_params);
int fman_reset_mac(struct fman *fman, u8 mac_id);
u16 fman_get_clock_freq(struct fman *fman);
u32 fman_get_bmi_max_fifo_size(struct fman *fman);
int fman_set_mac_max_frame(struct fman *fman, u8 mac_id, u16 mfl);
u32 fman_get_qman_channel_id(struct fman *fman, u32 port_id);
struct resource *fman_get_mem_region(struct fman *fman);
u16 fman_get_max_frm(void);
int fman_get_rx_extra_headroom(void);
struct fman *fman_bind(struct device *dev);
#endif /* __FM_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
/*
* 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 "fman_mac.h"
struct fman_mac *dtsec_config(struct fman_mac_params *params);
int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val);
int dtsec_modify_mac_address(struct fman_mac *dtsec, enet_addr_t *enet_addr);
int dtsec_adjust_link(struct fman_mac *dtsec,
u16 speed);
int dtsec_restart_autoneg(struct fman_mac *dtsec);
int dtsec_cfg_max_frame_len(struct fman_mac *dtsec, u16 new_val);
int dtsec_cfg_pad_and_crc(struct fman_mac *dtsec, bool new_val);
int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode);
int dtsec_disable(struct fman_mac *dtsec, enum comm_mode mode);
int dtsec_init(struct fman_mac *dtsec);
int dtsec_free(struct fman_mac *dtsec);
int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en);
int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, u8 priority,
u16 pause_time, u16 thresh_time);
int dtsec_set_exception(struct fman_mac *dtsec,
enum fman_mac_exceptions exception, bool enable);
int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr);
int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr);
int dtsec_get_version(struct fman_mac *dtsec, u32 *mac_version);
#endif /* __DTSEC_H */

View File

@ -0,0 +1,278 @@
/*
* 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 "fman.h"
#include <linux/slab.h>
#include <linux/phy.h>
#include <linux/if_ether.h>
struct fman_mac;
/* Ethernet Address */
typedef u8 enet_addr_t[ETH_ALEN];
#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 < ETH_ALEN; i++) \
(_enet_addr)[i] = \
(u8)((_addr64) >> ((5 - i) * 8)); \
} while (0)
/* 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, 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 fman_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 {
u64 addr; /* Ethernet Address */
struct list_head node;
};
typedef void (fman_mac_exception_cb)(void *dev_id,
enum fman_mac_exceptions exceptions);
/* FMan MAC config input */
struct fman_mac_params {
/* 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;
/* PHY interface */
phy_interface_t phy_if;
/* Note that the speed should indicate the maximum rate that
* this MAC should support rather than the actual speed;
*/
u16 max_speed;
/* 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 */
fman_mac_exception_cb *event_cb; /* MDIO Events Callback Routine */
fman_mac_exception_cb *exception_cb;/* Exception Callback Routine */
/* 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
*/
bool basex_if;
/* Pointer to TBI/PCS PHY node, used for TBI/PCS PHY access */
struct device_node *internal_phy_node;
};
struct eth_hash_t {
u16 size;
struct list_head *lsts;
};
static inline struct eth_hash_entry
*dequeue_addr_from_hash_entry(struct list_head *addr_lst)
{
struct eth_hash_entry *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 *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 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/*
* 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 "fman_mac.h"
#include <linux/netdevice.h>
struct fman_mac *memac_config(struct fman_mac_params *params);
int memac_set_promiscuous(struct fman_mac *memac, bool new_val);
int memac_modify_mac_address(struct fman_mac *memac, enet_addr_t *enet_addr);
int memac_adjust_link(struct fman_mac *memac, u16 speed);
int memac_cfg_max_frame_len(struct fman_mac *memac, u16 new_val);
int memac_cfg_reset_on_init(struct fman_mac *memac, bool enable);
int memac_cfg_fixed_link(struct fman_mac *memac,
struct fixed_phy_status *fixed_link);
int memac_enable(struct fman_mac *memac, enum comm_mode mode);
int memac_disable(struct fman_mac *memac, enum comm_mode mode);
int memac_init(struct fman_mac *memac);
int memac_free(struct fman_mac *memac);
int memac_accept_rx_pause_frames(struct fman_mac *memac, bool en);
int memac_set_tx_pause_frames(struct fman_mac *memac, u8 priority,
u16 pause_time, u16 thresh_time);
int memac_set_exception(struct fman_mac *memac,
enum fman_mac_exceptions exception, bool enable);
int memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
#endif /* __MEMAC_H */

View File

@ -0,0 +1,158 @@
/*
* 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 "fman_muram.h"
#include <linux/io.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;
};
static unsigned long fman_muram_vbase_to_offset(struct muram_info *muram,
unsigned long vaddr)
{
return vaddr - (unsigned long)muram->vbase;
}
/**
* fman_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 *fman_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__);
goto muram_free;
}
vaddr = ioremap(base, size);
if (!vaddr) {
pr_err("%s(): MURAM ioremap failed\n", __func__);
goto pool_destroy;
}
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);
goto pool_destroy;
}
memset_io(vaddr, 0, (int)size);
muram->vbase = vaddr;
muram->pbase = base;
return muram;
pool_destroy:
gen_pool_destroy(muram->pool);
muram_free:
kfree(muram);
return NULL;
}
/**
* fman_muram_offset_to_vbase
* @muram: FM-MURAM module pointer.
* @offset: the offset of the memory block
*
* Gives the address of the memory region from specific offset
*
* Return: The address of the memory block
*/
unsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
unsigned long offset)
{
return offset + (unsigned long)muram->vbase;
}
/**
* fman_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 fman_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 fman_muram_vbase_to_offset(muram, vaddr);
}
/**
* fman_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 fman_muram_free_mem(struct muram_info *muram, u32 offset, size_t size)
{
unsigned long addr = fman_muram_offset_to_vbase(muram, offset);
gen_pool_free(muram->pool, addr, size);
}

View File

@ -0,0 +1,51 @@
/*
* 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;
struct muram_info *fman_muram_init(phys_addr_t base, size_t size);
unsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
unsigned long offset);
int fman_muram_alloc(struct muram_info *muram, size_t size);
void fman_muram_free_mem(struct muram_info *muram, u32 offset, size_t size);
#endif /* __FM_MURAM_EXT */

File diff suppressed because it is too large Load Diff

View File

@ -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.
*/
#ifndef __FMAN_PORT_H
#define __FMAN_PORT_H
#include "fman.h"
/* FM Port API
* The FM uses a general module called "port" to represent a Tx port (MAC),
* an Rx port (MAC).
* 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.
*/
/* 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
struct fman_port;
/* A structure for additional Rx port parameters */
struct fman_port_rx_params {
u32 err_fqid; /* Error Queue Id. */
u32 dflt_fqid; /* Default Queue Id. */
/* Which external buffer pools are used
* (up to FMAN_PORT_MAX_EXT_POOLS_NUM), and their sizes.
*/
struct fman_ext_pools ext_buf_pools;
};
/* A structure for additional non-Rx port parameters */
struct fman_port_non_rx_params {
/* 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;
};
/* A union for additional parameters depending on port type */
union fman_port_specific_params {
/* Rx port parameters structure */
struct fman_port_rx_params rx_params;
/* Non-Rx port parameters structure */
struct fman_port_non_rx_params non_rx_params;
};
/* A structure representing FM initialization parameters */
struct fman_port_params {
/* Virtual Address of memory mapped FM Port registers. */
void *fm;
union fman_port_specific_params specific_params;
/* Additional parameters depending on port type. */
};
int fman_port_config(struct fman_port *port, struct fman_port_params *params);
int fman_port_init(struct fman_port *port);
int fman_port_cfg_buf_prefix_content(struct fman_port *port,
struct fman_buffer_prefix_content
*buffer_prefix_content);
int fman_port_disable(struct fman_port *port);
int fman_port_enable(struct fman_port *port);
u32 fman_port_get_qman_channel_id(struct fman_port *port);
struct fman_port *fman_port_bind(struct device *dev);
#endif /* __FMAN_PORT_H */

View File

@ -0,0 +1,166 @@
/*
* 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 "fman_sp.h"
#include "fman.h"
void fman_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fman_ext_pools
*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 fman_sp_build_buffer_struct(struct fman_sp_int_context_data_copy *
int_context_data_copy,
struct fman_buffer_prefix_content *
buffer_prefix_content,
struct fman_sp_buf_margins *buf_margins,
struct fman_sp_buffer_offsets *buffer_offsets,
u8 *internal_buf_offset)
{
u32 tmp;
/* Align start of internal context data to 16 byte */
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. */
buffer_offsets->prs_result_offset = (u32)ILLEGAL_BASE;
buffer_offsets->time_stamp_offset = (u32)ILLEGAL_BASE;
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. */
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 */
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)
buffer_offsets->prs_result_offset =
int_context_data_copy->ext_buf_offset;
if (buffer_prefix_content->pass_time_stamp)
buffer_offsets->time_stamp_offset =
buffer_prefix_content->pass_prs_result ?
(int_context_data_copy->ext_buf_offset +
sizeof(struct fman_prs_result)) :
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
*/
buffer_offsets->hash_result_offset =
buffer_prefix_content->pass_prs_result ?
(int_context_data_copy->ext_buf_offset +
sizeof(struct fman_prs_result) + 8) :
int_context_data_copy->ext_buf_offset + 8;
if (int_context_data_copy->size)
buf_margins->start_margins =
(u16)(int_context_data_copy->ext_buf_offset +
int_context_data_copy->size);
else
/* No Internal Context passing, STartMargin is
* immediately after private_info
*/
buf_margins->start_margins =
buffer_prefix_content->priv_data_size;
/* align data start */
tmp = (u32)(buf_margins->start_margins %
buffer_prefix_content->data_align);
if (tmp)
buf_margins->start_margins +=
(buffer_prefix_content->data_align - tmp);
buffer_offsets->data_offset = buf_margins->start_margins;
return 0;
}

View File

@ -0,0 +1,103 @@
/*
* Copyright 2008 - 2015 Freescale Semiconductor Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Freescale Semiconductor nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FM_SP_H
#define __FM_SP_H
#include "fman.h"
#include <linux/types.h>
#define ILLEGAL_BASE (~0)
/* defaults */
#define DFLT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN 64
/* 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
/* structure for defining internal context copying */
struct fman_sp_int_context_data_copy {
/* < 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 fman_sp_buf_margins {
/* 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 fman_sp_buffer_offsets {
u32 data_offset;
u32 prs_result_offset;
u32 time_stamp_offset;
u32 hash_result_offset;
};
int fman_sp_build_buffer_struct(struct fman_sp_int_context_data_copy
*int_context_data_copy,
struct fman_buffer_prefix_content
*buffer_prefix_content,
struct fman_sp_buf_margins *buf_margins,
struct fman_sp_buffer_offsets
*buffer_offsets,
u8 *internal_buf_offset);
void fman_sp_set_buf_pools_in_asc_order_of_buf_sizes(struct fman_ext_pools
*fm_ext_pools,
u8 *ordered_array,
u16 *sizes_array);
#endif /* __FM_SP_H */

View File

@ -0,0 +1,786 @@
/*
* 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 "fman_tgec.h"
#include "fman.h"
#include <linux/slab.h>
#include <linux/bitrev.h>
#include <linux/io.h>
#include <linux/crc32.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_NO_LEN_CHK 0x00020000
#define CMD_CFG_PAUSE_IGNORE 0x00000100
#define CMF_CFG_CRC_FWD 0x00000040
#define CMD_CFG_PROMIS_EN 0x00000010
#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
/* 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_TX_IPG_LENGTH 12
#define DEFAULT_MAX_FRAME_LENGTH 0x600
#define DEFAULT_PAUSE_QUANT 0xf000
/* 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
/* tGEC 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 {
bool pause_ignore;
bool promiscuous_mode_enable;
u16 max_frame_length;
u16 pause_quant;
u32 tx_ipg_length;
};
struct fman_mac {
/* Pointer to the memory mapped registers. */
struct tgec_regs __iomem *regs;
/* MAC address of device; */
u64 addr;
u16 max_speed;
void *dev_id; /* device cookie used by the exception cbs */
fman_mac_exception_cb *exception_cb;
fman_mac_exception_cb *event_cb;
/* 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;
u32 exceptions;
struct tgec_cfg *cfg;
void *fm;
struct fman_rev_info fm_rev_info;
};
static void 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);
}
static void set_dflts(struct tgec_cfg *cfg)
{
cfg->promiscuous_mode_enable = false;
cfg->pause_ignore = false;
cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH;
cfg->pause_quant = DEFAULT_PAUSE_QUANT;
}
static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
u32 exception_mask)
{
u32 tmp;
/* Config */
tmp = CMF_CFG_CRC_FWD;
if (cfg->promiscuous_mode_enable)
tmp |= CMD_CFG_PROMIS_EN;
if (cfg->pause_ignore)
tmp |= CMD_CFG_PAUSE_IGNORE;
/* Payload length check disable */
tmp |= CMD_CFG_NO_LEN_CHK;
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 */
iowrite32be(0xffffffff, &regs->ievent);
iowrite32be(ioread32be(&regs->imask) | exception_mask, &regs->imask);
return 0;
}
static int check_init_parameters(struct fman_mac *tgec)
{
if (tgec->max_speed < 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;
}
return 0;
}
static int get_exception_flag(enum fman_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 void tgec_err_exception(void *handle)
{
struct fman_mac *tgec = (struct fman_mac *)handle;
struct tgec_regs __iomem *regs = tgec->regs;
u32 event;
/* do not handle MDIO events */
event = ioread32be(&regs->ievent) &
~(TGEC_IMASK_MDIO_SCAN_EVENT |
TGEC_IMASK_MDIO_CMD_CMPL);
event &= ioread32be(&regs->imask);
iowrite32be(event, &regs->ievent);
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 fman_mac *tgec)
{
fman_unregister_intr(tgec->fm, FMAN_MOD_MAC, tgec->mac_id,
FMAN_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 *cfg)
{
/* Checks if tGEC driver parameters were initialized */
if (!cfg)
return true;
return false;
}
int tgec_enable(struct fman_mac *tgec, enum comm_mode mode)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (mode & COMM_MODE_RX)
tmp |= CMD_CFG_RX_EN;
if (mode & COMM_MODE_TX)
tmp |= CMD_CFG_TX_EN;
iowrite32be(tmp, &regs->command_config);
return 0;
}
int tgec_disable(struct fman_mac *tgec, enum comm_mode mode)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (mode & COMM_MODE_RX)
tmp &= ~CMD_CFG_RX_EN;
if (mode & COMM_MODE_TX)
tmp &= ~CMD_CFG_TX_EN;
iowrite32be(tmp, &regs->command_config);
return 0;
}
int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (new_val)
tmp |= CMD_CFG_PROMIS_EN;
else
tmp &= ~CMD_CFG_PROMIS_EN;
iowrite32be(tmp, &regs->command_config);
return 0;
}
int tgec_cfg_max_frame_len(struct fman_mac *tgec, u16 new_val)
{
if (is_init_done(tgec->cfg))
return -EINVAL;
tgec->cfg->max_frame_length = new_val;
return 0;
}
int tgec_set_tx_pause_frames(struct fman_mac *tgec, u8 __maybe_unused priority,
u16 pause_time, u16 __maybe_unused thresh_time)
{
struct tgec_regs __iomem *regs = tgec->regs;
if (!is_init_done(tgec->cfg))
return -EINVAL;
iowrite32be((u32)pause_time, &regs->pause_quant);
return 0;
}
int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (!en)
tmp |= CMD_CFG_PAUSE_IGNORE;
else
tmp &= ~CMD_CFG_PAUSE_IGNORE;
iowrite32be(tmp, &regs->command_config);
return 0;
}
int tgec_modify_mac_address(struct fman_mac *tgec, enet_addr_t *p_enet_addr)
{
if (!is_init_done(tgec->cfg))
return -EINVAL;
tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
set_mac_address(tgec->regs, (u8 *)(*p_enet_addr));
return 0;
}
int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr)
{
struct tgec_regs __iomem *regs = tgec->regs;
struct eth_hash_entry *hash_entry;
u32 crc = 0xFFFFFFFF, hash;
u64 addr;
if (!is_init_done(tgec->cfg))
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 = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
crc = bitrev32(crc);
/* 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]);
iowrite32be((hash | TGEC_HASH_MCAST_EN), &regs->hashtable_ctrl);
return 0;
}
int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr)
{
struct tgec_regs __iomem *regs = tgec->regs;
struct eth_hash_entry *hash_entry = NULL;
struct list_head *pos;
u32 crc = 0xFFFFFFFF, hash;
u64 addr;
if (!is_init_done(tgec->cfg))
return -EINVAL;
addr = ((*(u64 *)eth_addr) >> 16);
/* CRC calculation */
crc = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
crc = bitrev32(crc);
/* Take 9 MSB bits */
hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
list_for_each(pos, &tgec->multicast_addr_hash->lsts[hash]) {
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(&tgec->multicast_addr_hash->lsts[hash]))
iowrite32be((hash & ~TGEC_HASH_MCAST_EN),
&regs->hashtable_ctrl);
return 0;
}
int tgec_get_version(struct fman_mac *tgec, u32 *mac_version)
{
struct tgec_regs __iomem *regs = tgec->regs;
if (!is_init_done(tgec->cfg))
return -EINVAL;
*mac_version = ioread32be(&regs->tgec_id);
return 0;
}
int tgec_set_exception(struct fman_mac *tgec,
enum fman_mac_exceptions exception, bool enable)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 bit_mask = 0;
if (!is_init_done(tgec->cfg))
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)
iowrite32be(ioread32be(&regs->imask) | bit_mask, &regs->imask);
else
iowrite32be(ioread32be(&regs->imask) & ~bit_mask, &regs->imask);
return 0;
}
int tgec_init(struct fman_mac *tgec)
{
struct tgec_cfg *cfg;
enet_addr_t eth_addr;
int err;
if (is_init_done(tgec->cfg))
return -EINVAL;
if (DEFAULT_RESET_ON_INIT &&
(fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) {
pr_err("Can't reset MAC!\n");
return -EINVAL;
}
err = check_init_parameters(tgec);
if (err)
return err;
cfg = tgec->cfg;
MAKE_ENET_ADDR_FROM_UINT64(tgec->addr, eth_addr);
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 <= 2)
tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT |
TGEC_IMASK_LOC_FAULT);
err = init(tgec->regs, cfg, 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 = fman_set_mac_max_frame(tgec->fm, tgec->mac_id,
cfg->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 == 2) {
struct tgec_regs __iomem *regs = tgec->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);
}
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;
}
fman_register_intr(tgec->fm, FMAN_MOD_MAC, tgec->mac_id,
FMAN_INTR_TYPE_ERR, tgec_err_exception, tgec);
kfree(cfg);
tgec->cfg = NULL;
return 0;
}
int tgec_free(struct fman_mac *tgec)
{
free_init_resources(tgec);
if (tgec->cfg)
tgec->cfg = NULL;
kfree(tgec->cfg);
kfree(tgec);
return 0;
}
struct fman_mac *tgec_config(struct fman_mac_params *params)
{
struct fman_mac *tgec;
struct tgec_cfg *cfg;
void __iomem *base_addr;
base_addr = params->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. */
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
tgec_free(tgec);
return NULL;
}
/* Plant parameter structure pointer */
tgec->cfg = cfg;
set_dflts(cfg);
tgec->regs = base_addr;
tgec->addr = ENET_ADDR_TO_UINT64(params->addr);
tgec->max_speed = params->max_speed;
tgec->mac_id = params->mac_id;
tgec->exceptions = (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);
tgec->exception_cb = params->exception_cb;
tgec->event_cb = params->event_cb;
tgec->dev_id = params->dev_id;
tgec->fm = params->fm;
/* Save FMan revision */
fman_get_revision(tgec->fm, &tgec->fm_rev_info);
return tgec;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2008-2015 Freescale Semiconductor Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Freescale Semiconductor nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TGEC_H
#define __TGEC_H
#include "fman_mac.h"
struct fman_mac *tgec_config(struct fman_mac_params *params);
int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val);
int tgec_modify_mac_address(struct fman_mac *tgec, enet_addr_t *enet_addr);
int tgec_cfg_max_frame_len(struct fman_mac *tgec, u16 new_val);
int tgec_enable(struct fman_mac *tgec, enum comm_mode mode);
int tgec_disable(struct fman_mac *tgec, enum comm_mode mode);
int tgec_init(struct fman_mac *tgec);
int tgec_free(struct fman_mac *tgec);
int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en);
int tgec_set_tx_pause_frames(struct fman_mac *tgec, u8 priority,
u16 pause_time, u16 thresh_time);
int tgec_set_exception(struct fman_mac *tgec,
enum fman_mac_exceptions exception, bool enable);
int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr);
int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr);
int tgec_get_version(struct fman_mac *tgec, u32 *mac_version);
#endif /* __TGEC_H */

View File

@ -0,0 +1,978 @@
/* 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 <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/etherdevice.h>
#include <linux/libfdt_env.h>
#include "mac.h"
#include "fman_mac.h"
#include "fman_dtsec.h"
#include "fman_tgec.h"
#include "fman_memac.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("FSL FMan MAC API based driver");
struct mac_priv_s {
struct device *dev;
void __iomem *vaddr;
u8 cell_index;
phy_interface_t phy_if;
struct fman *fman;
struct device_node *phy_node;
struct device_node *internal_phy_node;
/* List of multicast addresses */
struct list_head mc_addr_list;
struct platform_device *eth_dev;
struct fixed_phy_status *fixed_link;
u16 speed;
u16 max_speed;
int (*enable)(struct fman_mac *mac_dev, enum comm_mode mode);
int (*disable)(struct fman_mac *mac_dev, enum comm_mode mode);
};
struct mac_address {
u8 addr[ETH_ALEN];
struct list_head list;
};
static void mac_exception(void *handle, enum fman_mac_exceptions ex)
{
struct mac_device *mac_dev;
struct mac_priv_s *priv;
mac_dev = handle;
priv = mac_dev->priv;
if (ex == FM_MAC_EX_10G_RX_FIFO_OVFL) {
/* don't flag RX FIFO after the first */
mac_dev->set_exception(mac_dev->fman_mac,
FM_MAC_EX_10G_RX_FIFO_OVFL, false);
dev_err(priv->dev, "10G MAC got RX FIFO Error = %x\n", ex);
}
dev_dbg(priv->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c",
__func__, ex);
}
static void set_fman_mac_params(struct mac_device *mac_dev,
struct fman_mac_params *params)
{
struct mac_priv_s *priv = mac_dev->priv;
params->base_addr = (typeof(params->base_addr))
devm_ioremap(priv->dev, mac_dev->res->start,
resource_size(mac_dev->res));
memcpy(&params->addr, mac_dev->addr, sizeof(mac_dev->addr));
params->max_speed = priv->max_speed;
params->phy_if = priv->phy_if;
params->basex_if = false;
params->mac_id = priv->cell_index;
params->fm = (void *)priv->fman;
params->exception_cb = mac_exception;
params->event_cb = mac_exception;
params->dev_id = mac_dev;
params->internal_phy_node = priv->internal_phy_node;
}
static int tgec_initialization(struct mac_device *mac_dev)
{
int err;
struct mac_priv_s *priv;
struct fman_mac_params params;
u32 version;
priv = mac_dev->priv;
set_fman_mac_params(mac_dev, &params);
mac_dev->fman_mac = tgec_config(&params);
if (!mac_dev->fman_mac) {
err = -EINVAL;
goto _return;
}
err = tgec_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm());
if (err < 0)
goto _return_fm_mac_free;
err = tgec_init(mac_dev->fman_mac);
if (err < 0)
goto _return_fm_mac_free;
/* For 10G MAC, disable Tx ECC exception */
err = mac_dev->set_exception(mac_dev->fman_mac,
FM_MAC_EX_10G_TX_ECC_ER, false);
if (err < 0)
goto _return_fm_mac_free;
err = tgec_get_version(mac_dev->fman_mac, &version);
if (err < 0)
goto _return_fm_mac_free;
dev_info(priv->dev, "FMan XGEC version: 0x%08x\n", version);
goto _return;
_return_fm_mac_free:
tgec_free(mac_dev->fman_mac);
_return:
return err;
}
static int dtsec_initialization(struct mac_device *mac_dev)
{
int err;
struct mac_priv_s *priv;
struct fman_mac_params params;
u32 version;
priv = mac_dev->priv;
set_fman_mac_params(mac_dev, &params);
mac_dev->fman_mac = dtsec_config(&params);
if (!mac_dev->fman_mac) {
err = -EINVAL;
goto _return;
}
err = dtsec_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm());
if (err < 0)
goto _return_fm_mac_free;
err = dtsec_cfg_pad_and_crc(mac_dev->fman_mac, true);
if (err < 0)
goto _return_fm_mac_free;
err = dtsec_init(mac_dev->fman_mac);
if (err < 0)
goto _return_fm_mac_free;
/* For 1G MAC, disable by default the MIB counters overflow interrupt */
err = mac_dev->set_exception(mac_dev->fman_mac,
FM_MAC_EX_1G_RX_MIB_CNT_OVFL, false);
if (err < 0)
goto _return_fm_mac_free;
err = dtsec_get_version(mac_dev->fman_mac, &version);
if (err < 0)
goto _return_fm_mac_free;
dev_info(priv->dev, "FMan dTSEC version: 0x%08x\n", version);
goto _return;
_return_fm_mac_free:
dtsec_free(mac_dev->fman_mac);
_return:
return err;
}
static int memac_initialization(struct mac_device *mac_dev)
{
int err;
struct mac_priv_s *priv;
struct fman_mac_params params;
priv = mac_dev->priv;
set_fman_mac_params(mac_dev, &params);
if (priv->max_speed == SPEED_10000)
params.phy_if = PHY_INTERFACE_MODE_XGMII;
mac_dev->fman_mac = memac_config(&params);
if (!mac_dev->fman_mac) {
err = -EINVAL;
goto _return;
}
err = memac_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm());
if (err < 0)
goto _return_fm_mac_free;
err = memac_cfg_reset_on_init(mac_dev->fman_mac, true);
if (err < 0)
goto _return_fm_mac_free;
err = memac_cfg_fixed_link(mac_dev->fman_mac, priv->fixed_link);
if (err < 0)
goto _return_fm_mac_free;
err = memac_init(mac_dev->fman_mac);
if (err < 0)
goto _return_fm_mac_free;
dev_info(priv->dev, "FMan MEMAC\n");
goto _return;
_return_fm_mac_free:
memac_free(mac_dev->fman_mac);
_return:
return err;
}
static int start(struct mac_device *mac_dev)
{
int err;
struct phy_device *phy_dev = mac_dev->phy_dev;
struct mac_priv_s *priv = mac_dev->priv;
err = priv->enable(mac_dev->fman_mac, COMM_MODE_RX_AND_TX);
if (!err && phy_dev)
phy_start(phy_dev);
return err;
}
static int stop(struct mac_device *mac_dev)
{
struct mac_priv_s *priv = mac_dev->priv;
if (mac_dev->phy_dev)
phy_stop(mac_dev->phy_dev);
return priv->disable(mac_dev->fman_mac, COMM_MODE_RX_AND_TX);
}
static int set_multi(struct net_device *net_dev, struct mac_device *mac_dev)
{
struct mac_priv_s *priv;
struct mac_address *old_addr, *tmp;
struct netdev_hw_addr *ha;
int err;
enet_addr_t *addr;
priv = mac_dev->priv;
/* Clear previous address list */
list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) {
addr = (enet_addr_t *)old_addr->addr;
err = mac_dev->remove_hash_mac_addr(mac_dev->fman_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_dev->fman_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, &priv->mc_addr_list);
}
return 0;
}
/**
* fman_set_mac_active_pause
* @mac_dev: A pointer to the MAC device
* @rx: Pause frame setting for RX
* @tx: Pause frame setting for TX
*
* Set the MAC RX/TX PAUSE frames settings
*
* 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.
*
* Return: 0 on success; Error code otherwise.
*/
int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
{
struct fman_mac *fman_mac = mac_dev->fman_mac;
int err = 0;
if (rx != mac_dev->rx_pause_active) {
err = mac_dev->set_rx_pause(fman_mac, 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(fman_mac, 0, pause_time, 0);
if (likely(err == 0))
mac_dev->tx_pause_active = tx;
}
return err;
}
EXPORT_SYMBOL(fman_set_mac_active_pause);
/**
* fman_get_pause_cfg
* @mac_dev: A pointer to the MAC device
* @rx: Return value for RX setting
* @tx: Return value for TX setting
*
* Determine the MAC RX/TX PAUSE frames settings based on PHY
* autonegotiation or values set by eththool.
*
* Return: Pointer to FMan device.
*/
void fman_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(fman_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 fman_mac *fman_mac;
bool rx_pause, tx_pause;
int err;
fman_mac = mac_dev->fman_mac;
if (!phy_dev->link) {
dtsec_restart_autoneg(fman_mac);
return;
}
dtsec_adjust_link(fman_mac, phy_dev->speed);
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
if (err < 0)
netdev_err(net_dev, "fman_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 fman_mac *fman_mac;
bool rx_pause, tx_pause;
int err;
fman_mac = mac_dev->fman_mac;
memac_adjust_link(fman_mac, phy_dev->speed);
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
if (err < 0)
netdev_err(net_dev, "fman_set_mac_active_pause() = %d\n", err);
}
/* Initializes driver's PHY state, and attaches to the PHY.
* Returns 0 on success.
*/
static int init_phy(struct net_device *net_dev,
struct mac_device *mac_dev,
void (*adj_lnk)(struct net_device *))
{
struct phy_device *phy_dev;
struct mac_priv_s *priv = mac_dev->priv;
phy_dev = of_phy_connect(net_dev, priv->phy_node, adj_lnk, 0,
priv->phy_if);
if (!phy_dev) {
netdev_err(net_dev, "Could not connect to PHY\n");
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 dtsec_init_phy(struct net_device *net_dev,
struct mac_device *mac_dev)
{
return init_phy(net_dev, mac_dev, &adjust_link_dtsec);
}
static int tgec_init_phy(struct net_device *net_dev,
struct mac_device *mac_dev)
{
return init_phy(net_dev, mac_dev, adjust_link_void);
}
static int memac_init_phy(struct net_device *net_dev,
struct mac_device *mac_dev)
{
return init_phy(net_dev, mac_dev, &adjust_link_memac);
}
static void setup_dtsec(struct mac_device *mac_dev)
{
mac_dev->init_phy = dtsec_init_phy;
mac_dev->init = dtsec_initialization;
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_tx_pause = dtsec_set_tx_pause_frames;
mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames;
mac_dev->set_exception = dtsec_set_exception;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
mac_dev->priv->enable = dtsec_enable;
mac_dev->priv->disable = dtsec_disable;
}
static void setup_tgec(struct mac_device *mac_dev)
{
mac_dev->init_phy = tgec_init_phy;
mac_dev->init = tgec_initialization;
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_tx_pause = tgec_set_tx_pause_frames;
mac_dev->set_rx_pause = tgec_accept_rx_pause_frames;
mac_dev->set_exception = tgec_set_exception;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
mac_dev->priv->enable = tgec_enable;
mac_dev->priv->disable = tgec_disable;
}
static void setup_memac(struct mac_device *mac_dev)
{
mac_dev->init_phy = memac_init_phy;
mac_dev->init = memac_initialization;
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_tx_pause = memac_set_tx_pause_frames;
mac_dev->set_rx_pause = memac_accept_rx_pause_frames;
mac_dev->set_exception = memac_set_exception;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
mac_dev->priv->enable = memac_enable;
mac_dev->priv->disable = memac_disable;
}
#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 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;
struct mac_priv_s *priv;
static int dpaa_eth_dev_cnt;
int ret;
priv = mac_dev->priv;
data.mac_dev = mac_dev;
data.mac_hw_id = priv->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[] = {
{ .compatible = "fsl,fman-dtsec" },
{ .compatible = "fsl,fman-xgec" },
{ .compatible = "fsl,fman-memac" },
{}
};
MODULE_DEVICE_TABLE(of, mac_match);
static int mac_probe(struct platform_device *_of_dev)
{
int err, i, lenp, nph;
struct device *dev;
struct device_node *mac_node, *dev_node;
struct mac_device *mac_dev;
struct platform_device *of_dev;
struct resource res;
struct mac_priv_s *priv;
const u8 *mac_addr;
const char *char_prop;
const u32 *u32_prop;
u8 fman_id;
dev = &_of_dev->dev;
mac_node = dev->of_node;
mac_dev = devm_kzalloc(dev, sizeof(*mac_dev), GFP_KERNEL);
if (!mac_dev) {
err = -ENOMEM;
dev_err(dev, "devm_kzalloc() = %d\n", err);
goto _return;
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
err = -ENOMEM;
goto _return;
}
/* Save private information */
mac_dev->priv = priv;
priv->dev = dev;
if (of_device_is_compatible(mac_node, "fsl,fman-dtsec")) {
setup_dtsec(mac_dev);
priv->internal_phy_node = of_parse_phandle(mac_node,
"tbi-handle", 0);
} else if (of_device_is_compatible(mac_node, "fsl,fman-xgec")) {
setup_tgec(mac_dev);
} else if (of_device_is_compatible(mac_node, "fsl,fman-memac")) {
setup_memac(mac_dev);
priv->internal_phy_node = of_parse_phandle(mac_node,
"pcsphy-handle", 0);
} else {
dev_err(dev, "MAC node (%s) contains unsupported MAC\n",
mac_node->full_name);
err = -EINVAL;
goto _return;
}
/* Register mac_dev */
dev_set_drvdata(dev, mac_dev);
INIT_LIST_HEAD(&priv->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;
}
WARN_ON(lenp != sizeof(u32));
/* cell-index 0 => FMan id 1 */
fman_id = (u8)(fdt32_to_cpu(u32_prop[0]) + 1);
priv->fman = fman_bind(&of_dev->dev);
if (!priv->fman) {
dev_err(dev, "fman_bind(%s) failed\n", dev_node->full_name);
err = -ENODEV;
goto _return_of_node_put;
}
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,
fman_get_mem_region(priv->fman),
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;
}
priv->vaddr = devm_ioremap(dev, mac_dev->res->start,
mac_dev->res->end + 1 - mac_dev->res->start);
if (!priv->vaddr) {
dev_err(dev, "devm_ioremap() failed\n");
err = -EIO;
goto _return_dev_set_drvdata;
}
if (!of_device_is_available(mac_node)) {
devm_iounmap(dev, priv->vaddr);
__devm_release_region(dev, fman_get_mem_region(priv->fman),
res.start, res.end + 1 - res.start);
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;
}
WARN_ON(lenp != sizeof(u32));
priv->cell_index = (u8)fdt32_to_cpu(u32_prop[0]);
/* 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 */
nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
if (unlikely(nph < 0)) {
dev_err(dev, "of_count_phandle_with_args(%s, fsl,fman-ports) failed\n",
mac_node->full_name);
err = nph;
goto _return_dev_set_drvdata;
}
if (nph != ARRAY_SIZE(mac_dev->port)) {
dev_err(dev, "Not supported number of fman-ports handles of mac node %s from device tree\n",
mac_node->full_name);
err = -EINVAL;
goto _return_dev_set_drvdata;
}
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
/* Find the port node */
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
if (!dev_node) {
dev_err(dev, "of_parse_phandle(%s, fsl,fman-ports) failed\n",
mac_node->full_name);
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[i] = fman_port_bind(&of_dev->dev);
if (!mac_dev->port[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);
priv->phy_if = PHY_INTERFACE_MODE_MII;
} else {
priv->phy_if = str2phy(char_prop);
}
priv->speed = phy2speed[priv->phy_if];
priv->max_speed = priv->speed;
mac_dev->if_support = DTSEC_SUPPORTED;
/* We don't support half-duplex in SGMII mode */
if (priv->phy_if == PHY_INTERFACE_MODE_SGMII)
mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
SUPPORTED_100baseT_Half);
/* Gigabit support (no half-duplex) */
if (priv->max_speed == 1000)
mac_dev->if_support |= SUPPORTED_1000baseT_Full;
/* The 10G interface only supports one mode */
if (priv->phy_if == PHY_INTERFACE_MODE_XGMII)
mac_dev->if_support = SUPPORTED_10000baseT_Full;
/* Get the rest of the PHY information */
priv->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
if (!priv->phy_node && of_phy_is_fixed_link(mac_node)) {
struct phy_device *phy;
err = of_phy_register_fixed_link(mac_node);
if (err)
goto _return_dev_set_drvdata;
priv->fixed_link = kzalloc(sizeof(*priv->fixed_link),
GFP_KERNEL);
if (!priv->fixed_link)
goto _return_dev_set_drvdata;
priv->phy_node = of_node_get(mac_node);
phy = of_phy_find_device(priv->phy_node);
if (!phy)
goto _return_dev_set_drvdata;
priv->fixed_link->link = phy->link;
priv->fixed_link->speed = phy->speed;
priv->fixed_link->duplex = phy->duplex;
priv->fixed_link->pause = phy->pause;
priv->fixed_link->asym_pause = phy->asym_pause;
}
err = mac_dev->init(mac_dev);
if (err < 0) {
dev_err(dev, "mac_dev->init() = %d\n", err);
of_node_put(priv->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 = fman_set_mac_active_pause(mac_dev, true, true);
if (err < 0)
dev_err(dev, "fman_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]);
priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev, mac_node);
if (IS_ERR(priv->eth_dev)) {
dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
priv->cell_index);
priv->eth_dev = NULL;
}
goto _return;
_return_of_node_put:
of_node_put(dev_node);
_return_dev_set_drvdata:
kfree(priv->fixed_link);
kfree(priv);
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);

View File

@ -0,0 +1,97 @@
/* 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>
#include <linux/if_ether.h>
#include <linux/phy.h>
#include <linux/list.h>
#include "fman_port.h"
#include "fman.h"
#include "fman_mac.h"
struct fman_mac;
struct mac_priv_s;
struct mac_device {
struct resource *res;
u8 addr[ETH_ALEN];
struct fman_port *port[2];
u32 if_support;
struct phy_device *phy_dev;
bool autoneg_pause;
bool rx_pause_req;
bool tx_pause_req;
bool rx_pause_active;
bool tx_pause_active;
bool promisc;
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 fman_mac *mac_dev, bool enable);
int (*change_addr)(struct fman_mac *mac_dev, enet_addr_t *enet_addr);
int (*set_multi)(struct net_device *net_dev,
struct mac_device *mac_dev);
int (*set_rx_pause)(struct fman_mac *mac_dev, bool en);
int (*set_tx_pause)(struct fman_mac *mac_dev, u8 priority,
u16 pause_time, u16 thresh_time);
int (*set_exception)(struct fman_mac *mac_dev,
enum fman_mac_exceptions exception, bool enable);
int (*add_hash_mac_addr)(struct fman_mac *mac_dev,
enet_addr_t *eth_addr);
int (*remove_hash_mac_addr)(struct fman_mac *mac_dev,
enet_addr_t *eth_addr);
struct fman_mac *fman_mac;
struct mac_priv_s *priv;
};
struct dpaa_eth_data {
struct device_node *mac_node;
struct mac_device *mac_dev;
int mac_hw_id;
int fman_hw_id;
};
extern const char *mac_driver_description;
int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx);
void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause,
bool *tx_pause);
#endif /* __MAC_H */