forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f9004dbfff8a3fbbd7e2a88c8a4327c7f2f8e5b2
kernel/drivers/net/ethernet/mellanox/mlxsw/core.c
....@@ -20,11 +20,13 @@
2020 #include <linux/rcupdate.h>
2121 #include <linux/slab.h>
2222 #include <linux/workqueue.h>
23
+#include <linux/firmware.h>
2324 #include <asm/byteorder.h>
2425 #include <net/devlink.h>
2526 #include <trace/events/devlink.h>
2627
2728 #include "core.h"
29
+#include "core_env.h"
2830 #include "item.h"
2931 #include "cmd.h"
3032 #include "port.h"
....@@ -32,6 +34,7 @@
3234 #include "emad.h"
3335 #include "reg.h"
3436 #include "resources.h"
37
+#include "../mlxfw/mlxfw.h"
3538
3639 static LIST_HEAD(mlxsw_core_driver_list);
3740 static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock);
....@@ -71,6 +74,7 @@
7174 struct list_head trans_list;
7275 spinlock_t trans_list_lock; /* protects trans_list writes */
7376 bool use_emad;
77
+ bool enable_string_tlv;
7478 } emad;
7579 struct {
7680 u8 *mapping; /* lag_id+port_index to local_port mapping */
....@@ -80,9 +84,13 @@
8084 struct mlxsw_thermal *thermal;
8185 struct mlxsw_core_port *ports;
8286 unsigned int max_ports;
83
- bool reload_fail;
8487 bool fw_flash_in_progress;
85
- unsigned long driver_priv[0];
88
+ struct {
89
+ struct devlink_health_reporter *fw_fatal;
90
+ } health;
91
+ struct mlxsw_env *env;
92
+ bool is_initialized; /* Denotes if core was already initialized. */
93
+ unsigned long driver_priv[];
8694 /* driver_priv has to be always the last item */
8795 };
8896
....@@ -122,10 +130,32 @@
122130 }
123131 EXPORT_SYMBOL(mlxsw_core_driver_priv);
124132
133
+bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core)
134
+{
135
+ return mlxsw_core->driver->res_query_enabled;
136
+}
137
+EXPORT_SYMBOL(mlxsw_core_res_query_enabled);
138
+
139
+bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core)
140
+{
141
+ return mlxsw_core->driver->temp_warn_enabled;
142
+}
143
+
144
+bool
145
+mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
146
+ const struct mlxsw_fw_rev *req_rev)
147
+{
148
+ return rev->minor > req_rev->minor ||
149
+ (rev->minor == req_rev->minor &&
150
+ rev->subminor >= req_rev->subminor);
151
+}
152
+EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate);
153
+
125154 struct mlxsw_rx_listener_item {
126155 struct list_head list;
127156 struct mlxsw_rx_listener rxl;
128157 void *priv;
158
+ bool enabled;
129159 };
130160
131161 struct mlxsw_event_listener_item {
....@@ -234,6 +264,25 @@
234264 */
235265 MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64);
236266
267
+/* emad_string_tlv_type
268
+ * Type of the TLV.
269
+ * Must be set to 0x2 (string TLV).
270
+ */
271
+MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5);
272
+
273
+/* emad_string_tlv_len
274
+ * Length of the string TLV in u32.
275
+ */
276
+MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11);
277
+
278
+#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128
279
+
280
+/* emad_string_tlv_string
281
+ * String provided by the device's firmware in case of erroneous register access
282
+ */
283
+MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04,
284
+ MLXSW_EMAD_STRING_TLV_STRING_LEN);
285
+
237286 /* emad_reg_tlv_type
238287 * Type of the TLV.
239288 * Must be set to 0x3 (register TLV).
....@@ -289,6 +338,12 @@
289338 memcpy(reg_tlv + sizeof(u32), payload, reg->len);
290339 }
291340
341
+static void mlxsw_emad_pack_string_tlv(char *string_tlv)
342
+{
343
+ mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING);
344
+ mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN);
345
+}
346
+
292347 static void mlxsw_emad_pack_op_tlv(char *op_tlv,
293348 const struct mlxsw_reg_info *reg,
294349 enum mlxsw_core_reg_access_type type,
....@@ -330,7 +385,7 @@
330385 const struct mlxsw_reg_info *reg,
331386 char *payload,
332387 enum mlxsw_core_reg_access_type type,
333
- u64 tid)
388
+ u64 tid, bool enable_string_tlv)
334389 {
335390 char *buf;
336391
....@@ -340,26 +395,82 @@
340395 buf = skb_push(skb, reg->len + sizeof(u32));
341396 mlxsw_emad_pack_reg_tlv(buf, reg, payload);
342397
398
+ if (enable_string_tlv) {
399
+ buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32));
400
+ mlxsw_emad_pack_string_tlv(buf);
401
+ }
402
+
343403 buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32));
344404 mlxsw_emad_pack_op_tlv(buf, reg, type, tid);
345405
346406 mlxsw_emad_construct_eth_hdr(skb);
347407 }
348408
409
+struct mlxsw_emad_tlv_offsets {
410
+ u16 op_tlv;
411
+ u16 string_tlv;
412
+ u16 reg_tlv;
413
+};
414
+
415
+static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv)
416
+{
417
+ u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv);
418
+
419
+ return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING;
420
+}
421
+
422
+static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
423
+{
424
+ struct mlxsw_emad_tlv_offsets *offsets =
425
+ (struct mlxsw_emad_tlv_offsets *) skb->cb;
426
+
427
+ offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN;
428
+ offsets->string_tlv = 0;
429
+ offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN +
430
+ MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
431
+
432
+ /* If string TLV is present, it must come after the operation TLV. */
433
+ if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) {
434
+ offsets->string_tlv = offsets->reg_tlv;
435
+ offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
436
+ }
437
+}
438
+
349439 static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
350440 {
351
- return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN));
441
+ struct mlxsw_emad_tlv_offsets *offsets =
442
+ (struct mlxsw_emad_tlv_offsets *) skb->cb;
443
+
444
+ return ((char *) (skb->data + offsets->op_tlv));
445
+}
446
+
447
+static char *mlxsw_emad_string_tlv(const struct sk_buff *skb)
448
+{
449
+ struct mlxsw_emad_tlv_offsets *offsets =
450
+ (struct mlxsw_emad_tlv_offsets *) skb->cb;
451
+
452
+ if (!offsets->string_tlv)
453
+ return NULL;
454
+
455
+ return ((char *) (skb->data + offsets->string_tlv));
352456 }
353457
354458 static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb)
355459 {
356
- return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN +
357
- MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)));
460
+ struct mlxsw_emad_tlv_offsets *offsets =
461
+ (struct mlxsw_emad_tlv_offsets *) skb->cb;
462
+
463
+ return ((char *) (skb->data + offsets->reg_tlv));
358464 }
359465
360
-static char *mlxsw_emad_reg_payload(const char *op_tlv)
466
+static char *mlxsw_emad_reg_payload(const char *reg_tlv)
361467 {
362
- return ((char *) (op_tlv + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
468
+ return ((char *) (reg_tlv + sizeof(u32)));
469
+}
470
+
471
+static char *mlxsw_emad_reg_payload_cmd(const char *mbox)
472
+{
473
+ return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
363474 }
364475
365476 static u64 mlxsw_emad_get_tid(const struct sk_buff *skb)
....@@ -425,9 +536,30 @@
425536 const struct mlxsw_reg_info *reg;
426537 enum mlxsw_core_reg_access_type type;
427538 int err;
539
+ char *emad_err_string;
428540 enum mlxsw_emad_op_tlv_status emad_status;
429541 struct rcu_head rcu;
430542 };
543
+
544
+static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb,
545
+ struct mlxsw_reg_trans *trans)
546
+{
547
+ char *string_tlv;
548
+ char *string;
549
+
550
+ string_tlv = mlxsw_emad_string_tlv(skb);
551
+ if (!string_tlv)
552
+ return;
553
+
554
+ trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN,
555
+ GFP_ATOMIC);
556
+ if (!trans->emad_err_string)
557
+ return;
558
+
559
+ string = mlxsw_emad_string_tlv_string_data(string_tlv);
560
+ strlcpy(trans->emad_err_string, string,
561
+ MLXSW_EMAD_STRING_TLV_STRING_LEN);
562
+}
431563
432564 #define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000
433565 #define MLXSW_EMAD_TIMEOUT_MS 200
....@@ -524,12 +656,14 @@
524656 mlxsw_emad_transmit_retry(mlxsw_core, trans);
525657 } else {
526658 if (err == 0) {
527
- char *op_tlv = mlxsw_emad_op_tlv(skb);
659
+ char *reg_tlv = mlxsw_emad_reg_tlv(skb);
528660
529661 if (trans->cb)
530662 trans->cb(mlxsw_core,
531
- mlxsw_emad_reg_payload(op_tlv),
663
+ mlxsw_emad_reg_payload(reg_tlv),
532664 trans->reg->len, trans->cb_priv);
665
+ } else {
666
+ mlxsw_emad_process_string_tlv(skb, trans);
533667 }
534668 mlxsw_emad_trans_finish(trans, err);
535669 }
....@@ -544,6 +678,8 @@
544678
545679 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0,
546680 skb->data, skb->len);
681
+
682
+ mlxsw_emad_tlv_parse(skb);
547683
548684 if (!mlxsw_emad_is_resp(skb))
549685 goto free_skb;
....@@ -621,7 +757,7 @@
621757 }
622758
623759 static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
624
- u16 reg_len)
760
+ u16 reg_len, bool enable_string_tlv)
625761 {
626762 struct sk_buff *skb;
627763 u16 emad_len;
....@@ -629,6 +765,8 @@
629765 emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
630766 (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
631767 sizeof(u32) + mlxsw_core->driver->txhdr_len);
768
+ if (enable_string_tlv)
769
+ emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
632770 if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
633771 return NULL;
634772
....@@ -650,6 +788,7 @@
650788 mlxsw_reg_trans_cb_t *cb,
651789 unsigned long cb_priv, u64 tid)
652790 {
791
+ bool enable_string_tlv;
653792 struct sk_buff *skb;
654793 int err;
655794
....@@ -657,7 +796,12 @@
657796 tid, reg->id, mlxsw_reg_id_str(reg->id),
658797 mlxsw_core_reg_access_type_str(type));
659798
660
- skb = mlxsw_emad_alloc(mlxsw_core, reg->len);
799
+ /* Since this can be changed during emad_reg_access, read it once and
800
+ * use the value all the way.
801
+ */
802
+ enable_string_tlv = mlxsw_core->emad.enable_string_tlv;
803
+
804
+ skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv);
661805 if (!skb)
662806 return -ENOMEM;
663807
....@@ -674,7 +818,8 @@
674818 trans->reg = reg;
675819 trans->type = type;
676820
677
- mlxsw_emad_construct(skb, reg, payload, type, trans->tid);
821
+ mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
822
+ enable_string_tlv);
678823 mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
679824
680825 spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
....@@ -736,6 +881,294 @@
736881 return mlxsw_driver;
737882 }
738883
884
+struct mlxsw_core_fw_info {
885
+ struct mlxfw_dev mlxfw_dev;
886
+ struct mlxsw_core *mlxsw_core;
887
+};
888
+
889
+static int mlxsw_core_fw_component_query(struct mlxfw_dev *mlxfw_dev,
890
+ u16 component_index, u32 *p_max_size,
891
+ u8 *p_align_bits, u16 *p_max_write_size)
892
+{
893
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
894
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
895
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
896
+ char mcqi_pl[MLXSW_REG_MCQI_LEN];
897
+ int err;
898
+
899
+ mlxsw_reg_mcqi_pack(mcqi_pl, component_index);
900
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcqi), mcqi_pl);
901
+ if (err)
902
+ return err;
903
+ mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, p_max_write_size);
904
+
905
+ *p_align_bits = max_t(u8, *p_align_bits, 2);
906
+ *p_max_write_size = min_t(u16, *p_max_write_size, MLXSW_REG_MCDA_MAX_DATA_LEN);
907
+ return 0;
908
+}
909
+
910
+static int mlxsw_core_fw_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
911
+{
912
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
913
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
914
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
915
+ char mcc_pl[MLXSW_REG_MCC_LEN];
916
+ u8 control_state;
917
+ int err;
918
+
919
+ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0);
920
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
921
+ if (err)
922
+ return err;
923
+
924
+ mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state);
925
+ if (control_state != MLXFW_FSM_STATE_IDLE)
926
+ return -EBUSY;
927
+
928
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, 0, *fwhandle, 0);
929
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
930
+}
931
+
932
+static int mlxsw_core_fw_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
933
+ u16 component_index, u32 component_size)
934
+{
935
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
936
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
937
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
938
+ char mcc_pl[MLXSW_REG_MCC_LEN];
939
+
940
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
941
+ component_index, fwhandle, component_size);
942
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
943
+}
944
+
945
+static int mlxsw_core_fw_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
946
+ u8 *data, u16 size, u32 offset)
947
+{
948
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
949
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
950
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
951
+ char mcda_pl[MLXSW_REG_MCDA_LEN];
952
+
953
+ mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data);
954
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcda), mcda_pl);
955
+}
956
+
957
+static int mlxsw_core_fw_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
958
+ u16 component_index)
959
+{
960
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
961
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
962
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
963
+ char mcc_pl[MLXSW_REG_MCC_LEN];
964
+
965
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
966
+ component_index, fwhandle, 0);
967
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
968
+}
969
+
970
+static int mlxsw_core_fw_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
971
+{
972
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
973
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
974
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
975
+ char mcc_pl[MLXSW_REG_MCC_LEN];
976
+
977
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, 0, fwhandle, 0);
978
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
979
+}
980
+
981
+static int mlxsw_core_fw_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
982
+ enum mlxfw_fsm_state *fsm_state,
983
+ enum mlxfw_fsm_state_err *fsm_state_err)
984
+{
985
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
986
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
987
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
988
+ char mcc_pl[MLXSW_REG_MCC_LEN];
989
+ u8 control_state;
990
+ u8 error_code;
991
+ int err;
992
+
993
+ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0);
994
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
995
+ if (err)
996
+ return err;
997
+
998
+ mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state);
999
+ *fsm_state = control_state;
1000
+ *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, MLXFW_FSM_STATE_ERR_MAX);
1001
+ return 0;
1002
+}
1003
+
1004
+static void mlxsw_core_fw_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
1005
+{
1006
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
1007
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
1008
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
1009
+ char mcc_pl[MLXSW_REG_MCC_LEN];
1010
+
1011
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
1012
+ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
1013
+}
1014
+
1015
+static void mlxsw_core_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
1016
+{
1017
+ struct mlxsw_core_fw_info *mlxsw_core_fw_info =
1018
+ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
1019
+ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
1020
+ char mcc_pl[MLXSW_REG_MCC_LEN];
1021
+
1022
+ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, fwhandle, 0);
1023
+ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
1024
+}
1025
+
1026
+static const struct mlxfw_dev_ops mlxsw_core_fw_mlxsw_dev_ops = {
1027
+ .component_query = mlxsw_core_fw_component_query,
1028
+ .fsm_lock = mlxsw_core_fw_fsm_lock,
1029
+ .fsm_component_update = mlxsw_core_fw_fsm_component_update,
1030
+ .fsm_block_download = mlxsw_core_fw_fsm_block_download,
1031
+ .fsm_component_verify = mlxsw_core_fw_fsm_component_verify,
1032
+ .fsm_activate = mlxsw_core_fw_fsm_activate,
1033
+ .fsm_query_state = mlxsw_core_fw_fsm_query_state,
1034
+ .fsm_cancel = mlxsw_core_fw_fsm_cancel,
1035
+ .fsm_release = mlxsw_core_fw_fsm_release,
1036
+};
1037
+
1038
+static int mlxsw_core_fw_flash(struct mlxsw_core *mlxsw_core, const struct firmware *firmware,
1039
+ struct netlink_ext_ack *extack)
1040
+{
1041
+ struct mlxsw_core_fw_info mlxsw_core_fw_info = {
1042
+ .mlxfw_dev = {
1043
+ .ops = &mlxsw_core_fw_mlxsw_dev_ops,
1044
+ .psid = mlxsw_core->bus_info->psid,
1045
+ .psid_size = strlen(mlxsw_core->bus_info->psid),
1046
+ .devlink = priv_to_devlink(mlxsw_core),
1047
+ },
1048
+ .mlxsw_core = mlxsw_core
1049
+ };
1050
+ int err;
1051
+
1052
+ mlxsw_core->fw_flash_in_progress = true;
1053
+ err = mlxfw_firmware_flash(&mlxsw_core_fw_info.mlxfw_dev, firmware, extack);
1054
+ mlxsw_core->fw_flash_in_progress = false;
1055
+
1056
+ return err;
1057
+}
1058
+
1059
+static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core,
1060
+ const struct mlxsw_bus_info *mlxsw_bus_info,
1061
+ const struct mlxsw_fw_rev *req_rev,
1062
+ const char *filename)
1063
+{
1064
+ const struct mlxsw_fw_rev *rev = &mlxsw_bus_info->fw_rev;
1065
+ union devlink_param_value value;
1066
+ const struct firmware *firmware;
1067
+ int err;
1068
+
1069
+ /* Don't check if driver does not require it */
1070
+ if (!req_rev || !filename)
1071
+ return 0;
1072
+
1073
+ /* Don't check if devlink 'fw_load_policy' param is 'flash' */
1074
+ err = devlink_param_driverinit_value_get(priv_to_devlink(mlxsw_core),
1075
+ DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
1076
+ &value);
1077
+ if (err)
1078
+ return err;
1079
+ if (value.vu8 == DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH)
1080
+ return 0;
1081
+
1082
+ /* Validate driver & FW are compatible */
1083
+ if (rev->major != req_rev->major) {
1084
+ WARN(1, "Mismatch in major FW version [%d:%d] is never expected; Please contact support\n",
1085
+ rev->major, req_rev->major);
1086
+ return -EINVAL;
1087
+ }
1088
+ if (mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev))
1089
+ return 0;
1090
+
1091
+ dev_err(mlxsw_bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
1092
+ rev->major, rev->minor, rev->subminor, req_rev->major,
1093
+ req_rev->minor, req_rev->subminor);
1094
+ dev_info(mlxsw_bus_info->dev, "Flashing firmware using file %s\n", filename);
1095
+
1096
+ err = request_firmware_direct(&firmware, filename, mlxsw_bus_info->dev);
1097
+ if (err) {
1098
+ dev_err(mlxsw_bus_info->dev, "Could not request firmware file %s\n", filename);
1099
+ return err;
1100
+ }
1101
+
1102
+ err = mlxsw_core_fw_flash(mlxsw_core, firmware, NULL);
1103
+ release_firmware(firmware);
1104
+ if (err)
1105
+ dev_err(mlxsw_bus_info->dev, "Could not upgrade firmware\n");
1106
+
1107
+ /* On FW flash success, tell the caller FW reset is needed
1108
+ * if current FW supports it.
1109
+ */
1110
+ if (rev->minor >= req_rev->can_reset_minor)
1111
+ return err ? err : -EAGAIN;
1112
+ else
1113
+ return 0;
1114
+}
1115
+
1116
+static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core,
1117
+ struct devlink_flash_update_params *params,
1118
+ struct netlink_ext_ack *extack)
1119
+{
1120
+ const struct firmware *firmware;
1121
+ int err;
1122
+
1123
+ err = request_firmware_direct(&firmware, params->file_name, mlxsw_core->bus_info->dev);
1124
+ if (err)
1125
+ return err;
1126
+ err = mlxsw_core_fw_flash(mlxsw_core, firmware, extack);
1127
+ release_firmware(firmware);
1128
+
1129
+ return err;
1130
+}
1131
+
1132
+static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id,
1133
+ union devlink_param_value val,
1134
+ struct netlink_ext_ack *extack)
1135
+{
1136
+ if (val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER &&
1137
+ val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) {
1138
+ NL_SET_ERR_MSG_MOD(extack, "'fw_load_policy' must be 'driver' or 'flash'");
1139
+ return -EINVAL;
1140
+ }
1141
+
1142
+ return 0;
1143
+}
1144
+
1145
+static const struct devlink_param mlxsw_core_fw_devlink_params[] = {
1146
+ DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL,
1147
+ mlxsw_core_devlink_param_fw_load_policy_validate),
1148
+};
1149
+
1150
+static int mlxsw_core_fw_params_register(struct mlxsw_core *mlxsw_core)
1151
+{
1152
+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
1153
+ union devlink_param_value value;
1154
+ int err;
1155
+
1156
+ err = devlink_params_register(devlink, mlxsw_core_fw_devlink_params,
1157
+ ARRAY_SIZE(mlxsw_core_fw_devlink_params));
1158
+ if (err)
1159
+ return err;
1160
+
1161
+ value.vu8 = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER;
1162
+ devlink_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY, value);
1163
+ return 0;
1164
+}
1165
+
1166
+static void mlxsw_core_fw_params_unregister(struct mlxsw_core *mlxsw_core)
1167
+{
1168
+ devlink_params_unregister(priv_to_devlink(mlxsw_core), mlxsw_core_fw_devlink_params,
1169
+ ARRAY_SIZE(mlxsw_core_fw_devlink_params));
1170
+}
1171
+
7391172 static int mlxsw_devlink_port_split(struct devlink *devlink,
7401173 unsigned int port_index,
7411174 unsigned int count,
....@@ -786,7 +1219,8 @@
7861219 static int
7871220 mlxsw_devlink_sb_pool_set(struct devlink *devlink,
7881221 unsigned int sb_index, u16 pool_index, u32 size,
789
- enum devlink_sb_threshold_type threshold_type)
1222
+ enum devlink_sb_threshold_type threshold_type,
1223
+ struct netlink_ext_ack *extack)
7901224 {
7911225 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
7921226 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
....@@ -794,7 +1228,8 @@
7941228 if (!mlxsw_driver->sb_pool_set)
7951229 return -EOPNOTSUPP;
7961230 return mlxsw_driver->sb_pool_set(mlxsw_core, sb_index,
797
- pool_index, size, threshold_type);
1231
+ pool_index, size, threshold_type,
1232
+ extack);
7981233 }
7991234
8001235 static void *__dl_port(struct devlink_port *devlink_port)
....@@ -834,7 +1269,8 @@
8341269
8351270 static int mlxsw_devlink_sb_port_pool_set(struct devlink_port *devlink_port,
8361271 unsigned int sb_index, u16 pool_index,
837
- u32 threshold)
1272
+ u32 threshold,
1273
+ struct netlink_ext_ack *extack)
8381274 {
8391275 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
8401276 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
....@@ -844,7 +1280,7 @@
8441280 !mlxsw_core_port_check(mlxsw_core_port))
8451281 return -EOPNOTSUPP;
8461282 return mlxsw_driver->sb_port_pool_set(mlxsw_core_port, sb_index,
847
- pool_index, threshold);
1283
+ pool_index, threshold, extack);
8481284 }
8491285
8501286 static int
....@@ -869,7 +1305,8 @@
8691305 mlxsw_devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
8701306 unsigned int sb_index, u16 tc_index,
8711307 enum devlink_sb_pool_type pool_type,
872
- u16 pool_index, u32 threshold)
1308
+ u16 pool_index, u32 threshold,
1309
+ struct netlink_ext_ack *extack)
8731310 {
8741311 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
8751312 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
....@@ -880,7 +1317,7 @@
8801317 return -EOPNOTSUPP;
8811318 return mlxsw_driver->sb_tc_pool_bind_set(mlxsw_core_port, sb_index,
8821319 tc_index, pool_type,
883
- pool_index, threshold);
1320
+ pool_index, threshold, extack);
8841321 }
8851322
8861323 static int mlxsw_devlink_sb_occ_snapshot(struct devlink *devlink,
....@@ -939,27 +1376,206 @@
9391376 pool_type, p_cur, p_max);
9401377 }
9411378
942
-static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink,
943
- struct netlink_ext_ack *extack)
1379
+static int
1380
+mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
1381
+ struct netlink_ext_ack *extack)
9441382 {
9451383 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1384
+ char fw_info_psid[MLXSW_REG_MGIR_FW_INFO_PSID_SIZE];
1385
+ u32 hw_rev, fw_major, fw_minor, fw_sub_minor;
1386
+ char mgir_pl[MLXSW_REG_MGIR_LEN];
1387
+ char buf[32];
9461388 int err;
1389
+
1390
+ err = devlink_info_driver_name_put(req,
1391
+ mlxsw_core->bus_info->device_kind);
1392
+ if (err)
1393
+ return err;
1394
+
1395
+ mlxsw_reg_mgir_pack(mgir_pl);
1396
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl);
1397
+ if (err)
1398
+ return err;
1399
+ mlxsw_reg_mgir_unpack(mgir_pl, &hw_rev, fw_info_psid, &fw_major,
1400
+ &fw_minor, &fw_sub_minor);
1401
+
1402
+ sprintf(buf, "%X", hw_rev);
1403
+ err = devlink_info_version_fixed_put(req, "hw.revision", buf);
1404
+ if (err)
1405
+ return err;
1406
+
1407
+ err = devlink_info_version_fixed_put(req, "fw.psid", fw_info_psid);
1408
+ if (err)
1409
+ return err;
1410
+
1411
+ sprintf(buf, "%d.%d.%d", fw_major, fw_minor, fw_sub_minor);
1412
+ err = devlink_info_version_running_put(req, "fw.version", buf);
1413
+ if (err)
1414
+ return err;
1415
+
1416
+ return 0;
1417
+}
1418
+
1419
+static int
1420
+mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink,
1421
+ bool netns_change, enum devlink_reload_action action,
1422
+ enum devlink_reload_limit limit,
1423
+ struct netlink_ext_ack *extack)
1424
+{
1425
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
9471426
9481427 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_RESET))
9491428 return -EOPNOTSUPP;
9501429
9511430 mlxsw_core_bus_device_unregister(mlxsw_core, true);
952
- err = mlxsw_core_bus_device_register(mlxsw_core->bus_info,
953
- mlxsw_core->bus,
954
- mlxsw_core->bus_priv, true,
955
- devlink);
956
- mlxsw_core->reload_fail = !!err;
1431
+ return 0;
1432
+}
9571433
958
- return err;
1434
+static int
1435
+mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink, enum devlink_reload_action action,
1436
+ enum devlink_reload_limit limit, u32 *actions_performed,
1437
+ struct netlink_ext_ack *extack)
1438
+{
1439
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1440
+
1441
+ *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
1442
+ BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE);
1443
+ return mlxsw_core_bus_device_register(mlxsw_core->bus_info,
1444
+ mlxsw_core->bus,
1445
+ mlxsw_core->bus_priv, true,
1446
+ devlink, extack);
1447
+}
1448
+
1449
+static int mlxsw_devlink_flash_update(struct devlink *devlink,
1450
+ struct devlink_flash_update_params *params,
1451
+ struct netlink_ext_ack *extack)
1452
+{
1453
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1454
+
1455
+ return mlxsw_core_fw_flash_update(mlxsw_core, params, extack);
1456
+}
1457
+
1458
+static int mlxsw_devlink_trap_init(struct devlink *devlink,
1459
+ const struct devlink_trap *trap,
1460
+ void *trap_ctx)
1461
+{
1462
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1463
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1464
+
1465
+ if (!mlxsw_driver->trap_init)
1466
+ return -EOPNOTSUPP;
1467
+ return mlxsw_driver->trap_init(mlxsw_core, trap, trap_ctx);
1468
+}
1469
+
1470
+static void mlxsw_devlink_trap_fini(struct devlink *devlink,
1471
+ const struct devlink_trap *trap,
1472
+ void *trap_ctx)
1473
+{
1474
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1475
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1476
+
1477
+ if (!mlxsw_driver->trap_fini)
1478
+ return;
1479
+ mlxsw_driver->trap_fini(mlxsw_core, trap, trap_ctx);
1480
+}
1481
+
1482
+static int mlxsw_devlink_trap_action_set(struct devlink *devlink,
1483
+ const struct devlink_trap *trap,
1484
+ enum devlink_trap_action action,
1485
+ struct netlink_ext_ack *extack)
1486
+{
1487
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1488
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1489
+
1490
+ if (!mlxsw_driver->trap_action_set)
1491
+ return -EOPNOTSUPP;
1492
+ return mlxsw_driver->trap_action_set(mlxsw_core, trap, action, extack);
1493
+}
1494
+
1495
+static int
1496
+mlxsw_devlink_trap_group_init(struct devlink *devlink,
1497
+ const struct devlink_trap_group *group)
1498
+{
1499
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1500
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1501
+
1502
+ if (!mlxsw_driver->trap_group_init)
1503
+ return -EOPNOTSUPP;
1504
+ return mlxsw_driver->trap_group_init(mlxsw_core, group);
1505
+}
1506
+
1507
+static int
1508
+mlxsw_devlink_trap_group_set(struct devlink *devlink,
1509
+ const struct devlink_trap_group *group,
1510
+ const struct devlink_trap_policer *policer,
1511
+ struct netlink_ext_ack *extack)
1512
+{
1513
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1514
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1515
+
1516
+ if (!mlxsw_driver->trap_group_set)
1517
+ return -EOPNOTSUPP;
1518
+ return mlxsw_driver->trap_group_set(mlxsw_core, group, policer, extack);
1519
+}
1520
+
1521
+static int
1522
+mlxsw_devlink_trap_policer_init(struct devlink *devlink,
1523
+ const struct devlink_trap_policer *policer)
1524
+{
1525
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1526
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1527
+
1528
+ if (!mlxsw_driver->trap_policer_init)
1529
+ return -EOPNOTSUPP;
1530
+ return mlxsw_driver->trap_policer_init(mlxsw_core, policer);
1531
+}
1532
+
1533
+static void
1534
+mlxsw_devlink_trap_policer_fini(struct devlink *devlink,
1535
+ const struct devlink_trap_policer *policer)
1536
+{
1537
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1538
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1539
+
1540
+ if (!mlxsw_driver->trap_policer_fini)
1541
+ return;
1542
+ mlxsw_driver->trap_policer_fini(mlxsw_core, policer);
1543
+}
1544
+
1545
+static int
1546
+mlxsw_devlink_trap_policer_set(struct devlink *devlink,
1547
+ const struct devlink_trap_policer *policer,
1548
+ u64 rate, u64 burst,
1549
+ struct netlink_ext_ack *extack)
1550
+{
1551
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1552
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1553
+
1554
+ if (!mlxsw_driver->trap_policer_set)
1555
+ return -EOPNOTSUPP;
1556
+ return mlxsw_driver->trap_policer_set(mlxsw_core, policer, rate, burst,
1557
+ extack);
1558
+}
1559
+
1560
+static int
1561
+mlxsw_devlink_trap_policer_counter_get(struct devlink *devlink,
1562
+ const struct devlink_trap_policer *policer,
1563
+ u64 *p_drops)
1564
+{
1565
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1566
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1567
+
1568
+ if (!mlxsw_driver->trap_policer_counter_get)
1569
+ return -EOPNOTSUPP;
1570
+ return mlxsw_driver->trap_policer_counter_get(mlxsw_core, policer,
1571
+ p_drops);
9591572 }
9601573
9611574 static const struct devlink_ops mlxsw_devlink_ops = {
962
- .reload = mlxsw_devlink_core_bus_device_reload,
1575
+ .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
1576
+ BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
1577
+ .reload_down = mlxsw_devlink_core_bus_device_reload_down,
1578
+ .reload_up = mlxsw_devlink_core_bus_device_reload_up,
9631579 .port_type_set = mlxsw_devlink_port_type_set,
9641580 .port_split = mlxsw_devlink_port_split,
9651581 .port_unsplit = mlxsw_devlink_port_unsplit,
....@@ -973,12 +1589,282 @@
9731589 .sb_occ_max_clear = mlxsw_devlink_sb_occ_max_clear,
9741590 .sb_occ_port_pool_get = mlxsw_devlink_sb_occ_port_pool_get,
9751591 .sb_occ_tc_port_bind_get = mlxsw_devlink_sb_occ_tc_port_bind_get,
1592
+ .info_get = mlxsw_devlink_info_get,
1593
+ .flash_update = mlxsw_devlink_flash_update,
1594
+ .trap_init = mlxsw_devlink_trap_init,
1595
+ .trap_fini = mlxsw_devlink_trap_fini,
1596
+ .trap_action_set = mlxsw_devlink_trap_action_set,
1597
+ .trap_group_init = mlxsw_devlink_trap_group_init,
1598
+ .trap_group_set = mlxsw_devlink_trap_group_set,
1599
+ .trap_policer_init = mlxsw_devlink_trap_policer_init,
1600
+ .trap_policer_fini = mlxsw_devlink_trap_policer_fini,
1601
+ .trap_policer_set = mlxsw_devlink_trap_policer_set,
1602
+ .trap_policer_counter_get = mlxsw_devlink_trap_policer_counter_get,
9761603 };
9771604
978
-int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
979
- const struct mlxsw_bus *mlxsw_bus,
980
- void *bus_priv, bool reload,
981
- struct devlink *devlink)
1605
+static int mlxsw_core_params_register(struct mlxsw_core *mlxsw_core)
1606
+{
1607
+ int err;
1608
+
1609
+ err = mlxsw_core_fw_params_register(mlxsw_core);
1610
+ if (err)
1611
+ return err;
1612
+
1613
+ if (mlxsw_core->driver->params_register) {
1614
+ err = mlxsw_core->driver->params_register(mlxsw_core);
1615
+ if (err)
1616
+ goto err_params_register;
1617
+ }
1618
+ return 0;
1619
+
1620
+err_params_register:
1621
+ mlxsw_core_fw_params_unregister(mlxsw_core);
1622
+ return err;
1623
+}
1624
+
1625
+static void mlxsw_core_params_unregister(struct mlxsw_core *mlxsw_core)
1626
+{
1627
+ mlxsw_core_fw_params_unregister(mlxsw_core);
1628
+ if (mlxsw_core->driver->params_register)
1629
+ mlxsw_core->driver->params_unregister(mlxsw_core);
1630
+}
1631
+
1632
+struct mlxsw_core_health_event {
1633
+ struct mlxsw_core *mlxsw_core;
1634
+ char mfde_pl[MLXSW_REG_MFDE_LEN];
1635
+ struct work_struct work;
1636
+};
1637
+
1638
+static void mlxsw_core_health_event_work(struct work_struct *work)
1639
+{
1640
+ struct mlxsw_core_health_event *event;
1641
+ struct mlxsw_core *mlxsw_core;
1642
+
1643
+ event = container_of(work, struct mlxsw_core_health_event, work);
1644
+ mlxsw_core = event->mlxsw_core;
1645
+ devlink_health_report(mlxsw_core->health.fw_fatal, "FW fatal event occurred",
1646
+ event->mfde_pl);
1647
+ kfree(event);
1648
+}
1649
+
1650
+static void mlxsw_core_health_listener_func(const struct mlxsw_reg_info *reg,
1651
+ char *mfde_pl, void *priv)
1652
+{
1653
+ struct mlxsw_core_health_event *event;
1654
+ struct mlxsw_core *mlxsw_core = priv;
1655
+
1656
+ event = kmalloc(sizeof(*event), GFP_ATOMIC);
1657
+ if (!event)
1658
+ return;
1659
+ event->mlxsw_core = mlxsw_core;
1660
+ memcpy(event->mfde_pl, mfde_pl, sizeof(event->mfde_pl));
1661
+ INIT_WORK(&event->work, mlxsw_core_health_event_work);
1662
+ mlxsw_core_schedule_work(&event->work);
1663
+}
1664
+
1665
+static const struct mlxsw_listener mlxsw_core_health_listener =
1666
+ MLXSW_EVENTL(mlxsw_core_health_listener_func, MFDE, MFDE);
1667
+
1668
+static int mlxsw_core_health_fw_fatal_dump(struct devlink_health_reporter *reporter,
1669
+ struct devlink_fmsg *fmsg, void *priv_ctx,
1670
+ struct netlink_ext_ack *extack)
1671
+{
1672
+ char *mfde_pl = priv_ctx;
1673
+ char *val_str;
1674
+ u8 event_id;
1675
+ u32 val;
1676
+ int err;
1677
+
1678
+ if (!priv_ctx)
1679
+ /* User-triggered dumps are not possible */
1680
+ return -EOPNOTSUPP;
1681
+
1682
+ val = mlxsw_reg_mfde_irisc_id_get(mfde_pl);
1683
+ err = devlink_fmsg_u8_pair_put(fmsg, "irisc_id", val);
1684
+ if (err)
1685
+ return err;
1686
+ err = devlink_fmsg_arr_pair_nest_start(fmsg, "event");
1687
+ if (err)
1688
+ return err;
1689
+
1690
+ event_id = mlxsw_reg_mfde_event_id_get(mfde_pl);
1691
+ err = devlink_fmsg_u8_pair_put(fmsg, "id", event_id);
1692
+ if (err)
1693
+ return err;
1694
+ switch (event_id) {
1695
+ case MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO:
1696
+ val_str = "CR space timeout";
1697
+ break;
1698
+ case MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP:
1699
+ val_str = "KVD insertion machine stopped";
1700
+ break;
1701
+ default:
1702
+ val_str = NULL;
1703
+ }
1704
+ if (val_str) {
1705
+ err = devlink_fmsg_string_pair_put(fmsg, "desc", val_str);
1706
+ if (err)
1707
+ return err;
1708
+ }
1709
+ err = devlink_fmsg_arr_pair_nest_end(fmsg);
1710
+ if (err)
1711
+ return err;
1712
+
1713
+ val = mlxsw_reg_mfde_method_get(mfde_pl);
1714
+ switch (val) {
1715
+ case MLXSW_REG_MFDE_METHOD_QUERY:
1716
+ val_str = "query";
1717
+ break;
1718
+ case MLXSW_REG_MFDE_METHOD_WRITE:
1719
+ val_str = "write";
1720
+ break;
1721
+ default:
1722
+ val_str = NULL;
1723
+ }
1724
+ if (val_str) {
1725
+ err = devlink_fmsg_string_pair_put(fmsg, "method", val_str);
1726
+ if (err)
1727
+ return err;
1728
+ }
1729
+
1730
+ val = mlxsw_reg_mfde_long_process_get(mfde_pl);
1731
+ err = devlink_fmsg_bool_pair_put(fmsg, "long_process", val);
1732
+ if (err)
1733
+ return err;
1734
+
1735
+ val = mlxsw_reg_mfde_command_type_get(mfde_pl);
1736
+ switch (val) {
1737
+ case MLXSW_REG_MFDE_COMMAND_TYPE_MAD:
1738
+ val_str = "mad";
1739
+ break;
1740
+ case MLXSW_REG_MFDE_COMMAND_TYPE_EMAD:
1741
+ val_str = "emad";
1742
+ break;
1743
+ case MLXSW_REG_MFDE_COMMAND_TYPE_CMDIF:
1744
+ val_str = "cmdif";
1745
+ break;
1746
+ default:
1747
+ val_str = NULL;
1748
+ }
1749
+ if (val_str) {
1750
+ err = devlink_fmsg_string_pair_put(fmsg, "command_type", val_str);
1751
+ if (err)
1752
+ return err;
1753
+ }
1754
+
1755
+ val = mlxsw_reg_mfde_reg_attr_id_get(mfde_pl);
1756
+ err = devlink_fmsg_u32_pair_put(fmsg, "reg_attr_id", val);
1757
+ if (err)
1758
+ return err;
1759
+
1760
+ if (event_id == MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO) {
1761
+ val = mlxsw_reg_mfde_log_address_get(mfde_pl);
1762
+ err = devlink_fmsg_u32_pair_put(fmsg, "log_address", val);
1763
+ if (err)
1764
+ return err;
1765
+ val = mlxsw_reg_mfde_log_id_get(mfde_pl);
1766
+ err = devlink_fmsg_u8_pair_put(fmsg, "log_irisc_id", val);
1767
+ if (err)
1768
+ return err;
1769
+ } else if (event_id == MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP) {
1770
+ val = mlxsw_reg_mfde_pipes_mask_get(mfde_pl);
1771
+ err = devlink_fmsg_u32_pair_put(fmsg, "pipes_mask", val);
1772
+ if (err)
1773
+ return err;
1774
+ }
1775
+
1776
+ return 0;
1777
+}
1778
+
1779
+static int
1780
+mlxsw_core_health_fw_fatal_test(struct devlink_health_reporter *reporter,
1781
+ struct netlink_ext_ack *extack)
1782
+{
1783
+ struct mlxsw_core *mlxsw_core = devlink_health_reporter_priv(reporter);
1784
+ char mfgd_pl[MLXSW_REG_MFGD_LEN];
1785
+ int err;
1786
+
1787
+ /* Read the register first to make sure no other bits are changed. */
1788
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1789
+ if (err)
1790
+ return err;
1791
+ mlxsw_reg_mfgd_trigger_test_set(mfgd_pl, true);
1792
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1793
+}
1794
+
1795
+static const struct devlink_health_reporter_ops
1796
+mlxsw_core_health_fw_fatal_ops = {
1797
+ .name = "fw_fatal",
1798
+ .dump = mlxsw_core_health_fw_fatal_dump,
1799
+ .test = mlxsw_core_health_fw_fatal_test,
1800
+};
1801
+
1802
+static int mlxsw_core_health_fw_fatal_config(struct mlxsw_core *mlxsw_core,
1803
+ bool enable)
1804
+{
1805
+ char mfgd_pl[MLXSW_REG_MFGD_LEN];
1806
+ int err;
1807
+
1808
+ /* Read the register first to make sure no other bits are changed. */
1809
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1810
+ if (err)
1811
+ return err;
1812
+ mlxsw_reg_mfgd_fatal_event_mode_set(mfgd_pl, enable);
1813
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1814
+}
1815
+
1816
+static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core)
1817
+{
1818
+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
1819
+ struct devlink_health_reporter *fw_fatal;
1820
+ int err;
1821
+
1822
+ if (!mlxsw_core->driver->fw_fatal_enabled)
1823
+ return 0;
1824
+
1825
+ fw_fatal = devlink_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops,
1826
+ 0, mlxsw_core);
1827
+ if (IS_ERR(fw_fatal)) {
1828
+ dev_err(mlxsw_core->bus_info->dev, "Failed to create fw fatal reporter");
1829
+ return PTR_ERR(fw_fatal);
1830
+ }
1831
+ mlxsw_core->health.fw_fatal = fw_fatal;
1832
+
1833
+ err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1834
+ if (err)
1835
+ goto err_trap_register;
1836
+
1837
+ err = mlxsw_core_health_fw_fatal_config(mlxsw_core, true);
1838
+ if (err)
1839
+ goto err_fw_fatal_config;
1840
+
1841
+ return 0;
1842
+
1843
+err_fw_fatal_config:
1844
+ mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1845
+err_trap_register:
1846
+ devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
1847
+ return err;
1848
+}
1849
+
1850
+static void mlxsw_core_health_fini(struct mlxsw_core *mlxsw_core)
1851
+{
1852
+ if (!mlxsw_core->driver->fw_fatal_enabled)
1853
+ return;
1854
+
1855
+ mlxsw_core_health_fw_fatal_config(mlxsw_core, false);
1856
+ mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1857
+ /* Make sure there is no more event work scheduled */
1858
+ mlxsw_core_flush_owq();
1859
+ devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
1860
+}
1861
+
1862
+static int
1863
+__mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1864
+ const struct mlxsw_bus *mlxsw_bus,
1865
+ void *bus_priv, bool reload,
1866
+ struct devlink *devlink,
1867
+ struct netlink_ext_ack *extack)
9821868 {
9831869 const char *device_kind = mlxsw_bus_info->device_kind;
9841870 struct mlxsw_core *mlxsw_core;
....@@ -1045,6 +1931,27 @@
10451931 goto err_devlink_register;
10461932 }
10471933
1934
+ if (!reload) {
1935
+ err = mlxsw_core_params_register(mlxsw_core);
1936
+ if (err)
1937
+ goto err_register_params;
1938
+ }
1939
+
1940
+ err = mlxsw_core_fw_rev_validate(mlxsw_core, mlxsw_bus_info, mlxsw_driver->fw_req_rev,
1941
+ mlxsw_driver->fw_filename);
1942
+ if (err)
1943
+ goto err_fw_rev_validate;
1944
+
1945
+ err = mlxsw_core_health_init(mlxsw_core);
1946
+ if (err)
1947
+ goto err_health_init;
1948
+
1949
+ if (mlxsw_driver->init) {
1950
+ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
1951
+ if (err)
1952
+ goto err_driver_init;
1953
+ }
1954
+
10481955 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
10491956 if (err)
10501957 goto err_hwmon_init;
....@@ -1054,19 +1961,32 @@
10541961 if (err)
10551962 goto err_thermal_init;
10561963
1057
- if (mlxsw_driver->init) {
1058
- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info);
1059
- if (err)
1060
- goto err_driver_init;
1061
- }
1964
+ err = mlxsw_env_init(mlxsw_core, &mlxsw_core->env);
1965
+ if (err)
1966
+ goto err_env_init;
1967
+
1968
+ mlxsw_core->is_initialized = true;
1969
+ devlink_params_publish(devlink);
1970
+
1971
+ if (!reload)
1972
+ devlink_reload_enable(devlink);
10621973
10631974 return 0;
10641975
1065
-err_driver_init:
1976
+err_env_init:
10661977 mlxsw_thermal_fini(mlxsw_core->thermal);
10671978 err_thermal_init:
10681979 mlxsw_hwmon_fini(mlxsw_core->hwmon);
10691980 err_hwmon_init:
1981
+ if (mlxsw_core->driver->fini)
1982
+ mlxsw_core->driver->fini(mlxsw_core);
1983
+err_driver_init:
1984
+ mlxsw_core_health_fini(mlxsw_core);
1985
+err_health_init:
1986
+err_fw_rev_validate:
1987
+ if (!reload)
1988
+ mlxsw_core_params_unregister(mlxsw_core);
1989
+err_register_params:
10701990 if (!reload)
10711991 devlink_unregister(devlink);
10721992 err_devlink_register:
....@@ -1086,6 +2006,31 @@
10862006 err_devlink_alloc:
10872007 return err;
10882008 }
2009
+
2010
+int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
2011
+ const struct mlxsw_bus *mlxsw_bus,
2012
+ void *bus_priv, bool reload,
2013
+ struct devlink *devlink,
2014
+ struct netlink_ext_ack *extack)
2015
+{
2016
+ bool called_again = false;
2017
+ int err;
2018
+
2019
+again:
2020
+ err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus,
2021
+ bus_priv, reload,
2022
+ devlink, extack);
2023
+ /* -EAGAIN is returned in case the FW was updated. FW needs
2024
+ * a reset, so lets try to call __mlxsw_core_bus_device_register()
2025
+ * again.
2026
+ */
2027
+ if (err == -EAGAIN && !called_again) {
2028
+ called_again = true;
2029
+ goto again;
2030
+ }
2031
+
2032
+ return err;
2033
+}
10892034 EXPORT_SYMBOL(mlxsw_core_bus_device_register);
10902035
10912036 void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
....@@ -1093,7 +2038,9 @@
10932038 {
10942039 struct devlink *devlink = priv_to_devlink(mlxsw_core);
10952040
1096
- if (mlxsw_core->reload_fail) {
2041
+ if (!reload)
2042
+ devlink_reload_disable(devlink);
2043
+ if (devlink_is_reload_failed(devlink)) {
10972044 if (!reload)
10982045 /* Only the parts that were not de-initialized in the
10992046 * failed reload attempt need to be de-initialized.
....@@ -1103,10 +2050,16 @@
11032050 return;
11042051 }
11052052
1106
- if (mlxsw_core->driver->fini)
1107
- mlxsw_core->driver->fini(mlxsw_core);
2053
+ devlink_params_unpublish(devlink);
2054
+ mlxsw_core->is_initialized = false;
2055
+ mlxsw_env_fini(mlxsw_core->env);
11082056 mlxsw_thermal_fini(mlxsw_core->thermal);
11092057 mlxsw_hwmon_fini(mlxsw_core->hwmon);
2058
+ if (mlxsw_core->driver->fini)
2059
+ mlxsw_core->driver->fini(mlxsw_core);
2060
+ mlxsw_core_health_fini(mlxsw_core);
2061
+ if (!reload)
2062
+ mlxsw_core_params_unregister(mlxsw_core);
11102063 if (!reload)
11112064 devlink_unregister(devlink);
11122065 mlxsw_emad_fini(mlxsw_core);
....@@ -1121,6 +2074,7 @@
11212074 return;
11222075
11232076 reload_fail_deinit:
2077
+ mlxsw_core_params_unregister(mlxsw_core);
11242078 devlink_unregister(devlink);
11252079 devlink_resources_unregister(devlink, NULL);
11262080 devlink_free(devlink);
....@@ -1143,24 +2097,32 @@
11432097 }
11442098 EXPORT_SYMBOL(mlxsw_core_skb_transmit);
11452099
2100
+void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
2101
+ struct sk_buff *skb, u8 local_port)
2102
+{
2103
+ if (mlxsw_core->driver->ptp_transmitted)
2104
+ mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb,
2105
+ local_port);
2106
+}
2107
+EXPORT_SYMBOL(mlxsw_core_ptp_transmitted);
2108
+
11462109 static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
11472110 const struct mlxsw_rx_listener *rxl_b)
11482111 {
11492112 return (rxl_a->func == rxl_b->func &&
11502113 rxl_a->local_port == rxl_b->local_port &&
1151
- rxl_a->trap_id == rxl_b->trap_id);
2114
+ rxl_a->trap_id == rxl_b->trap_id &&
2115
+ rxl_a->mirror_reason == rxl_b->mirror_reason);
11522116 }
11532117
11542118 static struct mlxsw_rx_listener_item *
11552119 __find_rx_listener_item(struct mlxsw_core *mlxsw_core,
1156
- const struct mlxsw_rx_listener *rxl,
1157
- void *priv)
2120
+ const struct mlxsw_rx_listener *rxl)
11582121 {
11592122 struct mlxsw_rx_listener_item *rxl_item;
11602123
11612124 list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) {
1162
- if (__is_rx_listener_equal(&rxl_item->rxl, rxl) &&
1163
- rxl_item->priv == priv)
2125
+ if (__is_rx_listener_equal(&rxl_item->rxl, rxl))
11642126 return rxl_item;
11652127 }
11662128 return NULL;
....@@ -1168,11 +2130,11 @@
11682130
11692131 int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core,
11702132 const struct mlxsw_rx_listener *rxl,
1171
- void *priv)
2133
+ void *priv, bool enabled)
11722134 {
11732135 struct mlxsw_rx_listener_item *rxl_item;
11742136
1175
- rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv);
2137
+ rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
11762138 if (rxl_item)
11772139 return -EEXIST;
11782140 rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL);
....@@ -1180,6 +2142,7 @@
11802142 return -ENOMEM;
11812143 rxl_item->rxl = *rxl;
11822144 rxl_item->priv = priv;
2145
+ rxl_item->enabled = enabled;
11832146
11842147 list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list);
11852148 return 0;
....@@ -1187,12 +2150,11 @@
11872150 EXPORT_SYMBOL(mlxsw_core_rx_listener_register);
11882151
11892152 void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core,
1190
- const struct mlxsw_rx_listener *rxl,
1191
- void *priv)
2153
+ const struct mlxsw_rx_listener *rxl)
11922154 {
11932155 struct mlxsw_rx_listener_item *rxl_item;
11942156
1195
- rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv);
2157
+ rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
11962158 if (!rxl_item)
11972159 return;
11982160 list_del_rcu(&rxl_item->list);
....@@ -1201,18 +2163,35 @@
12012163 }
12022164 EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister);
12032165
2166
+static void
2167
+mlxsw_core_rx_listener_state_set(struct mlxsw_core *mlxsw_core,
2168
+ const struct mlxsw_rx_listener *rxl,
2169
+ bool enabled)
2170
+{
2171
+ struct mlxsw_rx_listener_item *rxl_item;
2172
+
2173
+ rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
2174
+ if (WARN_ON(!rxl_item))
2175
+ return;
2176
+ rxl_item->enabled = enabled;
2177
+}
2178
+
12042179 static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port,
12052180 void *priv)
12062181 {
12072182 struct mlxsw_event_listener_item *event_listener_item = priv;
12082183 struct mlxsw_reg_info reg;
12092184 char *payload;
1210
- char *op_tlv = mlxsw_emad_op_tlv(skb);
1211
- char *reg_tlv = mlxsw_emad_reg_tlv(skb);
2185
+ char *reg_tlv;
2186
+ char *op_tlv;
2187
+
2188
+ mlxsw_emad_tlv_parse(skb);
2189
+ op_tlv = mlxsw_emad_op_tlv(skb);
2190
+ reg_tlv = mlxsw_emad_reg_tlv(skb);
12122191
12132192 reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv);
12142193 reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32);
1215
- payload = mlxsw_emad_reg_payload(op_tlv);
2194
+ payload = mlxsw_emad_reg_payload(reg_tlv);
12162195 event_listener_item->el.func(&reg, payload, event_listener_item->priv);
12172196 dev_kfree_skb(skb);
12182197 }
....@@ -1226,14 +2205,12 @@
12262205
12272206 static struct mlxsw_event_listener_item *
12282207 __find_event_listener_item(struct mlxsw_core *mlxsw_core,
1229
- const struct mlxsw_event_listener *el,
1230
- void *priv)
2208
+ const struct mlxsw_event_listener *el)
12312209 {
12322210 struct mlxsw_event_listener_item *el_item;
12332211
12342212 list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) {
1235
- if (__is_event_listener_equal(&el_item->el, el) &&
1236
- el_item->priv == priv)
2213
+ if (__is_event_listener_equal(&el_item->el, el))
12372214 return el_item;
12382215 }
12392216 return NULL;
....@@ -1251,7 +2228,7 @@
12512228 .trap_id = el->trap_id,
12522229 };
12532230
1254
- el_item = __find_event_listener_item(mlxsw_core, el, priv);
2231
+ el_item = __find_event_listener_item(mlxsw_core, el);
12552232 if (el_item)
12562233 return -EEXIST;
12572234 el_item = kmalloc(sizeof(*el_item), GFP_KERNEL);
....@@ -1260,7 +2237,7 @@
12602237 el_item->el = *el;
12612238 el_item->priv = priv;
12622239
1263
- err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item);
2240
+ err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item, true);
12642241 if (err)
12652242 goto err_rx_listener_register;
12662243
....@@ -1278,8 +2255,7 @@
12782255 EXPORT_SYMBOL(mlxsw_core_event_listener_register);
12792256
12802257 void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core,
1281
- const struct mlxsw_event_listener *el,
1282
- void *priv)
2258
+ const struct mlxsw_event_listener *el)
12832259 {
12842260 struct mlxsw_event_listener_item *el_item;
12852261 const struct mlxsw_rx_listener rxl = {
....@@ -1288,10 +2264,10 @@
12882264 .trap_id = el->trap_id,
12892265 };
12902266
1291
- el_item = __find_event_listener_item(mlxsw_core, el, priv);
2267
+ el_item = __find_event_listener_item(mlxsw_core, el);
12922268 if (!el_item)
12932269 return;
1294
- mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl, el_item);
2270
+ mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl);
12952271 list_del(&el_item->list);
12962272 kfree(el_item);
12972273 }
....@@ -1299,16 +2275,18 @@
12992275
13002276 static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core,
13012277 const struct mlxsw_listener *listener,
1302
- void *priv)
2278
+ void *priv, bool enabled)
13032279 {
1304
- if (listener->is_event)
2280
+ if (listener->is_event) {
2281
+ WARN_ON(!enabled);
13052282 return mlxsw_core_event_listener_register(mlxsw_core,
1306
- &listener->u.event_listener,
2283
+ &listener->event_listener,
13072284 priv);
1308
- else
2285
+ } else {
13092286 return mlxsw_core_rx_listener_register(mlxsw_core,
1310
- &listener->u.rx_listener,
1311
- priv);
2287
+ &listener->rx_listener,
2288
+ priv, enabled);
2289
+ }
13122290 }
13132291
13142292 static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core,
....@@ -1317,26 +2295,31 @@
13172295 {
13182296 if (listener->is_event)
13192297 mlxsw_core_event_listener_unregister(mlxsw_core,
1320
- &listener->u.event_listener,
1321
- priv);
2298
+ &listener->event_listener);
13222299 else
13232300 mlxsw_core_rx_listener_unregister(mlxsw_core,
1324
- &listener->u.rx_listener,
1325
- priv);
2301
+ &listener->rx_listener);
13262302 }
13272303
13282304 int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core,
13292305 const struct mlxsw_listener *listener, void *priv)
13302306 {
2307
+ enum mlxsw_reg_htgt_trap_group trap_group;
2308
+ enum mlxsw_reg_hpkt_action action;
13312309 char hpkt_pl[MLXSW_REG_HPKT_LEN];
13322310 int err;
13332311
1334
- err = mlxsw_core_listener_register(mlxsw_core, listener, priv);
2312
+ err = mlxsw_core_listener_register(mlxsw_core, listener, priv,
2313
+ listener->enabled_on_register);
13352314 if (err)
13362315 return err;
13372316
1338
- mlxsw_reg_hpkt_pack(hpkt_pl, listener->action, listener->trap_id,
1339
- listener->trap_group, listener->is_ctrl);
2317
+ action = listener->enabled_on_register ? listener->en_action :
2318
+ listener->dis_action;
2319
+ trap_group = listener->enabled_on_register ? listener->en_trap_group :
2320
+ listener->dis_trap_group;
2321
+ mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
2322
+ trap_group, listener->is_ctrl);
13402323 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
13412324 if (err)
13422325 goto err_trap_set;
....@@ -1356,8 +2339,8 @@
13562339 char hpkt_pl[MLXSW_REG_HPKT_LEN];
13572340
13582341 if (!listener->is_event) {
1359
- mlxsw_reg_hpkt_pack(hpkt_pl, listener->unreg_action,
1360
- listener->trap_id, listener->trap_group,
2342
+ mlxsw_reg_hpkt_pack(hpkt_pl, listener->dis_action,
2343
+ listener->trap_id, listener->dis_trap_group,
13612344 listener->is_ctrl);
13622345 mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
13632346 }
....@@ -1365,6 +2348,34 @@
13652348 mlxsw_core_listener_unregister(mlxsw_core, listener, priv);
13662349 }
13672350 EXPORT_SYMBOL(mlxsw_core_trap_unregister);
2351
+
2352
+int mlxsw_core_trap_state_set(struct mlxsw_core *mlxsw_core,
2353
+ const struct mlxsw_listener *listener,
2354
+ bool enabled)
2355
+{
2356
+ enum mlxsw_reg_htgt_trap_group trap_group;
2357
+ enum mlxsw_reg_hpkt_action action;
2358
+ char hpkt_pl[MLXSW_REG_HPKT_LEN];
2359
+ int err;
2360
+
2361
+ /* Not supported for event listener */
2362
+ if (WARN_ON(listener->is_event))
2363
+ return -EINVAL;
2364
+
2365
+ action = enabled ? listener->en_action : listener->dis_action;
2366
+ trap_group = enabled ? listener->en_trap_group :
2367
+ listener->dis_trap_group;
2368
+ mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
2369
+ trap_group, listener->is_ctrl);
2370
+ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
2371
+ if (err)
2372
+ return err;
2373
+
2374
+ mlxsw_core_rx_listener_state_set(mlxsw_core, &listener->rx_listener,
2375
+ enabled);
2376
+ return 0;
2377
+}
2378
+EXPORT_SYMBOL(mlxsw_core_trap_state_set);
13682379
13692380 static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core)
13702381 {
....@@ -1418,8 +2429,11 @@
14182429 }
14192430 EXPORT_SYMBOL(mlxsw_reg_trans_write);
14202431
2432
+#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256
2433
+
14212434 static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
14222435 {
2436
+ char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE];
14232437 struct mlxsw_core *mlxsw_core = trans->core;
14242438 int err;
14252439
....@@ -1430,13 +2444,25 @@
14302444 if (trans->retries)
14312445 dev_warn(mlxsw_core->bus_info->dev, "EMAD retries (%d/%d) (tid=%llx)\n",
14322446 trans->retries, MLXSW_EMAD_MAX_RETRY, trans->tid);
1433
- if (err)
2447
+ if (err) {
14342448 dev_err(mlxsw_core->bus_info->dev, "EMAD reg access failed (tid=%llx,reg_id=%x(%s),type=%s,status=%x(%s))\n",
14352449 trans->tid, trans->reg->id,
14362450 mlxsw_reg_id_str(trans->reg->id),
14372451 mlxsw_core_reg_access_type_str(trans->type),
14382452 trans->emad_status,
14392453 mlxsw_emad_op_tlv_status_str(trans->emad_status));
2454
+
2455
+ snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE,
2456
+ "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid,
2457
+ trans->reg->id, mlxsw_reg_id_str(trans->reg->id),
2458
+ mlxsw_emad_op_tlv_status_str(trans->emad_status),
2459
+ trans->emad_err_string ? trans->emad_err_string : "");
2460
+
2461
+ trace_devlink_hwerr(priv_to_devlink(mlxsw_core),
2462
+ trans->emad_status, err_string);
2463
+
2464
+ kfree(trans->emad_err_string);
2465
+ }
14402466
14412467 list_del(&trans->bulk_list);
14422468 kfree_rcu(trans, rcu);
....@@ -1509,7 +2535,7 @@
15092535 }
15102536
15112537 if (!err)
1512
- memcpy(payload, mlxsw_emad_reg_payload(out_mbox),
2538
+ memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox),
15132539 reg->len);
15142540
15152541 mlxsw_cmd_mbox_free(out_mbox);
....@@ -1606,8 +2632,10 @@
16062632 rxl = &rxl_item->rxl;
16072633 if ((rxl->local_port == MLXSW_PORT_DONT_CARE ||
16082634 rxl->local_port == local_port) &&
1609
- rxl->trap_id == rx_info->trap_id) {
1610
- found = true;
2635
+ rxl->trap_id == rx_info->trap_id &&
2636
+ rxl->mirror_reason == rx_info->mirror_reason) {
2637
+ if (rxl_item->enabled)
2638
+ found = true;
16112639 break;
16122640 }
16132641 }
....@@ -1681,23 +2709,38 @@
16812709 }
16822710 EXPORT_SYMBOL(mlxsw_core_res_get);
16832711
1684
-int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port)
2712
+static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2713
+ enum devlink_port_flavour flavour,
2714
+ u32 port_number, bool split,
2715
+ u32 split_port_subnumber,
2716
+ bool splittable, u32 lanes,
2717
+ const unsigned char *switch_id,
2718
+ unsigned char switch_id_len)
16852719 {
16862720 struct devlink *devlink = priv_to_devlink(mlxsw_core);
16872721 struct mlxsw_core_port *mlxsw_core_port =
16882722 &mlxsw_core->ports[local_port];
16892723 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2724
+ struct devlink_port_attrs attrs = {};
16902725 int err;
16912726
2727
+ attrs.split = split;
2728
+ attrs.lanes = lanes;
2729
+ attrs.splittable = splittable;
2730
+ attrs.flavour = flavour;
2731
+ attrs.phys.port_number = port_number;
2732
+ attrs.phys.split_subport_number = split_port_subnumber;
2733
+ memcpy(attrs.switch_id.id, switch_id, switch_id_len);
2734
+ attrs.switch_id.id_len = switch_id_len;
16922735 mlxsw_core_port->local_port = local_port;
2736
+ devlink_port_attrs_set(devlink_port, &attrs);
16932737 err = devlink_port_register(devlink, devlink_port, local_port);
16942738 if (err)
16952739 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
16962740 return err;
16972741 }
1698
-EXPORT_SYMBOL(mlxsw_core_port_init);
16992742
1700
-void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
2743
+static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
17012744 {
17022745 struct mlxsw_core_port *mlxsw_core_port =
17032746 &mlxsw_core->ports[local_port];
....@@ -1706,20 +2749,63 @@
17062749 devlink_port_unregister(devlink_port);
17072750 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
17082751 }
2752
+
2753
+int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2754
+ u32 port_number, bool split,
2755
+ u32 split_port_subnumber,
2756
+ bool splittable, u32 lanes,
2757
+ const unsigned char *switch_id,
2758
+ unsigned char switch_id_len)
2759
+{
2760
+ return __mlxsw_core_port_init(mlxsw_core, local_port,
2761
+ DEVLINK_PORT_FLAVOUR_PHYSICAL,
2762
+ port_number, split, split_port_subnumber,
2763
+ splittable, lanes,
2764
+ switch_id, switch_id_len);
2765
+}
2766
+EXPORT_SYMBOL(mlxsw_core_port_init);
2767
+
2768
+void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
2769
+{
2770
+ __mlxsw_core_port_fini(mlxsw_core, local_port);
2771
+}
17092772 EXPORT_SYMBOL(mlxsw_core_port_fini);
17102773
2774
+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
2775
+ void *port_driver_priv,
2776
+ const unsigned char *switch_id,
2777
+ unsigned char switch_id_len)
2778
+{
2779
+ struct mlxsw_core_port *mlxsw_core_port =
2780
+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
2781
+ int err;
2782
+
2783
+ err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT,
2784
+ DEVLINK_PORT_FLAVOUR_CPU,
2785
+ 0, false, 0, false, 0,
2786
+ switch_id, switch_id_len);
2787
+ if (err)
2788
+ return err;
2789
+
2790
+ mlxsw_core_port->port_driver_priv = port_driver_priv;
2791
+ return 0;
2792
+}
2793
+EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
2794
+
2795
+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
2796
+{
2797
+ __mlxsw_core_port_fini(mlxsw_core, MLXSW_PORT_CPU_PORT);
2798
+}
2799
+EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
2800
+
17112801 void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
1712
- void *port_driver_priv, struct net_device *dev,
1713
- u32 port_number, bool split,
1714
- u32 split_port_subnumber)
2802
+ void *port_driver_priv, struct net_device *dev)
17152803 {
17162804 struct mlxsw_core_port *mlxsw_core_port =
17172805 &mlxsw_core->ports[local_port];
17182806 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
17192807
17202808 mlxsw_core_port->port_driver_priv = port_driver_priv;
1721
- devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
1722
- port_number, split, split_port_subnumber);
17232809 devlink_port_type_eth_set(devlink_port, dev);
17242810 }
17252811 EXPORT_SYMBOL(mlxsw_core_port_eth_set);
....@@ -1759,16 +2845,66 @@
17592845 }
17602846 EXPORT_SYMBOL(mlxsw_core_port_type_get);
17612847
1762
-int mlxsw_core_port_get_phys_port_name(struct mlxsw_core *mlxsw_core,
1763
- u8 local_port, char *name, size_t len)
2848
+
2849
+struct devlink_port *
2850
+mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
2851
+ u8 local_port)
17642852 {
17652853 struct mlxsw_core_port *mlxsw_core_port =
17662854 &mlxsw_core->ports[local_port];
17672855 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
17682856
1769
- return devlink_port_get_phys_port_name(devlink_port, name, len);
2857
+ return devlink_port;
17702858 }
1771
-EXPORT_SYMBOL(mlxsw_core_port_get_phys_port_name);
2859
+EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
2860
+
2861
+struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
2862
+{
2863
+ return mlxsw_core->env;
2864
+}
2865
+
2866
+bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
2867
+{
2868
+ return mlxsw_core->is_initialized;
2869
+}
2870
+
2871
+int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
2872
+{
2873
+ enum mlxsw_reg_pmtm_module_type module_type;
2874
+ char pmtm_pl[MLXSW_REG_PMTM_LEN];
2875
+ int err;
2876
+
2877
+ mlxsw_reg_pmtm_pack(pmtm_pl, module);
2878
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
2879
+ if (err)
2880
+ return err;
2881
+ mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
2882
+
2883
+ /* Here we need to get the module width according to the module type. */
2884
+
2885
+ switch (module_type) {
2886
+ case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X:
2887
+ case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD:
2888
+ case MLXSW_REG_PMTM_MODULE_TYPE_OSFP:
2889
+ return 8;
2890
+ case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X:
2891
+ case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X:
2892
+ case MLXSW_REG_PMTM_MODULE_TYPE_QSFP:
2893
+ return 4;
2894
+ case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X:
2895
+ case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
2896
+ case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD:
2897
+ case MLXSW_REG_PMTM_MODULE_TYPE_DSFP:
2898
+ return 2;
2899
+ case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X:
2900
+ case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
2901
+ case MLXSW_REG_PMTM_MODULE_TYPE_SFP:
2902
+ return 1;
2903
+ default:
2904
+ return -EINVAL;
2905
+ }
2906
+}
2907
+EXPORT_SYMBOL(mlxsw_core_module_max_width);
17722908
17732909 static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
17742910 const char *buf, size_t size)
....@@ -1868,17 +3004,60 @@
18683004 }
18693005 EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);
18703006
1871
-void mlxsw_core_fw_flash_start(struct mlxsw_core *mlxsw_core)
3007
+int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox,
3008
+ struct mlxsw_res *res)
18723009 {
1873
- mlxsw_core->fw_flash_in_progress = true;
1874
-}
1875
-EXPORT_SYMBOL(mlxsw_core_fw_flash_start);
3010
+ int index, i;
3011
+ u64 data;
3012
+ u16 id;
3013
+ int err;
18763014
1877
-void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core)
1878
-{
1879
- mlxsw_core->fw_flash_in_progress = false;
3015
+ if (!res)
3016
+ return 0;
3017
+
3018
+ mlxsw_cmd_mbox_zero(mbox);
3019
+
3020
+ for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES;
3021
+ index++) {
3022
+ err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index);
3023
+ if (err)
3024
+ return err;
3025
+
3026
+ for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) {
3027
+ id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i);
3028
+ data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i);
3029
+
3030
+ if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID)
3031
+ return 0;
3032
+
3033
+ mlxsw_res_parse(res, id, data);
3034
+ }
3035
+ }
3036
+
3037
+ /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get
3038
+ * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW.
3039
+ */
3040
+ return -EIO;
18803041 }
1881
-EXPORT_SYMBOL(mlxsw_core_fw_flash_end);
3042
+EXPORT_SYMBOL(mlxsw_core_resources_query);
3043
+
3044
+u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core)
3045
+{
3046
+ return mlxsw_core->bus->read_frc_h(mlxsw_core->bus_priv);
3047
+}
3048
+EXPORT_SYMBOL(mlxsw_core_read_frc_h);
3049
+
3050
+u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
3051
+{
3052
+ return mlxsw_core->bus->read_frc_l(mlxsw_core->bus_priv);
3053
+}
3054
+EXPORT_SYMBOL(mlxsw_core_read_frc_l);
3055
+
3056
+void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core)
3057
+{
3058
+ mlxsw_core->emad.enable_string_tlv = true;
3059
+}
3060
+EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable);
18823061
18833062 static int __init mlxsw_core_module_init(void)
18843063 {