Commit 24157bc6 authored by Danielle Ratson's avatar Danielle Ratson Committed by David S. Miller

mlxsw: Send PTP packets as data packets to overcome a limitation

In Spectrum-2 and Spectrum-3, the correction field of PTP packets which are
sent as control packets is not updated at egress port. To overcome this
limitation, PTP packets which require time stamp, should be sent as data
packets with the following details:
1. FID valid = 1
2. FID value above the maximum FID
3. rx_router_port = 1

>From Spectrum-4 and on, this limitation will be solved.

Extend the function which handles TX header, in case that the packet is
a PTP packet, add TX header with type=data and all the above mentioned
requirements. Add operation as part of 'struct mlxsw_sp_ptp_ops', to be
able to separate the handling of PTP packets between different ASICs. Use
the data packet solution only for Spectrum-2 and Spectrum-3. Therefore, add
a dedicated operation structure for Spectrum-4, as it will be same to
Spectrum-2 in PTP implementation, just will not have the limitation of
control packets.
Signed-off-by: default avatarDanielle Ratson <danieller@nvidia.com>
Signed-off-by: default avatarAmit Cohen <amcohen@nvidia.com>
Reviewed-by: default avatarPetr Machata <petrm@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a5bf8e5e
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/netevent.h> #include <net/netevent.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <linux/ptp_classify.h>
#include "spectrum.h" #include "spectrum.h"
#include "pci.h" #include "pci.h"
...@@ -230,8 +231,8 @@ void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, ...@@ -230,8 +231,8 @@ void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
counter_index); counter_index);
} }
static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info) const struct mlxsw_tx_info *tx_info)
{ {
char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN); char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
...@@ -246,6 +247,82 @@ static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, ...@@ -246,6 +247,82 @@ static void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
} }
int
mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
char *txhdr;
u16 max_fid;
int err;
if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
err = -ENOMEM;
goto err_skb_cow_head;
}
if (!MLXSW_CORE_RES_VALID(mlxsw_core, FID)) {
err = -EIO;
goto err_res_valid;
}
max_fid = MLXSW_CORE_RES_GET(mlxsw_core, FID);
txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
memset(txhdr, 0, MLXSW_TXHDR_LEN);
mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
mlxsw_tx_hdr_rx_is_router_set(txhdr, true);
mlxsw_tx_hdr_fid_valid_set(txhdr, true);
mlxsw_tx_hdr_fid_set(txhdr, max_fid + tx_info->local_port - 1);
mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_DATA);
return 0;
err_res_valid:
err_skb_cow_head:
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
dev_kfree_skb_any(skb);
return err;
}
static bool mlxsw_sp_skb_requires_ts(struct sk_buff *skb)
{
unsigned int type;
if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
return false;
type = ptp_classify_raw(skb);
return !!ptp_parse_header(skb, type);
}
static int mlxsw_sp_txhdr_handle(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
/* In Spectrum-2 and Spectrum-3, PTP events that require a time stamp
* need special handling and cannot be transmitted as regular control
* packets.
*/
if (unlikely(mlxsw_sp_skb_requires_ts(skb)))
return mlxsw_sp->ptp_ops->txhdr_construct(mlxsw_core,
mlxsw_sp_port, skb,
tx_info);
if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
mlxsw_sp_txhdr_construct(skb, tx_info);
return 0;
}
enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state) enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state)
{ {
switch (state) { switch (state) {
...@@ -648,12 +725,6 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, ...@@ -648,12 +725,6 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
u64 len; u64 len;
int err; int err;
if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb)); memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info)) if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
...@@ -664,7 +735,11 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, ...@@ -664,7 +735,11 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
mlxsw_sp_txhdr_construct(skb, &tx_info); err = mlxsw_sp_txhdr_handle(mlxsw_sp->core, mlxsw_sp_port, skb,
&tx_info);
if (err)
return NETDEV_TX_OK;
/* TX header is consumed by HW on the way so we shouldn't count its /* TX header is consumed by HW on the way so we shouldn't count its
* bytes as being sent. * bytes as being sent.
*/ */
...@@ -2666,6 +2741,7 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = { ...@@ -2666,6 +2741,7 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
.get_stats_count = mlxsw_sp1_get_stats_count, .get_stats_count = mlxsw_sp1_get_stats_count,
.get_stats_strings = mlxsw_sp1_get_stats_strings, .get_stats_strings = mlxsw_sp1_get_stats_strings,
.get_stats = mlxsw_sp1_get_stats, .get_stats = mlxsw_sp1_get_stats,
.txhdr_construct = mlxsw_sp_ptp_txhdr_construct,
}; };
static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = { static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
...@@ -2682,6 +2758,24 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = { ...@@ -2682,6 +2758,24 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
.get_stats_count = mlxsw_sp2_get_stats_count, .get_stats_count = mlxsw_sp2_get_stats_count,
.get_stats_strings = mlxsw_sp2_get_stats_strings, .get_stats_strings = mlxsw_sp2_get_stats_strings,
.get_stats = mlxsw_sp2_get_stats, .get_stats = mlxsw_sp2_get_stats,
.txhdr_construct = mlxsw_sp2_ptp_txhdr_construct,
};
static const struct mlxsw_sp_ptp_ops mlxsw_sp4_ptp_ops = {
.clock_init = mlxsw_sp2_ptp_clock_init,
.clock_fini = mlxsw_sp2_ptp_clock_fini,
.init = mlxsw_sp2_ptp_init,
.fini = mlxsw_sp2_ptp_fini,
.receive = mlxsw_sp2_ptp_receive,
.transmitted = mlxsw_sp2_ptp_transmitted,
.hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get,
.hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set,
.shaper_work = mlxsw_sp2_ptp_shaper_work,
.get_ts_info = mlxsw_sp2_ptp_get_ts_info,
.get_stats_count = mlxsw_sp2_get_stats_count,
.get_stats_strings = mlxsw_sp2_get_stats_strings,
.get_stats = mlxsw_sp2_get_stats,
.txhdr_construct = mlxsw_sp_ptp_txhdr_construct,
}; };
struct mlxsw_sp_sample_trigger_node { struct mlxsw_sp_sample_trigger_node {
...@@ -3327,7 +3421,7 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core, ...@@ -3327,7 +3421,7 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops; mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;
mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; mlxsw_sp->ptp_ops = &mlxsw_sp4_ptp_ops;
mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
......
...@@ -243,6 +243,10 @@ struct mlxsw_sp_ptp_ops { ...@@ -243,6 +243,10 @@ struct mlxsw_sp_ptp_ops {
void (*get_stats_strings)(u8 **p); void (*get_stats_strings)(u8 **p);
void (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port, void (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
u64 *data, int data_index); u64 *data, int data_index);
int (*txhdr_construct)(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
}; };
static inline struct mlxsw_sp_upper * static inline struct mlxsw_sp_upper *
...@@ -700,6 +704,12 @@ int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, ...@@ -700,6 +704,12 @@ int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
unsigned int *p_counter_index); unsigned int *p_counter_index);
void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
unsigned int counter_index); unsigned int counter_index);
void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
int mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
bool mlxsw_sp_port_dev_check(const struct net_device *dev); bool mlxsw_sp_port_dev_check(const struct net_device *dev);
struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev);
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev);
......
...@@ -1385,3 +1385,37 @@ void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state_common) ...@@ -1385,3 +1385,37 @@ void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state_common)
mlxsw_sp_ptp_traps_unset(mlxsw_sp); mlxsw_sp_ptp_traps_unset(mlxsw_sp);
kfree(ptp_state); kfree(ptp_state);
} }
int mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
mlxsw_sp_txhdr_construct(skb, tx_info);
return 0;
}
int mlxsw_sp2_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
/* In Spectrum-2 and Spectrum-3, in order for PTP event packets to have
* their correction field correctly set on the egress port they must be
* transmitted as data packets. Such packets ingress the ASIC via the
* CPU port and must have a VLAN tag, as the CPU port is not configured
* with a PVID. Push the default VLAN (4095), which is configured as
* egress untagged on all the ports.
*/
if (!skb_vlan_tagged(skb)) {
skb = vlan_insert_tag_set_proto(skb, htons(ETH_P_8021Q),
MLXSW_SP_DEFAULT_VID);
if (!skb) {
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
return -ENOMEM;
}
}
return mlxsw_sp_txhdr_ptp_data_construct(mlxsw_core, mlxsw_sp_port, skb,
tx_info);
}
...@@ -57,6 +57,11 @@ void mlxsw_sp1_get_stats_strings(u8 **p); ...@@ -57,6 +57,11 @@ void mlxsw_sp1_get_stats_strings(u8 **p);
void mlxsw_sp1_get_stats(struct mlxsw_sp_port *mlxsw_sp_port, void mlxsw_sp1_get_stats(struct mlxsw_sp_port *mlxsw_sp_port,
u64 *data, int data_index); u64 *data, int data_index);
int mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
struct mlxsw_sp_ptp_clock * struct mlxsw_sp_ptp_clock *
mlxsw_sp2_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev); mlxsw_sp2_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev);
...@@ -65,6 +70,12 @@ void mlxsw_sp2_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock); ...@@ -65,6 +70,12 @@ void mlxsw_sp2_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock);
struct mlxsw_sp_ptp_state *mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp); struct mlxsw_sp_ptp_state *mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state); void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state);
int mlxsw_sp2_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
#else #else
static inline struct mlxsw_sp_ptp_clock * static inline struct mlxsw_sp_ptp_clock *
...@@ -145,6 +156,14 @@ static inline void mlxsw_sp1_get_stats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -145,6 +156,14 @@ static inline void mlxsw_sp1_get_stats(struct mlxsw_sp_port *mlxsw_sp_port,
{ {
} }
int mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
return -EOPNOTSUPP;
}
static inline struct mlxsw_sp_ptp_clock * static inline struct mlxsw_sp_ptp_clock *
mlxsw_sp2_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev) mlxsw_sp2_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev)
{ {
...@@ -164,6 +183,14 @@ mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp) ...@@ -164,6 +183,14 @@ mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp)
static inline void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state) static inline void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
{ {
} }
int mlxsw_sp2_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
return -EOPNOTSUPP;
}
#endif #endif
static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp, static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment