156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 2adb3dccfSVladimir Oltean /* Copyright 2019-2021 NXP Semiconductors 3375e1314SVladimir Oltean * 4375e1314SVladimir Oltean * This is an umbrella module for all network switches that are 5375e1314SVladimir Oltean * register-compatible with Ocelot and that perform I/O to their host CPU 6375e1314SVladimir Oltean * through an NPI (Node Processor Interface) Ethernet port. 756051948SVladimir Oltean */ 856051948SVladimir Oltean #include <uapi/linux/if_bridge.h> 907d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h> 10bdeced75SVladimir Oltean #include <soc/mscc/ocelot_qsys.h> 11bdeced75SVladimir Oltean #include <soc/mscc/ocelot_sys.h> 12bdeced75SVladimir Oltean #include <soc/mscc/ocelot_dev.h> 13bdeced75SVladimir Oltean #include <soc/mscc/ocelot_ana.h> 142b49d128SYangbo Lu #include <soc/mscc/ocelot_ptp.h> 1556051948SVladimir Oltean #include <soc/mscc/ocelot.h> 16e21268efSVladimir Oltean #include <linux/dsa/8021q.h> 1740d3f295SVladimir Oltean #include <linux/dsa/ocelot.h> 1884705fc1SMaxim Kochetkov #include <linux/platform_device.h> 1956051948SVladimir Oltean #include <linux/module.h> 20bdeced75SVladimir Oltean #include <linux/of_net.h> 2156051948SVladimir Oltean #include <linux/pci.h> 2256051948SVladimir Oltean #include <linux/of.h> 23588d0550SIoana Ciornei #include <linux/pcs-lynx.h> 24fc411eaaSVladimir Oltean #include <net/pkt_sched.h> 2556051948SVladimir Oltean #include <net/dsa.h> 2656051948SVladimir Oltean #include "felix.h" 2756051948SVladimir Oltean 28e21268efSVladimir Oltean static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid, 29e21268efSVladimir Oltean bool pvid, bool untagged) 30e21268efSVladimir Oltean { 31e21268efSVladimir Oltean struct ocelot_vcap_filter *outer_tagging_rule; 32e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 33e21268efSVladimir Oltean struct dsa_switch *ds = felix->ds; 34e21268efSVladimir Oltean int key_length, upstream, err; 35e21268efSVladimir Oltean 36e21268efSVladimir Oltean /* We don't need to install the rxvlan into the other ports' filtering 37e21268efSVladimir Oltean * tables, because we're just pushing the rxvlan when sending towards 38e21268efSVladimir Oltean * the CPU 39e21268efSVladimir Oltean */ 40e21268efSVladimir Oltean if (!pvid) 41e21268efSVladimir Oltean return 0; 42e21268efSVladimir Oltean 43e21268efSVladimir Oltean key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length; 44e21268efSVladimir Oltean upstream = dsa_upstream_port(ds, port); 45e21268efSVladimir Oltean 46e21268efSVladimir Oltean outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), 47e21268efSVladimir Oltean GFP_KERNEL); 48e21268efSVladimir Oltean if (!outer_tagging_rule) 49e21268efSVladimir Oltean return -ENOMEM; 50e21268efSVladimir Oltean 51e21268efSVladimir Oltean outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 52e21268efSVladimir Oltean outer_tagging_rule->prio = 1; 53e21268efSVladimir Oltean outer_tagging_rule->id.cookie = port; 54e21268efSVladimir Oltean outer_tagging_rule->id.tc_offload = false; 55e21268efSVladimir Oltean outer_tagging_rule->block_id = VCAP_ES0; 56e21268efSVladimir Oltean outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 57e21268efSVladimir Oltean outer_tagging_rule->lookup = 0; 58e21268efSVladimir Oltean outer_tagging_rule->ingress_port.value = port; 59e21268efSVladimir Oltean outer_tagging_rule->ingress_port.mask = GENMASK(key_length - 1, 0); 60e21268efSVladimir Oltean outer_tagging_rule->egress_port.value = upstream; 61e21268efSVladimir Oltean outer_tagging_rule->egress_port.mask = GENMASK(key_length - 1, 0); 62e21268efSVladimir Oltean outer_tagging_rule->action.push_outer_tag = OCELOT_ES0_TAG; 63e21268efSVladimir Oltean outer_tagging_rule->action.tag_a_tpid_sel = OCELOT_TAG_TPID_SEL_8021AD; 64e21268efSVladimir Oltean outer_tagging_rule->action.tag_a_vid_sel = 1; 65e21268efSVladimir Oltean outer_tagging_rule->action.vid_a_val = vid; 66e21268efSVladimir Oltean 67e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, outer_tagging_rule, NULL); 68e21268efSVladimir Oltean if (err) 69e21268efSVladimir Oltean kfree(outer_tagging_rule); 70e21268efSVladimir Oltean 71e21268efSVladimir Oltean return err; 72e21268efSVladimir Oltean } 73e21268efSVladimir Oltean 74e21268efSVladimir Oltean static int felix_tag_8021q_txvlan_add(struct felix *felix, int port, u16 vid, 75e21268efSVladimir Oltean bool pvid, bool untagged) 76e21268efSVladimir Oltean { 77e21268efSVladimir Oltean struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 78e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 79e21268efSVladimir Oltean struct dsa_switch *ds = felix->ds; 80e21268efSVladimir Oltean int upstream, err; 81e21268efSVladimir Oltean 82e21268efSVladimir Oltean /* tag_8021q.c assumes we are implementing this via port VLAN 83e21268efSVladimir Oltean * membership, which we aren't. So we don't need to add any VCAP filter 84e21268efSVladimir Oltean * for the CPU port. 85e21268efSVladimir Oltean */ 86e21268efSVladimir Oltean if (ocelot->ports[port]->is_dsa_8021q_cpu) 87e21268efSVladimir Oltean return 0; 88e21268efSVladimir Oltean 89e21268efSVladimir Oltean untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 90e21268efSVladimir Oltean if (!untagging_rule) 91e21268efSVladimir Oltean return -ENOMEM; 92e21268efSVladimir Oltean 93e21268efSVladimir Oltean redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 94e21268efSVladimir Oltean if (!redirect_rule) { 95e21268efSVladimir Oltean kfree(untagging_rule); 96e21268efSVladimir Oltean return -ENOMEM; 97e21268efSVladimir Oltean } 98e21268efSVladimir Oltean 99e21268efSVladimir Oltean upstream = dsa_upstream_port(ds, port); 100e21268efSVladimir Oltean 101e21268efSVladimir Oltean untagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 102e21268efSVladimir Oltean untagging_rule->ingress_port_mask = BIT(upstream); 103e21268efSVladimir Oltean untagging_rule->vlan.vid.value = vid; 104e21268efSVladimir Oltean untagging_rule->vlan.vid.mask = VLAN_VID_MASK; 105e21268efSVladimir Oltean untagging_rule->prio = 1; 106e21268efSVladimir Oltean untagging_rule->id.cookie = port; 107e21268efSVladimir Oltean untagging_rule->id.tc_offload = false; 108e21268efSVladimir Oltean untagging_rule->block_id = VCAP_IS1; 109e21268efSVladimir Oltean untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 110e21268efSVladimir Oltean untagging_rule->lookup = 0; 111e21268efSVladimir Oltean untagging_rule->action.vlan_pop_cnt_ena = true; 112e21268efSVladimir Oltean untagging_rule->action.vlan_pop_cnt = 1; 113e21268efSVladimir Oltean untagging_rule->action.pag_override_mask = 0xff; 114e21268efSVladimir Oltean untagging_rule->action.pag_val = port; 115e21268efSVladimir Oltean 116e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, untagging_rule, NULL); 117e21268efSVladimir Oltean if (err) { 118e21268efSVladimir Oltean kfree(untagging_rule); 119e21268efSVladimir Oltean kfree(redirect_rule); 120e21268efSVladimir Oltean return err; 121e21268efSVladimir Oltean } 122e21268efSVladimir Oltean 123e21268efSVladimir Oltean redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; 124e21268efSVladimir Oltean redirect_rule->ingress_port_mask = BIT(upstream); 125e21268efSVladimir Oltean redirect_rule->pag = port; 126e21268efSVladimir Oltean redirect_rule->prio = 1; 127e21268efSVladimir Oltean redirect_rule->id.cookie = port; 128e21268efSVladimir Oltean redirect_rule->id.tc_offload = false; 129e21268efSVladimir Oltean redirect_rule->block_id = VCAP_IS2; 130e21268efSVladimir Oltean redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 131e21268efSVladimir Oltean redirect_rule->lookup = 0; 132e21268efSVladimir Oltean redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 133e21268efSVladimir Oltean redirect_rule->action.port_mask = BIT(port); 134e21268efSVladimir Oltean 135e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); 136e21268efSVladimir Oltean if (err) { 137e21268efSVladimir Oltean ocelot_vcap_filter_del(ocelot, untagging_rule); 138e21268efSVladimir Oltean kfree(redirect_rule); 139e21268efSVladimir Oltean return err; 140e21268efSVladimir Oltean } 141e21268efSVladimir Oltean 142e21268efSVladimir Oltean return 0; 143e21268efSVladimir Oltean } 144e21268efSVladimir Oltean 145e21268efSVladimir Oltean static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, 146e21268efSVladimir Oltean u16 flags) 147e21268efSVladimir Oltean { 148e21268efSVladimir Oltean bool untagged = flags & BRIDGE_VLAN_INFO_UNTAGGED; 149e21268efSVladimir Oltean bool pvid = flags & BRIDGE_VLAN_INFO_PVID; 150e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 151e21268efSVladimir Oltean 152e21268efSVladimir Oltean if (vid_is_dsa_8021q_rxvlan(vid)) 153e21268efSVladimir Oltean return felix_tag_8021q_rxvlan_add(ocelot_to_felix(ocelot), 154e21268efSVladimir Oltean port, vid, pvid, untagged); 155e21268efSVladimir Oltean 156e21268efSVladimir Oltean if (vid_is_dsa_8021q_txvlan(vid)) 157e21268efSVladimir Oltean return felix_tag_8021q_txvlan_add(ocelot_to_felix(ocelot), 158e21268efSVladimir Oltean port, vid, pvid, untagged); 159e21268efSVladimir Oltean 160e21268efSVladimir Oltean return 0; 161e21268efSVladimir Oltean } 162e21268efSVladimir Oltean 163e21268efSVladimir Oltean static int felix_tag_8021q_rxvlan_del(struct felix *felix, int port, u16 vid) 164e21268efSVladimir Oltean { 165e21268efSVladimir Oltean struct ocelot_vcap_filter *outer_tagging_rule; 166e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_es0; 167e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 168e21268efSVladimir Oltean 169e21268efSVladimir Oltean block_vcap_es0 = &ocelot->block[VCAP_ES0]; 170e21268efSVladimir Oltean 171e21268efSVladimir Oltean outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0, 172e21268efSVladimir Oltean port, false); 173e21268efSVladimir Oltean /* In rxvlan_add, we had the "if (!pvid) return 0" logic to avoid 174e21268efSVladimir Oltean * installing outer tagging ES0 rules where they weren't needed. 175e21268efSVladimir Oltean * But in rxvlan_del, the API doesn't give us the "flags" anymore, 176e21268efSVladimir Oltean * so that forces us to be slightly sloppy here, and just assume that 177e21268efSVladimir Oltean * if we didn't find an outer_tagging_rule it means that there was 178e21268efSVladimir Oltean * none in the first place, i.e. rxvlan_del is called on a non-pvid 179e21268efSVladimir Oltean * port. This is most probably true though. 180e21268efSVladimir Oltean */ 181e21268efSVladimir Oltean if (!outer_tagging_rule) 182e21268efSVladimir Oltean return 0; 183e21268efSVladimir Oltean 184e21268efSVladimir Oltean return ocelot_vcap_filter_del(ocelot, outer_tagging_rule); 185e21268efSVladimir Oltean } 186e21268efSVladimir Oltean 187e21268efSVladimir Oltean static int felix_tag_8021q_txvlan_del(struct felix *felix, int port, u16 vid) 188e21268efSVladimir Oltean { 189e21268efSVladimir Oltean struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 190e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_is1; 191e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_is2; 192e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 193e21268efSVladimir Oltean int err; 194e21268efSVladimir Oltean 195e21268efSVladimir Oltean if (ocelot->ports[port]->is_dsa_8021q_cpu) 196e21268efSVladimir Oltean return 0; 197e21268efSVladimir Oltean 198e21268efSVladimir Oltean block_vcap_is1 = &ocelot->block[VCAP_IS1]; 199e21268efSVladimir Oltean block_vcap_is2 = &ocelot->block[VCAP_IS2]; 200e21268efSVladimir Oltean 201e21268efSVladimir Oltean untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, 202e21268efSVladimir Oltean port, false); 203e21268efSVladimir Oltean if (!untagging_rule) 204e21268efSVladimir Oltean return 0; 205e21268efSVladimir Oltean 206e21268efSVladimir Oltean err = ocelot_vcap_filter_del(ocelot, untagging_rule); 207e21268efSVladimir Oltean if (err) 208e21268efSVladimir Oltean return err; 209e21268efSVladimir Oltean 210e21268efSVladimir Oltean redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, 211e21268efSVladimir Oltean port, false); 212e21268efSVladimir Oltean if (!redirect_rule) 213e21268efSVladimir Oltean return 0; 214e21268efSVladimir Oltean 215e21268efSVladimir Oltean return ocelot_vcap_filter_del(ocelot, redirect_rule); 216e21268efSVladimir Oltean } 217e21268efSVladimir Oltean 218e21268efSVladimir Oltean static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) 219e21268efSVladimir Oltean { 220e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 221e21268efSVladimir Oltean 222e21268efSVladimir Oltean if (vid_is_dsa_8021q_rxvlan(vid)) 223e21268efSVladimir Oltean return felix_tag_8021q_rxvlan_del(ocelot_to_felix(ocelot), 224e21268efSVladimir Oltean port, vid); 225e21268efSVladimir Oltean 226e21268efSVladimir Oltean if (vid_is_dsa_8021q_txvlan(vid)) 227e21268efSVladimir Oltean return felix_tag_8021q_txvlan_del(ocelot_to_felix(ocelot), 228e21268efSVladimir Oltean port, vid); 229e21268efSVladimir Oltean 230e21268efSVladimir Oltean return 0; 231e21268efSVladimir Oltean } 232e21268efSVladimir Oltean 233e21268efSVladimir Oltean static const struct dsa_8021q_ops felix_tag_8021q_ops = { 234e21268efSVladimir Oltean .vlan_add = felix_tag_8021q_vlan_add, 235e21268efSVladimir Oltean .vlan_del = felix_tag_8021q_vlan_del, 236e21268efSVladimir Oltean }; 237e21268efSVladimir Oltean 238e21268efSVladimir Oltean /* Alternatively to using the NPI functionality, that same hardware MAC 239e21268efSVladimir Oltean * connected internally to the enetc or fman DSA master can be configured to 240e21268efSVladimir Oltean * use the software-defined tag_8021q frame format. As far as the hardware is 241e21268efSVladimir Oltean * concerned, it thinks it is a "dumb switch" - the queues of the CPU port 242e21268efSVladimir Oltean * module are now disconnected from it, but can still be accessed through 243e21268efSVladimir Oltean * register-based MMIO. 244e21268efSVladimir Oltean */ 245e21268efSVladimir Oltean static void felix_8021q_cpu_port_init(struct ocelot *ocelot, int port) 246e21268efSVladimir Oltean { 247e21268efSVladimir Oltean ocelot->ports[port]->is_dsa_8021q_cpu = true; 248e21268efSVladimir Oltean ocelot->npi = -1; 249e21268efSVladimir Oltean 250e21268efSVladimir Oltean /* Overwrite PGID_CPU with the non-tagging port */ 251e21268efSVladimir Oltean ocelot_write_rix(ocelot, BIT(port), ANA_PGID_PGID, PGID_CPU); 252e21268efSVladimir Oltean 253e21268efSVladimir Oltean ocelot_apply_bridge_fwd_mask(ocelot); 254e21268efSVladimir Oltean } 255e21268efSVladimir Oltean 256e21268efSVladimir Oltean static void felix_8021q_cpu_port_deinit(struct ocelot *ocelot, int port) 257e21268efSVladimir Oltean { 258e21268efSVladimir Oltean ocelot->ports[port]->is_dsa_8021q_cpu = false; 259e21268efSVladimir Oltean 260e21268efSVladimir Oltean /* Restore PGID_CPU */ 261e21268efSVladimir Oltean ocelot_write_rix(ocelot, BIT(ocelot->num_phys_ports), ANA_PGID_PGID, 262e21268efSVladimir Oltean PGID_CPU); 263e21268efSVladimir Oltean 264e21268efSVladimir Oltean ocelot_apply_bridge_fwd_mask(ocelot); 265e21268efSVladimir Oltean } 266e21268efSVladimir Oltean 267*c8c0ba4fSVladimir Oltean /* Set up a VCAP IS2 rule for delivering PTP frames to the CPU port module. 268*c8c0ba4fSVladimir Oltean * If the quirk_no_xtr_irq is in place, then also copy those PTP frames to the 269*c8c0ba4fSVladimir Oltean * tag_8021q CPU port. 270*c8c0ba4fSVladimir Oltean */ 271*c8c0ba4fSVladimir Oltean static int felix_setup_mmio_filtering(struct felix *felix) 272*c8c0ba4fSVladimir Oltean { 273*c8c0ba4fSVladimir Oltean unsigned long user_ports = 0, cpu_ports = 0; 274*c8c0ba4fSVladimir Oltean struct ocelot_vcap_filter *redirect_rule; 275*c8c0ba4fSVladimir Oltean struct ocelot_vcap_filter *tagging_rule; 276*c8c0ba4fSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 277*c8c0ba4fSVladimir Oltean struct dsa_switch *ds = felix->ds; 278*c8c0ba4fSVladimir Oltean int port, ret; 279*c8c0ba4fSVladimir Oltean 280*c8c0ba4fSVladimir Oltean tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 281*c8c0ba4fSVladimir Oltean if (!tagging_rule) 282*c8c0ba4fSVladimir Oltean return -ENOMEM; 283*c8c0ba4fSVladimir Oltean 284*c8c0ba4fSVladimir Oltean redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 285*c8c0ba4fSVladimir Oltean if (!redirect_rule) { 286*c8c0ba4fSVladimir Oltean kfree(tagging_rule); 287*c8c0ba4fSVladimir Oltean return -ENOMEM; 288*c8c0ba4fSVladimir Oltean } 289*c8c0ba4fSVladimir Oltean 290*c8c0ba4fSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) { 291*c8c0ba4fSVladimir Oltean if (dsa_is_user_port(ds, port)) 292*c8c0ba4fSVladimir Oltean user_ports |= BIT(port); 293*c8c0ba4fSVladimir Oltean if (dsa_is_cpu_port(ds, port)) 294*c8c0ba4fSVladimir Oltean cpu_ports |= BIT(port); 295*c8c0ba4fSVladimir Oltean } 296*c8c0ba4fSVladimir Oltean 297*c8c0ba4fSVladimir Oltean tagging_rule->key_type = OCELOT_VCAP_KEY_ETYPE; 298*c8c0ba4fSVladimir Oltean *(__be16 *)tagging_rule->key.etype.etype.value = htons(ETH_P_1588); 299*c8c0ba4fSVladimir Oltean *(__be16 *)tagging_rule->key.etype.etype.mask = htons(0xffff); 300*c8c0ba4fSVladimir Oltean tagging_rule->ingress_port_mask = user_ports; 301*c8c0ba4fSVladimir Oltean tagging_rule->prio = 1; 302*c8c0ba4fSVladimir Oltean tagging_rule->id.cookie = ocelot->num_phys_ports; 303*c8c0ba4fSVladimir Oltean tagging_rule->id.tc_offload = false; 304*c8c0ba4fSVladimir Oltean tagging_rule->block_id = VCAP_IS1; 305*c8c0ba4fSVladimir Oltean tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 306*c8c0ba4fSVladimir Oltean tagging_rule->lookup = 0; 307*c8c0ba4fSVladimir Oltean tagging_rule->action.pag_override_mask = 0xff; 308*c8c0ba4fSVladimir Oltean tagging_rule->action.pag_val = ocelot->num_phys_ports; 309*c8c0ba4fSVladimir Oltean 310*c8c0ba4fSVladimir Oltean ret = ocelot_vcap_filter_add(ocelot, tagging_rule, NULL); 311*c8c0ba4fSVladimir Oltean if (ret) { 312*c8c0ba4fSVladimir Oltean kfree(tagging_rule); 313*c8c0ba4fSVladimir Oltean kfree(redirect_rule); 314*c8c0ba4fSVladimir Oltean return ret; 315*c8c0ba4fSVladimir Oltean } 316*c8c0ba4fSVladimir Oltean 317*c8c0ba4fSVladimir Oltean redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; 318*c8c0ba4fSVladimir Oltean redirect_rule->ingress_port_mask = user_ports; 319*c8c0ba4fSVladimir Oltean redirect_rule->pag = ocelot->num_phys_ports; 320*c8c0ba4fSVladimir Oltean redirect_rule->prio = 1; 321*c8c0ba4fSVladimir Oltean redirect_rule->id.cookie = ocelot->num_phys_ports; 322*c8c0ba4fSVladimir Oltean redirect_rule->id.tc_offload = false; 323*c8c0ba4fSVladimir Oltean redirect_rule->block_id = VCAP_IS2; 324*c8c0ba4fSVladimir Oltean redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 325*c8c0ba4fSVladimir Oltean redirect_rule->lookup = 0; 326*c8c0ba4fSVladimir Oltean redirect_rule->action.cpu_copy_ena = true; 327*c8c0ba4fSVladimir Oltean if (felix->info->quirk_no_xtr_irq) { 328*c8c0ba4fSVladimir Oltean /* Redirect to the tag_8021q CPU but also copy PTP packets to 329*c8c0ba4fSVladimir Oltean * the CPU port module 330*c8c0ba4fSVladimir Oltean */ 331*c8c0ba4fSVladimir Oltean redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 332*c8c0ba4fSVladimir Oltean redirect_rule->action.port_mask = cpu_ports; 333*c8c0ba4fSVladimir Oltean } else { 334*c8c0ba4fSVladimir Oltean /* Trap PTP packets only to the CPU port module (which is 335*c8c0ba4fSVladimir Oltean * redirected to the NPI port) 336*c8c0ba4fSVladimir Oltean */ 337*c8c0ba4fSVladimir Oltean redirect_rule->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 338*c8c0ba4fSVladimir Oltean redirect_rule->action.port_mask = 0; 339*c8c0ba4fSVladimir Oltean } 340*c8c0ba4fSVladimir Oltean 341*c8c0ba4fSVladimir Oltean ret = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); 342*c8c0ba4fSVladimir Oltean if (ret) { 343*c8c0ba4fSVladimir Oltean ocelot_vcap_filter_del(ocelot, tagging_rule); 344*c8c0ba4fSVladimir Oltean kfree(redirect_rule); 345*c8c0ba4fSVladimir Oltean return ret; 346*c8c0ba4fSVladimir Oltean } 347*c8c0ba4fSVladimir Oltean 348*c8c0ba4fSVladimir Oltean return 0; 349*c8c0ba4fSVladimir Oltean } 350*c8c0ba4fSVladimir Oltean 351*c8c0ba4fSVladimir Oltean static int felix_teardown_mmio_filtering(struct felix *felix) 352*c8c0ba4fSVladimir Oltean { 353*c8c0ba4fSVladimir Oltean struct ocelot_vcap_filter *tagging_rule, *redirect_rule; 354*c8c0ba4fSVladimir Oltean struct ocelot_vcap_block *block_vcap_is1; 355*c8c0ba4fSVladimir Oltean struct ocelot_vcap_block *block_vcap_is2; 356*c8c0ba4fSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 357*c8c0ba4fSVladimir Oltean int err; 358*c8c0ba4fSVladimir Oltean 359*c8c0ba4fSVladimir Oltean block_vcap_is1 = &ocelot->block[VCAP_IS1]; 360*c8c0ba4fSVladimir Oltean block_vcap_is2 = &ocelot->block[VCAP_IS2]; 361*c8c0ba4fSVladimir Oltean 362*c8c0ba4fSVladimir Oltean tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, 363*c8c0ba4fSVladimir Oltean ocelot->num_phys_ports, 364*c8c0ba4fSVladimir Oltean false); 365*c8c0ba4fSVladimir Oltean if (!tagging_rule) 366*c8c0ba4fSVladimir Oltean return -ENOENT; 367*c8c0ba4fSVladimir Oltean 368*c8c0ba4fSVladimir Oltean err = ocelot_vcap_filter_del(ocelot, tagging_rule); 369*c8c0ba4fSVladimir Oltean if (err) 370*c8c0ba4fSVladimir Oltean return err; 371*c8c0ba4fSVladimir Oltean 372*c8c0ba4fSVladimir Oltean redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, 373*c8c0ba4fSVladimir Oltean ocelot->num_phys_ports, 374*c8c0ba4fSVladimir Oltean false); 375*c8c0ba4fSVladimir Oltean if (!redirect_rule) 376*c8c0ba4fSVladimir Oltean return -ENOENT; 377*c8c0ba4fSVladimir Oltean 378*c8c0ba4fSVladimir Oltean return ocelot_vcap_filter_del(ocelot, redirect_rule); 379*c8c0ba4fSVladimir Oltean } 380*c8c0ba4fSVladimir Oltean 381e21268efSVladimir Oltean static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) 382e21268efSVladimir Oltean { 383e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 384e21268efSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 385e21268efSVladimir Oltean unsigned long cpu_flood; 386e21268efSVladimir Oltean int port, err; 387e21268efSVladimir Oltean 388e21268efSVladimir Oltean felix_8021q_cpu_port_init(ocelot, cpu); 389e21268efSVladimir Oltean 390e21268efSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 391e21268efSVladimir Oltean if (dsa_is_unused_port(ds, port)) 392e21268efSVladimir Oltean continue; 393e21268efSVladimir Oltean 394e21268efSVladimir Oltean /* This overwrites ocelot_init(): 395e21268efSVladimir Oltean * Do not forward BPDU frames to the CPU port module, 396e21268efSVladimir Oltean * for 2 reasons: 397e21268efSVladimir Oltean * - When these packets are injected from the tag_8021q 398e21268efSVladimir Oltean * CPU port, we want them to go out, not loop back 399e21268efSVladimir Oltean * into the system. 400e21268efSVladimir Oltean * - STP traffic ingressing on a user port should go to 401e21268efSVladimir Oltean * the tag_8021q CPU port, not to the hardware CPU 402e21268efSVladimir Oltean * port module. 403e21268efSVladimir Oltean */ 404e21268efSVladimir Oltean ocelot_write_gix(ocelot, 405e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0), 406e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG, port); 407e21268efSVladimir Oltean } 408e21268efSVladimir Oltean 409*c8c0ba4fSVladimir Oltean /* In tag_8021q mode, the CPU port module is unused, except for PTP 410*c8c0ba4fSVladimir Oltean * frames. So we want to disable flooding of any kind to the CPU port 411*c8c0ba4fSVladimir Oltean * module, since packets going there will end in a black hole. 412e21268efSVladimir Oltean */ 413e21268efSVladimir Oltean cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 414e21268efSVladimir Oltean ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_UC); 415e21268efSVladimir Oltean ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_MC); 416b360d94fSVladimir Oltean ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_BC); 417e21268efSVladimir Oltean 418e21268efSVladimir Oltean felix->dsa_8021q_ctx = kzalloc(sizeof(*felix->dsa_8021q_ctx), 419e21268efSVladimir Oltean GFP_KERNEL); 420e21268efSVladimir Oltean if (!felix->dsa_8021q_ctx) 421e21268efSVladimir Oltean return -ENOMEM; 422e21268efSVladimir Oltean 423e21268efSVladimir Oltean felix->dsa_8021q_ctx->ops = &felix_tag_8021q_ops; 424e21268efSVladimir Oltean felix->dsa_8021q_ctx->proto = htons(ETH_P_8021AD); 425e21268efSVladimir Oltean felix->dsa_8021q_ctx->ds = ds; 426e21268efSVladimir Oltean 427e21268efSVladimir Oltean err = dsa_8021q_setup(felix->dsa_8021q_ctx, true); 428e21268efSVladimir Oltean if (err) 429e21268efSVladimir Oltean goto out_free_dsa_8021_ctx; 430e21268efSVladimir Oltean 431*c8c0ba4fSVladimir Oltean err = felix_setup_mmio_filtering(felix); 432*c8c0ba4fSVladimir Oltean if (err) 433*c8c0ba4fSVladimir Oltean goto out_teardown_dsa_8021q; 434*c8c0ba4fSVladimir Oltean 435e21268efSVladimir Oltean return 0; 436e21268efSVladimir Oltean 437*c8c0ba4fSVladimir Oltean out_teardown_dsa_8021q: 438*c8c0ba4fSVladimir Oltean dsa_8021q_setup(felix->dsa_8021q_ctx, false); 439e21268efSVladimir Oltean out_free_dsa_8021_ctx: 440e21268efSVladimir Oltean kfree(felix->dsa_8021q_ctx); 441e21268efSVladimir Oltean return err; 442e21268efSVladimir Oltean } 443e21268efSVladimir Oltean 444e21268efSVladimir Oltean static void felix_teardown_tag_8021q(struct dsa_switch *ds, int cpu) 445e21268efSVladimir Oltean { 446e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 447e21268efSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 448e21268efSVladimir Oltean int err, port; 449e21268efSVladimir Oltean 450*c8c0ba4fSVladimir Oltean err = felix_teardown_mmio_filtering(felix); 451*c8c0ba4fSVladimir Oltean if (err) 452*c8c0ba4fSVladimir Oltean dev_err(ds->dev, "felix_teardown_mmio_filtering returned %d", 453*c8c0ba4fSVladimir Oltean err); 454*c8c0ba4fSVladimir Oltean 455e21268efSVladimir Oltean err = dsa_8021q_setup(felix->dsa_8021q_ctx, false); 456e21268efSVladimir Oltean if (err) 457e21268efSVladimir Oltean dev_err(ds->dev, "dsa_8021q_setup returned %d", err); 458e21268efSVladimir Oltean 459e21268efSVladimir Oltean kfree(felix->dsa_8021q_ctx); 460e21268efSVladimir Oltean 461e21268efSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 462e21268efSVladimir Oltean if (dsa_is_unused_port(ds, port)) 463e21268efSVladimir Oltean continue; 464e21268efSVladimir Oltean 465e21268efSVladimir Oltean /* Restore the logic from ocelot_init: 466e21268efSVladimir Oltean * do not forward BPDU frames to the front ports. 467e21268efSVladimir Oltean */ 468e21268efSVladimir Oltean ocelot_write_gix(ocelot, 469e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), 470e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG, 471e21268efSVladimir Oltean port); 472e21268efSVladimir Oltean } 473e21268efSVladimir Oltean 474e21268efSVladimir Oltean felix_8021q_cpu_port_deinit(ocelot, cpu); 475e21268efSVladimir Oltean } 476e21268efSVladimir Oltean 477adb3dccfSVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This 478adb3dccfSVladimir Oltean * is the mode through which frames can be injected from and extracted to an 479adb3dccfSVladimir Oltean * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU 480adb3dccfSVladimir Oltean * running Linux, and this forms a DSA setup together with the enetc or fman 481adb3dccfSVladimir Oltean * DSA master. 482adb3dccfSVladimir Oltean */ 483adb3dccfSVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port) 484adb3dccfSVladimir Oltean { 485adb3dccfSVladimir Oltean ocelot->npi = port; 486adb3dccfSVladimir Oltean 487adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | 488adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), 489adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 490adb3dccfSVladimir Oltean 491adb3dccfSVladimir Oltean /* NPI port Injection/Extraction configuration */ 492adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 493adb3dccfSVladimir Oltean ocelot->npi_xtr_prefix); 494adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 495adb3dccfSVladimir Oltean ocelot->npi_inj_prefix); 496adb3dccfSVladimir Oltean 497adb3dccfSVladimir Oltean /* Disable transmission of pause frames */ 498adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); 499adb3dccfSVladimir Oltean } 500adb3dccfSVladimir Oltean 501adb3dccfSVladimir Oltean static void felix_npi_port_deinit(struct ocelot *ocelot, int port) 502adb3dccfSVladimir Oltean { 503adb3dccfSVladimir Oltean /* Restore hardware defaults */ 504adb3dccfSVladimir Oltean int unused_port = ocelot->num_phys_ports + 2; 505adb3dccfSVladimir Oltean 506adb3dccfSVladimir Oltean ocelot->npi = -1; 507adb3dccfSVladimir Oltean 508adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port), 509adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 510adb3dccfSVladimir Oltean 511adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 512adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 513adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 514adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 515adb3dccfSVladimir Oltean 516adb3dccfSVladimir Oltean /* Enable transmission of pause frames */ 517adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1); 518adb3dccfSVladimir Oltean } 519adb3dccfSVladimir Oltean 520adb3dccfSVladimir Oltean static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu) 521adb3dccfSVladimir Oltean { 522adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 523adb3dccfSVladimir Oltean unsigned long cpu_flood; 524adb3dccfSVladimir Oltean 525adb3dccfSVladimir Oltean felix_npi_port_init(ocelot, cpu); 526adb3dccfSVladimir Oltean 527adb3dccfSVladimir Oltean /* Include the CPU port module (and indirectly, the NPI port) 528adb3dccfSVladimir Oltean * in the forwarding mask for unknown unicast - the hardware 529adb3dccfSVladimir Oltean * default value for ANA_FLOODING_FLD_UNICAST excludes 530adb3dccfSVladimir Oltean * BIT(ocelot->num_phys_ports), and so does ocelot_init, 531adb3dccfSVladimir Oltean * since Ocelot relies on whitelisting MAC addresses towards 532adb3dccfSVladimir Oltean * PGID_CPU. 533adb3dccfSVladimir Oltean * We do this because DSA does not yet perform RX filtering, 534adb3dccfSVladimir Oltean * and the NPI port does not perform source address learning, 535adb3dccfSVladimir Oltean * so traffic sent to Linux is effectively unknown from the 536adb3dccfSVladimir Oltean * switch's perspective. 537adb3dccfSVladimir Oltean */ 538adb3dccfSVladimir Oltean cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 539adb3dccfSVladimir Oltean ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC); 5406edb9e8dSVladimir Oltean ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_MC); 541b360d94fSVladimir Oltean ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_BC); 542adb3dccfSVladimir Oltean 543adb3dccfSVladimir Oltean return 0; 544adb3dccfSVladimir Oltean } 545adb3dccfSVladimir Oltean 546adb3dccfSVladimir Oltean static void felix_teardown_tag_npi(struct dsa_switch *ds, int cpu) 547adb3dccfSVladimir Oltean { 548adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 549adb3dccfSVladimir Oltean 550adb3dccfSVladimir Oltean felix_npi_port_deinit(ocelot, cpu); 551adb3dccfSVladimir Oltean } 552adb3dccfSVladimir Oltean 553adb3dccfSVladimir Oltean static int felix_set_tag_protocol(struct dsa_switch *ds, int cpu, 554adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 555adb3dccfSVladimir Oltean { 556adb3dccfSVladimir Oltean int err; 557adb3dccfSVladimir Oltean 558adb3dccfSVladimir Oltean switch (proto) { 5597c4bb540SVladimir Oltean case DSA_TAG_PROTO_SEVILLE: 560adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 561adb3dccfSVladimir Oltean err = felix_setup_tag_npi(ds, cpu); 562adb3dccfSVladimir Oltean break; 563e21268efSVladimir Oltean case DSA_TAG_PROTO_OCELOT_8021Q: 564e21268efSVladimir Oltean err = felix_setup_tag_8021q(ds, cpu); 565e21268efSVladimir Oltean break; 566adb3dccfSVladimir Oltean default: 567adb3dccfSVladimir Oltean err = -EPROTONOSUPPORT; 568adb3dccfSVladimir Oltean } 569adb3dccfSVladimir Oltean 570adb3dccfSVladimir Oltean return err; 571adb3dccfSVladimir Oltean } 572adb3dccfSVladimir Oltean 573adb3dccfSVladimir Oltean static void felix_del_tag_protocol(struct dsa_switch *ds, int cpu, 574adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 575adb3dccfSVladimir Oltean { 576adb3dccfSVladimir Oltean switch (proto) { 5777c4bb540SVladimir Oltean case DSA_TAG_PROTO_SEVILLE: 578adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 579adb3dccfSVladimir Oltean felix_teardown_tag_npi(ds, cpu); 580adb3dccfSVladimir Oltean break; 581e21268efSVladimir Oltean case DSA_TAG_PROTO_OCELOT_8021Q: 582e21268efSVladimir Oltean felix_teardown_tag_8021q(ds, cpu); 583e21268efSVladimir Oltean break; 584adb3dccfSVladimir Oltean default: 585adb3dccfSVladimir Oltean break; 586adb3dccfSVladimir Oltean } 587adb3dccfSVladimir Oltean } 588adb3dccfSVladimir Oltean 589e21268efSVladimir Oltean /* This always leaves the switch in a consistent state, because although the 590e21268efSVladimir Oltean * tag_8021q setup can fail, the NPI setup can't. So either the change is made, 591e21268efSVladimir Oltean * or the restoration is guaranteed to work. 592e21268efSVladimir Oltean */ 593adb3dccfSVladimir Oltean static int felix_change_tag_protocol(struct dsa_switch *ds, int cpu, 594adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 595adb3dccfSVladimir Oltean { 596adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 597adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 598adb3dccfSVladimir Oltean enum dsa_tag_protocol old_proto = felix->tag_proto; 599adb3dccfSVladimir Oltean int err; 600adb3dccfSVladimir Oltean 6017c4bb540SVladimir Oltean if (proto != DSA_TAG_PROTO_SEVILLE && 6027c4bb540SVladimir Oltean proto != DSA_TAG_PROTO_OCELOT && 603e21268efSVladimir Oltean proto != DSA_TAG_PROTO_OCELOT_8021Q) 604adb3dccfSVladimir Oltean return -EPROTONOSUPPORT; 605adb3dccfSVladimir Oltean 606adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, cpu, old_proto); 607adb3dccfSVladimir Oltean 608adb3dccfSVladimir Oltean err = felix_set_tag_protocol(ds, cpu, proto); 609adb3dccfSVladimir Oltean if (err) { 610adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, cpu, old_proto); 611adb3dccfSVladimir Oltean return err; 612adb3dccfSVladimir Oltean } 613adb3dccfSVladimir Oltean 614adb3dccfSVladimir Oltean felix->tag_proto = proto; 615adb3dccfSVladimir Oltean 616adb3dccfSVladimir Oltean return 0; 617adb3dccfSVladimir Oltean } 618adb3dccfSVladimir Oltean 61956051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 6204d776482SFlorian Fainelli int port, 6214d776482SFlorian Fainelli enum dsa_tag_protocol mp) 62256051948SVladimir Oltean { 623adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 624adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 625adb3dccfSVladimir Oltean 626adb3dccfSVladimir Oltean return felix->tag_proto; 62756051948SVladimir Oltean } 62856051948SVladimir Oltean 62956051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 63056051948SVladimir Oltean unsigned int ageing_time) 63156051948SVladimir Oltean { 63256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 63356051948SVladimir Oltean 63456051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 63556051948SVladimir Oltean 63656051948SVladimir Oltean return 0; 63756051948SVladimir Oltean } 63856051948SVladimir Oltean 63956051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 64056051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 64156051948SVladimir Oltean { 64256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 64356051948SVladimir Oltean 64456051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 64556051948SVladimir Oltean } 64656051948SVladimir Oltean 64756051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 64856051948SVladimir Oltean const unsigned char *addr, u16 vid) 64956051948SVladimir Oltean { 65056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 65156051948SVladimir Oltean 65287b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 65356051948SVladimir Oltean } 65456051948SVladimir Oltean 65556051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 65656051948SVladimir Oltean const unsigned char *addr, u16 vid) 65756051948SVladimir Oltean { 65856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 65956051948SVladimir Oltean 66056051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 66156051948SVladimir Oltean } 66256051948SVladimir Oltean 663a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port, 664209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 665209edf95SVladimir Oltean { 666209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 667209edf95SVladimir Oltean 668a52b2da7SVladimir Oltean return ocelot_port_mdb_add(ocelot, port, mdb); 669209edf95SVladimir Oltean } 670209edf95SVladimir Oltean 671209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 672209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 673209edf95SVladimir Oltean { 674209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 675209edf95SVladimir Oltean 676209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 677209edf95SVladimir Oltean } 678209edf95SVladimir Oltean 67956051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 68056051948SVladimir Oltean u8 state) 68156051948SVladimir Oltean { 68256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 68356051948SVladimir Oltean 68456051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 68556051948SVladimir Oltean } 68656051948SVladimir Oltean 687421741eaSVladimir Oltean static int felix_pre_bridge_flags(struct dsa_switch *ds, int port, 688421741eaSVladimir Oltean struct switchdev_brport_flags val, 689421741eaSVladimir Oltean struct netlink_ext_ack *extack) 690421741eaSVladimir Oltean { 691421741eaSVladimir Oltean struct ocelot *ocelot = ds->priv; 692421741eaSVladimir Oltean 693421741eaSVladimir Oltean return ocelot_port_pre_bridge_flags(ocelot, port, val); 694421741eaSVladimir Oltean } 695421741eaSVladimir Oltean 696421741eaSVladimir Oltean static int felix_bridge_flags(struct dsa_switch *ds, int port, 697421741eaSVladimir Oltean struct switchdev_brport_flags val, 698421741eaSVladimir Oltean struct netlink_ext_ack *extack) 699421741eaSVladimir Oltean { 700421741eaSVladimir Oltean struct ocelot *ocelot = ds->priv; 701421741eaSVladimir Oltean 702421741eaSVladimir Oltean ocelot_port_bridge_flags(ocelot, port, val); 703421741eaSVladimir Oltean 704421741eaSVladimir Oltean return 0; 705421741eaSVladimir Oltean } 706421741eaSVladimir Oltean 70756051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 70856051948SVladimir Oltean struct net_device *br) 70956051948SVladimir Oltean { 71056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 71156051948SVladimir Oltean 71256051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 71356051948SVladimir Oltean } 71456051948SVladimir Oltean 71556051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 71656051948SVladimir Oltean struct net_device *br) 71756051948SVladimir Oltean { 71856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 71956051948SVladimir Oltean 72056051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 72156051948SVladimir Oltean } 72256051948SVladimir Oltean 7238fe6832eSVladimir Oltean static int felix_lag_join(struct dsa_switch *ds, int port, 7248fe6832eSVladimir Oltean struct net_device *bond, 7258fe6832eSVladimir Oltean struct netdev_lag_upper_info *info) 7268fe6832eSVladimir Oltean { 7278fe6832eSVladimir Oltean struct ocelot *ocelot = ds->priv; 7288fe6832eSVladimir Oltean 7298fe6832eSVladimir Oltean return ocelot_port_lag_join(ocelot, port, bond, info); 7308fe6832eSVladimir Oltean } 7318fe6832eSVladimir Oltean 7328fe6832eSVladimir Oltean static int felix_lag_leave(struct dsa_switch *ds, int port, 7338fe6832eSVladimir Oltean struct net_device *bond) 7348fe6832eSVladimir Oltean { 7358fe6832eSVladimir Oltean struct ocelot *ocelot = ds->priv; 7368fe6832eSVladimir Oltean 7378fe6832eSVladimir Oltean ocelot_port_lag_leave(ocelot, port, bond); 7388fe6832eSVladimir Oltean 7398fe6832eSVladimir Oltean return 0; 7408fe6832eSVladimir Oltean } 7418fe6832eSVladimir Oltean 7428fe6832eSVladimir Oltean static int felix_lag_change(struct dsa_switch *ds, int port) 7438fe6832eSVladimir Oltean { 7448fe6832eSVladimir Oltean struct dsa_port *dp = dsa_to_port(ds, port); 7458fe6832eSVladimir Oltean struct ocelot *ocelot = ds->priv; 7468fe6832eSVladimir Oltean 7478fe6832eSVladimir Oltean ocelot_port_lag_change(ocelot, port, dp->lag_tx_enabled); 7488fe6832eSVladimir Oltean 7498fe6832eSVladimir Oltean return 0; 7508fe6832eSVladimir Oltean } 7518fe6832eSVladimir Oltean 75256051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 75356051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 75456051948SVladimir Oltean { 7552f0402feSVladimir Oltean struct ocelot *ocelot = ds->priv; 756b7a9e0daSVladimir Oltean u16 flags = vlan->flags; 7572f0402feSVladimir Oltean 7589a720680SVladimir Oltean /* Ocelot switches copy frames as-is to the CPU, so the flags: 7599a720680SVladimir Oltean * egress-untagged or not, pvid or not, make no difference. This 7609a720680SVladimir Oltean * behavior is already better than what DSA just tries to approximate 7619a720680SVladimir Oltean * when it installs the VLAN with the same flags on the CPU port. 7629a720680SVladimir Oltean * Just accept any configuration, and don't let ocelot deny installing 7639a720680SVladimir Oltean * multiple native VLANs on the NPI port, because the switch doesn't 7649a720680SVladimir Oltean * look at the port tag settings towards the NPI interface anyway. 7659a720680SVladimir Oltean */ 7669a720680SVladimir Oltean if (port == ocelot->npi) 7679a720680SVladimir Oltean return 0; 7689a720680SVladimir Oltean 769b7a9e0daSVladimir Oltean return ocelot_vlan_prepare(ocelot, port, vlan->vid, 7702f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 7712f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 77256051948SVladimir Oltean } 77356051948SVladimir Oltean 774bae33f2bSVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 77556051948SVladimir Oltean { 77656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 77756051948SVladimir Oltean 778bae33f2bSVladimir Oltean return ocelot_port_vlan_filtering(ocelot, port, enabled); 77956051948SVladimir Oltean } 78056051948SVladimir Oltean 7811958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port, 78256051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 78356051948SVladimir Oltean { 78456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 785183be6f9SVladimir Oltean u16 flags = vlan->flags; 7861958d581SVladimir Oltean int err; 78756051948SVladimir Oltean 7881958d581SVladimir Oltean err = felix_vlan_prepare(ds, port, vlan); 7891958d581SVladimir Oltean if (err) 7901958d581SVladimir Oltean return err; 7911958d581SVladimir Oltean 7921958d581SVladimir Oltean return ocelot_vlan_add(ocelot, port, vlan->vid, 793183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 794183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 79556051948SVladimir Oltean } 79656051948SVladimir Oltean 79756051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 79856051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 79956051948SVladimir Oltean { 80056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 80156051948SVladimir Oltean 802b7a9e0daSVladimir Oltean return ocelot_vlan_del(ocelot, port, vlan->vid); 80356051948SVladimir Oltean } 80456051948SVladimir Oltean 80556051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 80656051948SVladimir Oltean struct phy_device *phy) 80756051948SVladimir Oltean { 80856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 80956051948SVladimir Oltean 81056051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 81156051948SVladimir Oltean 81256051948SVladimir Oltean return 0; 81356051948SVladimir Oltean } 81456051948SVladimir Oltean 81556051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 81656051948SVladimir Oltean { 81756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 81856051948SVladimir Oltean 81956051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 82056051948SVladimir Oltean } 82156051948SVladimir Oltean 822bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 823bdeced75SVladimir Oltean unsigned long *supported, 824bdeced75SVladimir Oltean struct phylink_link_state *state) 825bdeced75SVladimir Oltean { 826bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 827375e1314SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 828bdeced75SVladimir Oltean 829375e1314SVladimir Oltean if (felix->info->phylink_validate) 830375e1314SVladimir Oltean felix->info->phylink_validate(ocelot, port, supported, state); 831bdeced75SVladimir Oltean } 832bdeced75SVladimir Oltean 833bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 834bdeced75SVladimir Oltean unsigned int link_an_mode, 835bdeced75SVladimir Oltean const struct phylink_link_state *state) 836bdeced75SVladimir Oltean { 837bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 838bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 839588d0550SIoana Ciornei struct dsa_port *dp = dsa_to_port(ds, port); 840bdeced75SVladimir Oltean 841588d0550SIoana Ciornei if (felix->pcs[port]) 842588d0550SIoana Ciornei phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs); 843bdeced75SVladimir Oltean } 844bdeced75SVladimir Oltean 845bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 846bdeced75SVladimir Oltean unsigned int link_an_mode, 847bdeced75SVladimir Oltean phy_interface_t interface) 848bdeced75SVladimir Oltean { 849bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 850bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 851eb4733d7SVladimir Oltean int err; 852bdeced75SVladimir Oltean 853eb4733d7SVladimir Oltean ocelot_port_rmwl(ocelot_port, 0, DEV_MAC_ENA_CFG_RX_ENA, 854eb4733d7SVladimir Oltean DEV_MAC_ENA_CFG); 855eb4733d7SVladimir Oltean 856886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); 857eb4733d7SVladimir Oltean 858eb4733d7SVladimir Oltean err = ocelot_port_flush(ocelot, port); 859eb4733d7SVladimir Oltean if (err) 860eb4733d7SVladimir Oltean dev_err(ocelot->dev, "failed to flush port %d: %d\n", 861eb4733d7SVladimir Oltean port, err); 862eb4733d7SVladimir Oltean 863eb4733d7SVladimir Oltean /* Put the port in reset. */ 864eb4733d7SVladimir Oltean ocelot_port_writel(ocelot_port, 865eb4733d7SVladimir Oltean DEV_CLOCK_CFG_MAC_TX_RST | 866eb4733d7SVladimir Oltean DEV_CLOCK_CFG_MAC_RX_RST | 867eb4733d7SVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 868eb4733d7SVladimir Oltean DEV_CLOCK_CFG); 869bdeced75SVladimir Oltean } 870bdeced75SVladimir Oltean 871bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 872bdeced75SVladimir Oltean unsigned int link_an_mode, 873bdeced75SVladimir Oltean phy_interface_t interface, 8745b502a7bSRussell King struct phy_device *phydev, 8755b502a7bSRussell King int speed, int duplex, 8765b502a7bSRussell King bool tx_pause, bool rx_pause) 877bdeced75SVladimir Oltean { 878bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 879bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 8807e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 8817e14a2dcSVladimir Oltean u32 mac_fc_cfg; 882bdeced75SVladimir Oltean 8837e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 8847e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 8857e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 8867e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 8877e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 8887e14a2dcSVladimir Oltean * value). 8897e14a2dcSVladimir Oltean */ 8907e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 8917e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 8927e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 8937e14a2dcSVladimir Oltean 8947e14a2dcSVladimir Oltean switch (speed) { 8957e14a2dcSVladimir Oltean case SPEED_10: 8967e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 8977e14a2dcSVladimir Oltean break; 8987e14a2dcSVladimir Oltean case SPEED_100: 8997e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 9007e14a2dcSVladimir Oltean break; 9017e14a2dcSVladimir Oltean case SPEED_1000: 9027e14a2dcSVladimir Oltean case SPEED_2500: 9037e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 9047e14a2dcSVladimir Oltean break; 9057e14a2dcSVladimir Oltean default: 9067e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 9077e14a2dcSVladimir Oltean port, speed); 9087e14a2dcSVladimir Oltean return; 9097e14a2dcSVladimir Oltean } 9107e14a2dcSVladimir Oltean 9117e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 9127e14a2dcSVladimir Oltean * adaptation. 9137e14a2dcSVladimir Oltean */ 9147e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 9157e14a2dcSVladimir Oltean 9167e14a2dcSVladimir Oltean if (tx_pause) 9177e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 9187e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 9197e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 9207e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 9217e14a2dcSVladimir Oltean 9227e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 9237e14a2dcSVladimir Oltean * specification in incoming pause frames. 9247e14a2dcSVladimir Oltean */ 9257e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 9267e14a2dcSVladimir Oltean 9277e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 9287e14a2dcSVladimir Oltean 9297e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 9307e14a2dcSVladimir Oltean * enable MAC module 9317e14a2dcSVladimir Oltean */ 932bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 933bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 934bdeced75SVladimir Oltean 935bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 936bdeced75SVladimir Oltean * MAC addresses. 937bdeced75SVladimir Oltean */ 938bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 939bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 940bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 941bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 942bdeced75SVladimir Oltean 943bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 944886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, 945886e1387SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); 9467e14a2dcSVladimir Oltean 9477e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 9487e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 949bdeced75SVladimir Oltean } 950bdeced75SVladimir Oltean 951bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 952bd2b3161SXiaoliang Yang { 953bd2b3161SXiaoliang Yang int i; 954bd2b3161SXiaoliang Yang 955bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 956bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 957bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 958bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 959bd2b3161SXiaoliang Yang port); 960bd2b3161SXiaoliang Yang 96170d39a6eSVladimir Oltean for (i = 0; i < OCELOT_NUM_TC * 2; i++) { 962bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 963bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 964bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 965bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 966bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 967bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 968bd2b3161SXiaoliang Yang port, i); 969bd2b3161SXiaoliang Yang } 970bd2b3161SXiaoliang Yang } 971bd2b3161SXiaoliang Yang 97256051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 97356051948SVladimir Oltean u32 stringset, u8 *data) 97456051948SVladimir Oltean { 97556051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 97656051948SVladimir Oltean 97756051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 97856051948SVladimir Oltean } 97956051948SVladimir Oltean 98056051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 98156051948SVladimir Oltean { 98256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 98356051948SVladimir Oltean 98456051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 98556051948SVladimir Oltean } 98656051948SVladimir Oltean 98756051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 98856051948SVladimir Oltean { 98956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 99056051948SVladimir Oltean 99156051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 99256051948SVladimir Oltean } 99356051948SVladimir Oltean 99456051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 99556051948SVladimir Oltean struct ethtool_ts_info *info) 99656051948SVladimir Oltean { 99756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 99856051948SVladimir Oltean 99956051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 100056051948SVladimir Oltean } 100156051948SVladimir Oltean 1002bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 1003bdeced75SVladimir Oltean struct device_node *ports_node, 1004bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 1005bdeced75SVladimir Oltean { 1006bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 1007bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 1008bdeced75SVladimir Oltean struct device_node *child; 1009bdeced75SVladimir Oltean 101037fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 1011bdeced75SVladimir Oltean phy_interface_t phy_mode; 1012bdeced75SVladimir Oltean u32 port; 1013bdeced75SVladimir Oltean int err; 1014bdeced75SVladimir Oltean 1015bdeced75SVladimir Oltean /* Get switch port number from DT */ 1016bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 1017bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 1018bdeced75SVladimir Oltean "(property \"reg\")\n"); 1019bdeced75SVladimir Oltean of_node_put(child); 1020bdeced75SVladimir Oltean return -ENODEV; 1021bdeced75SVladimir Oltean } 1022bdeced75SVladimir Oltean 1023bdeced75SVladimir Oltean /* Get PHY mode from DT */ 1024bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 1025bdeced75SVladimir Oltean if (err) { 1026bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 1027bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 1028bdeced75SVladimir Oltean port); 1029bdeced75SVladimir Oltean of_node_put(child); 1030bdeced75SVladimir Oltean return -ENODEV; 1031bdeced75SVladimir Oltean } 1032bdeced75SVladimir Oltean 1033bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 1034bdeced75SVladimir Oltean if (err < 0) { 1035bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 1036bdeced75SVladimir Oltean phy_modes(phy_mode), port); 103759ebb430SSumera Priyadarsini of_node_put(child); 1038bdeced75SVladimir Oltean return err; 1039bdeced75SVladimir Oltean } 1040bdeced75SVladimir Oltean 1041bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 1042bdeced75SVladimir Oltean } 1043bdeced75SVladimir Oltean 1044bdeced75SVladimir Oltean return 0; 1045bdeced75SVladimir Oltean } 1046bdeced75SVladimir Oltean 1047bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 1048bdeced75SVladimir Oltean { 1049bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 1050bdeced75SVladimir Oltean struct device_node *switch_node; 1051bdeced75SVladimir Oltean struct device_node *ports_node; 1052bdeced75SVladimir Oltean int err; 1053bdeced75SVladimir Oltean 1054bdeced75SVladimir Oltean switch_node = dev->of_node; 1055bdeced75SVladimir Oltean 1056bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 1057bdeced75SVladimir Oltean if (!ports_node) { 1058bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 1059bdeced75SVladimir Oltean return -ENODEV; 1060bdeced75SVladimir Oltean } 1061bdeced75SVladimir Oltean 1062bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 1063bdeced75SVladimir Oltean of_node_put(ports_node); 1064bdeced75SVladimir Oltean 1065bdeced75SVladimir Oltean return err; 1066bdeced75SVladimir Oltean } 1067bdeced75SVladimir Oltean 106856051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 106956051948SVladimir Oltean { 107056051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 1071bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 1072b4024c9eSClaudiu Manoil struct resource res; 107356051948SVladimir Oltean int port, i, err; 107456051948SVladimir Oltean 107556051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 107656051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 107756051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 107856051948SVladimir Oltean if (!ocelot->ports) 107956051948SVladimir Oltean return -ENOMEM; 108056051948SVladimir Oltean 108156051948SVladimir Oltean ocelot->map = felix->info->map; 108256051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 108356051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 108421ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 108507d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 108656051948SVladimir Oltean ocelot->ops = felix->info->ops; 1087cacea62fSVladimir Oltean ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; 1088cacea62fSVladimir Oltean ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; 1089f59fd9caSVladimir Oltean ocelot->devlink = felix->ds->devlink; 109056051948SVladimir Oltean 1091bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 1092bdeced75SVladimir Oltean GFP_KERNEL); 1093bdeced75SVladimir Oltean if (!port_phy_modes) 1094bdeced75SVladimir Oltean return -ENOMEM; 1095bdeced75SVladimir Oltean 1096bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 1097bdeced75SVladimir Oltean if (err) { 1098bdeced75SVladimir Oltean kfree(port_phy_modes); 1099bdeced75SVladimir Oltean return err; 1100bdeced75SVladimir Oltean } 1101bdeced75SVladimir Oltean 110256051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 110356051948SVladimir Oltean struct regmap *target; 110456051948SVladimir Oltean 110556051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 110656051948SVladimir Oltean continue; 110756051948SVladimir Oltean 1108b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 1109b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 1110375e1314SVladimir Oltean res.start += felix->switch_base; 1111375e1314SVladimir Oltean res.end += felix->switch_base; 111256051948SVladimir Oltean 1113b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 111456051948SVladimir Oltean if (IS_ERR(target)) { 111556051948SVladimir Oltean dev_err(ocelot->dev, 111656051948SVladimir Oltean "Failed to map device memory space\n"); 1117bdeced75SVladimir Oltean kfree(port_phy_modes); 111856051948SVladimir Oltean return PTR_ERR(target); 111956051948SVladimir Oltean } 112056051948SVladimir Oltean 112156051948SVladimir Oltean ocelot->targets[i] = target; 112256051948SVladimir Oltean } 112356051948SVladimir Oltean 112456051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 112556051948SVladimir Oltean if (err) { 112656051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 1127bdeced75SVladimir Oltean kfree(port_phy_modes); 112856051948SVladimir Oltean return err; 112956051948SVladimir Oltean } 113056051948SVladimir Oltean 113156051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 113256051948SVladimir Oltean struct ocelot_port *ocelot_port; 113391c724cfSVladimir Oltean struct regmap *target; 113456051948SVladimir Oltean 113556051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 113656051948SVladimir Oltean sizeof(struct ocelot_port), 113756051948SVladimir Oltean GFP_KERNEL); 113856051948SVladimir Oltean if (!ocelot_port) { 113956051948SVladimir Oltean dev_err(ocelot->dev, 114056051948SVladimir Oltean "failed to allocate port memory\n"); 1141bdeced75SVladimir Oltean kfree(port_phy_modes); 114256051948SVladimir Oltean return -ENOMEM; 114356051948SVladimir Oltean } 114456051948SVladimir Oltean 1145b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 1146b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 1147375e1314SVladimir Oltean res.start += felix->switch_base; 1148375e1314SVladimir Oltean res.end += felix->switch_base; 114956051948SVladimir Oltean 115091c724cfSVladimir Oltean target = ocelot_regmap_init(ocelot, &res); 115191c724cfSVladimir Oltean if (IS_ERR(target)) { 115256051948SVladimir Oltean dev_err(ocelot->dev, 115391c724cfSVladimir Oltean "Failed to map memory space for port %d\n", 115491c724cfSVladimir Oltean port); 1155bdeced75SVladimir Oltean kfree(port_phy_modes); 115691c724cfSVladimir Oltean return PTR_ERR(target); 115756051948SVladimir Oltean } 115856051948SVladimir Oltean 1159bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 116056051948SVladimir Oltean ocelot_port->ocelot = ocelot; 116191c724cfSVladimir Oltean ocelot_port->target = target; 116256051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 116356051948SVladimir Oltean } 116456051948SVladimir Oltean 1165bdeced75SVladimir Oltean kfree(port_phy_modes); 1166bdeced75SVladimir Oltean 1167bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 1168bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 1169bdeced75SVladimir Oltean if (err < 0) 1170bdeced75SVladimir Oltean return err; 1171bdeced75SVladimir Oltean } 1172bdeced75SVladimir Oltean 117356051948SVladimir Oltean return 0; 117456051948SVladimir Oltean } 117556051948SVladimir Oltean 117656051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 117756051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 117856051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 117956051948SVladimir Oltean * (which will not work). 118056051948SVladimir Oltean */ 118156051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 118256051948SVladimir Oltean { 118356051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 118456051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 118556051948SVladimir Oltean int port, err; 118656051948SVladimir Oltean 118756051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 118856051948SVladimir Oltean if (err) 118956051948SVladimir Oltean return err; 119056051948SVladimir Oltean 1191d1cc0e93SVladimir Oltean err = ocelot_init(ocelot); 1192d1cc0e93SVladimir Oltean if (err) 1193d1cc0e93SVladimir Oltean return err; 1194d1cc0e93SVladimir Oltean 11952b49d128SYangbo Lu if (ocelot->ptp) { 11962ac7c6c5SVladimir Oltean err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); 11972b49d128SYangbo Lu if (err) { 11982b49d128SYangbo Lu dev_err(ocelot->dev, 11992b49d128SYangbo Lu "Timestamp initialization failed\n"); 12002b49d128SYangbo Lu ocelot->ptp = 0; 12012b49d128SYangbo Lu } 12022b49d128SYangbo Lu } 120356051948SVladimir Oltean 120456051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1205adb3dccfSVladimir Oltean if (dsa_is_unused_port(ds, port)) 1206adb3dccfSVladimir Oltean continue; 120756051948SVladimir Oltean 1208adb3dccfSVladimir Oltean ocelot_init_port(ocelot, port); 1209bd2b3161SXiaoliang Yang 1210bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 1211bd2b3161SXiaoliang Yang * bits of vlan tag. 1212bd2b3161SXiaoliang Yang */ 1213bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 121456051948SVladimir Oltean } 121556051948SVladimir Oltean 1216f59fd9caSVladimir Oltean err = ocelot_devlink_sb_register(ocelot); 1217f59fd9caSVladimir Oltean if (err) 1218f59fd9caSVladimir Oltean return err; 1219f59fd9caSVladimir Oltean 1220adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1221adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 1222adb3dccfSVladimir Oltean continue; 1223adb3dccfSVladimir Oltean 1224adb3dccfSVladimir Oltean /* The initial tag protocol is NPI which always returns 0, so 1225adb3dccfSVladimir Oltean * there's no real point in checking for errors. 12261cf3299bSVladimir Oltean */ 1227adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, port, felix->tag_proto); 1228adb3dccfSVladimir Oltean } 12291cf3299bSVladimir Oltean 12300b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 1231c54913c1SVladimir Oltean ds->assisted_learning_on_cpu_port = true; 1232bdeced75SVladimir Oltean 123356051948SVladimir Oltean return 0; 123456051948SVladimir Oltean } 123556051948SVladimir Oltean 123656051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 123756051948SVladimir Oltean { 123856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 1239bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1240e5fb512dSVladimir Oltean int port; 1241bdeced75SVladimir Oltean 1242adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1243adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 1244adb3dccfSVladimir Oltean continue; 1245adb3dccfSVladimir Oltean 1246adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, port, felix->tag_proto); 1247adb3dccfSVladimir Oltean } 1248adb3dccfSVladimir Oltean 1249f59fd9caSVladimir Oltean ocelot_devlink_sb_unregister(ocelot); 1250d19741b0SVladimir Oltean ocelot_deinit_timestamp(ocelot); 1251d19741b0SVladimir Oltean ocelot_deinit(ocelot); 125256051948SVladimir Oltean 1253e5fb512dSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) 1254e5fb512dSVladimir Oltean ocelot_deinit_port(ocelot, port); 1255d19741b0SVladimir Oltean 1256d19741b0SVladimir Oltean if (felix->info->mdio_bus_free) 1257d19741b0SVladimir Oltean felix->info->mdio_bus_free(ocelot); 125856051948SVladimir Oltean } 125956051948SVladimir Oltean 1260c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 1261c0bcf537SYangbo Lu struct ifreq *ifr) 1262c0bcf537SYangbo Lu { 1263c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1264c0bcf537SYangbo Lu 1265c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 1266c0bcf537SYangbo Lu } 1267c0bcf537SYangbo Lu 1268c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 1269c0bcf537SYangbo Lu struct ifreq *ifr) 1270c0bcf537SYangbo Lu { 1271c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1272c0bcf537SYangbo Lu 1273c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 1274c0bcf537SYangbo Lu } 1275c0bcf537SYangbo Lu 1276c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 1277c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 1278c0bcf537SYangbo Lu { 127940d3f295SVladimir Oltean u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 1280c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 1281c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1282c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 1283c0bcf537SYangbo Lu struct timespec64 ts; 1284c0bcf537SYangbo Lu u64 tstamp, val; 1285c0bcf537SYangbo Lu 1286c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 1287c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 1288c0bcf537SYangbo Lu 128940d3f295SVladimir Oltean ocelot_xfh_get_rew_val(extraction, &val); 1290c0bcf537SYangbo Lu tstamp_lo = (u32)val; 1291c0bcf537SYangbo Lu 1292c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 1293c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 1294c0bcf537SYangbo Lu tstamp_hi--; 1295c0bcf537SYangbo Lu 1296c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 1297c0bcf537SYangbo Lu 1298c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 1299c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 1300c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 1301c0bcf537SYangbo Lu return false; 1302c0bcf537SYangbo Lu } 1303c0bcf537SYangbo Lu 13043243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 1305c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 1306c0bcf537SYangbo Lu { 1307c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1308c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 1309c0bcf537SYangbo Lu 1310e2f9a8feSVladimir Oltean if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) && 1311e2f9a8feSVladimir Oltean ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 1312e2f9a8feSVladimir Oltean ocelot_port_add_txtstamp_skb(ocelot, port, clone); 1313c0bcf537SYangbo Lu return true; 1314e2f9a8feSVladimir Oltean } 1315c0bcf537SYangbo Lu 1316c0bcf537SYangbo Lu return false; 1317c0bcf537SYangbo Lu } 1318c0bcf537SYangbo Lu 13190b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 13200b912fc9SVladimir Oltean { 13210b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 13220b912fc9SVladimir Oltean 13230b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 13240b912fc9SVladimir Oltean 13250b912fc9SVladimir Oltean return 0; 13260b912fc9SVladimir Oltean } 13270b912fc9SVladimir Oltean 13280b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 13290b912fc9SVladimir Oltean { 13300b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 13310b912fc9SVladimir Oltean 13320b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 13330b912fc9SVladimir Oltean } 13340b912fc9SVladimir Oltean 133507d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 133607d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 133707d985eeSVladimir Oltean { 133807d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 133907d985eeSVladimir Oltean 134007d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 134107d985eeSVladimir Oltean } 134207d985eeSVladimir Oltean 134307d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 134407d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 134507d985eeSVladimir Oltean { 134607d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 134707d985eeSVladimir Oltean 134807d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 134907d985eeSVladimir Oltean } 135007d985eeSVladimir Oltean 135107d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 135207d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 135307d985eeSVladimir Oltean { 135407d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 135507d985eeSVladimir Oltean 135607d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 135707d985eeSVladimir Oltean } 135807d985eeSVladimir Oltean 1359fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 1360fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 1361fc411eaaSVladimir Oltean { 1362fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 1363fc411eaaSVladimir Oltean struct ocelot_policer pol = { 1364fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 13655f035af7SPo Liu .burst = policer->burst, 1366fc411eaaSVladimir Oltean }; 1367fc411eaaSVladimir Oltean 1368fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 1369fc411eaaSVladimir Oltean } 1370fc411eaaSVladimir Oltean 1371fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 1372fc411eaaSVladimir Oltean { 1373fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 1374fc411eaaSVladimir Oltean 1375fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 1376fc411eaaSVladimir Oltean } 1377fc411eaaSVladimir Oltean 1378de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 1379de143c0eSXiaoliang Yang enum tc_setup_type type, 1380de143c0eSXiaoliang Yang void *type_data) 1381de143c0eSXiaoliang Yang { 1382de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 1383de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 1384de143c0eSXiaoliang Yang 1385de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 1386de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 1387de143c0eSXiaoliang Yang else 1388de143c0eSXiaoliang Yang return -EOPNOTSUPP; 1389de143c0eSXiaoliang Yang } 1390de143c0eSXiaoliang Yang 1391f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index, 1392f59fd9caSVladimir Oltean u16 pool_index, 1393f59fd9caSVladimir Oltean struct devlink_sb_pool_info *pool_info) 1394f59fd9caSVladimir Oltean { 1395f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1396f59fd9caSVladimir Oltean 1397f59fd9caSVladimir Oltean return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info); 1398f59fd9caSVladimir Oltean } 1399f59fd9caSVladimir Oltean 1400f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index, 1401f59fd9caSVladimir Oltean u16 pool_index, u32 size, 1402f59fd9caSVladimir Oltean enum devlink_sb_threshold_type threshold_type, 1403f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 1404f59fd9caSVladimir Oltean { 1405f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1406f59fd9caSVladimir Oltean 1407f59fd9caSVladimir Oltean return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size, 1408f59fd9caSVladimir Oltean threshold_type, extack); 1409f59fd9caSVladimir Oltean } 1410f59fd9caSVladimir Oltean 1411f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port, 1412f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1413f59fd9caSVladimir Oltean u32 *p_threshold) 1414f59fd9caSVladimir Oltean { 1415f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1416f59fd9caSVladimir Oltean 1417f59fd9caSVladimir Oltean return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index, 1418f59fd9caSVladimir Oltean p_threshold); 1419f59fd9caSVladimir Oltean } 1420f59fd9caSVladimir Oltean 1421f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port, 1422f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1423f59fd9caSVladimir Oltean u32 threshold, struct netlink_ext_ack *extack) 1424f59fd9caSVladimir Oltean { 1425f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1426f59fd9caSVladimir Oltean 1427f59fd9caSVladimir Oltean return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index, 1428f59fd9caSVladimir Oltean threshold, extack); 1429f59fd9caSVladimir Oltean } 1430f59fd9caSVladimir Oltean 1431f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port, 1432f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1433f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1434f59fd9caSVladimir Oltean u16 *p_pool_index, u32 *p_threshold) 1435f59fd9caSVladimir Oltean { 1436f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1437f59fd9caSVladimir Oltean 1438f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index, 1439f59fd9caSVladimir Oltean pool_type, p_pool_index, 1440f59fd9caSVladimir Oltean p_threshold); 1441f59fd9caSVladimir Oltean } 1442f59fd9caSVladimir Oltean 1443f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port, 1444f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1445f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1446f59fd9caSVladimir Oltean u16 pool_index, u32 threshold, 1447f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 1448f59fd9caSVladimir Oltean { 1449f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1450f59fd9caSVladimir Oltean 1451f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index, 1452f59fd9caSVladimir Oltean pool_type, pool_index, threshold, 1453f59fd9caSVladimir Oltean extack); 1454f59fd9caSVladimir Oltean } 1455f59fd9caSVladimir Oltean 1456f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds, 1457f59fd9caSVladimir Oltean unsigned int sb_index) 1458f59fd9caSVladimir Oltean { 1459f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1460f59fd9caSVladimir Oltean 1461f59fd9caSVladimir Oltean return ocelot_sb_occ_snapshot(ocelot, sb_index); 1462f59fd9caSVladimir Oltean } 1463f59fd9caSVladimir Oltean 1464f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds, 1465f59fd9caSVladimir Oltean unsigned int sb_index) 1466f59fd9caSVladimir Oltean { 1467f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1468f59fd9caSVladimir Oltean 1469f59fd9caSVladimir Oltean return ocelot_sb_occ_max_clear(ocelot, sb_index); 1470f59fd9caSVladimir Oltean } 1471f59fd9caSVladimir Oltean 1472f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port, 1473f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1474f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 1475f59fd9caSVladimir Oltean { 1476f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1477f59fd9caSVladimir Oltean 1478f59fd9caSVladimir Oltean return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index, 1479f59fd9caSVladimir Oltean p_cur, p_max); 1480f59fd9caSVladimir Oltean } 1481f59fd9caSVladimir Oltean 1482f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port, 1483f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1484f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1485f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 1486f59fd9caSVladimir Oltean { 1487f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1488f59fd9caSVladimir Oltean 1489f59fd9caSVladimir Oltean return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index, 1490f59fd9caSVladimir Oltean pool_type, p_cur, p_max); 1491f59fd9caSVladimir Oltean } 1492f59fd9caSVladimir Oltean 1493375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = { 149456051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 1495adb3dccfSVladimir Oltean .change_tag_protocol = felix_change_tag_protocol, 149656051948SVladimir Oltean .setup = felix_setup, 149756051948SVladimir Oltean .teardown = felix_teardown, 149856051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 149956051948SVladimir Oltean .get_strings = felix_get_strings, 150056051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 150156051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 150256051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 1503bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 1504bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 1505bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 1506bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 150756051948SVladimir Oltean .port_enable = felix_port_enable, 150856051948SVladimir Oltean .port_disable = felix_port_disable, 150956051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 151056051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 151156051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 1512209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 1513209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 1514421741eaSVladimir Oltean .port_pre_bridge_flags = felix_pre_bridge_flags, 1515421741eaSVladimir Oltean .port_bridge_flags = felix_bridge_flags, 151656051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 151756051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 15188fe6832eSVladimir Oltean .port_lag_join = felix_lag_join, 15198fe6832eSVladimir Oltean .port_lag_leave = felix_lag_leave, 15208fe6832eSVladimir Oltean .port_lag_change = felix_lag_change, 152156051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 152256051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 152356051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 152456051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 1525c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 1526c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 1527c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 1528c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 15290b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 15300b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 1531fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 1532fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 153307d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 153407d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 153507d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 1536de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 1537f59fd9caSVladimir Oltean .devlink_sb_pool_get = felix_sb_pool_get, 1538f59fd9caSVladimir Oltean .devlink_sb_pool_set = felix_sb_pool_set, 1539f59fd9caSVladimir Oltean .devlink_sb_port_pool_get = felix_sb_port_pool_get, 1540f59fd9caSVladimir Oltean .devlink_sb_port_pool_set = felix_sb_port_pool_set, 1541f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get, 1542f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set, 1543f59fd9caSVladimir Oltean .devlink_sb_occ_snapshot = felix_sb_occ_snapshot, 1544f59fd9caSVladimir Oltean .devlink_sb_occ_max_clear = felix_sb_occ_max_clear, 1545f59fd9caSVladimir Oltean .devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get, 1546f59fd9caSVladimir Oltean .devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get, 154756051948SVladimir Oltean }; 1548319e4dd1SVladimir Oltean 1549319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) 1550319e4dd1SVladimir Oltean { 1551319e4dd1SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1552319e4dd1SVladimir Oltean struct dsa_switch *ds = felix->ds; 1553319e4dd1SVladimir Oltean 1554319e4dd1SVladimir Oltean if (!dsa_is_user_port(ds, port)) 1555319e4dd1SVladimir Oltean return NULL; 1556319e4dd1SVladimir Oltean 1557319e4dd1SVladimir Oltean return dsa_to_port(ds, port)->slave; 1558319e4dd1SVladimir Oltean } 1559319e4dd1SVladimir Oltean 1560319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev) 1561319e4dd1SVladimir Oltean { 1562319e4dd1SVladimir Oltean struct dsa_port *dp; 1563319e4dd1SVladimir Oltean 1564319e4dd1SVladimir Oltean dp = dsa_port_from_netdev(dev); 1565319e4dd1SVladimir Oltean if (IS_ERR(dp)) 1566319e4dd1SVladimir Oltean return -EINVAL; 1567319e4dd1SVladimir Oltean 1568319e4dd1SVladimir Oltean return dp->index; 1569319e4dd1SVladimir Oltean } 1570