156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 256051948SVladimir Oltean /* Copyright 2019 NXP Semiconductors 356051948SVladimir Oltean */ 456051948SVladimir Oltean #include <uapi/linux/if_bridge.h> 507d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h> 6bdeced75SVladimir Oltean #include <soc/mscc/ocelot_qsys.h> 7bdeced75SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 8bdeced75SVladimir Oltean #include <soc/mscc/ocelot_dev.h> 9bdeced75SVladimir Oltean #include <soc/mscc/ocelot_ana.h> 102b49d128SYangbo Lu #include <soc/mscc/ocelot_ptp.h> 1156051948SVladimir Oltean #include <soc/mscc/ocelot.h> 12c0bcf537SYangbo Lu #include <linux/packing.h> 1356051948SVladimir Oltean #include <linux/module.h> 14bdeced75SVladimir Oltean #include <linux/of_net.h> 1556051948SVladimir Oltean #include <linux/pci.h> 1656051948SVladimir Oltean #include <linux/of.h> 17fc411eaaSVladimir Oltean #include <net/pkt_sched.h> 1856051948SVladimir Oltean #include <net/dsa.h> 1956051948SVladimir Oltean #include "felix.h" 2056051948SVladimir Oltean 2156051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 224d776482SFlorian Fainelli int port, 234d776482SFlorian Fainelli enum dsa_tag_protocol mp) 2456051948SVladimir Oltean { 2556051948SVladimir Oltean return DSA_TAG_PROTO_OCELOT; 2656051948SVladimir Oltean } 2756051948SVladimir Oltean 2856051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 2956051948SVladimir Oltean unsigned int ageing_time) 3056051948SVladimir Oltean { 3156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 3256051948SVladimir Oltean 3356051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 3456051948SVladimir Oltean 3556051948SVladimir Oltean return 0; 3656051948SVladimir Oltean } 3756051948SVladimir Oltean 3856051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 3956051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 4056051948SVladimir Oltean { 4156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4256051948SVladimir Oltean 4356051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 4456051948SVladimir Oltean } 4556051948SVladimir Oltean 4656051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 4756051948SVladimir Oltean const unsigned char *addr, u16 vid) 4856051948SVladimir Oltean { 4956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5056051948SVladimir Oltean 5187b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 5256051948SVladimir Oltean } 5356051948SVladimir Oltean 5456051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 5556051948SVladimir Oltean const unsigned char *addr, u16 vid) 5656051948SVladimir Oltean { 5756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5856051948SVladimir Oltean 5956051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 6056051948SVladimir Oltean } 6156051948SVladimir Oltean 62209edf95SVladimir Oltean /* This callback needs to be present */ 63209edf95SVladimir Oltean static int felix_mdb_prepare(struct dsa_switch *ds, int port, 64209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 65209edf95SVladimir Oltean { 66209edf95SVladimir Oltean return 0; 67209edf95SVladimir Oltean } 68209edf95SVladimir Oltean 69209edf95SVladimir Oltean static void felix_mdb_add(struct dsa_switch *ds, int port, 70209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 71209edf95SVladimir Oltean { 72209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 73209edf95SVladimir Oltean 74209edf95SVladimir Oltean ocelot_port_mdb_add(ocelot, port, mdb); 75209edf95SVladimir Oltean } 76209edf95SVladimir Oltean 77209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 78209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 79209edf95SVladimir Oltean { 80209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 81209edf95SVladimir Oltean 82209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 83209edf95SVladimir Oltean } 84209edf95SVladimir Oltean 8556051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 8656051948SVladimir Oltean u8 state) 8756051948SVladimir Oltean { 8856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 8956051948SVladimir Oltean 9056051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 9156051948SVladimir Oltean } 9256051948SVladimir Oltean 9356051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 9456051948SVladimir Oltean struct net_device *br) 9556051948SVladimir Oltean { 9656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 9756051948SVladimir Oltean 9856051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 9956051948SVladimir Oltean } 10056051948SVladimir Oltean 10156051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 10256051948SVladimir Oltean struct net_device *br) 10356051948SVladimir Oltean { 10456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 10556051948SVladimir Oltean 10656051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 10756051948SVladimir Oltean } 10856051948SVladimir Oltean 10956051948SVladimir Oltean /* This callback needs to be present */ 11056051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 11156051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 11256051948SVladimir Oltean { 11356051948SVladimir Oltean return 0; 11456051948SVladimir Oltean } 11556051948SVladimir Oltean 11656051948SVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 11756051948SVladimir Oltean { 11856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 11956051948SVladimir Oltean 12056051948SVladimir Oltean ocelot_port_vlan_filtering(ocelot, port, enabled); 12156051948SVladimir Oltean 12256051948SVladimir Oltean return 0; 12356051948SVladimir Oltean } 12456051948SVladimir Oltean 12556051948SVladimir Oltean static void felix_vlan_add(struct dsa_switch *ds, int port, 12656051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 12756051948SVladimir Oltean { 12856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 129183be6f9SVladimir Oltean u16 flags = vlan->flags; 13056051948SVladimir Oltean u16 vid; 13156051948SVladimir Oltean int err; 13256051948SVladimir Oltean 133183be6f9SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 134183be6f9SVladimir Oltean flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; 135183be6f9SVladimir Oltean 13656051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 13756051948SVladimir Oltean err = ocelot_vlan_add(ocelot, port, vid, 138183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 139183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 14056051948SVladimir Oltean if (err) { 14156051948SVladimir Oltean dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n", 14256051948SVladimir Oltean vid, port, err); 14356051948SVladimir Oltean return; 14456051948SVladimir Oltean } 14556051948SVladimir Oltean } 14656051948SVladimir Oltean } 14756051948SVladimir Oltean 14856051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 14956051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 15056051948SVladimir Oltean { 15156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 15256051948SVladimir Oltean u16 vid; 15356051948SVladimir Oltean int err; 15456051948SVladimir Oltean 15556051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 15656051948SVladimir Oltean err = ocelot_vlan_del(ocelot, port, vid); 15756051948SVladimir Oltean if (err) { 15856051948SVladimir Oltean dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", 15956051948SVladimir Oltean vid, port, err); 16056051948SVladimir Oltean return err; 16156051948SVladimir Oltean } 16256051948SVladimir Oltean } 16356051948SVladimir Oltean return 0; 16456051948SVladimir Oltean } 16556051948SVladimir Oltean 16656051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 16756051948SVladimir Oltean struct phy_device *phy) 16856051948SVladimir Oltean { 16956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17056051948SVladimir Oltean 17156051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 17256051948SVladimir Oltean 17356051948SVladimir Oltean return 0; 17456051948SVladimir Oltean } 17556051948SVladimir Oltean 17656051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 17756051948SVladimir Oltean { 17856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17956051948SVladimir Oltean 18056051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 18156051948SVladimir Oltean } 18256051948SVladimir Oltean 183bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 184bdeced75SVladimir Oltean unsigned long *supported, 185bdeced75SVladimir Oltean struct phylink_link_state *state) 186bdeced75SVladimir Oltean { 187bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 188bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 189bdeced75SVladimir Oltean __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 190bdeced75SVladimir Oltean 191bdeced75SVladimir Oltean if (state->interface != PHY_INTERFACE_MODE_NA && 192bdeced75SVladimir Oltean state->interface != ocelot_port->phy_mode) { 193bdeced75SVladimir Oltean bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 194bdeced75SVladimir Oltean return; 195bdeced75SVladimir Oltean } 196bdeced75SVladimir Oltean 197bdeced75SVladimir Oltean phylink_set_port_modes(mask); 198bdeced75SVladimir Oltean phylink_set(mask, Autoneg); 199bdeced75SVladimir Oltean phylink_set(mask, Pause); 200bdeced75SVladimir Oltean phylink_set(mask, Asym_Pause); 201b1c7b874SVladimir Oltean phylink_set(mask, 10baseT_Half); 202bdeced75SVladimir Oltean phylink_set(mask, 10baseT_Full); 203b1c7b874SVladimir Oltean phylink_set(mask, 100baseT_Half); 204bdeced75SVladimir Oltean phylink_set(mask, 100baseT_Full); 205b1c7b874SVladimir Oltean phylink_set(mask, 1000baseT_Half); 206bdeced75SVladimir Oltean phylink_set(mask, 1000baseT_Full); 20774984a19SAlex Marginean 20828a134f5SVladimir Oltean if (state->interface == PHY_INTERFACE_MODE_INTERNAL || 209bdeced75SVladimir Oltean state->interface == PHY_INTERFACE_MODE_2500BASEX || 210bdeced75SVladimir Oltean state->interface == PHY_INTERFACE_MODE_USXGMII) { 211bdeced75SVladimir Oltean phylink_set(mask, 2500baseT_Full); 212bdeced75SVladimir Oltean phylink_set(mask, 2500baseX_Full); 213bdeced75SVladimir Oltean } 214bdeced75SVladimir Oltean 215bdeced75SVladimir Oltean bitmap_and(supported, supported, mask, 216bdeced75SVladimir Oltean __ETHTOOL_LINK_MODE_MASK_NBITS); 217bdeced75SVladimir Oltean bitmap_and(state->advertising, state->advertising, mask, 218bdeced75SVladimir Oltean __ETHTOOL_LINK_MODE_MASK_NBITS); 219bdeced75SVladimir Oltean } 220bdeced75SVladimir Oltean 221bdeced75SVladimir Oltean static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, 222bdeced75SVladimir Oltean struct phylink_link_state *state) 223bdeced75SVladimir Oltean { 224bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 225bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 226bdeced75SVladimir Oltean 227bdeced75SVladimir Oltean if (felix->info->pcs_link_state) 228bdeced75SVladimir Oltean felix->info->pcs_link_state(ocelot, port, state); 229bdeced75SVladimir Oltean 230bdeced75SVladimir Oltean return 0; 231bdeced75SVladimir Oltean } 232bdeced75SVladimir Oltean 233bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 234bdeced75SVladimir Oltean unsigned int link_an_mode, 235bdeced75SVladimir Oltean const struct phylink_link_state *state) 236bdeced75SVladimir Oltean { 237bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 238bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 239bdeced75SVladimir Oltean 240*7e14a2dcSVladimir Oltean if (felix->info->pcs_config) 241*7e14a2dcSVladimir Oltean felix->info->pcs_config(ocelot, port, link_an_mode, state); 242bdeced75SVladimir Oltean } 243bdeced75SVladimir Oltean 244bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 245bdeced75SVladimir Oltean unsigned int link_an_mode, 246bdeced75SVladimir Oltean phy_interface_t interface) 247bdeced75SVladimir Oltean { 248bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 249bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 250bdeced75SVladimir Oltean 251bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 252bdeced75SVladimir Oltean ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, 253bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE, port); 254bdeced75SVladimir Oltean } 255bdeced75SVladimir Oltean 256bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 257bdeced75SVladimir Oltean unsigned int link_an_mode, 258bdeced75SVladimir Oltean phy_interface_t interface, 2595b502a7bSRussell King struct phy_device *phydev, 2605b502a7bSRussell King int speed, int duplex, 2615b502a7bSRussell King bool tx_pause, bool rx_pause) 262bdeced75SVladimir Oltean { 263bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 264bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 265*7e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 266*7e14a2dcSVladimir Oltean u32 mac_fc_cfg; 267bdeced75SVladimir Oltean 268*7e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 269*7e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 270*7e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 271*7e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 272*7e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 273*7e14a2dcSVladimir Oltean * value). 274*7e14a2dcSVladimir Oltean */ 275*7e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 276*7e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 277*7e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 278*7e14a2dcSVladimir Oltean 279*7e14a2dcSVladimir Oltean switch (speed) { 280*7e14a2dcSVladimir Oltean case SPEED_10: 281*7e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 282*7e14a2dcSVladimir Oltean break; 283*7e14a2dcSVladimir Oltean case SPEED_100: 284*7e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 285*7e14a2dcSVladimir Oltean break; 286*7e14a2dcSVladimir Oltean case SPEED_1000: 287*7e14a2dcSVladimir Oltean case SPEED_2500: 288*7e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 289*7e14a2dcSVladimir Oltean break; 290*7e14a2dcSVladimir Oltean default: 291*7e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 292*7e14a2dcSVladimir Oltean port, speed); 293*7e14a2dcSVladimir Oltean return; 294*7e14a2dcSVladimir Oltean } 295*7e14a2dcSVladimir Oltean 296*7e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 297*7e14a2dcSVladimir Oltean * adaptation. 298*7e14a2dcSVladimir Oltean */ 299*7e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 300*7e14a2dcSVladimir Oltean 301*7e14a2dcSVladimir Oltean if (tx_pause) 302*7e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 303*7e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 304*7e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 305*7e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 306*7e14a2dcSVladimir Oltean 307*7e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 308*7e14a2dcSVladimir Oltean * specification in incoming pause frames. 309*7e14a2dcSVladimir Oltean */ 310*7e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 311*7e14a2dcSVladimir Oltean 312*7e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 313*7e14a2dcSVladimir Oltean 314*7e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 315*7e14a2dcSVladimir Oltean * enable MAC module 316*7e14a2dcSVladimir Oltean */ 317bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 318bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 319bdeced75SVladimir Oltean 320bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 321bdeced75SVladimir Oltean * MAC addresses. 322bdeced75SVladimir Oltean */ 323bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 324bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 325bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 326bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 327bdeced75SVladimir Oltean 328bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 329bdeced75SVladimir Oltean ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | 330bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | 331bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 332bdeced75SVladimir Oltean QSYS_SWITCH_PORT_MODE, port); 333*7e14a2dcSVladimir Oltean 334*7e14a2dcSVladimir Oltean if (felix->info->pcs_link_up) 335*7e14a2dcSVladimir Oltean felix->info->pcs_link_up(ocelot, port, link_an_mode, interface, 336*7e14a2dcSVladimir Oltean speed, duplex); 337*7e14a2dcSVladimir Oltean 338*7e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 339*7e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 340bdeced75SVladimir Oltean } 341bdeced75SVladimir Oltean 342bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 343bd2b3161SXiaoliang Yang { 344bd2b3161SXiaoliang Yang int i; 345bd2b3161SXiaoliang Yang 346bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 347bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 348bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 349bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 350bd2b3161SXiaoliang Yang port); 351bd2b3161SXiaoliang Yang 352bd2b3161SXiaoliang Yang for (i = 0; i < FELIX_NUM_TC * 2; i++) { 353bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 354bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 355bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 356bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 357bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 358bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 359bd2b3161SXiaoliang Yang port, i); 360bd2b3161SXiaoliang Yang } 361bd2b3161SXiaoliang Yang } 362bd2b3161SXiaoliang Yang 36356051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 36456051948SVladimir Oltean u32 stringset, u8 *data) 36556051948SVladimir Oltean { 36656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 36756051948SVladimir Oltean 36856051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 36956051948SVladimir Oltean } 37056051948SVladimir Oltean 37156051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 37256051948SVladimir Oltean { 37356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 37456051948SVladimir Oltean 37556051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 37656051948SVladimir Oltean } 37756051948SVladimir Oltean 37856051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 37956051948SVladimir Oltean { 38056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 38156051948SVladimir Oltean 38256051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 38356051948SVladimir Oltean } 38456051948SVladimir Oltean 38556051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 38656051948SVladimir Oltean struct ethtool_ts_info *info) 38756051948SVladimir Oltean { 38856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 38956051948SVladimir Oltean 39056051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 39156051948SVladimir Oltean } 39256051948SVladimir Oltean 393bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 394bdeced75SVladimir Oltean struct device_node *ports_node, 395bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 396bdeced75SVladimir Oltean { 397bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 398bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 399bdeced75SVladimir Oltean struct device_node *child; 400bdeced75SVladimir Oltean 40137fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 402bdeced75SVladimir Oltean phy_interface_t phy_mode; 403bdeced75SVladimir Oltean u32 port; 404bdeced75SVladimir Oltean int err; 405bdeced75SVladimir Oltean 406bdeced75SVladimir Oltean /* Get switch port number from DT */ 407bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 408bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 409bdeced75SVladimir Oltean "(property \"reg\")\n"); 410bdeced75SVladimir Oltean of_node_put(child); 411bdeced75SVladimir Oltean return -ENODEV; 412bdeced75SVladimir Oltean } 413bdeced75SVladimir Oltean 414bdeced75SVladimir Oltean /* Get PHY mode from DT */ 415bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 416bdeced75SVladimir Oltean if (err) { 417bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 418bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 419bdeced75SVladimir Oltean port); 420bdeced75SVladimir Oltean of_node_put(child); 421bdeced75SVladimir Oltean return -ENODEV; 422bdeced75SVladimir Oltean } 423bdeced75SVladimir Oltean 424bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 425bdeced75SVladimir Oltean if (err < 0) { 426bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 427bdeced75SVladimir Oltean phy_modes(phy_mode), port); 428bdeced75SVladimir Oltean return err; 429bdeced75SVladimir Oltean } 430bdeced75SVladimir Oltean 431bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 432bdeced75SVladimir Oltean } 433bdeced75SVladimir Oltean 434bdeced75SVladimir Oltean return 0; 435bdeced75SVladimir Oltean } 436bdeced75SVladimir Oltean 437bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 438bdeced75SVladimir Oltean { 439bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 440bdeced75SVladimir Oltean struct device_node *switch_node; 441bdeced75SVladimir Oltean struct device_node *ports_node; 442bdeced75SVladimir Oltean int err; 443bdeced75SVladimir Oltean 444bdeced75SVladimir Oltean switch_node = dev->of_node; 445bdeced75SVladimir Oltean 446bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 447bdeced75SVladimir Oltean if (!ports_node) { 448bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 449bdeced75SVladimir Oltean return -ENODEV; 450bdeced75SVladimir Oltean } 451bdeced75SVladimir Oltean 452bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 453bdeced75SVladimir Oltean of_node_put(ports_node); 454bdeced75SVladimir Oltean 455bdeced75SVladimir Oltean return err; 456bdeced75SVladimir Oltean } 457bdeced75SVladimir Oltean 45856051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 45956051948SVladimir Oltean { 46056051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 461bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 462bdeced75SVladimir Oltean resource_size_t switch_base; 463b4024c9eSClaudiu Manoil struct resource res; 46456051948SVladimir Oltean int port, i, err; 46556051948SVladimir Oltean 46656051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 46756051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 46856051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 46956051948SVladimir Oltean if (!ocelot->ports) 47056051948SVladimir Oltean return -ENOMEM; 47156051948SVladimir Oltean 47256051948SVladimir Oltean ocelot->map = felix->info->map; 47356051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 47456051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 47556051948SVladimir Oltean ocelot->shared_queue_sz = felix->info->shared_queue_sz; 47621ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 47707d985eeSVladimir Oltean ocelot->vcap_is2_keys = felix->info->vcap_is2_keys; 47807d985eeSVladimir Oltean ocelot->vcap_is2_actions= felix->info->vcap_is2_actions; 47907d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 48056051948SVladimir Oltean ocelot->ops = felix->info->ops; 48156051948SVladimir Oltean 482bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 483bdeced75SVladimir Oltean GFP_KERNEL); 484bdeced75SVladimir Oltean if (!port_phy_modes) 485bdeced75SVladimir Oltean return -ENOMEM; 486bdeced75SVladimir Oltean 487bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 488bdeced75SVladimir Oltean if (err) { 489bdeced75SVladimir Oltean kfree(port_phy_modes); 490bdeced75SVladimir Oltean return err; 491bdeced75SVladimir Oltean } 492bdeced75SVladimir Oltean 493bdeced75SVladimir Oltean switch_base = pci_resource_start(felix->pdev, 494bdeced75SVladimir Oltean felix->info->switch_pci_bar); 49556051948SVladimir Oltean 49656051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 49756051948SVladimir Oltean struct regmap *target; 49856051948SVladimir Oltean 49956051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 50056051948SVladimir Oltean continue; 50156051948SVladimir Oltean 502b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 503b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 504b4024c9eSClaudiu Manoil res.start += switch_base; 505b4024c9eSClaudiu Manoil res.end += switch_base; 50656051948SVladimir Oltean 507b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 50856051948SVladimir Oltean if (IS_ERR(target)) { 50956051948SVladimir Oltean dev_err(ocelot->dev, 51056051948SVladimir Oltean "Failed to map device memory space\n"); 511bdeced75SVladimir Oltean kfree(port_phy_modes); 51256051948SVladimir Oltean return PTR_ERR(target); 51356051948SVladimir Oltean } 51456051948SVladimir Oltean 51556051948SVladimir Oltean ocelot->targets[i] = target; 51656051948SVladimir Oltean } 51756051948SVladimir Oltean 51856051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 51956051948SVladimir Oltean if (err) { 52056051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 521bdeced75SVladimir Oltean kfree(port_phy_modes); 52256051948SVladimir Oltean return err; 52356051948SVladimir Oltean } 52456051948SVladimir Oltean 52556051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 52656051948SVladimir Oltean struct ocelot_port *ocelot_port; 52756051948SVladimir Oltean void __iomem *port_regs; 52856051948SVladimir Oltean 52956051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 53056051948SVladimir Oltean sizeof(struct ocelot_port), 53156051948SVladimir Oltean GFP_KERNEL); 53256051948SVladimir Oltean if (!ocelot_port) { 53356051948SVladimir Oltean dev_err(ocelot->dev, 53456051948SVladimir Oltean "failed to allocate port memory\n"); 535bdeced75SVladimir Oltean kfree(port_phy_modes); 53656051948SVladimir Oltean return -ENOMEM; 53756051948SVladimir Oltean } 53856051948SVladimir Oltean 539b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 540b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 541b4024c9eSClaudiu Manoil res.start += switch_base; 542b4024c9eSClaudiu Manoil res.end += switch_base; 54356051948SVladimir Oltean 544b4024c9eSClaudiu Manoil port_regs = devm_ioremap_resource(ocelot->dev, &res); 54556051948SVladimir Oltean if (IS_ERR(port_regs)) { 54656051948SVladimir Oltean dev_err(ocelot->dev, 54756051948SVladimir Oltean "failed to map registers for port %d\n", port); 548bdeced75SVladimir Oltean kfree(port_phy_modes); 54956051948SVladimir Oltean return PTR_ERR(port_regs); 55056051948SVladimir Oltean } 55156051948SVladimir Oltean 552bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 55356051948SVladimir Oltean ocelot_port->ocelot = ocelot; 55456051948SVladimir Oltean ocelot_port->regs = port_regs; 55556051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 55656051948SVladimir Oltean } 55756051948SVladimir Oltean 558bdeced75SVladimir Oltean kfree(port_phy_modes); 559bdeced75SVladimir Oltean 560bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 561bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 562bdeced75SVladimir Oltean if (err < 0) 563bdeced75SVladimir Oltean return err; 564bdeced75SVladimir Oltean } 565bdeced75SVladimir Oltean 56656051948SVladimir Oltean return 0; 56756051948SVladimir Oltean } 56856051948SVladimir Oltean 5692b49d128SYangbo Lu static struct ptp_clock_info ocelot_ptp_clock_info = { 5702b49d128SYangbo Lu .owner = THIS_MODULE, 5712b49d128SYangbo Lu .name = "felix ptp", 5722b49d128SYangbo Lu .max_adj = 0x7fffffff, 5732b49d128SYangbo Lu .n_alarm = 0, 5742b49d128SYangbo Lu .n_ext_ts = 0, 5755287be40SYangbo Lu .n_per_out = OCELOT_PTP_PINS_NUM, 5765287be40SYangbo Lu .n_pins = OCELOT_PTP_PINS_NUM, 5772b49d128SYangbo Lu .pps = 0, 5782b49d128SYangbo Lu .gettime64 = ocelot_ptp_gettime64, 5792b49d128SYangbo Lu .settime64 = ocelot_ptp_settime64, 5802b49d128SYangbo Lu .adjtime = ocelot_ptp_adjtime, 5812b49d128SYangbo Lu .adjfine = ocelot_ptp_adjfine, 5825287be40SYangbo Lu .verify = ocelot_ptp_verify, 5835287be40SYangbo Lu .enable = ocelot_ptp_enable, 5842b49d128SYangbo Lu }; 5852b49d128SYangbo Lu 58656051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 58756051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 58856051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 58956051948SVladimir Oltean * (which will not work). 59056051948SVladimir Oltean */ 59156051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 59256051948SVladimir Oltean { 59356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 59456051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 59556051948SVladimir Oltean int port, err; 5963c7b51bdSXiaoliang Yang int tc; 59756051948SVladimir Oltean 59856051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 59956051948SVladimir Oltean if (err) 60056051948SVladimir Oltean return err; 60156051948SVladimir Oltean 60256051948SVladimir Oltean ocelot_init(ocelot); 6032b49d128SYangbo Lu if (ocelot->ptp) { 6042b49d128SYangbo Lu err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); 6052b49d128SYangbo Lu if (err) { 6062b49d128SYangbo Lu dev_err(ocelot->dev, 6072b49d128SYangbo Lu "Timestamp initialization failed\n"); 6082b49d128SYangbo Lu ocelot->ptp = 0; 6092b49d128SYangbo Lu } 6102b49d128SYangbo Lu } 61156051948SVladimir Oltean 61256051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 61356051948SVladimir Oltean ocelot_init_port(ocelot, port); 61456051948SVladimir Oltean 61569df578cSVladimir Oltean /* Bring up the CPU port module and configure the NPI port */ 616b8fc7177SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 61769df578cSVladimir Oltean ocelot_configure_cpu(ocelot, port, 61856051948SVladimir Oltean OCELOT_TAG_PREFIX_NONE, 61956051948SVladimir Oltean OCELOT_TAG_PREFIX_LONG); 620bd2b3161SXiaoliang Yang 621bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 622bd2b3161SXiaoliang Yang * bits of vlan tag. 623bd2b3161SXiaoliang Yang */ 624bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 62556051948SVladimir Oltean } 62656051948SVladimir Oltean 6271cf3299bSVladimir Oltean /* Include the CPU port module in the forwarding mask for unknown 6281cf3299bSVladimir Oltean * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST 6291cf3299bSVladimir Oltean * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since 6301cf3299bSVladimir Oltean * Ocelot relies on whitelisting MAC addresses towards PGID_CPU. 6311cf3299bSVladimir Oltean */ 6321cf3299bSVladimir Oltean ocelot_write_rix(ocelot, 6331cf3299bSVladimir Oltean ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)), 6341cf3299bSVladimir Oltean ANA_PGID_PGID, PGID_UC); 6353c7b51bdSXiaoliang Yang /* Setup the per-traffic class flooding PGIDs */ 6363c7b51bdSXiaoliang Yang for (tc = 0; tc < FELIX_NUM_TC; tc++) 6373c7b51bdSXiaoliang Yang ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) | 6383c7b51bdSXiaoliang Yang ANA_FLOODING_FLD_BROADCAST(PGID_MC) | 6393c7b51bdSXiaoliang Yang ANA_FLOODING_FLD_UNICAST(PGID_UC), 6403c7b51bdSXiaoliang Yang ANA_FLOODING, tc); 6411cf3299bSVladimir Oltean 6420b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 643626a8323SVladimir Oltean ds->configure_vlan_while_not_filtering = true; 644bdeced75SVladimir Oltean /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040) 645bdeced75SVladimir Oltean * isn't instantiated for the Felix PF. 646bdeced75SVladimir Oltean * In-band AN may take a few ms to complete, so we need to poll. 647bdeced75SVladimir Oltean */ 648bdeced75SVladimir Oltean ds->pcs_poll = true; 649bdeced75SVladimir Oltean 65056051948SVladimir Oltean return 0; 65156051948SVladimir Oltean } 65256051948SVladimir Oltean 65356051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 65456051948SVladimir Oltean { 65556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 656bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 657bdeced75SVladimir Oltean 658bdeced75SVladimir Oltean if (felix->info->mdio_bus_free) 659bdeced75SVladimir Oltean felix->info->mdio_bus_free(ocelot); 66056051948SVladimir Oltean 6612b49d128SYangbo Lu ocelot_deinit_timestamp(ocelot); 66256051948SVladimir Oltean /* stop workqueue thread */ 66356051948SVladimir Oltean ocelot_deinit(ocelot); 66456051948SVladimir Oltean } 66556051948SVladimir Oltean 666c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 667c0bcf537SYangbo Lu struct ifreq *ifr) 668c0bcf537SYangbo Lu { 669c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 670c0bcf537SYangbo Lu 671c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 672c0bcf537SYangbo Lu } 673c0bcf537SYangbo Lu 674c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 675c0bcf537SYangbo Lu struct ifreq *ifr) 676c0bcf537SYangbo Lu { 677c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 678c0bcf537SYangbo Lu 679c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 680c0bcf537SYangbo Lu } 681c0bcf537SYangbo Lu 682c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 683c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 684c0bcf537SYangbo Lu { 685c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 686c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 687c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 688c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 689c0bcf537SYangbo Lu struct timespec64 ts; 690c0bcf537SYangbo Lu u64 tstamp, val; 691c0bcf537SYangbo Lu 692c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 693c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 694c0bcf537SYangbo Lu 695c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 696c0bcf537SYangbo Lu tstamp_lo = (u32)val; 697c0bcf537SYangbo Lu 698c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 699c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 700c0bcf537SYangbo Lu tstamp_hi--; 701c0bcf537SYangbo Lu 702c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 703c0bcf537SYangbo Lu 704c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 705c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 706c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 707c0bcf537SYangbo Lu return false; 708c0bcf537SYangbo Lu } 709c0bcf537SYangbo Lu 7103243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 711c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 712c0bcf537SYangbo Lu { 713c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 714c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 715c0bcf537SYangbo Lu 716c0bcf537SYangbo Lu if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone)) 717c0bcf537SYangbo Lu return true; 718c0bcf537SYangbo Lu 719c0bcf537SYangbo Lu return false; 720c0bcf537SYangbo Lu } 721c0bcf537SYangbo Lu 7220b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 7230b912fc9SVladimir Oltean { 7240b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 7250b912fc9SVladimir Oltean 7260b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 7270b912fc9SVladimir Oltean 7280b912fc9SVladimir Oltean return 0; 7290b912fc9SVladimir Oltean } 7300b912fc9SVladimir Oltean 7310b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 7320b912fc9SVladimir Oltean { 7330b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 7340b912fc9SVladimir Oltean 7350b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 7360b912fc9SVladimir Oltean } 7370b912fc9SVladimir Oltean 73807d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 73907d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 74007d985eeSVladimir Oltean { 74107d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 74207d985eeSVladimir Oltean 74307d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 74407d985eeSVladimir Oltean } 74507d985eeSVladimir Oltean 74607d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 74707d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 74807d985eeSVladimir Oltean { 74907d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 75007d985eeSVladimir Oltean 75107d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 75207d985eeSVladimir Oltean } 75307d985eeSVladimir Oltean 75407d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 75507d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 75607d985eeSVladimir Oltean { 75707d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 75807d985eeSVladimir Oltean 75907d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 76007d985eeSVladimir Oltean } 76107d985eeSVladimir Oltean 762fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 763fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 764fc411eaaSVladimir Oltean { 765fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 766fc411eaaSVladimir Oltean struct ocelot_policer pol = { 767fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 7685f035af7SPo Liu .burst = policer->burst, 769fc411eaaSVladimir Oltean }; 770fc411eaaSVladimir Oltean 771fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 772fc411eaaSVladimir Oltean } 773fc411eaaSVladimir Oltean 774fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 775fc411eaaSVladimir Oltean { 776fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 777fc411eaaSVladimir Oltean 778fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 779fc411eaaSVladimir Oltean } 780fc411eaaSVladimir Oltean 781de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 782de143c0eSXiaoliang Yang enum tc_setup_type type, 783de143c0eSXiaoliang Yang void *type_data) 784de143c0eSXiaoliang Yang { 785de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 786de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 787de143c0eSXiaoliang Yang 788de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 789de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 790de143c0eSXiaoliang Yang else 791de143c0eSXiaoliang Yang return -EOPNOTSUPP; 792de143c0eSXiaoliang Yang } 793de143c0eSXiaoliang Yang 79456051948SVladimir Oltean static const struct dsa_switch_ops felix_switch_ops = { 79556051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 79656051948SVladimir Oltean .setup = felix_setup, 79756051948SVladimir Oltean .teardown = felix_teardown, 79856051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 79956051948SVladimir Oltean .get_strings = felix_get_strings, 80056051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 80156051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 80256051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 803bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 804bdeced75SVladimir Oltean .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, 805bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 806bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 807bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 80856051948SVladimir Oltean .port_enable = felix_port_enable, 80956051948SVladimir Oltean .port_disable = felix_port_disable, 81056051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 81156051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 81256051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 813209edf95SVladimir Oltean .port_mdb_prepare = felix_mdb_prepare, 814209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 815209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 81656051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 81756051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 81856051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 81956051948SVladimir Oltean .port_vlan_prepare = felix_vlan_prepare, 82056051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 82156051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 82256051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 823c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 824c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 825c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 826c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 8270b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 8280b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 829fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 830fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 83107d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 83207d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 83307d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 834de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 83556051948SVladimir Oltean }; 83656051948SVladimir Oltean 83756051948SVladimir Oltean static struct felix_info *felix_instance_tbl[] = { 83856051948SVladimir Oltean [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959, 83956051948SVladimir Oltean }; 84056051948SVladimir Oltean 841c0bcf537SYangbo Lu static irqreturn_t felix_irq_handler(int irq, void *data) 842c0bcf537SYangbo Lu { 843c0bcf537SYangbo Lu struct ocelot *ocelot = (struct ocelot *)data; 844c0bcf537SYangbo Lu 845c0bcf537SYangbo Lu /* The INTB interrupt is used for both PTP TX timestamp interrupt 846c0bcf537SYangbo Lu * and preemption status change interrupt on each port. 847c0bcf537SYangbo Lu * 848c0bcf537SYangbo Lu * - Get txtstamp if have 849c0bcf537SYangbo Lu * - TODO: handle preemption. Without handling it, driver may get 850c0bcf537SYangbo Lu * interrupt storm. 851c0bcf537SYangbo Lu */ 852c0bcf537SYangbo Lu 853c0bcf537SYangbo Lu ocelot_get_txtstamp(ocelot); 854c0bcf537SYangbo Lu 855c0bcf537SYangbo Lu return IRQ_HANDLED; 856c0bcf537SYangbo Lu } 857c0bcf537SYangbo Lu 85856051948SVladimir Oltean static int felix_pci_probe(struct pci_dev *pdev, 85956051948SVladimir Oltean const struct pci_device_id *id) 86056051948SVladimir Oltean { 86156051948SVladimir Oltean enum felix_instance instance = id->driver_data; 86256051948SVladimir Oltean struct dsa_switch *ds; 86356051948SVladimir Oltean struct ocelot *ocelot; 86456051948SVladimir Oltean struct felix *felix; 86556051948SVladimir Oltean int err; 86656051948SVladimir Oltean 867e90c9fceSMichael Walle if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { 868e90c9fceSMichael Walle dev_info(&pdev->dev, "device is disabled, skipping\n"); 869e90c9fceSMichael Walle return -ENODEV; 870e90c9fceSMichael Walle } 871e90c9fceSMichael Walle 87256051948SVladimir Oltean err = pci_enable_device(pdev); 87356051948SVladimir Oltean if (err) { 87456051948SVladimir Oltean dev_err(&pdev->dev, "device enable failed\n"); 87556051948SVladimir Oltean goto err_pci_enable; 87656051948SVladimir Oltean } 87756051948SVladimir Oltean 87856051948SVladimir Oltean /* set up for high or low dma */ 87956051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 88056051948SVladimir Oltean if (err) { 88156051948SVladimir Oltean err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 88256051948SVladimir Oltean if (err) { 88356051948SVladimir Oltean dev_err(&pdev->dev, 88456051948SVladimir Oltean "DMA configuration failed: 0x%x\n", err); 88556051948SVladimir Oltean goto err_dma; 88656051948SVladimir Oltean } 88756051948SVladimir Oltean } 88856051948SVladimir Oltean 88956051948SVladimir Oltean felix = kzalloc(sizeof(struct felix), GFP_KERNEL); 89056051948SVladimir Oltean if (!felix) { 89156051948SVladimir Oltean err = -ENOMEM; 89256051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate driver memory\n"); 89356051948SVladimir Oltean goto err_alloc_felix; 89456051948SVladimir Oltean } 89556051948SVladimir Oltean 89656051948SVladimir Oltean pci_set_drvdata(pdev, felix); 89756051948SVladimir Oltean ocelot = &felix->ocelot; 89856051948SVladimir Oltean ocelot->dev = &pdev->dev; 89956051948SVladimir Oltean felix->pdev = pdev; 90056051948SVladimir Oltean felix->info = felix_instance_tbl[instance]; 90156051948SVladimir Oltean 90256051948SVladimir Oltean pci_set_master(pdev); 90356051948SVladimir Oltean 904c0bcf537SYangbo Lu err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, 905c0bcf537SYangbo Lu &felix_irq_handler, IRQF_ONESHOT, 906c0bcf537SYangbo Lu "felix-intb", ocelot); 907c0bcf537SYangbo Lu if (err) { 908c0bcf537SYangbo Lu dev_err(&pdev->dev, "Failed to request irq\n"); 909c0bcf537SYangbo Lu goto err_alloc_irq; 910c0bcf537SYangbo Lu } 911c0bcf537SYangbo Lu 912c0bcf537SYangbo Lu ocelot->ptp = 1; 913c0bcf537SYangbo Lu 91456051948SVladimir Oltean ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); 91556051948SVladimir Oltean if (!ds) { 91656051948SVladimir Oltean err = -ENOMEM; 91756051948SVladimir Oltean dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); 91856051948SVladimir Oltean goto err_alloc_ds; 91956051948SVladimir Oltean } 92056051948SVladimir Oltean 92156051948SVladimir Oltean ds->dev = &pdev->dev; 92256051948SVladimir Oltean ds->num_ports = felix->info->num_ports; 923de143c0eSXiaoliang Yang ds->num_tx_queues = felix->info->num_tx_queues; 92456051948SVladimir Oltean ds->ops = &felix_switch_ops; 92556051948SVladimir Oltean ds->priv = ocelot; 92656051948SVladimir Oltean felix->ds = ds; 92756051948SVladimir Oltean 92856051948SVladimir Oltean err = dsa_register_switch(ds); 92956051948SVladimir Oltean if (err) { 93056051948SVladimir Oltean dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err); 93156051948SVladimir Oltean goto err_register_ds; 93256051948SVladimir Oltean } 93356051948SVladimir Oltean 93456051948SVladimir Oltean return 0; 93556051948SVladimir Oltean 93656051948SVladimir Oltean err_register_ds: 93756051948SVladimir Oltean kfree(ds); 93856051948SVladimir Oltean err_alloc_ds: 939c0bcf537SYangbo Lu err_alloc_irq: 94056051948SVladimir Oltean err_alloc_felix: 94156051948SVladimir Oltean kfree(felix); 94256051948SVladimir Oltean err_dma: 94356051948SVladimir Oltean pci_disable_device(pdev); 94456051948SVladimir Oltean err_pci_enable: 94556051948SVladimir Oltean return err; 94656051948SVladimir Oltean } 94756051948SVladimir Oltean 94856051948SVladimir Oltean static void felix_pci_remove(struct pci_dev *pdev) 94956051948SVladimir Oltean { 95056051948SVladimir Oltean struct felix *felix; 95156051948SVladimir Oltean 95256051948SVladimir Oltean felix = pci_get_drvdata(pdev); 95356051948SVladimir Oltean 95456051948SVladimir Oltean dsa_unregister_switch(felix->ds); 95556051948SVladimir Oltean 95656051948SVladimir Oltean kfree(felix->ds); 95756051948SVladimir Oltean kfree(felix); 95856051948SVladimir Oltean 95956051948SVladimir Oltean pci_disable_device(pdev); 96056051948SVladimir Oltean } 96156051948SVladimir Oltean 96256051948SVladimir Oltean static struct pci_device_id felix_ids[] = { 96356051948SVladimir Oltean { 96456051948SVladimir Oltean /* NXP LS1028A */ 96556051948SVladimir Oltean PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), 96656051948SVladimir Oltean .driver_data = FELIX_INSTANCE_VSC9959, 96756051948SVladimir Oltean }, 96856051948SVladimir Oltean { 0, } 96956051948SVladimir Oltean }; 97056051948SVladimir Oltean MODULE_DEVICE_TABLE(pci, felix_ids); 97156051948SVladimir Oltean 97256051948SVladimir Oltean static struct pci_driver felix_pci_driver = { 97356051948SVladimir Oltean .name = KBUILD_MODNAME, 97456051948SVladimir Oltean .id_table = felix_ids, 97556051948SVladimir Oltean .probe = felix_pci_probe, 97656051948SVladimir Oltean .remove = felix_pci_remove, 97756051948SVladimir Oltean }; 97856051948SVladimir Oltean 97956051948SVladimir Oltean module_pci_driver(felix_pci_driver); 98056051948SVladimir Oltean 98156051948SVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 98256051948SVladimir Oltean MODULE_LICENSE("GPL v2"); 983