mlxsw: spectrum: PTP: Hook into packet receive path
authorPetr Machata <petrm@mellanox.com>
Sun, 30 Jun 2019 06:04:51 +0000 (09:04 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Jul 2019 01:58:34 +0000 (18:58 -0700)
When configured, the Spectrum hardware can recognize PTP packets and
trap them to the CPU using dedicated traps, PTP0 and PTP1.

One reason to get PTP packets under dedicated traps is to have a
separate policer suitable for the amount of PTP traffic expected when
switch is operated as a boundary clock. For this, add two new trap
groups, MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0 and _PTP1, and associate the
two PTP traps with these two groups.

In the driver, specifically for Spectrum-1, event PTP packets will need
to be paired up with their timestamps. Those arrive through a different
set of traps, added later in the patch set. To support this future use,
introduce a new PTP op, ptp_receive.

It is possible to configure which PTP messages should be trapped under
which PTP trap. On Spectrum systems, we will use PTP0 for event
packets (which need timestamping), and PTP1 for control packets (which
do not). Thus configure PTP0 trap with a custom callback that defers to
the ptp_receive op.

Additionally, L2 PTP packets are actually trapped through the LLDP trap,
not through any of the PTP traps. So treat the LLDP trap the same way as
the PTP0 trap. Unlike PTP traps, which are currently still disabled,
LLDP trap is active. Correspondingly, have all the implementations of
the ptp_receive op return true, which the handler treats as a signal to
forward the packet immediately.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
drivers/net/ethernet/mellanox/mlxsw/trap.h

index 8de9333e6eb18f1c76109272733a727739f7a4ee..76ff5b217c0416c5f8e19286849c45bb3a1938ca 100644 (file)
@@ -5292,6 +5292,8 @@ enum mlxsw_reg_htgt_trap_group {
        MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_MLD,
        MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND,
        MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
+       MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
+       MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
 };
 
 /* reg_htgt_trap_group
index 91486193454aa45d95e566bb6966377f0b64b439..84f4077b4b372c148086012dd1914f08d507ecd8 100644 (file)
@@ -147,6 +147,18 @@ struct mlxsw_sp_mlxfw_dev {
        struct mlxsw_sp *mlxsw_sp;
 };
 
+struct mlxsw_sp_ptp_ops {
+       struct mlxsw_sp_ptp_clock *
+               (*clock_init)(struct mlxsw_sp *mlxsw_sp, struct device *dev);
+       void (*clock_fini)(struct mlxsw_sp_ptp_clock *clock);
+
+       /* Notify a driver that a packet that might be PTP was received. Driver
+        * is responsible for freeing the passed-in SKB.
+        */
+       void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+                       u8 local_port);
+};
+
 static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev,
                                    u16 component_index, u32 *p_max_size,
                                    u8 *p_align_bits, u16 *p_max_write_size)
@@ -3947,8 +3959,8 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
        }
 }
 
-static void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
-                                             u8 local_port, void *priv)
+void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
+                                      u8 local_port, void *priv)
 {
        struct mlxsw_sp *mlxsw_sp = priv;
        struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
@@ -4022,6 +4034,14 @@ out:
        consume_skb(skb);
 }
 
+static void mlxsw_sp_rx_listener_ptp(struct sk_buff *skb, u8 local_port,
+                                    void *priv)
+{
+       struct mlxsw_sp *mlxsw_sp = priv;
+
+       mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port);
+}
+
 #define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
        MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \
                  _is_ctrl, SP_##_trap_group, DISCARD)
@@ -4043,7 +4063,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
        /* L2 traps */
        MLXSW_SP_RXL_NO_MARK(STP, TRAP_TO_CPU, STP, true),
        MLXSW_SP_RXL_NO_MARK(LACP, TRAP_TO_CPU, LACP, true),
-       MLXSW_SP_RXL_NO_MARK(LLDP, TRAP_TO_CPU, LLDP, true),
+       MLXSW_RXL(mlxsw_sp_rx_listener_ptp, LLDP, TRAP_TO_CPU,
+                 false, SP_LLDP, DISCARD),
        MLXSW_SP_RXL_MARK(DHCP, MIRROR_TO_CPU, DHCP, false),
        MLXSW_SP_RXL_MARK(IGMP_QUERY, MIRROR_TO_CPU, IGMP, false),
        MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, TRAP_TO_CPU, IGMP, false),
@@ -4112,6 +4133,10 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
        /* NVE traps */
        MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false),
        MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, TRAP_TO_CPU, ARP, false),
+       /* PTP traps */
+       MLXSW_RXL(mlxsw_sp_rx_listener_ptp, PTP0, TRAP_TO_CPU,
+                 false, SP_PTP0, DISCARD),
+       MLXSW_SP_RXL_NO_MARK(PTP1, TRAP_TO_CPU, PTP1, false),
 };
 
 static const struct mlxsw_listener mlxsw_sp1_listener[] = {
@@ -4166,6 +4191,14 @@ static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
                        rate = 1024;
                        burst_size = 7;
                        break;
+               case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0:
+                       rate = 24 * 1024;
+                       burst_size = 12;
+                       break;
+               case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1:
+                       rate = 19 * 1024;
+                       burst_size = 12;
+                       break;
                default:
                        continue;
                }
@@ -4204,6 +4237,7 @@ static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP:
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF:
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM:
+               case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0:
                        priority = 5;
                        tc = 5;
                        break;
@@ -4221,6 +4255,7 @@ static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP:
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND:
                case MLXSW_REG_HTGT_TRAP_GROUP_SP_RPF:
+               case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1:
                        priority = 2;
                        tc = 2;
                        break;
@@ -4383,20 +4418,16 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
        return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
 }
 
-struct mlxsw_sp_ptp_ops {
-       struct mlxsw_sp_ptp_clock *
-               (*clock_init)(struct mlxsw_sp *mlxsw_sp, struct device *dev);
-       void (*clock_fini)(struct mlxsw_sp_ptp_clock *clock);
-};
-
 static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
        .clock_init     = mlxsw_sp1_ptp_clock_init,
        .clock_fini     = mlxsw_sp1_ptp_clock_fini,
+       .receive        = mlxsw_sp1_ptp_receive,
 };
 
 static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
        .clock_init     = mlxsw_sp2_ptp_clock_init,
        .clock_fini     = mlxsw_sp2_ptp_clock_fini,
+       .receive        = mlxsw_sp2_ptp_receive,
 };
 
 static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
index 9136a86dc55f7546e6d6c627d74b38e6def2e66a..139fb1c53f963aa159bb0181e516285a5dd27136 100644 (file)
@@ -440,6 +440,8 @@ struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
 extern struct notifier_block mlxsw_sp_switchdev_notifier;
 
 /* spectrum.c */
+void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
+                                      u8 local_port, void *priv);
 int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
                          enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
                          bool dwrr, u8 dwrr_weight);
index bb6c0cb257711bd39ee5170313e7dc69b444be99..8eca1ac03e7a06713ee7614960f810269259b0e1 100644 (file)
@@ -264,3 +264,9 @@ void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
        cancel_delayed_work_sync(&clock->overflow_work);
        kfree(clock);
 }
+
+void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+                          u8 local_port)
+{
+       mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+}
index 76fa00a4be75f7ba47652e335e123bcf94ec3b0c..06bb303b54076106bdfae35dd79b692ac62ad897 100644 (file)
@@ -17,6 +17,9 @@ mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev);
 
 void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock);
 
+void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+                          u8 local_port);
+
 #else
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -29,6 +32,12 @@ static inline void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
 {
 }
 
+static inline void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp,
+                                        struct sk_buff *skb, u8 local_port)
+{
+       mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+}
+
 #endif
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -41,4 +50,10 @@ static inline void mlxsw_sp2_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
 {
 }
 
+static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp,
+                                        struct sk_buff *skb, u8 local_port)
+{
+       mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+}
+
 #endif
index 451216dd7f6bbc1025ff26b71f426fd76c40d4f8..f05b7ff4b9df181c151b6261af28514762004bfa 100644 (file)
@@ -17,6 +17,8 @@ enum {
        MLXSW_TRAP_ID_MVRP = 0x15,
        MLXSW_TRAP_ID_RPVST = 0x16,
        MLXSW_TRAP_ID_DHCP = 0x19,
+       MLXSW_TRAP_ID_PTP0 = 0x28,
+       MLXSW_TRAP_ID_PTP1 = 0x29,
        MLXSW_TRAP_ID_IGMP_QUERY = 0x30,
        MLXSW_TRAP_ID_IGMP_V1_REPORT = 0x31,
        MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32,