Skip to content

Commit b55cbbe

Browse files
committed
Merge branch 'mlxsw-Add-extended-ACK-for-EMADs'
Ido Schimmel says: ==================== mlxsw: Add extended ACK for EMADs Shalom says: 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. Up until now, whenever the driver issued an erroneous register access it only got an error code indicating a bad parameter was used. This patch set adds a new TLV (string TLV) that can be used by the firmware to encode a 128 character string describing the error. The new TLV is allocated by the driver and set to zeros. In case of error, the driver will check the length of the string in the response and report it using devlink hwerr tracepoint. Example: $ perf record -a -q -e devlink:devlink_hwerr & $ pkill -2 perf $ perf script -F trace:event,trace | grep hwerr devlink:devlink_hwerr: bus_name=pci dev_name=0000:03:00.0 driver_name=mlxsw_spectrum err=7 (tid=9913892d00001593,reg_id=8018(rauhtd)) bad parameter (inside er_rauhtd_write_query(), num_rec=32 is over the maximum number of records supported) Patch #1 parses the offsets of the different TLVs in incoming EMADs and stores them in the skb's control block. This makes it easier to later add new TLVs. Patches #2-#3 remove deprecated TLVs and add string TLV definition. Patches #4-#7 gradually add support for the new string TLV. v2: * Use existing devlink hwerr tracepoint to report the error string, instead of printing it to kernel log ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents b2ef81d + 9032b9e commit b55cbbe

File tree

4 files changed

+162
-20
lines changed

4 files changed

+162
-20
lines changed

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

Lines changed: 154 additions & 17 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 */
@@ -249,6 +250,25 @@ MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8);
249250
*/
250251
MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64);
251252

253+
/* emad_string_tlv_type
254+
* Type of the TLV.
255+
* Must be set to 0x2 (string TLV).
256+
*/
257+
MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5);
258+
259+
/* emad_string_tlv_len
260+
* Length of the string TLV in u32.
261+
*/
262+
MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11);
263+
264+
#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128
265+
266+
/* emad_string_tlv_string
267+
* String provided by the device's firmware in case of erroneous register access
268+
*/
269+
MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04,
270+
MLXSW_EMAD_STRING_TLV_STRING_LEN);
271+
252272
/* emad_reg_tlv_type
253273
* Type of the TLV.
254274
* Must be set to 0x3 (register TLV).
@@ -304,6 +324,12 @@ static void mlxsw_emad_pack_reg_tlv(char *reg_tlv,
304324
memcpy(reg_tlv + sizeof(u32), payload, reg->len);
305325
}
306326

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+
307333
static void mlxsw_emad_pack_op_tlv(char *op_tlv,
308334
const struct mlxsw_reg_info *reg,
309335
enum mlxsw_core_reg_access_type type,
@@ -345,7 +371,7 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
345371
const struct mlxsw_reg_info *reg,
346372
char *payload,
347373
enum mlxsw_core_reg_access_type type,
348-
u64 tid)
374+
u64 tid, bool enable_string_tlv)
349375
{
350376
char *buf;
351377

@@ -355,26 +381,82 @@ static void mlxsw_emad_construct(struct sk_buff *skb,
355381
buf = skb_push(skb, reg->len + sizeof(u32));
356382
mlxsw_emad_pack_reg_tlv(buf, reg, payload);
357383

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+
358389
buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32));
359390
mlxsw_emad_pack_op_tlv(buf, reg, type, tid);
360391

361392
mlxsw_emad_construct_eth_hdr(skb);
362393
}
363394

395+
struct mlxsw_emad_tlv_offsets {
396+
u16 op_tlv;
397+
u16 string_tlv;
398+
u16 reg_tlv;
399+
};
400+
401+
static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv)
402+
{
403+
u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv);
404+
405+
return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING;
406+
}
407+
408+
static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
409+
{
410+
struct mlxsw_emad_tlv_offsets *offsets =
411+
(struct mlxsw_emad_tlv_offsets *) skb->cb;
412+
413+
offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN;
414+
offsets->string_tlv = 0;
415+
offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN +
416+
MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
417+
418+
/* If string TLV is present, it must come after the operation TLV. */
419+
if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) {
420+
offsets->string_tlv = offsets->reg_tlv;
421+
offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
422+
}
423+
}
424+
364425
static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
365426
{
366-
return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN));
427+
struct mlxsw_emad_tlv_offsets *offsets =
428+
(struct mlxsw_emad_tlv_offsets *) skb->cb;
429+
430+
return ((char *) (skb->data + offsets->op_tlv));
431+
}
432+
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));
367442
}
368443

369444
static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb)
370445
{
371-
return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN +
372-
MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)));
446+
struct mlxsw_emad_tlv_offsets *offsets =
447+
(struct mlxsw_emad_tlv_offsets *) skb->cb;
448+
449+
return ((char *) (skb->data + offsets->reg_tlv));
450+
}
451+
452+
static char *mlxsw_emad_reg_payload(const char *reg_tlv)
453+
{
454+
return ((char *) (reg_tlv + sizeof(u32)));
373455
}
374456

375-
static char *mlxsw_emad_reg_payload(const char *op_tlv)
457+
static char *mlxsw_emad_reg_payload_cmd(const char *mbox)
376458
{
377-
return ((char *) (op_tlv + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
459+
return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
378460
}
379461

380462
static u64 mlxsw_emad_get_tid(const struct sk_buff *skb)
@@ -440,10 +522,31 @@ struct mlxsw_reg_trans {
440522
const struct mlxsw_reg_info *reg;
441523
enum mlxsw_core_reg_access_type type;
442524
int err;
525+
char *emad_err_string;
443526
enum mlxsw_emad_op_tlv_status emad_status;
444527
struct rcu_head rcu;
445528
};
446529

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+
447550
#define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000
448551
#define MLXSW_EMAD_TIMEOUT_MS 200
449552

@@ -535,12 +638,14 @@ static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core,
535638
mlxsw_emad_transmit_retry(mlxsw_core, trans);
536639
} else {
537640
if (err == 0) {
538-
char *op_tlv = mlxsw_emad_op_tlv(skb);
641+
char *reg_tlv = mlxsw_emad_reg_tlv(skb);
539642

540643
if (trans->cb)
541644
trans->cb(mlxsw_core,
542-
mlxsw_emad_reg_payload(op_tlv),
645+
mlxsw_emad_reg_payload(reg_tlv),
543646
trans->reg->len, trans->cb_priv);
647+
} else {
648+
mlxsw_emad_process_string_tlv(skb, trans);
544649
}
545650
mlxsw_emad_trans_finish(trans, err);
546651
}
@@ -556,6 +661,8 @@ static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port,
556661
trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0,
557662
skb->data, skb->len);
558663

664+
mlxsw_emad_tlv_parse(skb);
665+
559666
if (!mlxsw_emad_is_resp(skb))
560667
goto free_skb;
561668

@@ -631,14 +738,16 @@ static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core)
631738
}
632739

633740
static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
634-
u16 reg_len)
741+
u16 reg_len, bool enable_string_tlv)
635742
{
636743
struct sk_buff *skb;
637744
u16 emad_len;
638745

639746
emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
640747
(MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
641748
sizeof(u32) + mlxsw_core->driver->txhdr_len);
749+
if (enable_string_tlv)
750+
emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
642751
if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
643752
return NULL;
644753

@@ -660,14 +769,20 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
660769
mlxsw_reg_trans_cb_t *cb,
661770
unsigned long cb_priv, u64 tid)
662771
{
772+
bool enable_string_tlv;
663773
struct sk_buff *skb;
664774
int err;
665775

666776
dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n",
667777
tid, reg->id, mlxsw_reg_id_str(reg->id),
668778
mlxsw_core_reg_access_type_str(type));
669779

670-
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);
671786
if (!skb)
672787
return -ENOMEM;
673788

@@ -684,7 +799,8 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
684799
trans->reg = reg;
685800
trans->type = type;
686801

687-
mlxsw_emad_construct(skb, reg, payload, type, trans->tid);
802+
mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
803+
enable_string_tlv);
688804
mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
689805

690806
spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
@@ -1395,12 +1511,16 @@ static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port,
13951511
struct mlxsw_event_listener_item *event_listener_item = priv;
13961512
struct mlxsw_reg_info reg;
13971513
char *payload;
1398-
char *op_tlv = mlxsw_emad_op_tlv(skb);
1399-
char *reg_tlv = mlxsw_emad_reg_tlv(skb);
1514+
char *reg_tlv;
1515+
char *op_tlv;
1516+
1517+
mlxsw_emad_tlv_parse(skb);
1518+
op_tlv = mlxsw_emad_op_tlv(skb);
1519+
reg_tlv = mlxsw_emad_reg_tlv(skb);
14001520

14011521
reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv);
14021522
reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32);
1403-
payload = mlxsw_emad_reg_payload(op_tlv);
1523+
payload = mlxsw_emad_reg_payload(reg_tlv);
14041524
event_listener_item->el.func(&reg, payload, event_listener_item->priv);
14051525
dev_kfree_skb(skb);
14061526
}
@@ -1618,8 +1738,11 @@ int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core,
16181738
}
16191739
EXPORT_SYMBOL(mlxsw_reg_trans_write);
16201740

1741+
#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256
1742+
16211743
static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
16221744
{
1745+
char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE];
16231746
struct mlxsw_core *mlxsw_core = trans->core;
16241747
int err;
16251748

@@ -1637,9 +1760,17 @@ static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
16371760
mlxsw_core_reg_access_type_str(trans->type),
16381761
trans->emad_status,
16391762
mlxsw_emad_op_tlv_status_str(trans->emad_status));
1763+
1764+
snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE,
1765+
"(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid,
1766+
trans->reg->id, mlxsw_reg_id_str(trans->reg->id),
1767+
mlxsw_emad_op_tlv_status_str(trans->emad_status),
1768+
trans->emad_err_string ? trans->emad_err_string : "");
1769+
16401770
trace_devlink_hwerr(priv_to_devlink(mlxsw_core),
1641-
trans->emad_status,
1642-
mlxsw_emad_op_tlv_status_str(trans->emad_status));
1771+
trans->emad_status, err_string);
1772+
1773+
kfree(trans->emad_err_string);
16431774
}
16441775

16451776
list_del(&trans->bulk_list);
@@ -1713,7 +1844,7 @@ static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core,
17131844
}
17141845

17151846
if (!err)
1716-
memcpy(payload, mlxsw_emad_reg_payload(out_mbox),
1847+
memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox),
17171848
reg->len);
17181849

17191850
mlxsw_cmd_mbox_free(out_mbox);
@@ -2210,6 +2341,12 @@ u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
22102341
}
22112342
EXPORT_SYMBOL(mlxsw_core_read_frc_l);
22122343

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+
22132350
static int __init mlxsw_core_module_init(void)
22142351
{
22152352
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

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
enum {
2020
MLXSW_EMAD_TLV_TYPE_END,
2121
MLXSW_EMAD_TLV_TYPE_OP,
22-
MLXSW_EMAD_TLV_TYPE_DR,
22+
MLXSW_EMAD_TLV_TYPE_STRING,
2323
MLXSW_EMAD_TLV_TYPE_REG,
24-
MLXSW_EMAD_TLV_TYPE_USERDATA,
25-
MLXSW_EMAD_TLV_TYPE_OOBETH,
2624
};
2725

2826
/* OP TLV */
@@ -89,6 +87,9 @@ enum {
8987
MLXSW_EMAD_OP_TLV_METHOD_EVENT = 5,
9088
};
9189

90+
/* STRING TLV */
91+
#define MLXSW_EMAD_STRING_TLV_LEN 33 /* Length in u32 */
92+
9293
/* END TLV */
9394
#define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */
9495

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4894,6 +4894,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
48944894
if (err)
48954895
return err;
48964896

4897+
mlxsw_core_emad_string_tlv_enable(mlxsw_core);
4898+
48974899
err = mlxsw_sp_base_mac_get(mlxsw_sp);
48984900
if (err) {
48994901
dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n");

0 commit comments

Comments
 (0)