16f8d3f33SWingman Kwok /*
290cff9e2SWingman Kwok  * Keystone GBE and XGBE subsystem code
36f8d3f33SWingman Kwok  *
46f8d3f33SWingman Kwok  * Copyright (C) 2014 Texas Instruments Incorporated
56f8d3f33SWingman Kwok  * Authors:	Sandeep Nair <sandeep_n@ti.com>
66f8d3f33SWingman Kwok  *		Sandeep Paulraj <s-paulraj@ti.com>
76f8d3f33SWingman Kwok  *		Cyril Chemparathy <cyril@ti.com>
86f8d3f33SWingman Kwok  *		Santosh Shilimkar <santosh.shilimkar@ti.com>
96f8d3f33SWingman Kwok  *		Wingman Kwok <w-kwok2@ti.com>
106f8d3f33SWingman Kwok  *
116f8d3f33SWingman Kwok  * This program is free software; you can redistribute it and/or
126f8d3f33SWingman Kwok  * modify it under the terms of the GNU General Public License as
136f8d3f33SWingman Kwok  * published by the Free Software Foundation version 2.
146f8d3f33SWingman Kwok  *
156f8d3f33SWingman Kwok  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
166f8d3f33SWingman Kwok  * kind, whether express or implied; without even the implied warranty
176f8d3f33SWingman Kwok  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
186f8d3f33SWingman Kwok  * GNU General Public License for more details.
196f8d3f33SWingman Kwok  */
206f8d3f33SWingman Kwok 
216f8d3f33SWingman Kwok #include <linux/io.h>
226f8d3f33SWingman Kwok #include <linux/of_mdio.h>
236f8d3f33SWingman Kwok #include <linux/of_address.h>
246f8d3f33SWingman Kwok #include <linux/if_vlan.h>
256f8d3f33SWingman Kwok #include <linux/ethtool.h>
266f8d3f33SWingman Kwok 
276f8d3f33SWingman Kwok #include "cpsw_ale.h"
286f8d3f33SWingman Kwok #include "netcp.h"
296f8d3f33SWingman Kwok 
306f8d3f33SWingman Kwok #define NETCP_DRIVER_NAME		"TI KeyStone Ethernet Driver"
316f8d3f33SWingman Kwok #define NETCP_DRIVER_VERSION		"v1.0"
326f8d3f33SWingman Kwok 
336f8d3f33SWingman Kwok #define GBE_IDENT(reg)			((reg >> 16) & 0xffff)
346f8d3f33SWingman Kwok #define GBE_MAJOR_VERSION(reg)		(reg >> 8 & 0x7)
356f8d3f33SWingman Kwok #define GBE_MINOR_VERSION(reg)		(reg & 0xff)
366f8d3f33SWingman Kwok #define GBE_RTL_VERSION(reg)		((reg >> 11) & 0x1f)
376f8d3f33SWingman Kwok 
386f8d3f33SWingman Kwok /* 1G Ethernet SS defines */
396f8d3f33SWingman Kwok #define GBE_MODULE_NAME			"netcp-gbe"
406f8d3f33SWingman Kwok #define GBE_SS_VERSION_14		0x4ed21104
416f8d3f33SWingman Kwok 
426f8d3f33SWingman Kwok #define GBE13_SGMII_MODULE_OFFSET	0x100
436f8d3f33SWingman Kwok #define GBE13_SGMII34_MODULE_OFFSET	0x400
446f8d3f33SWingman Kwok #define GBE13_SWITCH_MODULE_OFFSET	0x800
456f8d3f33SWingman Kwok #define GBE13_HOST_PORT_OFFSET		0x834
466f8d3f33SWingman Kwok #define GBE13_SLAVE_PORT_OFFSET		0x860
476f8d3f33SWingman Kwok #define GBE13_EMAC_OFFSET		0x900
486f8d3f33SWingman Kwok #define GBE13_SLAVE_PORT2_OFFSET	0xa00
496f8d3f33SWingman Kwok #define GBE13_HW_STATS_OFFSET		0xb00
506f8d3f33SWingman Kwok #define GBE13_ALE_OFFSET		0xe00
516f8d3f33SWingman Kwok #define GBE13_HOST_PORT_NUM		0
526f8d3f33SWingman Kwok #define GBE13_NUM_SLAVES		4
536f8d3f33SWingman Kwok #define GBE13_NUM_ALE_PORTS		(GBE13_NUM_SLAVES + 1)
546f8d3f33SWingman Kwok #define GBE13_NUM_ALE_ENTRIES		1024
556f8d3f33SWingman Kwok 
5690cff9e2SWingman Kwok /* 10G Ethernet SS defines */
5790cff9e2SWingman Kwok #define XGBE_MODULE_NAME		"netcp-xgbe"
5890cff9e2SWingman Kwok #define XGBE_SS_VERSION_10		0x4ee42100
5990cff9e2SWingman Kwok 
6090cff9e2SWingman Kwok #define XGBE_SERDES_REG_INDEX		1
6190cff9e2SWingman Kwok #define XGBE10_SGMII_MODULE_OFFSET	0x100
6290cff9e2SWingman Kwok #define XGBE10_SWITCH_MODULE_OFFSET	0x1000
6390cff9e2SWingman Kwok #define XGBE10_HOST_PORT_OFFSET		0x1034
6490cff9e2SWingman Kwok #define XGBE10_SLAVE_PORT_OFFSET	0x1064
6590cff9e2SWingman Kwok #define XGBE10_EMAC_OFFSET		0x1400
6690cff9e2SWingman Kwok #define XGBE10_ALE_OFFSET		0x1700
6790cff9e2SWingman Kwok #define XGBE10_HW_STATS_OFFSET		0x1800
6890cff9e2SWingman Kwok #define XGBE10_HOST_PORT_NUM		0
6990cff9e2SWingman Kwok #define XGBE10_NUM_SLAVES		2
7090cff9e2SWingman Kwok #define XGBE10_NUM_ALE_PORTS		(XGBE10_NUM_SLAVES + 1)
7190cff9e2SWingman Kwok #define XGBE10_NUM_ALE_ENTRIES		1024
7290cff9e2SWingman Kwok 
736f8d3f33SWingman Kwok #define	GBE_TIMER_INTERVAL			(HZ / 2)
746f8d3f33SWingman Kwok 
756f8d3f33SWingman Kwok /* Soft reset register values */
766f8d3f33SWingman Kwok #define SOFT_RESET_MASK				BIT(0)
776f8d3f33SWingman Kwok #define SOFT_RESET				BIT(0)
786f8d3f33SWingman Kwok #define DEVICE_EMACSL_RESET_POLL_COUNT		100
796f8d3f33SWingman Kwok #define GMACSL_RET_WARN_RESET_INCOMPLETE	-2
806f8d3f33SWingman Kwok 
816f8d3f33SWingman Kwok #define MACSL_RX_ENABLE_CSF			BIT(23)
826f8d3f33SWingman Kwok #define MACSL_ENABLE_EXT_CTL			BIT(18)
8390cff9e2SWingman Kwok #define MACSL_XGMII_ENABLE			BIT(13)
8490cff9e2SWingman Kwok #define MACSL_XGIG_MODE				BIT(8)
856f8d3f33SWingman Kwok #define MACSL_GIG_MODE				BIT(7)
866f8d3f33SWingman Kwok #define MACSL_GMII_ENABLE			BIT(5)
876f8d3f33SWingman Kwok #define MACSL_FULLDUPLEX			BIT(0)
886f8d3f33SWingman Kwok 
896f8d3f33SWingman Kwok #define GBE_CTL_P0_ENABLE			BIT(2)
906f8d3f33SWingman Kwok #define GBE_REG_VAL_STAT_ENABLE_ALL		0xff
9190cff9e2SWingman Kwok #define XGBE_REG_VAL_STAT_ENABLE_ALL		0xf
926f8d3f33SWingman Kwok #define GBE_STATS_CD_SEL			BIT(28)
936f8d3f33SWingman Kwok 
946f8d3f33SWingman Kwok #define GBE_PORT_MASK(x)			(BIT(x) - 1)
956f8d3f33SWingman Kwok #define GBE_MASK_NO_PORTS			0
966f8d3f33SWingman Kwok 
976f8d3f33SWingman Kwok #define GBE_DEF_1G_MAC_CONTROL					\
986f8d3f33SWingman Kwok 		(MACSL_GIG_MODE | MACSL_GMII_ENABLE |		\
996f8d3f33SWingman Kwok 		 MACSL_ENABLE_EXT_CTL |	MACSL_RX_ENABLE_CSF)
1006f8d3f33SWingman Kwok 
10190cff9e2SWingman Kwok #define GBE_DEF_10G_MAC_CONTROL				\
10290cff9e2SWingman Kwok 		(MACSL_XGIG_MODE | MACSL_XGMII_ENABLE |		\
10390cff9e2SWingman Kwok 		 MACSL_ENABLE_EXT_CTL |	MACSL_RX_ENABLE_CSF)
10490cff9e2SWingman Kwok 
1056f8d3f33SWingman Kwok #define GBE_STATSA_MODULE			0
1066f8d3f33SWingman Kwok #define GBE_STATSB_MODULE			1
1076f8d3f33SWingman Kwok #define GBE_STATSC_MODULE			2
1086f8d3f33SWingman Kwok #define GBE_STATSD_MODULE			3
1096f8d3f33SWingman Kwok 
11090cff9e2SWingman Kwok #define XGBE_STATS0_MODULE			0
11190cff9e2SWingman Kwok #define XGBE_STATS1_MODULE			1
11290cff9e2SWingman Kwok #define XGBE_STATS2_MODULE			2
11390cff9e2SWingman Kwok 
1146f8d3f33SWingman Kwok #define MAX_SLAVES				GBE13_NUM_SLAVES
1156f8d3f33SWingman Kwok /* s: 0-based slave_port */
1166f8d3f33SWingman Kwok #define SGMII_BASE(s) \
1176f8d3f33SWingman Kwok 	(((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs)
1186f8d3f33SWingman Kwok 
1196f8d3f33SWingman Kwok #define GBE_TX_QUEUE				648
1206f8d3f33SWingman Kwok #define	GBE_TXHOOK_ORDER			0
1216f8d3f33SWingman Kwok #define GBE_DEFAULT_ALE_AGEOUT			30
12290cff9e2SWingman Kwok #define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY)
1236f8d3f33SWingman Kwok #define NETCP_LINK_STATE_INVALID		-1
1246f8d3f33SWingman Kwok 
1256f8d3f33SWingman Kwok #define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \
1266f8d3f33SWingman Kwok 		offsetof(struct gbe##_##rb, rn)
12790cff9e2SWingman Kwok #define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \
12890cff9e2SWingman Kwok 		offsetof(struct xgbe##_##rb, rn)
1296f8d3f33SWingman Kwok #define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn)
1306f8d3f33SWingman Kwok 
13190cff9e2SWingman Kwok struct xgbe_ss_regs {
13290cff9e2SWingman Kwok 	u32	id_ver;
13390cff9e2SWingman Kwok 	u32	synce_count;
13490cff9e2SWingman Kwok 	u32	synce_mux;
13590cff9e2SWingman Kwok 	u32	control;
13690cff9e2SWingman Kwok };
13790cff9e2SWingman Kwok 
13890cff9e2SWingman Kwok struct xgbe_switch_regs {
13990cff9e2SWingman Kwok 	u32	id_ver;
14090cff9e2SWingman Kwok 	u32	control;
14190cff9e2SWingman Kwok 	u32	emcontrol;
14290cff9e2SWingman Kwok 	u32	stat_port_en;
14390cff9e2SWingman Kwok 	u32	ptype;
14490cff9e2SWingman Kwok 	u32	soft_idle;
14590cff9e2SWingman Kwok 	u32	thru_rate;
14690cff9e2SWingman Kwok 	u32	gap_thresh;
14790cff9e2SWingman Kwok 	u32	tx_start_wds;
14890cff9e2SWingman Kwok 	u32	flow_control;
14990cff9e2SWingman Kwok 	u32	cppi_thresh;
15090cff9e2SWingman Kwok };
15190cff9e2SWingman Kwok 
15290cff9e2SWingman Kwok struct xgbe_port_regs {
15390cff9e2SWingman Kwok 	u32	blk_cnt;
15490cff9e2SWingman Kwok 	u32	port_vlan;
15590cff9e2SWingman Kwok 	u32	tx_pri_map;
15690cff9e2SWingman Kwok 	u32	sa_lo;
15790cff9e2SWingman Kwok 	u32	sa_hi;
15890cff9e2SWingman Kwok 	u32	ts_ctl;
15990cff9e2SWingman Kwok 	u32	ts_seq_ltype;
16090cff9e2SWingman Kwok 	u32	ts_vlan;
16190cff9e2SWingman Kwok 	u32	ts_ctl_ltype2;
16290cff9e2SWingman Kwok 	u32	ts_ctl2;
16390cff9e2SWingman Kwok 	u32	control;
16490cff9e2SWingman Kwok };
16590cff9e2SWingman Kwok 
16690cff9e2SWingman Kwok struct xgbe_host_port_regs {
16790cff9e2SWingman Kwok 	u32	blk_cnt;
16890cff9e2SWingman Kwok 	u32	port_vlan;
16990cff9e2SWingman Kwok 	u32	tx_pri_map;
17090cff9e2SWingman Kwok 	u32	src_id;
17190cff9e2SWingman Kwok 	u32	rx_pri_map;
17290cff9e2SWingman Kwok 	u32	rx_maxlen;
17390cff9e2SWingman Kwok };
17490cff9e2SWingman Kwok 
17590cff9e2SWingman Kwok struct xgbe_emac_regs {
17690cff9e2SWingman Kwok 	u32	id_ver;
17790cff9e2SWingman Kwok 	u32	mac_control;
17890cff9e2SWingman Kwok 	u32	mac_status;
17990cff9e2SWingman Kwok 	u32	soft_reset;
18090cff9e2SWingman Kwok 	u32	rx_maxlen;
18190cff9e2SWingman Kwok 	u32	__reserved_0;
18290cff9e2SWingman Kwok 	u32	rx_pause;
18390cff9e2SWingman Kwok 	u32	tx_pause;
18490cff9e2SWingman Kwok 	u32	em_control;
18590cff9e2SWingman Kwok 	u32	__reserved_1;
18690cff9e2SWingman Kwok 	u32	tx_gap;
18790cff9e2SWingman Kwok 	u32	rsvd[4];
18890cff9e2SWingman Kwok };
18990cff9e2SWingman Kwok 
19090cff9e2SWingman Kwok struct xgbe_host_hw_stats {
19190cff9e2SWingman Kwok 	u32	rx_good_frames;
19290cff9e2SWingman Kwok 	u32	rx_broadcast_frames;
19390cff9e2SWingman Kwok 	u32	rx_multicast_frames;
19490cff9e2SWingman Kwok 	u32	__rsvd_0[3];
19590cff9e2SWingman Kwok 	u32	rx_oversized_frames;
19690cff9e2SWingman Kwok 	u32	__rsvd_1;
19790cff9e2SWingman Kwok 	u32	rx_undersized_frames;
19890cff9e2SWingman Kwok 	u32	__rsvd_2;
19990cff9e2SWingman Kwok 	u32	overrun_type4;
20090cff9e2SWingman Kwok 	u32	overrun_type5;
20190cff9e2SWingman Kwok 	u32	rx_bytes;
20290cff9e2SWingman Kwok 	u32	tx_good_frames;
20390cff9e2SWingman Kwok 	u32	tx_broadcast_frames;
20490cff9e2SWingman Kwok 	u32	tx_multicast_frames;
20590cff9e2SWingman Kwok 	u32	__rsvd_3[9];
20690cff9e2SWingman Kwok 	u32	tx_bytes;
20790cff9e2SWingman Kwok 	u32	tx_64byte_frames;
20890cff9e2SWingman Kwok 	u32	tx_65_to_127byte_frames;
20990cff9e2SWingman Kwok 	u32	tx_128_to_255byte_frames;
21090cff9e2SWingman Kwok 	u32	tx_256_to_511byte_frames;
21190cff9e2SWingman Kwok 	u32	tx_512_to_1023byte_frames;
21290cff9e2SWingman Kwok 	u32	tx_1024byte_frames;
21390cff9e2SWingman Kwok 	u32	net_bytes;
21490cff9e2SWingman Kwok 	u32	rx_sof_overruns;
21590cff9e2SWingman Kwok 	u32	rx_mof_overruns;
21690cff9e2SWingman Kwok 	u32	rx_dma_overruns;
21790cff9e2SWingman Kwok };
21890cff9e2SWingman Kwok 
21990cff9e2SWingman Kwok struct xgbe_hw_stats {
22090cff9e2SWingman Kwok 	u32	rx_good_frames;
22190cff9e2SWingman Kwok 	u32	rx_broadcast_frames;
22290cff9e2SWingman Kwok 	u32	rx_multicast_frames;
22390cff9e2SWingman Kwok 	u32	rx_pause_frames;
22490cff9e2SWingman Kwok 	u32	rx_crc_errors;
22590cff9e2SWingman Kwok 	u32	rx_align_code_errors;
22690cff9e2SWingman Kwok 	u32	rx_oversized_frames;
22790cff9e2SWingman Kwok 	u32	rx_jabber_frames;
22890cff9e2SWingman Kwok 	u32	rx_undersized_frames;
22990cff9e2SWingman Kwok 	u32	rx_fragments;
23090cff9e2SWingman Kwok 	u32	overrun_type4;
23190cff9e2SWingman Kwok 	u32	overrun_type5;
23290cff9e2SWingman Kwok 	u32	rx_bytes;
23390cff9e2SWingman Kwok 	u32	tx_good_frames;
23490cff9e2SWingman Kwok 	u32	tx_broadcast_frames;
23590cff9e2SWingman Kwok 	u32	tx_multicast_frames;
23690cff9e2SWingman Kwok 	u32	tx_pause_frames;
23790cff9e2SWingman Kwok 	u32	tx_deferred_frames;
23890cff9e2SWingman Kwok 	u32	tx_collision_frames;
23990cff9e2SWingman Kwok 	u32	tx_single_coll_frames;
24090cff9e2SWingman Kwok 	u32	tx_mult_coll_frames;
24190cff9e2SWingman Kwok 	u32	tx_excessive_collisions;
24290cff9e2SWingman Kwok 	u32	tx_late_collisions;
24390cff9e2SWingman Kwok 	u32	tx_underrun;
24490cff9e2SWingman Kwok 	u32	tx_carrier_sense_errors;
24590cff9e2SWingman Kwok 	u32	tx_bytes;
24690cff9e2SWingman Kwok 	u32	tx_64byte_frames;
24790cff9e2SWingman Kwok 	u32	tx_65_to_127byte_frames;
24890cff9e2SWingman Kwok 	u32	tx_128_to_255byte_frames;
24990cff9e2SWingman Kwok 	u32	tx_256_to_511byte_frames;
25090cff9e2SWingman Kwok 	u32	tx_512_to_1023byte_frames;
25190cff9e2SWingman Kwok 	u32	tx_1024byte_frames;
25290cff9e2SWingman Kwok 	u32	net_bytes;
25390cff9e2SWingman Kwok 	u32	rx_sof_overruns;
25490cff9e2SWingman Kwok 	u32	rx_mof_overruns;
25590cff9e2SWingman Kwok 	u32	rx_dma_overruns;
25690cff9e2SWingman Kwok };
25790cff9e2SWingman Kwok 
25890cff9e2SWingman Kwok #define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32))
25990cff9e2SWingman Kwok 
2606f8d3f33SWingman Kwok struct gbe_ss_regs {
2616f8d3f33SWingman Kwok 	u32	id_ver;
2626f8d3f33SWingman Kwok 	u32	synce_count;
2636f8d3f33SWingman Kwok 	u32	synce_mux;
2646f8d3f33SWingman Kwok };
2656f8d3f33SWingman Kwok 
2666f8d3f33SWingman Kwok struct gbe_ss_regs_ofs {
2676f8d3f33SWingman Kwok 	u16	id_ver;
2686f8d3f33SWingman Kwok 	u16	control;
2696f8d3f33SWingman Kwok };
2706f8d3f33SWingman Kwok 
2716f8d3f33SWingman Kwok struct gbe_switch_regs {
2726f8d3f33SWingman Kwok 	u32	id_ver;
2736f8d3f33SWingman Kwok 	u32	control;
2746f8d3f33SWingman Kwok 	u32	soft_reset;
2756f8d3f33SWingman Kwok 	u32	stat_port_en;
2766f8d3f33SWingman Kwok 	u32	ptype;
2776f8d3f33SWingman Kwok 	u32	soft_idle;
2786f8d3f33SWingman Kwok 	u32	thru_rate;
2796f8d3f33SWingman Kwok 	u32	gap_thresh;
2806f8d3f33SWingman Kwok 	u32	tx_start_wds;
2816f8d3f33SWingman Kwok 	u32	flow_control;
2826f8d3f33SWingman Kwok };
2836f8d3f33SWingman Kwok 
2846f8d3f33SWingman Kwok struct gbe_switch_regs_ofs {
2856f8d3f33SWingman Kwok 	u16	id_ver;
2866f8d3f33SWingman Kwok 	u16	control;
2876f8d3f33SWingman Kwok 	u16	soft_reset;
2886f8d3f33SWingman Kwok 	u16	emcontrol;
2896f8d3f33SWingman Kwok 	u16	stat_port_en;
2906f8d3f33SWingman Kwok 	u16	ptype;
2916f8d3f33SWingman Kwok 	u16	flow_control;
2926f8d3f33SWingman Kwok };
2936f8d3f33SWingman Kwok 
2946f8d3f33SWingman Kwok struct gbe_port_regs {
2956f8d3f33SWingman Kwok 	u32	max_blks;
2966f8d3f33SWingman Kwok 	u32	blk_cnt;
2976f8d3f33SWingman Kwok 	u32	port_vlan;
2986f8d3f33SWingman Kwok 	u32	tx_pri_map;
2996f8d3f33SWingman Kwok 	u32	sa_lo;
3006f8d3f33SWingman Kwok 	u32	sa_hi;
3016f8d3f33SWingman Kwok 	u32	ts_ctl;
3026f8d3f33SWingman Kwok 	u32	ts_seq_ltype;
3036f8d3f33SWingman Kwok 	u32	ts_vlan;
3046f8d3f33SWingman Kwok 	u32	ts_ctl_ltype2;
3056f8d3f33SWingman Kwok 	u32	ts_ctl2;
3066f8d3f33SWingman Kwok };
3076f8d3f33SWingman Kwok 
3086f8d3f33SWingman Kwok struct gbe_port_regs_ofs {
3096f8d3f33SWingman Kwok 	u16	port_vlan;
3106f8d3f33SWingman Kwok 	u16	tx_pri_map;
3116f8d3f33SWingman Kwok 	u16	sa_lo;
3126f8d3f33SWingman Kwok 	u16	sa_hi;
3136f8d3f33SWingman Kwok 	u16	ts_ctl;
3146f8d3f33SWingman Kwok 	u16	ts_seq_ltype;
3156f8d3f33SWingman Kwok 	u16	ts_vlan;
3166f8d3f33SWingman Kwok 	u16	ts_ctl_ltype2;
3176f8d3f33SWingman Kwok 	u16	ts_ctl2;
3186f8d3f33SWingman Kwok };
3196f8d3f33SWingman Kwok 
3206f8d3f33SWingman Kwok struct gbe_host_port_regs {
3216f8d3f33SWingman Kwok 	u32	src_id;
3226f8d3f33SWingman Kwok 	u32	port_vlan;
3236f8d3f33SWingman Kwok 	u32	rx_pri_map;
3246f8d3f33SWingman Kwok 	u32	rx_maxlen;
3256f8d3f33SWingman Kwok };
3266f8d3f33SWingman Kwok 
3276f8d3f33SWingman Kwok struct gbe_host_port_regs_ofs {
3286f8d3f33SWingman Kwok 	u16	port_vlan;
3296f8d3f33SWingman Kwok 	u16	tx_pri_map;
3306f8d3f33SWingman Kwok 	u16	rx_maxlen;
3316f8d3f33SWingman Kwok };
3326f8d3f33SWingman Kwok 
3336f8d3f33SWingman Kwok struct gbe_emac_regs {
3346f8d3f33SWingman Kwok 	u32	id_ver;
3356f8d3f33SWingman Kwok 	u32	mac_control;
3366f8d3f33SWingman Kwok 	u32	mac_status;
3376f8d3f33SWingman Kwok 	u32	soft_reset;
3386f8d3f33SWingman Kwok 	u32	rx_maxlen;
3396f8d3f33SWingman Kwok 	u32	__reserved_0;
3406f8d3f33SWingman Kwok 	u32	rx_pause;
3416f8d3f33SWingman Kwok 	u32	tx_pause;
3426f8d3f33SWingman Kwok 	u32	__reserved_1;
3436f8d3f33SWingman Kwok 	u32	rx_pri_map;
3446f8d3f33SWingman Kwok 	u32	rsvd[6];
3456f8d3f33SWingman Kwok };
3466f8d3f33SWingman Kwok 
3476f8d3f33SWingman Kwok struct gbe_emac_regs_ofs {
3486f8d3f33SWingman Kwok 	u16	mac_control;
3496f8d3f33SWingman Kwok 	u16	soft_reset;
3506f8d3f33SWingman Kwok 	u16	rx_maxlen;
3516f8d3f33SWingman Kwok };
3526f8d3f33SWingman Kwok 
3536f8d3f33SWingman Kwok struct gbe_hw_stats {
3546f8d3f33SWingman Kwok 	u32	rx_good_frames;
3556f8d3f33SWingman Kwok 	u32	rx_broadcast_frames;
3566f8d3f33SWingman Kwok 	u32	rx_multicast_frames;
3576f8d3f33SWingman Kwok 	u32	rx_pause_frames;
3586f8d3f33SWingman Kwok 	u32	rx_crc_errors;
3596f8d3f33SWingman Kwok 	u32	rx_align_code_errors;
3606f8d3f33SWingman Kwok 	u32	rx_oversized_frames;
3616f8d3f33SWingman Kwok 	u32	rx_jabber_frames;
3626f8d3f33SWingman Kwok 	u32	rx_undersized_frames;
3636f8d3f33SWingman Kwok 	u32	rx_fragments;
3646f8d3f33SWingman Kwok 	u32	__pad_0[2];
3656f8d3f33SWingman Kwok 	u32	rx_bytes;
3666f8d3f33SWingman Kwok 	u32	tx_good_frames;
3676f8d3f33SWingman Kwok 	u32	tx_broadcast_frames;
3686f8d3f33SWingman Kwok 	u32	tx_multicast_frames;
3696f8d3f33SWingman Kwok 	u32	tx_pause_frames;
3706f8d3f33SWingman Kwok 	u32	tx_deferred_frames;
3716f8d3f33SWingman Kwok 	u32	tx_collision_frames;
3726f8d3f33SWingman Kwok 	u32	tx_single_coll_frames;
3736f8d3f33SWingman Kwok 	u32	tx_mult_coll_frames;
3746f8d3f33SWingman Kwok 	u32	tx_excessive_collisions;
3756f8d3f33SWingman Kwok 	u32	tx_late_collisions;
3766f8d3f33SWingman Kwok 	u32	tx_underrun;
3776f8d3f33SWingman Kwok 	u32	tx_carrier_sense_errors;
3786f8d3f33SWingman Kwok 	u32	tx_bytes;
3796f8d3f33SWingman Kwok 	u32	tx_64byte_frames;
3806f8d3f33SWingman Kwok 	u32	tx_65_to_127byte_frames;
3816f8d3f33SWingman Kwok 	u32	tx_128_to_255byte_frames;
3826f8d3f33SWingman Kwok 	u32	tx_256_to_511byte_frames;
3836f8d3f33SWingman Kwok 	u32	tx_512_to_1023byte_frames;
3846f8d3f33SWingman Kwok 	u32	tx_1024byte_frames;
3856f8d3f33SWingman Kwok 	u32	net_bytes;
3866f8d3f33SWingman Kwok 	u32	rx_sof_overruns;
3876f8d3f33SWingman Kwok 	u32	rx_mof_overruns;
3886f8d3f33SWingman Kwok 	u32	rx_dma_overruns;
3896f8d3f33SWingman Kwok };
3906f8d3f33SWingman Kwok 
3916f8d3f33SWingman Kwok #define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32))
3926f8d3f33SWingman Kwok #define GBE13_NUM_HW_STATS_MOD			2
39390cff9e2SWingman Kwok #define XGBE10_NUM_HW_STATS_MOD			3
3946f8d3f33SWingman Kwok #define GBE_MAX_HW_STAT_MODS			3
3956f8d3f33SWingman Kwok #define GBE_HW_STATS_REG_MAP_SZ			0x100
3966f8d3f33SWingman Kwok 
3976f8d3f33SWingman Kwok struct gbe_slave {
3986f8d3f33SWingman Kwok 	void __iomem			*port_regs;
3996f8d3f33SWingman Kwok 	void __iomem			*emac_regs;
4006f8d3f33SWingman Kwok 	struct gbe_port_regs_ofs	port_regs_ofs;
4016f8d3f33SWingman Kwok 	struct gbe_emac_regs_ofs	emac_regs_ofs;
4026f8d3f33SWingman Kwok 	int				slave_num; /* 0 based logical number */
4036f8d3f33SWingman Kwok 	int				port_num;  /* actual port number */
4046f8d3f33SWingman Kwok 	atomic_t			link_state;
4056f8d3f33SWingman Kwok 	bool				open;
4066f8d3f33SWingman Kwok 	struct phy_device		*phy;
4076f8d3f33SWingman Kwok 	u32				link_interface;
4086f8d3f33SWingman Kwok 	u32				mac_control;
4096f8d3f33SWingman Kwok 	u8				phy_port_t;
4106f8d3f33SWingman Kwok 	struct device_node		*phy_node;
4116f8d3f33SWingman Kwok 	struct list_head		slave_list;
4126f8d3f33SWingman Kwok };
4136f8d3f33SWingman Kwok 
4146f8d3f33SWingman Kwok struct gbe_priv {
4156f8d3f33SWingman Kwok 	struct device			*dev;
4166f8d3f33SWingman Kwok 	struct netcp_device		*netcp_device;
4176f8d3f33SWingman Kwok 	struct timer_list		timer;
4186f8d3f33SWingman Kwok 	u32				num_slaves;
4196f8d3f33SWingman Kwok 	u32				ale_entries;
4206f8d3f33SWingman Kwok 	u32				ale_ports;
4216f8d3f33SWingman Kwok 	bool				enable_ale;
4226f8d3f33SWingman Kwok 	struct netcp_tx_pipe		tx_pipe;
4236f8d3f33SWingman Kwok 
4246f8d3f33SWingman Kwok 	int				host_port;
4256f8d3f33SWingman Kwok 	u32				rx_packet_max;
4266f8d3f33SWingman Kwok 	u32				ss_version;
4276f8d3f33SWingman Kwok 
4286f8d3f33SWingman Kwok 	void __iomem			*ss_regs;
4296f8d3f33SWingman Kwok 	void __iomem			*switch_regs;
4306f8d3f33SWingman Kwok 	void __iomem			*host_port_regs;
4316f8d3f33SWingman Kwok 	void __iomem			*ale_reg;
4326f8d3f33SWingman Kwok 	void __iomem			*sgmii_port_regs;
4336f8d3f33SWingman Kwok 	void __iomem			*sgmii_port34_regs;
4346f8d3f33SWingman Kwok 	void __iomem			*xgbe_serdes_regs;
4356f8d3f33SWingman Kwok 	void __iomem			*hw_stats_regs[GBE_MAX_HW_STAT_MODS];
4366f8d3f33SWingman Kwok 
4376f8d3f33SWingman Kwok 	struct gbe_ss_regs_ofs		ss_regs_ofs;
4386f8d3f33SWingman Kwok 	struct gbe_switch_regs_ofs	switch_regs_ofs;
4396f8d3f33SWingman Kwok 	struct gbe_host_port_regs_ofs	host_port_regs_ofs;
4406f8d3f33SWingman Kwok 
4416f8d3f33SWingman Kwok 	struct cpsw_ale			*ale;
4426f8d3f33SWingman Kwok 	unsigned int			tx_queue_id;
4436f8d3f33SWingman Kwok 	const char			*dma_chan_name;
4446f8d3f33SWingman Kwok 
4456f8d3f33SWingman Kwok 	struct list_head		gbe_intf_head;
4466f8d3f33SWingman Kwok 	struct list_head		secondary_slaves;
4476f8d3f33SWingman Kwok 	struct net_device		*dummy_ndev;
4486f8d3f33SWingman Kwok 
4496f8d3f33SWingman Kwok 	u64				*hw_stats;
4506f8d3f33SWingman Kwok 	const struct netcp_ethtool_stat *et_stats;
4516f8d3f33SWingman Kwok 	int				num_et_stats;
4526f8d3f33SWingman Kwok 	/*  Lock for updating the hwstats */
4536f8d3f33SWingman Kwok 	spinlock_t			hw_stats_lock;
4546f8d3f33SWingman Kwok };
4556f8d3f33SWingman Kwok 
4566f8d3f33SWingman Kwok struct gbe_intf {
4576f8d3f33SWingman Kwok 	struct net_device	*ndev;
4586f8d3f33SWingman Kwok 	struct device		*dev;
4596f8d3f33SWingman Kwok 	struct gbe_priv		*gbe_dev;
4606f8d3f33SWingman Kwok 	struct netcp_tx_pipe	tx_pipe;
4616f8d3f33SWingman Kwok 	struct gbe_slave	*slave;
4626f8d3f33SWingman Kwok 	struct list_head	gbe_intf_list;
4636f8d3f33SWingman Kwok 	unsigned long		active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
4646f8d3f33SWingman Kwok };
4656f8d3f33SWingman Kwok 
4666f8d3f33SWingman Kwok static struct netcp_module gbe_module;
46790cff9e2SWingman Kwok static struct netcp_module xgbe_module;
4686f8d3f33SWingman Kwok 
4696f8d3f33SWingman Kwok /* Statistic management */
4706f8d3f33SWingman Kwok struct netcp_ethtool_stat {
4716f8d3f33SWingman Kwok 	char desc[ETH_GSTRING_LEN];
4726f8d3f33SWingman Kwok 	int type;
4736f8d3f33SWingman Kwok 	u32 size;
4746f8d3f33SWingman Kwok 	int offset;
4756f8d3f33SWingman Kwok };
4766f8d3f33SWingman Kwok 
4776f8d3f33SWingman Kwok #define GBE_STATSA_INFO(field)		"GBE_A:"#field, GBE_STATSA_MODULE,\
4786f8d3f33SWingman Kwok 				FIELD_SIZEOF(struct gbe_hw_stats, field), \
4796f8d3f33SWingman Kwok 				offsetof(struct gbe_hw_stats, field)
4806f8d3f33SWingman Kwok 
4816f8d3f33SWingman Kwok #define GBE_STATSB_INFO(field)		"GBE_B:"#field, GBE_STATSB_MODULE,\
4826f8d3f33SWingman Kwok 				FIELD_SIZEOF(struct gbe_hw_stats, field), \
4836f8d3f33SWingman Kwok 				offsetof(struct gbe_hw_stats, field)
4846f8d3f33SWingman Kwok 
4856f8d3f33SWingman Kwok #define GBE_STATSC_INFO(field)		"GBE_C:"#field, GBE_STATSC_MODULE,\
4866f8d3f33SWingman Kwok 				FIELD_SIZEOF(struct gbe_hw_stats, field), \
4876f8d3f33SWingman Kwok 				offsetof(struct gbe_hw_stats, field)
4886f8d3f33SWingman Kwok 
4896f8d3f33SWingman Kwok #define GBE_STATSD_INFO(field)		"GBE_D:"#field, GBE_STATSD_MODULE,\
4906f8d3f33SWingman Kwok 				FIELD_SIZEOF(struct gbe_hw_stats, field), \
4916f8d3f33SWingman Kwok 				offsetof(struct gbe_hw_stats, field)
4926f8d3f33SWingman Kwok 
4936f8d3f33SWingman Kwok static const struct netcp_ethtool_stat gbe13_et_stats[] = {
4946f8d3f33SWingman Kwok 	/* GBE module A */
4956f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_good_frames)},
4966f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_broadcast_frames)},
4976f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_multicast_frames)},
4986f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_pause_frames)},
4996f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_crc_errors)},
5006f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_align_code_errors)},
5016f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_oversized_frames)},
5026f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_jabber_frames)},
5036f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_undersized_frames)},
5046f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_fragments)},
5056f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_bytes)},
5066f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_good_frames)},
5076f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_broadcast_frames)},
5086f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_multicast_frames)},
5096f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_pause_frames)},
5106f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_deferred_frames)},
5116f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_collision_frames)},
5126f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_single_coll_frames)},
5136f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_mult_coll_frames)},
5146f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_excessive_collisions)},
5156f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_late_collisions)},
5166f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_underrun)},
5176f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_carrier_sense_errors)},
5186f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_bytes)},
5196f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_64byte_frames)},
5206f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_65_to_127byte_frames)},
5216f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_128_to_255byte_frames)},
5226f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_256_to_511byte_frames)},
5236f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_512_to_1023byte_frames)},
5246f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(tx_1024byte_frames)},
5256f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(net_bytes)},
5266f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_sof_overruns)},
5276f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_mof_overruns)},
5286f8d3f33SWingman Kwok 	{GBE_STATSA_INFO(rx_dma_overruns)},
5296f8d3f33SWingman Kwok 	/* GBE module B */
5306f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_good_frames)},
5316f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_broadcast_frames)},
5326f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_multicast_frames)},
5336f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_pause_frames)},
5346f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_crc_errors)},
5356f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_align_code_errors)},
5366f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_oversized_frames)},
5376f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_jabber_frames)},
5386f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_undersized_frames)},
5396f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_fragments)},
5406f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_bytes)},
5416f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_good_frames)},
5426f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_broadcast_frames)},
5436f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_multicast_frames)},
5446f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_pause_frames)},
5456f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_deferred_frames)},
5466f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_collision_frames)},
5476f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_single_coll_frames)},
5486f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_mult_coll_frames)},
5496f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_excessive_collisions)},
5506f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_late_collisions)},
5516f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_underrun)},
5526f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_carrier_sense_errors)},
5536f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_bytes)},
5546f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_64byte_frames)},
5556f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_65_to_127byte_frames)},
5566f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_128_to_255byte_frames)},
5576f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_256_to_511byte_frames)},
5586f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_512_to_1023byte_frames)},
5596f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(tx_1024byte_frames)},
5606f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(net_bytes)},
5616f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_sof_overruns)},
5626f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_mof_overruns)},
5636f8d3f33SWingman Kwok 	{GBE_STATSB_INFO(rx_dma_overruns)},
5646f8d3f33SWingman Kwok 	/* GBE module C */
5656f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_good_frames)},
5666f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_broadcast_frames)},
5676f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_multicast_frames)},
5686f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_pause_frames)},
5696f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_crc_errors)},
5706f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_align_code_errors)},
5716f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_oversized_frames)},
5726f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_jabber_frames)},
5736f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_undersized_frames)},
5746f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_fragments)},
5756f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_bytes)},
5766f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_good_frames)},
5776f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_broadcast_frames)},
5786f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_multicast_frames)},
5796f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_pause_frames)},
5806f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_deferred_frames)},
5816f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_collision_frames)},
5826f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_single_coll_frames)},
5836f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_mult_coll_frames)},
5846f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_excessive_collisions)},
5856f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_late_collisions)},
5866f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_underrun)},
5876f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_carrier_sense_errors)},
5886f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_bytes)},
5896f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_64byte_frames)},
5906f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_65_to_127byte_frames)},
5916f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_128_to_255byte_frames)},
5926f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_256_to_511byte_frames)},
5936f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_512_to_1023byte_frames)},
5946f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(tx_1024byte_frames)},
5956f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(net_bytes)},
5966f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_sof_overruns)},
5976f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_mof_overruns)},
5986f8d3f33SWingman Kwok 	{GBE_STATSC_INFO(rx_dma_overruns)},
5996f8d3f33SWingman Kwok 	/* GBE module D */
6006f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_good_frames)},
6016f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_broadcast_frames)},
6026f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_multicast_frames)},
6036f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_pause_frames)},
6046f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_crc_errors)},
6056f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_align_code_errors)},
6066f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_oversized_frames)},
6076f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_jabber_frames)},
6086f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_undersized_frames)},
6096f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_fragments)},
6106f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_bytes)},
6116f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_good_frames)},
6126f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_broadcast_frames)},
6136f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_multicast_frames)},
6146f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_pause_frames)},
6156f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_deferred_frames)},
6166f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_collision_frames)},
6176f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_single_coll_frames)},
6186f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_mult_coll_frames)},
6196f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_excessive_collisions)},
6206f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_late_collisions)},
6216f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_underrun)},
6226f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_carrier_sense_errors)},
6236f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_bytes)},
6246f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_64byte_frames)},
6256f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_65_to_127byte_frames)},
6266f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_128_to_255byte_frames)},
6276f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_256_to_511byte_frames)},
6286f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_512_to_1023byte_frames)},
6296f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(tx_1024byte_frames)},
6306f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(net_bytes)},
6316f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_sof_overruns)},
6326f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_mof_overruns)},
6336f8d3f33SWingman Kwok 	{GBE_STATSD_INFO(rx_dma_overruns)},
6346f8d3f33SWingman Kwok };
6356f8d3f33SWingman Kwok 
63690cff9e2SWingman Kwok #define XGBE_STATS0_INFO(field)	"GBE_0:"#field, XGBE_STATS0_MODULE, \
63790cff9e2SWingman Kwok 				FIELD_SIZEOF(struct xgbe_hw_stats, field), \
63890cff9e2SWingman Kwok 				offsetof(struct xgbe_hw_stats, field)
63990cff9e2SWingman Kwok 
64090cff9e2SWingman Kwok #define XGBE_STATS1_INFO(field)	"GBE_1:"#field, XGBE_STATS1_MODULE, \
64190cff9e2SWingman Kwok 				FIELD_SIZEOF(struct xgbe_hw_stats, field), \
64290cff9e2SWingman Kwok 				offsetof(struct xgbe_hw_stats, field)
64390cff9e2SWingman Kwok 
64490cff9e2SWingman Kwok #define XGBE_STATS2_INFO(field)	"GBE_2:"#field, XGBE_STATS2_MODULE, \
64590cff9e2SWingman Kwok 				FIELD_SIZEOF(struct xgbe_hw_stats, field), \
64690cff9e2SWingman Kwok 				offsetof(struct xgbe_hw_stats, field)
64790cff9e2SWingman Kwok 
64890cff9e2SWingman Kwok static const struct netcp_ethtool_stat xgbe10_et_stats[] = {
64990cff9e2SWingman Kwok 	/* GBE module 0 */
65090cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_good_frames)},
65190cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_broadcast_frames)},
65290cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_multicast_frames)},
65390cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_oversized_frames)},
65490cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_undersized_frames)},
65590cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(overrun_type4)},
65690cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(overrun_type5)},
65790cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_bytes)},
65890cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_good_frames)},
65990cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_broadcast_frames)},
66090cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_multicast_frames)},
66190cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_bytes)},
66290cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_64byte_frames)},
66390cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_65_to_127byte_frames)},
66490cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_128_to_255byte_frames)},
66590cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_256_to_511byte_frames)},
66690cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_512_to_1023byte_frames)},
66790cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(tx_1024byte_frames)},
66890cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(net_bytes)},
66990cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_sof_overruns)},
67090cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_mof_overruns)},
67190cff9e2SWingman Kwok 	{XGBE_STATS0_INFO(rx_dma_overruns)},
67290cff9e2SWingman Kwok 	/* XGBE module 1 */
67390cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_good_frames)},
67490cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_broadcast_frames)},
67590cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_multicast_frames)},
67690cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_pause_frames)},
67790cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_crc_errors)},
67890cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_align_code_errors)},
67990cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_oversized_frames)},
68090cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_jabber_frames)},
68190cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_undersized_frames)},
68290cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_fragments)},
68390cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(overrun_type4)},
68490cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(overrun_type5)},
68590cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_bytes)},
68690cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_good_frames)},
68790cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_broadcast_frames)},
68890cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_multicast_frames)},
68990cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_pause_frames)},
69090cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_deferred_frames)},
69190cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_collision_frames)},
69290cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_single_coll_frames)},
69390cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_mult_coll_frames)},
69490cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_excessive_collisions)},
69590cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_late_collisions)},
69690cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_underrun)},
69790cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_carrier_sense_errors)},
69890cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_bytes)},
69990cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_64byte_frames)},
70090cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_65_to_127byte_frames)},
70190cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_128_to_255byte_frames)},
70290cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_256_to_511byte_frames)},
70390cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_512_to_1023byte_frames)},
70490cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(tx_1024byte_frames)},
70590cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(net_bytes)},
70690cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_sof_overruns)},
70790cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_mof_overruns)},
70890cff9e2SWingman Kwok 	{XGBE_STATS1_INFO(rx_dma_overruns)},
70990cff9e2SWingman Kwok 	/* XGBE module 2 */
71090cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_good_frames)},
71190cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_broadcast_frames)},
71290cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_multicast_frames)},
71390cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_pause_frames)},
71490cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_crc_errors)},
71590cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_align_code_errors)},
71690cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_oversized_frames)},
71790cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_jabber_frames)},
71890cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_undersized_frames)},
71990cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_fragments)},
72090cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(overrun_type4)},
72190cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(overrun_type5)},
72290cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_bytes)},
72390cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_good_frames)},
72490cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_broadcast_frames)},
72590cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_multicast_frames)},
72690cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_pause_frames)},
72790cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_deferred_frames)},
72890cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_collision_frames)},
72990cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_single_coll_frames)},
73090cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_mult_coll_frames)},
73190cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_excessive_collisions)},
73290cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_late_collisions)},
73390cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_underrun)},
73490cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_carrier_sense_errors)},
73590cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_bytes)},
73690cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_64byte_frames)},
73790cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_65_to_127byte_frames)},
73890cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_128_to_255byte_frames)},
73990cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_256_to_511byte_frames)},
74090cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_512_to_1023byte_frames)},
74190cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(tx_1024byte_frames)},
74290cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(net_bytes)},
74390cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_sof_overruns)},
74490cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_mof_overruns)},
74590cff9e2SWingman Kwok 	{XGBE_STATS2_INFO(rx_dma_overruns)},
74690cff9e2SWingman Kwok };
74790cff9e2SWingman Kwok 
7486f8d3f33SWingman Kwok #define for_each_intf(i, priv) \
7496f8d3f33SWingman Kwok 	list_for_each_entry((i), &(priv)->gbe_intf_head, gbe_intf_list)
7506f8d3f33SWingman Kwok 
7516f8d3f33SWingman Kwok #define for_each_sec_slave(slave, priv) \
7526f8d3f33SWingman Kwok 	list_for_each_entry((slave), &(priv)->secondary_slaves, slave_list)
7536f8d3f33SWingman Kwok 
7546f8d3f33SWingman Kwok #define first_sec_slave(priv)					\
7556f8d3f33SWingman Kwok 	list_first_entry(&priv->secondary_slaves, \
7566f8d3f33SWingman Kwok 			struct gbe_slave, slave_list)
7576f8d3f33SWingman Kwok 
7586f8d3f33SWingman Kwok static void keystone_get_drvinfo(struct net_device *ndev,
7596f8d3f33SWingman Kwok 				 struct ethtool_drvinfo *info)
7606f8d3f33SWingman Kwok {
7616f8d3f33SWingman Kwok 	strncpy(info->driver, NETCP_DRIVER_NAME, sizeof(info->driver));
7626f8d3f33SWingman Kwok 	strncpy(info->version, NETCP_DRIVER_VERSION, sizeof(info->version));
7636f8d3f33SWingman Kwok }
7646f8d3f33SWingman Kwok 
7656f8d3f33SWingman Kwok static u32 keystone_get_msglevel(struct net_device *ndev)
7666f8d3f33SWingman Kwok {
7676f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
7686f8d3f33SWingman Kwok 
7696f8d3f33SWingman Kwok 	return netcp->msg_enable;
7706f8d3f33SWingman Kwok }
7716f8d3f33SWingman Kwok 
7726f8d3f33SWingman Kwok static void keystone_set_msglevel(struct net_device *ndev, u32 value)
7736f8d3f33SWingman Kwok {
7746f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
7756f8d3f33SWingman Kwok 
7766f8d3f33SWingman Kwok 	netcp->msg_enable = value;
7776f8d3f33SWingman Kwok }
7786f8d3f33SWingman Kwok 
7796f8d3f33SWingman Kwok static void keystone_get_stat_strings(struct net_device *ndev,
7806f8d3f33SWingman Kwok 				      uint32_t stringset, uint8_t *data)
7816f8d3f33SWingman Kwok {
7826f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
7836f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
7846f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev;
7856f8d3f33SWingman Kwok 	int i;
7866f8d3f33SWingman Kwok 
7876f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
7886f8d3f33SWingman Kwok 	if (!gbe_intf)
7896f8d3f33SWingman Kwok 		return;
7906f8d3f33SWingman Kwok 	gbe_dev = gbe_intf->gbe_dev;
7916f8d3f33SWingman Kwok 
7926f8d3f33SWingman Kwok 	switch (stringset) {
7936f8d3f33SWingman Kwok 	case ETH_SS_STATS:
7946f8d3f33SWingman Kwok 		for (i = 0; i < gbe_dev->num_et_stats; i++) {
7956f8d3f33SWingman Kwok 			memcpy(data, gbe_dev->et_stats[i].desc,
7966f8d3f33SWingman Kwok 			       ETH_GSTRING_LEN);
7976f8d3f33SWingman Kwok 			data += ETH_GSTRING_LEN;
7986f8d3f33SWingman Kwok 		}
7996f8d3f33SWingman Kwok 		break;
8006f8d3f33SWingman Kwok 	case ETH_SS_TEST:
8016f8d3f33SWingman Kwok 		break;
8026f8d3f33SWingman Kwok 	}
8036f8d3f33SWingman Kwok }
8046f8d3f33SWingman Kwok 
8056f8d3f33SWingman Kwok static int keystone_get_sset_count(struct net_device *ndev, int stringset)
8066f8d3f33SWingman Kwok {
8076f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
8086f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
8096f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev;
8106f8d3f33SWingman Kwok 
8116f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
8126f8d3f33SWingman Kwok 	if (!gbe_intf)
8136f8d3f33SWingman Kwok 		return -EINVAL;
8146f8d3f33SWingman Kwok 	gbe_dev = gbe_intf->gbe_dev;
8156f8d3f33SWingman Kwok 
8166f8d3f33SWingman Kwok 	switch (stringset) {
8176f8d3f33SWingman Kwok 	case ETH_SS_TEST:
8186f8d3f33SWingman Kwok 		return 0;
8196f8d3f33SWingman Kwok 	case ETH_SS_STATS:
8206f8d3f33SWingman Kwok 		return gbe_dev->num_et_stats;
8216f8d3f33SWingman Kwok 	default:
8226f8d3f33SWingman Kwok 		return -EINVAL;
8236f8d3f33SWingman Kwok 	}
8246f8d3f33SWingman Kwok }
8256f8d3f33SWingman Kwok 
8266f8d3f33SWingman Kwok static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data)
8276f8d3f33SWingman Kwok {
8286f8d3f33SWingman Kwok 	void __iomem *base = NULL;
8296f8d3f33SWingman Kwok 	u32  __iomem *p;
8306f8d3f33SWingman Kwok 	u32 tmp = 0;
8316f8d3f33SWingman Kwok 	int i;
8326f8d3f33SWingman Kwok 
8336f8d3f33SWingman Kwok 	for (i = 0; i < gbe_dev->num_et_stats; i++) {
8346f8d3f33SWingman Kwok 		base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type];
8356f8d3f33SWingman Kwok 		p = base + gbe_dev->et_stats[i].offset;
8366f8d3f33SWingman Kwok 		tmp = readl(p);
8376f8d3f33SWingman Kwok 		gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp;
8386f8d3f33SWingman Kwok 		if (data)
8396f8d3f33SWingman Kwok 			data[i] = gbe_dev->hw_stats[i];
8406f8d3f33SWingman Kwok 		/* write-to-decrement:
8416f8d3f33SWingman Kwok 		 * new register value = old register value - write value
8426f8d3f33SWingman Kwok 		 */
8436f8d3f33SWingman Kwok 		writel(tmp, p);
8446f8d3f33SWingman Kwok 	}
8456f8d3f33SWingman Kwok }
8466f8d3f33SWingman Kwok 
8476f8d3f33SWingman Kwok static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data)
8486f8d3f33SWingman Kwok {
8496f8d3f33SWingman Kwok 	void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0];
8506f8d3f33SWingman Kwok 	void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1];
8516f8d3f33SWingman Kwok 	u64 *hw_stats = &gbe_dev->hw_stats[0];
8526f8d3f33SWingman Kwok 	void __iomem *base = NULL;
8536f8d3f33SWingman Kwok 	u32  __iomem *p;
8546f8d3f33SWingman Kwok 	u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2);
8556f8d3f33SWingman Kwok 	int i, j, pair;
8566f8d3f33SWingman Kwok 
8576f8d3f33SWingman Kwok 	for (pair = 0; pair < 2; pair++) {
8586f8d3f33SWingman Kwok 		val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en));
8596f8d3f33SWingman Kwok 
8606f8d3f33SWingman Kwok 		if (pair == 0)
8616f8d3f33SWingman Kwok 			val &= ~GBE_STATS_CD_SEL;
8626f8d3f33SWingman Kwok 		else
8636f8d3f33SWingman Kwok 			val |= GBE_STATS_CD_SEL;
8646f8d3f33SWingman Kwok 
8656f8d3f33SWingman Kwok 		/* make the stat modules visible */
8666f8d3f33SWingman Kwok 		writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en));
8676f8d3f33SWingman Kwok 
8686f8d3f33SWingman Kwok 		for (i = 0; i < pair_size; i++) {
8696f8d3f33SWingman Kwok 			j = pair * pair_size + i;
8706f8d3f33SWingman Kwok 			switch (gbe_dev->et_stats[j].type) {
8716f8d3f33SWingman Kwok 			case GBE_STATSA_MODULE:
8726f8d3f33SWingman Kwok 			case GBE_STATSC_MODULE:
8736f8d3f33SWingman Kwok 				base = gbe_statsa;
8746f8d3f33SWingman Kwok 			break;
8756f8d3f33SWingman Kwok 			case GBE_STATSB_MODULE:
8766f8d3f33SWingman Kwok 			case GBE_STATSD_MODULE:
8776f8d3f33SWingman Kwok 				base  = gbe_statsb;
8786f8d3f33SWingman Kwok 			break;
8796f8d3f33SWingman Kwok 			}
8806f8d3f33SWingman Kwok 
8816f8d3f33SWingman Kwok 			p = base + gbe_dev->et_stats[j].offset;
8826f8d3f33SWingman Kwok 			tmp = readl(p);
8836f8d3f33SWingman Kwok 			hw_stats[j] += tmp;
8846f8d3f33SWingman Kwok 			if (data)
8856f8d3f33SWingman Kwok 				data[j] = hw_stats[j];
8866f8d3f33SWingman Kwok 			/* write-to-decrement:
8876f8d3f33SWingman Kwok 			 * new register value = old register value - write value
8886f8d3f33SWingman Kwok 			 */
8896f8d3f33SWingman Kwok 			writel(tmp, p);
8906f8d3f33SWingman Kwok 		}
8916f8d3f33SWingman Kwok 	}
8926f8d3f33SWingman Kwok }
8936f8d3f33SWingman Kwok 
8946f8d3f33SWingman Kwok static void keystone_get_ethtool_stats(struct net_device *ndev,
8956f8d3f33SWingman Kwok 				       struct ethtool_stats *stats,
8966f8d3f33SWingman Kwok 				       uint64_t *data)
8976f8d3f33SWingman Kwok {
8986f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
8996f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
9006f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev;
9016f8d3f33SWingman Kwok 
9026f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
9036f8d3f33SWingman Kwok 	if (!gbe_intf)
9046f8d3f33SWingman Kwok 		return;
9056f8d3f33SWingman Kwok 
9066f8d3f33SWingman Kwok 	gbe_dev = gbe_intf->gbe_dev;
9076f8d3f33SWingman Kwok 	spin_lock_bh(&gbe_dev->hw_stats_lock);
90890cff9e2SWingman Kwok 	if (gbe_dev->ss_version == GBE_SS_VERSION_14)
9096f8d3f33SWingman Kwok 		gbe_update_stats_ver14(gbe_dev, data);
91090cff9e2SWingman Kwok 	else
91190cff9e2SWingman Kwok 		gbe_update_stats(gbe_dev, data);
9126f8d3f33SWingman Kwok 	spin_unlock_bh(&gbe_dev->hw_stats_lock);
9136f8d3f33SWingman Kwok }
9146f8d3f33SWingman Kwok 
9156f8d3f33SWingman Kwok static int keystone_get_settings(struct net_device *ndev,
9166f8d3f33SWingman Kwok 				 struct ethtool_cmd *cmd)
9176f8d3f33SWingman Kwok {
9186f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
9196f8d3f33SWingman Kwok 	struct phy_device *phy = ndev->phydev;
9206f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
9216f8d3f33SWingman Kwok 	int ret;
9226f8d3f33SWingman Kwok 
9236f8d3f33SWingman Kwok 	if (!phy)
9246f8d3f33SWingman Kwok 		return -EINVAL;
9256f8d3f33SWingman Kwok 
9266f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
9276f8d3f33SWingman Kwok 	if (!gbe_intf)
9286f8d3f33SWingman Kwok 		return -EINVAL;
9296f8d3f33SWingman Kwok 
9306f8d3f33SWingman Kwok 	if (!gbe_intf->slave)
9316f8d3f33SWingman Kwok 		return -EINVAL;
9326f8d3f33SWingman Kwok 
9336f8d3f33SWingman Kwok 	ret = phy_ethtool_gset(phy, cmd);
9346f8d3f33SWingman Kwok 	if (!ret)
9356f8d3f33SWingman Kwok 		cmd->port = gbe_intf->slave->phy_port_t;
9366f8d3f33SWingman Kwok 
9376f8d3f33SWingman Kwok 	return ret;
9386f8d3f33SWingman Kwok }
9396f8d3f33SWingman Kwok 
9406f8d3f33SWingman Kwok static int keystone_set_settings(struct net_device *ndev,
9416f8d3f33SWingman Kwok 				 struct ethtool_cmd *cmd)
9426f8d3f33SWingman Kwok {
9436f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
9446f8d3f33SWingman Kwok 	struct phy_device *phy = ndev->phydev;
9456f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
9466f8d3f33SWingman Kwok 	u32 features = cmd->advertising & cmd->supported;
9476f8d3f33SWingman Kwok 
9486f8d3f33SWingman Kwok 	if (!phy)
9496f8d3f33SWingman Kwok 		return -EINVAL;
9506f8d3f33SWingman Kwok 
9516f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
9526f8d3f33SWingman Kwok 	if (!gbe_intf)
9536f8d3f33SWingman Kwok 		return -EINVAL;
9546f8d3f33SWingman Kwok 
9556f8d3f33SWingman Kwok 	if (!gbe_intf->slave)
9566f8d3f33SWingman Kwok 		return -EINVAL;
9576f8d3f33SWingman Kwok 
9586f8d3f33SWingman Kwok 	if (cmd->port != gbe_intf->slave->phy_port_t) {
9596f8d3f33SWingman Kwok 		if ((cmd->port == PORT_TP) && !(features & ADVERTISED_TP))
9606f8d3f33SWingman Kwok 			return -EINVAL;
9616f8d3f33SWingman Kwok 
9626f8d3f33SWingman Kwok 		if ((cmd->port == PORT_AUI) && !(features & ADVERTISED_AUI))
9636f8d3f33SWingman Kwok 			return -EINVAL;
9646f8d3f33SWingman Kwok 
9656f8d3f33SWingman Kwok 		if ((cmd->port == PORT_BNC) && !(features & ADVERTISED_BNC))
9666f8d3f33SWingman Kwok 			return -EINVAL;
9676f8d3f33SWingman Kwok 
9686f8d3f33SWingman Kwok 		if ((cmd->port == PORT_MII) && !(features & ADVERTISED_MII))
9696f8d3f33SWingman Kwok 			return -EINVAL;
9706f8d3f33SWingman Kwok 
9716f8d3f33SWingman Kwok 		if ((cmd->port == PORT_FIBRE) && !(features & ADVERTISED_FIBRE))
9726f8d3f33SWingman Kwok 			return -EINVAL;
9736f8d3f33SWingman Kwok 	}
9746f8d3f33SWingman Kwok 
9756f8d3f33SWingman Kwok 	gbe_intf->slave->phy_port_t = cmd->port;
9766f8d3f33SWingman Kwok 	return phy_ethtool_sset(phy, cmd);
9776f8d3f33SWingman Kwok }
9786f8d3f33SWingman Kwok 
9796f8d3f33SWingman Kwok static const struct ethtool_ops keystone_ethtool_ops = {
9806f8d3f33SWingman Kwok 	.get_drvinfo		= keystone_get_drvinfo,
9816f8d3f33SWingman Kwok 	.get_link		= ethtool_op_get_link,
9826f8d3f33SWingman Kwok 	.get_msglevel		= keystone_get_msglevel,
9836f8d3f33SWingman Kwok 	.set_msglevel		= keystone_set_msglevel,
9846f8d3f33SWingman Kwok 	.get_strings		= keystone_get_stat_strings,
9856f8d3f33SWingman Kwok 	.get_sset_count		= keystone_get_sset_count,
9866f8d3f33SWingman Kwok 	.get_ethtool_stats	= keystone_get_ethtool_stats,
9876f8d3f33SWingman Kwok 	.get_settings		= keystone_get_settings,
9886f8d3f33SWingman Kwok 	.set_settings		= keystone_set_settings,
9896f8d3f33SWingman Kwok };
9906f8d3f33SWingman Kwok 
9916f8d3f33SWingman Kwok #define mac_hi(mac)	(((mac)[0] << 0) | ((mac)[1] << 8) |	\
9926f8d3f33SWingman Kwok 			 ((mac)[2] << 16) | ((mac)[3] << 24))
9936f8d3f33SWingman Kwok #define mac_lo(mac)	(((mac)[4] << 0) | ((mac)[5] << 8))
9946f8d3f33SWingman Kwok 
9956f8d3f33SWingman Kwok static void gbe_set_slave_mac(struct gbe_slave *slave,
9966f8d3f33SWingman Kwok 			      struct gbe_intf *gbe_intf)
9976f8d3f33SWingman Kwok {
9986f8d3f33SWingman Kwok 	struct net_device *ndev = gbe_intf->ndev;
9996f8d3f33SWingman Kwok 
10006f8d3f33SWingman Kwok 	writel(mac_hi(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_hi));
10016f8d3f33SWingman Kwok 	writel(mac_lo(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_lo));
10026f8d3f33SWingman Kwok }
10036f8d3f33SWingman Kwok 
10046f8d3f33SWingman Kwok static int gbe_get_slave_port(struct gbe_priv *priv, u32 slave_num)
10056f8d3f33SWingman Kwok {
10066f8d3f33SWingman Kwok 	if (priv->host_port == 0)
10076f8d3f33SWingman Kwok 		return slave_num + 1;
10086f8d3f33SWingman Kwok 
10096f8d3f33SWingman Kwok 	return slave_num;
10106f8d3f33SWingman Kwok }
10116f8d3f33SWingman Kwok 
10126f8d3f33SWingman Kwok static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev,
10136f8d3f33SWingman Kwok 					  struct net_device *ndev,
10146f8d3f33SWingman Kwok 					  struct gbe_slave *slave,
10156f8d3f33SWingman Kwok 					  int up)
10166f8d3f33SWingman Kwok {
10176f8d3f33SWingman Kwok 	struct phy_device *phy = slave->phy;
10186f8d3f33SWingman Kwok 	u32 mac_control = 0;
10196f8d3f33SWingman Kwok 
10206f8d3f33SWingman Kwok 	if (up) {
10216f8d3f33SWingman Kwok 		mac_control = slave->mac_control;
102290cff9e2SWingman Kwok 		if (phy && (phy->speed == SPEED_1000)) {
10236f8d3f33SWingman Kwok 			mac_control |= MACSL_GIG_MODE;
102490cff9e2SWingman Kwok 			mac_control &= ~MACSL_XGIG_MODE;
102590cff9e2SWingman Kwok 		} else if (phy && (phy->speed == SPEED_10000)) {
102690cff9e2SWingman Kwok 			mac_control |= MACSL_XGIG_MODE;
102790cff9e2SWingman Kwok 			mac_control &= ~MACSL_GIG_MODE;
102890cff9e2SWingman Kwok 		}
10296f8d3f33SWingman Kwok 
10306f8d3f33SWingman Kwok 		writel(mac_control, GBE_REG_ADDR(slave, emac_regs,
10316f8d3f33SWingman Kwok 						 mac_control));
10326f8d3f33SWingman Kwok 
10336f8d3f33SWingman Kwok 		cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
10346f8d3f33SWingman Kwok 				     ALE_PORT_STATE,
10356f8d3f33SWingman Kwok 				     ALE_PORT_STATE_FORWARD);
10366f8d3f33SWingman Kwok 
10376f8d3f33SWingman Kwok 		if (ndev && slave->open)
10386f8d3f33SWingman Kwok 			netif_carrier_on(ndev);
10396f8d3f33SWingman Kwok 	} else {
10406f8d3f33SWingman Kwok 		writel(mac_control, GBE_REG_ADDR(slave, emac_regs,
10416f8d3f33SWingman Kwok 						 mac_control));
10426f8d3f33SWingman Kwok 		cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
10436f8d3f33SWingman Kwok 				     ALE_PORT_STATE,
10446f8d3f33SWingman Kwok 				     ALE_PORT_STATE_DISABLE);
10456f8d3f33SWingman Kwok 		if (ndev)
10466f8d3f33SWingman Kwok 			netif_carrier_off(ndev);
10476f8d3f33SWingman Kwok 	}
10486f8d3f33SWingman Kwok 
10496f8d3f33SWingman Kwok 	if (phy)
10506f8d3f33SWingman Kwok 		phy_print_status(phy);
10516f8d3f33SWingman Kwok }
10526f8d3f33SWingman Kwok 
10536f8d3f33SWingman Kwok static bool gbe_phy_link_status(struct gbe_slave *slave)
10546f8d3f33SWingman Kwok {
10556f8d3f33SWingman Kwok 	 return !slave->phy || slave->phy->link;
10566f8d3f33SWingman Kwok }
10576f8d3f33SWingman Kwok 
10586f8d3f33SWingman Kwok static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev,
10596f8d3f33SWingman Kwok 					  struct gbe_slave *slave,
10606f8d3f33SWingman Kwok 					  struct net_device *ndev)
10616f8d3f33SWingman Kwok {
10626f8d3f33SWingman Kwok 	int sp = slave->slave_num;
10636f8d3f33SWingman Kwok 	int phy_link_state, sgmii_link_state = 1, link_state;
10646f8d3f33SWingman Kwok 
10656f8d3f33SWingman Kwok 	if (!slave->open)
10666f8d3f33SWingman Kwok 		return;
10676f8d3f33SWingman Kwok 
106890cff9e2SWingman Kwok 	if (!SLAVE_LINK_IS_XGMII(slave))
106990cff9e2SWingman Kwok 		sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp),
107090cff9e2SWingman Kwok 							     sp);
10716f8d3f33SWingman Kwok 	phy_link_state = gbe_phy_link_status(slave);
10726f8d3f33SWingman Kwok 	link_state = phy_link_state & sgmii_link_state;
10736f8d3f33SWingman Kwok 
10746f8d3f33SWingman Kwok 	if (atomic_xchg(&slave->link_state, link_state) != link_state)
10756f8d3f33SWingman Kwok 		netcp_ethss_link_state_action(gbe_dev, ndev, slave,
10766f8d3f33SWingman Kwok 					      link_state);
10776f8d3f33SWingman Kwok }
10786f8d3f33SWingman Kwok 
107990cff9e2SWingman Kwok static void xgbe_adjust_link(struct net_device *ndev)
108090cff9e2SWingman Kwok {
108190cff9e2SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
108290cff9e2SWingman Kwok 	struct gbe_intf *gbe_intf;
108390cff9e2SWingman Kwok 
108490cff9e2SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp);
108590cff9e2SWingman Kwok 	if (!gbe_intf)
108690cff9e2SWingman Kwok 		return;
108790cff9e2SWingman Kwok 
108890cff9e2SWingman Kwok 	netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave,
108990cff9e2SWingman Kwok 				      ndev);
109090cff9e2SWingman Kwok }
109190cff9e2SWingman Kwok 
10926f8d3f33SWingman Kwok static void gbe_adjust_link(struct net_device *ndev)
10936f8d3f33SWingman Kwok {
10946f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
10956f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
10966f8d3f33SWingman Kwok 
10976f8d3f33SWingman Kwok 	gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
10986f8d3f33SWingman Kwok 	if (!gbe_intf)
10996f8d3f33SWingman Kwok 		return;
11006f8d3f33SWingman Kwok 
11016f8d3f33SWingman Kwok 	netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave,
11026f8d3f33SWingman Kwok 				      ndev);
11036f8d3f33SWingman Kwok }
11046f8d3f33SWingman Kwok 
11056f8d3f33SWingman Kwok static void gbe_adjust_link_sec_slaves(struct net_device *ndev)
11066f8d3f33SWingman Kwok {
11076f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = netdev_priv(ndev);
11086f8d3f33SWingman Kwok 	struct gbe_slave *slave;
11096f8d3f33SWingman Kwok 
11106f8d3f33SWingman Kwok 	for_each_sec_slave(slave, gbe_dev)
11116f8d3f33SWingman Kwok 		netcp_ethss_update_link_state(gbe_dev, slave, NULL);
11126f8d3f33SWingman Kwok }
11136f8d3f33SWingman Kwok 
11146f8d3f33SWingman Kwok /* Reset EMAC
11156f8d3f33SWingman Kwok  * Soft reset is set and polled until clear, or until a timeout occurs
11166f8d3f33SWingman Kwok  */
11176f8d3f33SWingman Kwok static int gbe_port_reset(struct gbe_slave *slave)
11186f8d3f33SWingman Kwok {
11196f8d3f33SWingman Kwok 	u32 i, v;
11206f8d3f33SWingman Kwok 
11216f8d3f33SWingman Kwok 	/* Set the soft reset bit */
11226f8d3f33SWingman Kwok 	writel(SOFT_RESET, GBE_REG_ADDR(slave, emac_regs, soft_reset));
11236f8d3f33SWingman Kwok 
11246f8d3f33SWingman Kwok 	/* Wait for the bit to clear */
11256f8d3f33SWingman Kwok 	for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
11266f8d3f33SWingman Kwok 		v = readl(GBE_REG_ADDR(slave, emac_regs, soft_reset));
11276f8d3f33SWingman Kwok 		if ((v & SOFT_RESET_MASK) != SOFT_RESET)
11286f8d3f33SWingman Kwok 			return 0;
11296f8d3f33SWingman Kwok 	}
11306f8d3f33SWingman Kwok 
11316f8d3f33SWingman Kwok 	/* Timeout on the reset */
11326f8d3f33SWingman Kwok 	return GMACSL_RET_WARN_RESET_INCOMPLETE;
11336f8d3f33SWingman Kwok }
11346f8d3f33SWingman Kwok 
11356f8d3f33SWingman Kwok /* Configure EMAC */
11366f8d3f33SWingman Kwok static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
11376f8d3f33SWingman Kwok 			    int max_rx_len)
11386f8d3f33SWingman Kwok {
113990cff9e2SWingman Kwok 	u32 xgmii_mode;
114090cff9e2SWingman Kwok 
11416f8d3f33SWingman Kwok 	if (max_rx_len > NETCP_MAX_FRAME_SIZE)
11426f8d3f33SWingman Kwok 		max_rx_len = NETCP_MAX_FRAME_SIZE;
11436f8d3f33SWingman Kwok 
114490cff9e2SWingman Kwok 	/* Enable correct MII mode at SS level */
114590cff9e2SWingman Kwok 	if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) &&
114690cff9e2SWingman Kwok 	    (slave->link_interface >= XGMII_LINK_MAC_PHY)) {
114790cff9e2SWingman Kwok 		xgmii_mode = readl(GBE_REG_ADDR(gbe_dev, ss_regs, control));
114890cff9e2SWingman Kwok 		xgmii_mode |= (1 << slave->slave_num);
114990cff9e2SWingman Kwok 		writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control));
115090cff9e2SWingman Kwok 	}
115190cff9e2SWingman Kwok 
11526f8d3f33SWingman Kwok 	writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen));
11536f8d3f33SWingman Kwok 	writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control));
11546f8d3f33SWingman Kwok }
11556f8d3f33SWingman Kwok 
11566f8d3f33SWingman Kwok static void gbe_slave_stop(struct gbe_intf *intf)
11576f8d3f33SWingman Kwok {
11586f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = intf->gbe_dev;
11596f8d3f33SWingman Kwok 	struct gbe_slave *slave = intf->slave;
11606f8d3f33SWingman Kwok 
11616f8d3f33SWingman Kwok 	gbe_port_reset(slave);
11626f8d3f33SWingman Kwok 	/* Disable forwarding */
11636f8d3f33SWingman Kwok 	cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
11646f8d3f33SWingman Kwok 			     ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
11656f8d3f33SWingman Kwok 	cpsw_ale_del_mcast(gbe_dev->ale, intf->ndev->broadcast,
11666f8d3f33SWingman Kwok 			   1 << slave->port_num, 0, 0);
11676f8d3f33SWingman Kwok 
11686f8d3f33SWingman Kwok 	if (!slave->phy)
11696f8d3f33SWingman Kwok 		return;
11706f8d3f33SWingman Kwok 
11716f8d3f33SWingman Kwok 	phy_stop(slave->phy);
11726f8d3f33SWingman Kwok 	phy_disconnect(slave->phy);
11736f8d3f33SWingman Kwok 	slave->phy = NULL;
11746f8d3f33SWingman Kwok }
11756f8d3f33SWingman Kwok 
11766f8d3f33SWingman Kwok static void gbe_sgmii_config(struct gbe_priv *priv, struct gbe_slave *slave)
11776f8d3f33SWingman Kwok {
11786f8d3f33SWingman Kwok 	void __iomem *sgmii_port_regs;
11796f8d3f33SWingman Kwok 
11806f8d3f33SWingman Kwok 	sgmii_port_regs = priv->sgmii_port_regs;
11816f8d3f33SWingman Kwok 	if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2))
11826f8d3f33SWingman Kwok 		sgmii_port_regs = priv->sgmii_port34_regs;
11836f8d3f33SWingman Kwok 
118490cff9e2SWingman Kwok 	if (!SLAVE_LINK_IS_XGMII(slave)) {
11856f8d3f33SWingman Kwok 		netcp_sgmii_reset(sgmii_port_regs, slave->slave_num);
11866f8d3f33SWingman Kwok 		netcp_sgmii_config(sgmii_port_regs, slave->slave_num,
11876f8d3f33SWingman Kwok 				   slave->link_interface);
11886f8d3f33SWingman Kwok 	}
118990cff9e2SWingman Kwok }
11906f8d3f33SWingman Kwok 
11916f8d3f33SWingman Kwok static int gbe_slave_open(struct gbe_intf *gbe_intf)
11926f8d3f33SWingman Kwok {
11936f8d3f33SWingman Kwok 	struct gbe_priv *priv = gbe_intf->gbe_dev;
11946f8d3f33SWingman Kwok 	struct gbe_slave *slave = gbe_intf->slave;
11956f8d3f33SWingman Kwok 	phy_interface_t phy_mode;
11966f8d3f33SWingman Kwok 	bool has_phy = false;
11976f8d3f33SWingman Kwok 
11986f8d3f33SWingman Kwok 	void (*hndlr)(struct net_device *) = gbe_adjust_link;
11996f8d3f33SWingman Kwok 
12006f8d3f33SWingman Kwok 	gbe_sgmii_config(priv, slave);
12016f8d3f33SWingman Kwok 	gbe_port_reset(slave);
12026f8d3f33SWingman Kwok 	gbe_port_config(priv, slave, priv->rx_packet_max);
12036f8d3f33SWingman Kwok 	gbe_set_slave_mac(slave, gbe_intf);
12046f8d3f33SWingman Kwok 	/* enable forwarding */
12056f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, slave->port_num,
12066f8d3f33SWingman Kwok 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
12076f8d3f33SWingman Kwok 	cpsw_ale_add_mcast(priv->ale, gbe_intf->ndev->broadcast,
12086f8d3f33SWingman Kwok 			   1 << slave->port_num, 0, 0, ALE_MCAST_FWD_2);
12096f8d3f33SWingman Kwok 
12106f8d3f33SWingman Kwok 	if (slave->link_interface == SGMII_LINK_MAC_PHY) {
12116f8d3f33SWingman Kwok 		has_phy = true;
12126f8d3f33SWingman Kwok 		phy_mode = PHY_INTERFACE_MODE_SGMII;
12136f8d3f33SWingman Kwok 		slave->phy_port_t = PORT_MII;
12146f8d3f33SWingman Kwok 	} else if (slave->link_interface == XGMII_LINK_MAC_PHY) {
12156f8d3f33SWingman Kwok 		has_phy = true;
12166f8d3f33SWingman Kwok 		phy_mode = PHY_INTERFACE_MODE_NA;
12176f8d3f33SWingman Kwok 		slave->phy_port_t = PORT_FIBRE;
12186f8d3f33SWingman Kwok 	}
12196f8d3f33SWingman Kwok 
12206f8d3f33SWingman Kwok 	if (has_phy) {
122190cff9e2SWingman Kwok 		if (priv->ss_version == XGBE_SS_VERSION_10)
122290cff9e2SWingman Kwok 			hndlr = xgbe_adjust_link;
122390cff9e2SWingman Kwok 
12246f8d3f33SWingman Kwok 		slave->phy = of_phy_connect(gbe_intf->ndev,
12256f8d3f33SWingman Kwok 					    slave->phy_node,
12266f8d3f33SWingman Kwok 					    hndlr, 0,
12276f8d3f33SWingman Kwok 					    phy_mode);
12286f8d3f33SWingman Kwok 		if (!slave->phy) {
12296f8d3f33SWingman Kwok 			dev_err(priv->dev, "phy not found on slave %d\n",
12306f8d3f33SWingman Kwok 				slave->slave_num);
12316f8d3f33SWingman Kwok 			return -ENODEV;
12326f8d3f33SWingman Kwok 		}
12336f8d3f33SWingman Kwok 		dev_dbg(priv->dev, "phy found: id is: 0x%s\n",
12346f8d3f33SWingman Kwok 			dev_name(&slave->phy->dev));
12356f8d3f33SWingman Kwok 		phy_start(slave->phy);
12366f8d3f33SWingman Kwok 		phy_read_status(slave->phy);
12376f8d3f33SWingman Kwok 	}
12386f8d3f33SWingman Kwok 	return 0;
12396f8d3f33SWingman Kwok }
12406f8d3f33SWingman Kwok 
12416f8d3f33SWingman Kwok static void gbe_init_host_port(struct gbe_priv *priv)
12426f8d3f33SWingman Kwok {
12436f8d3f33SWingman Kwok 	int bypass_en = 1;
12446f8d3f33SWingman Kwok 	/* Max length register */
12456f8d3f33SWingman Kwok 	writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs,
12466f8d3f33SWingman Kwok 						  rx_maxlen));
12476f8d3f33SWingman Kwok 
12486f8d3f33SWingman Kwok 	cpsw_ale_start(priv->ale);
12496f8d3f33SWingman Kwok 
12506f8d3f33SWingman Kwok 	if (priv->enable_ale)
12516f8d3f33SWingman Kwok 		bypass_en = 0;
12526f8d3f33SWingman Kwok 
12536f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0, ALE_BYPASS, bypass_en);
12546f8d3f33SWingman Kwok 
12556f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0, ALE_NO_PORT_VLAN, 1);
12566f8d3f33SWingman Kwok 
12576f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, priv->host_port,
12586f8d3f33SWingman Kwok 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
12596f8d3f33SWingman Kwok 
12606f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0,
12616f8d3f33SWingman Kwok 			     ALE_PORT_UNKNOWN_VLAN_MEMBER,
12626f8d3f33SWingman Kwok 			     GBE_PORT_MASK(priv->ale_ports));
12636f8d3f33SWingman Kwok 
12646f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0,
12656f8d3f33SWingman Kwok 			     ALE_PORT_UNKNOWN_MCAST_FLOOD,
12666f8d3f33SWingman Kwok 			     GBE_PORT_MASK(priv->ale_ports - 1));
12676f8d3f33SWingman Kwok 
12686f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0,
12696f8d3f33SWingman Kwok 			     ALE_PORT_UNKNOWN_REG_MCAST_FLOOD,
12706f8d3f33SWingman Kwok 			     GBE_PORT_MASK(priv->ale_ports));
12716f8d3f33SWingman Kwok 
12726f8d3f33SWingman Kwok 	cpsw_ale_control_set(priv->ale, 0,
12736f8d3f33SWingman Kwok 			     ALE_PORT_UNTAGGED_EGRESS,
12746f8d3f33SWingman Kwok 			     GBE_PORT_MASK(priv->ale_ports));
12756f8d3f33SWingman Kwok }
12766f8d3f33SWingman Kwok 
12776f8d3f33SWingman Kwok static void gbe_add_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr)
12786f8d3f33SWingman Kwok {
12796f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
12806f8d3f33SWingman Kwok 	u16 vlan_id;
12816f8d3f33SWingman Kwok 
12826f8d3f33SWingman Kwok 	cpsw_ale_add_mcast(gbe_dev->ale, addr,
12836f8d3f33SWingman Kwok 			   GBE_PORT_MASK(gbe_dev->ale_ports), 0, 0,
12846f8d3f33SWingman Kwok 			   ALE_MCAST_FWD_2);
12856f8d3f33SWingman Kwok 	for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
12866f8d3f33SWingman Kwok 		cpsw_ale_add_mcast(gbe_dev->ale, addr,
12876f8d3f33SWingman Kwok 				   GBE_PORT_MASK(gbe_dev->ale_ports),
12886f8d3f33SWingman Kwok 				   ALE_VLAN, vlan_id, ALE_MCAST_FWD_2);
12896f8d3f33SWingman Kwok 	}
12906f8d3f33SWingman Kwok }
12916f8d3f33SWingman Kwok 
12926f8d3f33SWingman Kwok static void gbe_add_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr)
12936f8d3f33SWingman Kwok {
12946f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
12956f8d3f33SWingman Kwok 	u16 vlan_id;
12966f8d3f33SWingman Kwok 
12976f8d3f33SWingman Kwok 	cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0);
12986f8d3f33SWingman Kwok 
12996f8d3f33SWingman Kwok 	for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID)
13006f8d3f33SWingman Kwok 		cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port,
13016f8d3f33SWingman Kwok 				   ALE_VLAN, vlan_id);
13026f8d3f33SWingman Kwok }
13036f8d3f33SWingman Kwok 
13046f8d3f33SWingman Kwok static void gbe_del_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr)
13056f8d3f33SWingman Kwok {
13066f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
13076f8d3f33SWingman Kwok 	u16 vlan_id;
13086f8d3f33SWingman Kwok 
13096f8d3f33SWingman Kwok 	cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, 0, 0);
13106f8d3f33SWingman Kwok 
13116f8d3f33SWingman Kwok 	for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
13126f8d3f33SWingman Kwok 		cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, ALE_VLAN, vlan_id);
13136f8d3f33SWingman Kwok 	}
13146f8d3f33SWingman Kwok }
13156f8d3f33SWingman Kwok 
13166f8d3f33SWingman Kwok static void gbe_del_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr)
13176f8d3f33SWingman Kwok {
13186f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
13196f8d3f33SWingman Kwok 	u16 vlan_id;
13206f8d3f33SWingman Kwok 
13216f8d3f33SWingman Kwok 	cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0);
13226f8d3f33SWingman Kwok 
13236f8d3f33SWingman Kwok 	for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
13246f8d3f33SWingman Kwok 		cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port,
13256f8d3f33SWingman Kwok 				   ALE_VLAN, vlan_id);
13266f8d3f33SWingman Kwok 	}
13276f8d3f33SWingman Kwok }
13286f8d3f33SWingman Kwok 
13296f8d3f33SWingman Kwok static int gbe_add_addr(void *intf_priv, struct netcp_addr *naddr)
13306f8d3f33SWingman Kwok {
13316f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
13326f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
13336f8d3f33SWingman Kwok 
13346f8d3f33SWingman Kwok 	dev_dbg(gbe_dev->dev, "ethss adding address %pM, type %d\n",
13356f8d3f33SWingman Kwok 		naddr->addr, naddr->type);
13366f8d3f33SWingman Kwok 
13376f8d3f33SWingman Kwok 	switch (naddr->type) {
13386f8d3f33SWingman Kwok 	case ADDR_MCAST:
13396f8d3f33SWingman Kwok 	case ADDR_BCAST:
13406f8d3f33SWingman Kwok 		gbe_add_mcast_addr(gbe_intf, naddr->addr);
13416f8d3f33SWingman Kwok 		break;
13426f8d3f33SWingman Kwok 	case ADDR_UCAST:
13436f8d3f33SWingman Kwok 	case ADDR_DEV:
13446f8d3f33SWingman Kwok 		gbe_add_ucast_addr(gbe_intf, naddr->addr);
13456f8d3f33SWingman Kwok 		break;
13466f8d3f33SWingman Kwok 	case ADDR_ANY:
13476f8d3f33SWingman Kwok 		/* nothing to do for promiscuous */
13486f8d3f33SWingman Kwok 	default:
13496f8d3f33SWingman Kwok 		break;
13506f8d3f33SWingman Kwok 	}
13516f8d3f33SWingman Kwok 
13526f8d3f33SWingman Kwok 	return 0;
13536f8d3f33SWingman Kwok }
13546f8d3f33SWingman Kwok 
13556f8d3f33SWingman Kwok static int gbe_del_addr(void *intf_priv, struct netcp_addr *naddr)
13566f8d3f33SWingman Kwok {
13576f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
13586f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
13596f8d3f33SWingman Kwok 
13606f8d3f33SWingman Kwok 	dev_dbg(gbe_dev->dev, "ethss deleting address %pM, type %d\n",
13616f8d3f33SWingman Kwok 		naddr->addr, naddr->type);
13626f8d3f33SWingman Kwok 
13636f8d3f33SWingman Kwok 	switch (naddr->type) {
13646f8d3f33SWingman Kwok 	case ADDR_MCAST:
13656f8d3f33SWingman Kwok 	case ADDR_BCAST:
13666f8d3f33SWingman Kwok 		gbe_del_mcast_addr(gbe_intf, naddr->addr);
13676f8d3f33SWingman Kwok 		break;
13686f8d3f33SWingman Kwok 	case ADDR_UCAST:
13696f8d3f33SWingman Kwok 	case ADDR_DEV:
13706f8d3f33SWingman Kwok 		gbe_del_ucast_addr(gbe_intf, naddr->addr);
13716f8d3f33SWingman Kwok 		break;
13726f8d3f33SWingman Kwok 	case ADDR_ANY:
13736f8d3f33SWingman Kwok 		/* nothing to do for promiscuous */
13746f8d3f33SWingman Kwok 	default:
13756f8d3f33SWingman Kwok 		break;
13766f8d3f33SWingman Kwok 	}
13776f8d3f33SWingman Kwok 
13786f8d3f33SWingman Kwok 	return 0;
13796f8d3f33SWingman Kwok }
13806f8d3f33SWingman Kwok 
13816f8d3f33SWingman Kwok static int gbe_add_vid(void *intf_priv, int vid)
13826f8d3f33SWingman Kwok {
13836f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
13846f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
13856f8d3f33SWingman Kwok 
13866f8d3f33SWingman Kwok 	set_bit(vid, gbe_intf->active_vlans);
13876f8d3f33SWingman Kwok 
13886f8d3f33SWingman Kwok 	cpsw_ale_add_vlan(gbe_dev->ale, vid,
13896f8d3f33SWingman Kwok 			  GBE_PORT_MASK(gbe_dev->ale_ports),
13906f8d3f33SWingman Kwok 			  GBE_MASK_NO_PORTS,
13916f8d3f33SWingman Kwok 			  GBE_PORT_MASK(gbe_dev->ale_ports),
13926f8d3f33SWingman Kwok 			  GBE_PORT_MASK(gbe_dev->ale_ports - 1));
13936f8d3f33SWingman Kwok 
13946f8d3f33SWingman Kwok 	return 0;
13956f8d3f33SWingman Kwok }
13966f8d3f33SWingman Kwok 
13976f8d3f33SWingman Kwok static int gbe_del_vid(void *intf_priv, int vid)
13986f8d3f33SWingman Kwok {
13996f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
14006f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
14016f8d3f33SWingman Kwok 
14026f8d3f33SWingman Kwok 	cpsw_ale_del_vlan(gbe_dev->ale, vid, 0);
14036f8d3f33SWingman Kwok 	clear_bit(vid, gbe_intf->active_vlans);
14046f8d3f33SWingman Kwok 	return 0;
14056f8d3f33SWingman Kwok }
14066f8d3f33SWingman Kwok 
14076f8d3f33SWingman Kwok static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd)
14086f8d3f33SWingman Kwok {
14096f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
14106f8d3f33SWingman Kwok 	struct phy_device *phy = gbe_intf->slave->phy;
14116f8d3f33SWingman Kwok 	int ret = -EOPNOTSUPP;
14126f8d3f33SWingman Kwok 
14136f8d3f33SWingman Kwok 	if (phy)
14146f8d3f33SWingman Kwok 		ret = phy_mii_ioctl(phy, req, cmd);
14156f8d3f33SWingman Kwok 
14166f8d3f33SWingman Kwok 	return ret;
14176f8d3f33SWingman Kwok }
14186f8d3f33SWingman Kwok 
14196f8d3f33SWingman Kwok static void netcp_ethss_timer(unsigned long arg)
14206f8d3f33SWingman Kwok {
14216f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = (struct gbe_priv *)arg;
14226f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
14236f8d3f33SWingman Kwok 	struct gbe_slave *slave;
14246f8d3f33SWingman Kwok 
14256f8d3f33SWingman Kwok 	/* Check & update SGMII link state of interfaces */
14266f8d3f33SWingman Kwok 	for_each_intf(gbe_intf, gbe_dev) {
14276f8d3f33SWingman Kwok 		if (!gbe_intf->slave->open)
14286f8d3f33SWingman Kwok 			continue;
14296f8d3f33SWingman Kwok 		netcp_ethss_update_link_state(gbe_dev, gbe_intf->slave,
14306f8d3f33SWingman Kwok 					      gbe_intf->ndev);
14316f8d3f33SWingman Kwok 	}
14326f8d3f33SWingman Kwok 
14336f8d3f33SWingman Kwok 	/* Check & update SGMII link state of secondary ports */
14346f8d3f33SWingman Kwok 	for_each_sec_slave(slave, gbe_dev) {
14356f8d3f33SWingman Kwok 		netcp_ethss_update_link_state(gbe_dev, slave, NULL);
14366f8d3f33SWingman Kwok 	}
14376f8d3f33SWingman Kwok 
14386f8d3f33SWingman Kwok 	spin_lock_bh(&gbe_dev->hw_stats_lock);
14396f8d3f33SWingman Kwok 
14406f8d3f33SWingman Kwok 	if (gbe_dev->ss_version == GBE_SS_VERSION_14)
14416f8d3f33SWingman Kwok 		gbe_update_stats_ver14(gbe_dev, NULL);
14426f8d3f33SWingman Kwok 	else
14436f8d3f33SWingman Kwok 		gbe_update_stats(gbe_dev, NULL);
14446f8d3f33SWingman Kwok 
14456f8d3f33SWingman Kwok 	spin_unlock_bh(&gbe_dev->hw_stats_lock);
14466f8d3f33SWingman Kwok 
14476f8d3f33SWingman Kwok 	gbe_dev->timer.expires	= jiffies + GBE_TIMER_INTERVAL;
14486f8d3f33SWingman Kwok 	add_timer(&gbe_dev->timer);
14496f8d3f33SWingman Kwok }
14506f8d3f33SWingman Kwok 
14516f8d3f33SWingman Kwok static int gbe_tx_hook(int order, void *data, struct netcp_packet *p_info)
14526f8d3f33SWingman Kwok {
14536f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = data;
14546f8d3f33SWingman Kwok 
14556f8d3f33SWingman Kwok 	p_info->tx_pipe = &gbe_intf->tx_pipe;
14566f8d3f33SWingman Kwok 	return 0;
14576f8d3f33SWingman Kwok }
14586f8d3f33SWingman Kwok 
14596f8d3f33SWingman Kwok static int gbe_open(void *intf_priv, struct net_device *ndev)
14606f8d3f33SWingman Kwok {
14616f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
14626f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
14636f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
14646f8d3f33SWingman Kwok 	struct gbe_slave *slave = gbe_intf->slave;
14656f8d3f33SWingman Kwok 	int port_num = slave->port_num;
14666f8d3f33SWingman Kwok 	u32 reg;
14676f8d3f33SWingman Kwok 	int ret;
14686f8d3f33SWingman Kwok 
14696f8d3f33SWingman Kwok 	reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver));
14706f8d3f33SWingman Kwok 	dev_dbg(gbe_dev->dev, "initializing gbe version %d.%d (%d) GBE identification value 0x%x\n",
14716f8d3f33SWingman Kwok 		GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg),
14726f8d3f33SWingman Kwok 		GBE_RTL_VERSION(reg), GBE_IDENT(reg));
14736f8d3f33SWingman Kwok 
14746f8d3f33SWingman Kwok 	if (gbe_dev->enable_ale)
14756f8d3f33SWingman Kwok 		gbe_intf->tx_pipe.dma_psflags = 0;
14766f8d3f33SWingman Kwok 	else
14776f8d3f33SWingman Kwok 		gbe_intf->tx_pipe.dma_psflags = port_num;
14786f8d3f33SWingman Kwok 
14796f8d3f33SWingman Kwok 	dev_dbg(gbe_dev->dev, "opened TX channel %s: %p with psflags %d\n",
14806f8d3f33SWingman Kwok 		gbe_intf->tx_pipe.dma_chan_name,
14816f8d3f33SWingman Kwok 		gbe_intf->tx_pipe.dma_channel,
14826f8d3f33SWingman Kwok 		gbe_intf->tx_pipe.dma_psflags);
14836f8d3f33SWingman Kwok 
14846f8d3f33SWingman Kwok 	gbe_slave_stop(gbe_intf);
14856f8d3f33SWingman Kwok 
14866f8d3f33SWingman Kwok 	/* disable priority elevation and enable statistics on all ports */
14876f8d3f33SWingman Kwok 	writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype));
14886f8d3f33SWingman Kwok 
14896f8d3f33SWingman Kwok 	/* Control register */
14906f8d3f33SWingman Kwok 	writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control));
14916f8d3f33SWingman Kwok 
14926f8d3f33SWingman Kwok 	/* All statistics enabled and STAT AB visible by default */
14936f8d3f33SWingman Kwok 	writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs,
14946f8d3f33SWingman Kwok 							 stat_port_en));
14956f8d3f33SWingman Kwok 
14966f8d3f33SWingman Kwok 	ret = gbe_slave_open(gbe_intf);
14976f8d3f33SWingman Kwok 	if (ret)
14986f8d3f33SWingman Kwok 		goto fail;
14996f8d3f33SWingman Kwok 
15006f8d3f33SWingman Kwok 	netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
15016f8d3f33SWingman Kwok 			      gbe_intf);
15026f8d3f33SWingman Kwok 
15036f8d3f33SWingman Kwok 	slave->open = true;
15046f8d3f33SWingman Kwok 	netcp_ethss_update_link_state(gbe_dev, slave, ndev);
15056f8d3f33SWingman Kwok 	return 0;
15066f8d3f33SWingman Kwok 
15076f8d3f33SWingman Kwok fail:
15086f8d3f33SWingman Kwok 	gbe_slave_stop(gbe_intf);
15096f8d3f33SWingman Kwok 	return ret;
15106f8d3f33SWingman Kwok }
15116f8d3f33SWingman Kwok 
15126f8d3f33SWingman Kwok static int gbe_close(void *intf_priv, struct net_device *ndev)
15136f8d3f33SWingman Kwok {
15146f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
15156f8d3f33SWingman Kwok 	struct netcp_intf *netcp = netdev_priv(ndev);
15166f8d3f33SWingman Kwok 
15176f8d3f33SWingman Kwok 	gbe_slave_stop(gbe_intf);
15186f8d3f33SWingman Kwok 	netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
15196f8d3f33SWingman Kwok 				gbe_intf);
15206f8d3f33SWingman Kwok 
15216f8d3f33SWingman Kwok 	gbe_intf->slave->open = false;
15226f8d3f33SWingman Kwok 	atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID);
15236f8d3f33SWingman Kwok 	return 0;
15246f8d3f33SWingman Kwok }
15256f8d3f33SWingman Kwok 
15266f8d3f33SWingman Kwok static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
15276f8d3f33SWingman Kwok 		      struct device_node *node)
15286f8d3f33SWingman Kwok {
15296f8d3f33SWingman Kwok 	int port_reg_num;
15306f8d3f33SWingman Kwok 	u32 port_reg_ofs, emac_reg_ofs;
15316f8d3f33SWingman Kwok 
15326f8d3f33SWingman Kwok 	if (of_property_read_u32(node, "slave-port", &slave->slave_num)) {
15336f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "missing slave-port parameter\n");
15346f8d3f33SWingman Kwok 		return -EINVAL;
15356f8d3f33SWingman Kwok 	}
15366f8d3f33SWingman Kwok 
15376f8d3f33SWingman Kwok 	if (of_property_read_u32(node, "link-interface",
15386f8d3f33SWingman Kwok 				 &slave->link_interface)) {
15396f8d3f33SWingman Kwok 		dev_warn(gbe_dev->dev,
15406f8d3f33SWingman Kwok 			 "missing link-interface value defaulting to 1G mac-phy link\n");
15416f8d3f33SWingman Kwok 		slave->link_interface = SGMII_LINK_MAC_PHY;
15426f8d3f33SWingman Kwok 	}
15436f8d3f33SWingman Kwok 
15446f8d3f33SWingman Kwok 	slave->open = false;
15456f8d3f33SWingman Kwok 	slave->phy_node = of_parse_phandle(node, "phy-handle", 0);
15466f8d3f33SWingman Kwok 	slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num);
15476f8d3f33SWingman Kwok 
154890cff9e2SWingman Kwok 	if (slave->link_interface >= XGMII_LINK_MAC_PHY)
154990cff9e2SWingman Kwok 		slave->mac_control = GBE_DEF_10G_MAC_CONTROL;
155090cff9e2SWingman Kwok 	else
15516f8d3f33SWingman Kwok 		slave->mac_control = GBE_DEF_1G_MAC_CONTROL;
15526f8d3f33SWingman Kwok 
15536f8d3f33SWingman Kwok 	/* Emac regs memmap are contiguous but port regs are not */
15546f8d3f33SWingman Kwok 	port_reg_num = slave->slave_num;
15556f8d3f33SWingman Kwok 	if (gbe_dev->ss_version == GBE_SS_VERSION_14) {
15566f8d3f33SWingman Kwok 		if (slave->slave_num > 1) {
15576f8d3f33SWingman Kwok 			port_reg_ofs = GBE13_SLAVE_PORT2_OFFSET;
15586f8d3f33SWingman Kwok 			port_reg_num -= 2;
15596f8d3f33SWingman Kwok 		} else {
15606f8d3f33SWingman Kwok 			port_reg_ofs = GBE13_SLAVE_PORT_OFFSET;
15616f8d3f33SWingman Kwok 		}
156290cff9e2SWingman Kwok 	} else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) {
156390cff9e2SWingman Kwok 		port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET;
15646f8d3f33SWingman Kwok 	} else {
15656f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n",
15666f8d3f33SWingman Kwok 			gbe_dev->ss_version);
15676f8d3f33SWingman Kwok 		return -EINVAL;
15686f8d3f33SWingman Kwok 	}
15696f8d3f33SWingman Kwok 
15706f8d3f33SWingman Kwok 	if (gbe_dev->ss_version == GBE_SS_VERSION_14)
15716f8d3f33SWingman Kwok 		emac_reg_ofs = GBE13_EMAC_OFFSET;
157290cff9e2SWingman Kwok 	else if (gbe_dev->ss_version == XGBE_SS_VERSION_10)
157390cff9e2SWingman Kwok 		emac_reg_ofs = XGBE10_EMAC_OFFSET;
15746f8d3f33SWingman Kwok 
15756f8d3f33SWingman Kwok 	slave->port_regs = gbe_dev->ss_regs + port_reg_ofs +
15766f8d3f33SWingman Kwok 				(0x30 * port_reg_num);
15776f8d3f33SWingman Kwok 	slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs +
15786f8d3f33SWingman Kwok 				(0x40 * slave->slave_num);
15796f8d3f33SWingman Kwok 
15806f8d3f33SWingman Kwok 	if (gbe_dev->ss_version == GBE_SS_VERSION_14) {
15816f8d3f33SWingman Kwok 		/* Initialize  slave port register offsets */
15826f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, port_vlan);
15836f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, tx_pri_map);
15846f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, sa_lo);
15856f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, sa_hi);
15866f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, ts_ctl);
15876f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype);
15886f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, ts_vlan);
15896f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2);
15906f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, port_regs, ts_ctl2);
15916f8d3f33SWingman Kwok 
15926f8d3f33SWingman Kwok 		/* Initialize EMAC register offsets */
15936f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, emac_regs, mac_control);
15946f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, emac_regs, soft_reset);
15956f8d3f33SWingman Kwok 		GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen);
15966f8d3f33SWingman Kwok 
159790cff9e2SWingman Kwok 	} else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) {
159890cff9e2SWingman Kwok 		/* Initialize  slave port register offsets */
159990cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, port_vlan);
160090cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, tx_pri_map);
160190cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, sa_lo);
160290cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, sa_hi);
160390cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, ts_ctl);
160490cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype);
160590cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, ts_vlan);
160690cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2);
160790cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, port_regs, ts_ctl2);
160890cff9e2SWingman Kwok 
160990cff9e2SWingman Kwok 		/* Initialize EMAC register offsets */
161090cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, emac_regs, mac_control);
161190cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, emac_regs, soft_reset);
161290cff9e2SWingman Kwok 		XGBE_SET_REG_OFS(slave, emac_regs, rx_maxlen);
16136f8d3f33SWingman Kwok 	}
16146f8d3f33SWingman Kwok 
16156f8d3f33SWingman Kwok 	atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID);
16166f8d3f33SWingman Kwok 	return 0;
16176f8d3f33SWingman Kwok }
16186f8d3f33SWingman Kwok 
16196f8d3f33SWingman Kwok static void init_secondary_ports(struct gbe_priv *gbe_dev,
16206f8d3f33SWingman Kwok 				 struct device_node *node)
16216f8d3f33SWingman Kwok {
16226f8d3f33SWingman Kwok 	struct device *dev = gbe_dev->dev;
16236f8d3f33SWingman Kwok 	phy_interface_t phy_mode;
16246f8d3f33SWingman Kwok 	struct gbe_priv **priv;
16256f8d3f33SWingman Kwok 	struct device_node *port;
16266f8d3f33SWingman Kwok 	struct gbe_slave *slave;
16276f8d3f33SWingman Kwok 	bool mac_phy_link = false;
16286f8d3f33SWingman Kwok 
16296f8d3f33SWingman Kwok 	for_each_child_of_node(node, port) {
16306f8d3f33SWingman Kwok 		slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL);
16316f8d3f33SWingman Kwok 		if (!slave) {
16326f8d3f33SWingman Kwok 			dev_err(dev,
16336f8d3f33SWingman Kwok 				"memomry alloc failed for secondary port(%s), skipping...\n",
16346f8d3f33SWingman Kwok 				port->name);
16356f8d3f33SWingman Kwok 			continue;
16366f8d3f33SWingman Kwok 		}
16376f8d3f33SWingman Kwok 
16386f8d3f33SWingman Kwok 		if (init_slave(gbe_dev, slave, port)) {
16396f8d3f33SWingman Kwok 			dev_err(dev,
16406f8d3f33SWingman Kwok 				"Failed to initialize secondary port(%s), skipping...\n",
16416f8d3f33SWingman Kwok 				port->name);
16426f8d3f33SWingman Kwok 			devm_kfree(dev, slave);
16436f8d3f33SWingman Kwok 			continue;
16446f8d3f33SWingman Kwok 		}
16456f8d3f33SWingman Kwok 
16466f8d3f33SWingman Kwok 		gbe_sgmii_config(gbe_dev, slave);
16476f8d3f33SWingman Kwok 		gbe_port_reset(slave);
16486f8d3f33SWingman Kwok 		gbe_port_config(gbe_dev, slave, gbe_dev->rx_packet_max);
16496f8d3f33SWingman Kwok 		list_add_tail(&slave->slave_list, &gbe_dev->secondary_slaves);
16506f8d3f33SWingman Kwok 		gbe_dev->num_slaves++;
165190cff9e2SWingman Kwok 		if ((slave->link_interface == SGMII_LINK_MAC_PHY) ||
165290cff9e2SWingman Kwok 		    (slave->link_interface == XGMII_LINK_MAC_PHY))
16536f8d3f33SWingman Kwok 			mac_phy_link = true;
16546f8d3f33SWingman Kwok 
16556f8d3f33SWingman Kwok 		slave->open = true;
16566f8d3f33SWingman Kwok 	}
16576f8d3f33SWingman Kwok 
16586f8d3f33SWingman Kwok 	/* of_phy_connect() is needed only for MAC-PHY interface */
16596f8d3f33SWingman Kwok 	if (!mac_phy_link)
16606f8d3f33SWingman Kwok 		return;
16616f8d3f33SWingman Kwok 
16626f8d3f33SWingman Kwok 	/* Allocate dummy netdev device for attaching to phy device */
16636f8d3f33SWingman Kwok 	gbe_dev->dummy_ndev = alloc_netdev(sizeof(gbe_dev), "dummy",
16646f8d3f33SWingman Kwok 					NET_NAME_UNKNOWN, ether_setup);
16656f8d3f33SWingman Kwok 	if (!gbe_dev->dummy_ndev) {
16666f8d3f33SWingman Kwok 		dev_err(dev,
16676f8d3f33SWingman Kwok 			"Failed to allocate dummy netdev for secondary ports, skipping phy_connect()...\n");
16686f8d3f33SWingman Kwok 		return;
16696f8d3f33SWingman Kwok 	}
16706f8d3f33SWingman Kwok 	priv = netdev_priv(gbe_dev->dummy_ndev);
16716f8d3f33SWingman Kwok 	*priv = gbe_dev;
16726f8d3f33SWingman Kwok 
16736f8d3f33SWingman Kwok 	if (slave->link_interface == SGMII_LINK_MAC_PHY) {
16746f8d3f33SWingman Kwok 		phy_mode = PHY_INTERFACE_MODE_SGMII;
16756f8d3f33SWingman Kwok 		slave->phy_port_t = PORT_MII;
16766f8d3f33SWingman Kwok 	} else {
16776f8d3f33SWingman Kwok 		phy_mode = PHY_INTERFACE_MODE_NA;
16786f8d3f33SWingman Kwok 		slave->phy_port_t = PORT_FIBRE;
16796f8d3f33SWingman Kwok 	}
16806f8d3f33SWingman Kwok 
16816f8d3f33SWingman Kwok 	for_each_sec_slave(slave, gbe_dev) {
168290cff9e2SWingman Kwok 		if ((slave->link_interface != SGMII_LINK_MAC_PHY) &&
168390cff9e2SWingman Kwok 		    (slave->link_interface != XGMII_LINK_MAC_PHY))
16846f8d3f33SWingman Kwok 			continue;
16856f8d3f33SWingman Kwok 		slave->phy =
16866f8d3f33SWingman Kwok 			of_phy_connect(gbe_dev->dummy_ndev,
16876f8d3f33SWingman Kwok 				       slave->phy_node,
16886f8d3f33SWingman Kwok 				       gbe_adjust_link_sec_slaves,
16896f8d3f33SWingman Kwok 				       0, phy_mode);
16906f8d3f33SWingman Kwok 		if (!slave->phy) {
16916f8d3f33SWingman Kwok 			dev_err(dev, "phy not found for slave %d\n",
16926f8d3f33SWingman Kwok 				slave->slave_num);
16936f8d3f33SWingman Kwok 			slave->phy = NULL;
16946f8d3f33SWingman Kwok 		} else {
16956f8d3f33SWingman Kwok 			dev_dbg(dev, "phy found: id is: 0x%s\n",
16966f8d3f33SWingman Kwok 				dev_name(&slave->phy->dev));
16976f8d3f33SWingman Kwok 			phy_start(slave->phy);
16986f8d3f33SWingman Kwok 			phy_read_status(slave->phy);
16996f8d3f33SWingman Kwok 		}
17006f8d3f33SWingman Kwok 	}
17016f8d3f33SWingman Kwok }
17026f8d3f33SWingman Kwok 
17036f8d3f33SWingman Kwok static void free_secondary_ports(struct gbe_priv *gbe_dev)
17046f8d3f33SWingman Kwok {
17056f8d3f33SWingman Kwok 	struct gbe_slave *slave;
17066f8d3f33SWingman Kwok 
17076f8d3f33SWingman Kwok 	for (;;) {
17086f8d3f33SWingman Kwok 		slave = first_sec_slave(gbe_dev);
17096f8d3f33SWingman Kwok 		if (!slave)
17106f8d3f33SWingman Kwok 			break;
17116f8d3f33SWingman Kwok 		if (slave->phy)
17126f8d3f33SWingman Kwok 			phy_disconnect(slave->phy);
17136f8d3f33SWingman Kwok 		list_del(&slave->slave_list);
17146f8d3f33SWingman Kwok 	}
17156f8d3f33SWingman Kwok 	if (gbe_dev->dummy_ndev)
17166f8d3f33SWingman Kwok 		free_netdev(gbe_dev->dummy_ndev);
17176f8d3f33SWingman Kwok }
17186f8d3f33SWingman Kwok 
171990cff9e2SWingman Kwok static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
172090cff9e2SWingman Kwok 				 struct device_node *node)
172190cff9e2SWingman Kwok {
172290cff9e2SWingman Kwok 	struct resource res;
172390cff9e2SWingman Kwok 	void __iomem *regs;
172490cff9e2SWingman Kwok 	int ret, i;
172590cff9e2SWingman Kwok 
172690cff9e2SWingman Kwok 	ret = of_address_to_resource(node, 0, &res);
172790cff9e2SWingman Kwok 	if (ret) {
172890cff9e2SWingman Kwok 		dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n",
172990cff9e2SWingman Kwok 			node->name);
173090cff9e2SWingman Kwok 		return ret;
173190cff9e2SWingman Kwok 	}
173290cff9e2SWingman Kwok 
173390cff9e2SWingman Kwok 	regs = devm_ioremap_resource(gbe_dev->dev, &res);
173490cff9e2SWingman Kwok 	if (IS_ERR(regs)) {
173590cff9e2SWingman Kwok 		dev_err(gbe_dev->dev, "Failed to map xgbe register base\n");
173690cff9e2SWingman Kwok 		return PTR_ERR(regs);
173790cff9e2SWingman Kwok 	}
173890cff9e2SWingman Kwok 	gbe_dev->ss_regs = regs;
173990cff9e2SWingman Kwok 
174090cff9e2SWingman Kwok 	ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res);
174190cff9e2SWingman Kwok 	if (ret) {
174290cff9e2SWingman Kwok 		dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n",
174390cff9e2SWingman Kwok 			node->name);
174490cff9e2SWingman Kwok 		return ret;
174590cff9e2SWingman Kwok 	}
174690cff9e2SWingman Kwok 
174790cff9e2SWingman Kwok 	regs = devm_ioremap_resource(gbe_dev->dev, &res);
174890cff9e2SWingman Kwok 	if (IS_ERR(regs)) {
174990cff9e2SWingman Kwok 		dev_err(gbe_dev->dev, "Failed to map xgbe serdes register base\n");
175090cff9e2SWingman Kwok 		return PTR_ERR(regs);
175190cff9e2SWingman Kwok 	}
175290cff9e2SWingman Kwok 	gbe_dev->xgbe_serdes_regs = regs;
175390cff9e2SWingman Kwok 
175490cff9e2SWingman Kwok 	gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev,
175590cff9e2SWingman Kwok 					  XGBE10_NUM_STAT_ENTRIES *
175690cff9e2SWingman Kwok 					  (XGBE10_NUM_SLAVES + 1) * sizeof(u64),
175790cff9e2SWingman Kwok 					  GFP_KERNEL);
175890cff9e2SWingman Kwok 	if (!gbe_dev->hw_stats) {
175990cff9e2SWingman Kwok 		dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n");
176090cff9e2SWingman Kwok 		return -ENOMEM;
176190cff9e2SWingman Kwok 	}
176290cff9e2SWingman Kwok 
176390cff9e2SWingman Kwok 	gbe_dev->ss_version = XGBE_SS_VERSION_10;
176490cff9e2SWingman Kwok 	gbe_dev->sgmii_port_regs = gbe_dev->ss_regs +
176590cff9e2SWingman Kwok 					XGBE10_SGMII_MODULE_OFFSET;
176690cff9e2SWingman Kwok 	gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET;
176790cff9e2SWingman Kwok 	gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET;
176890cff9e2SWingman Kwok 
176990cff9e2SWingman Kwok 	for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++)
177090cff9e2SWingman Kwok 		gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs +
177190cff9e2SWingman Kwok 			XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i);
177290cff9e2SWingman Kwok 
177390cff9e2SWingman Kwok 	gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET;
177490cff9e2SWingman Kwok 	gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS;
177590cff9e2SWingman Kwok 	gbe_dev->host_port = XGBE10_HOST_PORT_NUM;
177690cff9e2SWingman Kwok 	gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES;
177790cff9e2SWingman Kwok 	gbe_dev->et_stats = xgbe10_et_stats;
177890cff9e2SWingman Kwok 	gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats);
177990cff9e2SWingman Kwok 
178090cff9e2SWingman Kwok 	/* Subsystem registers */
178190cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver);
178290cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, ss_regs, control);
178390cff9e2SWingman Kwok 
178490cff9e2SWingman Kwok 	/* Switch module registers */
178590cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver);
178690cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, switch_regs, control);
178790cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, switch_regs, ptype);
178890cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en);
178990cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control);
179090cff9e2SWingman Kwok 
179190cff9e2SWingman Kwok 	/* Host port registers */
179290cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan);
179390cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map);
179490cff9e2SWingman Kwok 	XGBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen);
179590cff9e2SWingman Kwok 	return 0;
179690cff9e2SWingman Kwok }
179790cff9e2SWingman Kwok 
17986f8d3f33SWingman Kwok static int get_gbe_resource_version(struct gbe_priv *gbe_dev,
17996f8d3f33SWingman Kwok 				    struct device_node *node)
18006f8d3f33SWingman Kwok {
18016f8d3f33SWingman Kwok 	struct resource res;
18026f8d3f33SWingman Kwok 	void __iomem *regs;
18036f8d3f33SWingman Kwok 	int ret;
18046f8d3f33SWingman Kwok 
18056f8d3f33SWingman Kwok 	ret = of_address_to_resource(node, 0, &res);
18066f8d3f33SWingman Kwok 	if (ret) {
18076f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n",
18086f8d3f33SWingman Kwok 			node->name);
18096f8d3f33SWingman Kwok 		return ret;
18106f8d3f33SWingman Kwok 	}
18116f8d3f33SWingman Kwok 
18126f8d3f33SWingman Kwok 	regs = devm_ioremap_resource(gbe_dev->dev, &res);
18136f8d3f33SWingman Kwok 	if (IS_ERR(regs)) {
18146f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "Failed to map gbe register base\n");
18156f8d3f33SWingman Kwok 		return PTR_ERR(regs);
18166f8d3f33SWingman Kwok 	}
18176f8d3f33SWingman Kwok 	gbe_dev->ss_regs = regs;
18186f8d3f33SWingman Kwok 	gbe_dev->ss_version = readl(gbe_dev->ss_regs);
18196f8d3f33SWingman Kwok 	return 0;
18206f8d3f33SWingman Kwok }
18216f8d3f33SWingman Kwok 
18226f8d3f33SWingman Kwok static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
18236f8d3f33SWingman Kwok 				struct device_node *node)
18246f8d3f33SWingman Kwok {
18256f8d3f33SWingman Kwok 	void __iomem *regs;
18266f8d3f33SWingman Kwok 	int i;
18276f8d3f33SWingman Kwok 
18286f8d3f33SWingman Kwok 	gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev,
18296f8d3f33SWingman Kwok 					  GBE13_NUM_HW_STAT_ENTRIES *
18306f8d3f33SWingman Kwok 					  GBE13_NUM_SLAVES * sizeof(u64),
18316f8d3f33SWingman Kwok 					  GFP_KERNEL);
18326f8d3f33SWingman Kwok 	if (!gbe_dev->hw_stats) {
18336f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n");
18346f8d3f33SWingman Kwok 		return -ENOMEM;
18356f8d3f33SWingman Kwok 	}
18366f8d3f33SWingman Kwok 
18376f8d3f33SWingman Kwok 	regs = gbe_dev->ss_regs;
18386f8d3f33SWingman Kwok 	gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET;
18396f8d3f33SWingman Kwok 	gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET;
18406f8d3f33SWingman Kwok 	gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET;
18416f8d3f33SWingman Kwok 	gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET;
18426f8d3f33SWingman Kwok 
18436f8d3f33SWingman Kwok 	for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++)
18446f8d3f33SWingman Kwok 		gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET +
18456f8d3f33SWingman Kwok 				(GBE_HW_STATS_REG_MAP_SZ * i);
18466f8d3f33SWingman Kwok 
18476f8d3f33SWingman Kwok 	gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET;
18486f8d3f33SWingman Kwok 	gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS;
18496f8d3f33SWingman Kwok 	gbe_dev->host_port = GBE13_HOST_PORT_NUM;
18506f8d3f33SWingman Kwok 	gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES;
18516f8d3f33SWingman Kwok 	gbe_dev->et_stats = gbe13_et_stats;
18526f8d3f33SWingman Kwok 	gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats);
18536f8d3f33SWingman Kwok 
18546f8d3f33SWingman Kwok 	/* Subsystem registers */
18556f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver);
18566f8d3f33SWingman Kwok 
18576f8d3f33SWingman Kwok 	/* Switch module registers */
18586f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver);
18596f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, control);
18606f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, soft_reset);
18616f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en);
18626f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, ptype);
18636f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control);
18646f8d3f33SWingman Kwok 
18656f8d3f33SWingman Kwok 	/* Host port registers */
18666f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan);
18676f8d3f33SWingman Kwok 	GBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen);
18686f8d3f33SWingman Kwok 	return 0;
18696f8d3f33SWingman Kwok }
18706f8d3f33SWingman Kwok 
18716f8d3f33SWingman Kwok static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
18726f8d3f33SWingman Kwok 		     struct device_node *node, void **inst_priv)
18736f8d3f33SWingman Kwok {
18746f8d3f33SWingman Kwok 	struct device_node *interfaces, *interface;
18756f8d3f33SWingman Kwok 	struct device_node *secondary_ports;
18766f8d3f33SWingman Kwok 	struct cpsw_ale_params ale_params;
18776f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev;
18786f8d3f33SWingman Kwok 	u32 slave_num;
18796f8d3f33SWingman Kwok 	int ret = 0;
18806f8d3f33SWingman Kwok 
18816f8d3f33SWingman Kwok 	if (!node) {
18826f8d3f33SWingman Kwok 		dev_err(dev, "device tree info unavailable\n");
18836f8d3f33SWingman Kwok 		return -ENODEV;
18846f8d3f33SWingman Kwok 	}
18856f8d3f33SWingman Kwok 
18866f8d3f33SWingman Kwok 	gbe_dev = devm_kzalloc(dev, sizeof(struct gbe_priv), GFP_KERNEL);
18876f8d3f33SWingman Kwok 	if (!gbe_dev)
18886f8d3f33SWingman Kwok 		return -ENOMEM;
18896f8d3f33SWingman Kwok 
18906f8d3f33SWingman Kwok 	gbe_dev->dev = dev;
18916f8d3f33SWingman Kwok 	gbe_dev->netcp_device = netcp_device;
18926f8d3f33SWingman Kwok 	gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE;
18936f8d3f33SWingman Kwok 
18946f8d3f33SWingman Kwok 	/* init the hw stats lock */
18956f8d3f33SWingman Kwok 	spin_lock_init(&gbe_dev->hw_stats_lock);
18966f8d3f33SWingman Kwok 
18976f8d3f33SWingman Kwok 	if (of_find_property(node, "enable-ale", NULL)) {
18986f8d3f33SWingman Kwok 		gbe_dev->enable_ale = true;
18996f8d3f33SWingman Kwok 		dev_info(dev, "ALE enabled\n");
19006f8d3f33SWingman Kwok 	} else {
19016f8d3f33SWingman Kwok 		gbe_dev->enable_ale = false;
19026f8d3f33SWingman Kwok 		dev_dbg(dev, "ALE bypass enabled*\n");
19036f8d3f33SWingman Kwok 	}
19046f8d3f33SWingman Kwok 
19056f8d3f33SWingman Kwok 	ret = of_property_read_u32(node, "tx-queue",
19066f8d3f33SWingman Kwok 				   &gbe_dev->tx_queue_id);
19076f8d3f33SWingman Kwok 	if (ret < 0) {
19086f8d3f33SWingman Kwok 		dev_err(dev, "missing tx_queue parameter\n");
19096f8d3f33SWingman Kwok 		gbe_dev->tx_queue_id = GBE_TX_QUEUE;
19106f8d3f33SWingman Kwok 	}
19116f8d3f33SWingman Kwok 
19126f8d3f33SWingman Kwok 	ret = of_property_read_string(node, "tx-channel",
19136f8d3f33SWingman Kwok 				      &gbe_dev->dma_chan_name);
19146f8d3f33SWingman Kwok 	if (ret < 0) {
19156f8d3f33SWingman Kwok 		dev_err(dev, "missing \"tx-channel\" parameter\n");
19166f8d3f33SWingman Kwok 		ret = -ENODEV;
19176f8d3f33SWingman Kwok 		goto quit;
19186f8d3f33SWingman Kwok 	}
19196f8d3f33SWingman Kwok 
19206f8d3f33SWingman Kwok 	if (!strcmp(node->name, "gbe")) {
19216f8d3f33SWingman Kwok 		ret = get_gbe_resource_version(gbe_dev, node);
19226f8d3f33SWingman Kwok 		if (ret)
19236f8d3f33SWingman Kwok 			goto quit;
19246f8d3f33SWingman Kwok 
19256f8d3f33SWingman Kwok 		ret = set_gbe_ethss14_priv(gbe_dev, node);
19266f8d3f33SWingman Kwok 		if (ret)
19276f8d3f33SWingman Kwok 			goto quit;
192890cff9e2SWingman Kwok 	} else if (!strcmp(node->name, "xgbe")) {
192990cff9e2SWingman Kwok 		ret = set_xgbe_ethss10_priv(gbe_dev, node);
193090cff9e2SWingman Kwok 		if (ret)
193190cff9e2SWingman Kwok 			goto quit;
193290cff9e2SWingman Kwok 		ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs,
193390cff9e2SWingman Kwok 					     gbe_dev->ss_regs);
193490cff9e2SWingman Kwok 		if (ret)
193590cff9e2SWingman Kwok 			goto quit;
19366f8d3f33SWingman Kwok 	} else {
19376f8d3f33SWingman Kwok 		dev_err(dev, "unknown GBE node(%s)\n", node->name);
19386f8d3f33SWingman Kwok 		ret = -ENODEV;
19396f8d3f33SWingman Kwok 		goto quit;
19406f8d3f33SWingman Kwok 	}
19416f8d3f33SWingman Kwok 
19426f8d3f33SWingman Kwok 	interfaces = of_get_child_by_name(node, "interfaces");
19436f8d3f33SWingman Kwok 	if (!interfaces)
19446f8d3f33SWingman Kwok 		dev_err(dev, "could not find interfaces\n");
19456f8d3f33SWingman Kwok 
19466f8d3f33SWingman Kwok 	ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device,
19476f8d3f33SWingman Kwok 				gbe_dev->dma_chan_name, gbe_dev->tx_queue_id);
19486f8d3f33SWingman Kwok 	if (ret)
19496f8d3f33SWingman Kwok 		goto quit;
19506f8d3f33SWingman Kwok 
19516f8d3f33SWingman Kwok 	ret = netcp_txpipe_open(&gbe_dev->tx_pipe);
19526f8d3f33SWingman Kwok 	if (ret)
19536f8d3f33SWingman Kwok 		goto quit;
19546f8d3f33SWingman Kwok 
19556f8d3f33SWingman Kwok 	/* Create network interfaces */
19566f8d3f33SWingman Kwok 	INIT_LIST_HEAD(&gbe_dev->gbe_intf_head);
19576f8d3f33SWingman Kwok 	for_each_child_of_node(interfaces, interface) {
19586f8d3f33SWingman Kwok 		ret = of_property_read_u32(interface, "slave-port", &slave_num);
19596f8d3f33SWingman Kwok 		if (ret) {
19606f8d3f33SWingman Kwok 			dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n",
19616f8d3f33SWingman Kwok 				interface->name);
19626f8d3f33SWingman Kwok 			continue;
19636f8d3f33SWingman Kwok 		}
19646f8d3f33SWingman Kwok 		gbe_dev->num_slaves++;
19656f8d3f33SWingman Kwok 	}
19666f8d3f33SWingman Kwok 
19676f8d3f33SWingman Kwok 	if (!gbe_dev->num_slaves)
19686f8d3f33SWingman Kwok 		dev_warn(dev, "No network interface configured\n");
19696f8d3f33SWingman Kwok 
19706f8d3f33SWingman Kwok 	/* Initialize Secondary slave ports */
19716f8d3f33SWingman Kwok 	secondary_ports = of_get_child_by_name(node, "secondary-slave-ports");
19726f8d3f33SWingman Kwok 	INIT_LIST_HEAD(&gbe_dev->secondary_slaves);
19736f8d3f33SWingman Kwok 	if (secondary_ports)
19746f8d3f33SWingman Kwok 		init_secondary_ports(gbe_dev, secondary_ports);
19756f8d3f33SWingman Kwok 	of_node_put(secondary_ports);
19766f8d3f33SWingman Kwok 
19776f8d3f33SWingman Kwok 	if (!gbe_dev->num_slaves) {
19786f8d3f33SWingman Kwok 		dev_err(dev, "No network interface or secondary ports configured\n");
19796f8d3f33SWingman Kwok 		ret = -ENODEV;
19806f8d3f33SWingman Kwok 		goto quit;
19816f8d3f33SWingman Kwok 	}
19826f8d3f33SWingman Kwok 
19836f8d3f33SWingman Kwok 	memset(&ale_params, 0, sizeof(ale_params));
19846f8d3f33SWingman Kwok 	ale_params.dev		= gbe_dev->dev;
19856f8d3f33SWingman Kwok 	ale_params.ale_regs	= gbe_dev->ale_reg;
19866f8d3f33SWingman Kwok 	ale_params.ale_ageout	= GBE_DEFAULT_ALE_AGEOUT;
19876f8d3f33SWingman Kwok 	ale_params.ale_entries	= gbe_dev->ale_entries;
19886f8d3f33SWingman Kwok 	ale_params.ale_ports	= gbe_dev->ale_ports;
19896f8d3f33SWingman Kwok 
19906f8d3f33SWingman Kwok 	gbe_dev->ale = cpsw_ale_create(&ale_params);
19916f8d3f33SWingman Kwok 	if (!gbe_dev->ale) {
19926f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "error initializing ale engine\n");
19936f8d3f33SWingman Kwok 		ret = -ENODEV;
19946f8d3f33SWingman Kwok 		goto quit;
19956f8d3f33SWingman Kwok 	} else {
19966f8d3f33SWingman Kwok 		dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
19976f8d3f33SWingman Kwok 	}
19986f8d3f33SWingman Kwok 
19996f8d3f33SWingman Kwok 	/* initialize host port */
20006f8d3f33SWingman Kwok 	gbe_init_host_port(gbe_dev);
20016f8d3f33SWingman Kwok 
20026f8d3f33SWingman Kwok 	init_timer(&gbe_dev->timer);
20036f8d3f33SWingman Kwok 	gbe_dev->timer.data	 = (unsigned long)gbe_dev;
20046f8d3f33SWingman Kwok 	gbe_dev->timer.function = netcp_ethss_timer;
20056f8d3f33SWingman Kwok 	gbe_dev->timer.expires	 = jiffies + GBE_TIMER_INTERVAL;
20066f8d3f33SWingman Kwok 	add_timer(&gbe_dev->timer);
20076f8d3f33SWingman Kwok 	*inst_priv = gbe_dev;
20086f8d3f33SWingman Kwok 	return 0;
20096f8d3f33SWingman Kwok 
20106f8d3f33SWingman Kwok quit:
20116f8d3f33SWingman Kwok 	if (gbe_dev->hw_stats)
20126f8d3f33SWingman Kwok 		devm_kfree(dev, gbe_dev->hw_stats);
20136f8d3f33SWingman Kwok 	if (gbe_dev->ale)
20146f8d3f33SWingman Kwok 		cpsw_ale_destroy(gbe_dev->ale);
20156f8d3f33SWingman Kwok 	if (gbe_dev->ss_regs)
20166f8d3f33SWingman Kwok 		devm_iounmap(dev, gbe_dev->ss_regs);
20176f8d3f33SWingman Kwok 	if (interfaces)
20186f8d3f33SWingman Kwok 		of_node_put(interfaces);
20196f8d3f33SWingman Kwok 	devm_kfree(dev, gbe_dev);
20206f8d3f33SWingman Kwok 	return ret;
20216f8d3f33SWingman Kwok }
20226f8d3f33SWingman Kwok 
20236f8d3f33SWingman Kwok static int gbe_attach(void *inst_priv, struct net_device *ndev,
20246f8d3f33SWingman Kwok 		      struct device_node *node, void **intf_priv)
20256f8d3f33SWingman Kwok {
20266f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = inst_priv;
20276f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf;
20286f8d3f33SWingman Kwok 	int ret;
20296f8d3f33SWingman Kwok 
20306f8d3f33SWingman Kwok 	if (!node) {
20316f8d3f33SWingman Kwok 		dev_err(gbe_dev->dev, "interface node not available\n");
20326f8d3f33SWingman Kwok 		return -ENODEV;
20336f8d3f33SWingman Kwok 	}
20346f8d3f33SWingman Kwok 
20356f8d3f33SWingman Kwok 	gbe_intf = devm_kzalloc(gbe_dev->dev, sizeof(*gbe_intf), GFP_KERNEL);
20366f8d3f33SWingman Kwok 	if (!gbe_intf)
20376f8d3f33SWingman Kwok 		return -ENOMEM;
20386f8d3f33SWingman Kwok 
20396f8d3f33SWingman Kwok 	gbe_intf->ndev = ndev;
20406f8d3f33SWingman Kwok 	gbe_intf->dev = gbe_dev->dev;
20416f8d3f33SWingman Kwok 	gbe_intf->gbe_dev = gbe_dev;
20426f8d3f33SWingman Kwok 
20436f8d3f33SWingman Kwok 	gbe_intf->slave = devm_kzalloc(gbe_dev->dev,
20446f8d3f33SWingman Kwok 					sizeof(*gbe_intf->slave),
20456f8d3f33SWingman Kwok 					GFP_KERNEL);
20466f8d3f33SWingman Kwok 	if (!gbe_intf->slave) {
20476f8d3f33SWingman Kwok 		ret = -ENOMEM;
20486f8d3f33SWingman Kwok 		goto fail;
20496f8d3f33SWingman Kwok 	}
20506f8d3f33SWingman Kwok 
20516f8d3f33SWingman Kwok 	if (init_slave(gbe_dev, gbe_intf->slave, node)) {
20526f8d3f33SWingman Kwok 		ret = -ENODEV;
20536f8d3f33SWingman Kwok 		goto fail;
20546f8d3f33SWingman Kwok 	}
20556f8d3f33SWingman Kwok 
20566f8d3f33SWingman Kwok 	gbe_intf->tx_pipe = gbe_dev->tx_pipe;
20576f8d3f33SWingman Kwok 	ndev->ethtool_ops = &keystone_ethtool_ops;
20586f8d3f33SWingman Kwok 	list_add_tail(&gbe_intf->gbe_intf_list, &gbe_dev->gbe_intf_head);
20596f8d3f33SWingman Kwok 	*intf_priv = gbe_intf;
20606f8d3f33SWingman Kwok 	return 0;
20616f8d3f33SWingman Kwok 
20626f8d3f33SWingman Kwok fail:
20636f8d3f33SWingman Kwok 	if (gbe_intf->slave)
20646f8d3f33SWingman Kwok 		devm_kfree(gbe_dev->dev, gbe_intf->slave);
20656f8d3f33SWingman Kwok 	if (gbe_intf)
20666f8d3f33SWingman Kwok 		devm_kfree(gbe_dev->dev, gbe_intf);
20676f8d3f33SWingman Kwok 	return ret;
20686f8d3f33SWingman Kwok }
20696f8d3f33SWingman Kwok 
20706f8d3f33SWingman Kwok static int gbe_release(void *intf_priv)
20716f8d3f33SWingman Kwok {
20726f8d3f33SWingman Kwok 	struct gbe_intf *gbe_intf = intf_priv;
20736f8d3f33SWingman Kwok 
20746f8d3f33SWingman Kwok 	gbe_intf->ndev->ethtool_ops = NULL;
20756f8d3f33SWingman Kwok 	list_del(&gbe_intf->gbe_intf_list);
20766f8d3f33SWingman Kwok 	devm_kfree(gbe_intf->dev, gbe_intf->slave);
20776f8d3f33SWingman Kwok 	devm_kfree(gbe_intf->dev, gbe_intf);
20786f8d3f33SWingman Kwok 	return 0;
20796f8d3f33SWingman Kwok }
20806f8d3f33SWingman Kwok 
20816f8d3f33SWingman Kwok static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
20826f8d3f33SWingman Kwok {
20836f8d3f33SWingman Kwok 	struct gbe_priv *gbe_dev = inst_priv;
20846f8d3f33SWingman Kwok 
20856f8d3f33SWingman Kwok 	del_timer_sync(&gbe_dev->timer);
20866f8d3f33SWingman Kwok 	cpsw_ale_stop(gbe_dev->ale);
20876f8d3f33SWingman Kwok 	cpsw_ale_destroy(gbe_dev->ale);
20886f8d3f33SWingman Kwok 	netcp_txpipe_close(&gbe_dev->tx_pipe);
20896f8d3f33SWingman Kwok 	free_secondary_ports(gbe_dev);
20906f8d3f33SWingman Kwok 
20916f8d3f33SWingman Kwok 	if (!list_empty(&gbe_dev->gbe_intf_head))
20926f8d3f33SWingman Kwok 		dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n");
20936f8d3f33SWingman Kwok 
20946f8d3f33SWingman Kwok 	devm_kfree(gbe_dev->dev, gbe_dev->hw_stats);
20956f8d3f33SWingman Kwok 	devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs);
20966f8d3f33SWingman Kwok 	memset(gbe_dev, 0x00, sizeof(*gbe_dev));
20976f8d3f33SWingman Kwok 	devm_kfree(gbe_dev->dev, gbe_dev);
20986f8d3f33SWingman Kwok 	return 0;
20996f8d3f33SWingman Kwok }
21006f8d3f33SWingman Kwok 
21016f8d3f33SWingman Kwok static struct netcp_module gbe_module = {
21026f8d3f33SWingman Kwok 	.name		= GBE_MODULE_NAME,
21036f8d3f33SWingman Kwok 	.owner		= THIS_MODULE,
21046f8d3f33SWingman Kwok 	.primary	= true,
21056f8d3f33SWingman Kwok 	.probe		= gbe_probe,
21066f8d3f33SWingman Kwok 	.open		= gbe_open,
21076f8d3f33SWingman Kwok 	.close		= gbe_close,
21086f8d3f33SWingman Kwok 	.remove		= gbe_remove,
21096f8d3f33SWingman Kwok 	.attach		= gbe_attach,
21106f8d3f33SWingman Kwok 	.release	= gbe_release,
21116f8d3f33SWingman Kwok 	.add_addr	= gbe_add_addr,
21126f8d3f33SWingman Kwok 	.del_addr	= gbe_del_addr,
21136f8d3f33SWingman Kwok 	.add_vid	= gbe_add_vid,
21146f8d3f33SWingman Kwok 	.del_vid	= gbe_del_vid,
21156f8d3f33SWingman Kwok 	.ioctl		= gbe_ioctl,
21166f8d3f33SWingman Kwok };
21176f8d3f33SWingman Kwok 
211890cff9e2SWingman Kwok static struct netcp_module xgbe_module = {
211990cff9e2SWingman Kwok 	.name		= XGBE_MODULE_NAME,
212090cff9e2SWingman Kwok 	.owner		= THIS_MODULE,
212190cff9e2SWingman Kwok 	.primary	= true,
212290cff9e2SWingman Kwok 	.probe		= gbe_probe,
212390cff9e2SWingman Kwok 	.open		= gbe_open,
212490cff9e2SWingman Kwok 	.close		= gbe_close,
212590cff9e2SWingman Kwok 	.remove		= gbe_remove,
212690cff9e2SWingman Kwok 	.attach		= gbe_attach,
212790cff9e2SWingman Kwok 	.release	= gbe_release,
212890cff9e2SWingman Kwok 	.add_addr	= gbe_add_addr,
212990cff9e2SWingman Kwok 	.del_addr	= gbe_del_addr,
213090cff9e2SWingman Kwok 	.add_vid	= gbe_add_vid,
213190cff9e2SWingman Kwok 	.del_vid	= gbe_del_vid,
213290cff9e2SWingman Kwok 	.ioctl		= gbe_ioctl,
213390cff9e2SWingman Kwok };
213490cff9e2SWingman Kwok 
21356f8d3f33SWingman Kwok static int __init keystone_gbe_init(void)
21366f8d3f33SWingman Kwok {
21376f8d3f33SWingman Kwok 	int ret;
21386f8d3f33SWingman Kwok 
21396f8d3f33SWingman Kwok 	ret = netcp_register_module(&gbe_module);
21406f8d3f33SWingman Kwok 	if (ret)
21416f8d3f33SWingman Kwok 		return ret;
21426f8d3f33SWingman Kwok 
214390cff9e2SWingman Kwok 	ret = netcp_register_module(&xgbe_module);
214490cff9e2SWingman Kwok 	if (ret)
214590cff9e2SWingman Kwok 		return ret;
214690cff9e2SWingman Kwok 
21476f8d3f33SWingman Kwok 	return 0;
21486f8d3f33SWingman Kwok }
21496f8d3f33SWingman Kwok module_init(keystone_gbe_init);
21506f8d3f33SWingman Kwok 
21516f8d3f33SWingman Kwok static void __exit keystone_gbe_exit(void)
21526f8d3f33SWingman Kwok {
21536f8d3f33SWingman Kwok 	netcp_unregister_module(&gbe_module);
215490cff9e2SWingman Kwok 	netcp_unregister_module(&xgbe_module);
21556f8d3f33SWingman Kwok }
21566f8d3f33SWingman Kwok module_exit(keystone_gbe_exit);
2157