Skip to content

Commit 5d716ab

Browse files
Shalom Toledodavem330
authored andcommitted
mlxsw: core: Add support for using EMAD string TLV
In case the firmware had an error while processing EMADs, it can send back an ASCII string with the reason using EMAD string TLV. This patch adds the support for using EMAD string TLV. In case of an error, reports the reason using devlink hwerr tracepoint. Signed-off-by: Shalom Toledo <[email protected]> Acked-by: Jiri Pirko <[email protected]> Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 72c8f42 commit 5d716ab

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

drivers/net/ethernet/mellanox/mlxsw/core.c

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct mlxsw_core {
7171
struct list_head trans_list;
7272
spinlock_t trans_list_lock; /* protects trans_list writes */
7373
bool use_emad;
74+
bool enable_string_tlv;
7475
} emad;
7576
struct {
7677
u8 *mapping; /* lag_id+port_index to local_port mapping */
@@ -323,6 +324,12 @@ static void mlxsw_emad_pack_reg_tlv(char *reg_tlv,
323324
memcpy(reg_tlv + sizeof(u32), payload, reg->len);
324325
}
325326

327+
static void mlxsw_emad_pack_string_tlv(char *string_tlv)
328+
{
329+
mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING);
330+
mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN);
331+
}
332+
326333
static void mlxsw_emad_pack_op_tlv(char *op_tlv,
327334
const struct mlxsw_reg_info *reg,
328335
enum mlxsw_core_reg_access_type type,
@@ -364,7 +371,7 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
364371
const struct mlxsw_reg_info *reg,
365372
char *payload,
366373
enum mlxsw_core_reg_access_type type,
367-
u64 tid)
374+
u64 tid, bool enable_string_tlv)
368375
{
369376
char *buf;
370377

@@ -374,6 +381,11 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
374381
buf = skb_push(skb, reg->len + sizeof(u32));
375382
mlxsw_emad_pack_reg_tlv(buf, reg, payload);
376383

384+
if (enable_string_tlv) {
385+
buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32));
386+
mlxsw_emad_pack_string_tlv(buf);
387+
}
388+
377389
buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32));
378390
mlxsw_emad_pack_op_tlv(buf, reg, type, tid);
379391

@@ -418,6 +430,17 @@ static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
418430
return ((char *) (skb->data + offsets->op_tlv));
419431
}
420432

433+
static char *mlxsw_emad_string_tlv(const struct sk_buff *skb)
434+
{
435+
struct mlxsw_emad_tlv_offsets *offsets =
436+
(struct mlxsw_emad_tlv_offsets *) skb->cb;
437+
438+
if (!offsets->string_tlv)
439+
return NULL;
440+
441+
return ((char *) (skb->data + offsets->string_tlv));
442+
}
443+
421444
static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb)
422445
{
423446
struct mlxsw_emad_tlv_offsets *offsets =
@@ -499,10 +522,31 @@ struct mlxsw_reg_trans {
499522
const struct mlxsw_reg_info *reg;
500523
enum mlxsw_core_reg_access_type type;
501524
int err;
525+
char *emad_err_string;
502526
enum mlxsw_emad_op_tlv_status emad_status;
503527
struct rcu_head rcu;
504528
};
505529

530+
static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb,
531+
struct mlxsw_reg_trans *trans)
532+
{
533+
char *string_tlv;
534+
char *string;
535+
536+
string_tlv = mlxsw_emad_string_tlv(skb);
537+
if (!string_tlv)
538+
return;
539+
540+
trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN,
541+
GFP_ATOMIC);
542+
if (!trans->emad_err_string)
543+
return;
544+
545+
string = mlxsw_emad_string_tlv_string_data(string_tlv);
546+
strlcpy(trans->emad_err_string, string,
547+
MLXSW_EMAD_STRING_TLV_STRING_LEN);
548+
}
549+
506550
#define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000
507551
#define MLXSW_EMAD_TIMEOUT_MS 200
508552

@@ -600,6 +644,8 @@ static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core,
600644
trans->cb(mlxsw_core,
601645
mlxsw_emad_reg_payload(reg_tlv),
602646
trans->reg->len, trans->cb_priv);
647+
} else {
648+
mlxsw_emad_process_string_tlv(skb, trans);
603649
}
604650
mlxsw_emad_trans_finish(trans, err);
605651
}
@@ -692,14 +738,16 @@ static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core)
692738
}
693739

694740
static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
695-
u16 reg_len)
741+
u16 reg_len, bool enable_string_tlv)
696742
{
697743
struct sk_buff *skb;
698744
u16 emad_len;
699745

700746
emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
701747
(MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
702748
sizeof(u32) + mlxsw_core->driver->txhdr_len);
749+
if (enable_string_tlv)
750+
emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
703751
if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
704752
return NULL;
705753

@@ -721,14 +769,20 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
721769
mlxsw_reg_trans_cb_t *cb,
722770
unsigned long cb_priv, u64 tid)
723771
{
772+
bool enable_string_tlv;
724773
struct sk_buff *skb;
725774
int err;
726775

727776
dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n",
728777
tid, reg->id, mlxsw_reg_id_str(reg->id),
729778
mlxsw_core_reg_access_type_str(type));
730779

731-
skb = mlxsw_emad_alloc(mlxsw_core, reg->len);
780+
/* Since this can be changed during emad_reg_access, read it once and
781+
* use the value all the way.
782+
*/
783+
enable_string_tlv = mlxsw_core->emad.enable_string_tlv;
784+
785+
skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv);
732786
if (!skb)
733787
return -ENOMEM;
734788

@@ -745,7 +799,8 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
745799
trans->reg = reg;
746800
trans->type = type;
747801

748-
mlxsw_emad_construct(skb, reg, payload, type, trans->tid);
802+
mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
803+
enable_string_tlv);
749804
mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
750805

751806
spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
@@ -1707,12 +1762,15 @@ static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
17071762
mlxsw_emad_op_tlv_status_str(trans->emad_status));
17081763

17091764
snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE,
1710-
"(tid=%llx,reg_id=%x(%s)) %s\n", trans->tid,
1765+
"(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid,
17111766
trans->reg->id, mlxsw_reg_id_str(trans->reg->id),
1712-
mlxsw_emad_op_tlv_status_str(trans->emad_status));
1767+
mlxsw_emad_op_tlv_status_str(trans->emad_status),
1768+
trans->emad_err_string ? trans->emad_err_string : "");
17131769

17141770
trace_devlink_hwerr(priv_to_devlink(mlxsw_core),
17151771
trans->emad_status, err_string);
1772+
1773+
kfree(trans->emad_err_string);
17161774
}
17171775

17181776
list_del(&trans->bulk_list);
@@ -2283,6 +2341,12 @@ u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
22832341
}
22842342
EXPORT_SYMBOL(mlxsw_core_read_frc_l);
22852343

2344+
void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core)
2345+
{
2346+
mlxsw_core->emad.enable_string_tlv = true;
2347+
}
2348+
EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable);
2349+
22862350
static int __init mlxsw_core_module_init(void)
22872351
{
22882352
int err;

drivers/net/ethernet/mellanox/mlxsw/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core);
347347
u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core);
348348
u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core);
349349

350+
void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core);
351+
350352
bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
351353
enum mlxsw_res_id res_id);
352354

0 commit comments

Comments
 (0)