Commit a7b87d2a authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlxsw-add-support-of-latency-tlv'

Petr Machata says:

====================
mlxsw: Add support of latency TLV

Amit Cohen writes:

Ethernet Management Datagrams (EMADs) are Ethernet packets sent between
the driver and device's firmware. They are used to pass various
configurations to the device, but also to get events (e.g., port up)
from it. After the Ethernet header, these packets are built in a TLV
format.

This is the structure of EMADs:
* Ethernet header
* Operation TLV
* String TLV (optional)
* Latency TLV (optional)
* Reg TLV
* End TLV

The latency of each EMAD is measured by firmware. The driver can get the
measurement via latency TLV which can be added to each EMAD. This TLV is
optional, when EMAD is sent with this TLV, the EMAD's response will include
the TLV and will contain the firmware measurement.

Add support for Latency TLV and use it by default for all EMADs (see
more information in commit messages). The latency measurements can be
processed using BPF program for example, to create a histogram and average
of the latency per register. In addition, it is possible to measure the
end-to-end latency, so then the latency of the software overhead can be
calculated. This information can be useful to improve the driver
performance.

See an example of output of BPF tool which presents these measurements:

$ ./emadlatency -f -a
    Tracing EMADs... Hit Ctrl-C to end.
    Register write = RALUE (0x8013)
    E2E Measurements:
    average = 23 usecs, total = 32052693 usecs, count = 1337061
         usecs               : count    distribution
             0 -> 1          : 0        |                                 |
             2 -> 3          : 0        |                                 |
             4 -> 7          : 0        |                                 |
             8 -> 15         : 0        |                                 |
            16 -> 31         : 1290814  |*********************************|
            32 -> 63         : 45339    |*                                |
            64 -> 127        : 532      |                                 |
           128 -> 255        : 247      |                                 |
           256 -> 511        : 57       |                                 |
           512 -> 1023       : 26       |                                 |
          1024 -> 2047       : 33       |                                 |
          2048 -> 4095       : 0        |                                 |
          4096 -> 8191       : 10       |                                 |
          8192 -> 16383      : 1        |                                 |
         16384 -> 32767      : 1        |                                 |
         32768 -> 65535      : 1        |                                 |

    Firmware Measurements:
    average = 10 usecs, total = 13884128 usecs, count = 1337061
         usecs               : count    distribution
             0 -> 1          : 0        |                                 |
             2 -> 3          : 0        |                                 |
             4 -> 7          : 0        |                                 |
             8 -> 15         : 1337035  |*********************************|
            16 -> 31         : 17       |                                 |
            32 -> 63         : 7        |                                 |
            64 -> 127        : 0        |                                 |
           128 -> 255        : 2        |                                 |

    Diff between measurements: 13 usecs

Patch set overview:
Patches #1-#3 add support for querying MGIR, to know if string TLV and
latency TLV are supported
Patches #4-#5 add some relevant fields to support latency TLV
Patch #6 adds support of latency TLV
====================

Link: https://lore.kernel.org/r/cover.1674123673.git.petrm@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 24a7fffb 49f5b769
......@@ -78,6 +78,7 @@ struct mlxsw_core {
spinlock_t trans_list_lock; /* protects trans_list writes */
bool use_emad;
bool enable_string_tlv;
bool enable_latency_tlv;
} emad;
struct {
u16 *mapping; /* lag_id+port_index to local_port mapping */
......@@ -378,6 +379,22 @@ MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11);
MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04,
MLXSW_EMAD_STRING_TLV_STRING_LEN);
/* emad_latency_tlv_type
* Type of the TLV.
* Must be set to 0x4 (latency TLV).
*/
MLXSW_ITEM32(emad, latency_tlv, type, 0x00, 27, 5);
/* emad_latency_tlv_len
* Length of the latency TLV in u32.
*/
MLXSW_ITEM32(emad, latency_tlv, len, 0x00, 16, 11);
/* emad_latency_tlv_latency_time
* EMAD latency time in units of uSec.
*/
MLXSW_ITEM32(emad, latency_tlv, latency_time, 0x04, 0, 32);
/* emad_reg_tlv_type
* Type of the TLV.
* Must be set to 0x3 (register TLV).
......@@ -461,6 +478,12 @@ static void mlxsw_emad_pack_op_tlv(char *op_tlv,
mlxsw_emad_op_tlv_tid_set(op_tlv, tid);
}
static void mlxsw_emad_pack_latency_tlv(char *latency_tlv)
{
mlxsw_emad_latency_tlv_type_set(latency_tlv, MLXSW_EMAD_TLV_TYPE_LATENCY);
mlxsw_emad_latency_tlv_len_set(latency_tlv, MLXSW_EMAD_LATENCY_TLV_LEN);
}
static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb)
{
char *eth_hdr = skb_push(skb, MLXSW_EMAD_ETH_HDR_LEN);
......@@ -476,11 +499,11 @@ static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb)
return 0;
}
static void mlxsw_emad_construct(struct sk_buff *skb,
static void mlxsw_emad_construct(const struct mlxsw_core *mlxsw_core,
struct sk_buff *skb,
const struct mlxsw_reg_info *reg,
char *payload,
enum mlxsw_core_reg_access_type type,
u64 tid, bool enable_string_tlv)
enum mlxsw_core_reg_access_type type, u64 tid)
{
char *buf;
......@@ -490,7 +513,12 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
buf = skb_push(skb, reg->len + sizeof(u32));
mlxsw_emad_pack_reg_tlv(buf, reg, payload);
if (enable_string_tlv) {
if (mlxsw_core->emad.enable_latency_tlv) {
buf = skb_push(skb, MLXSW_EMAD_LATENCY_TLV_LEN * sizeof(u32));
mlxsw_emad_pack_latency_tlv(buf);
}
if (mlxsw_core->emad.enable_string_tlv) {
buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32));
mlxsw_emad_pack_string_tlv(buf);
}
......@@ -504,6 +532,7 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
struct mlxsw_emad_tlv_offsets {
u16 op_tlv;
u16 string_tlv;
u16 latency_tlv;
u16 reg_tlv;
};
......@@ -514,6 +543,13 @@ static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv)
return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING;
}
static bool mlxsw_emad_tlv_is_latency_tlv(const char *tlv)
{
u8 tlv_type = mlxsw_emad_latency_tlv_type_get(tlv);
return tlv_type == MLXSW_EMAD_TLV_TYPE_LATENCY;
}
static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
{
struct mlxsw_emad_tlv_offsets *offsets =
......@@ -521,6 +557,8 @@ static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN;
offsets->string_tlv = 0;
offsets->latency_tlv = 0;
offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN +
MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
......@@ -529,6 +567,11 @@ static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
offsets->string_tlv = offsets->reg_tlv;
offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
}
if (mlxsw_emad_tlv_is_latency_tlv(skb->data + offsets->reg_tlv)) {
offsets->latency_tlv = offsets->reg_tlv;
offsets->reg_tlv += MLXSW_EMAD_LATENCY_TLV_LEN * sizeof(u32);
}
}
static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
......@@ -794,6 +837,32 @@ static const struct mlxsw_listener mlxsw_emad_rx_listener =
MLXSW_RXL(mlxsw_emad_rx_listener_func, ETHEMAD, TRAP_TO_CPU, false,
EMAD, DISCARD);
static int mlxsw_emad_tlv_enable(struct mlxsw_core *mlxsw_core)
{
char mgir_pl[MLXSW_REG_MGIR_LEN];
bool string_tlv, latency_tlv;
int err;
mlxsw_reg_mgir_pack(mgir_pl);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl);
if (err)
return err;
string_tlv = mlxsw_reg_mgir_fw_info_string_tlv_get(mgir_pl);
mlxsw_core->emad.enable_string_tlv = string_tlv;
latency_tlv = mlxsw_reg_mgir_fw_info_latency_tlv_get(mgir_pl);
mlxsw_core->emad.enable_latency_tlv = latency_tlv;
return 0;
}
static void mlxsw_emad_tlv_disable(struct mlxsw_core *mlxsw_core)
{
mlxsw_core->emad.enable_latency_tlv = false;
mlxsw_core->emad.enable_string_tlv = false;
}
static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core)
{
struct workqueue_struct *emad_wq;
......@@ -824,10 +893,17 @@ static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core)
if (err)
goto err_trap_register;
err = mlxsw_emad_tlv_enable(mlxsw_core);
if (err)
goto err_emad_tlv_enable;
mlxsw_core->emad.use_emad = true;
return 0;
err_emad_tlv_enable:
mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
mlxsw_core);
err_trap_register:
destroy_workqueue(mlxsw_core->emad_wq);
return err;
......@@ -840,13 +916,14 @@ static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core)
return;
mlxsw_core->emad.use_emad = false;
mlxsw_emad_tlv_disable(mlxsw_core);
mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
mlxsw_core);
destroy_workqueue(mlxsw_core->emad_wq);
}
static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
u16 reg_len, bool enable_string_tlv)
u16 reg_len)
{
struct sk_buff *skb;
u16 emad_len;
......@@ -854,8 +931,10 @@ static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
(MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
sizeof(u32) + mlxsw_core->driver->txhdr_len);
if (enable_string_tlv)
if (mlxsw_core->emad.enable_string_tlv)
emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
if (mlxsw_core->emad.enable_latency_tlv)
emad_len += MLXSW_EMAD_LATENCY_TLV_LEN * sizeof(u32);
if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
return NULL;
......@@ -877,7 +956,6 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
mlxsw_reg_trans_cb_t *cb,
unsigned long cb_priv, u64 tid)
{
bool enable_string_tlv;
struct sk_buff *skb;
int err;
......@@ -885,12 +963,7 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
tid, reg->id, mlxsw_reg_id_str(reg->id),
mlxsw_core_reg_access_type_str(type));
/* Since this can be changed during emad_reg_access, read it once and
* use the value all the way.
*/
enable_string_tlv = mlxsw_core->emad.enable_string_tlv;
skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv);
skb = mlxsw_emad_alloc(mlxsw_core, reg->len);
if (!skb)
return -ENOMEM;
......@@ -907,8 +980,7 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
trans->reg = reg;
trans->type = type;
mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
enable_string_tlv);
mlxsw_emad_construct(mlxsw_core, skb, reg, payload, type, trans->tid);
mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
......@@ -3377,12 +3449,6 @@ bool mlxsw_core_sdq_supports_cqe_v2(struct mlxsw_core *mlxsw_core)
}
EXPORT_SYMBOL(mlxsw_core_sdq_supports_cqe_v2);
void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core)
{
mlxsw_core->emad.enable_string_tlv = true;
}
EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable);
static int __init mlxsw_core_module_init(void)
{
int err;
......
......@@ -448,8 +448,6 @@ u32 mlxsw_core_read_utc_nsec(struct mlxsw_core *mlxsw_core);
bool mlxsw_core_sdq_supports_cqe_v2(struct mlxsw_core *mlxsw_core);
void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core);
bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
enum mlxsw_res_id res_id);
......
......@@ -21,6 +21,7 @@ enum {
MLXSW_EMAD_TLV_TYPE_OP,
MLXSW_EMAD_TLV_TYPE_STRING,
MLXSW_EMAD_TLV_TYPE_REG,
MLXSW_EMAD_TLV_TYPE_LATENCY,
};
/* OP TLV */
......@@ -90,6 +91,9 @@ enum {
/* STRING TLV */
#define MLXSW_EMAD_STRING_TLV_LEN 33 /* Length in u32 */
/* LATENCY TLV */
#define MLXSW_EMAD_LATENCY_TLV_LEN 7 /* Length in u32 */
/* END TLV */
#define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */
......
......@@ -10009,6 +10009,18 @@ MLXSW_REG_DEFINE(mgir, MLXSW_REG_MGIR_ID, MLXSW_REG_MGIR_LEN);
*/
MLXSW_ITEM32(reg, mgir, hw_info_device_hw_revision, 0x0, 16, 16);
/* reg_mgir_fw_info_latency_tlv
* When set, latency-TLV is supported.
* Access: RO
*/
MLXSW_ITEM32(reg, mgir, fw_info_latency_tlv, 0x20, 29, 1);
/* reg_mgir_fw_info_string_tlv
* When set, string-TLV is supported.
* Access: RO
*/
MLXSW_ITEM32(reg, mgir, fw_info_string_tlv, 0x20, 28, 1);
#define MLXSW_REG_MGIR_FW_INFO_PSID_SIZE 16
/* reg_mgir_fw_info_psid
......
......@@ -3092,7 +3092,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->bus_info = mlxsw_bus_info;
mlxsw_sp_parsing_init(mlxsw_sp);
mlxsw_core_emad_string_tlv_enable(mlxsw_core);
err = mlxsw_sp_base_mac_get(mlxsw_sp);
if (err) {
......
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