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 8de9333..76ff5b2 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 9148619..84f4077 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 9136a86..139fb1c 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 bb6c0cb..8eca1ac 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 76fa00a..06bb303 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 451216d..f05b7ff 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,