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> 16*e21268efSVladimir Oltean #include <linux/dsa/8021q.h> 1784705fc1SMaxim Kochetkov #include <linux/platform_device.h> 18c0bcf537SYangbo Lu #include <linux/packing.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 28*e21268efSVladimir Oltean static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid, 29*e21268efSVladimir Oltean bool pvid, bool untagged) 30*e21268efSVladimir Oltean { 31*e21268efSVladimir Oltean struct ocelot_vcap_filter *outer_tagging_rule; 32*e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 33*e21268efSVladimir Oltean struct dsa_switch *ds = felix->ds; 34*e21268efSVladimir Oltean int key_length, upstream, err; 35*e21268efSVladimir Oltean 36*e21268efSVladimir Oltean /* We don't need to install the rxvlan into the other ports' filtering 37*e21268efSVladimir Oltean * tables, because we're just pushing the rxvlan when sending towards 38*e21268efSVladimir Oltean * the CPU 39*e21268efSVladimir Oltean */ 40*e21268efSVladimir Oltean if (!pvid) 41*e21268efSVladimir Oltean return 0; 42*e21268efSVladimir Oltean 43*e21268efSVladimir Oltean key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length; 44*e21268efSVladimir Oltean upstream = dsa_upstream_port(ds, port); 45*e21268efSVladimir Oltean 46*e21268efSVladimir Oltean outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), 47*e21268efSVladimir Oltean GFP_KERNEL); 48*e21268efSVladimir Oltean if (!outer_tagging_rule) 49*e21268efSVladimir Oltean return -ENOMEM; 50*e21268efSVladimir Oltean 51*e21268efSVladimir Oltean outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 52*e21268efSVladimir Oltean outer_tagging_rule->prio = 1; 53*e21268efSVladimir Oltean outer_tagging_rule->id.cookie = port; 54*e21268efSVladimir Oltean outer_tagging_rule->id.tc_offload = false; 55*e21268efSVladimir Oltean outer_tagging_rule->block_id = VCAP_ES0; 56*e21268efSVladimir Oltean outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 57*e21268efSVladimir Oltean outer_tagging_rule->lookup = 0; 58*e21268efSVladimir Oltean outer_tagging_rule->ingress_port.value = port; 59*e21268efSVladimir Oltean outer_tagging_rule->ingress_port.mask = GENMASK(key_length - 1, 0); 60*e21268efSVladimir Oltean outer_tagging_rule->egress_port.value = upstream; 61*e21268efSVladimir Oltean outer_tagging_rule->egress_port.mask = GENMASK(key_length - 1, 0); 62*e21268efSVladimir Oltean outer_tagging_rule->action.push_outer_tag = OCELOT_ES0_TAG; 63*e21268efSVladimir Oltean outer_tagging_rule->action.tag_a_tpid_sel = OCELOT_TAG_TPID_SEL_8021AD; 64*e21268efSVladimir Oltean outer_tagging_rule->action.tag_a_vid_sel = 1; 65*e21268efSVladimir Oltean outer_tagging_rule->action.vid_a_val = vid; 66*e21268efSVladimir Oltean 67*e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, outer_tagging_rule, NULL); 68*e21268efSVladimir Oltean if (err) 69*e21268efSVladimir Oltean kfree(outer_tagging_rule); 70*e21268efSVladimir Oltean 71*e21268efSVladimir Oltean return err; 72*e21268efSVladimir Oltean } 73*e21268efSVladimir Oltean 74*e21268efSVladimir Oltean static int felix_tag_8021q_txvlan_add(struct felix *felix, int port, u16 vid, 75*e21268efSVladimir Oltean bool pvid, bool untagged) 76*e21268efSVladimir Oltean { 77*e21268efSVladimir Oltean struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 78*e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 79*e21268efSVladimir Oltean struct dsa_switch *ds = felix->ds; 80*e21268efSVladimir Oltean int upstream, err; 81*e21268efSVladimir Oltean 82*e21268efSVladimir Oltean /* tag_8021q.c assumes we are implementing this via port VLAN 83*e21268efSVladimir Oltean * membership, which we aren't. So we don't need to add any VCAP filter 84*e21268efSVladimir Oltean * for the CPU port. 85*e21268efSVladimir Oltean */ 86*e21268efSVladimir Oltean if (ocelot->ports[port]->is_dsa_8021q_cpu) 87*e21268efSVladimir Oltean return 0; 88*e21268efSVladimir Oltean 89*e21268efSVladimir Oltean untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 90*e21268efSVladimir Oltean if (!untagging_rule) 91*e21268efSVladimir Oltean return -ENOMEM; 92*e21268efSVladimir Oltean 93*e21268efSVladimir Oltean redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); 94*e21268efSVladimir Oltean if (!redirect_rule) { 95*e21268efSVladimir Oltean kfree(untagging_rule); 96*e21268efSVladimir Oltean return -ENOMEM; 97*e21268efSVladimir Oltean } 98*e21268efSVladimir Oltean 99*e21268efSVladimir Oltean upstream = dsa_upstream_port(ds, port); 100*e21268efSVladimir Oltean 101*e21268efSVladimir Oltean untagging_rule->key_type = OCELOT_VCAP_KEY_ANY; 102*e21268efSVladimir Oltean untagging_rule->ingress_port_mask = BIT(upstream); 103*e21268efSVladimir Oltean untagging_rule->vlan.vid.value = vid; 104*e21268efSVladimir Oltean untagging_rule->vlan.vid.mask = VLAN_VID_MASK; 105*e21268efSVladimir Oltean untagging_rule->prio = 1; 106*e21268efSVladimir Oltean untagging_rule->id.cookie = port; 107*e21268efSVladimir Oltean untagging_rule->id.tc_offload = false; 108*e21268efSVladimir Oltean untagging_rule->block_id = VCAP_IS1; 109*e21268efSVladimir Oltean untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 110*e21268efSVladimir Oltean untagging_rule->lookup = 0; 111*e21268efSVladimir Oltean untagging_rule->action.vlan_pop_cnt_ena = true; 112*e21268efSVladimir Oltean untagging_rule->action.vlan_pop_cnt = 1; 113*e21268efSVladimir Oltean untagging_rule->action.pag_override_mask = 0xff; 114*e21268efSVladimir Oltean untagging_rule->action.pag_val = port; 115*e21268efSVladimir Oltean 116*e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, untagging_rule, NULL); 117*e21268efSVladimir Oltean if (err) { 118*e21268efSVladimir Oltean kfree(untagging_rule); 119*e21268efSVladimir Oltean kfree(redirect_rule); 120*e21268efSVladimir Oltean return err; 121*e21268efSVladimir Oltean } 122*e21268efSVladimir Oltean 123*e21268efSVladimir Oltean redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; 124*e21268efSVladimir Oltean redirect_rule->ingress_port_mask = BIT(upstream); 125*e21268efSVladimir Oltean redirect_rule->pag = port; 126*e21268efSVladimir Oltean redirect_rule->prio = 1; 127*e21268efSVladimir Oltean redirect_rule->id.cookie = port; 128*e21268efSVladimir Oltean redirect_rule->id.tc_offload = false; 129*e21268efSVladimir Oltean redirect_rule->block_id = VCAP_IS2; 130*e21268efSVladimir Oltean redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; 131*e21268efSVladimir Oltean redirect_rule->lookup = 0; 132*e21268efSVladimir Oltean redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 133*e21268efSVladimir Oltean redirect_rule->action.port_mask = BIT(port); 134*e21268efSVladimir Oltean 135*e21268efSVladimir Oltean err = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); 136*e21268efSVladimir Oltean if (err) { 137*e21268efSVladimir Oltean ocelot_vcap_filter_del(ocelot, untagging_rule); 138*e21268efSVladimir Oltean kfree(redirect_rule); 139*e21268efSVladimir Oltean return err; 140*e21268efSVladimir Oltean } 141*e21268efSVladimir Oltean 142*e21268efSVladimir Oltean return 0; 143*e21268efSVladimir Oltean } 144*e21268efSVladimir Oltean 145*e21268efSVladimir Oltean static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, 146*e21268efSVladimir Oltean u16 flags) 147*e21268efSVladimir Oltean { 148*e21268efSVladimir Oltean bool untagged = flags & BRIDGE_VLAN_INFO_UNTAGGED; 149*e21268efSVladimir Oltean bool pvid = flags & BRIDGE_VLAN_INFO_PVID; 150*e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 151*e21268efSVladimir Oltean 152*e21268efSVladimir Oltean if (vid_is_dsa_8021q_rxvlan(vid)) 153*e21268efSVladimir Oltean return felix_tag_8021q_rxvlan_add(ocelot_to_felix(ocelot), 154*e21268efSVladimir Oltean port, vid, pvid, untagged); 155*e21268efSVladimir Oltean 156*e21268efSVladimir Oltean if (vid_is_dsa_8021q_txvlan(vid)) 157*e21268efSVladimir Oltean return felix_tag_8021q_txvlan_add(ocelot_to_felix(ocelot), 158*e21268efSVladimir Oltean port, vid, pvid, untagged); 159*e21268efSVladimir Oltean 160*e21268efSVladimir Oltean return 0; 161*e21268efSVladimir Oltean } 162*e21268efSVladimir Oltean 163*e21268efSVladimir Oltean static int felix_tag_8021q_rxvlan_del(struct felix *felix, int port, u16 vid) 164*e21268efSVladimir Oltean { 165*e21268efSVladimir Oltean struct ocelot_vcap_filter *outer_tagging_rule; 166*e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_es0; 167*e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 168*e21268efSVladimir Oltean 169*e21268efSVladimir Oltean block_vcap_es0 = &ocelot->block[VCAP_ES0]; 170*e21268efSVladimir Oltean 171*e21268efSVladimir Oltean outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0, 172*e21268efSVladimir Oltean port, false); 173*e21268efSVladimir Oltean /* In rxvlan_add, we had the "if (!pvid) return 0" logic to avoid 174*e21268efSVladimir Oltean * installing outer tagging ES0 rules where they weren't needed. 175*e21268efSVladimir Oltean * But in rxvlan_del, the API doesn't give us the "flags" anymore, 176*e21268efSVladimir Oltean * so that forces us to be slightly sloppy here, and just assume that 177*e21268efSVladimir Oltean * if we didn't find an outer_tagging_rule it means that there was 178*e21268efSVladimir Oltean * none in the first place, i.e. rxvlan_del is called on a non-pvid 179*e21268efSVladimir Oltean * port. This is most probably true though. 180*e21268efSVladimir Oltean */ 181*e21268efSVladimir Oltean if (!outer_tagging_rule) 182*e21268efSVladimir Oltean return 0; 183*e21268efSVladimir Oltean 184*e21268efSVladimir Oltean return ocelot_vcap_filter_del(ocelot, outer_tagging_rule); 185*e21268efSVladimir Oltean } 186*e21268efSVladimir Oltean 187*e21268efSVladimir Oltean static int felix_tag_8021q_txvlan_del(struct felix *felix, int port, u16 vid) 188*e21268efSVladimir Oltean { 189*e21268efSVladimir Oltean struct ocelot_vcap_filter *untagging_rule, *redirect_rule; 190*e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_is1; 191*e21268efSVladimir Oltean struct ocelot_vcap_block *block_vcap_is2; 192*e21268efSVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 193*e21268efSVladimir Oltean int err; 194*e21268efSVladimir Oltean 195*e21268efSVladimir Oltean if (ocelot->ports[port]->is_dsa_8021q_cpu) 196*e21268efSVladimir Oltean return 0; 197*e21268efSVladimir Oltean 198*e21268efSVladimir Oltean block_vcap_is1 = &ocelot->block[VCAP_IS1]; 199*e21268efSVladimir Oltean block_vcap_is2 = &ocelot->block[VCAP_IS2]; 200*e21268efSVladimir Oltean 201*e21268efSVladimir Oltean untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, 202*e21268efSVladimir Oltean port, false); 203*e21268efSVladimir Oltean if (!untagging_rule) 204*e21268efSVladimir Oltean return 0; 205*e21268efSVladimir Oltean 206*e21268efSVladimir Oltean err = ocelot_vcap_filter_del(ocelot, untagging_rule); 207*e21268efSVladimir Oltean if (err) 208*e21268efSVladimir Oltean return err; 209*e21268efSVladimir Oltean 210*e21268efSVladimir Oltean redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, 211*e21268efSVladimir Oltean port, false); 212*e21268efSVladimir Oltean if (!redirect_rule) 213*e21268efSVladimir Oltean return 0; 214*e21268efSVladimir Oltean 215*e21268efSVladimir Oltean return ocelot_vcap_filter_del(ocelot, redirect_rule); 216*e21268efSVladimir Oltean } 217*e21268efSVladimir Oltean 218*e21268efSVladimir Oltean static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) 219*e21268efSVladimir Oltean { 220*e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 221*e21268efSVladimir Oltean 222*e21268efSVladimir Oltean if (vid_is_dsa_8021q_rxvlan(vid)) 223*e21268efSVladimir Oltean return felix_tag_8021q_rxvlan_del(ocelot_to_felix(ocelot), 224*e21268efSVladimir Oltean port, vid); 225*e21268efSVladimir Oltean 226*e21268efSVladimir Oltean if (vid_is_dsa_8021q_txvlan(vid)) 227*e21268efSVladimir Oltean return felix_tag_8021q_txvlan_del(ocelot_to_felix(ocelot), 228*e21268efSVladimir Oltean port, vid); 229*e21268efSVladimir Oltean 230*e21268efSVladimir Oltean return 0; 231*e21268efSVladimir Oltean } 232*e21268efSVladimir Oltean 233*e21268efSVladimir Oltean static const struct dsa_8021q_ops felix_tag_8021q_ops = { 234*e21268efSVladimir Oltean .vlan_add = felix_tag_8021q_vlan_add, 235*e21268efSVladimir Oltean .vlan_del = felix_tag_8021q_vlan_del, 236*e21268efSVladimir Oltean }; 237*e21268efSVladimir Oltean 238*e21268efSVladimir Oltean /* Alternatively to using the NPI functionality, that same hardware MAC 239*e21268efSVladimir Oltean * connected internally to the enetc or fman DSA master can be configured to 240*e21268efSVladimir Oltean * use the software-defined tag_8021q frame format. As far as the hardware is 241*e21268efSVladimir Oltean * concerned, it thinks it is a "dumb switch" - the queues of the CPU port 242*e21268efSVladimir Oltean * module are now disconnected from it, but can still be accessed through 243*e21268efSVladimir Oltean * register-based MMIO. 244*e21268efSVladimir Oltean */ 245*e21268efSVladimir Oltean static void felix_8021q_cpu_port_init(struct ocelot *ocelot, int port) 246*e21268efSVladimir Oltean { 247*e21268efSVladimir Oltean ocelot->ports[port]->is_dsa_8021q_cpu = true; 248*e21268efSVladimir Oltean ocelot->npi = -1; 249*e21268efSVladimir Oltean 250*e21268efSVladimir Oltean /* Overwrite PGID_CPU with the non-tagging port */ 251*e21268efSVladimir Oltean ocelot_write_rix(ocelot, BIT(port), ANA_PGID_PGID, PGID_CPU); 252*e21268efSVladimir Oltean 253*e21268efSVladimir Oltean ocelot_apply_bridge_fwd_mask(ocelot); 254*e21268efSVladimir Oltean } 255*e21268efSVladimir Oltean 256*e21268efSVladimir Oltean static void felix_8021q_cpu_port_deinit(struct ocelot *ocelot, int port) 257*e21268efSVladimir Oltean { 258*e21268efSVladimir Oltean ocelot->ports[port]->is_dsa_8021q_cpu = false; 259*e21268efSVladimir Oltean 260*e21268efSVladimir Oltean /* Restore PGID_CPU */ 261*e21268efSVladimir Oltean ocelot_write_rix(ocelot, BIT(ocelot->num_phys_ports), ANA_PGID_PGID, 262*e21268efSVladimir Oltean PGID_CPU); 263*e21268efSVladimir Oltean 264*e21268efSVladimir Oltean ocelot_apply_bridge_fwd_mask(ocelot); 265*e21268efSVladimir Oltean } 266*e21268efSVladimir Oltean 267*e21268efSVladimir Oltean static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) 268*e21268efSVladimir Oltean { 269*e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 270*e21268efSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 271*e21268efSVladimir Oltean unsigned long cpu_flood; 272*e21268efSVladimir Oltean int port, err; 273*e21268efSVladimir Oltean 274*e21268efSVladimir Oltean felix_8021q_cpu_port_init(ocelot, cpu); 275*e21268efSVladimir Oltean 276*e21268efSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 277*e21268efSVladimir Oltean if (dsa_is_unused_port(ds, port)) 278*e21268efSVladimir Oltean continue; 279*e21268efSVladimir Oltean 280*e21268efSVladimir Oltean /* This overwrites ocelot_init(): 281*e21268efSVladimir Oltean * Do not forward BPDU frames to the CPU port module, 282*e21268efSVladimir Oltean * for 2 reasons: 283*e21268efSVladimir Oltean * - When these packets are injected from the tag_8021q 284*e21268efSVladimir Oltean * CPU port, we want them to go out, not loop back 285*e21268efSVladimir Oltean * into the system. 286*e21268efSVladimir Oltean * - STP traffic ingressing on a user port should go to 287*e21268efSVladimir Oltean * the tag_8021q CPU port, not to the hardware CPU 288*e21268efSVladimir Oltean * port module. 289*e21268efSVladimir Oltean */ 290*e21268efSVladimir Oltean ocelot_write_gix(ocelot, 291*e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0), 292*e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG, port); 293*e21268efSVladimir Oltean } 294*e21268efSVladimir Oltean 295*e21268efSVladimir Oltean /* In tag_8021q mode, the CPU port module is unused. So we 296*e21268efSVladimir Oltean * want to disable flooding of any kind to the CPU port module, 297*e21268efSVladimir Oltean * since packets going there will end in a black hole. 298*e21268efSVladimir Oltean */ 299*e21268efSVladimir Oltean cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 300*e21268efSVladimir Oltean ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_UC); 301*e21268efSVladimir Oltean ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_MC); 302*e21268efSVladimir Oltean 303*e21268efSVladimir Oltean felix->dsa_8021q_ctx = kzalloc(sizeof(*felix->dsa_8021q_ctx), 304*e21268efSVladimir Oltean GFP_KERNEL); 305*e21268efSVladimir Oltean if (!felix->dsa_8021q_ctx) 306*e21268efSVladimir Oltean return -ENOMEM; 307*e21268efSVladimir Oltean 308*e21268efSVladimir Oltean felix->dsa_8021q_ctx->ops = &felix_tag_8021q_ops; 309*e21268efSVladimir Oltean felix->dsa_8021q_ctx->proto = htons(ETH_P_8021AD); 310*e21268efSVladimir Oltean felix->dsa_8021q_ctx->ds = ds; 311*e21268efSVladimir Oltean 312*e21268efSVladimir Oltean err = dsa_8021q_setup(felix->dsa_8021q_ctx, true); 313*e21268efSVladimir Oltean if (err) 314*e21268efSVladimir Oltean goto out_free_dsa_8021_ctx; 315*e21268efSVladimir Oltean 316*e21268efSVladimir Oltean return 0; 317*e21268efSVladimir Oltean 318*e21268efSVladimir Oltean out_free_dsa_8021_ctx: 319*e21268efSVladimir Oltean kfree(felix->dsa_8021q_ctx); 320*e21268efSVladimir Oltean return err; 321*e21268efSVladimir Oltean } 322*e21268efSVladimir Oltean 323*e21268efSVladimir Oltean static void felix_teardown_tag_8021q(struct dsa_switch *ds, int cpu) 324*e21268efSVladimir Oltean { 325*e21268efSVladimir Oltean struct ocelot *ocelot = ds->priv; 326*e21268efSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 327*e21268efSVladimir Oltean int err, port; 328*e21268efSVladimir Oltean 329*e21268efSVladimir Oltean err = dsa_8021q_setup(felix->dsa_8021q_ctx, false); 330*e21268efSVladimir Oltean if (err) 331*e21268efSVladimir Oltean dev_err(ds->dev, "dsa_8021q_setup returned %d", err); 332*e21268efSVladimir Oltean 333*e21268efSVladimir Oltean kfree(felix->dsa_8021q_ctx); 334*e21268efSVladimir Oltean 335*e21268efSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 336*e21268efSVladimir Oltean if (dsa_is_unused_port(ds, port)) 337*e21268efSVladimir Oltean continue; 338*e21268efSVladimir Oltean 339*e21268efSVladimir Oltean /* Restore the logic from ocelot_init: 340*e21268efSVladimir Oltean * do not forward BPDU frames to the front ports. 341*e21268efSVladimir Oltean */ 342*e21268efSVladimir Oltean ocelot_write_gix(ocelot, 343*e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), 344*e21268efSVladimir Oltean ANA_PORT_CPU_FWD_BPDU_CFG, 345*e21268efSVladimir Oltean port); 346*e21268efSVladimir Oltean } 347*e21268efSVladimir Oltean 348*e21268efSVladimir Oltean felix_8021q_cpu_port_deinit(ocelot, cpu); 349*e21268efSVladimir Oltean } 350*e21268efSVladimir Oltean 351adb3dccfSVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This 352adb3dccfSVladimir Oltean * is the mode through which frames can be injected from and extracted to an 353adb3dccfSVladimir Oltean * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU 354adb3dccfSVladimir Oltean * running Linux, and this forms a DSA setup together with the enetc or fman 355adb3dccfSVladimir Oltean * DSA master. 356adb3dccfSVladimir Oltean */ 357adb3dccfSVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port) 358adb3dccfSVladimir Oltean { 359adb3dccfSVladimir Oltean ocelot->npi = port; 360adb3dccfSVladimir Oltean 361adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | 362adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), 363adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 364adb3dccfSVladimir Oltean 365adb3dccfSVladimir Oltean /* NPI port Injection/Extraction configuration */ 366adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 367adb3dccfSVladimir Oltean ocelot->npi_xtr_prefix); 368adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 369adb3dccfSVladimir Oltean ocelot->npi_inj_prefix); 370adb3dccfSVladimir Oltean 371adb3dccfSVladimir Oltean /* Disable transmission of pause frames */ 372adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); 373adb3dccfSVladimir Oltean } 374adb3dccfSVladimir Oltean 375adb3dccfSVladimir Oltean static void felix_npi_port_deinit(struct ocelot *ocelot, int port) 376adb3dccfSVladimir Oltean { 377adb3dccfSVladimir Oltean /* Restore hardware defaults */ 378adb3dccfSVladimir Oltean int unused_port = ocelot->num_phys_ports + 2; 379adb3dccfSVladimir Oltean 380adb3dccfSVladimir Oltean ocelot->npi = -1; 381adb3dccfSVladimir Oltean 382adb3dccfSVladimir Oltean ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port), 383adb3dccfSVladimir Oltean QSYS_EXT_CPU_CFG); 384adb3dccfSVladimir Oltean 385adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, 386adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 387adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, 388adb3dccfSVladimir Oltean OCELOT_TAG_PREFIX_DISABLED); 389adb3dccfSVladimir Oltean 390adb3dccfSVladimir Oltean /* Enable transmission of pause frames */ 391adb3dccfSVladimir Oltean ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1); 392adb3dccfSVladimir Oltean } 393adb3dccfSVladimir Oltean 394adb3dccfSVladimir Oltean static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu) 395adb3dccfSVladimir Oltean { 396adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 397adb3dccfSVladimir Oltean unsigned long cpu_flood; 398adb3dccfSVladimir Oltean 399adb3dccfSVladimir Oltean felix_npi_port_init(ocelot, cpu); 400adb3dccfSVladimir Oltean 401adb3dccfSVladimir Oltean /* Include the CPU port module (and indirectly, the NPI port) 402adb3dccfSVladimir Oltean * in the forwarding mask for unknown unicast - the hardware 403adb3dccfSVladimir Oltean * default value for ANA_FLOODING_FLD_UNICAST excludes 404adb3dccfSVladimir Oltean * BIT(ocelot->num_phys_ports), and so does ocelot_init, 405adb3dccfSVladimir Oltean * since Ocelot relies on whitelisting MAC addresses towards 406adb3dccfSVladimir Oltean * PGID_CPU. 407adb3dccfSVladimir Oltean * We do this because DSA does not yet perform RX filtering, 408adb3dccfSVladimir Oltean * and the NPI port does not perform source address learning, 409adb3dccfSVladimir Oltean * so traffic sent to Linux is effectively unknown from the 410adb3dccfSVladimir Oltean * switch's perspective. 411adb3dccfSVladimir Oltean */ 412adb3dccfSVladimir Oltean cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); 413adb3dccfSVladimir Oltean ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC); 414adb3dccfSVladimir Oltean 415adb3dccfSVladimir Oltean return 0; 416adb3dccfSVladimir Oltean } 417adb3dccfSVladimir Oltean 418adb3dccfSVladimir Oltean static void felix_teardown_tag_npi(struct dsa_switch *ds, int cpu) 419adb3dccfSVladimir Oltean { 420adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 421adb3dccfSVladimir Oltean 422adb3dccfSVladimir Oltean felix_npi_port_deinit(ocelot, cpu); 423adb3dccfSVladimir Oltean } 424adb3dccfSVladimir Oltean 425adb3dccfSVladimir Oltean static int felix_set_tag_protocol(struct dsa_switch *ds, int cpu, 426adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 427adb3dccfSVladimir Oltean { 428adb3dccfSVladimir Oltean int err; 429adb3dccfSVladimir Oltean 430adb3dccfSVladimir Oltean switch (proto) { 431adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 432adb3dccfSVladimir Oltean err = felix_setup_tag_npi(ds, cpu); 433adb3dccfSVladimir Oltean break; 434*e21268efSVladimir Oltean case DSA_TAG_PROTO_OCELOT_8021Q: 435*e21268efSVladimir Oltean err = felix_setup_tag_8021q(ds, cpu); 436*e21268efSVladimir Oltean break; 437adb3dccfSVladimir Oltean default: 438adb3dccfSVladimir Oltean err = -EPROTONOSUPPORT; 439adb3dccfSVladimir Oltean } 440adb3dccfSVladimir Oltean 441adb3dccfSVladimir Oltean return err; 442adb3dccfSVladimir Oltean } 443adb3dccfSVladimir Oltean 444adb3dccfSVladimir Oltean static void felix_del_tag_protocol(struct dsa_switch *ds, int cpu, 445adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 446adb3dccfSVladimir Oltean { 447adb3dccfSVladimir Oltean switch (proto) { 448adb3dccfSVladimir Oltean case DSA_TAG_PROTO_OCELOT: 449adb3dccfSVladimir Oltean felix_teardown_tag_npi(ds, cpu); 450adb3dccfSVladimir Oltean break; 451*e21268efSVladimir Oltean case DSA_TAG_PROTO_OCELOT_8021Q: 452*e21268efSVladimir Oltean felix_teardown_tag_8021q(ds, cpu); 453*e21268efSVladimir Oltean break; 454adb3dccfSVladimir Oltean default: 455adb3dccfSVladimir Oltean break; 456adb3dccfSVladimir Oltean } 457adb3dccfSVladimir Oltean } 458adb3dccfSVladimir Oltean 459*e21268efSVladimir Oltean /* This always leaves the switch in a consistent state, because although the 460*e21268efSVladimir Oltean * tag_8021q setup can fail, the NPI setup can't. So either the change is made, 461*e21268efSVladimir Oltean * or the restoration is guaranteed to work. 462*e21268efSVladimir Oltean */ 463adb3dccfSVladimir Oltean static int felix_change_tag_protocol(struct dsa_switch *ds, int cpu, 464adb3dccfSVladimir Oltean enum dsa_tag_protocol proto) 465adb3dccfSVladimir Oltean { 466adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 467adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 468adb3dccfSVladimir Oltean enum dsa_tag_protocol old_proto = felix->tag_proto; 469adb3dccfSVladimir Oltean int err; 470adb3dccfSVladimir Oltean 471*e21268efSVladimir Oltean if (proto != DSA_TAG_PROTO_OCELOT && 472*e21268efSVladimir Oltean proto != DSA_TAG_PROTO_OCELOT_8021Q) 473adb3dccfSVladimir Oltean return -EPROTONOSUPPORT; 474adb3dccfSVladimir Oltean 475adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, cpu, old_proto); 476adb3dccfSVladimir Oltean 477adb3dccfSVladimir Oltean err = felix_set_tag_protocol(ds, cpu, proto); 478adb3dccfSVladimir Oltean if (err) { 479adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, cpu, old_proto); 480adb3dccfSVladimir Oltean return err; 481adb3dccfSVladimir Oltean } 482adb3dccfSVladimir Oltean 483adb3dccfSVladimir Oltean felix->tag_proto = proto; 484adb3dccfSVladimir Oltean 485adb3dccfSVladimir Oltean return 0; 486adb3dccfSVladimir Oltean } 487adb3dccfSVladimir Oltean 48856051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 4894d776482SFlorian Fainelli int port, 4904d776482SFlorian Fainelli enum dsa_tag_protocol mp) 49156051948SVladimir Oltean { 492adb3dccfSVladimir Oltean struct ocelot *ocelot = ds->priv; 493adb3dccfSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 494adb3dccfSVladimir Oltean 495adb3dccfSVladimir Oltean return felix->tag_proto; 49656051948SVladimir Oltean } 49756051948SVladimir Oltean 49856051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds, 49956051948SVladimir Oltean unsigned int ageing_time) 50056051948SVladimir Oltean { 50156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 50256051948SVladimir Oltean 50356051948SVladimir Oltean ocelot_set_ageing_time(ocelot, ageing_time); 50456051948SVladimir Oltean 50556051948SVladimir Oltean return 0; 50656051948SVladimir Oltean } 50756051948SVladimir Oltean 50856051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port, 50956051948SVladimir Oltean dsa_fdb_dump_cb_t *cb, void *data) 51056051948SVladimir Oltean { 51156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 51256051948SVladimir Oltean 51356051948SVladimir Oltean return ocelot_fdb_dump(ocelot, port, cb, data); 51456051948SVladimir Oltean } 51556051948SVladimir Oltean 51656051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port, 51756051948SVladimir Oltean const unsigned char *addr, u16 vid) 51856051948SVladimir Oltean { 51956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 52056051948SVladimir Oltean 52187b0f983SVladimir Oltean return ocelot_fdb_add(ocelot, port, addr, vid); 52256051948SVladimir Oltean } 52356051948SVladimir Oltean 52456051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port, 52556051948SVladimir Oltean const unsigned char *addr, u16 vid) 52656051948SVladimir Oltean { 52756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 52856051948SVladimir Oltean 52956051948SVladimir Oltean return ocelot_fdb_del(ocelot, port, addr, vid); 53056051948SVladimir Oltean } 53156051948SVladimir Oltean 532a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port, 533209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 534209edf95SVladimir Oltean { 535209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 536209edf95SVladimir Oltean 537a52b2da7SVladimir Oltean return ocelot_port_mdb_add(ocelot, port, mdb); 538209edf95SVladimir Oltean } 539209edf95SVladimir Oltean 540209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port, 541209edf95SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 542209edf95SVladimir Oltean { 543209edf95SVladimir Oltean struct ocelot *ocelot = ds->priv; 544209edf95SVladimir Oltean 545209edf95SVladimir Oltean return ocelot_port_mdb_del(ocelot, port, mdb); 546209edf95SVladimir Oltean } 547209edf95SVladimir Oltean 54856051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, 54956051948SVladimir Oltean u8 state) 55056051948SVladimir Oltean { 55156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 55256051948SVladimir Oltean 55356051948SVladimir Oltean return ocelot_bridge_stp_state_set(ocelot, port, state); 55456051948SVladimir Oltean } 55556051948SVladimir Oltean 55656051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port, 55756051948SVladimir Oltean struct net_device *br) 55856051948SVladimir Oltean { 55956051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 56056051948SVladimir Oltean 56156051948SVladimir Oltean return ocelot_port_bridge_join(ocelot, port, br); 56256051948SVladimir Oltean } 56356051948SVladimir Oltean 56456051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port, 56556051948SVladimir Oltean struct net_device *br) 56656051948SVladimir Oltean { 56756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 56856051948SVladimir Oltean 56956051948SVladimir Oltean ocelot_port_bridge_leave(ocelot, port, br); 57056051948SVladimir Oltean } 57156051948SVladimir Oltean 57256051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port, 57356051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 57456051948SVladimir Oltean { 5752f0402feSVladimir Oltean struct ocelot *ocelot = ds->priv; 576b7a9e0daSVladimir Oltean u16 flags = vlan->flags; 5772f0402feSVladimir Oltean 5789a720680SVladimir Oltean /* Ocelot switches copy frames as-is to the CPU, so the flags: 5799a720680SVladimir Oltean * egress-untagged or not, pvid or not, make no difference. This 5809a720680SVladimir Oltean * behavior is already better than what DSA just tries to approximate 5819a720680SVladimir Oltean * when it installs the VLAN with the same flags on the CPU port. 5829a720680SVladimir Oltean * Just accept any configuration, and don't let ocelot deny installing 5839a720680SVladimir Oltean * multiple native VLANs on the NPI port, because the switch doesn't 5849a720680SVladimir Oltean * look at the port tag settings towards the NPI interface anyway. 5859a720680SVladimir Oltean */ 5869a720680SVladimir Oltean if (port == ocelot->npi) 5879a720680SVladimir Oltean return 0; 5889a720680SVladimir Oltean 589b7a9e0daSVladimir Oltean return ocelot_vlan_prepare(ocelot, port, vlan->vid, 5902f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 5912f0402feSVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 59256051948SVladimir Oltean } 59356051948SVladimir Oltean 594bae33f2bSVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) 59556051948SVladimir Oltean { 59656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 59756051948SVladimir Oltean 598bae33f2bSVladimir Oltean return ocelot_port_vlan_filtering(ocelot, port, enabled); 59956051948SVladimir Oltean } 60056051948SVladimir Oltean 6011958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port, 60256051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 60356051948SVladimir Oltean { 60456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 605183be6f9SVladimir Oltean u16 flags = vlan->flags; 6061958d581SVladimir Oltean int err; 60756051948SVladimir Oltean 6081958d581SVladimir Oltean err = felix_vlan_prepare(ds, port, vlan); 6091958d581SVladimir Oltean if (err) 6101958d581SVladimir Oltean return err; 6111958d581SVladimir Oltean 6121958d581SVladimir Oltean return ocelot_vlan_add(ocelot, port, vlan->vid, 613183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_PVID, 614183be6f9SVladimir Oltean flags & BRIDGE_VLAN_INFO_UNTAGGED); 61556051948SVladimir Oltean } 61656051948SVladimir Oltean 61756051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port, 61856051948SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 61956051948SVladimir Oltean { 62056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 62156051948SVladimir Oltean 622b7a9e0daSVladimir Oltean return ocelot_vlan_del(ocelot, port, vlan->vid); 62356051948SVladimir Oltean } 62456051948SVladimir Oltean 62556051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port, 62656051948SVladimir Oltean struct phy_device *phy) 62756051948SVladimir Oltean { 62856051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 62956051948SVladimir Oltean 63056051948SVladimir Oltean ocelot_port_enable(ocelot, port, phy); 63156051948SVladimir Oltean 63256051948SVladimir Oltean return 0; 63356051948SVladimir Oltean } 63456051948SVladimir Oltean 63556051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port) 63656051948SVladimir Oltean { 63756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 63856051948SVladimir Oltean 63956051948SVladimir Oltean return ocelot_port_disable(ocelot, port); 64056051948SVladimir Oltean } 64156051948SVladimir Oltean 642bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port, 643bdeced75SVladimir Oltean unsigned long *supported, 644bdeced75SVladimir Oltean struct phylink_link_state *state) 645bdeced75SVladimir Oltean { 646bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 647375e1314SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 648bdeced75SVladimir Oltean 649375e1314SVladimir Oltean if (felix->info->phylink_validate) 650375e1314SVladimir Oltean felix->info->phylink_validate(ocelot, port, supported, state); 651bdeced75SVladimir Oltean } 652bdeced75SVladimir Oltean 653bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port, 654bdeced75SVladimir Oltean unsigned int link_an_mode, 655bdeced75SVladimir Oltean const struct phylink_link_state *state) 656bdeced75SVladimir Oltean { 657bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 658bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 659588d0550SIoana Ciornei struct dsa_port *dp = dsa_to_port(ds, port); 660bdeced75SVladimir Oltean 661588d0550SIoana Ciornei if (felix->pcs[port]) 662588d0550SIoana Ciornei phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs); 663bdeced75SVladimir Oltean } 664bdeced75SVladimir Oltean 665bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, 666bdeced75SVladimir Oltean unsigned int link_an_mode, 667bdeced75SVladimir Oltean phy_interface_t interface) 668bdeced75SVladimir Oltean { 669bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 670bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 671bdeced75SVladimir Oltean 672bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); 673886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); 674bdeced75SVladimir Oltean } 675bdeced75SVladimir Oltean 676bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, 677bdeced75SVladimir Oltean unsigned int link_an_mode, 678bdeced75SVladimir Oltean phy_interface_t interface, 6795b502a7bSRussell King struct phy_device *phydev, 6805b502a7bSRussell King int speed, int duplex, 6815b502a7bSRussell King bool tx_pause, bool rx_pause) 682bdeced75SVladimir Oltean { 683bdeced75SVladimir Oltean struct ocelot *ocelot = ds->priv; 684bdeced75SVladimir Oltean struct ocelot_port *ocelot_port = ocelot->ports[port]; 6857e14a2dcSVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 6867e14a2dcSVladimir Oltean u32 mac_fc_cfg; 687bdeced75SVladimir Oltean 6887e14a2dcSVladimir Oltean /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and 6897e14a2dcSVladimir Oltean * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is 6907e14a2dcSVladimir Oltean * integrated is that the MAC speed is fixed and it's the PCS who is 6917e14a2dcSVladimir Oltean * performing the rate adaptation, so we have to write "1000Mbps" into 6927e14a2dcSVladimir Oltean * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default 6937e14a2dcSVladimir Oltean * value). 6947e14a2dcSVladimir Oltean */ 6957e14a2dcSVladimir Oltean ocelot_port_writel(ocelot_port, 6967e14a2dcSVladimir Oltean DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), 6977e14a2dcSVladimir Oltean DEV_CLOCK_CFG); 6987e14a2dcSVladimir Oltean 6997e14a2dcSVladimir Oltean switch (speed) { 7007e14a2dcSVladimir Oltean case SPEED_10: 7017e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); 7027e14a2dcSVladimir Oltean break; 7037e14a2dcSVladimir Oltean case SPEED_100: 7047e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); 7057e14a2dcSVladimir Oltean break; 7067e14a2dcSVladimir Oltean case SPEED_1000: 7077e14a2dcSVladimir Oltean case SPEED_2500: 7087e14a2dcSVladimir Oltean mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); 7097e14a2dcSVladimir Oltean break; 7107e14a2dcSVladimir Oltean default: 7117e14a2dcSVladimir Oltean dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", 7127e14a2dcSVladimir Oltean port, speed); 7137e14a2dcSVladimir Oltean return; 7147e14a2dcSVladimir Oltean } 7157e14a2dcSVladimir Oltean 7167e14a2dcSVladimir Oltean /* handle Rx pause in all cases, with 2500base-X this is used for rate 7177e14a2dcSVladimir Oltean * adaptation. 7187e14a2dcSVladimir Oltean */ 7197e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; 7207e14a2dcSVladimir Oltean 7217e14a2dcSVladimir Oltean if (tx_pause) 7227e14a2dcSVladimir Oltean mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | 7237e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | 7247e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | 7257e14a2dcSVladimir Oltean SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; 7267e14a2dcSVladimir Oltean 7277e14a2dcSVladimir Oltean /* Flow control. Link speed is only used here to evaluate the time 7287e14a2dcSVladimir Oltean * specification in incoming pause frames. 7297e14a2dcSVladimir Oltean */ 7307e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); 7317e14a2dcSVladimir Oltean 7327e14a2dcSVladimir Oltean ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); 7337e14a2dcSVladimir Oltean 7347e14a2dcSVladimir Oltean /* Undo the effects of felix_phylink_mac_link_down: 7357e14a2dcSVladimir Oltean * enable MAC module 7367e14a2dcSVladimir Oltean */ 737bdeced75SVladimir Oltean ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | 738bdeced75SVladimir Oltean DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); 739bdeced75SVladimir Oltean 740bdeced75SVladimir Oltean /* Enable receiving frames on the port, and activate auto-learning of 741bdeced75SVladimir Oltean * MAC addresses. 742bdeced75SVladimir Oltean */ 743bdeced75SVladimir Oltean ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | 744bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_RECV_ENA | 745bdeced75SVladimir Oltean ANA_PORT_PORT_CFG_PORTID_VAL(port), 746bdeced75SVladimir Oltean ANA_PORT_PORT_CFG, port); 747bdeced75SVladimir Oltean 748bdeced75SVladimir Oltean /* Core: Enable port for frame transfer */ 749886e1387SVladimir Oltean ocelot_fields_write(ocelot, port, 750886e1387SVladimir Oltean QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); 7517e14a2dcSVladimir Oltean 7527e14a2dcSVladimir Oltean if (felix->info->port_sched_speed_set) 7537e14a2dcSVladimir Oltean felix->info->port_sched_speed_set(ocelot, port, speed); 754bdeced75SVladimir Oltean } 755bdeced75SVladimir Oltean 756bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port) 757bd2b3161SXiaoliang Yang { 758bd2b3161SXiaoliang Yang int i; 759bd2b3161SXiaoliang Yang 760bd2b3161SXiaoliang Yang ocelot_rmw_gix(ocelot, 761bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 762bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG_QOS_PCP_ENA, 763bd2b3161SXiaoliang Yang ANA_PORT_QOS_CFG, 764bd2b3161SXiaoliang Yang port); 765bd2b3161SXiaoliang Yang 76670d39a6eSVladimir Oltean for (i = 0; i < OCELOT_NUM_TC * 2; i++) { 767bd2b3161SXiaoliang Yang ocelot_rmw_ix(ocelot, 768bd2b3161SXiaoliang Yang (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | 769bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), 770bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | 771bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, 772bd2b3161SXiaoliang Yang ANA_PORT_PCP_DEI_MAP, 773bd2b3161SXiaoliang Yang port, i); 774bd2b3161SXiaoliang Yang } 775bd2b3161SXiaoliang Yang } 776bd2b3161SXiaoliang Yang 77756051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port, 77856051948SVladimir Oltean u32 stringset, u8 *data) 77956051948SVladimir Oltean { 78056051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 78156051948SVladimir Oltean 78256051948SVladimir Oltean return ocelot_get_strings(ocelot, port, stringset, data); 78356051948SVladimir Oltean } 78456051948SVladimir Oltean 78556051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 78656051948SVladimir Oltean { 78756051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 78856051948SVladimir Oltean 78956051948SVladimir Oltean ocelot_get_ethtool_stats(ocelot, port, data); 79056051948SVladimir Oltean } 79156051948SVladimir Oltean 79256051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) 79356051948SVladimir Oltean { 79456051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 79556051948SVladimir Oltean 79656051948SVladimir Oltean return ocelot_get_sset_count(ocelot, port, sset); 79756051948SVladimir Oltean } 79856051948SVladimir Oltean 79956051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port, 80056051948SVladimir Oltean struct ethtool_ts_info *info) 80156051948SVladimir Oltean { 80256051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 80356051948SVladimir Oltean 80456051948SVladimir Oltean return ocelot_get_ts_info(ocelot, port, info); 80556051948SVladimir Oltean } 80656051948SVladimir Oltean 807bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix, 808bdeced75SVladimir Oltean struct device_node *ports_node, 809bdeced75SVladimir Oltean phy_interface_t *port_phy_modes) 810bdeced75SVladimir Oltean { 811bdeced75SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 812bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 813bdeced75SVladimir Oltean struct device_node *child; 814bdeced75SVladimir Oltean 81537fe45adSVladimir Oltean for_each_available_child_of_node(ports_node, child) { 816bdeced75SVladimir Oltean phy_interface_t phy_mode; 817bdeced75SVladimir Oltean u32 port; 818bdeced75SVladimir Oltean int err; 819bdeced75SVladimir Oltean 820bdeced75SVladimir Oltean /* Get switch port number from DT */ 821bdeced75SVladimir Oltean if (of_property_read_u32(child, "reg", &port) < 0) { 822bdeced75SVladimir Oltean dev_err(dev, "Port number not defined in device tree " 823bdeced75SVladimir Oltean "(property \"reg\")\n"); 824bdeced75SVladimir Oltean of_node_put(child); 825bdeced75SVladimir Oltean return -ENODEV; 826bdeced75SVladimir Oltean } 827bdeced75SVladimir Oltean 828bdeced75SVladimir Oltean /* Get PHY mode from DT */ 829bdeced75SVladimir Oltean err = of_get_phy_mode(child, &phy_mode); 830bdeced75SVladimir Oltean if (err) { 831bdeced75SVladimir Oltean dev_err(dev, "Failed to read phy-mode or " 832bdeced75SVladimir Oltean "phy-interface-type property for port %d\n", 833bdeced75SVladimir Oltean port); 834bdeced75SVladimir Oltean of_node_put(child); 835bdeced75SVladimir Oltean return -ENODEV; 836bdeced75SVladimir Oltean } 837bdeced75SVladimir Oltean 838bdeced75SVladimir Oltean err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); 839bdeced75SVladimir Oltean if (err < 0) { 840bdeced75SVladimir Oltean dev_err(dev, "Unsupported PHY mode %s on port %d\n", 841bdeced75SVladimir Oltean phy_modes(phy_mode), port); 84259ebb430SSumera Priyadarsini of_node_put(child); 843bdeced75SVladimir Oltean return err; 844bdeced75SVladimir Oltean } 845bdeced75SVladimir Oltean 846bdeced75SVladimir Oltean port_phy_modes[port] = phy_mode; 847bdeced75SVladimir Oltean } 848bdeced75SVladimir Oltean 849bdeced75SVladimir Oltean return 0; 850bdeced75SVladimir Oltean } 851bdeced75SVladimir Oltean 852bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) 853bdeced75SVladimir Oltean { 854bdeced75SVladimir Oltean struct device *dev = felix->ocelot.dev; 855bdeced75SVladimir Oltean struct device_node *switch_node; 856bdeced75SVladimir Oltean struct device_node *ports_node; 857bdeced75SVladimir Oltean int err; 858bdeced75SVladimir Oltean 859bdeced75SVladimir Oltean switch_node = dev->of_node; 860bdeced75SVladimir Oltean 861bdeced75SVladimir Oltean ports_node = of_get_child_by_name(switch_node, "ports"); 862bdeced75SVladimir Oltean if (!ports_node) { 863bdeced75SVladimir Oltean dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); 864bdeced75SVladimir Oltean return -ENODEV; 865bdeced75SVladimir Oltean } 866bdeced75SVladimir Oltean 867bdeced75SVladimir Oltean err = felix_parse_ports_node(felix, ports_node, port_phy_modes); 868bdeced75SVladimir Oltean of_node_put(ports_node); 869bdeced75SVladimir Oltean 870bdeced75SVladimir Oltean return err; 871bdeced75SVladimir Oltean } 872bdeced75SVladimir Oltean 87356051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports) 87456051948SVladimir Oltean { 87556051948SVladimir Oltean struct ocelot *ocelot = &felix->ocelot; 876bdeced75SVladimir Oltean phy_interface_t *port_phy_modes; 877b4024c9eSClaudiu Manoil struct resource res; 87856051948SVladimir Oltean int port, i, err; 87956051948SVladimir Oltean 88056051948SVladimir Oltean ocelot->num_phys_ports = num_phys_ports; 88156051948SVladimir Oltean ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, 88256051948SVladimir Oltean sizeof(struct ocelot_port *), GFP_KERNEL); 88356051948SVladimir Oltean if (!ocelot->ports) 88456051948SVladimir Oltean return -ENOMEM; 88556051948SVladimir Oltean 88656051948SVladimir Oltean ocelot->map = felix->info->map; 88756051948SVladimir Oltean ocelot->stats_layout = felix->info->stats_layout; 88856051948SVladimir Oltean ocelot->num_stats = felix->info->num_stats; 88921ce7f3eSVladimir Oltean ocelot->num_mact_rows = felix->info->num_mact_rows; 89007d985eeSVladimir Oltean ocelot->vcap = felix->info->vcap; 89156051948SVladimir Oltean ocelot->ops = felix->info->ops; 892cacea62fSVladimir Oltean ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; 893cacea62fSVladimir Oltean ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; 894f59fd9caSVladimir Oltean ocelot->devlink = felix->ds->devlink; 89556051948SVladimir Oltean 896bdeced75SVladimir Oltean port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), 897bdeced75SVladimir Oltean GFP_KERNEL); 898bdeced75SVladimir Oltean if (!port_phy_modes) 899bdeced75SVladimir Oltean return -ENOMEM; 900bdeced75SVladimir Oltean 901bdeced75SVladimir Oltean err = felix_parse_dt(felix, port_phy_modes); 902bdeced75SVladimir Oltean if (err) { 903bdeced75SVladimir Oltean kfree(port_phy_modes); 904bdeced75SVladimir Oltean return err; 905bdeced75SVladimir Oltean } 906bdeced75SVladimir Oltean 90756051948SVladimir Oltean for (i = 0; i < TARGET_MAX; i++) { 90856051948SVladimir Oltean struct regmap *target; 90956051948SVladimir Oltean 91056051948SVladimir Oltean if (!felix->info->target_io_res[i].name) 91156051948SVladimir Oltean continue; 91256051948SVladimir Oltean 913b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); 914b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 915375e1314SVladimir Oltean res.start += felix->switch_base; 916375e1314SVladimir Oltean res.end += felix->switch_base; 91756051948SVladimir Oltean 918b4024c9eSClaudiu Manoil target = ocelot_regmap_init(ocelot, &res); 91956051948SVladimir Oltean if (IS_ERR(target)) { 92056051948SVladimir Oltean dev_err(ocelot->dev, 92156051948SVladimir Oltean "Failed to map device memory space\n"); 922bdeced75SVladimir Oltean kfree(port_phy_modes); 92356051948SVladimir Oltean return PTR_ERR(target); 92456051948SVladimir Oltean } 92556051948SVladimir Oltean 92656051948SVladimir Oltean ocelot->targets[i] = target; 92756051948SVladimir Oltean } 92856051948SVladimir Oltean 92956051948SVladimir Oltean err = ocelot_regfields_init(ocelot, felix->info->regfields); 93056051948SVladimir Oltean if (err) { 93156051948SVladimir Oltean dev_err(ocelot->dev, "failed to init reg fields map\n"); 932bdeced75SVladimir Oltean kfree(port_phy_modes); 93356051948SVladimir Oltean return err; 93456051948SVladimir Oltean } 93556051948SVladimir Oltean 93656051948SVladimir Oltean for (port = 0; port < num_phys_ports; port++) { 93756051948SVladimir Oltean struct ocelot_port *ocelot_port; 93891c724cfSVladimir Oltean struct regmap *target; 93967c24049SVladimir Oltean u8 *template; 94056051948SVladimir Oltean 94156051948SVladimir Oltean ocelot_port = devm_kzalloc(ocelot->dev, 94256051948SVladimir Oltean sizeof(struct ocelot_port), 94356051948SVladimir Oltean GFP_KERNEL); 94456051948SVladimir Oltean if (!ocelot_port) { 94556051948SVladimir Oltean dev_err(ocelot->dev, 94656051948SVladimir Oltean "failed to allocate port memory\n"); 947bdeced75SVladimir Oltean kfree(port_phy_modes); 94856051948SVladimir Oltean return -ENOMEM; 94956051948SVladimir Oltean } 95056051948SVladimir Oltean 951b4024c9eSClaudiu Manoil memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); 952b4024c9eSClaudiu Manoil res.flags = IORESOURCE_MEM; 953375e1314SVladimir Oltean res.start += felix->switch_base; 954375e1314SVladimir Oltean res.end += felix->switch_base; 95556051948SVladimir Oltean 95691c724cfSVladimir Oltean target = ocelot_regmap_init(ocelot, &res); 95791c724cfSVladimir Oltean if (IS_ERR(target)) { 95856051948SVladimir Oltean dev_err(ocelot->dev, 95991c724cfSVladimir Oltean "Failed to map memory space for port %d\n", 96091c724cfSVladimir Oltean port); 961bdeced75SVladimir Oltean kfree(port_phy_modes); 96291c724cfSVladimir Oltean return PTR_ERR(target); 96356051948SVladimir Oltean } 96456051948SVladimir Oltean 9655124197cSVladimir Oltean template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN, 96667c24049SVladimir Oltean GFP_KERNEL); 96767c24049SVladimir Oltean if (!template) { 96867c24049SVladimir Oltean dev_err(ocelot->dev, 96967c24049SVladimir Oltean "Failed to allocate memory for DSA tag\n"); 97067c24049SVladimir Oltean kfree(port_phy_modes); 97167c24049SVladimir Oltean return -ENOMEM; 97267c24049SVladimir Oltean } 97367c24049SVladimir Oltean 974bdeced75SVladimir Oltean ocelot_port->phy_mode = port_phy_modes[port]; 97556051948SVladimir Oltean ocelot_port->ocelot = ocelot; 97691c724cfSVladimir Oltean ocelot_port->target = target; 97767c24049SVladimir Oltean ocelot_port->xmit_template = template; 97856051948SVladimir Oltean ocelot->ports[port] = ocelot_port; 97967c24049SVladimir Oltean 98067c24049SVladimir Oltean felix->info->xmit_template_populate(ocelot, port); 98156051948SVladimir Oltean } 98256051948SVladimir Oltean 983bdeced75SVladimir Oltean kfree(port_phy_modes); 984bdeced75SVladimir Oltean 985bdeced75SVladimir Oltean if (felix->info->mdio_bus_alloc) { 986bdeced75SVladimir Oltean err = felix->info->mdio_bus_alloc(ocelot); 987bdeced75SVladimir Oltean if (err < 0) 988bdeced75SVladimir Oltean return err; 989bdeced75SVladimir Oltean } 990bdeced75SVladimir Oltean 99156051948SVladimir Oltean return 0; 99256051948SVladimir Oltean } 99356051948SVladimir Oltean 99456051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with 99556051948SVladimir Oltean * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing 99656051948SVladimir Oltean * us to allocate structures twice (leak memory) and map PCI memory twice 99756051948SVladimir Oltean * (which will not work). 99856051948SVladimir Oltean */ 99956051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds) 100056051948SVladimir Oltean { 100156051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 100256051948SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 100356051948SVladimir Oltean int port, err; 100456051948SVladimir Oltean 100556051948SVladimir Oltean err = felix_init_structs(felix, ds->num_ports); 100656051948SVladimir Oltean if (err) 100756051948SVladimir Oltean return err; 100856051948SVladimir Oltean 1009d1cc0e93SVladimir Oltean err = ocelot_init(ocelot); 1010d1cc0e93SVladimir Oltean if (err) 1011d1cc0e93SVladimir Oltean return err; 1012d1cc0e93SVladimir Oltean 10132b49d128SYangbo Lu if (ocelot->ptp) { 10142ac7c6c5SVladimir Oltean err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); 10152b49d128SYangbo Lu if (err) { 10162b49d128SYangbo Lu dev_err(ocelot->dev, 10172b49d128SYangbo Lu "Timestamp initialization failed\n"); 10182b49d128SYangbo Lu ocelot->ptp = 0; 10192b49d128SYangbo Lu } 10202b49d128SYangbo Lu } 102156051948SVladimir Oltean 102256051948SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1023adb3dccfSVladimir Oltean if (dsa_is_unused_port(ds, port)) 1024adb3dccfSVladimir Oltean continue; 102556051948SVladimir Oltean 1026adb3dccfSVladimir Oltean ocelot_init_port(ocelot, port); 1027bd2b3161SXiaoliang Yang 1028bd2b3161SXiaoliang Yang /* Set the default QoS Classification based on PCP and DEI 1029bd2b3161SXiaoliang Yang * bits of vlan tag. 1030bd2b3161SXiaoliang Yang */ 1031bd2b3161SXiaoliang Yang felix_port_qos_map_init(ocelot, port); 103256051948SVladimir Oltean } 103356051948SVladimir Oltean 1034f59fd9caSVladimir Oltean err = ocelot_devlink_sb_register(ocelot); 1035f59fd9caSVladimir Oltean if (err) 1036f59fd9caSVladimir Oltean return err; 1037f59fd9caSVladimir Oltean 1038adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1039adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 1040adb3dccfSVladimir Oltean continue; 1041adb3dccfSVladimir Oltean 1042adb3dccfSVladimir Oltean /* The initial tag protocol is NPI which always returns 0, so 1043adb3dccfSVladimir Oltean * there's no real point in checking for errors. 10441cf3299bSVladimir Oltean */ 1045adb3dccfSVladimir Oltean felix_set_tag_protocol(ds, port, felix->tag_proto); 1046adb3dccfSVladimir Oltean } 10471cf3299bSVladimir Oltean 10480b912fc9SVladimir Oltean ds->mtu_enforcement_ingress = true; 1049c54913c1SVladimir Oltean ds->assisted_learning_on_cpu_port = true; 1050bdeced75SVladimir Oltean 105156051948SVladimir Oltean return 0; 105256051948SVladimir Oltean } 105356051948SVladimir Oltean 105456051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds) 105556051948SVladimir Oltean { 105656051948SVladimir Oltean struct ocelot *ocelot = ds->priv; 1057bdeced75SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1058e5fb512dSVladimir Oltean int port; 1059bdeced75SVladimir Oltean 1060adb3dccfSVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 1061adb3dccfSVladimir Oltean if (!dsa_is_cpu_port(ds, port)) 1062adb3dccfSVladimir Oltean continue; 1063adb3dccfSVladimir Oltean 1064adb3dccfSVladimir Oltean felix_del_tag_protocol(ds, port, felix->tag_proto); 1065adb3dccfSVladimir Oltean } 1066adb3dccfSVladimir Oltean 1067f59fd9caSVladimir Oltean ocelot_devlink_sb_unregister(ocelot); 1068d19741b0SVladimir Oltean ocelot_deinit_timestamp(ocelot); 1069d19741b0SVladimir Oltean ocelot_deinit(ocelot); 107056051948SVladimir Oltean 1071e5fb512dSVladimir Oltean for (port = 0; port < ocelot->num_phys_ports; port++) 1072e5fb512dSVladimir Oltean ocelot_deinit_port(ocelot, port); 1073d19741b0SVladimir Oltean 1074d19741b0SVladimir Oltean if (felix->info->mdio_bus_free) 1075d19741b0SVladimir Oltean felix->info->mdio_bus_free(ocelot); 107656051948SVladimir Oltean } 107756051948SVladimir Oltean 1078c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port, 1079c0bcf537SYangbo Lu struct ifreq *ifr) 1080c0bcf537SYangbo Lu { 1081c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1082c0bcf537SYangbo Lu 1083c0bcf537SYangbo Lu return ocelot_hwstamp_get(ocelot, port, ifr); 1084c0bcf537SYangbo Lu } 1085c0bcf537SYangbo Lu 1086c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port, 1087c0bcf537SYangbo Lu struct ifreq *ifr) 1088c0bcf537SYangbo Lu { 1089c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1090c0bcf537SYangbo Lu 1091c0bcf537SYangbo Lu return ocelot_hwstamp_set(ocelot, port, ifr); 1092c0bcf537SYangbo Lu } 1093c0bcf537SYangbo Lu 1094c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port, 1095c0bcf537SYangbo Lu struct sk_buff *skb, unsigned int type) 1096c0bcf537SYangbo Lu { 1097c0bcf537SYangbo Lu struct skb_shared_hwtstamps *shhwtstamps; 1098c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1099c0bcf537SYangbo Lu u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; 1100c0bcf537SYangbo Lu u32 tstamp_lo, tstamp_hi; 1101c0bcf537SYangbo Lu struct timespec64 ts; 1102c0bcf537SYangbo Lu u64 tstamp, val; 1103c0bcf537SYangbo Lu 1104c0bcf537SYangbo Lu ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); 1105c0bcf537SYangbo Lu tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); 1106c0bcf537SYangbo Lu 1107c0bcf537SYangbo Lu packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); 1108c0bcf537SYangbo Lu tstamp_lo = (u32)val; 1109c0bcf537SYangbo Lu 1110c0bcf537SYangbo Lu tstamp_hi = tstamp >> 32; 1111c0bcf537SYangbo Lu if ((tstamp & 0xffffffff) < tstamp_lo) 1112c0bcf537SYangbo Lu tstamp_hi--; 1113c0bcf537SYangbo Lu 1114c0bcf537SYangbo Lu tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; 1115c0bcf537SYangbo Lu 1116c0bcf537SYangbo Lu shhwtstamps = skb_hwtstamps(skb); 1117c0bcf537SYangbo Lu memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 1118c0bcf537SYangbo Lu shhwtstamps->hwtstamp = tstamp; 1119c0bcf537SYangbo Lu return false; 1120c0bcf537SYangbo Lu } 1121c0bcf537SYangbo Lu 11223243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port, 1123c0bcf537SYangbo Lu struct sk_buff *clone, unsigned int type) 1124c0bcf537SYangbo Lu { 1125c0bcf537SYangbo Lu struct ocelot *ocelot = ds->priv; 1126c0bcf537SYangbo Lu struct ocelot_port *ocelot_port = ocelot->ports[port]; 1127c0bcf537SYangbo Lu 1128e2f9a8feSVladimir Oltean if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) && 1129e2f9a8feSVladimir Oltean ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 1130e2f9a8feSVladimir Oltean ocelot_port_add_txtstamp_skb(ocelot, port, clone); 1131c0bcf537SYangbo Lu return true; 1132e2f9a8feSVladimir Oltean } 1133c0bcf537SYangbo Lu 1134c0bcf537SYangbo Lu return false; 1135c0bcf537SYangbo Lu } 1136c0bcf537SYangbo Lu 11370b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 11380b912fc9SVladimir Oltean { 11390b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 11400b912fc9SVladimir Oltean 11410b912fc9SVladimir Oltean ocelot_port_set_maxlen(ocelot, port, new_mtu); 11420b912fc9SVladimir Oltean 11430b912fc9SVladimir Oltean return 0; 11440b912fc9SVladimir Oltean } 11450b912fc9SVladimir Oltean 11460b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port) 11470b912fc9SVladimir Oltean { 11480b912fc9SVladimir Oltean struct ocelot *ocelot = ds->priv; 11490b912fc9SVladimir Oltean 11500b912fc9SVladimir Oltean return ocelot_get_max_mtu(ocelot, port); 11510b912fc9SVladimir Oltean } 11520b912fc9SVladimir Oltean 115307d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port, 115407d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 115507d985eeSVladimir Oltean { 115607d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 115707d985eeSVladimir Oltean 115807d985eeSVladimir Oltean return ocelot_cls_flower_replace(ocelot, port, cls, ingress); 115907d985eeSVladimir Oltean } 116007d985eeSVladimir Oltean 116107d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port, 116207d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 116307d985eeSVladimir Oltean { 116407d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 116507d985eeSVladimir Oltean 116607d985eeSVladimir Oltean return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); 116707d985eeSVladimir Oltean } 116807d985eeSVladimir Oltean 116907d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port, 117007d985eeSVladimir Oltean struct flow_cls_offload *cls, bool ingress) 117107d985eeSVladimir Oltean { 117207d985eeSVladimir Oltean struct ocelot *ocelot = ds->priv; 117307d985eeSVladimir Oltean 117407d985eeSVladimir Oltean return ocelot_cls_flower_stats(ocelot, port, cls, ingress); 117507d985eeSVladimir Oltean } 117607d985eeSVladimir Oltean 1177fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port, 1178fc411eaaSVladimir Oltean struct dsa_mall_policer_tc_entry *policer) 1179fc411eaaSVladimir Oltean { 1180fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 1181fc411eaaSVladimir Oltean struct ocelot_policer pol = { 1182fc411eaaSVladimir Oltean .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, 11835f035af7SPo Liu .burst = policer->burst, 1184fc411eaaSVladimir Oltean }; 1185fc411eaaSVladimir Oltean 1186fc411eaaSVladimir Oltean return ocelot_port_policer_add(ocelot, port, &pol); 1187fc411eaaSVladimir Oltean } 1188fc411eaaSVladimir Oltean 1189fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port) 1190fc411eaaSVladimir Oltean { 1191fc411eaaSVladimir Oltean struct ocelot *ocelot = ds->priv; 1192fc411eaaSVladimir Oltean 1193fc411eaaSVladimir Oltean ocelot_port_policer_del(ocelot, port); 1194fc411eaaSVladimir Oltean } 1195fc411eaaSVladimir Oltean 1196de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port, 1197de143c0eSXiaoliang Yang enum tc_setup_type type, 1198de143c0eSXiaoliang Yang void *type_data) 1199de143c0eSXiaoliang Yang { 1200de143c0eSXiaoliang Yang struct ocelot *ocelot = ds->priv; 1201de143c0eSXiaoliang Yang struct felix *felix = ocelot_to_felix(ocelot); 1202de143c0eSXiaoliang Yang 1203de143c0eSXiaoliang Yang if (felix->info->port_setup_tc) 1204de143c0eSXiaoliang Yang return felix->info->port_setup_tc(ds, port, type, type_data); 1205de143c0eSXiaoliang Yang else 1206de143c0eSXiaoliang Yang return -EOPNOTSUPP; 1207de143c0eSXiaoliang Yang } 1208de143c0eSXiaoliang Yang 1209f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index, 1210f59fd9caSVladimir Oltean u16 pool_index, 1211f59fd9caSVladimir Oltean struct devlink_sb_pool_info *pool_info) 1212f59fd9caSVladimir Oltean { 1213f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1214f59fd9caSVladimir Oltean 1215f59fd9caSVladimir Oltean return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info); 1216f59fd9caSVladimir Oltean } 1217f59fd9caSVladimir Oltean 1218f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index, 1219f59fd9caSVladimir Oltean u16 pool_index, u32 size, 1220f59fd9caSVladimir Oltean enum devlink_sb_threshold_type threshold_type, 1221f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 1222f59fd9caSVladimir Oltean { 1223f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1224f59fd9caSVladimir Oltean 1225f59fd9caSVladimir Oltean return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size, 1226f59fd9caSVladimir Oltean threshold_type, extack); 1227f59fd9caSVladimir Oltean } 1228f59fd9caSVladimir Oltean 1229f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port, 1230f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1231f59fd9caSVladimir Oltean u32 *p_threshold) 1232f59fd9caSVladimir Oltean { 1233f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1234f59fd9caSVladimir Oltean 1235f59fd9caSVladimir Oltean return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index, 1236f59fd9caSVladimir Oltean p_threshold); 1237f59fd9caSVladimir Oltean } 1238f59fd9caSVladimir Oltean 1239f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port, 1240f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1241f59fd9caSVladimir Oltean u32 threshold, struct netlink_ext_ack *extack) 1242f59fd9caSVladimir Oltean { 1243f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1244f59fd9caSVladimir Oltean 1245f59fd9caSVladimir Oltean return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index, 1246f59fd9caSVladimir Oltean threshold, extack); 1247f59fd9caSVladimir Oltean } 1248f59fd9caSVladimir Oltean 1249f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port, 1250f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1251f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1252f59fd9caSVladimir Oltean u16 *p_pool_index, u32 *p_threshold) 1253f59fd9caSVladimir Oltean { 1254f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1255f59fd9caSVladimir Oltean 1256f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index, 1257f59fd9caSVladimir Oltean pool_type, p_pool_index, 1258f59fd9caSVladimir Oltean p_threshold); 1259f59fd9caSVladimir Oltean } 1260f59fd9caSVladimir Oltean 1261f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port, 1262f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1263f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1264f59fd9caSVladimir Oltean u16 pool_index, u32 threshold, 1265f59fd9caSVladimir Oltean struct netlink_ext_ack *extack) 1266f59fd9caSVladimir Oltean { 1267f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1268f59fd9caSVladimir Oltean 1269f59fd9caSVladimir Oltean return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index, 1270f59fd9caSVladimir Oltean pool_type, pool_index, threshold, 1271f59fd9caSVladimir Oltean extack); 1272f59fd9caSVladimir Oltean } 1273f59fd9caSVladimir Oltean 1274f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds, 1275f59fd9caSVladimir Oltean unsigned int sb_index) 1276f59fd9caSVladimir Oltean { 1277f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1278f59fd9caSVladimir Oltean 1279f59fd9caSVladimir Oltean return ocelot_sb_occ_snapshot(ocelot, sb_index); 1280f59fd9caSVladimir Oltean } 1281f59fd9caSVladimir Oltean 1282f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds, 1283f59fd9caSVladimir Oltean unsigned int sb_index) 1284f59fd9caSVladimir Oltean { 1285f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1286f59fd9caSVladimir Oltean 1287f59fd9caSVladimir Oltean return ocelot_sb_occ_max_clear(ocelot, sb_index); 1288f59fd9caSVladimir Oltean } 1289f59fd9caSVladimir Oltean 1290f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port, 1291f59fd9caSVladimir Oltean unsigned int sb_index, u16 pool_index, 1292f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 1293f59fd9caSVladimir Oltean { 1294f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1295f59fd9caSVladimir Oltean 1296f59fd9caSVladimir Oltean return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index, 1297f59fd9caSVladimir Oltean p_cur, p_max); 1298f59fd9caSVladimir Oltean } 1299f59fd9caSVladimir Oltean 1300f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port, 1301f59fd9caSVladimir Oltean unsigned int sb_index, u16 tc_index, 1302f59fd9caSVladimir Oltean enum devlink_sb_pool_type pool_type, 1303f59fd9caSVladimir Oltean u32 *p_cur, u32 *p_max) 1304f59fd9caSVladimir Oltean { 1305f59fd9caSVladimir Oltean struct ocelot *ocelot = ds->priv; 1306f59fd9caSVladimir Oltean 1307f59fd9caSVladimir Oltean return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index, 1308f59fd9caSVladimir Oltean pool_type, p_cur, p_max); 1309f59fd9caSVladimir Oltean } 1310f59fd9caSVladimir Oltean 1311375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = { 131256051948SVladimir Oltean .get_tag_protocol = felix_get_tag_protocol, 1313adb3dccfSVladimir Oltean .change_tag_protocol = felix_change_tag_protocol, 131456051948SVladimir Oltean .setup = felix_setup, 131556051948SVladimir Oltean .teardown = felix_teardown, 131656051948SVladimir Oltean .set_ageing_time = felix_set_ageing_time, 131756051948SVladimir Oltean .get_strings = felix_get_strings, 131856051948SVladimir Oltean .get_ethtool_stats = felix_get_ethtool_stats, 131956051948SVladimir Oltean .get_sset_count = felix_get_sset_count, 132056051948SVladimir Oltean .get_ts_info = felix_get_ts_info, 1321bdeced75SVladimir Oltean .phylink_validate = felix_phylink_validate, 1322bdeced75SVladimir Oltean .phylink_mac_config = felix_phylink_mac_config, 1323bdeced75SVladimir Oltean .phylink_mac_link_down = felix_phylink_mac_link_down, 1324bdeced75SVladimir Oltean .phylink_mac_link_up = felix_phylink_mac_link_up, 132556051948SVladimir Oltean .port_enable = felix_port_enable, 132656051948SVladimir Oltean .port_disable = felix_port_disable, 132756051948SVladimir Oltean .port_fdb_dump = felix_fdb_dump, 132856051948SVladimir Oltean .port_fdb_add = felix_fdb_add, 132956051948SVladimir Oltean .port_fdb_del = felix_fdb_del, 1330209edf95SVladimir Oltean .port_mdb_add = felix_mdb_add, 1331209edf95SVladimir Oltean .port_mdb_del = felix_mdb_del, 133256051948SVladimir Oltean .port_bridge_join = felix_bridge_join, 133356051948SVladimir Oltean .port_bridge_leave = felix_bridge_leave, 133456051948SVladimir Oltean .port_stp_state_set = felix_bridge_stp_state_set, 133556051948SVladimir Oltean .port_vlan_filtering = felix_vlan_filtering, 133656051948SVladimir Oltean .port_vlan_add = felix_vlan_add, 133756051948SVladimir Oltean .port_vlan_del = felix_vlan_del, 1338c0bcf537SYangbo Lu .port_hwtstamp_get = felix_hwtstamp_get, 1339c0bcf537SYangbo Lu .port_hwtstamp_set = felix_hwtstamp_set, 1340c0bcf537SYangbo Lu .port_rxtstamp = felix_rxtstamp, 1341c0bcf537SYangbo Lu .port_txtstamp = felix_txtstamp, 13420b912fc9SVladimir Oltean .port_change_mtu = felix_change_mtu, 13430b912fc9SVladimir Oltean .port_max_mtu = felix_get_max_mtu, 1344fc411eaaSVladimir Oltean .port_policer_add = felix_port_policer_add, 1345fc411eaaSVladimir Oltean .port_policer_del = felix_port_policer_del, 134607d985eeSVladimir Oltean .cls_flower_add = felix_cls_flower_add, 134707d985eeSVladimir Oltean .cls_flower_del = felix_cls_flower_del, 134807d985eeSVladimir Oltean .cls_flower_stats = felix_cls_flower_stats, 1349de143c0eSXiaoliang Yang .port_setup_tc = felix_port_setup_tc, 1350f59fd9caSVladimir Oltean .devlink_sb_pool_get = felix_sb_pool_get, 1351f59fd9caSVladimir Oltean .devlink_sb_pool_set = felix_sb_pool_set, 1352f59fd9caSVladimir Oltean .devlink_sb_port_pool_get = felix_sb_port_pool_get, 1353f59fd9caSVladimir Oltean .devlink_sb_port_pool_set = felix_sb_port_pool_set, 1354f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get, 1355f59fd9caSVladimir Oltean .devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set, 1356f59fd9caSVladimir Oltean .devlink_sb_occ_snapshot = felix_sb_occ_snapshot, 1357f59fd9caSVladimir Oltean .devlink_sb_occ_max_clear = felix_sb_occ_max_clear, 1358f59fd9caSVladimir Oltean .devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get, 1359f59fd9caSVladimir Oltean .devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get, 136056051948SVladimir Oltean }; 1361319e4dd1SVladimir Oltean 1362319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) 1363319e4dd1SVladimir Oltean { 1364319e4dd1SVladimir Oltean struct felix *felix = ocelot_to_felix(ocelot); 1365319e4dd1SVladimir Oltean struct dsa_switch *ds = felix->ds; 1366319e4dd1SVladimir Oltean 1367319e4dd1SVladimir Oltean if (!dsa_is_user_port(ds, port)) 1368319e4dd1SVladimir Oltean return NULL; 1369319e4dd1SVladimir Oltean 1370319e4dd1SVladimir Oltean return dsa_to_port(ds, port)->slave; 1371319e4dd1SVladimir Oltean } 1372319e4dd1SVladimir Oltean 1373319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev) 1374319e4dd1SVladimir Oltean { 1375319e4dd1SVladimir Oltean struct dsa_port *dp; 1376319e4dd1SVladimir Oltean 1377319e4dd1SVladimir Oltean dp = dsa_port_from_netdev(dev); 1378319e4dd1SVladimir Oltean if (IS_ERR(dp)) 1379319e4dd1SVladimir Oltean return -EINVAL; 1380319e4dd1SVladimir Oltean 1381319e4dd1SVladimir Oltean return dp->index; 1382319e4dd1SVladimir Oltean } 1383