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