xref: /openbmc/linux/drivers/net/ethernet/freescale/fman/fman_dtsec.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
18585bdadSSean Anderson // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
257ba4c9bSIgal Liberman /*
357ba4c9bSIgal Liberman  * Copyright 2008 - 2015 Freescale Semiconductor Inc.
457ba4c9bSIgal Liberman  */
557ba4c9bSIgal Liberman 
657ba4c9bSIgal Liberman #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
757ba4c9bSIgal Liberman 
857ba4c9bSIgal Liberman #include "fman_dtsec.h"
957ba4c9bSIgal Liberman #include "fman.h"
10302376feSSean Anderson #include "mac.h"
1157ba4c9bSIgal Liberman 
1257ba4c9bSIgal Liberman #include <linux/slab.h>
1357ba4c9bSIgal Liberman #include <linux/bitrev.h>
1457ba4c9bSIgal Liberman #include <linux/io.h>
1557ba4c9bSIgal Liberman #include <linux/delay.h>
1657ba4c9bSIgal Liberman #include <linux/phy.h>
1757ba4c9bSIgal Liberman #include <linux/crc32.h>
1857ba4c9bSIgal Liberman #include <linux/of_mdio.h>
1957ba4c9bSIgal Liberman #include <linux/mii.h>
205d93cfcfSSean Anderson #include <linux/netdevice.h>
2157ba4c9bSIgal Liberman 
2257ba4c9bSIgal Liberman /* TBI register addresses */
2357ba4c9bSIgal Liberman #define MII_TBICON		0x11
2457ba4c9bSIgal Liberman 
2557ba4c9bSIgal Liberman /* TBICON register bit fields */
2657ba4c9bSIgal Liberman #define TBICON_SOFT_RESET	0x8000	/* Soft reset */
2757ba4c9bSIgal Liberman #define TBICON_DISABLE_RX_DIS	0x2000	/* Disable receive disparity */
2857ba4c9bSIgal Liberman #define TBICON_DISABLE_TX_DIS	0x1000	/* Disable transmit disparity */
2957ba4c9bSIgal Liberman #define TBICON_AN_SENSE		0x0100	/* Auto-negotiation sense enable */
3057ba4c9bSIgal Liberman #define TBICON_CLK_SELECT	0x0020	/* Clock select */
3157ba4c9bSIgal Liberman #define TBICON_MI_MODE		0x0010	/* GMII mode (TBI if not set) */
3257ba4c9bSIgal Liberman 
3357ba4c9bSIgal Liberman /* Interrupt Mask Register (IMASK) */
3457ba4c9bSIgal Liberman #define DTSEC_IMASK_BREN	0x80000000
3557ba4c9bSIgal Liberman #define DTSEC_IMASK_RXCEN	0x40000000
3657ba4c9bSIgal Liberman #define DTSEC_IMASK_MSROEN	0x04000000
3757ba4c9bSIgal Liberman #define DTSEC_IMASK_GTSCEN	0x02000000
3857ba4c9bSIgal Liberman #define DTSEC_IMASK_BTEN	0x01000000
3957ba4c9bSIgal Liberman #define DTSEC_IMASK_TXCEN	0x00800000
4057ba4c9bSIgal Liberman #define DTSEC_IMASK_TXEEN	0x00400000
4157ba4c9bSIgal Liberman #define DTSEC_IMASK_LCEN	0x00040000
4257ba4c9bSIgal Liberman #define DTSEC_IMASK_CRLEN	0x00020000
4357ba4c9bSIgal Liberman #define DTSEC_IMASK_XFUNEN	0x00010000
4457ba4c9bSIgal Liberman #define DTSEC_IMASK_ABRTEN	0x00008000
4557ba4c9bSIgal Liberman #define DTSEC_IMASK_IFERREN	0x00004000
4657ba4c9bSIgal Liberman #define DTSEC_IMASK_MAGEN	0x00000800
4757ba4c9bSIgal Liberman #define DTSEC_IMASK_MMRDEN	0x00000400
4857ba4c9bSIgal Liberman #define DTSEC_IMASK_MMWREN	0x00000200
4957ba4c9bSIgal Liberman #define DTSEC_IMASK_GRSCEN	0x00000100
5057ba4c9bSIgal Liberman #define DTSEC_IMASK_TDPEEN	0x00000002
5157ba4c9bSIgal Liberman #define DTSEC_IMASK_RDPEEN	0x00000001
5257ba4c9bSIgal Liberman 
5357ba4c9bSIgal Liberman #define DTSEC_EVENTS_MASK		\
5457ba4c9bSIgal Liberman 	 ((u32)(DTSEC_IMASK_BREN    |	\
5557ba4c9bSIgal Liberman 		DTSEC_IMASK_RXCEN   |	\
5657ba4c9bSIgal Liberman 		DTSEC_IMASK_BTEN    |	\
5757ba4c9bSIgal Liberman 		DTSEC_IMASK_TXCEN   |	\
5857ba4c9bSIgal Liberman 		DTSEC_IMASK_TXEEN   |	\
5957ba4c9bSIgal Liberman 		DTSEC_IMASK_ABRTEN  |	\
6057ba4c9bSIgal Liberman 		DTSEC_IMASK_LCEN    |	\
6157ba4c9bSIgal Liberman 		DTSEC_IMASK_CRLEN   |	\
6257ba4c9bSIgal Liberman 		DTSEC_IMASK_XFUNEN  |	\
6357ba4c9bSIgal Liberman 		DTSEC_IMASK_IFERREN |	\
6457ba4c9bSIgal Liberman 		DTSEC_IMASK_MAGEN   |	\
6557ba4c9bSIgal Liberman 		DTSEC_IMASK_TDPEEN  |	\
6657ba4c9bSIgal Liberman 		DTSEC_IMASK_RDPEEN))
6757ba4c9bSIgal Liberman 
6857ba4c9bSIgal Liberman /* dtsec timestamp event bits */
6957ba4c9bSIgal Liberman #define TMR_PEMASK_TSREEN	0x00010000
7057ba4c9bSIgal Liberman #define TMR_PEVENT_TSRE		0x00010000
7157ba4c9bSIgal Liberman 
7257ba4c9bSIgal Liberman /* Group address bit indication */
7357ba4c9bSIgal Liberman #define MAC_GROUP_ADDRESS	0x0000010000000000ULL
7457ba4c9bSIgal Liberman 
7557ba4c9bSIgal Liberman /* Defaults */
7657ba4c9bSIgal Liberman #define DEFAULT_HALFDUP_RETRANSMIT		0xf
7757ba4c9bSIgal Liberman #define DEFAULT_HALFDUP_COLL_WINDOW		0x37
7857ba4c9bSIgal Liberman #define DEFAULT_TX_PAUSE_TIME			0xf000
7957ba4c9bSIgal Liberman #define DEFAULT_RX_PREPEND			0
8057ba4c9bSIgal Liberman #define DEFAULT_PREAMBLE_LEN			7
8157ba4c9bSIgal Liberman #define DEFAULT_TX_PAUSE_TIME_EXTD		0
8257ba4c9bSIgal Liberman #define DEFAULT_NON_BACK_TO_BACK_IPG1		0x40
8357ba4c9bSIgal Liberman #define DEFAULT_NON_BACK_TO_BACK_IPG2		0x60
8457ba4c9bSIgal Liberman #define DEFAULT_MIN_IFG_ENFORCEMENT		0x50
8557ba4c9bSIgal Liberman #define DEFAULT_BACK_TO_BACK_IPG		0x60
8657ba4c9bSIgal Liberman #define DEFAULT_MAXIMUM_FRAME			0x600
8757ba4c9bSIgal Liberman 
8857ba4c9bSIgal Liberman /* register related defines (bits, field offsets..) */
8957ba4c9bSIgal Liberman #define DTSEC_ID2_INT_REDUCED_OFF	0x00010000
9057ba4c9bSIgal Liberman 
9157ba4c9bSIgal Liberman #define DTSEC_ECNTRL_GMIIM		0x00000040
9257ba4c9bSIgal Liberman #define DTSEC_ECNTRL_TBIM		0x00000020
9357ba4c9bSIgal Liberman #define DTSEC_ECNTRL_RPM		0x00000010
9457ba4c9bSIgal Liberman #define DTSEC_ECNTRL_R100M		0x00000008
955d93cfcfSSean Anderson #define DTSEC_ECNTRL_RMM		0x00000004
965d93cfcfSSean Anderson #define DTSEC_ECNTRL_SGMIIM		0x00000002
9757ba4c9bSIgal Liberman #define DTSEC_ECNTRL_QSGMIIM		0x00000001
9857ba4c9bSIgal Liberman 
990fab782aSYangbo Lu #define TCTRL_TTSE			0x00000040
100e37425c2SFlorinel Iordache #define TCTRL_GTS			0x00000020
10157ba4c9bSIgal Liberman 
10257ba4c9bSIgal Liberman #define RCTRL_PAL_MASK			0x001f0000
10357ba4c9bSIgal Liberman #define RCTRL_PAL_SHIFT			16
10457ba4c9bSIgal Liberman #define RCTRL_GHTX			0x00000400
1050fab782aSYangbo Lu #define RCTRL_RTSE			0x00000040
10657ba4c9bSIgal Liberman #define RCTRL_GRS			0x00000020
10757ba4c9bSIgal Liberman #define RCTRL_MPROM			0x00000008
10857ba4c9bSIgal Liberman #define RCTRL_RSF			0x00000004
10957ba4c9bSIgal Liberman #define RCTRL_UPROM			0x00000001
11057ba4c9bSIgal Liberman 
11157ba4c9bSIgal Liberman #define MACCFG1_SOFT_RESET		0x80000000
11257ba4c9bSIgal Liberman #define MACCFG1_RX_FLOW			0x00000020
11357ba4c9bSIgal Liberman #define MACCFG1_TX_FLOW			0x00000010
11457ba4c9bSIgal Liberman #define MACCFG1_TX_EN			0x00000001
11557ba4c9bSIgal Liberman #define MACCFG1_RX_EN			0x00000004
11657ba4c9bSIgal Liberman 
11757ba4c9bSIgal Liberman #define MACCFG2_NIBBLE_MODE		0x00000100
11857ba4c9bSIgal Liberman #define MACCFG2_BYTE_MODE		0x00000200
11957ba4c9bSIgal Liberman #define MACCFG2_PAD_CRC_EN		0x00000004
12057ba4c9bSIgal Liberman #define MACCFG2_FULL_DUPLEX		0x00000001
12157ba4c9bSIgal Liberman #define MACCFG2_PREAMBLE_LENGTH_MASK	0x0000f000
12257ba4c9bSIgal Liberman #define MACCFG2_PREAMBLE_LENGTH_SHIFT	12
12357ba4c9bSIgal Liberman 
12457ba4c9bSIgal Liberman #define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT	24
12557ba4c9bSIgal Liberman #define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT	16
12657ba4c9bSIgal Liberman #define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT	8
12757ba4c9bSIgal Liberman 
12857ba4c9bSIgal Liberman #define IPGIFG_NON_BACK_TO_BACK_IPG_1	0x7F000000
12957ba4c9bSIgal Liberman #define IPGIFG_NON_BACK_TO_BACK_IPG_2	0x007F0000
13057ba4c9bSIgal Liberman #define IPGIFG_MIN_IFG_ENFORCEMENT	0x0000FF00
13157ba4c9bSIgal Liberman #define IPGIFG_BACK_TO_BACK_IPG	0x0000007F
13257ba4c9bSIgal Liberman 
13357ba4c9bSIgal Liberman #define HAFDUP_EXCESS_DEFER			0x00010000
13457ba4c9bSIgal Liberman #define HAFDUP_COLLISION_WINDOW		0x000003ff
13557ba4c9bSIgal Liberman #define HAFDUP_RETRANSMISSION_MAX_SHIFT	12
13657ba4c9bSIgal Liberman #define HAFDUP_RETRANSMISSION_MAX		0x0000f000
13757ba4c9bSIgal Liberman 
13857ba4c9bSIgal Liberman #define NUM_OF_HASH_REGS	8	/* Number of hash table registers */
13957ba4c9bSIgal Liberman 
14057ba4c9bSIgal Liberman #define PTV_PTE_MASK		0xffff0000
14157ba4c9bSIgal Liberman #define PTV_PT_MASK		0x0000ffff
14257ba4c9bSIgal Liberman #define PTV_PTE_SHIFT		16
14357ba4c9bSIgal Liberman 
14457ba4c9bSIgal Liberman #define MAX_PACKET_ALIGNMENT		31
14557ba4c9bSIgal Liberman #define MAX_INTER_PACKET_GAP		0x7f
14657ba4c9bSIgal Liberman #define MAX_RETRANSMISSION		0x0f
14757ba4c9bSIgal Liberman #define MAX_COLLISION_WINDOW		0x03ff
14857ba4c9bSIgal Liberman 
14957ba4c9bSIgal Liberman /* Hash table size (32 bits*8 regs) */
15057ba4c9bSIgal Liberman #define DTSEC_HASH_TABLE_SIZE		256
15157ba4c9bSIgal Liberman /* Extended Hash table size (32 bits*16 regs) */
15257ba4c9bSIgal Liberman #define EXTENDED_HASH_TABLE_SIZE	512
15357ba4c9bSIgal Liberman 
15457ba4c9bSIgal Liberman /* dTSEC Memory Map registers */
15557ba4c9bSIgal Liberman struct dtsec_regs {
15657ba4c9bSIgal Liberman 	/* dTSEC General Control and Status Registers */
15757ba4c9bSIgal Liberman 	u32 tsec_id;		/* 0x000 ETSEC_ID register */
15857ba4c9bSIgal Liberman 	u32 tsec_id2;		/* 0x004 ETSEC_ID2 register */
15957ba4c9bSIgal Liberman 	u32 ievent;		/* 0x008 Interrupt event register */
16057ba4c9bSIgal Liberman 	u32 imask;		/* 0x00C Interrupt mask register */
16157ba4c9bSIgal Liberman 	u32 reserved0010[1];
16257ba4c9bSIgal Liberman 	u32 ecntrl;		/* 0x014 E control register */
16357ba4c9bSIgal Liberman 	u32 ptv;		/* 0x018 Pause time value register */
16457ba4c9bSIgal Liberman 	u32 tbipa;		/* 0x01C TBI PHY address register */
16557ba4c9bSIgal Liberman 	u32 tmr_ctrl;		/* 0x020 Time-stamp Control register */
16657ba4c9bSIgal Liberman 	u32 tmr_pevent;		/* 0x024 Time-stamp event register */
16757ba4c9bSIgal Liberman 	u32 tmr_pemask;		/* 0x028 Timer event mask register */
16857ba4c9bSIgal Liberman 	u32 reserved002c[5];
16957ba4c9bSIgal Liberman 	u32 tctrl;		/* 0x040 Transmit control register */
17057ba4c9bSIgal Liberman 	u32 reserved0044[3];
17157ba4c9bSIgal Liberman 	u32 rctrl;		/* 0x050 Receive control register */
17257ba4c9bSIgal Liberman 	u32 reserved0054[11];
17357ba4c9bSIgal Liberman 	u32 igaddr[8];		/* 0x080-0x09C Individual/group address */
17457ba4c9bSIgal Liberman 	u32 gaddr[8];		/* 0x0A0-0x0BC Group address registers 0-7 */
17557ba4c9bSIgal Liberman 	u32 reserved00c0[16];
17657ba4c9bSIgal Liberman 	u32 maccfg1;		/* 0x100 MAC configuration #1 */
17757ba4c9bSIgal Liberman 	u32 maccfg2;		/* 0x104 MAC configuration #2 */
17857ba4c9bSIgal Liberman 	u32 ipgifg;		/* 0x108 IPG/IFG */
17957ba4c9bSIgal Liberman 	u32 hafdup;		/* 0x10C Half-duplex */
18057ba4c9bSIgal Liberman 	u32 maxfrm;		/* 0x110 Maximum frame */
18157ba4c9bSIgal Liberman 	u32 reserved0114[10];
18257ba4c9bSIgal Liberman 	u32 ifstat;		/* 0x13C Interface status */
18357ba4c9bSIgal Liberman 	u32 macstnaddr1;	/* 0x140 Station Address,part 1 */
18457ba4c9bSIgal Liberman 	u32 macstnaddr2;	/* 0x144 Station Address,part 2 */
18557ba4c9bSIgal Liberman 	struct {
18657ba4c9bSIgal Liberman 		u32 exact_match1;	/* octets 1-4 */
18757ba4c9bSIgal Liberman 		u32 exact_match2;	/* octets 5-6 */
18857ba4c9bSIgal Liberman 	} macaddr[15];		/* 0x148-0x1BC mac exact match addresses 1-15 */
18957ba4c9bSIgal Liberman 	u32 reserved01c0[16];
19057ba4c9bSIgal Liberman 	u32 tr64;	/* 0x200 Tx and Rx 64 byte frame counter */
19157ba4c9bSIgal Liberman 	u32 tr127;	/* 0x204 Tx and Rx 65 to 127 byte frame counter */
19257ba4c9bSIgal Liberman 	u32 tr255;	/* 0x208 Tx and Rx 128 to 255 byte frame counter */
19357ba4c9bSIgal Liberman 	u32 tr511;	/* 0x20C Tx and Rx 256 to 511 byte frame counter */
19457ba4c9bSIgal Liberman 	u32 tr1k;	/* 0x210 Tx and Rx 512 to 1023 byte frame counter */
19557ba4c9bSIgal Liberman 	u32 trmax;	/* 0x214 Tx and Rx 1024 to 1518 byte frame counter */
19657ba4c9bSIgal Liberman 	u32 trmgv;
19757ba4c9bSIgal Liberman 	/* 0x218 Tx and Rx 1519 to 1522 byte good VLAN frame count */
19857ba4c9bSIgal Liberman 	u32 rbyt;	/* 0x21C receive byte counter */
19957ba4c9bSIgal Liberman 	u32 rpkt;	/* 0x220 receive packet counter */
20057ba4c9bSIgal Liberman 	u32 rfcs;	/* 0x224 receive FCS error counter */
20157ba4c9bSIgal Liberman 	u32 rmca;	/* 0x228 RMCA Rx multicast packet counter */
20257ba4c9bSIgal Liberman 	u32 rbca;	/* 0x22C Rx broadcast packet counter */
20357ba4c9bSIgal Liberman 	u32 rxcf;	/* 0x230 Rx control frame packet counter */
20457ba4c9bSIgal Liberman 	u32 rxpf;	/* 0x234 Rx pause frame packet counter */
20557ba4c9bSIgal Liberman 	u32 rxuo;	/* 0x238 Rx unknown OP code counter */
20657ba4c9bSIgal Liberman 	u32 raln;	/* 0x23C Rx alignment error counter */
20757ba4c9bSIgal Liberman 	u32 rflr;	/* 0x240 Rx frame length error counter */
20857ba4c9bSIgal Liberman 	u32 rcde;	/* 0x244 Rx code error counter */
20957ba4c9bSIgal Liberman 	u32 rcse;	/* 0x248 Rx carrier sense error counter */
21057ba4c9bSIgal Liberman 	u32 rund;	/* 0x24C Rx undersize packet counter */
21157ba4c9bSIgal Liberman 	u32 rovr;	/* 0x250 Rx oversize packet counter */
21257ba4c9bSIgal Liberman 	u32 rfrg;	/* 0x254 Rx fragments counter */
21357ba4c9bSIgal Liberman 	u32 rjbr;	/* 0x258 Rx jabber counter */
21457ba4c9bSIgal Liberman 	u32 rdrp;	/* 0x25C Rx drop */
21557ba4c9bSIgal Liberman 	u32 tbyt;	/* 0x260 Tx byte counter */
21657ba4c9bSIgal Liberman 	u32 tpkt;	/* 0x264 Tx packet counter */
21757ba4c9bSIgal Liberman 	u32 tmca;	/* 0x268 Tx multicast packet counter */
21857ba4c9bSIgal Liberman 	u32 tbca;	/* 0x26C Tx broadcast packet counter */
21957ba4c9bSIgal Liberman 	u32 txpf;	/* 0x270 Tx pause control frame counter */
22057ba4c9bSIgal Liberman 	u32 tdfr;	/* 0x274 Tx deferral packet counter */
22157ba4c9bSIgal Liberman 	u32 tedf;	/* 0x278 Tx excessive deferral packet counter */
22257ba4c9bSIgal Liberman 	u32 tscl;	/* 0x27C Tx single collision packet counter */
22357ba4c9bSIgal Liberman 	u32 tmcl;	/* 0x280 Tx multiple collision packet counter */
22457ba4c9bSIgal Liberman 	u32 tlcl;	/* 0x284 Tx late collision packet counter */
22557ba4c9bSIgal Liberman 	u32 txcl;	/* 0x288 Tx excessive collision packet counter */
22657ba4c9bSIgal Liberman 	u32 tncl;	/* 0x28C Tx total collision counter */
22757ba4c9bSIgal Liberman 	u32 reserved0290[1];
22857ba4c9bSIgal Liberman 	u32 tdrp;	/* 0x294 Tx drop frame counter */
22957ba4c9bSIgal Liberman 	u32 tjbr;	/* 0x298 Tx jabber frame counter */
23057ba4c9bSIgal Liberman 	u32 tfcs;	/* 0x29C Tx FCS error counter */
23157ba4c9bSIgal Liberman 	u32 txcf;	/* 0x2A0 Tx control frame counter */
23257ba4c9bSIgal Liberman 	u32 tovr;	/* 0x2A4 Tx oversize frame counter */
23357ba4c9bSIgal Liberman 	u32 tund;	/* 0x2A8 Tx undersize frame counter */
23457ba4c9bSIgal Liberman 	u32 tfrg;	/* 0x2AC Tx fragments frame counter */
23557ba4c9bSIgal Liberman 	u32 car1;	/* 0x2B0 carry register one register* */
23657ba4c9bSIgal Liberman 	u32 car2;	/* 0x2B4 carry register two register* */
23757ba4c9bSIgal Liberman 	u32 cam1;	/* 0x2B8 carry register one mask register */
23857ba4c9bSIgal Liberman 	u32 cam2;	/* 0x2BC carry register two mask register */
23957ba4c9bSIgal Liberman 	u32 reserved02c0[848];
24057ba4c9bSIgal Liberman };
24157ba4c9bSIgal Liberman 
24257ba4c9bSIgal Liberman /* struct dtsec_cfg - dTSEC configuration
24357ba4c9bSIgal Liberman  * Transmit half-duplex flow control, under software control for 10/100-Mbps
24457ba4c9bSIgal Liberman  * half-duplex media. If set, back pressure is applied to media by raising
24557ba4c9bSIgal Liberman  * carrier.
24657ba4c9bSIgal Liberman  * halfdup_retransmit:
24757ba4c9bSIgal Liberman  * Number of retransmission attempts following a collision.
24857ba4c9bSIgal Liberman  * If this is exceeded dTSEC aborts transmission due to excessive collisions.
24957ba4c9bSIgal Liberman  * The standard specifies the attempt limit to be 15.
25057ba4c9bSIgal Liberman  * halfdup_coll_window:
25157ba4c9bSIgal Liberman  * The number of bytes of the frame during which collisions may occur.
25257ba4c9bSIgal Liberman  * The default value of 55 corresponds to the frame byte at the end of the
25357ba4c9bSIgal Liberman  * standard 512-bit slot time window. If collisions are detected after this
25457ba4c9bSIgal Liberman  * byte, the late collision event is asserted and transmission of current
25557ba4c9bSIgal Liberman  * frame is aborted.
25657ba4c9bSIgal Liberman  * tx_pad_crc:
25757ba4c9bSIgal Liberman  * Pad and append CRC. If set, the MAC pads all ransmitted short frames and
25857ba4c9bSIgal Liberman  * appends a CRC to every frame regardless of padding requirement.
25957ba4c9bSIgal Liberman  * tx_pause_time:
26057ba4c9bSIgal Liberman  * Transmit pause time value. This pause value is used as part of the pause
26157ba4c9bSIgal Liberman  * frame to be sent when a transmit pause frame is initiated.
26257ba4c9bSIgal Liberman  * If set to 0 this disables transmission of pause frames.
26357ba4c9bSIgal Liberman  * preamble_len:
26457ba4c9bSIgal Liberman  * Length, in bytes, of the preamble field preceding each Ethernet
26557ba4c9bSIgal Liberman  * start-of-frame delimiter byte. The default value of 0x7 should be used in
26657ba4c9bSIgal Liberman  * order to guarantee reliable operation with IEEE 802.3 compliant hardware.
26757ba4c9bSIgal Liberman  * rx_prepend:
26857ba4c9bSIgal Liberman  * Packet alignment padding length. The specified number of bytes (1-31)
26957ba4c9bSIgal Liberman  * of zero padding are inserted before the start of each received frame.
27057ba4c9bSIgal Liberman  * For Ethernet, where optional preamble extraction is enabled, the padding
27157ba4c9bSIgal Liberman  * appears before the preamble, otherwise the padding precedes the
27257ba4c9bSIgal Liberman  * layer 2 header.
27357ba4c9bSIgal Liberman  *
27457ba4c9bSIgal Liberman  * This structure contains basic dTSEC configuration and must be passed to
27557ba4c9bSIgal Liberman  * init() function. A default set of configuration values can be
27657ba4c9bSIgal Liberman  * obtained by calling set_dflts().
27757ba4c9bSIgal Liberman  */
27857ba4c9bSIgal Liberman struct dtsec_cfg {
27957ba4c9bSIgal Liberman 	u16 halfdup_retransmit;
28057ba4c9bSIgal Liberman 	u16 halfdup_coll_window;
28157ba4c9bSIgal Liberman 	bool tx_pad_crc;
28257ba4c9bSIgal Liberman 	u16 tx_pause_time;
28357ba4c9bSIgal Liberman 	bool ptp_tsu_en;
28457ba4c9bSIgal Liberman 	bool ptp_exception_en;
28557ba4c9bSIgal Liberman 	u32 preamble_len;
28657ba4c9bSIgal Liberman 	u32 rx_prepend;
28757ba4c9bSIgal Liberman 	u16 tx_pause_time_extd;
28857ba4c9bSIgal Liberman 	u16 maximum_frame;
28957ba4c9bSIgal Liberman 	u32 non_back_to_back_ipg1;
29057ba4c9bSIgal Liberman 	u32 non_back_to_back_ipg2;
29157ba4c9bSIgal Liberman 	u32 min_ifg_enforcement;
29257ba4c9bSIgal Liberman 	u32 back_to_back_ipg;
29357ba4c9bSIgal Liberman };
29457ba4c9bSIgal Liberman 
29557ba4c9bSIgal Liberman struct fman_mac {
29657ba4c9bSIgal Liberman 	/* pointer to dTSEC memory mapped registers */
29757ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs;
29857ba4c9bSIgal Liberman 	/* MAC address of device */
29957ba4c9bSIgal Liberman 	u64 addr;
30057ba4c9bSIgal Liberman 	/* Ethernet physical interface */
30157ba4c9bSIgal Liberman 	phy_interface_t phy_if;
30257ba4c9bSIgal Liberman 	u16 max_speed;
3035b6acb55SSean Anderson 	struct mac_device *dev_id; /* device cookie used by the exception cbs */
30457ba4c9bSIgal Liberman 	fman_mac_exception_cb *exception_cb;
30557ba4c9bSIgal Liberman 	fman_mac_exception_cb *event_cb;
30657ba4c9bSIgal Liberman 	/* Number of individual addresses in registers for this station */
30757ba4c9bSIgal Liberman 	u8 num_of_ind_addr_in_regs;
30857ba4c9bSIgal Liberman 	/* pointer to driver's global address hash table */
30957ba4c9bSIgal Liberman 	struct eth_hash_t *multicast_addr_hash;
31057ba4c9bSIgal Liberman 	/* pointer to driver's individual address hash table */
31157ba4c9bSIgal Liberman 	struct eth_hash_t *unicast_addr_hash;
31257ba4c9bSIgal Liberman 	u8 mac_id;
31357ba4c9bSIgal Liberman 	u32 exceptions;
31457ba4c9bSIgal Liberman 	bool ptp_tsu_enabled;
315f74f92beSColin Ian King 	bool en_tsu_err_exception;
31657ba4c9bSIgal Liberman 	struct dtsec_cfg *dtsec_drv_param;
31757ba4c9bSIgal Liberman 	void *fm;
31857ba4c9bSIgal Liberman 	struct fman_rev_info fm_rev_info;
31957ba4c9bSIgal Liberman 	bool basex_if;
3205d93cfcfSSean Anderson 	struct mdio_device *tbidev;
3215d93cfcfSSean Anderson 	struct phylink_pcs pcs;
32257ba4c9bSIgal Liberman };
32357ba4c9bSIgal Liberman 
set_dflts(struct dtsec_cfg * cfg)32457ba4c9bSIgal Liberman static void set_dflts(struct dtsec_cfg *cfg)
32557ba4c9bSIgal Liberman {
32657ba4c9bSIgal Liberman 	cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT;
32757ba4c9bSIgal Liberman 	cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW;
32857ba4c9bSIgal Liberman 	cfg->tx_pad_crc = true;
32957ba4c9bSIgal Liberman 	cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME;
33057ba4c9bSIgal Liberman 	/* PHY address 0 is reserved (DPAA RM) */
33157ba4c9bSIgal Liberman 	cfg->rx_prepend = DEFAULT_RX_PREPEND;
33257ba4c9bSIgal Liberman 	cfg->ptp_tsu_en = true;
33357ba4c9bSIgal Liberman 	cfg->ptp_exception_en = true;
33457ba4c9bSIgal Liberman 	cfg->preamble_len = DEFAULT_PREAMBLE_LEN;
33557ba4c9bSIgal Liberman 	cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD;
33657ba4c9bSIgal Liberman 	cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1;
33757ba4c9bSIgal Liberman 	cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2;
33857ba4c9bSIgal Liberman 	cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT;
33957ba4c9bSIgal Liberman 	cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG;
34057ba4c9bSIgal Liberman 	cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME;
34157ba4c9bSIgal Liberman }
34257ba4c9bSIgal Liberman 
set_mac_address(struct dtsec_regs __iomem * regs,const u8 * adr)34376660757SJakub Kicinski static void set_mac_address(struct dtsec_regs __iomem *regs, const u8 *adr)
3446b995bdeSMadalin Bucur {
3456b995bdeSMadalin Bucur 	u32 tmp;
3466b995bdeSMadalin Bucur 
3476b995bdeSMadalin Bucur 	tmp = (u32)((adr[5] << 24) |
3486b995bdeSMadalin Bucur 		    (adr[4] << 16) | (adr[3] << 8) | adr[2]);
3496b995bdeSMadalin Bucur 	iowrite32be(tmp, &regs->macstnaddr1);
3506b995bdeSMadalin Bucur 
3516b995bdeSMadalin Bucur 	tmp = (u32)((adr[1] << 24) | (adr[0] << 16));
3526b995bdeSMadalin Bucur 	iowrite32be(tmp, &regs->macstnaddr2);
3536b995bdeSMadalin Bucur }
3546b995bdeSMadalin Bucur 
init(struct dtsec_regs __iomem * regs,struct dtsec_cfg * cfg,phy_interface_t iface,u16 iface_speed,u64 addr,u32 exception_mask,u8 tbi_addr)35557ba4c9bSIgal Liberman static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
3566b995bdeSMadalin Bucur 		phy_interface_t iface, u16 iface_speed, u64 addr,
35757ba4c9bSIgal Liberman 		u32 exception_mask, u8 tbi_addr)
35857ba4c9bSIgal Liberman {
3596b995bdeSMadalin Bucur 	enet_addr_t eth_addr;
3605d93cfcfSSean Anderson 	u32 tmp = 0;
3616b995bdeSMadalin Bucur 	int i;
36257ba4c9bSIgal Liberman 
36357ba4c9bSIgal Liberman 	/* Soft reset */
36457ba4c9bSIgal Liberman 	iowrite32be(MACCFG1_SOFT_RESET, &regs->maccfg1);
36557ba4c9bSIgal Liberman 	iowrite32be(0, &regs->maccfg1);
36657ba4c9bSIgal Liberman 
36757ba4c9bSIgal Liberman 	if (cfg->tx_pause_time)
36857ba4c9bSIgal Liberman 		tmp |= cfg->tx_pause_time;
36957ba4c9bSIgal Liberman 	if (cfg->tx_pause_time_extd)
37057ba4c9bSIgal Liberman 		tmp |= cfg->tx_pause_time_extd << PTV_PTE_SHIFT;
37157ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->ptv);
37257ba4c9bSIgal Liberman 
37357ba4c9bSIgal Liberman 	tmp = 0;
37457ba4c9bSIgal Liberman 	tmp |= (cfg->rx_prepend << RCTRL_PAL_SHIFT) & RCTRL_PAL_MASK;
37557ba4c9bSIgal Liberman 	/* Accept short frames */
37657ba4c9bSIgal Liberman 	tmp |= RCTRL_RSF;
37757ba4c9bSIgal Liberman 
37857ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->rctrl);
37957ba4c9bSIgal Liberman 
38057ba4c9bSIgal Liberman 	/* Assign a Phy Address to the TBI (TBIPA).
38157ba4c9bSIgal Liberman 	 * Done also in cases where TBI is not selected to avoid conflict with
38257ba4c9bSIgal Liberman 	 * the external PHY's Physical address
38357ba4c9bSIgal Liberman 	 */
38457ba4c9bSIgal Liberman 	iowrite32be(tbi_addr, &regs->tbipa);
38557ba4c9bSIgal Liberman 
38657ba4c9bSIgal Liberman 	iowrite32be(0, &regs->tmr_ctrl);
38757ba4c9bSIgal Liberman 
38857ba4c9bSIgal Liberman 	if (cfg->ptp_tsu_en) {
38957ba4c9bSIgal Liberman 		tmp = 0;
39057ba4c9bSIgal Liberman 		tmp |= TMR_PEVENT_TSRE;
39157ba4c9bSIgal Liberman 		iowrite32be(tmp, &regs->tmr_pevent);
39257ba4c9bSIgal Liberman 
39357ba4c9bSIgal Liberman 		if (cfg->ptp_exception_en) {
39457ba4c9bSIgal Liberman 			tmp = 0;
39557ba4c9bSIgal Liberman 			tmp |= TMR_PEMASK_TSREEN;
39657ba4c9bSIgal Liberman 			iowrite32be(tmp, &regs->tmr_pemask);
39757ba4c9bSIgal Liberman 		}
39857ba4c9bSIgal Liberman 	}
39957ba4c9bSIgal Liberman 
40057ba4c9bSIgal Liberman 	tmp = 0;
40157ba4c9bSIgal Liberman 	tmp |= MACCFG1_RX_FLOW;
40257ba4c9bSIgal Liberman 	tmp |= MACCFG1_TX_FLOW;
40357ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->maccfg1);
40457ba4c9bSIgal Liberman 
40557ba4c9bSIgal Liberman 	tmp = 0;
40657ba4c9bSIgal Liberman 
40757ba4c9bSIgal Liberman 	tmp |= (cfg->preamble_len << MACCFG2_PREAMBLE_LENGTH_SHIFT) &
40857ba4c9bSIgal Liberman 		MACCFG2_PREAMBLE_LENGTH_MASK;
40957ba4c9bSIgal Liberman 	if (cfg->tx_pad_crc)
41057ba4c9bSIgal Liberman 		tmp |= MACCFG2_PAD_CRC_EN;
41157ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->maccfg2);
41257ba4c9bSIgal Liberman 
41357ba4c9bSIgal Liberman 	tmp = (((cfg->non_back_to_back_ipg1 <<
41457ba4c9bSIgal Liberman 		 IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT)
41557ba4c9bSIgal Liberman 		& IPGIFG_NON_BACK_TO_BACK_IPG_1)
41657ba4c9bSIgal Liberman 	       | ((cfg->non_back_to_back_ipg2 <<
41757ba4c9bSIgal Liberman 		   IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT)
41857ba4c9bSIgal Liberman 		 & IPGIFG_NON_BACK_TO_BACK_IPG_2)
41957ba4c9bSIgal Liberman 	       | ((cfg->min_ifg_enforcement << IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT)
42057ba4c9bSIgal Liberman 		 & IPGIFG_MIN_IFG_ENFORCEMENT)
42157ba4c9bSIgal Liberman 	       | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG));
42257ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->ipgifg);
42357ba4c9bSIgal Liberman 
42457ba4c9bSIgal Liberman 	tmp = 0;
42557ba4c9bSIgal Liberman 	tmp |= HAFDUP_EXCESS_DEFER;
42657ba4c9bSIgal Liberman 	tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT)
42757ba4c9bSIgal Liberman 		& HAFDUP_RETRANSMISSION_MAX);
42857ba4c9bSIgal Liberman 	tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW);
42957ba4c9bSIgal Liberman 
43057ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->hafdup);
43157ba4c9bSIgal Liberman 
43257ba4c9bSIgal Liberman 	/* Initialize Maximum frame length */
43357ba4c9bSIgal Liberman 	iowrite32be(cfg->maximum_frame, &regs->maxfrm);
43457ba4c9bSIgal Liberman 
43557ba4c9bSIgal Liberman 	iowrite32be(0xffffffff, &regs->cam1);
43657ba4c9bSIgal Liberman 	iowrite32be(0xffffffff, &regs->cam2);
43757ba4c9bSIgal Liberman 
43857ba4c9bSIgal Liberman 	iowrite32be(exception_mask, &regs->imask);
43957ba4c9bSIgal Liberman 
44057ba4c9bSIgal Liberman 	iowrite32be(0xffffffff, &regs->ievent);
44157ba4c9bSIgal Liberman 
442f3353b99SMadalin Bucur 	if (addr) {
4436b995bdeSMadalin Bucur 		MAKE_ENET_ADDR_FROM_UINT64(addr, eth_addr);
44476660757SJakub Kicinski 		set_mac_address(regs, (const u8 *)eth_addr);
445f3353b99SMadalin Bucur 	}
44657ba4c9bSIgal Liberman 
44757ba4c9bSIgal Liberman 	/* HASH */
44857ba4c9bSIgal Liberman 	for (i = 0; i < NUM_OF_HASH_REGS; i++) {
44957ba4c9bSIgal Liberman 		/* Initialize IADDRx */
45057ba4c9bSIgal Liberman 		iowrite32be(0, &regs->igaddr[i]);
45157ba4c9bSIgal Liberman 		/* Initialize GADDRx */
45257ba4c9bSIgal Liberman 		iowrite32be(0, &regs->gaddr[i]);
45357ba4c9bSIgal Liberman 	}
45457ba4c9bSIgal Liberman 
45557ba4c9bSIgal Liberman 	return 0;
45657ba4c9bSIgal Liberman }
45757ba4c9bSIgal Liberman 
set_bucket(struct dtsec_regs __iomem * regs,int bucket,bool enable)45857ba4c9bSIgal Liberman static void set_bucket(struct dtsec_regs __iomem *regs, int bucket,
45957ba4c9bSIgal Liberman 		       bool enable)
46057ba4c9bSIgal Liberman {
46157ba4c9bSIgal Liberman 	int reg_idx = (bucket >> 5) & 0xf;
46257ba4c9bSIgal Liberman 	int bit_idx = bucket & 0x1f;
46357ba4c9bSIgal Liberman 	u32 bit_mask = 0x80000000 >> bit_idx;
46457ba4c9bSIgal Liberman 	u32 __iomem *reg;
46557ba4c9bSIgal Liberman 
46657ba4c9bSIgal Liberman 	if (reg_idx > 7)
46757ba4c9bSIgal Liberman 		reg = &regs->gaddr[reg_idx - 8];
46857ba4c9bSIgal Liberman 	else
46957ba4c9bSIgal Liberman 		reg = &regs->igaddr[reg_idx];
47057ba4c9bSIgal Liberman 
47157ba4c9bSIgal Liberman 	if (enable)
47257ba4c9bSIgal Liberman 		iowrite32be(ioread32be(reg) | bit_mask, reg);
47357ba4c9bSIgal Liberman 	else
47457ba4c9bSIgal Liberman 		iowrite32be(ioread32be(reg) & (~bit_mask), reg);
47557ba4c9bSIgal Liberman }
47657ba4c9bSIgal Liberman 
check_init_parameters(struct fman_mac * dtsec)47757ba4c9bSIgal Liberman static int check_init_parameters(struct fman_mac *dtsec)
47857ba4c9bSIgal Liberman {
47957ba4c9bSIgal Liberman 	if ((dtsec->dtsec_drv_param)->rx_prepend >
48057ba4c9bSIgal Liberman 	    MAX_PACKET_ALIGNMENT) {
48157ba4c9bSIgal Liberman 		pr_err("packetAlignmentPadding can't be > than %d\n",
48257ba4c9bSIgal Liberman 		       MAX_PACKET_ALIGNMENT);
48357ba4c9bSIgal Liberman 		return -EINVAL;
48457ba4c9bSIgal Liberman 	}
48557ba4c9bSIgal Liberman 	if (((dtsec->dtsec_drv_param)->non_back_to_back_ipg1 >
48657ba4c9bSIgal Liberman 	     MAX_INTER_PACKET_GAP) ||
48757ba4c9bSIgal Liberman 	    ((dtsec->dtsec_drv_param)->non_back_to_back_ipg2 >
48857ba4c9bSIgal Liberman 	     MAX_INTER_PACKET_GAP) ||
48957ba4c9bSIgal Liberman 	     ((dtsec->dtsec_drv_param)->back_to_back_ipg >
49057ba4c9bSIgal Liberman 	      MAX_INTER_PACKET_GAP)) {
49157ba4c9bSIgal Liberman 		pr_err("Inter packet gap can't be greater than %d\n",
49257ba4c9bSIgal Liberman 		       MAX_INTER_PACKET_GAP);
49357ba4c9bSIgal Liberman 		return -EINVAL;
49457ba4c9bSIgal Liberman 	}
49557ba4c9bSIgal Liberman 	if ((dtsec->dtsec_drv_param)->halfdup_retransmit >
49657ba4c9bSIgal Liberman 	    MAX_RETRANSMISSION) {
49757ba4c9bSIgal Liberman 		pr_err("maxRetransmission can't be greater than %d\n",
49857ba4c9bSIgal Liberman 		       MAX_RETRANSMISSION);
49957ba4c9bSIgal Liberman 		return -EINVAL;
50057ba4c9bSIgal Liberman 	}
50157ba4c9bSIgal Liberman 	if ((dtsec->dtsec_drv_param)->halfdup_coll_window >
50257ba4c9bSIgal Liberman 	    MAX_COLLISION_WINDOW) {
50357ba4c9bSIgal Liberman 		pr_err("collisionWindow can't be greater than %d\n",
50457ba4c9bSIgal Liberman 		       MAX_COLLISION_WINDOW);
50557ba4c9bSIgal Liberman 		return -EINVAL;
50657ba4c9bSIgal Liberman 	/* If Auto negotiation process is disabled, need to set up the PHY
50757ba4c9bSIgal Liberman 	 * using the MII Management Interface
50857ba4c9bSIgal Liberman 	 */
50957ba4c9bSIgal Liberman 	}
51057ba4c9bSIgal Liberman 	if (!dtsec->exception_cb) {
51157ba4c9bSIgal Liberman 		pr_err("uninitialized exception_cb\n");
51257ba4c9bSIgal Liberman 		return -EINVAL;
51357ba4c9bSIgal Liberman 	}
51457ba4c9bSIgal Liberman 	if (!dtsec->event_cb) {
51557ba4c9bSIgal Liberman 		pr_err("uninitialized event_cb\n");
51657ba4c9bSIgal Liberman 		return -EINVAL;
51757ba4c9bSIgal Liberman 	}
51857ba4c9bSIgal Liberman 
51957ba4c9bSIgal Liberman 	return 0;
52057ba4c9bSIgal Liberman }
52157ba4c9bSIgal Liberman 
get_exception_flag(enum fman_mac_exceptions exception)52257ba4c9bSIgal Liberman static int get_exception_flag(enum fman_mac_exceptions exception)
52357ba4c9bSIgal Liberman {
52457ba4c9bSIgal Liberman 	u32 bit_mask;
52557ba4c9bSIgal Liberman 
52657ba4c9bSIgal Liberman 	switch (exception) {
52757ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_BAB_RX:
52857ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_BREN;
52957ba4c9bSIgal Liberman 		break;
53057ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_RX_CTL:
53157ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_RXCEN;
53257ba4c9bSIgal Liberman 		break;
53357ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET:
53457ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_GTSCEN;
53557ba4c9bSIgal Liberman 		break;
53657ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_BAB_TX:
53757ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_BTEN;
53857ba4c9bSIgal Liberman 		break;
53957ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_TX_CTL:
54057ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_TXCEN;
54157ba4c9bSIgal Liberman 		break;
54257ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_TX_ERR:
54357ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_TXEEN;
54457ba4c9bSIgal Liberman 		break;
54557ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_LATE_COL:
54657ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_LCEN;
54757ba4c9bSIgal Liberman 		break;
54857ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_COL_RET_LMT:
54957ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_CRLEN;
55057ba4c9bSIgal Liberman 		break;
55157ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_TX_FIFO_UNDRN:
55257ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_XFUNEN;
55357ba4c9bSIgal Liberman 		break;
55457ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_MAG_PCKT:
55557ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_MAGEN;
55657ba4c9bSIgal Liberman 		break;
55757ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_MII_MNG_RD_COMPLET:
55857ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_MMRDEN;
55957ba4c9bSIgal Liberman 		break;
56057ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_MII_MNG_WR_COMPLET:
56157ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_MMWREN;
56257ba4c9bSIgal Liberman 		break;
56357ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET:
56457ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_GRSCEN;
56557ba4c9bSIgal Liberman 		break;
56657ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_DATA_ERR:
56757ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_TDPEEN;
56857ba4c9bSIgal Liberman 		break;
56957ba4c9bSIgal Liberman 	case FM_MAC_EX_1G_RX_MIB_CNT_OVFL:
57057ba4c9bSIgal Liberman 		bit_mask = DTSEC_IMASK_MSROEN;
57157ba4c9bSIgal Liberman 		break;
57257ba4c9bSIgal Liberman 	default:
57357ba4c9bSIgal Liberman 		bit_mask = 0;
57457ba4c9bSIgal Liberman 		break;
57557ba4c9bSIgal Liberman 	}
57657ba4c9bSIgal Liberman 
57757ba4c9bSIgal Liberman 	return bit_mask;
57857ba4c9bSIgal Liberman }
57957ba4c9bSIgal Liberman 
dtsec_get_max_frame_length(struct fman_mac * dtsec)58057ba4c9bSIgal Liberman static u16 dtsec_get_max_frame_length(struct fman_mac *dtsec)
58157ba4c9bSIgal Liberman {
58257ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
58357ba4c9bSIgal Liberman 
58457ba4c9bSIgal Liberman 	return (u16)ioread32be(&regs->maxfrm);
58557ba4c9bSIgal Liberman }
58657ba4c9bSIgal Liberman 
dtsec_isr(void * handle)58757ba4c9bSIgal Liberman static void dtsec_isr(void *handle)
58857ba4c9bSIgal Liberman {
58957ba4c9bSIgal Liberman 	struct fman_mac *dtsec = (struct fman_mac *)handle;
59057ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
59157ba4c9bSIgal Liberman 	u32 event;
59257ba4c9bSIgal Liberman 
59357ba4c9bSIgal Liberman 	/* do not handle MDIO events */
59457ba4c9bSIgal Liberman 	event = ioread32be(&regs->ievent) &
59557ba4c9bSIgal Liberman 		(u32)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN));
59657ba4c9bSIgal Liberman 
59757ba4c9bSIgal Liberman 	event &= ioread32be(&regs->imask);
59857ba4c9bSIgal Liberman 
59957ba4c9bSIgal Liberman 	iowrite32be(event, &regs->ievent);
60057ba4c9bSIgal Liberman 
60157ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_BREN)
60257ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_BAB_RX);
60357ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_RXCEN)
60457ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_RX_CTL);
60557ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_GTSCEN)
60657ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id,
60757ba4c9bSIgal Liberman 				    FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET);
60857ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_BTEN)
60957ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_BAB_TX);
61057ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_TXCEN)
61157ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_CTL);
61257ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_TXEEN)
61357ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_ERR);
61457ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_LCEN)
61557ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_LATE_COL);
61657ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_CRLEN)
61757ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_COL_RET_LMT);
61857ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_XFUNEN) {
61957ba4c9bSIgal Liberman 		/* FM_TX_LOCKUP_ERRATA_DTSEC6 Errata workaround */
6205d93cfcfSSean Anderson 		/* FIXME: This races with the rest of the driver! */
62157ba4c9bSIgal Liberman 		if (dtsec->fm_rev_info.major == 2) {
62257ba4c9bSIgal Liberman 			u32 tpkt1, tmp_reg1, tpkt2, tmp_reg2, i;
62357ba4c9bSIgal Liberman 			/* a. Write 0x00E0_0C00 to DTSEC_ID
62457ba4c9bSIgal Liberman 			 *	This is a read only register
62557ba4c9bSIgal Liberman 			 * b. Read and save the value of TPKT
62657ba4c9bSIgal Liberman 			 */
62757ba4c9bSIgal Liberman 			tpkt1 = ioread32be(&regs->tpkt);
62857ba4c9bSIgal Liberman 
62957ba4c9bSIgal Liberman 			/* c. Read the register at dTSEC address offset 0x32C */
63057ba4c9bSIgal Liberman 			tmp_reg1 = ioread32be(&regs->reserved02c0[27]);
63157ba4c9bSIgal Liberman 
63257ba4c9bSIgal Liberman 			/* d. Compare bits [9:15] to bits [25:31] of the
63357ba4c9bSIgal Liberman 			 * register at address offset 0x32C.
63457ba4c9bSIgal Liberman 			 */
63557ba4c9bSIgal Liberman 			if ((tmp_reg1 & 0x007F0000) !=
63657ba4c9bSIgal Liberman 				(tmp_reg1 & 0x0000007F)) {
63757ba4c9bSIgal Liberman 				/* If they are not equal, save the value of
63857ba4c9bSIgal Liberman 				 * this register and wait for at least
63957ba4c9bSIgal Liberman 				 * MAXFRM*16 ns
64057ba4c9bSIgal Liberman 				 */
64157ba4c9bSIgal Liberman 				usleep_range((u32)(min
64257ba4c9bSIgal Liberman 					(dtsec_get_max_frame_length(dtsec) *
64357ba4c9bSIgal Liberman 					16 / 1000, 1)), (u32)
64457ba4c9bSIgal Liberman 					(min(dtsec_get_max_frame_length
64557ba4c9bSIgal Liberman 					(dtsec) * 16 / 1000, 1) + 1));
64657ba4c9bSIgal Liberman 			}
64757ba4c9bSIgal Liberman 
64857ba4c9bSIgal Liberman 			/* e. Read and save TPKT again and read the register
64957ba4c9bSIgal Liberman 			 * at dTSEC address offset 0x32C again
65057ba4c9bSIgal Liberman 			 */
65157ba4c9bSIgal Liberman 			tpkt2 = ioread32be(&regs->tpkt);
65257ba4c9bSIgal Liberman 			tmp_reg2 = ioread32be(&regs->reserved02c0[27]);
65357ba4c9bSIgal Liberman 
65457ba4c9bSIgal Liberman 			/* f. Compare the value of TPKT saved in step b to
65557ba4c9bSIgal Liberman 			 * value read in step e. Also compare bits [9:15] of
65657ba4c9bSIgal Liberman 			 * the register at offset 0x32C saved in step d to the
65757ba4c9bSIgal Liberman 			 * value of bits [9:15] saved in step e. If the two
65857ba4c9bSIgal Liberman 			 * registers values are unchanged, then the transmit
65957ba4c9bSIgal Liberman 			 * portion of the dTSEC controller is locked up and
66057ba4c9bSIgal Liberman 			 * the user should proceed to the recover sequence.
66157ba4c9bSIgal Liberman 			 */
66257ba4c9bSIgal Liberman 			if ((tpkt1 == tpkt2) && ((tmp_reg1 & 0x007F0000) ==
66357ba4c9bSIgal Liberman 				(tmp_reg2 & 0x007F0000))) {
66457ba4c9bSIgal Liberman 				/* recover sequence */
66557ba4c9bSIgal Liberman 
66657ba4c9bSIgal Liberman 				/* a.Write a 1 to RCTRL[GRS] */
66757ba4c9bSIgal Liberman 
66857ba4c9bSIgal Liberman 				iowrite32be(ioread32be(&regs->rctrl) |
66957ba4c9bSIgal Liberman 					    RCTRL_GRS, &regs->rctrl);
67057ba4c9bSIgal Liberman 
67157ba4c9bSIgal Liberman 				/* b.Wait until IEVENT[GRSC]=1, or at least
67257ba4c9bSIgal Liberman 				 * 100 us has elapsed.
67357ba4c9bSIgal Liberman 				 */
67457ba4c9bSIgal Liberman 				for (i = 0; i < 100; i++) {
67557ba4c9bSIgal Liberman 					if (ioread32be(&regs->ievent) &
67657ba4c9bSIgal Liberman 					    DTSEC_IMASK_GRSCEN)
67757ba4c9bSIgal Liberman 						break;
67857ba4c9bSIgal Liberman 					udelay(1);
67957ba4c9bSIgal Liberman 				}
68057ba4c9bSIgal Liberman 				if (ioread32be(&regs->ievent) &
68157ba4c9bSIgal Liberman 				    DTSEC_IMASK_GRSCEN)
68257ba4c9bSIgal Liberman 					iowrite32be(DTSEC_IMASK_GRSCEN,
68357ba4c9bSIgal Liberman 						    &regs->ievent);
68457ba4c9bSIgal Liberman 				else
68557ba4c9bSIgal Liberman 					pr_debug("Rx lockup due to Tx lockup\n");
68657ba4c9bSIgal Liberman 
68757ba4c9bSIgal Liberman 				/* c.Write a 1 to bit n of FM_RSTC
68857ba4c9bSIgal Liberman 				 * (offset 0x0CC of FPM)
68957ba4c9bSIgal Liberman 				 */
69057ba4c9bSIgal Liberman 				fman_reset_mac(dtsec->fm, dtsec->mac_id);
69157ba4c9bSIgal Liberman 
69257ba4c9bSIgal Liberman 				/* d.Wait 4 Tx clocks (32 ns) */
69357ba4c9bSIgal Liberman 				udelay(1);
69457ba4c9bSIgal Liberman 
69557ba4c9bSIgal Liberman 				/* e.Write a 0 to bit n of FM_RSTC. */
69657ba4c9bSIgal Liberman 				/* cleared by FMAN
69757ba4c9bSIgal Liberman 				 */
69857ba4c9bSIgal Liberman 			}
69957ba4c9bSIgal Liberman 		}
70057ba4c9bSIgal Liberman 
70157ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_TX_FIFO_UNDRN);
70257ba4c9bSIgal Liberman 	}
70357ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_MAGEN)
70457ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_MAG_PCKT);
70557ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_GRSCEN)
70657ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id,
70757ba4c9bSIgal Liberman 				    FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET);
70857ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_TDPEEN)
70957ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_DATA_ERR);
71057ba4c9bSIgal Liberman 	if (event & DTSEC_IMASK_RDPEEN)
71157ba4c9bSIgal Liberman 		dtsec->exception_cb(dtsec->dev_id, FM_MAC_1G_RX_DATA_ERR);
71257ba4c9bSIgal Liberman 
71357ba4c9bSIgal Liberman 	/* masked interrupts */
71457ba4c9bSIgal Liberman 	WARN_ON(event & DTSEC_IMASK_ABRTEN);
71557ba4c9bSIgal Liberman 	WARN_ON(event & DTSEC_IMASK_IFERREN);
71657ba4c9bSIgal Liberman }
71757ba4c9bSIgal Liberman 
dtsec_1588_isr(void * handle)71857ba4c9bSIgal Liberman static void dtsec_1588_isr(void *handle)
71957ba4c9bSIgal Liberman {
72057ba4c9bSIgal Liberman 	struct fman_mac *dtsec = (struct fman_mac *)handle;
72157ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
72257ba4c9bSIgal Liberman 	u32 event;
72357ba4c9bSIgal Liberman 
72457ba4c9bSIgal Liberman 	if (dtsec->ptp_tsu_enabled) {
72557ba4c9bSIgal Liberman 		event = ioread32be(&regs->tmr_pevent);
72657ba4c9bSIgal Liberman 		event &= ioread32be(&regs->tmr_pemask);
72757ba4c9bSIgal Liberman 
72857ba4c9bSIgal Liberman 		if (event) {
72957ba4c9bSIgal Liberman 			iowrite32be(event, &regs->tmr_pevent);
73057ba4c9bSIgal Liberman 			WARN_ON(event & TMR_PEVENT_TSRE);
73157ba4c9bSIgal Liberman 			dtsec->exception_cb(dtsec->dev_id,
73257ba4c9bSIgal Liberman 					    FM_MAC_EX_1G_1588_TS_RX_ERR);
73357ba4c9bSIgal Liberman 		}
73457ba4c9bSIgal Liberman 	}
73557ba4c9bSIgal Liberman }
73657ba4c9bSIgal Liberman 
free_init_resources(struct fman_mac * dtsec)73757ba4c9bSIgal Liberman static void free_init_resources(struct fman_mac *dtsec)
73857ba4c9bSIgal Liberman {
73957ba4c9bSIgal Liberman 	fman_unregister_intr(dtsec->fm, FMAN_MOD_MAC, dtsec->mac_id,
74057ba4c9bSIgal Liberman 			     FMAN_INTR_TYPE_ERR);
74157ba4c9bSIgal Liberman 	fman_unregister_intr(dtsec->fm, FMAN_MOD_MAC, dtsec->mac_id,
74257ba4c9bSIgal Liberman 			     FMAN_INTR_TYPE_NORMAL);
74357ba4c9bSIgal Liberman 
74457ba4c9bSIgal Liberman 	/* release the driver's group hash table */
74557ba4c9bSIgal Liberman 	free_hash_table(dtsec->multicast_addr_hash);
74657ba4c9bSIgal Liberman 	dtsec->multicast_addr_hash = NULL;
74757ba4c9bSIgal Liberman 
74857ba4c9bSIgal Liberman 	/* release the driver's individual hash table */
74957ba4c9bSIgal Liberman 	free_hash_table(dtsec->unicast_addr_hash);
75057ba4c9bSIgal Liberman 	dtsec->unicast_addr_hash = NULL;
75157ba4c9bSIgal Liberman }
75257ba4c9bSIgal Liberman 
pcs_to_dtsec(struct phylink_pcs * pcs)7535d93cfcfSSean Anderson static struct fman_mac *pcs_to_dtsec(struct phylink_pcs *pcs)
7545d93cfcfSSean Anderson {
7555d93cfcfSSean Anderson 	return container_of(pcs, struct fman_mac, pcs);
7565d93cfcfSSean Anderson }
7575d93cfcfSSean Anderson 
dtsec_pcs_get_state(struct phylink_pcs * pcs,struct phylink_link_state * state)7585d93cfcfSSean Anderson static void dtsec_pcs_get_state(struct phylink_pcs *pcs,
7595d93cfcfSSean Anderson 				struct phylink_link_state *state)
7605d93cfcfSSean Anderson {
7615d93cfcfSSean Anderson 	struct fman_mac *dtsec = pcs_to_dtsec(pcs);
7625d93cfcfSSean Anderson 
7635d93cfcfSSean Anderson 	phylink_mii_c22_pcs_get_state(dtsec->tbidev, state);
7645d93cfcfSSean Anderson }
7655d93cfcfSSean Anderson 
dtsec_pcs_config(struct phylink_pcs * pcs,unsigned int neg_mode,phy_interface_t interface,const unsigned long * advertising,bool permit_pause_to_mac)766*febf2aafSRussell King (Oracle) static int dtsec_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
7675d93cfcfSSean Anderson 			    phy_interface_t interface,
7685d93cfcfSSean Anderson 			    const unsigned long *advertising,
7695d93cfcfSSean Anderson 			    bool permit_pause_to_mac)
7705d93cfcfSSean Anderson {
7715d93cfcfSSean Anderson 	struct fman_mac *dtsec = pcs_to_dtsec(pcs);
7725d93cfcfSSean Anderson 
773*febf2aafSRussell King (Oracle) 	return phylink_mii_c22_pcs_config(dtsec->tbidev, interface,
774*febf2aafSRussell King (Oracle) 					  advertising, neg_mode);
7755d93cfcfSSean Anderson }
7765d93cfcfSSean Anderson 
dtsec_pcs_an_restart(struct phylink_pcs * pcs)7775d93cfcfSSean Anderson static void dtsec_pcs_an_restart(struct phylink_pcs *pcs)
7785d93cfcfSSean Anderson {
7795d93cfcfSSean Anderson 	struct fman_mac *dtsec = pcs_to_dtsec(pcs);
7805d93cfcfSSean Anderson 
7815d93cfcfSSean Anderson 	phylink_mii_c22_pcs_an_restart(dtsec->tbidev);
7825d93cfcfSSean Anderson }
7835d93cfcfSSean Anderson 
7845d93cfcfSSean Anderson static const struct phylink_pcs_ops dtsec_pcs_ops = {
7855d93cfcfSSean Anderson 	.pcs_get_state = dtsec_pcs_get_state,
7865d93cfcfSSean Anderson 	.pcs_config = dtsec_pcs_config,
7875d93cfcfSSean Anderson 	.pcs_an_restart = dtsec_pcs_an_restart,
7885d93cfcfSSean Anderson };
7895d93cfcfSSean Anderson 
graceful_start(struct fman_mac * dtsec)790aae73fdeSSean Anderson static void graceful_start(struct fman_mac *dtsec)
791e37425c2SFlorinel Iordache {
792e37425c2SFlorinel Iordache 	struct dtsec_regs __iomem *regs = dtsec->regs;
793e37425c2SFlorinel Iordache 
794aae73fdeSSean Anderson 	iowrite32be(ioread32be(&regs->tctrl) & ~TCTRL_GTS, &regs->tctrl);
795aae73fdeSSean Anderson 	iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS, &regs->rctrl);
796e37425c2SFlorinel Iordache }
797e37425c2SFlorinel Iordache 
graceful_stop(struct fman_mac * dtsec)798aae73fdeSSean Anderson static void graceful_stop(struct fman_mac *dtsec)
799e37425c2SFlorinel Iordache {
800e37425c2SFlorinel Iordache 	struct dtsec_regs __iomem *regs = dtsec->regs;
801e37425c2SFlorinel Iordache 	u32 tmp;
802e37425c2SFlorinel Iordache 
803e37425c2SFlorinel Iordache 	/* Graceful stop - Assert the graceful Rx stop bit */
804e37425c2SFlorinel Iordache 	tmp = ioread32be(&regs->rctrl) | RCTRL_GRS;
805e37425c2SFlorinel Iordache 	iowrite32be(tmp, &regs->rctrl);
806e37425c2SFlorinel Iordache 
807e37425c2SFlorinel Iordache 	if (dtsec->fm_rev_info.major == 2) {
808e37425c2SFlorinel Iordache 		/* Workaround for dTSEC Errata A002 */
809e37425c2SFlorinel Iordache 		usleep_range(100, 200);
810e37425c2SFlorinel Iordache 	} else {
811e37425c2SFlorinel Iordache 		/* Workaround for dTSEC Errata A004839 */
812e37425c2SFlorinel Iordache 		usleep_range(10, 50);
813e37425c2SFlorinel Iordache 	}
814e37425c2SFlorinel Iordache 
815e37425c2SFlorinel Iordache 	/* Graceful stop - Assert the graceful Tx stop bit */
816e37425c2SFlorinel Iordache 	if (dtsec->fm_rev_info.major == 2) {
817e37425c2SFlorinel Iordache 		/* dTSEC Errata A004: Do not use TCTRL[GTS]=1 */
818e37425c2SFlorinel Iordache 		pr_debug("GTS not supported due to DTSEC_A004 Errata.\n");
819e37425c2SFlorinel Iordache 	} else {
820e37425c2SFlorinel Iordache 		tmp = ioread32be(&regs->tctrl) | TCTRL_GTS;
821e37425c2SFlorinel Iordache 		iowrite32be(tmp, &regs->tctrl);
822e37425c2SFlorinel Iordache 
823e37425c2SFlorinel Iordache 		/* Workaround for dTSEC Errata A0012, A0014 */
824e37425c2SFlorinel Iordache 		usleep_range(10, 50);
825e37425c2SFlorinel Iordache 	}
826e37425c2SFlorinel Iordache }
827e37425c2SFlorinel Iordache 
dtsec_enable(struct fman_mac * dtsec)8281257c962SSean Anderson static int dtsec_enable(struct fman_mac *dtsec)
82957ba4c9bSIgal Liberman {
83057ba4c9bSIgal Liberman 	return 0;
83157ba4c9bSIgal Liberman }
83257ba4c9bSIgal Liberman 
dtsec_disable(struct fman_mac * dtsec)833901bdff2SSean Anderson static void dtsec_disable(struct fman_mac *dtsec)
83457ba4c9bSIgal Liberman {
83557ba4c9bSIgal Liberman }
83657ba4c9bSIgal Liberman 
dtsec_set_tx_pause_frames(struct fman_mac * dtsec,u8 __maybe_unused priority,u16 pause_time,u16 __maybe_unused thresh_time)8371257c962SSean Anderson static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
83857ba4c9bSIgal Liberman 				     u8 __maybe_unused priority,
8391257c962SSean Anderson 				     u16 pause_time,
8401257c962SSean Anderson 				     u16 __maybe_unused thresh_time)
84157ba4c9bSIgal Liberman {
84257ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
84357ba4c9bSIgal Liberman 	u32 ptv = 0;
84457ba4c9bSIgal Liberman 
8457c82a7b9SIgal Liberman 	if (pause_time) {
84657ba4c9bSIgal Liberman 		/* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
8477c82a7b9SIgal Liberman 		if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
84857ba4c9bSIgal Liberman 			pr_warn("pause-time: %d illegal.Should be > 320\n",
84957ba4c9bSIgal Liberman 				pause_time);
85057ba4c9bSIgal Liberman 			return -EINVAL;
85157ba4c9bSIgal Liberman 		}
85257ba4c9bSIgal Liberman 
85357ba4c9bSIgal Liberman 		ptv = ioread32be(&regs->ptv);
85457ba4c9bSIgal Liberman 		ptv &= PTV_PTE_MASK;
85557ba4c9bSIgal Liberman 		ptv |= pause_time & PTV_PT_MASK;
85657ba4c9bSIgal Liberman 		iowrite32be(ptv, &regs->ptv);
85757ba4c9bSIgal Liberman 
85857ba4c9bSIgal Liberman 		/* trigger the transmission of a flow-control pause frame */
85957ba4c9bSIgal Liberman 		iowrite32be(ioread32be(&regs->maccfg1) | MACCFG1_TX_FLOW,
86057ba4c9bSIgal Liberman 			    &regs->maccfg1);
86157ba4c9bSIgal Liberman 	} else
86257ba4c9bSIgal Liberman 		iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
86357ba4c9bSIgal Liberman 			    &regs->maccfg1);
86457ba4c9bSIgal Liberman 
86557ba4c9bSIgal Liberman 	return 0;
86657ba4c9bSIgal Liberman }
86757ba4c9bSIgal Liberman 
dtsec_accept_rx_pause_frames(struct fman_mac * dtsec,bool en)8681257c962SSean Anderson static int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
86957ba4c9bSIgal Liberman {
87057ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
87157ba4c9bSIgal Liberman 	u32 tmp;
87257ba4c9bSIgal Liberman 
87357ba4c9bSIgal Liberman 	tmp = ioread32be(&regs->maccfg1);
87457ba4c9bSIgal Liberman 	if (en)
87557ba4c9bSIgal Liberman 		tmp |= MACCFG1_RX_FLOW;
87657ba4c9bSIgal Liberman 	else
87757ba4c9bSIgal Liberman 		tmp &= ~MACCFG1_RX_FLOW;
87857ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->maccfg1);
87957ba4c9bSIgal Liberman 
88057ba4c9bSIgal Liberman 	return 0;
88157ba4c9bSIgal Liberman }
88257ba4c9bSIgal Liberman 
dtsec_select_pcs(struct phylink_config * config,phy_interface_t iface)8835d93cfcfSSean Anderson static struct phylink_pcs *dtsec_select_pcs(struct phylink_config *config,
8845d93cfcfSSean Anderson 					    phy_interface_t iface)
8855d93cfcfSSean Anderson {
8865d93cfcfSSean Anderson 	struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac;
8875d93cfcfSSean Anderson 
8885d93cfcfSSean Anderson 	switch (iface) {
8895d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_SGMII:
8905d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_1000BASEX:
8915d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_2500BASEX:
8925d93cfcfSSean Anderson 		return &dtsec->pcs;
8935d93cfcfSSean Anderson 	default:
8945d93cfcfSSean Anderson 		return NULL;
8955d93cfcfSSean Anderson 	}
8965d93cfcfSSean Anderson }
8975d93cfcfSSean Anderson 
dtsec_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)8985d93cfcfSSean Anderson static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
8995d93cfcfSSean Anderson 			     const struct phylink_link_state *state)
9005d93cfcfSSean Anderson {
9015d93cfcfSSean Anderson 	struct mac_device *mac_dev = fman_config_to_mac(config);
9025d93cfcfSSean Anderson 	struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs;
9035d93cfcfSSean Anderson 	u32 tmp;
9045d93cfcfSSean Anderson 
9055d93cfcfSSean Anderson 	switch (state->interface) {
9065d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_RMII:
9075d93cfcfSSean Anderson 		tmp = DTSEC_ECNTRL_RMM;
9085d93cfcfSSean Anderson 		break;
9095d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_RGMII:
9105d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_RGMII_ID:
9115d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_RGMII_RXID:
9125d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_RGMII_TXID:
9135d93cfcfSSean Anderson 		tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
9145d93cfcfSSean Anderson 		break;
9155d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_SGMII:
9165d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_1000BASEX:
9175d93cfcfSSean Anderson 	case PHY_INTERFACE_MODE_2500BASEX:
9185d93cfcfSSean Anderson 		tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
9195d93cfcfSSean Anderson 		break;
9205d93cfcfSSean Anderson 	default:
9215d93cfcfSSean Anderson 		dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n",
9225d93cfcfSSean Anderson 			 phy_modes(state->interface));
9235d93cfcfSSean Anderson 		return;
9245d93cfcfSSean Anderson 	}
9255d93cfcfSSean Anderson 
9265d93cfcfSSean Anderson 	iowrite32be(tmp, &regs->ecntrl);
9275d93cfcfSSean Anderson }
9285d93cfcfSSean Anderson 
dtsec_link_up(struct phylink_config * config,struct phy_device * phy,unsigned int mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)9295d93cfcfSSean Anderson static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy,
9305d93cfcfSSean Anderson 			  unsigned int mode, phy_interface_t interface,
9315d93cfcfSSean Anderson 			  int speed, int duplex, bool tx_pause, bool rx_pause)
9325d93cfcfSSean Anderson {
9335d93cfcfSSean Anderson 	struct mac_device *mac_dev = fman_config_to_mac(config);
9345d93cfcfSSean Anderson 	struct fman_mac *dtsec = mac_dev->fman_mac;
9355d93cfcfSSean Anderson 	struct dtsec_regs __iomem *regs = dtsec->regs;
9365d93cfcfSSean Anderson 	u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
9375d93cfcfSSean Anderson 			 FSL_FM_PAUSE_TIME_DISABLE;
9385d93cfcfSSean Anderson 	u32 tmp;
9395d93cfcfSSean Anderson 
9405d93cfcfSSean Anderson 	dtsec_set_tx_pause_frames(dtsec, 0, pause_time, 0);
9415d93cfcfSSean Anderson 	dtsec_accept_rx_pause_frames(dtsec, rx_pause);
9425d93cfcfSSean Anderson 
9435d93cfcfSSean Anderson 	tmp = ioread32be(&regs->ecntrl);
9445d93cfcfSSean Anderson 	if (speed == SPEED_100)
9455d93cfcfSSean Anderson 		tmp |= DTSEC_ECNTRL_R100M;
9465d93cfcfSSean Anderson 	else
9475d93cfcfSSean Anderson 		tmp &= ~DTSEC_ECNTRL_R100M;
9485d93cfcfSSean Anderson 	iowrite32be(tmp, &regs->ecntrl);
9495d93cfcfSSean Anderson 
9505d93cfcfSSean Anderson 	tmp = ioread32be(&regs->maccfg2);
9515d93cfcfSSean Anderson 	tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE | MACCFG2_FULL_DUPLEX);
9525d93cfcfSSean Anderson 	if (speed >= SPEED_1000)
9535d93cfcfSSean Anderson 		tmp |= MACCFG2_BYTE_MODE;
9545d93cfcfSSean Anderson 	else
9555d93cfcfSSean Anderson 		tmp |= MACCFG2_NIBBLE_MODE;
9565d93cfcfSSean Anderson 
9575d93cfcfSSean Anderson 	if (duplex == DUPLEX_FULL)
9585d93cfcfSSean Anderson 		tmp |= MACCFG2_FULL_DUPLEX;
9595d93cfcfSSean Anderson 
9605d93cfcfSSean Anderson 	iowrite32be(tmp, &regs->maccfg2);
9615d93cfcfSSean Anderson 
9625d93cfcfSSean Anderson 	mac_dev->update_speed(mac_dev, speed);
9635d93cfcfSSean Anderson 
9645d93cfcfSSean Anderson 	/* Enable */
9655d93cfcfSSean Anderson 	tmp = ioread32be(&regs->maccfg1);
9665d93cfcfSSean Anderson 	tmp |= MACCFG1_RX_EN | MACCFG1_TX_EN;
9675d93cfcfSSean Anderson 	iowrite32be(tmp, &regs->maccfg1);
9685d93cfcfSSean Anderson 
9695d93cfcfSSean Anderson 	/* Graceful start - clear the graceful Rx/Tx stop bit */
9705d93cfcfSSean Anderson 	graceful_start(dtsec);
9715d93cfcfSSean Anderson }
9725d93cfcfSSean Anderson 
dtsec_link_down(struct phylink_config * config,unsigned int mode,phy_interface_t interface)9735d93cfcfSSean Anderson static void dtsec_link_down(struct phylink_config *config, unsigned int mode,
9745d93cfcfSSean Anderson 			    phy_interface_t interface)
9755d93cfcfSSean Anderson {
9765d93cfcfSSean Anderson 	struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac;
9775d93cfcfSSean Anderson 	struct dtsec_regs __iomem *regs = dtsec->regs;
9785d93cfcfSSean Anderson 	u32 tmp;
9795d93cfcfSSean Anderson 
9805d93cfcfSSean Anderson 	/* Graceful stop - Assert the graceful Rx/Tx stop bit */
9815d93cfcfSSean Anderson 	graceful_stop(dtsec);
9825d93cfcfSSean Anderson 
9835d93cfcfSSean Anderson 	tmp = ioread32be(&regs->maccfg1);
9845d93cfcfSSean Anderson 	tmp &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
9855d93cfcfSSean Anderson 	iowrite32be(tmp, &regs->maccfg1);
9865d93cfcfSSean Anderson }
9875d93cfcfSSean Anderson 
9885d93cfcfSSean Anderson static const struct phylink_mac_ops dtsec_mac_ops = {
9895d93cfcfSSean Anderson 	.mac_select_pcs = dtsec_select_pcs,
9905d93cfcfSSean Anderson 	.mac_config = dtsec_mac_config,
9915d93cfcfSSean Anderson 	.mac_link_up = dtsec_link_up,
9925d93cfcfSSean Anderson 	.mac_link_down = dtsec_link_down,
9935d93cfcfSSean Anderson };
9945d93cfcfSSean Anderson 
dtsec_modify_mac_address(struct fman_mac * dtsec,const enet_addr_t * enet_addr)9951257c962SSean Anderson static int dtsec_modify_mac_address(struct fman_mac *dtsec,
9961257c962SSean Anderson 				    const enet_addr_t *enet_addr)
99757ba4c9bSIgal Liberman {
998aae73fdeSSean Anderson 	graceful_stop(dtsec);
999e37425c2SFlorinel Iordache 
100057ba4c9bSIgal Liberman 	/* Initialize MAC Station Address registers (1 & 2)
100157ba4c9bSIgal Liberman 	 * Station address have to be swapped (big endian to little endian
100257ba4c9bSIgal Liberman 	 */
100357ba4c9bSIgal Liberman 	dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr);
100476660757SJakub Kicinski 	set_mac_address(dtsec->regs, (const u8 *)(*enet_addr));
100557ba4c9bSIgal Liberman 
1006aae73fdeSSean Anderson 	graceful_start(dtsec);
1007e37425c2SFlorinel Iordache 
100857ba4c9bSIgal Liberman 	return 0;
100957ba4c9bSIgal Liberman }
101057ba4c9bSIgal Liberman 
dtsec_add_hash_mac_address(struct fman_mac * dtsec,enet_addr_t * eth_addr)10111257c962SSean Anderson static int dtsec_add_hash_mac_address(struct fman_mac *dtsec,
10121257c962SSean Anderson 				      enet_addr_t *eth_addr)
101357ba4c9bSIgal Liberman {
101457ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
101557ba4c9bSIgal Liberman 	struct eth_hash_entry *hash_entry;
101657ba4c9bSIgal Liberman 	u64 addr;
101757ba4c9bSIgal Liberman 	s32 bucket;
101857ba4c9bSIgal Liberman 	u32 crc = 0xFFFFFFFF;
101957ba4c9bSIgal Liberman 	bool mcast, ghtx;
102057ba4c9bSIgal Liberman 
102157ba4c9bSIgal Liberman 	addr = ENET_ADDR_TO_UINT64(*eth_addr);
102257ba4c9bSIgal Liberman 
102357ba4c9bSIgal Liberman 	ghtx = (bool)((ioread32be(&regs->rctrl) & RCTRL_GHTX) ? true : false);
102457ba4c9bSIgal Liberman 	mcast = (bool)((addr & MAC_GROUP_ADDRESS) ? true : false);
102557ba4c9bSIgal Liberman 
102657ba4c9bSIgal Liberman 	/* Cannot handle unicast mac addr when GHTX is on */
102757ba4c9bSIgal Liberman 	if (ghtx && !mcast) {
102857ba4c9bSIgal Liberman 		pr_err("Could not compute hash bucket\n");
102957ba4c9bSIgal Liberman 		return -EINVAL;
103057ba4c9bSIgal Liberman 	}
103157ba4c9bSIgal Liberman 	crc = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
103257ba4c9bSIgal Liberman 	crc = bitrev32(crc);
103357ba4c9bSIgal Liberman 
103457ba4c9bSIgal Liberman 	/* considering the 9 highest order bits in crc H[8:0]:
103557ba4c9bSIgal Liberman 	 *if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register
103657ba4c9bSIgal Liberman 	 *and H[5:1] (next 5 bits) identify the hash bit
103757ba4c9bSIgal Liberman 	 *if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register
103857ba4c9bSIgal Liberman 	 *and H[4:0] (next 5 bits) identify the hash bit.
103957ba4c9bSIgal Liberman 	 *
104057ba4c9bSIgal Liberman 	 *In bucket index output the low 5 bits identify the hash register
104157ba4c9bSIgal Liberman 	 *bit, while the higher 4 bits identify the hash register
104257ba4c9bSIgal Liberman 	 */
104357ba4c9bSIgal Liberman 
104457ba4c9bSIgal Liberman 	if (ghtx) {
104557ba4c9bSIgal Liberman 		bucket = (s32)((crc >> 23) & 0x1ff);
104657ba4c9bSIgal Liberman 	} else {
104757ba4c9bSIgal Liberman 		bucket = (s32)((crc >> 24) & 0xff);
104857ba4c9bSIgal Liberman 		/* if !ghtx and mcast the bit must be set in gaddr instead of
104957ba4c9bSIgal Liberman 		 *igaddr.
105057ba4c9bSIgal Liberman 		 */
105157ba4c9bSIgal Liberman 		if (mcast)
105257ba4c9bSIgal Liberman 			bucket += 0x100;
105357ba4c9bSIgal Liberman 	}
105457ba4c9bSIgal Liberman 
105557ba4c9bSIgal Liberman 	set_bucket(dtsec->regs, bucket, true);
105657ba4c9bSIgal Liberman 
105757ba4c9bSIgal Liberman 	/* Create element to be added to the driver hash table */
1058803fafbeSDenis Kirjanov 	hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC);
105957ba4c9bSIgal Liberman 	if (!hash_entry)
106057ba4c9bSIgal Liberman 		return -ENOMEM;
106157ba4c9bSIgal Liberman 	hash_entry->addr = addr;
106257ba4c9bSIgal Liberman 	INIT_LIST_HEAD(&hash_entry->node);
106357ba4c9bSIgal Liberman 
106457ba4c9bSIgal Liberman 	if (addr & MAC_GROUP_ADDRESS)
106557ba4c9bSIgal Liberman 		/* Group Address */
106657ba4c9bSIgal Liberman 		list_add_tail(&hash_entry->node,
106757ba4c9bSIgal Liberman 			      &dtsec->multicast_addr_hash->lsts[bucket]);
106857ba4c9bSIgal Liberman 	else
106957ba4c9bSIgal Liberman 		list_add_tail(&hash_entry->node,
107057ba4c9bSIgal Liberman 			      &dtsec->unicast_addr_hash->lsts[bucket]);
107157ba4c9bSIgal Liberman 
107257ba4c9bSIgal Liberman 	return 0;
107357ba4c9bSIgal Liberman }
107457ba4c9bSIgal Liberman 
dtsec_set_allmulti(struct fman_mac * dtsec,bool enable)10751257c962SSean Anderson static int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable)
1076c893238eSRadu Bulie {
1077c893238eSRadu Bulie 	u32 tmp;
1078c893238eSRadu Bulie 	struct dtsec_regs __iomem *regs = dtsec->regs;
1079c893238eSRadu Bulie 
1080c893238eSRadu Bulie 	tmp = ioread32be(&regs->rctrl);
1081c893238eSRadu Bulie 	if (enable)
1082c893238eSRadu Bulie 		tmp |= RCTRL_MPROM;
1083c893238eSRadu Bulie 	else
1084c893238eSRadu Bulie 		tmp &= ~RCTRL_MPROM;
1085c893238eSRadu Bulie 
1086c893238eSRadu Bulie 	iowrite32be(tmp, &regs->rctrl);
1087c893238eSRadu Bulie 
1088c893238eSRadu Bulie 	return 0;
1089c893238eSRadu Bulie }
1090c893238eSRadu Bulie 
dtsec_set_tstamp(struct fman_mac * dtsec,bool enable)10911257c962SSean Anderson static int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable)
10920fab782aSYangbo Lu {
10930fab782aSYangbo Lu 	struct dtsec_regs __iomem *regs = dtsec->regs;
10940fab782aSYangbo Lu 	u32 rctrl, tctrl;
10950fab782aSYangbo Lu 
10960fab782aSYangbo Lu 	rctrl = ioread32be(&regs->rctrl);
10970fab782aSYangbo Lu 	tctrl = ioread32be(&regs->tctrl);
10980fab782aSYangbo Lu 
10990fab782aSYangbo Lu 	if (enable) {
11000fab782aSYangbo Lu 		rctrl |= RCTRL_RTSE;
11010fab782aSYangbo Lu 		tctrl |= TCTRL_TTSE;
11020fab782aSYangbo Lu 	} else {
11030fab782aSYangbo Lu 		rctrl &= ~RCTRL_RTSE;
11040fab782aSYangbo Lu 		tctrl &= ~TCTRL_TTSE;
11050fab782aSYangbo Lu 	}
11060fab782aSYangbo Lu 
11070fab782aSYangbo Lu 	iowrite32be(rctrl, &regs->rctrl);
11080fab782aSYangbo Lu 	iowrite32be(tctrl, &regs->tctrl);
11090fab782aSYangbo Lu 
11100fab782aSYangbo Lu 	return 0;
11110fab782aSYangbo Lu }
11120fab782aSYangbo Lu 
dtsec_del_hash_mac_address(struct fman_mac * dtsec,enet_addr_t * eth_addr)11131257c962SSean Anderson static int dtsec_del_hash_mac_address(struct fman_mac *dtsec,
11141257c962SSean Anderson 				      enet_addr_t *eth_addr)
111557ba4c9bSIgal Liberman {
111657ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
111757ba4c9bSIgal Liberman 	struct list_head *pos;
111857ba4c9bSIgal Liberman 	struct eth_hash_entry *hash_entry = NULL;
111957ba4c9bSIgal Liberman 	u64 addr;
112057ba4c9bSIgal Liberman 	s32 bucket;
112157ba4c9bSIgal Liberman 	u32 crc = 0xFFFFFFFF;
112257ba4c9bSIgal Liberman 	bool mcast, ghtx;
112357ba4c9bSIgal Liberman 
112457ba4c9bSIgal Liberman 	addr = ENET_ADDR_TO_UINT64(*eth_addr);
112557ba4c9bSIgal Liberman 
112657ba4c9bSIgal Liberman 	ghtx = (bool)((ioread32be(&regs->rctrl) & RCTRL_GHTX) ? true : false);
112757ba4c9bSIgal Liberman 	mcast = (bool)((addr & MAC_GROUP_ADDRESS) ? true : false);
112857ba4c9bSIgal Liberman 
112957ba4c9bSIgal Liberman 	/* Cannot handle unicast mac addr when GHTX is on */
113057ba4c9bSIgal Liberman 	if (ghtx && !mcast) {
113157ba4c9bSIgal Liberman 		pr_err("Could not compute hash bucket\n");
113257ba4c9bSIgal Liberman 		return -EINVAL;
113357ba4c9bSIgal Liberman 	}
113457ba4c9bSIgal Liberman 	crc = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
113557ba4c9bSIgal Liberman 	crc = bitrev32(crc);
113657ba4c9bSIgal Liberman 
113757ba4c9bSIgal Liberman 	if (ghtx) {
113857ba4c9bSIgal Liberman 		bucket = (s32)((crc >> 23) & 0x1ff);
113957ba4c9bSIgal Liberman 	} else {
114057ba4c9bSIgal Liberman 		bucket = (s32)((crc >> 24) & 0xff);
114157ba4c9bSIgal Liberman 		/* if !ghtx and mcast the bit must be set
114257ba4c9bSIgal Liberman 		 * in gaddr instead of igaddr.
114357ba4c9bSIgal Liberman 		 */
114457ba4c9bSIgal Liberman 		if (mcast)
114557ba4c9bSIgal Liberman 			bucket += 0x100;
114657ba4c9bSIgal Liberman 	}
114757ba4c9bSIgal Liberman 
114857ba4c9bSIgal Liberman 	if (addr & MAC_GROUP_ADDRESS) {
114957ba4c9bSIgal Liberman 		/* Group Address */
115057ba4c9bSIgal Liberman 		list_for_each(pos,
115157ba4c9bSIgal Liberman 			      &dtsec->multicast_addr_hash->lsts[bucket]) {
115257ba4c9bSIgal Liberman 			hash_entry = ETH_HASH_ENTRY_OBJ(pos);
1153cc5d229aSFlorinel Iordache 			if (hash_entry && hash_entry->addr == addr) {
115457ba4c9bSIgal Liberman 				list_del_init(&hash_entry->node);
115557ba4c9bSIgal Liberman 				kfree(hash_entry);
115657ba4c9bSIgal Liberman 				break;
115757ba4c9bSIgal Liberman 			}
115857ba4c9bSIgal Liberman 		}
115957ba4c9bSIgal Liberman 		if (list_empty(&dtsec->multicast_addr_hash->lsts[bucket]))
116057ba4c9bSIgal Liberman 			set_bucket(dtsec->regs, bucket, false);
116157ba4c9bSIgal Liberman 	} else {
116257ba4c9bSIgal Liberman 		/* Individual Address */
116357ba4c9bSIgal Liberman 		list_for_each(pos,
116457ba4c9bSIgal Liberman 			      &dtsec->unicast_addr_hash->lsts[bucket]) {
116557ba4c9bSIgal Liberman 			hash_entry = ETH_HASH_ENTRY_OBJ(pos);
1166cc5d229aSFlorinel Iordache 			if (hash_entry && hash_entry->addr == addr) {
116757ba4c9bSIgal Liberman 				list_del_init(&hash_entry->node);
116857ba4c9bSIgal Liberman 				kfree(hash_entry);
116957ba4c9bSIgal Liberman 				break;
117057ba4c9bSIgal Liberman 			}
117157ba4c9bSIgal Liberman 		}
117257ba4c9bSIgal Liberman 		if (list_empty(&dtsec->unicast_addr_hash->lsts[bucket]))
117357ba4c9bSIgal Liberman 			set_bucket(dtsec->regs, bucket, false);
117457ba4c9bSIgal Liberman 	}
117557ba4c9bSIgal Liberman 
117657ba4c9bSIgal Liberman 	/* address does not exist */
117757ba4c9bSIgal Liberman 	WARN_ON(!hash_entry);
117857ba4c9bSIgal Liberman 
117957ba4c9bSIgal Liberman 	return 0;
118057ba4c9bSIgal Liberman }
118157ba4c9bSIgal Liberman 
dtsec_set_promiscuous(struct fman_mac * dtsec,bool new_val)11821257c962SSean Anderson static int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val)
118357ba4c9bSIgal Liberman {
118457ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
118557ba4c9bSIgal Liberman 	u32 tmp;
118657ba4c9bSIgal Liberman 
118757ba4c9bSIgal Liberman 	/* Set unicast promiscuous */
118857ba4c9bSIgal Liberman 	tmp = ioread32be(&regs->rctrl);
118957ba4c9bSIgal Liberman 	if (new_val)
119057ba4c9bSIgal Liberman 		tmp |= RCTRL_UPROM;
119157ba4c9bSIgal Liberman 	else
119257ba4c9bSIgal Liberman 		tmp &= ~RCTRL_UPROM;
119357ba4c9bSIgal Liberman 
119457ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->rctrl);
119557ba4c9bSIgal Liberman 
119657ba4c9bSIgal Liberman 	/* Set multicast promiscuous */
119757ba4c9bSIgal Liberman 	tmp = ioread32be(&regs->rctrl);
119857ba4c9bSIgal Liberman 	if (new_val)
119957ba4c9bSIgal Liberman 		tmp |= RCTRL_MPROM;
120057ba4c9bSIgal Liberman 	else
120157ba4c9bSIgal Liberman 		tmp &= ~RCTRL_MPROM;
120257ba4c9bSIgal Liberman 
120357ba4c9bSIgal Liberman 	iowrite32be(tmp, &regs->rctrl);
120457ba4c9bSIgal Liberman 
120557ba4c9bSIgal Liberman 	return 0;
120657ba4c9bSIgal Liberman }
120757ba4c9bSIgal Liberman 
dtsec_set_exception(struct fman_mac * dtsec,enum fman_mac_exceptions exception,bool enable)12081257c962SSean Anderson static int dtsec_set_exception(struct fman_mac *dtsec,
120957ba4c9bSIgal Liberman 			       enum fman_mac_exceptions exception, bool enable)
121057ba4c9bSIgal Liberman {
121157ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
121257ba4c9bSIgal Liberman 	u32 bit_mask = 0;
121357ba4c9bSIgal Liberman 
121457ba4c9bSIgal Liberman 	if (exception != FM_MAC_EX_1G_1588_TS_RX_ERR) {
121557ba4c9bSIgal Liberman 		bit_mask = get_exception_flag(exception);
121657ba4c9bSIgal Liberman 		if (bit_mask) {
121757ba4c9bSIgal Liberman 			if (enable)
121857ba4c9bSIgal Liberman 				dtsec->exceptions |= bit_mask;
121957ba4c9bSIgal Liberman 			else
122057ba4c9bSIgal Liberman 				dtsec->exceptions &= ~bit_mask;
122157ba4c9bSIgal Liberman 		} else {
122257ba4c9bSIgal Liberman 			pr_err("Undefined exception\n");
122357ba4c9bSIgal Liberman 			return -EINVAL;
122457ba4c9bSIgal Liberman 		}
122557ba4c9bSIgal Liberman 		if (enable)
122657ba4c9bSIgal Liberman 			iowrite32be(ioread32be(&regs->imask) | bit_mask,
122757ba4c9bSIgal Liberman 				    &regs->imask);
122857ba4c9bSIgal Liberman 		else
122957ba4c9bSIgal Liberman 			iowrite32be(ioread32be(&regs->imask) & ~bit_mask,
123057ba4c9bSIgal Liberman 				    &regs->imask);
123157ba4c9bSIgal Liberman 	} else {
123257ba4c9bSIgal Liberman 		if (!dtsec->ptp_tsu_enabled) {
123357ba4c9bSIgal Liberman 			pr_err("Exception valid for 1588 only\n");
123457ba4c9bSIgal Liberman 			return -EINVAL;
123557ba4c9bSIgal Liberman 		}
123657ba4c9bSIgal Liberman 		switch (exception) {
123757ba4c9bSIgal Liberman 		case FM_MAC_EX_1G_1588_TS_RX_ERR:
123857ba4c9bSIgal Liberman 			if (enable) {
1239f74f92beSColin Ian King 				dtsec->en_tsu_err_exception = true;
124057ba4c9bSIgal Liberman 				iowrite32be(ioread32be(&regs->tmr_pemask) |
124157ba4c9bSIgal Liberman 					    TMR_PEMASK_TSREEN,
124257ba4c9bSIgal Liberman 					    &regs->tmr_pemask);
124357ba4c9bSIgal Liberman 			} else {
1244f74f92beSColin Ian King 				dtsec->en_tsu_err_exception = false;
124557ba4c9bSIgal Liberman 				iowrite32be(ioread32be(&regs->tmr_pemask) &
124657ba4c9bSIgal Liberman 					    ~TMR_PEMASK_TSREEN,
124757ba4c9bSIgal Liberman 					    &regs->tmr_pemask);
124857ba4c9bSIgal Liberman 			}
124957ba4c9bSIgal Liberman 			break;
125057ba4c9bSIgal Liberman 		default:
125157ba4c9bSIgal Liberman 			pr_err("Undefined exception\n");
125257ba4c9bSIgal Liberman 			return -EINVAL;
125357ba4c9bSIgal Liberman 		}
125457ba4c9bSIgal Liberman 	}
125557ba4c9bSIgal Liberman 
125657ba4c9bSIgal Liberman 	return 0;
125757ba4c9bSIgal Liberman }
125857ba4c9bSIgal Liberman 
dtsec_init(struct fman_mac * dtsec)12591257c962SSean Anderson static int dtsec_init(struct fman_mac *dtsec)
126057ba4c9bSIgal Liberman {
126157ba4c9bSIgal Liberman 	struct dtsec_regs __iomem *regs = dtsec->regs;
126257ba4c9bSIgal Liberman 	struct dtsec_cfg *dtsec_drv_param;
12635d93cfcfSSean Anderson 	u16 max_frm_ln, tbicon;
12646b995bdeSMadalin Bucur 	int err;
126557ba4c9bSIgal Liberman 
126657ba4c9bSIgal Liberman 	if (DEFAULT_RESET_ON_INIT &&
126757ba4c9bSIgal Liberman 	    (fman_reset_mac(dtsec->fm, dtsec->mac_id) != 0)) {
126857ba4c9bSIgal Liberman 		pr_err("Can't reset MAC!\n");
126957ba4c9bSIgal Liberman 		return -EINVAL;
127057ba4c9bSIgal Liberman 	}
127157ba4c9bSIgal Liberman 
127257ba4c9bSIgal Liberman 	err = check_init_parameters(dtsec);
127357ba4c9bSIgal Liberman 	if (err)
127457ba4c9bSIgal Liberman 		return err;
127557ba4c9bSIgal Liberman 
127657ba4c9bSIgal Liberman 	dtsec_drv_param = dtsec->dtsec_drv_param;
127757ba4c9bSIgal Liberman 
127857ba4c9bSIgal Liberman 	err = init(dtsec->regs, dtsec_drv_param, dtsec->phy_if,
12796b995bdeSMadalin Bucur 		   dtsec->max_speed, dtsec->addr, dtsec->exceptions,
12805d93cfcfSSean Anderson 		   dtsec->tbidev->addr);
128157ba4c9bSIgal Liberman 	if (err) {
128257ba4c9bSIgal Liberman 		free_init_resources(dtsec);
128357ba4c9bSIgal Liberman 		pr_err("DTSEC version doesn't support this i/f mode\n");
128457ba4c9bSIgal Liberman 		return err;
128557ba4c9bSIgal Liberman 	}
128657ba4c9bSIgal Liberman 
128757ba4c9bSIgal Liberman 	/* Configure the TBI PHY Control Register */
12885d93cfcfSSean Anderson 	tbicon = TBICON_CLK_SELECT | TBICON_SOFT_RESET;
12895d93cfcfSSean Anderson 	mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon);
129057ba4c9bSIgal Liberman 
12915d93cfcfSSean Anderson 	tbicon = TBICON_CLK_SELECT;
12925d93cfcfSSean Anderson 	mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon);
129357ba4c9bSIgal Liberman 
129457ba4c9bSIgal Liberman 	/* Max Frame Length */
129557ba4c9bSIgal Liberman 	max_frm_ln = (u16)ioread32be(&regs->maxfrm);
129657ba4c9bSIgal Liberman 	err = fman_set_mac_max_frame(dtsec->fm, dtsec->mac_id, max_frm_ln);
129757ba4c9bSIgal Liberman 	if (err) {
129857ba4c9bSIgal Liberman 		pr_err("Setting max frame length failed\n");
129957ba4c9bSIgal Liberman 		free_init_resources(dtsec);
130057ba4c9bSIgal Liberman 		return -EINVAL;
130157ba4c9bSIgal Liberman 	}
130257ba4c9bSIgal Liberman 
130357ba4c9bSIgal Liberman 	dtsec->multicast_addr_hash =
130457ba4c9bSIgal Liberman 	alloc_hash_table(EXTENDED_HASH_TABLE_SIZE);
130557ba4c9bSIgal Liberman 	if (!dtsec->multicast_addr_hash) {
130657ba4c9bSIgal Liberman 		free_init_resources(dtsec);
130757ba4c9bSIgal Liberman 		pr_err("MC hash table is failed\n");
130857ba4c9bSIgal Liberman 		return -ENOMEM;
130957ba4c9bSIgal Liberman 	}
131057ba4c9bSIgal Liberman 
131157ba4c9bSIgal Liberman 	dtsec->unicast_addr_hash = alloc_hash_table(DTSEC_HASH_TABLE_SIZE);
131257ba4c9bSIgal Liberman 	if (!dtsec->unicast_addr_hash) {
131357ba4c9bSIgal Liberman 		free_init_resources(dtsec);
131457ba4c9bSIgal Liberman 		pr_err("UC hash table is failed\n");
131557ba4c9bSIgal Liberman 		return -ENOMEM;
131657ba4c9bSIgal Liberman 	}
131757ba4c9bSIgal Liberman 
131857ba4c9bSIgal Liberman 	/* register err intr handler for dtsec to FPM (err) */
131957ba4c9bSIgal Liberman 	fman_register_intr(dtsec->fm, FMAN_MOD_MAC, dtsec->mac_id,
132057ba4c9bSIgal Liberman 			   FMAN_INTR_TYPE_ERR, dtsec_isr, dtsec);
132157ba4c9bSIgal Liberman 	/* register 1588 intr handler for TMR to FPM (normal) */
132257ba4c9bSIgal Liberman 	fman_register_intr(dtsec->fm, FMAN_MOD_MAC, dtsec->mac_id,
132357ba4c9bSIgal Liberman 			   FMAN_INTR_TYPE_NORMAL, dtsec_1588_isr, dtsec);
132457ba4c9bSIgal Liberman 
132557ba4c9bSIgal Liberman 	kfree(dtsec_drv_param);
132657ba4c9bSIgal Liberman 	dtsec->dtsec_drv_param = NULL;
132757ba4c9bSIgal Liberman 
132857ba4c9bSIgal Liberman 	return 0;
132957ba4c9bSIgal Liberman }
133057ba4c9bSIgal Liberman 
dtsec_free(struct fman_mac * dtsec)13311257c962SSean Anderson static int dtsec_free(struct fman_mac *dtsec)
133257ba4c9bSIgal Liberman {
133357ba4c9bSIgal Liberman 	free_init_resources(dtsec);
133457ba4c9bSIgal Liberman 
133557ba4c9bSIgal Liberman 	kfree(dtsec->dtsec_drv_param);
133657ba4c9bSIgal Liberman 	dtsec->dtsec_drv_param = NULL;
13375d93cfcfSSean Anderson 	if (!IS_ERR_OR_NULL(dtsec->tbidev))
13385d93cfcfSSean Anderson 		put_device(&dtsec->tbidev->dev);
133957ba4c9bSIgal Liberman 	kfree(dtsec);
134057ba4c9bSIgal Liberman 
134157ba4c9bSIgal Liberman 	return 0;
134257ba4c9bSIgal Liberman }
134357ba4c9bSIgal Liberman 
dtsec_config(struct mac_device * mac_dev,struct fman_mac_params * params)134419c788b1SSean Anderson static struct fman_mac *dtsec_config(struct mac_device *mac_dev,
134519c788b1SSean Anderson 				     struct fman_mac_params *params)
134657ba4c9bSIgal Liberman {
134757ba4c9bSIgal Liberman 	struct fman_mac *dtsec;
134857ba4c9bSIgal Liberman 	struct dtsec_cfg *dtsec_drv_param;
134957ba4c9bSIgal Liberman 
135057ba4c9bSIgal Liberman 	/* allocate memory for the UCC GETH data structure. */
135157ba4c9bSIgal Liberman 	dtsec = kzalloc(sizeof(*dtsec), GFP_KERNEL);
135257ba4c9bSIgal Liberman 	if (!dtsec)
135357ba4c9bSIgal Liberman 		return NULL;
135457ba4c9bSIgal Liberman 
135557ba4c9bSIgal Liberman 	/* allocate memory for the d_tsec driver parameters data structure. */
135657ba4c9bSIgal Liberman 	dtsec_drv_param = kzalloc(sizeof(*dtsec_drv_param), GFP_KERNEL);
135757ba4c9bSIgal Liberman 	if (!dtsec_drv_param)
135857ba4c9bSIgal Liberman 		goto err_dtsec;
135957ba4c9bSIgal Liberman 
136057ba4c9bSIgal Liberman 	/* Plant parameter structure pointer */
136157ba4c9bSIgal Liberman 	dtsec->dtsec_drv_param = dtsec_drv_param;
136257ba4c9bSIgal Liberman 
136357ba4c9bSIgal Liberman 	set_dflts(dtsec_drv_param);
136457ba4c9bSIgal Liberman 
136519c788b1SSean Anderson 	dtsec->regs = mac_dev->vaddr;
136619c788b1SSean Anderson 	dtsec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
136719c788b1SSean Anderson 	dtsec->phy_if = mac_dev->phy_if;
136857ba4c9bSIgal Liberman 	dtsec->mac_id = params->mac_id;
136957ba4c9bSIgal Liberman 	dtsec->exceptions = (DTSEC_IMASK_BREN	|
137057ba4c9bSIgal Liberman 			     DTSEC_IMASK_RXCEN	|
137157ba4c9bSIgal Liberman 			     DTSEC_IMASK_BTEN	|
137257ba4c9bSIgal Liberman 			     DTSEC_IMASK_TXCEN	|
137357ba4c9bSIgal Liberman 			     DTSEC_IMASK_TXEEN	|
137457ba4c9bSIgal Liberman 			     DTSEC_IMASK_ABRTEN	|
137557ba4c9bSIgal Liberman 			     DTSEC_IMASK_LCEN	|
137657ba4c9bSIgal Liberman 			     DTSEC_IMASK_CRLEN	|
137757ba4c9bSIgal Liberman 			     DTSEC_IMASK_XFUNEN	|
137857ba4c9bSIgal Liberman 			     DTSEC_IMASK_IFERREN |
137957ba4c9bSIgal Liberman 			     DTSEC_IMASK_MAGEN	|
138057ba4c9bSIgal Liberman 			     DTSEC_IMASK_TDPEEN	|
138157ba4c9bSIgal Liberman 			     DTSEC_IMASK_RDPEEN);
138257ba4c9bSIgal Liberman 	dtsec->exception_cb = params->exception_cb;
138357ba4c9bSIgal Liberman 	dtsec->event_cb = params->event_cb;
138419c788b1SSean Anderson 	dtsec->dev_id = mac_dev;
138557ba4c9bSIgal Liberman 	dtsec->ptp_tsu_enabled = dtsec->dtsec_drv_param->ptp_tsu_en;
1386f74f92beSColin Ian King 	dtsec->en_tsu_err_exception = dtsec->dtsec_drv_param->ptp_exception_en;
138757ba4c9bSIgal Liberman 
138857ba4c9bSIgal Liberman 	dtsec->fm = params->fm;
138957ba4c9bSIgal Liberman 
139057ba4c9bSIgal Liberman 	/* Save FMan revision */
139157ba4c9bSIgal Liberman 	fman_get_revision(dtsec->fm, &dtsec->fm_rev_info);
139257ba4c9bSIgal Liberman 
139357ba4c9bSIgal Liberman 	return dtsec;
139457ba4c9bSIgal Liberman 
139557ba4c9bSIgal Liberman err_dtsec:
139657ba4c9bSIgal Liberman 	kfree(dtsec);
139757ba4c9bSIgal Liberman 	return NULL;
139857ba4c9bSIgal Liberman }
1399302376feSSean Anderson 
dtsec_initialization(struct mac_device * mac_dev,struct device_node * mac_node,struct fman_mac_params * params)1400302376feSSean Anderson int dtsec_initialization(struct mac_device *mac_dev,
1401c6b7b1b5SSean Anderson 			 struct device_node *mac_node,
1402c6b7b1b5SSean Anderson 			 struct fman_mac_params *params)
1403302376feSSean Anderson {
1404302376feSSean Anderson 	int			err;
140544988627SSean Anderson 	struct fman_mac		*dtsec;
140645fa34bfSSean Anderson 	struct device_node	*phy_node;
14075d93cfcfSSean Anderson 	unsigned long		 capabilities;
14085d93cfcfSSean Anderson 	unsigned long		*supported;
1409302376feSSean Anderson 
14105d93cfcfSSean Anderson 	mac_dev->phylink_ops		= &dtsec_mac_ops;
1411302376feSSean Anderson 	mac_dev->set_promisc		= dtsec_set_promiscuous;
1412302376feSSean Anderson 	mac_dev->change_addr		= dtsec_modify_mac_address;
1413302376feSSean Anderson 	mac_dev->add_hash_mac_addr	= dtsec_add_hash_mac_address;
1414302376feSSean Anderson 	mac_dev->remove_hash_mac_addr	= dtsec_del_hash_mac_address;
1415302376feSSean Anderson 	mac_dev->set_exception		= dtsec_set_exception;
1416302376feSSean Anderson 	mac_dev->set_allmulti		= dtsec_set_allmulti;
1417302376feSSean Anderson 	mac_dev->set_tstamp		= dtsec_set_tstamp;
1418302376feSSean Anderson 	mac_dev->set_multi		= fman_set_multi;
1419302376feSSean Anderson 	mac_dev->enable			= dtsec_enable;
1420302376feSSean Anderson 	mac_dev->disable		= dtsec_disable;
1421302376feSSean Anderson 
142219c788b1SSean Anderson 	mac_dev->fman_mac = dtsec_config(mac_dev, params);
1423302376feSSean Anderson 	if (!mac_dev->fman_mac) {
1424302376feSSean Anderson 		err = -EINVAL;
1425302376feSSean Anderson 		goto _return;
1426302376feSSean Anderson 	}
1427302376feSSean Anderson 
142844988627SSean Anderson 	dtsec = mac_dev->fman_mac;
142944988627SSean Anderson 	dtsec->dtsec_drv_param->maximum_frame = fman_get_max_frm();
143044988627SSean Anderson 	dtsec->dtsec_drv_param->tx_pad_crc = true;
143145fa34bfSSean Anderson 
143245fa34bfSSean Anderson 	phy_node = of_parse_phandle(mac_node, "tbi-handle", 0);
14337dc61838SSean Anderson 	if (!phy_node || !of_device_is_available(phy_node)) {
14345d93cfcfSSean Anderson 		of_node_put(phy_node);
143545fa34bfSSean Anderson 		err = -EINVAL;
14365d93cfcfSSean Anderson 		dev_err_probe(mac_dev->dev, err,
14375d93cfcfSSean Anderson 			      "TBI PCS node is not available\n");
143845fa34bfSSean Anderson 		goto _return_fm_mac_free;
143945fa34bfSSean Anderson 	}
144045fa34bfSSean Anderson 
14415d93cfcfSSean Anderson 	dtsec->tbidev = of_mdio_find_device(phy_node);
14425d93cfcfSSean Anderson 	of_node_put(phy_node);
14435d93cfcfSSean Anderson 	if (!dtsec->tbidev) {
14445d93cfcfSSean Anderson 		err = -EPROBE_DEFER;
14455d93cfcfSSean Anderson 		dev_err_probe(mac_dev->dev, err,
14465d93cfcfSSean Anderson 			      "could not find mdiodev for PCS\n");
144745fa34bfSSean Anderson 		goto _return_fm_mac_free;
144845fa34bfSSean Anderson 	}
14495d93cfcfSSean Anderson 	dtsec->pcs.ops = &dtsec_pcs_ops;
1450*febf2aafSRussell King (Oracle) 	dtsec->pcs.neg_mode = true;
14515d93cfcfSSean Anderson 	dtsec->pcs.poll = true;
14525d93cfcfSSean Anderson 
14535d93cfcfSSean Anderson 	supported = mac_dev->phylink_config.supported_interfaces;
14545d93cfcfSSean Anderson 
14555d93cfcfSSean Anderson 	/* FIXME: Can we use DTSEC_ID2_INT_FULL_OFF to determine if these are
14565d93cfcfSSean Anderson 	 * supported? If not, we can determine support via the phy if SerDes
14575d93cfcfSSean Anderson 	 * support is added.
14585d93cfcfSSean Anderson 	 */
14595d93cfcfSSean Anderson 	if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII ||
14605d93cfcfSSean Anderson 	    mac_dev->phy_if == PHY_INTERFACE_MODE_1000BASEX) {
14615d93cfcfSSean Anderson 		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
14625d93cfcfSSean Anderson 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
14635d93cfcfSSean Anderson 	} else if (mac_dev->phy_if == PHY_INTERFACE_MODE_2500BASEX) {
14645d93cfcfSSean Anderson 		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
14655d93cfcfSSean Anderson 	}
14665d93cfcfSSean Anderson 
14675d93cfcfSSean Anderson 	if (!(ioread32be(&dtsec->regs->tsec_id2) & DTSEC_ID2_INT_REDUCED_OFF)) {
14685d93cfcfSSean Anderson 		phy_interface_set_rgmii(supported);
14695d93cfcfSSean Anderson 
14705d93cfcfSSean Anderson 		/* DTSEC_ID2_INT_REDUCED_OFF indicates that the dTSEC supports
14715d93cfcfSSean Anderson 		 * RMII and RGMII. However, the only SoCs which support RMII
14725d93cfcfSSean Anderson 		 * are the P1017 and P1023. Avoid advertising this mode on
14735d93cfcfSSean Anderson 		 * other SoCs. This is a bit of a moot point, since there's no
14745d93cfcfSSean Anderson 		 * in-tree support for ethernet on these platforms...
14755d93cfcfSSean Anderson 		 */
14765d93cfcfSSean Anderson 		if (of_machine_is_compatible("fsl,P1023") ||
14775d93cfcfSSean Anderson 		    of_machine_is_compatible("fsl,P1023RDB"))
14785d93cfcfSSean Anderson 			__set_bit(PHY_INTERFACE_MODE_RMII, supported);
14795d93cfcfSSean Anderson 	}
14805d93cfcfSSean Anderson 
14815d93cfcfSSean Anderson 	capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
14825d93cfcfSSean Anderson 	capabilities |= MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD;
14835d93cfcfSSean Anderson 	mac_dev->phylink_config.mac_capabilities = capabilities;
148445fa34bfSSean Anderson 
148544988627SSean Anderson 	err = dtsec_init(dtsec);
1486302376feSSean Anderson 	if (err < 0)
1487302376feSSean Anderson 		goto _return_fm_mac_free;
1488302376feSSean Anderson 
1489302376feSSean Anderson 	/* For 1G MAC, disable by default the MIB counters overflow interrupt */
149044988627SSean Anderson 	err = dtsec_set_exception(dtsec, FM_MAC_EX_1G_RX_MIB_CNT_OVFL, false);
1491302376feSSean Anderson 	if (err < 0)
1492302376feSSean Anderson 		goto _return_fm_mac_free;
1493302376feSSean Anderson 
149444988627SSean Anderson 	dev_info(mac_dev->dev, "FMan dTSEC version: 0x%08x\n",
149544988627SSean Anderson 		 ioread32be(&dtsec->regs->tsec_id));
1496302376feSSean Anderson 
1497302376feSSean Anderson 	goto _return;
1498302376feSSean Anderson 
1499302376feSSean Anderson _return_fm_mac_free:
150044988627SSean Anderson 	dtsec_free(dtsec);
1501302376feSSean Anderson 
1502302376feSSean Anderson _return:
1503302376feSSean Anderson 	return err;
1504302376feSSean Anderson }
1505