ocelot_apply_bridge_fwd_mask(ocelot);
}
+/* Set up a VCAP IS2 rule for delivering PTP frames to the CPU port module.
+ * If the quirk_no_xtr_irq is in place, then also copy those PTP frames to the
+ * tag_8021q CPU port.
+ */
+static int felix_setup_mmio_filtering(struct felix *felix)
+{
+ unsigned long user_ports = 0, cpu_ports = 0;
+ struct ocelot_vcap_filter *redirect_rule;
+ struct ocelot_vcap_filter *tagging_rule;
+ struct ocelot *ocelot = &felix->ocelot;
+ struct dsa_switch *ds = felix->ds;
+ int port, ret;
+
+ tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL);
+ if (!tagging_rule)
+ return -ENOMEM;
+
+ redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL);
+ if (!redirect_rule) {
+ kfree(tagging_rule);
+ return -ENOMEM;
+ }
+
+ for (port = 0; port < ocelot->num_phys_ports; port++) {
+ if (dsa_is_user_port(ds, port))
+ user_ports |= BIT(port);
+ if (dsa_is_cpu_port(ds, port))
+ cpu_ports |= BIT(port);
+ }
+
+ tagging_rule->key_type = OCELOT_VCAP_KEY_ETYPE;
+ *(__be16 *)tagging_rule->key.etype.etype.value = htons(ETH_P_1588);
+ *(__be16 *)tagging_rule->key.etype.etype.mask = htons(0xffff);
+ tagging_rule->ingress_port_mask = user_ports;
+ tagging_rule->prio = 1;
+ tagging_rule->id.cookie = ocelot->num_phys_ports;
+ tagging_rule->id.tc_offload = false;
+ tagging_rule->block_id = VCAP_IS1;
+ tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD;
+ tagging_rule->lookup = 0;
+ tagging_rule->action.pag_override_mask = 0xff;
+ tagging_rule->action.pag_val = ocelot->num_phys_ports;
+
+ ret = ocelot_vcap_filter_add(ocelot, tagging_rule, NULL);
+ if (ret) {
+ kfree(tagging_rule);
+ kfree(redirect_rule);
+ return ret;
+ }
+
+ redirect_rule->key_type = OCELOT_VCAP_KEY_ANY;
+ redirect_rule->ingress_port_mask = user_ports;
+ redirect_rule->pag = ocelot->num_phys_ports;
+ redirect_rule->prio = 1;
+ redirect_rule->id.cookie = ocelot->num_phys_ports;
+ redirect_rule->id.tc_offload = false;
+ redirect_rule->block_id = VCAP_IS2;
+ redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD;
+ redirect_rule->lookup = 0;
+ redirect_rule->action.cpu_copy_ena = true;
+ if (felix->info->quirk_no_xtr_irq) {
+ /* Redirect to the tag_8021q CPU but also copy PTP packets to
+ * the CPU port module
+ */
+ redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
+ redirect_rule->action.port_mask = cpu_ports;
+ } else {
+ /* Trap PTP packets only to the CPU port module (which is
+ * redirected to the NPI port)
+ */
+ redirect_rule->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
+ redirect_rule->action.port_mask = 0;
+ }
+
+ ret = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL);
+ if (ret) {
+ ocelot_vcap_filter_del(ocelot, tagging_rule);
+ kfree(redirect_rule);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int felix_teardown_mmio_filtering(struct felix *felix)
+{
+ struct ocelot_vcap_filter *tagging_rule, *redirect_rule;
+ struct ocelot_vcap_block *block_vcap_is1;
+ struct ocelot_vcap_block *block_vcap_is2;
+ struct ocelot *ocelot = &felix->ocelot;
+ int err;
+
+ block_vcap_is1 = &ocelot->block[VCAP_IS1];
+ block_vcap_is2 = &ocelot->block[VCAP_IS2];
+
+ tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1,
+ ocelot->num_phys_ports,
+ false);
+ if (!tagging_rule)
+ return -ENOENT;
+
+ err = ocelot_vcap_filter_del(ocelot, tagging_rule);
+ if (err)
+ return err;
+
+ redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2,
+ ocelot->num_phys_ports,
+ false);
+ if (!redirect_rule)
+ return -ENOENT;
+
+ return ocelot_vcap_filter_del(ocelot, redirect_rule);
+}
+
static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu)
{
struct ocelot *ocelot = ds->priv;
ANA_PORT_CPU_FWD_BPDU_CFG, port);
}
- /* In tag_8021q mode, the CPU port module is unused. So we
- * want to disable flooding of any kind to the CPU port module,
- * since packets going there will end in a black hole.
+ /* In tag_8021q mode, the CPU port module is unused, except for PTP
+ * frames. So we want to disable flooding of any kind to the CPU port
+ * module, since packets going there will end in a black hole.
*/
cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports));
ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_UC);
if (err)
goto out_free_dsa_8021_ctx;
+ err = felix_setup_mmio_filtering(felix);
+ if (err)
+ goto out_teardown_dsa_8021q;
+
return 0;
+out_teardown_dsa_8021q:
+ dsa_8021q_setup(felix->dsa_8021q_ctx, false);
out_free_dsa_8021_ctx:
kfree(felix->dsa_8021q_ctx);
return err;
struct felix *felix = ocelot_to_felix(ocelot);
int err, port;
+ err = felix_teardown_mmio_filtering(felix);
+ if (err)
+ dev_err(ds->dev, "felix_teardown_mmio_filtering returned %d",
+ err);
+
err = dsa_8021q_setup(felix->dsa_8021q_ctx, false);
if (err)
dev_err(ds->dev, "dsa_8021q_setup returned %d", err);