156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 2*adb3dccfSVladimir Oltean /* Copyright 2019-2021 NXP Semiconductors 3375e1314SVladimir Oltean * 4375e1314SVladimir Oltean * This is an umbrella module for all network switches that are 5375e1314SVladimir Oltean * register-compatible with Ocelot and that perform I/O to their host CPU 6375e1314SVladimir Oltean * through an NPI (Node Processor Interface) Ethernet port. 756051948SVladimir Oltean */ 856051948SVladimir Oltean #include <uapi/linux/if_bridge.h> 907d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h> 10bdeced75SVladimir Oltean #include <soc/mscc/ocelot_qsys.h> 11bdeced75SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 12bdeced75SVladimir Oltean #include <soc/mscc/ocelot_dev.h> 13bdeced75SVladimir Oltean #include <soc/mscc/ocelot_ana.h> 142b49d128SYangbo Lu #include <soc/mscc/ocelot_ptp.h> 1556051948SVladimir Oltean #include <soc/mscc/ocelot.h> 1684705fc1SMaxim Kochetkov #include <linux/platform_device.h> 17c0bcf537SYangbo Lu #include <linux/packing.h> 1856051948SVladimir Oltean #include <linux/module.h> 19bdeced75SVladimir Oltean #include <linux/of_net.h> 2056051948SVladimir Oltean #include <linux/pci.h> 2156051948SVladimir Oltean #include <linux/of.h> 22588d0550SIoana Ciornei #include <linux/pcs-lynx.h> 23fc411eaaSVladimir Oltean #include <net/pkt_sched.h> 2456051948SVladimir Oltean #include <net/dsa.h> 2556051948SVladimir Oltean #include "felix.h" 2656051948SVladimir Oltean 27*adb3dccfSVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This 28*adb3dccfSVladimir Oltean * is the mode through which frames can be injected from and extracted to an 29*adb3dccfSVladimir Oltean * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU 30*adb3dccfSVladimir Oltean * running Linux, and this forms a DSA setup together with the enetc or fman 31*adb3dccfSVladimir Oltean * DSA master. 32*adb3dccfSVladimir Oltean */ 33*adb3dccfSVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port) 34*adb3dccfSVladimir Oltean { 35*adb3dccfSVladimir Oltean ocelot->npi = port; 36*adb3dccfSVladimir Oltean 37*adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | 38*adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), 39*adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 40*adb3dccfSVladimir Oltean 41*adb3dccfSVladimir Oltean /* NPI port Injection/Extraction configuration */ 42*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 43*adb3dccfSVladimir Oltean ocelot->npi_xtr_prefix); 44*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 45*adb3dccfSVladimir Oltean ocelot->npi_inj_prefix); 46*adb3dccfSVladimir Oltean 47*adb3dccfSVladimir Oltean /* Disable transmission of pause frames */ 48*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); 49*adb3dccfSVladimir Oltean } 50*adb3dccfSVladimir Oltean 51*adb3dccfSVladimir Oltean static void felix_npi_port_deinit(struct ocelot *ocelot, int port) 52*adb3dccfSVladimir Oltean { 53*adb3dccfSVladimir Oltean /* Restore hardware defaults */ 54*adb3dccfSVladimir Oltean int unused_port = ocelot->num_phys_ports + 2; 55*adb3dccfSVladimir Oltean 56*adb3dccfSVladimir Oltean ocelot->npi = -1; 57*adb3dccfSVladimir Oltean 58*adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port), 59*adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 60*adb3dccfSVladimir Oltean 61*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 62*adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 63*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 64*adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 65*adb3dccfSVladimir Oltean 66*adb3dccfSVladimir Oltean /* Enable transmission of pause frames */ 67*adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1); 68*adb3dccfSVladimir Oltean } 69*adb3dccfSVladimir Oltean 70*adb3dccfSVladimir Oltean static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu) 71*adb3dccfSVladimir Oltean { 72*adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 73*adb3dccfSVladimir Oltean unsigned long cpu_flood; 74*adb3dccfSVladimir Oltean 75*adb3dccfSVladimir Oltean felix_npi_port_init(ocelot, cpu); 76*adb3dccfSVladimir Oltean 77*adb3dccfSVladimir Oltean /* Include the CPU port module (and indirectly, the NPI port) 78*adb3dccfSVladimir Oltean * in the forwarding mask for unknown unicast - the hardware 79*adb3dccfSVladimir Oltean * default value for ANA_FLOODING_FLD_UNICAST excludes 80*adb3dccfSVladimir Oltean * BIT(ocelot->num_phys_ports), and so does ocelot_init, 81*adb3dccfSVladimir Oltean * since Ocelot relies on whitelisting MAC addresses towards 82*adb3dccfSVladimir Oltean * PGID_CPU. 83*adb3dccfSVladimir Oltean * We do this because DSA does not yet perform RX filtering, 84*adb3dccfSVladimir Oltean * and the NPI port does not perform source address learning, 85*adb3dccfSVladimir Oltean * so traffic sent to Linux is effectively unknown from the 86*adb3dccfSVladimir Oltean * switch's perspective. 87*adb3dccfSVladimir Oltean */ 88*adb3dccfSVladimir Oltean cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 89*adb3dccfSVladimir Oltean ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC); 90*adb3dccfSVladimir Oltean 91*adb3dccfSVladimir Oltean return 0; 92*adb3dccfSVladimir Oltean } 93*adb3dccfSVladimir Oltean 94*adb3dccfSVladimir Oltean static void felix_teardown_tag_npi(struct dsa_switch *ds, int cpu) 95*adb3dccfSVladimir Oltean { 96*adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 97*adb3dccfSVladimir Oltean 98*adb3dccfSVladimir Oltean felix_npi_port_deinit(ocelot, cpu); 99*adb3dccfSVladimir Oltean } 100*adb3dccfSVladimir Oltean 101*adb3dccfSVladimir Oltean static int felix_set_tag_protocol(struct dsa_switch *ds, int cpu, 102*adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 103*adb3dccfSVladimir Oltean { 104*adb3dccfSVladimir Oltean int err; 105*adb3dccfSVladimir Oltean 106*adb3dccfSVladimir Oltean switch (proto) { 107*adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 108*adb3dccfSVladimir Oltean err = felix_setup_tag_npi(ds, cpu); 109*adb3dccfSVladimir Oltean break; 110*adb3dccfSVladimir Oltean default: 111*adb3dccfSVladimir Oltean err = -EPROTONOSUPPORT; 112*adb3dccfSVladimir Oltean } 113*adb3dccfSVladimir Oltean 114*adb3dccfSVladimir Oltean return err; 115*adb3dccfSVladimir Oltean } 116*adb3dccfSVladimir Oltean 117*adb3dccfSVladimir Oltean static void felix_del_tag_protocol(struct dsa_switch *ds, int cpu, 118*adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 119*adb3dccfSVladimir Oltean { 120*adb3dccfSVladimir Oltean switch (proto) { 121*adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 122*adb3dccfSVladimir Oltean felix_teardown_tag_npi(ds, cpu); 123*adb3dccfSVladimir Oltean break; 124*adb3dccfSVladimir Oltean default: 125*adb3dccfSVladimir Oltean break; 126*adb3dccfSVladimir Oltean } 127*adb3dccfSVladimir Oltean } 128*adb3dccfSVladimir Oltean 129*adb3dccfSVladimir Oltean static int felix_change_tag_protocol(struct dsa_switch *ds, int cpu, 130*adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 131*adb3dccfSVladimir Oltean { 132*adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 133*adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 134*adb3dccfSVladimir Oltean enum dsa_tag_protocol old_proto = felix->tag_proto; 135*adb3dccfSVladimir Oltean int err; 136*adb3dccfSVladimir Oltean 137*adb3dccfSVladimir Oltean if (proto != DSA_TAG_PROTO_OCELOT) 138*adb3dccfSVladimir Oltean return -EPROTONOSUPPORT; 139*adb3dccfSVladimir Oltean 140*adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, cpu, old_proto); 141*adb3dccfSVladimir Oltean 142*adb3dccfSVladimir Oltean err = felix_set_tag_protocol(ds, cpu, proto); 143*adb3dccfSVladimir Oltean if (err) { 144*adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, cpu, old_proto); 145*adb3dccfSVladimir Oltean return err; 146*adb3dccfSVladimir Oltean } 147*adb3dccfSVladimir Oltean 148*adb3dccfSVladimir Oltean felix->tag_proto = proto; 149*adb3dccfSVladimir Oltean 150*adb3dccfSVladimir Oltean return 0; 151*adb3dccfSVladimir Oltean } 152*adb3dccfSVladimir Oltean 15356051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 1544d776482SFlorian Fainelli int port, 1554d776482SFlorian Fainelli enum dsa_tag_protocol mp) 15656051948SVladimir Oltean { 157*adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 158*adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 159*adb3dccfSVladimir Oltean 160*adb3dccfSVladimir Oltean return felix->tag_proto; 16156051948SVladimir Oltean } 16256051948SVladimir Oltean 16356051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 16456051948SVladimir Oltean unsigned int ageing_time) 16556051948SVladimir Oltean { 16656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 16756051948SVladimir Oltean 16856051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 16956051948SVladimir Oltean 17056051948SVladimir Oltean return 0; 17156051948SVladimir Oltean } 17256051948SVladimir Oltean 17356051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 17456051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 17556051948SVladimir Oltean { 17656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17756051948SVladimir Oltean 17856051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 17956051948SVladimir Oltean } 18056051948SVladimir Oltean 18156051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 18256051948SVladimir Oltean const unsigned char *addr, u16 vid) 18356051948SVladimir Oltean { 18456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 18556051948SVladimir Oltean 18687b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 18756051948SVladimir Oltean } 18856051948SVladimir Oltean 18956051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 19056051948SVladimir Oltean const unsigned char *addr, u16 vid) 19156051948SVladimir Oltean { 19256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 19356051948SVladimir Oltean 19456051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 19556051948SVladimir Oltean } 19656051948SVladimir Oltean 197a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port, 198209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 199209edf95SVladimir Oltean { 200209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 201209edf95SVladimir Oltean 202a52b2da7SVladimir Oltean return ocelot_port_mdb_add(ocelot, port, mdb); 203209edf95SVladimir Oltean } 204209edf95SVladimir Oltean 205209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 206209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 207209edf95SVladimir Oltean { 208209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 209209edf95SVladimir Oltean 210209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 211209edf95SVladimir Oltean } 212209edf95SVladimir Oltean 21356051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 21456051948SVladimir Oltean u8 state) 21556051948SVladimir Oltean { 21656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 21756051948SVladimir Oltean 21856051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 21956051948SVladimir Oltean } 22056051948SVladimir Oltean 22156051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 22256051948SVladimir Oltean struct net_device *br) 22356051948SVladimir Oltean { 22456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 22556051948SVladimir Oltean 22656051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 22756051948SVladimir Oltean } 22856051948SVladimir Oltean 22956051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 23056051948SVladimir Oltean struct net_device *br) 23156051948SVladimir Oltean { 23256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 23356051948SVladimir Oltean 23456051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 23556051948SVladimir Oltean } 23656051948SVladimir Oltean 23756051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 23856051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 23956051948SVladimir Oltean { 2402f0402feSVladimir Oltean struct ocelot *ocelot = ds->priv; 241b7a9e0daSVladimir Oltean u16 flags = vlan->flags; 2422f0402feSVladimir Oltean 2439a720680SVladimir Oltean /* Ocelot switches copy frames as-is to the CPU, so the flags: 2449a720680SVladimir Oltean * egress-untagged or not, pvid or not, make no difference. This 2459a720680SVladimir Oltean * behavior is already better than what DSA just tries to approximate 2469a720680SVladimir Oltean * when it installs the VLAN with the same flags on the CPU port. 2479a720680SVladimir Oltean * Just accept any configuration, and don't let ocelot deny installing 2489a720680SVladimir Oltean * multiple native VLANs on the NPI port, because the switch doesn't 2499a720680SVladimir Oltean * look at the port tag settings towards the NPI interface anyway. 2509a720680SVladimir Oltean */ 2519a720680SVladimir Oltean if (port == ocelot->npi) 2529a720680SVladimir Oltean return 0; 2539a720680SVladimir Oltean 254b7a9e0daSVladimir Oltean return ocelot_vlan_prepare(ocelot, port, vlan->vid, 2552f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 2562f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 25756051948SVladimir Oltean } 25856051948SVladimir Oltean 259bae33f2bSVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 26056051948SVladimir Oltean { 26156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 26256051948SVladimir Oltean 263bae33f2bSVladimir Oltean return ocelot_port_vlan_filtering(ocelot, port, enabled); 26456051948SVladimir Oltean } 26556051948SVladimir Oltean 2661958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port, 26756051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 26856051948SVladimir Oltean { 26956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 270183be6f9SVladimir Oltean u16 flags = vlan->flags; 2711958d581SVladimir Oltean int err; 27256051948SVladimir Oltean 2731958d581SVladimir Oltean err = felix_vlan_prepare(ds, port, vlan); 2741958d581SVladimir Oltean if (err) 2751958d581SVladimir Oltean return err; 2761958d581SVladimir Oltean 2771958d581SVladimir Oltean return ocelot_vlan_add(ocelot, port, vlan->vid, 278183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 279183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 28056051948SVladimir Oltean } 28156051948SVladimir Oltean 28256051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 28356051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 28456051948SVladimir Oltean { 28556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 28656051948SVladimir Oltean 287b7a9e0daSVladimir Oltean return ocelot_vlan_del(ocelot, port, vlan->vid); 28856051948SVladimir Oltean } 28956051948SVladimir Oltean 29056051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 29156051948SVladimir Oltean struct phy_device *phy) 29256051948SVladimir Oltean { 29356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 29456051948SVladimir Oltean 29556051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 29656051948SVladimir Oltean 29756051948SVladimir Oltean return 0; 29856051948SVladimir Oltean } 29956051948SVladimir Oltean 30056051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 30156051948SVladimir Oltean { 30256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 30356051948SVladimir Oltean 30456051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 30556051948SVladimir Oltean } 30656051948SVladimir Oltean 307bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 308bdeced75SVladimir Oltean unsigned long *supported, 309bdeced75SVladimir Oltean struct phylink_link_state *state) 310bdeced75SVladimir Oltean { 311bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 312375e1314SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 313bdeced75SVladimir Oltean 314375e1314SVladimir Oltean if (felix->info->phylink_validate) 315375e1314SVladimir Oltean felix->info->phylink_validate(ocelot, port, supported, state); 316bdeced75SVladimir Oltean } 317bdeced75SVladimir Oltean 318bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 319bdeced75SVladimir Oltean unsigned int link_an_mode, 320bdeced75SVladimir Oltean const struct phylink_link_state *state) 321bdeced75SVladimir Oltean { 322bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 323bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 324588d0550SIoana Ciornei struct dsa_port *dp = dsa_to_port(ds, port); 325bdeced75SVladimir Oltean 326588d0550SIoana Ciornei if (felix->pcs[port]) 327588d0550SIoana Ciornei phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs); 328bdeced75SVladimir Oltean } 329bdeced75SVladimir Oltean 330bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 331bdeced75SVladimir Oltean unsigned int link_an_mode, 332bdeced75SVladimir Oltean phy_interface_t interface) 333bdeced75SVladimir Oltean { 334bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 335bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 336bdeced75SVladimir Oltean 337bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 338886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); 339bdeced75SVladimir Oltean } 340bdeced75SVladimir Oltean 341bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 342bdeced75SVladimir Oltean unsigned int link_an_mode, 343bdeced75SVladimir Oltean phy_interface_t interface, 3445b502a7bSRussell King struct phy_device *phydev, 3455b502a7bSRussell King int speed, int duplex, 3465b502a7bSRussell King bool tx_pause, bool rx_pause) 347bdeced75SVladimir Oltean { 348bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 349bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 3507e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 3517e14a2dcSVladimir Oltean u32 mac_fc_cfg; 352bdeced75SVladimir Oltean 3537e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 3547e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 3557e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 3567e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 3577e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 3587e14a2dcSVladimir Oltean * value). 3597e14a2dcSVladimir Oltean */ 3607e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 3617e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 3627e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 3637e14a2dcSVladimir Oltean 3647e14a2dcSVladimir Oltean switch (speed) { 3657e14a2dcSVladimir Oltean case SPEED_10: 3667e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 3677e14a2dcSVladimir Oltean break; 3687e14a2dcSVladimir Oltean case SPEED_100: 3697e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 3707e14a2dcSVladimir Oltean break; 3717e14a2dcSVladimir Oltean case SPEED_1000: 3727e14a2dcSVladimir Oltean case SPEED_2500: 3737e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 3747e14a2dcSVladimir Oltean break; 3757e14a2dcSVladimir Oltean default: 3767e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 3777e14a2dcSVladimir Oltean port, speed); 3787e14a2dcSVladimir Oltean return; 3797e14a2dcSVladimir Oltean } 3807e14a2dcSVladimir Oltean 3817e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 3827e14a2dcSVladimir Oltean * adaptation. 3837e14a2dcSVladimir Oltean */ 3847e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 3857e14a2dcSVladimir Oltean 3867e14a2dcSVladimir Oltean if (tx_pause) 3877e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 3887e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 3897e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 3907e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 3917e14a2dcSVladimir Oltean 3927e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 3937e14a2dcSVladimir Oltean * specification in incoming pause frames. 3947e14a2dcSVladimir Oltean */ 3957e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 3967e14a2dcSVladimir Oltean 3977e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 3987e14a2dcSVladimir Oltean 3997e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 4007e14a2dcSVladimir Oltean * enable MAC module 4017e14a2dcSVladimir Oltean */ 402bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 403bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 404bdeced75SVladimir Oltean 405bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 406bdeced75SVladimir Oltean * MAC addresses. 407bdeced75SVladimir Oltean */ 408bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 409bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 410bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 411bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 412bdeced75SVladimir Oltean 413bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 414886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, 415886e1387SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); 4167e14a2dcSVladimir Oltean 4177e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 4187e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 419bdeced75SVladimir Oltean } 420bdeced75SVladimir Oltean 421bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 422bd2b3161SXiaoliang Yang { 423bd2b3161SXiaoliang Yang int i; 424bd2b3161SXiaoliang Yang 425bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 426bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 427bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 428bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 429bd2b3161SXiaoliang Yang port); 430bd2b3161SXiaoliang Yang 43170d39a6eSVladimir Oltean for (i = 0; i < OCELOT_NUM_TC * 2; i++) { 432bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 433bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 434bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 435bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 436bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 437bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 438bd2b3161SXiaoliang Yang port, i); 439bd2b3161SXiaoliang Yang } 440bd2b3161SXiaoliang Yang } 441bd2b3161SXiaoliang Yang 44256051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 44356051948SVladimir Oltean u32 stringset, u8 *data) 44456051948SVladimir Oltean { 44556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 44656051948SVladimir Oltean 44756051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 44856051948SVladimir Oltean } 44956051948SVladimir Oltean 45056051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 45156051948SVladimir Oltean { 45256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 45356051948SVladimir Oltean 45456051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 45556051948SVladimir Oltean } 45656051948SVladimir Oltean 45756051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 45856051948SVladimir Oltean { 45956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 46056051948SVladimir Oltean 46156051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 46256051948SVladimir Oltean } 46356051948SVladimir Oltean 46456051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 46556051948SVladimir Oltean struct ethtool_ts_info *info) 46656051948SVladimir Oltean { 46756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 46856051948SVladimir Oltean 46956051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 47056051948SVladimir Oltean } 47156051948SVladimir Oltean 472bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 473bdeced75SVladimir Oltean struct device_node *ports_node, 474bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 475bdeced75SVladimir Oltean { 476bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 477bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 478bdeced75SVladimir Oltean struct device_node *child; 479bdeced75SVladimir Oltean 48037fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 481bdeced75SVladimir Oltean phy_interface_t phy_mode; 482bdeced75SVladimir Oltean u32 port; 483bdeced75SVladimir Oltean int err; 484bdeced75SVladimir Oltean 485bdeced75SVladimir Oltean /* Get switch port number from DT */ 486bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 487bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 488bdeced75SVladimir Oltean "(property \"reg\")\n"); 489bdeced75SVladimir Oltean of_node_put(child); 490bdeced75SVladimir Oltean return -ENODEV; 491bdeced75SVladimir Oltean } 492bdeced75SVladimir Oltean 493bdeced75SVladimir Oltean /* Get PHY mode from DT */ 494bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 495bdeced75SVladimir Oltean if (err) { 496bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 497bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 498bdeced75SVladimir Oltean port); 499bdeced75SVladimir Oltean of_node_put(child); 500bdeced75SVladimir Oltean return -ENODEV; 501bdeced75SVladimir Oltean } 502bdeced75SVladimir Oltean 503bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 504bdeced75SVladimir Oltean if (err < 0) { 505bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 506bdeced75SVladimir Oltean phy_modes(phy_mode), port); 50759ebb430SSumera Priyadarsini of_node_put(child); 508bdeced75SVladimir Oltean return err; 509bdeced75SVladimir Oltean } 510bdeced75SVladimir Oltean 511bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 512bdeced75SVladimir Oltean } 513bdeced75SVladimir Oltean 514bdeced75SVladimir Oltean return 0; 515bdeced75SVladimir Oltean } 516bdeced75SVladimir Oltean 517bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 518bdeced75SVladimir Oltean { 519bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 520bdeced75SVladimir Oltean struct device_node *switch_node; 521bdeced75SVladimir Oltean struct device_node *ports_node; 522bdeced75SVladimir Oltean int err; 523bdeced75SVladimir Oltean 524bdeced75SVladimir Oltean switch_node = dev->of_node; 525bdeced75SVladimir Oltean 526bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 527bdeced75SVladimir Oltean if (!ports_node) { 528bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 529bdeced75SVladimir Oltean return -ENODEV; 530bdeced75SVladimir Oltean } 531bdeced75SVladimir Oltean 532bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 533bdeced75SVladimir Oltean of_node_put(ports_node); 534bdeced75SVladimir Oltean 535bdeced75SVladimir Oltean return err; 536bdeced75SVladimir Oltean } 537bdeced75SVladimir Oltean 53856051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 53956051948SVladimir Oltean { 54056051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 541bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 542b4024c9eSClaudiu Manoil struct resource res; 54356051948SVladimir Oltean int port, i, err; 54456051948SVladimir Oltean 54556051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 54656051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 54756051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 54856051948SVladimir Oltean if (!ocelot->ports) 54956051948SVladimir Oltean return -ENOMEM; 55056051948SVladimir Oltean 55156051948SVladimir Oltean ocelot->map = felix->info->map; 55256051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 55356051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 55421ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 55507d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 55656051948SVladimir Oltean ocelot->ops = felix->info->ops; 557cacea62fSVladimir Oltean ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; 558cacea62fSVladimir Oltean ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; 559f59fd9caSVladimir Oltean ocelot->devlink = felix->ds->devlink; 56056051948SVladimir Oltean 561bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 562bdeced75SVladimir Oltean GFP_KERNEL); 563bdeced75SVladimir Oltean if (!port_phy_modes) 564bdeced75SVladimir Oltean return -ENOMEM; 565bdeced75SVladimir Oltean 566bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 567bdeced75SVladimir Oltean if (err) { 568bdeced75SVladimir Oltean kfree(port_phy_modes); 569bdeced75SVladimir Oltean return err; 570bdeced75SVladimir Oltean } 571bdeced75SVladimir Oltean 57256051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 57356051948SVladimir Oltean struct regmap *target; 57456051948SVladimir Oltean 57556051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 57656051948SVladimir Oltean continue; 57756051948SVladimir Oltean 578b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 579b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 580375e1314SVladimir Oltean res.start += felix->switch_base; 581375e1314SVladimir Oltean res.end += felix->switch_base; 58256051948SVladimir Oltean 583b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 58456051948SVladimir Oltean if (IS_ERR(target)) { 58556051948SVladimir Oltean dev_err(ocelot->dev, 58656051948SVladimir Oltean "Failed to map device memory space\n"); 587bdeced75SVladimir Oltean kfree(port_phy_modes); 58856051948SVladimir Oltean return PTR_ERR(target); 58956051948SVladimir Oltean } 59056051948SVladimir Oltean 59156051948SVladimir Oltean ocelot->targets[i] = target; 59256051948SVladimir Oltean } 59356051948SVladimir Oltean 59456051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 59556051948SVladimir Oltean if (err) { 59656051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 597bdeced75SVladimir Oltean kfree(port_phy_modes); 59856051948SVladimir Oltean return err; 59956051948SVladimir Oltean } 60056051948SVladimir Oltean 60156051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 60256051948SVladimir Oltean struct ocelot_port *ocelot_port; 60391c724cfSVladimir Oltean struct regmap *target; 60467c24049SVladimir Oltean u8 *template; 60556051948SVladimir Oltean 60656051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 60756051948SVladimir Oltean sizeof(struct ocelot_port), 60856051948SVladimir Oltean GFP_KERNEL); 60956051948SVladimir Oltean if (!ocelot_port) { 61056051948SVladimir Oltean dev_err(ocelot->dev, 61156051948SVladimir Oltean "failed to allocate port memory\n"); 612bdeced75SVladimir Oltean kfree(port_phy_modes); 61356051948SVladimir Oltean return -ENOMEM; 61456051948SVladimir Oltean } 61556051948SVladimir Oltean 616b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 617b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 618375e1314SVladimir Oltean res.start += felix->switch_base; 619375e1314SVladimir Oltean res.end += felix->switch_base; 62056051948SVladimir Oltean 62191c724cfSVladimir Oltean target = ocelot_regmap_init(ocelot, &res); 62291c724cfSVladimir Oltean if (IS_ERR(target)) { 62356051948SVladimir Oltean dev_err(ocelot->dev, 62491c724cfSVladimir Oltean "Failed to map memory space for port %d\n", 62591c724cfSVladimir Oltean port); 626bdeced75SVladimir Oltean kfree(port_phy_modes); 62791c724cfSVladimir Oltean return PTR_ERR(target); 62856051948SVladimir Oltean } 62956051948SVladimir Oltean 6305124197cSVladimir Oltean template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN, 63167c24049SVladimir Oltean GFP_KERNEL); 63267c24049SVladimir Oltean if (!template) { 63367c24049SVladimir Oltean dev_err(ocelot->dev, 63467c24049SVladimir Oltean "Failed to allocate memory for DSA tag\n"); 63567c24049SVladimir Oltean kfree(port_phy_modes); 63667c24049SVladimir Oltean return -ENOMEM; 63767c24049SVladimir Oltean } 63867c24049SVladimir Oltean 639bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 64056051948SVladimir Oltean ocelot_port->ocelot = ocelot; 64191c724cfSVladimir Oltean ocelot_port->target = target; 64267c24049SVladimir Oltean ocelot_port->xmit_template = template; 64356051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 64467c24049SVladimir Oltean 64567c24049SVladimir Oltean felix->info->xmit_template_populate(ocelot, port); 64656051948SVladimir Oltean } 64756051948SVladimir Oltean 648bdeced75SVladimir Oltean kfree(port_phy_modes); 649bdeced75SVladimir Oltean 650bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 651bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 652bdeced75SVladimir Oltean if (err < 0) 653bdeced75SVladimir Oltean return err; 654bdeced75SVladimir Oltean } 655bdeced75SVladimir Oltean 65656051948SVladimir Oltean return 0; 65756051948SVladimir Oltean } 65856051948SVladimir Oltean 65956051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 66056051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 66156051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 66256051948SVladimir Oltean * (which will not work). 66356051948SVladimir Oltean */ 66456051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 66556051948SVladimir Oltean { 66656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 66756051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 66856051948SVladimir Oltean int port, err; 66956051948SVladimir Oltean 67056051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 67156051948SVladimir Oltean if (err) 67256051948SVladimir Oltean return err; 67356051948SVladimir Oltean 674d1cc0e93SVladimir Oltean err = ocelot_init(ocelot); 675d1cc0e93SVladimir Oltean if (err) 676d1cc0e93SVladimir Oltean return err; 677d1cc0e93SVladimir Oltean 6782b49d128SYangbo Lu if (ocelot->ptp) { 6792ac7c6c5SVladimir Oltean err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); 6802b49d128SYangbo Lu if (err) { 6812b49d128SYangbo Lu dev_err(ocelot->dev, 6822b49d128SYangbo Lu "Timestamp initialization failed\n"); 6832b49d128SYangbo Lu ocelot->ptp = 0; 6842b49d128SYangbo Lu } 6852b49d128SYangbo Lu } 68656051948SVladimir Oltean 68756051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 688*adb3dccfSVladimir Oltean if (dsa_is_unused_port(ds, port)) 689*adb3dccfSVladimir Oltean continue; 69056051948SVladimir Oltean 691*adb3dccfSVladimir Oltean ocelot_init_port(ocelot, port); 692bd2b3161SXiaoliang Yang 693bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 694bd2b3161SXiaoliang Yang * bits of vlan tag. 695bd2b3161SXiaoliang Yang */ 696bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 69756051948SVladimir Oltean } 69856051948SVladimir Oltean 699f59fd9caSVladimir Oltean err = ocelot_devlink_sb_register(ocelot); 700f59fd9caSVladimir Oltean if (err) 701f59fd9caSVladimir Oltean return err; 702f59fd9caSVladimir Oltean 703*adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 704*adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 705*adb3dccfSVladimir Oltean continue; 706*adb3dccfSVladimir Oltean 707*adb3dccfSVladimir Oltean /* The initial tag protocol is NPI which always returns 0, so 708*adb3dccfSVladimir Oltean * there's no real point in checking for errors. 7091cf3299bSVladimir Oltean */ 710*adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, port, felix->tag_proto); 711*adb3dccfSVladimir Oltean } 7121cf3299bSVladimir Oltean 7130b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 714c54913c1SVladimir Oltean ds->assisted_learning_on_cpu_port = true; 715bdeced75SVladimir Oltean 71656051948SVladimir Oltean return 0; 71756051948SVladimir Oltean } 71856051948SVladimir Oltean 71956051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 72056051948SVladimir Oltean { 72156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 722bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 723e5fb512dSVladimir Oltean int port; 724bdeced75SVladimir Oltean 725*adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 726*adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 727*adb3dccfSVladimir Oltean continue; 728*adb3dccfSVladimir Oltean 729*adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, port, felix->tag_proto); 730*adb3dccfSVladimir Oltean } 731*adb3dccfSVladimir Oltean 732f59fd9caSVladimir Oltean ocelot_devlink_sb_unregister(ocelot); 733d19741b0SVladimir Oltean ocelot_deinit_timestamp(ocelot); 734d19741b0SVladimir Oltean ocelot_deinit(ocelot); 73556051948SVladimir Oltean 736e5fb512dSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) 737e5fb512dSVladimir Oltean ocelot_deinit_port(ocelot, port); 738d19741b0SVladimir Oltean 739d19741b0SVladimir Oltean if (felix->info->mdio_bus_free) 740d19741b0SVladimir Oltean felix->info->mdio_bus_free(ocelot); 74156051948SVladimir Oltean } 74256051948SVladimir Oltean 743c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 744c0bcf537SYangbo Lu struct ifreq *ifr) 745c0bcf537SYangbo Lu { 746c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 747c0bcf537SYangbo Lu 748c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 749c0bcf537SYangbo Lu } 750c0bcf537SYangbo Lu 751c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 752c0bcf537SYangbo Lu struct ifreq *ifr) 753c0bcf537SYangbo Lu { 754c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 755c0bcf537SYangbo Lu 756c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 757c0bcf537SYangbo Lu } 758c0bcf537SYangbo Lu 759c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 760c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 761c0bcf537SYangbo Lu { 762c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 763c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 764c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 765c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 766c0bcf537SYangbo Lu struct timespec64 ts; 767c0bcf537SYangbo Lu u64 tstamp, val; 768c0bcf537SYangbo Lu 769c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 770c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 771c0bcf537SYangbo Lu 772c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 773c0bcf537SYangbo Lu tstamp_lo = (u32)val; 774c0bcf537SYangbo Lu 775c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 776c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 777c0bcf537SYangbo Lu tstamp_hi--; 778c0bcf537SYangbo Lu 779c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 780c0bcf537SYangbo Lu 781c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 782c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 783c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 784c0bcf537SYangbo Lu return false; 785c0bcf537SYangbo Lu } 786c0bcf537SYangbo Lu 7873243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 788c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 789c0bcf537SYangbo Lu { 790c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 791c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 792c0bcf537SYangbo Lu 793e2f9a8feSVladimir Oltean if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) && 794e2f9a8feSVladimir Oltean ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 795e2f9a8feSVladimir Oltean ocelot_port_add_txtstamp_skb(ocelot, port, clone); 796c0bcf537SYangbo Lu return true; 797e2f9a8feSVladimir Oltean } 798c0bcf537SYangbo Lu 799c0bcf537SYangbo Lu return false; 800c0bcf537SYangbo Lu } 801c0bcf537SYangbo Lu 8020b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 8030b912fc9SVladimir Oltean { 8040b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 8050b912fc9SVladimir Oltean 8060b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 8070b912fc9SVladimir Oltean 8080b912fc9SVladimir Oltean return 0; 8090b912fc9SVladimir Oltean } 8100b912fc9SVladimir Oltean 8110b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 8120b912fc9SVladimir Oltean { 8130b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 8140b912fc9SVladimir Oltean 8150b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 8160b912fc9SVladimir Oltean } 8170b912fc9SVladimir Oltean 81807d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 81907d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 82007d985eeSVladimir Oltean { 82107d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 82207d985eeSVladimir Oltean 82307d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 82407d985eeSVladimir Oltean } 82507d985eeSVladimir Oltean 82607d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 82707d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 82807d985eeSVladimir Oltean { 82907d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 83007d985eeSVladimir Oltean 83107d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 83207d985eeSVladimir Oltean } 83307d985eeSVladimir Oltean 83407d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 83507d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 83607d985eeSVladimir Oltean { 83707d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 83807d985eeSVladimir Oltean 83907d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 84007d985eeSVladimir Oltean } 84107d985eeSVladimir Oltean 842fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 843fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 844fc411eaaSVladimir Oltean { 845fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 846fc411eaaSVladimir Oltean struct ocelot_policer pol = { 847fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 8485f035af7SPo Liu .burst = policer->burst, 849fc411eaaSVladimir Oltean }; 850fc411eaaSVladimir Oltean 851fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 852fc411eaaSVladimir Oltean } 853fc411eaaSVladimir Oltean 854fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 855fc411eaaSVladimir Oltean { 856fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 857fc411eaaSVladimir Oltean 858fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 859fc411eaaSVladimir Oltean } 860fc411eaaSVladimir Oltean 861de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 862de143c0eSXiaoliang Yang enum tc_setup_type type, 863de143c0eSXiaoliang Yang void *type_data) 864de143c0eSXiaoliang Yang { 865de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 866de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 867de143c0eSXiaoliang Yang 868de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 869de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 870de143c0eSXiaoliang Yang else 871de143c0eSXiaoliang Yang return -EOPNOTSUPP; 872de143c0eSXiaoliang Yang } 873de143c0eSXiaoliang Yang 874f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index, 875f59fd9caSVladimir Oltean u16 pool_index, 876f59fd9caSVladimir Oltean struct devlink_sb_pool_info *pool_info) 877f59fd9caSVladimir Oltean { 878f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 879f59fd9caSVladimir Oltean 880f59fd9caSVladimir Oltean return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info); 881f59fd9caSVladimir Oltean } 882f59fd9caSVladimir Oltean 883f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index, 884f59fd9caSVladimir Oltean u16 pool_index, u32 size, 885f59fd9caSVladimir Oltean enum devlink_sb_threshold_type threshold_type, 886f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 887f59fd9caSVladimir Oltean { 888f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 889f59fd9caSVladimir Oltean 890f59fd9caSVladimir Oltean return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size, 891f59fd9caSVladimir Oltean threshold_type, extack); 892f59fd9caSVladimir Oltean } 893f59fd9caSVladimir Oltean 894f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port, 895f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 896f59fd9caSVladimir Oltean u32 *p_threshold) 897f59fd9caSVladimir Oltean { 898f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 899f59fd9caSVladimir Oltean 900f59fd9caSVladimir Oltean return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index, 901f59fd9caSVladimir Oltean p_threshold); 902f59fd9caSVladimir Oltean } 903f59fd9caSVladimir Oltean 904f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port, 905f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 906f59fd9caSVladimir Oltean u32 threshold, struct netlink_ext_ack *extack) 907f59fd9caSVladimir Oltean { 908f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 909f59fd9caSVladimir Oltean 910f59fd9caSVladimir Oltean return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index, 911f59fd9caSVladimir Oltean threshold, extack); 912f59fd9caSVladimir Oltean } 913f59fd9caSVladimir Oltean 914f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port, 915f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 916f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 917f59fd9caSVladimir Oltean u16 *p_pool_index, u32 *p_threshold) 918f59fd9caSVladimir Oltean { 919f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 920f59fd9caSVladimir Oltean 921f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index, 922f59fd9caSVladimir Oltean pool_type, p_pool_index, 923f59fd9caSVladimir Oltean p_threshold); 924f59fd9caSVladimir Oltean } 925f59fd9caSVladimir Oltean 926f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port, 927f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 928f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 929f59fd9caSVladimir Oltean u16 pool_index, u32 threshold, 930f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 931f59fd9caSVladimir Oltean { 932f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 933f59fd9caSVladimir Oltean 934f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index, 935f59fd9caSVladimir Oltean pool_type, pool_index, threshold, 936f59fd9caSVladimir Oltean extack); 937f59fd9caSVladimir Oltean } 938f59fd9caSVladimir Oltean 939f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds, 940f59fd9caSVladimir Oltean unsigned int sb_index) 941f59fd9caSVladimir Oltean { 942f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 943f59fd9caSVladimir Oltean 944f59fd9caSVladimir Oltean return ocelot_sb_occ_snapshot(ocelot, sb_index); 945f59fd9caSVladimir Oltean } 946f59fd9caSVladimir Oltean 947f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds, 948f59fd9caSVladimir Oltean unsigned int sb_index) 949f59fd9caSVladimir Oltean { 950f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 951f59fd9caSVladimir Oltean 952f59fd9caSVladimir Oltean return ocelot_sb_occ_max_clear(ocelot, sb_index); 953f59fd9caSVladimir Oltean } 954f59fd9caSVladimir Oltean 955f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port, 956f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 957f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 958f59fd9caSVladimir Oltean { 959f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 960f59fd9caSVladimir Oltean 961f59fd9caSVladimir Oltean return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index, 962f59fd9caSVladimir Oltean p_cur, p_max); 963f59fd9caSVladimir Oltean } 964f59fd9caSVladimir Oltean 965f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port, 966f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 967f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 968f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 969f59fd9caSVladimir Oltean { 970f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 971f59fd9caSVladimir Oltean 972f59fd9caSVladimir Oltean return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index, 973f59fd9caSVladimir Oltean pool_type, p_cur, p_max); 974f59fd9caSVladimir Oltean } 975f59fd9caSVladimir Oltean 976375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = { 97756051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 978*adb3dccfSVladimir Oltean .change_tag_protocol = felix_change_tag_protocol, 97956051948SVladimir Oltean .setup = felix_setup, 98056051948SVladimir Oltean .teardown = felix_teardown, 98156051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 98256051948SVladimir Oltean .get_strings = felix_get_strings, 98356051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 98456051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 98556051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 986bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 987bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 988bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 989bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 99056051948SVladimir Oltean .port_enable = felix_port_enable, 99156051948SVladimir Oltean .port_disable = felix_port_disable, 99256051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 99356051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 99456051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 995209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 996209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 99756051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 99856051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 99956051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 100056051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 100156051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 100256051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 1003c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 1004c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 1005c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 1006c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 10070b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 10080b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 1009fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 1010fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 101107d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 101207d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 101307d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 1014de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 1015f59fd9caSVladimir Oltean .devlink_sb_pool_get = felix_sb_pool_get, 1016f59fd9caSVladimir Oltean .devlink_sb_pool_set = felix_sb_pool_set, 1017f59fd9caSVladimir Oltean .devlink_sb_port_pool_get = felix_sb_port_pool_get, 1018f59fd9caSVladimir Oltean .devlink_sb_port_pool_set = felix_sb_port_pool_set, 1019f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get, 1020f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set, 1021f59fd9caSVladimir Oltean .devlink_sb_occ_snapshot = felix_sb_occ_snapshot, 1022f59fd9caSVladimir Oltean .devlink_sb_occ_max_clear = felix_sb_occ_max_clear, 1023f59fd9caSVladimir Oltean .devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get, 1024f59fd9caSVladimir Oltean .devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get, 102556051948SVladimir Oltean }; 1026319e4dd1SVladimir Oltean 1027319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) 1028319e4dd1SVladimir Oltean { 1029319e4dd1SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1030319e4dd1SVladimir Oltean struct dsa_switch *ds = felix->ds; 1031319e4dd1SVladimir Oltean 1032319e4dd1SVladimir Oltean if (!dsa_is_user_port(ds, port)) 1033319e4dd1SVladimir Oltean return NULL; 1034319e4dd1SVladimir Oltean 1035319e4dd1SVladimir Oltean return dsa_to_port(ds, port)->slave; 1036319e4dd1SVladimir Oltean } 1037319e4dd1SVladimir Oltean 1038319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev) 1039319e4dd1SVladimir Oltean { 1040319e4dd1SVladimir Oltean struct dsa_port *dp; 1041319e4dd1SVladimir Oltean 1042319e4dd1SVladimir Oltean dp = dsa_port_from_netdev(dev); 1043319e4dd1SVladimir Oltean if (IS_ERR(dp)) 1044319e4dd1SVladimir Oltean return -EINVAL; 1045319e4dd1SVladimir Oltean 1046319e4dd1SVladimir Oltean return dp->index; 1047319e4dd1SVladimir Oltean } 1048