156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 256051948SVladimir Oltean /* Copyright 2019 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 2756051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 284d776482SFlorian Fainelli int port, 294d776482SFlorian Fainelli enum dsa_tag_protocol mp) 3056051948SVladimir Oltean { 3156051948SVladimir Oltean return DSA_TAG_PROTO_OCELOT; 3256051948SVladimir Oltean } 3356051948SVladimir Oltean 3456051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 3556051948SVladimir Oltean unsigned int ageing_time) 3656051948SVladimir Oltean { 3756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 3856051948SVladimir Oltean 3956051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 4056051948SVladimir Oltean 4156051948SVladimir Oltean return 0; 4256051948SVladimir Oltean } 4356051948SVladimir Oltean 4456051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 4556051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 4656051948SVladimir Oltean { 4756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4856051948SVladimir Oltean 4956051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 5056051948SVladimir Oltean } 5156051948SVladimir Oltean 5256051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 5356051948SVladimir Oltean const unsigned char *addr, u16 vid) 5456051948SVladimir Oltean { 5556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5656051948SVladimir Oltean 5787b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 5856051948SVladimir Oltean } 5956051948SVladimir Oltean 6056051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 6156051948SVladimir Oltean const unsigned char *addr, u16 vid) 6256051948SVladimir Oltean { 6356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 6456051948SVladimir Oltean 6556051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 6656051948SVladimir Oltean } 6756051948SVladimir Oltean 68a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port, 69209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 70209edf95SVladimir Oltean { 71209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 72209edf95SVladimir Oltean 73a52b2da7SVladimir Oltean return ocelot_port_mdb_add(ocelot, port, mdb); 74209edf95SVladimir Oltean } 75209edf95SVladimir Oltean 76209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 77209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 78209edf95SVladimir Oltean { 79209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 80209edf95SVladimir Oltean 81209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 82209edf95SVladimir Oltean } 83209edf95SVladimir Oltean 8456051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 8556051948SVladimir Oltean u8 state) 8656051948SVladimir Oltean { 8756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 8856051948SVladimir Oltean 8956051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 9056051948SVladimir Oltean } 9156051948SVladimir Oltean 9256051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 9356051948SVladimir Oltean struct net_device *br) 9456051948SVladimir Oltean { 9556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 9656051948SVladimir Oltean 9756051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 9856051948SVladimir Oltean } 9956051948SVladimir Oltean 10056051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 10156051948SVladimir Oltean struct net_device *br) 10256051948SVladimir Oltean { 10356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 10456051948SVladimir Oltean 10556051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 10656051948SVladimir Oltean } 10756051948SVladimir Oltean 10856051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 10956051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 11056051948SVladimir Oltean { 1112f0402feSVladimir Oltean struct ocelot *ocelot = ds->priv; 112b7a9e0daSVladimir Oltean u16 flags = vlan->flags; 1132f0402feSVladimir Oltean 1149a720680SVladimir Oltean /* Ocelot switches copy frames as-is to the CPU, so the flags: 1159a720680SVladimir Oltean * egress-untagged or not, pvid or not, make no difference. This 1169a720680SVladimir Oltean * behavior is already better than what DSA just tries to approximate 1179a720680SVladimir Oltean * when it installs the VLAN with the same flags on the CPU port. 1189a720680SVladimir Oltean * Just accept any configuration, and don't let ocelot deny installing 1199a720680SVladimir Oltean * multiple native VLANs on the NPI port, because the switch doesn't 1209a720680SVladimir Oltean * look at the port tag settings towards the NPI interface anyway. 1219a720680SVladimir Oltean */ 1229a720680SVladimir Oltean if (port == ocelot->npi) 1239a720680SVladimir Oltean return 0; 1249a720680SVladimir Oltean 125b7a9e0daSVladimir Oltean return ocelot_vlan_prepare(ocelot, port, vlan->vid, 1262f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 1272f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 12856051948SVladimir Oltean } 12956051948SVladimir Oltean 130bae33f2bSVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 13156051948SVladimir Oltean { 13256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 13356051948SVladimir Oltean 134bae33f2bSVladimir Oltean return ocelot_port_vlan_filtering(ocelot, port, enabled); 13556051948SVladimir Oltean } 13656051948SVladimir Oltean 1371958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port, 13856051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 13956051948SVladimir Oltean { 14056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 141183be6f9SVladimir Oltean u16 flags = vlan->flags; 1421958d581SVladimir Oltean int err; 14356051948SVladimir Oltean 1441958d581SVladimir Oltean err = felix_vlan_prepare(ds, port, vlan); 1451958d581SVladimir Oltean if (err) 1461958d581SVladimir Oltean return err; 1471958d581SVladimir Oltean 1481958d581SVladimir Oltean return ocelot_vlan_add(ocelot, port, vlan->vid, 149183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 150183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 15156051948SVladimir Oltean } 15256051948SVladimir Oltean 15356051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 15456051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 15556051948SVladimir Oltean { 15656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 15756051948SVladimir Oltean 158b7a9e0daSVladimir Oltean return ocelot_vlan_del(ocelot, port, vlan->vid); 15956051948SVladimir Oltean } 16056051948SVladimir Oltean 16156051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 16256051948SVladimir Oltean struct phy_device *phy) 16356051948SVladimir Oltean { 16456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 16556051948SVladimir Oltean 16656051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 16756051948SVladimir Oltean 16856051948SVladimir Oltean return 0; 16956051948SVladimir Oltean } 17056051948SVladimir Oltean 17156051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 17256051948SVladimir Oltean { 17356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17456051948SVladimir Oltean 17556051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 17656051948SVladimir Oltean } 17756051948SVladimir Oltean 178bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 179bdeced75SVladimir Oltean unsigned long *supported, 180bdeced75SVladimir Oltean struct phylink_link_state *state) 181bdeced75SVladimir Oltean { 182bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 183375e1314SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 184bdeced75SVladimir Oltean 185375e1314SVladimir Oltean if (felix->info->phylink_validate) 186375e1314SVladimir Oltean felix->info->phylink_validate(ocelot, port, supported, state); 187bdeced75SVladimir Oltean } 188bdeced75SVladimir Oltean 189bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 190bdeced75SVladimir Oltean unsigned int link_an_mode, 191bdeced75SVladimir Oltean const struct phylink_link_state *state) 192bdeced75SVladimir Oltean { 193bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 194bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 195588d0550SIoana Ciornei struct dsa_port *dp = dsa_to_port(ds, port); 196bdeced75SVladimir Oltean 197588d0550SIoana Ciornei if (felix->pcs[port]) 198588d0550SIoana Ciornei phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs); 199bdeced75SVladimir Oltean } 200bdeced75SVladimir Oltean 201bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 202bdeced75SVladimir Oltean unsigned int link_an_mode, 203bdeced75SVladimir Oltean phy_interface_t interface) 204bdeced75SVladimir Oltean { 205bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 206bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 207bdeced75SVladimir Oltean 208bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 209886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); 210bdeced75SVladimir Oltean } 211bdeced75SVladimir Oltean 212bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 213bdeced75SVladimir Oltean unsigned int link_an_mode, 214bdeced75SVladimir Oltean phy_interface_t interface, 2155b502a7bSRussell King struct phy_device *phydev, 2165b502a7bSRussell King int speed, int duplex, 2175b502a7bSRussell King bool tx_pause, bool rx_pause) 218bdeced75SVladimir Oltean { 219bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 220bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 2217e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 2227e14a2dcSVladimir Oltean u32 mac_fc_cfg; 223bdeced75SVladimir Oltean 2247e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 2257e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 2267e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 2277e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 2287e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 2297e14a2dcSVladimir Oltean * value). 2307e14a2dcSVladimir Oltean */ 2317e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 2327e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 2337e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 2347e14a2dcSVladimir Oltean 2357e14a2dcSVladimir Oltean switch (speed) { 2367e14a2dcSVladimir Oltean case SPEED_10: 2377e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 2387e14a2dcSVladimir Oltean break; 2397e14a2dcSVladimir Oltean case SPEED_100: 2407e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 2417e14a2dcSVladimir Oltean break; 2427e14a2dcSVladimir Oltean case SPEED_1000: 2437e14a2dcSVladimir Oltean case SPEED_2500: 2447e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 2457e14a2dcSVladimir Oltean break; 2467e14a2dcSVladimir Oltean default: 2477e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 2487e14a2dcSVladimir Oltean port, speed); 2497e14a2dcSVladimir Oltean return; 2507e14a2dcSVladimir Oltean } 2517e14a2dcSVladimir Oltean 2527e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 2537e14a2dcSVladimir Oltean * adaptation. 2547e14a2dcSVladimir Oltean */ 2557e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 2567e14a2dcSVladimir Oltean 2577e14a2dcSVladimir Oltean if (tx_pause) 2587e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 2597e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 2607e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 2617e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 2627e14a2dcSVladimir Oltean 2637e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 2647e14a2dcSVladimir Oltean * specification in incoming pause frames. 2657e14a2dcSVladimir Oltean */ 2667e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 2677e14a2dcSVladimir Oltean 2687e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 2697e14a2dcSVladimir Oltean 2707e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 2717e14a2dcSVladimir Oltean * enable MAC module 2727e14a2dcSVladimir Oltean */ 273bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 274bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 275bdeced75SVladimir Oltean 276bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 277bdeced75SVladimir Oltean * MAC addresses. 278bdeced75SVladimir Oltean */ 279bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 280bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 281bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 282bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 283bdeced75SVladimir Oltean 284bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 285886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, 286886e1387SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); 2877e14a2dcSVladimir Oltean 2887e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 2897e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 290bdeced75SVladimir Oltean } 291bdeced75SVladimir Oltean 292bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 293bd2b3161SXiaoliang Yang { 294bd2b3161SXiaoliang Yang int i; 295bd2b3161SXiaoliang Yang 296bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 297bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 298bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 299bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 300bd2b3161SXiaoliang Yang port); 301bd2b3161SXiaoliang Yang 30270d39a6eSVladimir Oltean for (i = 0; i < OCELOT_NUM_TC * 2; i++) { 303bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 304bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 305bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 306bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 307bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 308bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 309bd2b3161SXiaoliang Yang port, i); 310bd2b3161SXiaoliang Yang } 311bd2b3161SXiaoliang Yang } 312bd2b3161SXiaoliang Yang 31356051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 31456051948SVladimir Oltean u32 stringset, u8 *data) 31556051948SVladimir Oltean { 31656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 31756051948SVladimir Oltean 31856051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 31956051948SVladimir Oltean } 32056051948SVladimir Oltean 32156051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 32256051948SVladimir Oltean { 32356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 32456051948SVladimir Oltean 32556051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 32656051948SVladimir Oltean } 32756051948SVladimir Oltean 32856051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 32956051948SVladimir Oltean { 33056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 33156051948SVladimir Oltean 33256051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 33356051948SVladimir Oltean } 33456051948SVladimir Oltean 33556051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 33656051948SVladimir Oltean struct ethtool_ts_info *info) 33756051948SVladimir Oltean { 33856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 33956051948SVladimir Oltean 34056051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 34156051948SVladimir Oltean } 34256051948SVladimir Oltean 343bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 344bdeced75SVladimir Oltean struct device_node *ports_node, 345bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 346bdeced75SVladimir Oltean { 347bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 348bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 349bdeced75SVladimir Oltean struct device_node *child; 350bdeced75SVladimir Oltean 35137fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 352bdeced75SVladimir Oltean phy_interface_t phy_mode; 353bdeced75SVladimir Oltean u32 port; 354bdeced75SVladimir Oltean int err; 355bdeced75SVladimir Oltean 356bdeced75SVladimir Oltean /* Get switch port number from DT */ 357bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 358bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 359bdeced75SVladimir Oltean "(property \"reg\")\n"); 360bdeced75SVladimir Oltean of_node_put(child); 361bdeced75SVladimir Oltean return -ENODEV; 362bdeced75SVladimir Oltean } 363bdeced75SVladimir Oltean 364bdeced75SVladimir Oltean /* Get PHY mode from DT */ 365bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 366bdeced75SVladimir Oltean if (err) { 367bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 368bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 369bdeced75SVladimir Oltean port); 370bdeced75SVladimir Oltean of_node_put(child); 371bdeced75SVladimir Oltean return -ENODEV; 372bdeced75SVladimir Oltean } 373bdeced75SVladimir Oltean 374bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 375bdeced75SVladimir Oltean if (err < 0) { 376bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 377bdeced75SVladimir Oltean phy_modes(phy_mode), port); 37859ebb430SSumera Priyadarsini of_node_put(child); 379bdeced75SVladimir Oltean return err; 380bdeced75SVladimir Oltean } 381bdeced75SVladimir Oltean 382bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 383bdeced75SVladimir Oltean } 384bdeced75SVladimir Oltean 385bdeced75SVladimir Oltean return 0; 386bdeced75SVladimir Oltean } 387bdeced75SVladimir Oltean 388bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 389bdeced75SVladimir Oltean { 390bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 391bdeced75SVladimir Oltean struct device_node *switch_node; 392bdeced75SVladimir Oltean struct device_node *ports_node; 393bdeced75SVladimir Oltean int err; 394bdeced75SVladimir Oltean 395bdeced75SVladimir Oltean switch_node = dev->of_node; 396bdeced75SVladimir Oltean 397bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 398bdeced75SVladimir Oltean if (!ports_node) { 399bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 400bdeced75SVladimir Oltean return -ENODEV; 401bdeced75SVladimir Oltean } 402bdeced75SVladimir Oltean 403bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 404bdeced75SVladimir Oltean of_node_put(ports_node); 405bdeced75SVladimir Oltean 406bdeced75SVladimir Oltean return err; 407bdeced75SVladimir Oltean } 408bdeced75SVladimir Oltean 40956051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 41056051948SVladimir Oltean { 41156051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 412bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 413b4024c9eSClaudiu Manoil struct resource res; 41456051948SVladimir Oltean int port, i, err; 41556051948SVladimir Oltean 41656051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 41756051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 41856051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 41956051948SVladimir Oltean if (!ocelot->ports) 42056051948SVladimir Oltean return -ENOMEM; 42156051948SVladimir Oltean 42256051948SVladimir Oltean ocelot->map = felix->info->map; 42356051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 42456051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 42521ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 42607d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 42756051948SVladimir Oltean ocelot->ops = felix->info->ops; 428*cacea62fSVladimir Oltean ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; 429*cacea62fSVladimir Oltean ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; 430f59fd9caSVladimir Oltean ocelot->devlink = felix->ds->devlink; 43156051948SVladimir Oltean 432bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 433bdeced75SVladimir Oltean GFP_KERNEL); 434bdeced75SVladimir Oltean if (!port_phy_modes) 435bdeced75SVladimir Oltean return -ENOMEM; 436bdeced75SVladimir Oltean 437bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 438bdeced75SVladimir Oltean if (err) { 439bdeced75SVladimir Oltean kfree(port_phy_modes); 440bdeced75SVladimir Oltean return err; 441bdeced75SVladimir Oltean } 442bdeced75SVladimir Oltean 44356051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 44456051948SVladimir Oltean struct regmap *target; 44556051948SVladimir Oltean 44656051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 44756051948SVladimir Oltean continue; 44856051948SVladimir Oltean 449b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 450b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 451375e1314SVladimir Oltean res.start += felix->switch_base; 452375e1314SVladimir Oltean res.end += felix->switch_base; 45356051948SVladimir Oltean 454b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 45556051948SVladimir Oltean if (IS_ERR(target)) { 45656051948SVladimir Oltean dev_err(ocelot->dev, 45756051948SVladimir Oltean "Failed to map device memory space\n"); 458bdeced75SVladimir Oltean kfree(port_phy_modes); 45956051948SVladimir Oltean return PTR_ERR(target); 46056051948SVladimir Oltean } 46156051948SVladimir Oltean 46256051948SVladimir Oltean ocelot->targets[i] = target; 46356051948SVladimir Oltean } 46456051948SVladimir Oltean 46556051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 46656051948SVladimir Oltean if (err) { 46756051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 468bdeced75SVladimir Oltean kfree(port_phy_modes); 46956051948SVladimir Oltean return err; 47056051948SVladimir Oltean } 47156051948SVladimir Oltean 47256051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 47356051948SVladimir Oltean struct ocelot_port *ocelot_port; 47491c724cfSVladimir Oltean struct regmap *target; 47567c24049SVladimir Oltean u8 *template; 47656051948SVladimir Oltean 47756051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 47856051948SVladimir Oltean sizeof(struct ocelot_port), 47956051948SVladimir Oltean GFP_KERNEL); 48056051948SVladimir Oltean if (!ocelot_port) { 48156051948SVladimir Oltean dev_err(ocelot->dev, 48256051948SVladimir Oltean "failed to allocate port memory\n"); 483bdeced75SVladimir Oltean kfree(port_phy_modes); 48456051948SVladimir Oltean return -ENOMEM; 48556051948SVladimir Oltean } 48656051948SVladimir Oltean 487b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 488b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 489375e1314SVladimir Oltean res.start += felix->switch_base; 490375e1314SVladimir Oltean res.end += felix->switch_base; 49156051948SVladimir Oltean 49291c724cfSVladimir Oltean target = ocelot_regmap_init(ocelot, &res); 49391c724cfSVladimir Oltean if (IS_ERR(target)) { 49456051948SVladimir Oltean dev_err(ocelot->dev, 49591c724cfSVladimir Oltean "Failed to map memory space for port %d\n", 49691c724cfSVladimir Oltean port); 497bdeced75SVladimir Oltean kfree(port_phy_modes); 49891c724cfSVladimir Oltean return PTR_ERR(target); 49956051948SVladimir Oltean } 50056051948SVladimir Oltean 5015124197cSVladimir Oltean template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN, 50267c24049SVladimir Oltean GFP_KERNEL); 50367c24049SVladimir Oltean if (!template) { 50467c24049SVladimir Oltean dev_err(ocelot->dev, 50567c24049SVladimir Oltean "Failed to allocate memory for DSA tag\n"); 50667c24049SVladimir Oltean kfree(port_phy_modes); 50767c24049SVladimir Oltean return -ENOMEM; 50867c24049SVladimir Oltean } 50967c24049SVladimir Oltean 510bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 51156051948SVladimir Oltean ocelot_port->ocelot = ocelot; 51291c724cfSVladimir Oltean ocelot_port->target = target; 51367c24049SVladimir Oltean ocelot_port->xmit_template = template; 51456051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 51567c24049SVladimir Oltean 51667c24049SVladimir Oltean felix->info->xmit_template_populate(ocelot, port); 51756051948SVladimir Oltean } 51856051948SVladimir Oltean 519bdeced75SVladimir Oltean kfree(port_phy_modes); 520bdeced75SVladimir Oltean 521bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 522bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 523bdeced75SVladimir Oltean if (err < 0) 524bdeced75SVladimir Oltean return err; 525bdeced75SVladimir Oltean } 526bdeced75SVladimir Oltean 52756051948SVladimir Oltean return 0; 52856051948SVladimir Oltean } 52956051948SVladimir Oltean 5302d44b097SVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This 5312d44b097SVladimir Oltean * is the mode through which frames can be injected from and extracted to an 5322d44b097SVladimir Oltean * external CPU, over Ethernet. 5332d44b097SVladimir Oltean */ 5342d44b097SVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port) 5352d44b097SVladimir Oltean { 5362d44b097SVladimir Oltean ocelot->npi = port; 5372d44b097SVladimir Oltean 5382d44b097SVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | 5392d44b097SVladimir Oltean QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), 5402d44b097SVladimir Oltean QSYS_EXT_CPU_CFG); 5412d44b097SVladimir Oltean 5422d44b097SVladimir Oltean /* NPI port Injection/Extraction configuration */ 5432d44b097SVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 544*cacea62fSVladimir Oltean ocelot->npi_xtr_prefix); 5452d44b097SVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 546*cacea62fSVladimir Oltean ocelot->npi_inj_prefix); 5472d44b097SVladimir Oltean 5482d44b097SVladimir Oltean /* Disable transmission of pause frames */ 5492d44b097SVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); 5502d44b097SVladimir Oltean } 5512d44b097SVladimir Oltean 55256051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 55356051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 55456051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 55556051948SVladimir Oltean * (which will not work). 55656051948SVladimir Oltean */ 55756051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 55856051948SVladimir Oltean { 55956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 56056051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 56156051948SVladimir Oltean int port, err; 56256051948SVladimir Oltean 56356051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 56456051948SVladimir Oltean if (err) 56556051948SVladimir Oltean return err; 56656051948SVladimir Oltean 567d1cc0e93SVladimir Oltean err = ocelot_init(ocelot); 568d1cc0e93SVladimir Oltean if (err) 569d1cc0e93SVladimir Oltean return err; 570d1cc0e93SVladimir Oltean 5712b49d128SYangbo Lu if (ocelot->ptp) { 5722ac7c6c5SVladimir Oltean err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); 5732b49d128SYangbo Lu if (err) { 5742b49d128SYangbo Lu dev_err(ocelot->dev, 5752b49d128SYangbo Lu "Timestamp initialization failed\n"); 5762b49d128SYangbo Lu ocelot->ptp = 0; 5772b49d128SYangbo Lu } 5782b49d128SYangbo Lu } 57956051948SVladimir Oltean 58056051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 58156051948SVladimir Oltean ocelot_init_port(ocelot, port); 58256051948SVladimir Oltean 583b8fc7177SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 5842d44b097SVladimir Oltean felix_npi_port_init(ocelot, port); 585bd2b3161SXiaoliang Yang 586bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 587bd2b3161SXiaoliang Yang * bits of vlan tag. 588bd2b3161SXiaoliang Yang */ 589bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 59056051948SVladimir Oltean } 59156051948SVladimir Oltean 592f59fd9caSVladimir Oltean err = ocelot_devlink_sb_register(ocelot); 593f59fd9caSVladimir Oltean if (err) 594f59fd9caSVladimir Oltean return err; 595f59fd9caSVladimir Oltean 5961cf3299bSVladimir Oltean /* Include the CPU port module in the forwarding mask for unknown 5971cf3299bSVladimir Oltean * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST 5981cf3299bSVladimir Oltean * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since 5991cf3299bSVladimir Oltean * Ocelot relies on whitelisting MAC addresses towards PGID_CPU. 6001cf3299bSVladimir Oltean */ 6011cf3299bSVladimir Oltean ocelot_write_rix(ocelot, 6021cf3299bSVladimir Oltean ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)), 6031cf3299bSVladimir Oltean ANA_PGID_PGID, PGID_UC); 6041cf3299bSVladimir Oltean 6050b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 606c54913c1SVladimir Oltean ds->assisted_learning_on_cpu_port = true; 607bdeced75SVladimir Oltean 60856051948SVladimir Oltean return 0; 60956051948SVladimir Oltean } 61056051948SVladimir Oltean 61156051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 61256051948SVladimir Oltean { 61356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 614bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 615e5fb512dSVladimir Oltean int port; 616bdeced75SVladimir Oltean 617f59fd9caSVladimir Oltean ocelot_devlink_sb_unregister(ocelot); 618d19741b0SVladimir Oltean ocelot_deinit_timestamp(ocelot); 619d19741b0SVladimir Oltean ocelot_deinit(ocelot); 62056051948SVladimir Oltean 621e5fb512dSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) 622e5fb512dSVladimir Oltean ocelot_deinit_port(ocelot, port); 623d19741b0SVladimir Oltean 624d19741b0SVladimir Oltean if (felix->info->mdio_bus_free) 625d19741b0SVladimir Oltean felix->info->mdio_bus_free(ocelot); 62656051948SVladimir Oltean } 62756051948SVladimir Oltean 628c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 629c0bcf537SYangbo Lu struct ifreq *ifr) 630c0bcf537SYangbo Lu { 631c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 632c0bcf537SYangbo Lu 633c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 634c0bcf537SYangbo Lu } 635c0bcf537SYangbo Lu 636c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 637c0bcf537SYangbo Lu struct ifreq *ifr) 638c0bcf537SYangbo Lu { 639c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 640c0bcf537SYangbo Lu 641c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 642c0bcf537SYangbo Lu } 643c0bcf537SYangbo Lu 644c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 645c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 646c0bcf537SYangbo Lu { 647c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 648c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 649c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 650c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 651c0bcf537SYangbo Lu struct timespec64 ts; 652c0bcf537SYangbo Lu u64 tstamp, val; 653c0bcf537SYangbo Lu 654c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 655c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 656c0bcf537SYangbo Lu 657c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 658c0bcf537SYangbo Lu tstamp_lo = (u32)val; 659c0bcf537SYangbo Lu 660c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 661c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 662c0bcf537SYangbo Lu tstamp_hi--; 663c0bcf537SYangbo Lu 664c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 665c0bcf537SYangbo Lu 666c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 667c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 668c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 669c0bcf537SYangbo Lu return false; 670c0bcf537SYangbo Lu } 671c0bcf537SYangbo Lu 6723243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 673c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 674c0bcf537SYangbo Lu { 675c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 676c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 677c0bcf537SYangbo Lu 678e2f9a8feSVladimir Oltean if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) && 679e2f9a8feSVladimir Oltean ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 680e2f9a8feSVladimir Oltean ocelot_port_add_txtstamp_skb(ocelot, port, clone); 681c0bcf537SYangbo Lu return true; 682e2f9a8feSVladimir Oltean } 683c0bcf537SYangbo Lu 684c0bcf537SYangbo Lu return false; 685c0bcf537SYangbo Lu } 686c0bcf537SYangbo Lu 6870b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 6880b912fc9SVladimir Oltean { 6890b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 6900b912fc9SVladimir Oltean 6910b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 6920b912fc9SVladimir Oltean 6930b912fc9SVladimir Oltean return 0; 6940b912fc9SVladimir Oltean } 6950b912fc9SVladimir Oltean 6960b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 6970b912fc9SVladimir Oltean { 6980b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 6990b912fc9SVladimir Oltean 7000b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 7010b912fc9SVladimir Oltean } 7020b912fc9SVladimir Oltean 70307d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 70407d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 70507d985eeSVladimir Oltean { 70607d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 70707d985eeSVladimir Oltean 70807d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 70907d985eeSVladimir Oltean } 71007d985eeSVladimir Oltean 71107d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 71207d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 71307d985eeSVladimir Oltean { 71407d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 71507d985eeSVladimir Oltean 71607d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 71707d985eeSVladimir Oltean } 71807d985eeSVladimir Oltean 71907d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 72007d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 72107d985eeSVladimir Oltean { 72207d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 72307d985eeSVladimir Oltean 72407d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 72507d985eeSVladimir Oltean } 72607d985eeSVladimir Oltean 727fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 728fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 729fc411eaaSVladimir Oltean { 730fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 731fc411eaaSVladimir Oltean struct ocelot_policer pol = { 732fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 7335f035af7SPo Liu .burst = policer->burst, 734fc411eaaSVladimir Oltean }; 735fc411eaaSVladimir Oltean 736fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 737fc411eaaSVladimir Oltean } 738fc411eaaSVladimir Oltean 739fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 740fc411eaaSVladimir Oltean { 741fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 742fc411eaaSVladimir Oltean 743fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 744fc411eaaSVladimir Oltean } 745fc411eaaSVladimir Oltean 746de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 747de143c0eSXiaoliang Yang enum tc_setup_type type, 748de143c0eSXiaoliang Yang void *type_data) 749de143c0eSXiaoliang Yang { 750de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 751de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 752de143c0eSXiaoliang Yang 753de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 754de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 755de143c0eSXiaoliang Yang else 756de143c0eSXiaoliang Yang return -EOPNOTSUPP; 757de143c0eSXiaoliang Yang } 758de143c0eSXiaoliang Yang 759f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index, 760f59fd9caSVladimir Oltean u16 pool_index, 761f59fd9caSVladimir Oltean struct devlink_sb_pool_info *pool_info) 762f59fd9caSVladimir Oltean { 763f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 764f59fd9caSVladimir Oltean 765f59fd9caSVladimir Oltean return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info); 766f59fd9caSVladimir Oltean } 767f59fd9caSVladimir Oltean 768f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index, 769f59fd9caSVladimir Oltean u16 pool_index, u32 size, 770f59fd9caSVladimir Oltean enum devlink_sb_threshold_type threshold_type, 771f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 772f59fd9caSVladimir Oltean { 773f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 774f59fd9caSVladimir Oltean 775f59fd9caSVladimir Oltean return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size, 776f59fd9caSVladimir Oltean threshold_type, extack); 777f59fd9caSVladimir Oltean } 778f59fd9caSVladimir Oltean 779f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port, 780f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 781f59fd9caSVladimir Oltean u32 *p_threshold) 782f59fd9caSVladimir Oltean { 783f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 784f59fd9caSVladimir Oltean 785f59fd9caSVladimir Oltean return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index, 786f59fd9caSVladimir Oltean p_threshold); 787f59fd9caSVladimir Oltean } 788f59fd9caSVladimir Oltean 789f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port, 790f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 791f59fd9caSVladimir Oltean u32 threshold, struct netlink_ext_ack *extack) 792f59fd9caSVladimir Oltean { 793f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 794f59fd9caSVladimir Oltean 795f59fd9caSVladimir Oltean return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index, 796f59fd9caSVladimir Oltean threshold, extack); 797f59fd9caSVladimir Oltean } 798f59fd9caSVladimir Oltean 799f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port, 800f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 801f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 802f59fd9caSVladimir Oltean u16 *p_pool_index, u32 *p_threshold) 803f59fd9caSVladimir Oltean { 804f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 805f59fd9caSVladimir Oltean 806f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index, 807f59fd9caSVladimir Oltean pool_type, p_pool_index, 808f59fd9caSVladimir Oltean p_threshold); 809f59fd9caSVladimir Oltean } 810f59fd9caSVladimir Oltean 811f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port, 812f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 813f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 814f59fd9caSVladimir Oltean u16 pool_index, u32 threshold, 815f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 816f59fd9caSVladimir Oltean { 817f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 818f59fd9caSVladimir Oltean 819f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index, 820f59fd9caSVladimir Oltean pool_type, pool_index, threshold, 821f59fd9caSVladimir Oltean extack); 822f59fd9caSVladimir Oltean } 823f59fd9caSVladimir Oltean 824f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds, 825f59fd9caSVladimir Oltean unsigned int sb_index) 826f59fd9caSVladimir Oltean { 827f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 828f59fd9caSVladimir Oltean 829f59fd9caSVladimir Oltean return ocelot_sb_occ_snapshot(ocelot, sb_index); 830f59fd9caSVladimir Oltean } 831f59fd9caSVladimir Oltean 832f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds, 833f59fd9caSVladimir Oltean unsigned int sb_index) 834f59fd9caSVladimir Oltean { 835f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 836f59fd9caSVladimir Oltean 837f59fd9caSVladimir Oltean return ocelot_sb_occ_max_clear(ocelot, sb_index); 838f59fd9caSVladimir Oltean } 839f59fd9caSVladimir Oltean 840f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port, 841f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 842f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 843f59fd9caSVladimir Oltean { 844f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 845f59fd9caSVladimir Oltean 846f59fd9caSVladimir Oltean return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index, 847f59fd9caSVladimir Oltean p_cur, p_max); 848f59fd9caSVladimir Oltean } 849f59fd9caSVladimir Oltean 850f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port, 851f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 852f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 853f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 854f59fd9caSVladimir Oltean { 855f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 856f59fd9caSVladimir Oltean 857f59fd9caSVladimir Oltean return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index, 858f59fd9caSVladimir Oltean pool_type, p_cur, p_max); 859f59fd9caSVladimir Oltean } 860f59fd9caSVladimir Oltean 861375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = { 86256051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 86356051948SVladimir Oltean .setup = felix_setup, 86456051948SVladimir Oltean .teardown = felix_teardown, 86556051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 86656051948SVladimir Oltean .get_strings = felix_get_strings, 86756051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 86856051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 86956051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 870bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 871bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 872bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 873bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 87456051948SVladimir Oltean .port_enable = felix_port_enable, 87556051948SVladimir Oltean .port_disable = felix_port_disable, 87656051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 87756051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 87856051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 879209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 880209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 88156051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 88256051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 88356051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 88456051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 88556051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 88656051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 887c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 888c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 889c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 890c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 8910b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 8920b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 893fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 894fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 89507d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 89607d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 89707d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 898de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 899f59fd9caSVladimir Oltean .devlink_sb_pool_get = felix_sb_pool_get, 900f59fd9caSVladimir Oltean .devlink_sb_pool_set = felix_sb_pool_set, 901f59fd9caSVladimir Oltean .devlink_sb_port_pool_get = felix_sb_port_pool_get, 902f59fd9caSVladimir Oltean .devlink_sb_port_pool_set = felix_sb_port_pool_set, 903f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get, 904f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set, 905f59fd9caSVladimir Oltean .devlink_sb_occ_snapshot = felix_sb_occ_snapshot, 906f59fd9caSVladimir Oltean .devlink_sb_occ_max_clear = felix_sb_occ_max_clear, 907f59fd9caSVladimir Oltean .devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get, 908f59fd9caSVladimir Oltean .devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get, 90956051948SVladimir Oltean }; 910319e4dd1SVladimir Oltean 911319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) 912319e4dd1SVladimir Oltean { 913319e4dd1SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 914319e4dd1SVladimir Oltean struct dsa_switch *ds = felix->ds; 915319e4dd1SVladimir Oltean 916319e4dd1SVladimir Oltean if (!dsa_is_user_port(ds, port)) 917319e4dd1SVladimir Oltean return NULL; 918319e4dd1SVladimir Oltean 919319e4dd1SVladimir Oltean return dsa_to_port(ds, port)->slave; 920319e4dd1SVladimir Oltean } 921319e4dd1SVladimir Oltean 922319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev) 923319e4dd1SVladimir Oltean { 924319e4dd1SVladimir Oltean struct dsa_port *dp; 925319e4dd1SVladimir Oltean 926319e4dd1SVladimir Oltean dp = dsa_port_from_netdev(dev); 927319e4dd1SVladimir Oltean if (IS_ERR(dp)) 928319e4dd1SVladimir Oltean return -EINVAL; 929319e4dd1SVladimir Oltean 930319e4dd1SVladimir Oltean return dp->index; 931319e4dd1SVladimir Oltean } 932