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> 22fc411eaaSVladimir Oltean #include <net/pkt_sched.h> 2356051948SVladimir Oltean #include <net/dsa.h> 2456051948SVladimir Oltean #include "felix.h" 2556051948SVladimir Oltean 2656051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 274d776482SFlorian Fainelli int port, 284d776482SFlorian Fainelli enum dsa_tag_protocol mp) 2956051948SVladimir Oltean { 3056051948SVladimir Oltean return DSA_TAG_PROTO_OCELOT; 3156051948SVladimir Oltean } 3256051948SVladimir Oltean 3356051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 3456051948SVladimir Oltean unsigned int ageing_time) 3556051948SVladimir Oltean { 3656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 3756051948SVladimir Oltean 3856051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 3956051948SVladimir Oltean 4056051948SVladimir Oltean return 0; 4156051948SVladimir Oltean } 4256051948SVladimir Oltean 4356051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 4456051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 4556051948SVladimir Oltean { 4656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 4756051948SVladimir Oltean 4856051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 4956051948SVladimir Oltean } 5056051948SVladimir Oltean 5156051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 5256051948SVladimir Oltean const unsigned char *addr, u16 vid) 5356051948SVladimir Oltean { 5456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 5556051948SVladimir Oltean 5687b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 5756051948SVladimir Oltean } 5856051948SVladimir Oltean 5956051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 6056051948SVladimir Oltean const unsigned char *addr, u16 vid) 6156051948SVladimir Oltean { 6256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 6356051948SVladimir Oltean 6456051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 6556051948SVladimir Oltean } 6656051948SVladimir Oltean 67209edf95SVladimir Oltean /* This callback needs to be present */ 68209edf95SVladimir Oltean static int felix_mdb_prepare(struct dsa_switch *ds, int port, 69209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 70209edf95SVladimir Oltean { 71209edf95SVladimir Oltean return 0; 72209edf95SVladimir Oltean } 73209edf95SVladimir Oltean 74209edf95SVladimir Oltean static void felix_mdb_add(struct dsa_switch *ds, int port, 75209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 76209edf95SVladimir Oltean { 77209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 78209edf95SVladimir Oltean 79209edf95SVladimir Oltean ocelot_port_mdb_add(ocelot, port, mdb); 80209edf95SVladimir Oltean } 81209edf95SVladimir Oltean 82209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 83209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 84209edf95SVladimir Oltean { 85209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 86209edf95SVladimir Oltean 87209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 88209edf95SVladimir Oltean } 89209edf95SVladimir Oltean 9056051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 9156051948SVladimir Oltean u8 state) 9256051948SVladimir Oltean { 9356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 9456051948SVladimir Oltean 9556051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 9656051948SVladimir Oltean } 9756051948SVladimir Oltean 9856051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 9956051948SVladimir Oltean struct net_device *br) 10056051948SVladimir Oltean { 10156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 10256051948SVladimir Oltean 10356051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 10456051948SVladimir Oltean } 10556051948SVladimir Oltean 10656051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 10756051948SVladimir Oltean struct net_device *br) 10856051948SVladimir Oltean { 10956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 11056051948SVladimir Oltean 11156051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 11256051948SVladimir Oltean } 11356051948SVladimir Oltean 11456051948SVladimir Oltean /* This callback needs to be present */ 11556051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 11656051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 11756051948SVladimir Oltean { 11856051948SVladimir Oltean return 0; 11956051948SVladimir Oltean } 12056051948SVladimir Oltean 12156051948SVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 12256051948SVladimir Oltean { 12356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 12456051948SVladimir Oltean 12556051948SVladimir Oltean ocelot_port_vlan_filtering(ocelot, port, enabled); 12656051948SVladimir Oltean 12756051948SVladimir Oltean return 0; 12856051948SVladimir Oltean } 12956051948SVladimir Oltean 13056051948SVladimir Oltean static void felix_vlan_add(struct dsa_switch *ds, int port, 13156051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 13256051948SVladimir Oltean { 13356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 134183be6f9SVladimir Oltean u16 flags = vlan->flags; 13556051948SVladimir Oltean u16 vid; 13656051948SVladimir Oltean int err; 13756051948SVladimir Oltean 138183be6f9SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 139183be6f9SVladimir Oltean flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; 140183be6f9SVladimir Oltean 14156051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 14256051948SVladimir Oltean err = ocelot_vlan_add(ocelot, port, vid, 143183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 144183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 14556051948SVladimir Oltean if (err) { 14656051948SVladimir Oltean dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n", 14756051948SVladimir Oltean vid, port, err); 14856051948SVladimir Oltean return; 14956051948SVladimir Oltean } 15056051948SVladimir Oltean } 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 u16 vid; 15856051948SVladimir Oltean int err; 15956051948SVladimir Oltean 16056051948SVladimir Oltean for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 16156051948SVladimir Oltean err = ocelot_vlan_del(ocelot, port, vid); 16256051948SVladimir Oltean if (err) { 16356051948SVladimir Oltean dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", 16456051948SVladimir Oltean vid, port, err); 16556051948SVladimir Oltean return err; 16656051948SVladimir Oltean } 16756051948SVladimir Oltean } 16856051948SVladimir Oltean return 0; 16956051948SVladimir Oltean } 17056051948SVladimir Oltean 17156051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 17256051948SVladimir Oltean struct phy_device *phy) 17356051948SVladimir Oltean { 17456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 17556051948SVladimir Oltean 17656051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 17756051948SVladimir Oltean 17856051948SVladimir Oltean return 0; 17956051948SVladimir Oltean } 18056051948SVladimir Oltean 18156051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 18256051948SVladimir Oltean { 18356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 18456051948SVladimir Oltean 18556051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 18656051948SVladimir Oltean } 18756051948SVladimir Oltean 188bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 189bdeced75SVladimir Oltean unsigned long *supported, 190bdeced75SVladimir Oltean struct phylink_link_state *state) 191bdeced75SVladimir Oltean { 192bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 193375e1314SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 194bdeced75SVladimir Oltean 195375e1314SVladimir Oltean if (felix->info->phylink_validate) 196375e1314SVladimir Oltean felix->info->phylink_validate(ocelot, port, supported, state); 197bdeced75SVladimir Oltean } 198bdeced75SVladimir Oltean 199bdeced75SVladimir Oltean static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, 200bdeced75SVladimir Oltean struct phylink_link_state *state) 201bdeced75SVladimir Oltean { 202bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 203bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 204bdeced75SVladimir Oltean 205bdeced75SVladimir Oltean if (felix->info->pcs_link_state) 206bdeced75SVladimir Oltean felix->info->pcs_link_state(ocelot, port, state); 207bdeced75SVladimir Oltean 208bdeced75SVladimir Oltean return 0; 209bdeced75SVladimir Oltean } 210bdeced75SVladimir Oltean 211bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 212bdeced75SVladimir Oltean unsigned int link_an_mode, 213bdeced75SVladimir Oltean const struct phylink_link_state *state) 214bdeced75SVladimir Oltean { 215bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 216bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 217bdeced75SVladimir Oltean 2187e14a2dcSVladimir Oltean if (felix->info->pcs_config) 2197e14a2dcSVladimir Oltean felix->info->pcs_config(ocelot, port, link_an_mode, state); 220bdeced75SVladimir Oltean } 221bdeced75SVladimir Oltean 222bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 223bdeced75SVladimir Oltean unsigned int link_an_mode, 224bdeced75SVladimir Oltean phy_interface_t interface) 225bdeced75SVladimir Oltean { 226bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 227bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 228bdeced75SVladimir Oltean 229bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 230886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); 231bdeced75SVladimir Oltean } 232bdeced75SVladimir Oltean 233bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 234bdeced75SVladimir Oltean unsigned int link_an_mode, 235bdeced75SVladimir Oltean phy_interface_t interface, 2365b502a7bSRussell King struct phy_device *phydev, 2375b502a7bSRussell King int speed, int duplex, 2385b502a7bSRussell King bool tx_pause, bool rx_pause) 239bdeced75SVladimir Oltean { 240bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 241bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 2427e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 2437e14a2dcSVladimir Oltean u32 mac_fc_cfg; 244bdeced75SVladimir Oltean 2457e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 2467e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 2477e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 2487e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 2497e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 2507e14a2dcSVladimir Oltean * value). 2517e14a2dcSVladimir Oltean */ 2527e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 2537e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 2547e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 2557e14a2dcSVladimir Oltean 2567e14a2dcSVladimir Oltean switch (speed) { 2577e14a2dcSVladimir Oltean case SPEED_10: 2587e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 2597e14a2dcSVladimir Oltean break; 2607e14a2dcSVladimir Oltean case SPEED_100: 2617e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 2627e14a2dcSVladimir Oltean break; 2637e14a2dcSVladimir Oltean case SPEED_1000: 2647e14a2dcSVladimir Oltean case SPEED_2500: 2657e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 2667e14a2dcSVladimir Oltean break; 2677e14a2dcSVladimir Oltean default: 2687e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 2697e14a2dcSVladimir Oltean port, speed); 2707e14a2dcSVladimir Oltean return; 2717e14a2dcSVladimir Oltean } 2727e14a2dcSVladimir Oltean 2737e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 2747e14a2dcSVladimir Oltean * adaptation. 2757e14a2dcSVladimir Oltean */ 2767e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 2777e14a2dcSVladimir Oltean 2787e14a2dcSVladimir Oltean if (tx_pause) 2797e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 2807e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 2817e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 2827e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 2837e14a2dcSVladimir Oltean 2847e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 2857e14a2dcSVladimir Oltean * specification in incoming pause frames. 2867e14a2dcSVladimir Oltean */ 2877e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 2887e14a2dcSVladimir Oltean 2897e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 2907e14a2dcSVladimir Oltean 2917e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 2927e14a2dcSVladimir Oltean * enable MAC module 2937e14a2dcSVladimir Oltean */ 294bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 295bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 296bdeced75SVladimir Oltean 297bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 298bdeced75SVladimir Oltean * MAC addresses. 299bdeced75SVladimir Oltean */ 300bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 301bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 302bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 303bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 304bdeced75SVladimir Oltean 305bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 306886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, 307886e1387SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); 3087e14a2dcSVladimir Oltean 3097e14a2dcSVladimir Oltean if (felix->info->pcs_link_up) 3107e14a2dcSVladimir Oltean felix->info->pcs_link_up(ocelot, port, link_an_mode, interface, 3117e14a2dcSVladimir Oltean speed, duplex); 3127e14a2dcSVladimir Oltean 3137e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 3147e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 315bdeced75SVladimir Oltean } 316bdeced75SVladimir Oltean 317bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 318bd2b3161SXiaoliang Yang { 319bd2b3161SXiaoliang Yang int i; 320bd2b3161SXiaoliang Yang 321bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 322bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 323bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 324bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 325bd2b3161SXiaoliang Yang port); 326bd2b3161SXiaoliang Yang 327bd2b3161SXiaoliang Yang for (i = 0; i < FELIX_NUM_TC * 2; i++) { 328bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 329bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 330bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 331bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 332bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 333bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 334bd2b3161SXiaoliang Yang port, i); 335bd2b3161SXiaoliang Yang } 336bd2b3161SXiaoliang Yang } 337bd2b3161SXiaoliang Yang 33856051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 33956051948SVladimir Oltean u32 stringset, u8 *data) 34056051948SVladimir Oltean { 34156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 34256051948SVladimir Oltean 34356051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 34456051948SVladimir Oltean } 34556051948SVladimir Oltean 34656051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 34756051948SVladimir Oltean { 34856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 34956051948SVladimir Oltean 35056051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 35156051948SVladimir Oltean } 35256051948SVladimir Oltean 35356051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 35456051948SVladimir Oltean { 35556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 35656051948SVladimir Oltean 35756051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 35856051948SVladimir Oltean } 35956051948SVladimir Oltean 36056051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 36156051948SVladimir Oltean struct ethtool_ts_info *info) 36256051948SVladimir Oltean { 36356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 36456051948SVladimir Oltean 36556051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 36656051948SVladimir Oltean } 36756051948SVladimir Oltean 368bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 369bdeced75SVladimir Oltean struct device_node *ports_node, 370bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 371bdeced75SVladimir Oltean { 372bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 373bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 374bdeced75SVladimir Oltean struct device_node *child; 375bdeced75SVladimir Oltean 37637fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 377bdeced75SVladimir Oltean phy_interface_t phy_mode; 378bdeced75SVladimir Oltean u32 port; 379bdeced75SVladimir Oltean int err; 380bdeced75SVladimir Oltean 381bdeced75SVladimir Oltean /* Get switch port number from DT */ 382bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 383bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 384bdeced75SVladimir Oltean "(property \"reg\")\n"); 385bdeced75SVladimir Oltean of_node_put(child); 386bdeced75SVladimir Oltean return -ENODEV; 387bdeced75SVladimir Oltean } 388bdeced75SVladimir Oltean 389bdeced75SVladimir Oltean /* Get PHY mode from DT */ 390bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 391bdeced75SVladimir Oltean if (err) { 392bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 393bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 394bdeced75SVladimir Oltean port); 395bdeced75SVladimir Oltean of_node_put(child); 396bdeced75SVladimir Oltean return -ENODEV; 397bdeced75SVladimir Oltean } 398bdeced75SVladimir Oltean 399bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 400bdeced75SVladimir Oltean if (err < 0) { 401bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 402bdeced75SVladimir Oltean phy_modes(phy_mode), port); 40359ebb430SSumera Priyadarsini of_node_put(child); 404bdeced75SVladimir Oltean return err; 405bdeced75SVladimir Oltean } 406bdeced75SVladimir Oltean 407bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 408bdeced75SVladimir Oltean } 409bdeced75SVladimir Oltean 410bdeced75SVladimir Oltean return 0; 411bdeced75SVladimir Oltean } 412bdeced75SVladimir Oltean 413bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 414bdeced75SVladimir Oltean { 415bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 416bdeced75SVladimir Oltean struct device_node *switch_node; 417bdeced75SVladimir Oltean struct device_node *ports_node; 418bdeced75SVladimir Oltean int err; 419bdeced75SVladimir Oltean 420bdeced75SVladimir Oltean switch_node = dev->of_node; 421bdeced75SVladimir Oltean 422bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 423bdeced75SVladimir Oltean if (!ports_node) { 424bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 425bdeced75SVladimir Oltean return -ENODEV; 426bdeced75SVladimir Oltean } 427bdeced75SVladimir Oltean 428bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 429bdeced75SVladimir Oltean of_node_put(ports_node); 430bdeced75SVladimir Oltean 431bdeced75SVladimir Oltean return err; 432bdeced75SVladimir Oltean } 433bdeced75SVladimir Oltean 43456051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 43556051948SVladimir Oltean { 43656051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 437bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 438b4024c9eSClaudiu Manoil struct resource res; 43956051948SVladimir Oltean int port, i, err; 44056051948SVladimir Oltean 44156051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 44256051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 44356051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 44456051948SVladimir Oltean if (!ocelot->ports) 44556051948SVladimir Oltean return -ENOMEM; 44656051948SVladimir Oltean 44756051948SVladimir Oltean ocelot->map = felix->info->map; 44856051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 44956051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 45056051948SVladimir Oltean ocelot->shared_queue_sz = felix->info->shared_queue_sz; 45121ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 45207d985eeSVladimir Oltean ocelot->vcap_is2_keys = felix->info->vcap_is2_keys; 45307d985eeSVladimir Oltean ocelot->vcap_is2_actions= felix->info->vcap_is2_actions; 45407d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 45556051948SVladimir Oltean ocelot->ops = felix->info->ops; 45656051948SVladimir Oltean 457bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 458bdeced75SVladimir Oltean GFP_KERNEL); 459bdeced75SVladimir Oltean if (!port_phy_modes) 460bdeced75SVladimir Oltean return -ENOMEM; 461bdeced75SVladimir Oltean 462bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 463bdeced75SVladimir Oltean if (err) { 464bdeced75SVladimir Oltean kfree(port_phy_modes); 465bdeced75SVladimir Oltean return err; 466bdeced75SVladimir Oltean } 467bdeced75SVladimir Oltean 46856051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 46956051948SVladimir Oltean struct regmap *target; 47056051948SVladimir Oltean 47156051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 47256051948SVladimir Oltean continue; 47356051948SVladimir Oltean 474b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 475b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 476375e1314SVladimir Oltean res.start += felix->switch_base; 477375e1314SVladimir Oltean res.end += felix->switch_base; 47856051948SVladimir Oltean 479b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 48056051948SVladimir Oltean if (IS_ERR(target)) { 48156051948SVladimir Oltean dev_err(ocelot->dev, 48256051948SVladimir Oltean "Failed to map device memory space\n"); 483bdeced75SVladimir Oltean kfree(port_phy_modes); 48456051948SVladimir Oltean return PTR_ERR(target); 48556051948SVladimir Oltean } 48656051948SVladimir Oltean 48756051948SVladimir Oltean ocelot->targets[i] = target; 48856051948SVladimir Oltean } 48956051948SVladimir Oltean 49056051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 49156051948SVladimir Oltean if (err) { 49256051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 493bdeced75SVladimir Oltean kfree(port_phy_modes); 49456051948SVladimir Oltean return err; 49556051948SVladimir Oltean } 49656051948SVladimir Oltean 49756051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 49856051948SVladimir Oltean struct ocelot_port *ocelot_port; 49991c724cfSVladimir Oltean struct regmap *target; 50067c24049SVladimir Oltean u8 *template; 50156051948SVladimir Oltean 50256051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 50356051948SVladimir Oltean sizeof(struct ocelot_port), 50456051948SVladimir Oltean GFP_KERNEL); 50556051948SVladimir Oltean if (!ocelot_port) { 50656051948SVladimir Oltean dev_err(ocelot->dev, 50756051948SVladimir Oltean "failed to allocate port memory\n"); 508bdeced75SVladimir Oltean kfree(port_phy_modes); 50956051948SVladimir Oltean return -ENOMEM; 51056051948SVladimir Oltean } 51156051948SVladimir Oltean 512b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 513b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 514375e1314SVladimir Oltean res.start += felix->switch_base; 515375e1314SVladimir Oltean res.end += felix->switch_base; 51656051948SVladimir Oltean 51791c724cfSVladimir Oltean target = ocelot_regmap_init(ocelot, &res); 51891c724cfSVladimir Oltean if (IS_ERR(target)) { 51956051948SVladimir Oltean dev_err(ocelot->dev, 52091c724cfSVladimir Oltean "Failed to map memory space for port %d\n", 52191c724cfSVladimir Oltean port); 522bdeced75SVladimir Oltean kfree(port_phy_modes); 52391c724cfSVladimir Oltean return PTR_ERR(target); 52456051948SVladimir Oltean } 52556051948SVladimir Oltean 52667c24049SVladimir Oltean template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN, 52767c24049SVladimir Oltean GFP_KERNEL); 52867c24049SVladimir Oltean if (!template) { 52967c24049SVladimir Oltean dev_err(ocelot->dev, 53067c24049SVladimir Oltean "Failed to allocate memory for DSA tag\n"); 53167c24049SVladimir Oltean kfree(port_phy_modes); 53267c24049SVladimir Oltean return -ENOMEM; 53367c24049SVladimir Oltean } 53467c24049SVladimir Oltean 535bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 53656051948SVladimir Oltean ocelot_port->ocelot = ocelot; 53791c724cfSVladimir Oltean ocelot_port->target = target; 53867c24049SVladimir Oltean ocelot_port->xmit_template = template; 53956051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 54067c24049SVladimir Oltean 54167c24049SVladimir Oltean felix->info->xmit_template_populate(ocelot, port); 54256051948SVladimir Oltean } 54356051948SVladimir Oltean 544bdeced75SVladimir Oltean kfree(port_phy_modes); 545bdeced75SVladimir Oltean 546bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 547bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 548bdeced75SVladimir Oltean if (err < 0) 549bdeced75SVladimir Oltean return err; 550bdeced75SVladimir Oltean } 551bdeced75SVladimir Oltean 55256051948SVladimir Oltean return 0; 55356051948SVladimir Oltean } 55456051948SVladimir Oltean 5552b49d128SYangbo Lu static struct ptp_clock_info ocelot_ptp_clock_info = { 5562b49d128SYangbo Lu .owner = THIS_MODULE, 5572b49d128SYangbo Lu .name = "felix ptp", 5582b49d128SYangbo Lu .max_adj = 0x7fffffff, 5592b49d128SYangbo Lu .n_alarm = 0, 5602b49d128SYangbo Lu .n_ext_ts = 0, 5615287be40SYangbo Lu .n_per_out = OCELOT_PTP_PINS_NUM, 5625287be40SYangbo Lu .n_pins = OCELOT_PTP_PINS_NUM, 5632b49d128SYangbo Lu .pps = 0, 5642b49d128SYangbo Lu .gettime64 = ocelot_ptp_gettime64, 5652b49d128SYangbo Lu .settime64 = ocelot_ptp_settime64, 5662b49d128SYangbo Lu .adjtime = ocelot_ptp_adjtime, 5672b49d128SYangbo Lu .adjfine = ocelot_ptp_adjfine, 5685287be40SYangbo Lu .verify = ocelot_ptp_verify, 5695287be40SYangbo Lu .enable = ocelot_ptp_enable, 5702b49d128SYangbo Lu }; 5712b49d128SYangbo Lu 57256051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 57356051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 57456051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 57556051948SVladimir Oltean * (which will not work). 57656051948SVladimir Oltean */ 57756051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 57856051948SVladimir Oltean { 57956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 58056051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 58156051948SVladimir Oltean int port, err; 5823c7b51bdSXiaoliang Yang int tc; 58356051948SVladimir Oltean 58456051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 58556051948SVladimir Oltean if (err) 58656051948SVladimir Oltean return err; 58756051948SVladimir Oltean 588*d1cc0e93SVladimir Oltean err = ocelot_init(ocelot); 589*d1cc0e93SVladimir Oltean if (err) 590*d1cc0e93SVladimir Oltean return err; 591*d1cc0e93SVladimir Oltean 5922b49d128SYangbo Lu if (ocelot->ptp) { 5932b49d128SYangbo Lu err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); 5942b49d128SYangbo Lu if (err) { 5952b49d128SYangbo Lu dev_err(ocelot->dev, 5962b49d128SYangbo Lu "Timestamp initialization failed\n"); 5972b49d128SYangbo Lu ocelot->ptp = 0; 5982b49d128SYangbo Lu } 5992b49d128SYangbo Lu } 60056051948SVladimir Oltean 60156051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 60256051948SVladimir Oltean ocelot_init_port(ocelot, port); 60356051948SVladimir Oltean 60469df578cSVladimir Oltean /* Bring up the CPU port module and configure the NPI port */ 605b8fc7177SVladimir Oltean if (dsa_is_cpu_port(ds, port)) 60669df578cSVladimir Oltean ocelot_configure_cpu(ocelot, port, 60756051948SVladimir Oltean OCELOT_TAG_PREFIX_NONE, 60856051948SVladimir Oltean OCELOT_TAG_PREFIX_LONG); 609bd2b3161SXiaoliang Yang 610bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 611bd2b3161SXiaoliang Yang * bits of vlan tag. 612bd2b3161SXiaoliang Yang */ 613bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 61456051948SVladimir Oltean } 61556051948SVladimir Oltean 6161cf3299bSVladimir Oltean /* Include the CPU port module in the forwarding mask for unknown 6171cf3299bSVladimir Oltean * unicast - the hardware default value for ANA_FLOODING_FLD_UNICAST 6181cf3299bSVladimir Oltean * excludes BIT(ocelot->num_phys_ports), and so does ocelot_init, since 6191cf3299bSVladimir Oltean * Ocelot relies on whitelisting MAC addresses towards PGID_CPU. 6201cf3299bSVladimir Oltean */ 6211cf3299bSVladimir Oltean ocelot_write_rix(ocelot, 6221cf3299bSVladimir Oltean ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)), 6231cf3299bSVladimir Oltean ANA_PGID_PGID, PGID_UC); 6243c7b51bdSXiaoliang Yang /* Setup the per-traffic class flooding PGIDs */ 6253c7b51bdSXiaoliang Yang for (tc = 0; tc < FELIX_NUM_TC; tc++) 6263c7b51bdSXiaoliang Yang ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) | 6273c7b51bdSXiaoliang Yang ANA_FLOODING_FLD_BROADCAST(PGID_MC) | 6283c7b51bdSXiaoliang Yang ANA_FLOODING_FLD_UNICAST(PGID_UC), 6293c7b51bdSXiaoliang Yang ANA_FLOODING, tc); 6301cf3299bSVladimir Oltean 6310b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 632626a8323SVladimir Oltean ds->configure_vlan_while_not_filtering = true; 633bdeced75SVladimir Oltean /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040) 634bdeced75SVladimir Oltean * isn't instantiated for the Felix PF. 635bdeced75SVladimir Oltean * In-band AN may take a few ms to complete, so we need to poll. 636bdeced75SVladimir Oltean */ 637bdeced75SVladimir Oltean ds->pcs_poll = true; 638bdeced75SVladimir Oltean 63956051948SVladimir Oltean return 0; 64056051948SVladimir Oltean } 64156051948SVladimir Oltean 64256051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 64356051948SVladimir Oltean { 64456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 645bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 646bdeced75SVladimir Oltean 647bdeced75SVladimir Oltean if (felix->info->mdio_bus_free) 648bdeced75SVladimir Oltean felix->info->mdio_bus_free(ocelot); 64956051948SVladimir Oltean 6502b49d128SYangbo Lu ocelot_deinit_timestamp(ocelot); 65156051948SVladimir Oltean /* stop workqueue thread */ 65256051948SVladimir Oltean ocelot_deinit(ocelot); 65356051948SVladimir Oltean } 65456051948SVladimir Oltean 655c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 656c0bcf537SYangbo Lu struct ifreq *ifr) 657c0bcf537SYangbo Lu { 658c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 659c0bcf537SYangbo Lu 660c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 661c0bcf537SYangbo Lu } 662c0bcf537SYangbo Lu 663c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 664c0bcf537SYangbo Lu struct ifreq *ifr) 665c0bcf537SYangbo Lu { 666c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 667c0bcf537SYangbo Lu 668c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 669c0bcf537SYangbo Lu } 670c0bcf537SYangbo Lu 671c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 672c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 673c0bcf537SYangbo Lu { 674c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 675c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 676c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 677c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 678c0bcf537SYangbo Lu struct timespec64 ts; 679c0bcf537SYangbo Lu u64 tstamp, val; 680c0bcf537SYangbo Lu 681c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 682c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 683c0bcf537SYangbo Lu 684c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 685c0bcf537SYangbo Lu tstamp_lo = (u32)val; 686c0bcf537SYangbo Lu 687c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 688c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 689c0bcf537SYangbo Lu tstamp_hi--; 690c0bcf537SYangbo Lu 691c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 692c0bcf537SYangbo Lu 693c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 694c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 695c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 696c0bcf537SYangbo Lu return false; 697c0bcf537SYangbo Lu } 698c0bcf537SYangbo Lu 6993243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 700c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 701c0bcf537SYangbo Lu { 702c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 703c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 704c0bcf537SYangbo Lu 705c0bcf537SYangbo Lu if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone)) 706c0bcf537SYangbo Lu return true; 707c0bcf537SYangbo Lu 708c0bcf537SYangbo Lu return false; 709c0bcf537SYangbo Lu } 710c0bcf537SYangbo Lu 7110b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 7120b912fc9SVladimir Oltean { 7130b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 7140b912fc9SVladimir Oltean 7150b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 7160b912fc9SVladimir Oltean 7170b912fc9SVladimir Oltean return 0; 7180b912fc9SVladimir Oltean } 7190b912fc9SVladimir Oltean 7200b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 7210b912fc9SVladimir Oltean { 7220b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 7230b912fc9SVladimir Oltean 7240b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 7250b912fc9SVladimir Oltean } 7260b912fc9SVladimir Oltean 72707d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 72807d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 72907d985eeSVladimir Oltean { 73007d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 73107d985eeSVladimir Oltean 73207d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 73307d985eeSVladimir Oltean } 73407d985eeSVladimir Oltean 73507d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 73607d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 73707d985eeSVladimir Oltean { 73807d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 73907d985eeSVladimir Oltean 74007d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 74107d985eeSVladimir Oltean } 74207d985eeSVladimir Oltean 74307d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 74407d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 74507d985eeSVladimir Oltean { 74607d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 74707d985eeSVladimir Oltean 74807d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 74907d985eeSVladimir Oltean } 75007d985eeSVladimir Oltean 751fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 752fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 753fc411eaaSVladimir Oltean { 754fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 755fc411eaaSVladimir Oltean struct ocelot_policer pol = { 756fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 7575f035af7SPo Liu .burst = policer->burst, 758fc411eaaSVladimir Oltean }; 759fc411eaaSVladimir Oltean 760fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 761fc411eaaSVladimir Oltean } 762fc411eaaSVladimir Oltean 763fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 764fc411eaaSVladimir Oltean { 765fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 766fc411eaaSVladimir Oltean 767fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 768fc411eaaSVladimir Oltean } 769fc411eaaSVladimir Oltean 770de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 771de143c0eSXiaoliang Yang enum tc_setup_type type, 772de143c0eSXiaoliang Yang void *type_data) 773de143c0eSXiaoliang Yang { 774de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 775de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 776de143c0eSXiaoliang Yang 777de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 778de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 779de143c0eSXiaoliang Yang else 780de143c0eSXiaoliang Yang return -EOPNOTSUPP; 781de143c0eSXiaoliang Yang } 782de143c0eSXiaoliang Yang 783375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = { 78456051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 78556051948SVladimir Oltean .setup = felix_setup, 78656051948SVladimir Oltean .teardown = felix_teardown, 78756051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 78856051948SVladimir Oltean .get_strings = felix_get_strings, 78956051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 79056051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 79156051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 792bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 793bdeced75SVladimir Oltean .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, 794bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 795bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 796bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 79756051948SVladimir Oltean .port_enable = felix_port_enable, 79856051948SVladimir Oltean .port_disable = felix_port_disable, 79956051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 80056051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 80156051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 802209edf95SVladimir Oltean .port_mdb_prepare = felix_mdb_prepare, 803209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 804209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 80556051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 80656051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 80756051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 80856051948SVladimir Oltean .port_vlan_prepare = felix_vlan_prepare, 80956051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 81056051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 81156051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 812c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 813c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 814c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 815c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 8160b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 8170b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 818fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 819fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 82007d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 82107d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 82207d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 823de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 82456051948SVladimir Oltean }; 82556051948SVladimir Oltean 826375e1314SVladimir Oltean static int __init felix_init(void) 827c0bcf537SYangbo Lu { 82884705fc1SMaxim Kochetkov int err; 82984705fc1SMaxim Kochetkov 83084705fc1SMaxim Kochetkov err = pci_register_driver(&felix_vsc9959_pci_driver); 83184705fc1SMaxim Kochetkov if (err) 83284705fc1SMaxim Kochetkov return err; 83384705fc1SMaxim Kochetkov 83484705fc1SMaxim Kochetkov err = platform_driver_register(&seville_vsc9953_driver); 83584705fc1SMaxim Kochetkov if (err) 83684705fc1SMaxim Kochetkov return err; 83784705fc1SMaxim Kochetkov 83884705fc1SMaxim Kochetkov return 0; 839c0bcf537SYangbo Lu } 840375e1314SVladimir Oltean module_init(felix_init); 841c0bcf537SYangbo Lu 842375e1314SVladimir Oltean static void __exit felix_exit(void) 84356051948SVladimir Oltean { 844375e1314SVladimir Oltean pci_unregister_driver(&felix_vsc9959_pci_driver); 84584705fc1SMaxim Kochetkov platform_driver_unregister(&seville_vsc9953_driver); 846e90c9fceSMichael Walle } 847375e1314SVladimir Oltean module_exit(felix_exit); 84856051948SVladimir Oltean 84956051948SVladimir Oltean MODULE_DESCRIPTION("Felix Switch driver"); 85056051948SVladimir Oltean MODULE_LICENSE("GPL v2"); 851