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);