History

Merge tag 'mlx5-updates-2019-06-13' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says: ==================== mlx5-updates-2019-06-13 Mlx5 devlink health fw reporters and sw reset support This series provides mlx5 firmware reset support and firmware devlink health reporters. 1) Add initial mlx5 kernel documentation and include devlink health reporters 2) Add CR-Space access and FW Crdump snapshot support via devlink region_snapshot 3) Issue software reset upon FW asserts 4) Add fw and fw_fatal devlink heath reporters to follow fw errors indication by dump and recover procedures and enable trigger these functionality by user. 4.1) fw reporter: The fw reporter implements diagnose and dump callbacks. It follows symptoms of fw error such as fw syndrome by triggering fw core dump and storing it and any other fw trace into the dump buffer. The fw reporter diagnose command can be triggered any time by the user to check current fw status. 4.2) fw_fatal repoter: The fw_fatal reporter implements dump and recover callbacks. It follows fatal errors indications by CR-space dump and recover flow. The CR-space dump uses vsc interface which is valid even if the FW command interface is not functional, which is the case in most FW fatal errors. The CR-space dump is stored as a memory region snapshot to ease read by address. The recover function runs recover flow which reloads the driver and triggers fw reset if needed. ====================

David S. Miller committed 7 years ago

Commit b4a6d9a2 parents 363887a 06efeb519 files · +1516 −144Browse files

Unified · Split

19 files
  1. Documentation/networking/device_drivers/index.rst +1 −0
  2. Documentation/networking/device_drivers/mellanox/mlx5.rst +173 −0
  3. MAINTAINERS +1 −0
  4. drivers/net/ethernet/mellanox/mlx5/core/Makefile +2 −1
  5. drivers/net/ethernet/mellanox/mlx5/core/devlink.c +58 −0
  6. drivers/net/ethernet/mellanox/mlx5/core/devlink.h +14 −0
  7. drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c +115 −0
  8. drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +139 −0
  9. drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h +20 −0
  10. drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +1 −1
  11. drivers/net/ethernet/mellanox/mlx5/core/health.c +496 −73
  12. drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +3 −0
  13. drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c +316 −0
  14. drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h +32 −0
  15. drivers/net/ethernet/mellanox/mlx5/core/main.c +21 −44
  16. drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +7 −1
  17. include/linux/mlx5/device.h +9 −1
  18. include/linux/mlx5/driver.h +10 −3
  19. net/core/devlink.c +98 −20
Documentation/networking/device_drivers/index.rst+1−0
@@ -21,6 +21,7 @@ Contents: · 20 unmodified lines
21 intel/i40e21 intel/i40e
22 intel/iavf22 intel/iavf
23 intel/ice23 intel/ice
24 mellanox/mlx5
24 25
25.. only:: subproject26.. only:: subproject
26 27
Documentation/networking/device_drivers/mellanox/mlx5.rst+173−0
@@ -0,0 +1,173 @@
1.. SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2
3=================================================
4Mellanox ConnectX(R) mlx5 core VPI Network Driver
5=================================================
6
7Copyright (c) 2019, Mellanox Technologies LTD.
8
9Contents
10========
11
12- `Enabling the driver and kconfig options`_
13- `Devlink health reporters`_
14
15Enabling the driver and kconfig options
16================================================
17
18| mlx5 core is modular and most of the major mlx5 core driver features can be selected (compiled in/out)
19| at build time via kernel Kconfig flags.
20| Basic features, ethernet net device rx/tx offloads and XDP, are available with the most basic flags
21| CONFIG_MLX5_CORE=y/m and CONFIG_MLX5_CORE_EN=y.
22| For the list of advanced features please see below.
23
24**CONFIG_MLX5_CORE=(y/m/n)** (module mlx5_core.ko)
25
26| The driver can be enabled by choosing CONFIG_MLX5_CORE=y/m in kernel config.
27| This will provide mlx5 core driver for mlx5 ulps to interface with (mlx5e, mlx5_ib).
28
29
30**CONFIG_MLX5_CORE_EN=(y/n)**
31
32| Choosing this option will allow basic ethernet netdevice support with all of the standard rx/tx offloads.
33| mlx5e is the mlx5 ulp driver which provides netdevice kernel interface, when chosen, mlx5e will be
34| built-in into mlx5_core.ko.
35
36
37**CONFIG_MLX5_EN_ARFS=(y/n)**
38
39| Enables Hardware-accelerated receive flow steering (arfs) support, and ntuple filtering.
40| https://community.mellanox.com/s/article/howto-configure-arfs-on-connectx-4
41
42
43**CONFIG_MLX5_EN_RXNFC=(y/n)**
44
45| Enables ethtool receive network flow classification, which allows user defined
46| flow rules to direct traffic into arbitrary rx queue via ethtool set/get_rxnfc API.
47
48
49**CONFIG_MLX5_CORE_EN_DCB=(y/n)**:
50
51| Enables `Data Center Bridging (DCB) Support <https://community.mellanox.com/s/article/howto-auto-config-pfc-and-ets-on-connectx-4-via-lldp-dcbx>`_.
52
53
54**CONFIG_MLX5_MPFS=(y/n)**
55
56| Ethernet Multi-Physical Function Switch (MPFS) support in ConnectX NIC.
57| MPFs is required for when `Multi-Host <http://www.mellanox.com/page/multihost>`_ configuration is enabled to allow passing
58| user configured unicast MAC addresses to the requesting PF.
59
60
61**CONFIG_MLX5_ESWITCH=(y/n)**
62
63| Ethernet SRIOV E-Switch support in ConnectX NIC. E-Switch provides internal SRIOV packet steering
64| and switching for the enabled VFs and PF in two available modes:
65| 1) `Legacy SRIOV mode (L2 mac vlan steering based) <https://community.mellanox.com/s/article/howto-configure-sr-iov-for-connectx-4-connectx-5-with-kvm--ethernet-x>`_.
66| 2) `Switchdev mode (eswitch offloads) <https://www.mellanox.com/related-docs/prod_software/ASAP2_Hardware_Offloading_for_vSwitches_User_Manual_v4.4.pdf>`_.
67
68
69**CONFIG_MLX5_CORE_IPOIB=(y/n)**
70
71| IPoIB offloads & acceleration support.
72| Requires CONFIG_MLX5_CORE_EN to provide an accelerated interface for the rdma
73| IPoIB ulp netdevice.
74
75
76**CONFIG_MLX5_FPGA=(y/n)**
77
78| Build support for the Innova family of network cards by Mellanox Technologies.
79| Innova network cards are comprised of a ConnectX chip and an FPGA chip on one board.
80| If you select this option, the mlx5_core driver will include the Innova FPGA core and allow
81| building sandbox-specific client drivers.
82
83
84**CONFIG_MLX5_EN_IPSEC=(y/n)**
85
86| Enables `IPSec XFRM cryptography-offload accelaration <http://www.mellanox.com/related-docs/prod_software/Mellanox_Innova_IPsec_Ethernet_Adapter_Card_User_Manual.pdf>`_.
87
88**CONFIG_MLX5_EN_TLS=(y/n)**
89
90| TLS cryptography-offload accelaration.
91
92
93**CONFIG_MLX5_INFINIBAND=(y/n/m)** (module mlx5_ib.ko)
94
95| Provides low-level InfiniBand/RDMA and `RoCE <https://community.mellanox.com/s/article/recommended-network-configuration-examples-for-roce-deployment>`_ support.
96
97
98**External options** ( Choose if the corresponding mlx5 feature is required )
99
100- CONFIG_PTP_1588_CLOCK: When chosen, mlx5 ptp support will be enabled
101- CONFIG_VXLAN: When chosen, mlx5 vxaln support will be enabled.
102- CONFIG_MLXFW: When chosen, mlx5 firmware flashing support will be enabled (via devlink and ethtool).
103
104
105Devlink health reporters
106========================
107
108tx reporter
109-----------
110The tx reporter is responsible of two error scenarios:
111
112- TX timeout
113 Report on kernel tx timeout detection.
114 Recover by searching lost interrupts.
115- TX error completion
116 Report on error tx completion.
117 Recover by flushing the TX queue and reset it.
118
119TX reporter also support Diagnose callback, on which it provides
120real time information of its send queues status.
121
122User commands examples:
123
124- Diagnose send queues status::
125
126 $ devlink health diagnose pci/0000:82:00.0 reporter tx
127
128- Show number of tx errors indicated, number of recover flows ended successfully,
129 is autorecover enabled and graceful period from last recover::
130
131 $ devlink health show pci/0000:82:00.0 reporter tx
132
133fw reporter
134-----------
135The fw reporter implements diagnose and dump callbacks.
136It follows symptoms of fw error such as fw syndrome by triggering
137fw core dump and storing it into the dump buffer.
138The fw reporter diagnose command can be triggered any time by the user to check
139current fw status.
140
141User commands examples:
142
143- Check fw heath status::
144
145 $ devlink health diagnose pci/0000:82:00.0 reporter fw
146
147- Read FW core dump if already stored or trigger new one::
148
149 $ devlink health dump show pci/0000:82:00.0 reporter fw
150
151NOTE: This command can run only on the PF which has fw tracer ownership,
152running it on other PF or any VF will return "Operation not permitted".
153
154fw fatal reporter
155-----------------
156The fw fatal reporter implements dump and recover callbacks.
157It follows fatal errors indications by CR-space dump and recover flow.
158The CR-space dump uses vsc interface which is valid even if the FW command
159interface is not functional, which is the case in most FW fatal errors.
160The recover function runs recover flow which reloads the driver and triggers fw
161reset if needed.
162
163User commands examples:
164
165- Run fw recover flow manually::
166
167 $ devlink health recover pci/0000:82:00.0 reporter fw_fatal
168
169- Read FW CR-space dump if already strored or trigger new one::
170
171 $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal
172
173NOTE: This command can run only on PF.
MAINTAINERS+1−0
@@ -10108,6 +10108,7 @@ Q: http://patchwork.ozlabs.org/project/netdev/list/ · 10107 unmodified lines
10108S: Supported10108S: Supported
10109F: drivers/net/ethernet/mellanox/mlx5/core/10109F: drivers/net/ethernet/mellanox/mlx5/core/
10110F: include/linux/mlx5/10110F: include/linux/mlx5/
10111F: Documentation/networking/device_drivers/mellanox/
10111 10112
10112MELLANOX MLX5 IB driver10113MELLANOX MLX5 IB driver
10113M: Leon Romanovsky <leonro@mellanox.com>10114M: Leon Romanovsky <leonro@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/Makefile+2−1
@@ -15,7 +15,8 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ · 14 unmodified lines
15 health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \15 health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \
16 transobj.o vport.o sriov.o fs_cmd.o fs_core.o \16 transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
17 fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \17 fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
18 lib/devcom.o diag/fs_tracepoint.o diag/fw_tracer.o18 lib/devcom.o lib/pci_vsc.o diag/fs_tracepoint.o \
19 diag/fw_tracer.o diag/crdump.o devlink.o
19 20
20#21#
21# Netdev basic22# Netdev basic
drivers/net/ethernet/mellanox/mlx5/core/devlink.c+58−0
@@ -0,0 +1,58 @@
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#include <devlink.h>
5
6#include "mlx5_core.h"
7#include "eswitch.h"
8
9static int mlx5_devlink_flash_update(struct devlink *devlink,
10 const char *file_name,
11 const char *component,
12 struct netlink_ext_ack *extack)
13{
14 struct mlx5_core_dev *dev = devlink_priv(devlink);
15 const struct firmware *fw;
16 int err;
17
18 if (component)
19 return -EOPNOTSUPP;
20
21 err = request_firmware_direct(&fw, file_name, &dev->pdev->dev);
22 if (err)
23 return err;
24
25 return mlx5_firmware_flash(dev, fw, extack);
26}
27
28static const struct devlink_ops mlx5_devlink_ops = {
29#ifdef CONFIG_MLX5_ESWITCH
30 .eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
31 .eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
32 .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
33 .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
34 .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,
35 .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
36#endif
37 .flash_update = mlx5_devlink_flash_update,
38};
39
40struct devlink *mlx5_devlink_alloc()
41{
42 return devlink_alloc(&mlx5_devlink_ops, sizeof(struct mlx5_core_dev));
43}
44
45void mlx5_devlink_free(struct devlink *devlink)
46{
47 devlink_free(devlink);
48}
49
50int mlx5_devlink_register(struct devlink *devlink, struct device *dev)
51{
52 return devlink_register(devlink, dev);
53}
54
55void mlx5_devlink_unregister(struct devlink *devlink)
56{
57 devlink_unregister(devlink);
58}
drivers/net/ethernet/mellanox/mlx5/core/devlink.h+14−0
@@ -0,0 +1,14 @@
1/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2/* Copyright (c) 2019, Mellanox Technologies */
3
4#ifndef __MLX5_DEVLINK_H__
5#define __MLX5_DEVLINK_H__
6
7#include <net/devlink.h>
8
9struct devlink *mlx5_devlink_alloc(void);
10void mlx5_devlink_free(struct devlink *devlink);
11int mlx5_devlink_register(struct devlink *devlink, struct device *dev);
12void mlx5_devlink_unregister(struct devlink *devlink);
13
14#endif /* __MLX5_DEVLINK_H__ */
drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c+115−0
@@ -0,0 +1,115 @@
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#include <linux/mlx5/driver.h>
5#include "mlx5_core.h"
6#include "lib/pci_vsc.h"
7#include "lib/mlx5.h"
8
9#define BAD_ACCESS 0xBADACCE5
10#define MLX5_PROTECTED_CR_SCAN_CRSPACE 0x7
11
12static bool mlx5_crdump_enabled(struct mlx5_core_dev *dev)
13{
14 return !!dev->priv.health.crdump_size;
15}
16
17static int mlx5_crdump_fill(struct mlx5_core_dev *dev, u32 *cr_data)
18{
19 u32 crdump_size = dev->priv.health.crdump_size;
20 int i, ret;
21
22 for (i = 0; i < (crdump_size / 4); i++)
23 cr_data[i] = BAD_ACCESS;
24
25 ret = mlx5_vsc_gw_read_block_fast(dev, cr_data, crdump_size);
26 if (ret <= 0) {
27 if (ret == 0)
28 return -EIO;
29 return ret;
30 }
31
32 if (crdump_size != ret) {
33 mlx5_core_warn(dev, "failed to read full dump, read %d out of %u\n",
34 ret, crdump_size);
35 return -EINVAL;
36 }
37
38 return 0;
39}
40
41int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data)
42{
43 int ret;
44
45 if (!mlx5_crdump_enabled(dev))
46 return -ENODEV;
47
48 ret = mlx5_vsc_gw_lock(dev);
49 if (ret) {
50 mlx5_core_warn(dev, "crdump: failed to lock vsc gw err %d\n",
51 ret);
52 return ret;
53 }
54 /* Verify no other PF is running cr-dump or sw reset */
55 ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET,
56 MLX5_VSC_LOCK);
57 if (ret) {
58 mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
59 goto unlock_gw;
60 }
61
62 ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE, NULL);
63 if (ret)
64 goto unlock_sem;
65
66 ret = mlx5_crdump_fill(dev, cr_data);
67
68unlock_sem:
69 mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, MLX5_VSC_UNLOCK);
70unlock_gw:
71 mlx5_vsc_gw_unlock(dev);
72 return ret;
73}
74
75int mlx5_crdump_enable(struct mlx5_core_dev *dev)
76{
77 struct mlx5_priv *priv = &dev->priv;
78 u32 space_size;
79 int ret;
80
81 if (!mlx5_core_is_pf(dev) || !mlx5_vsc_accessible(dev) ||
82 mlx5_crdump_enabled(dev))
83 return 0;
84
85 ret = mlx5_vsc_gw_lock(dev);
86 if (ret)
87 return ret;
88
89 /* Check if space is supported and get space size */
90 ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE,
91 &space_size);
92 if (ret) {
93 /* Unlock and mask error since space is not supported */
94 mlx5_vsc_gw_unlock(dev);
95 return 0;
96 }
97
98 if (!space_size) {
99 mlx5_core_warn(dev, "Invalid Crspace size, zero\n");
100 mlx5_vsc_gw_unlock(dev);
101 return -EINVAL;
102 }
103
104 ret = mlx5_vsc_gw_unlock(dev);
105 if (ret)
106 return ret;
107
108 priv->health.crdump_size = space_size;
109 return 0;
110}
111
112void mlx5_crdump_disable(struct mlx5_core_dev *dev)
113{
114 dev->priv.health.crdump_size = 0;
115}
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c+139−0
@@ -243,6 +243,19 @@ free_strings_db: · 242 unmodified lines
243 return -ENOMEM;243 return -ENOMEM;
244}244}
245 245
246static void
247mlx5_fw_tracer_init_saved_traces_array(struct mlx5_fw_tracer *tracer)
248{
249 tracer->st_arr.saved_traces_index = 0;
250 mutex_init(&tracer->st_arr.lock);
251}
252
253static void
254mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer)
255{
256 mutex_destroy(&tracer->st_arr.lock);
257}
258
246static void mlx5_tracer_read_strings_db(struct work_struct *work)259static void mlx5_tracer_read_strings_db(struct work_struct *work)
247{260{
248 struct mlx5_fw_tracer *tracer = container_of(work, struct mlx5_fw_tracer,261 struct mlx5_fw_tracer *tracer = container_of(work, struct mlx5_fw_tracer,
@@ -522,6 +535,24 @@ static void mlx5_fw_tracer_clean_ready_list(struct mlx5_fw_tracer *tracer) · 273 unmodified lines
522 list_del(&str_frmt->list);535 list_del(&str_frmt->list);
523}536}
524 537
538static void mlx5_fw_tracer_save_trace(struct mlx5_fw_tracer *tracer,
539 u64 timestamp, bool lost,
540 u8 event_id, char *msg)
541{
542 struct mlx5_fw_trace_data *trace_data;
543
544 mutex_lock(&tracer->st_arr.lock);
545 trace_data = &tracer->st_arr.straces[tracer->st_arr.saved_traces_index];
546 trace_data->timestamp = timestamp;
547 trace_data->lost = lost;
548 trace_data->event_id = event_id;
549 strncpy(trace_data->msg, msg, TRACE_STR_MSG);
550
551 tracer->st_arr.saved_traces_index =
552 (tracer->st_arr.saved_traces_index + 1) & (SAVED_TRACES_NUM - 1);
553 mutex_unlock(&tracer->st_arr.lock);
554}
555
525static void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,556static void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
526 struct mlx5_core_dev *dev,557 struct mlx5_core_dev *dev,
527 u64 trace_timestamp)558 u64 trace_timestamp)
@@ -540,6 +571,9 @@ static void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt, · 12 unmodified lines
540 trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost,571 trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost,
541 str_frmt->event_id, tmp);572 str_frmt->event_id, tmp);
542 573
574 mlx5_fw_tracer_save_trace(dev->tracer, trace_timestamp,
575 str_frmt->lost, str_frmt->event_id, tmp);
576
543 /* remove it from hash */577 /* remove it from hash */
544 mlx5_tracer_clean_message(str_frmt);578 mlx5_tracer_clean_message(str_frmt);
545}579}
@@ -786,6 +820,109 @@ static void mlx5_fw_tracer_ownership_change(struct work_struct *work) · 240 unmodified lines
786 mlx5_fw_tracer_start(tracer);820 mlx5_fw_tracer_start(tracer);
787}821}
788 822
823static int mlx5_fw_tracer_set_core_dump_reg(struct mlx5_core_dev *dev,
824 u32 *in, int size_in)
825{
826 u32 out[MLX5_ST_SZ_DW(core_dump_reg)] = {};
827
828 if (!MLX5_CAP_DEBUG(dev, core_dump_general) &&
829 !MLX5_CAP_DEBUG(dev, core_dump_qp))
830 return -EOPNOTSUPP;
831
832 return mlx5_core_access_reg(dev, in, size_in, out, sizeof(out),
833 MLX5_REG_CORE_DUMP, 0, 1);
834}
835
836int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev)
837{
838 struct mlx5_fw_tracer *tracer = dev->tracer;
839 u32 in[MLX5_ST_SZ_DW(core_dump_reg)] = {};
840 int err;
841
842 if (!MLX5_CAP_DEBUG(dev, core_dump_general) || !tracer)
843 return -EOPNOTSUPP;
844 if (!tracer->owner)
845 return -EPERM;
846
847 MLX5_SET(core_dump_reg, in, core_dump_type, 0x0);
848
849 err = mlx5_fw_tracer_set_core_dump_reg(dev, in, sizeof(in));
850 if (err)
851 return err;
852 queue_work(tracer->work_queue, &tracer->handle_traces_work);
853 flush_workqueue(tracer->work_queue);
854 return 0;
855}
856
857static int
858mlx5_devlink_fmsg_fill_trace(struct devlink_fmsg *fmsg,
859 struct mlx5_fw_trace_data *trace_data)
860{
861 int err;
862
863 err = devlink_fmsg_obj_nest_start(fmsg);
864 if (err)
865 return err;
866
867 err = devlink_fmsg_u64_pair_put(fmsg, "timestamp", trace_data->timestamp);
868 if (err)
869 return err;
870
871 err = devlink_fmsg_bool_pair_put(fmsg, "lost", trace_data->lost);
872 if (err)
873 return err;
874
875 err = devlink_fmsg_u8_pair_put(fmsg, "event_id", trace_data->event_id);
876 if (err)
877 return err;
878
879 err = devlink_fmsg_string_pair_put(fmsg, "msg", trace_data->msg);
880 if (err)
881 return err;
882
883 err = devlink_fmsg_obj_nest_end(fmsg);
884 if (err)
885 return err;
886 return 0;
887}
888
889int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
890 struct devlink_fmsg *fmsg)
891{
892 struct mlx5_fw_trace_data *straces = tracer->st_arr.straces;
893 u32 index, start_index, end_index;
894 u32 saved_traces_index;
895 int err;
896
897 if (!straces[0].timestamp)
898 return -ENOMSG;
899
900 mutex_lock(&tracer->st_arr.lock);
901 saved_traces_index = tracer->st_arr.saved_traces_index;
902 if (straces[saved_traces_index].timestamp)
903 start_index = saved_traces_index;
904 else
905 start_index = 0;
906 end_index = (saved_traces_index - 1) & (SAVED_TRACES_NUM - 1);
907
908 err = devlink_fmsg_arr_pair_nest_start(fmsg, "dump fw traces");
909 if (err)
910 goto unlock;
911 index = start_index;
912 while (index != end_index) {
913 err = mlx5_devlink_fmsg_fill_trace(fmsg, &straces[index]);
914 if (err)
915 goto unlock;
916
917 index = (index + 1) & (SAVED_TRACES_NUM - 1);
918 }
919
920 err = devlink_fmsg_arr_pair_nest_end(fmsg);
921unlock:
922 mutex_unlock(&tracer->st_arr.lock);
923 return err;
924}
925
789/* Create software resources (Buffers, etc ..) */926/* Create software resources (Buffers, etc ..) */
790struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)927struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
791{928{
@@ -833,6 +970,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev) · 41 unmodified lines
833 goto free_log_buf;970 goto free_log_buf;
834 }971 }
835 972
973 mlx5_fw_tracer_init_saved_traces_array(tracer);
836 mlx5_core_dbg(dev, "FWTracer: Tracer created\n");974 mlx5_core_dbg(dev, "FWTracer: Tracer created\n");
837 975
838 return tracer;976 return tracer;
@@ -917,6 +1055,7 @@ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer) · 78 unmodified lines
917 cancel_work_sync(&tracer->read_fw_strings_work);1055 cancel_work_sync(&tracer->read_fw_strings_work);
918 mlx5_fw_tracer_clean_ready_list(tracer);1056 mlx5_fw_tracer_clean_ready_list(tracer);
919 mlx5_fw_tracer_clean_print_hash(tracer);1057 mlx5_fw_tracer_clean_print_hash(tracer);
1058 mlx5_fw_tracer_clean_saved_traces_array(tracer);
920 mlx5_fw_tracer_free_strings_db(tracer);1059 mlx5_fw_tracer_free_strings_db(tracer);
921 mlx5_fw_tracer_destroy_log_buf(tracer);1060 mlx5_fw_tracer_destroy_log_buf(tracer);
922 flush_workqueue(tracer->work_queue);1061 flush_workqueue(tracer->work_queue);
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h+20−0
@@ -46,6 +46,9 @@ · 45 unmodified lines
46#define TRACER_BLOCK_SIZE_BYTE 25646#define TRACER_BLOCK_SIZE_BYTE 256
47#define TRACES_PER_BLOCK 3247#define TRACES_PER_BLOCK 32
48 48
49#define TRACE_STR_MSG 256
50#define SAVED_TRACES_NUM 8192
51
49#define TRACER_MAX_PARAMS 752#define TRACER_MAX_PARAMS 7
50#define MESSAGE_HASH_BITS 653#define MESSAGE_HASH_BITS 6
51#define MESSAGE_HASH_SIZE BIT(MESSAGE_HASH_BITS)54#define MESSAGE_HASH_SIZE BIT(MESSAGE_HASH_BITS)
@@ -53,6 +56,13 @@ · 1 unmodified line
53#define MASK_52_7 (0x1FFFFFFFFFFF80)56#define MASK_52_7 (0x1FFFFFFFFFFF80)
54#define MASK_6_0 (0x7F)57#define MASK_6_0 (0x7F)
55 58
59struct mlx5_fw_trace_data {
60 u64 timestamp;
61 bool lost;
62 u8 event_id;
63 char msg[TRACE_STR_MSG];
64};
65
56struct mlx5_fw_tracer {66struct mlx5_fw_tracer {
57 struct mlx5_core_dev *dev;67 struct mlx5_core_dev *dev;
58 struct mlx5_nb nb;68 struct mlx5_nb nb;
@@ -83,6 +93,13 @@ struct mlx5_fw_tracer { · 24 unmodified lines
83 u32 consumer_index;93 u32 consumer_index;
84 } buff;94 } buff;
85 95
96 /* Saved Traces Array */
97 struct {
98 struct mlx5_fw_trace_data straces[SAVED_TRACES_NUM];
99 u32 saved_traces_index;
100 struct mutex lock; /* Protect st_arr access */
101 } st_arr;
102
86 u64 last_timestamp;103 u64 last_timestamp;
87 struct work_struct handle_traces_work;104 struct work_struct handle_traces_work;
88 struct hlist_head hash[MESSAGE_HASH_SIZE];105 struct hlist_head hash[MESSAGE_HASH_SIZE];
@@ -171,5 +188,8 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev); · 82 unmodified lines
171int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer);188int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer);
172void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer);189void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer);
173void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer);190void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer);
191int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev);
192int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
193 struct devlink_fmsg *fmsg);
174 194
175#endif195#endif
drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c+1−1
@@ -64,7 +64,7 @@ static int mlx5e_test_health_info(struct mlx5e_priv *priv) · 63 unmodified lines
64{64{
65 struct mlx5_core_health *health = &priv->mdev->priv.health;65 struct mlx5_core_health *health = &priv->mdev->priv.health;
66 66
67 return health->sick ? 1 : 0;67 return health->fatal_error ? 1 : 0;
68}68}
69 69
70static int mlx5e_test_link_state(struct mlx5e_priv *priv)70static int mlx5e_test_link_state(struct mlx5e_priv *priv)
drivers/net/ethernet/mellanox/mlx5/core/health.c+496−73
@@ -40,6 +40,8 @@ · 39 unmodified lines
40#include "mlx5_core.h"40#include "mlx5_core.h"
41#include "lib/eq.h"41#include "lib/eq.h"
42#include "lib/mlx5.h"42#include "lib/mlx5.h"
43#include "lib/pci_vsc.h"
44#include "diag/fw_tracer.h"
43 45
44enum {46enum {
45 MLX5_HEALTH_POLL_INTERVAL = 2 * HZ,47 MLX5_HEALTH_POLL_INTERVAL = 2 * HZ,
@@ -62,12 +64,20 @@ enum { · 16 unmodified lines
62 64
63enum {65enum {
64 MLX5_DROP_NEW_HEALTH_WORK,66 MLX5_DROP_NEW_HEALTH_WORK,
65 MLX5_DROP_NEW_RECOVERY_WORK,67};
68
69enum {
70 MLX5_SENSOR_NO_ERR = 0,
71 MLX5_SENSOR_PCI_COMM_ERR = 1,
72 MLX5_SENSOR_PCI_ERR = 2,
73 MLX5_SENSOR_NIC_DISABLED = 3,
74 MLX5_SENSOR_NIC_SW_RESET = 4,
75 MLX5_SENSOR_FW_SYND_RFR = 5,
66};76};
67 77
68u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)78u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
69{79{
70 return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;80 return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 7;
71}81}
72 82
73void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)83void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
@@ -80,18 +90,105 @@ void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state) · 6 unmodified lines
80 &dev->iseg->cmdq_addr_l_sz);90 &dev->iseg->cmdq_addr_l_sz);
81}91}
82 92
83static int in_fatal(struct mlx5_core_dev *dev)93static bool sensor_pci_not_working(struct mlx5_core_dev *dev)
84{94{
85 struct mlx5_core_health *health = &dev->priv.health;95 struct mlx5_core_health *health = &dev->priv.health;
86 struct health_buffer __iomem *h = health->health;96 struct health_buffer __iomem *h = health->health;
87 97
98 /* Offline PCI reads return 0xffffffff */
99 return (ioread32be(&h->fw_ver) == 0xffffffff);
100}
101
102static bool sensor_fw_synd_rfr(struct mlx5_core_dev *dev)
103{
104 struct mlx5_core_health *health = &dev->priv.health;
105 struct health_buffer __iomem *h = health->health;
106 u32 rfr = ioread32be(&h->rfr) >> MLX5_RFR_OFFSET;
107 u8 synd = ioread8(&h->synd);
108
109 if (rfr && synd)
110 mlx5_core_dbg(dev, "FW requests reset, synd: %d\n", synd);
111 return rfr && synd;
112}
113
114static u32 check_fatal_sensors(struct mlx5_core_dev *dev)
115{
116 if (sensor_pci_not_working(dev))
117 return MLX5_SENSOR_PCI_COMM_ERR;
118 if (pci_channel_offline(dev->pdev))
119 return MLX5_SENSOR_PCI_ERR;
88 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)120 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
89 return 1;121 return MLX5_SENSOR_NIC_DISABLED;
122 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_SW_RESET)
123 return MLX5_SENSOR_NIC_SW_RESET;
124 if (sensor_fw_synd_rfr(dev))
125 return MLX5_SENSOR_FW_SYND_RFR;
90 126
91 if (ioread32be(&h->fw_ver) == 0xffffffff)127 return MLX5_SENSOR_NO_ERR;
92 return 1;128}
93 129
94 return 0;130static int lock_sem_sw_reset(struct mlx5_core_dev *dev, bool lock)
131{
132 enum mlx5_vsc_state state;
133 int ret;
134
135 if (!mlx5_core_is_pf(dev))
136 return -EBUSY;
137
138 /* Try to lock GW access, this stage doesn't return
139 * EBUSY because locked GW does not mean that other PF
140 * already started the reset.
141 */
142 ret = mlx5_vsc_gw_lock(dev);
143 if (ret == -EBUSY)
144 return -EINVAL;
145 if (ret)
146 return ret;
147
148 state = lock ? MLX5_VSC_LOCK : MLX5_VSC_UNLOCK;
149 /* At this stage, if the return status == EBUSY, then we know
150 * for sure that another PF started the reset, so don't allow
151 * another reset.
152 */
153 ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, state);
154 if (ret)
155 mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
156
157 /* Unlock GW access */
158 mlx5_vsc_gw_unlock(dev);
159
160 return ret;
161}
162
163static bool reset_fw_if_needed(struct mlx5_core_dev *dev)
164{
165 bool supported = (ioread32be(&dev->iseg->initializing) >>
166 MLX5_FW_RESET_SUPPORTED_OFFSET) & 1;
167 u32 fatal_error;
168
169 if (!supported)
170 return false;
171
172 /* The reset only needs to be issued by one PF. The health buffer is
173 * shared between all functions, and will be cleared during a reset.
174 * Check again to avoid a redundant 2nd reset. If the fatal erros was
175 * PCI related a reset won't help.
176 */
177 fatal_error = check_fatal_sensors(dev);
178 if (fatal_error == MLX5_SENSOR_PCI_COMM_ERR ||
179 fatal_error == MLX5_SENSOR_NIC_DISABLED ||
180 fatal_error == MLX5_SENSOR_NIC_SW_RESET) {
181 mlx5_core_warn(dev, "Not issuing FW reset. Either it's already done or won't help.");
182 return false;
183 }
184
185 mlx5_core_warn(dev, "Issuing FW Reset\n");
186 /* Write the NIC interface field to initiate the reset, the command
187 * interface address also resides here, don't overwrite it.
188 */
189 mlx5_set_nic_state(dev, MLX5_NIC_IFC_SW_RESET);
190
191 return true;
95}192}
96 193
97void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)194void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
@@ -99,14 +196,65 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) · 1 unmodified line
99 mutex_lock(&dev->intf_state_mutex);196 mutex_lock(&dev->intf_state_mutex);
100 if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)197 if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
101 goto unlock;198 goto unlock;
199 if (dev->state == MLX5_DEVICE_STATE_UNINITIALIZED) {
200 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
201 goto unlock;
202 }
102 203
103 mlx5_core_err(dev, "start\n");204 if (check_fatal_sensors(dev) || force) {
104 if (pci_channel_offline(dev->pdev) || in_fatal(dev) || force) {
105 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;205 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
106 mlx5_cmd_flush(dev);206 mlx5_cmd_flush(dev);
107 }207 }
108 208
109 mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_SYS_ERROR, (void *)1);209 mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_SYS_ERROR, (void *)1);
210unlock:
211 mutex_unlock(&dev->intf_state_mutex);
212}
213
214#define MLX5_CRDUMP_WAIT_MS 60000
215#define MLX5_FW_RESET_WAIT_MS 1000
216void mlx5_error_sw_reset(struct mlx5_core_dev *dev)
217{
218 unsigned long end, delay_ms = MLX5_FW_RESET_WAIT_MS;
219 int lock = -EBUSY;
220
221 mutex_lock(&dev->intf_state_mutex);
222 if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
223 goto unlock;
224
225 mlx5_core_err(dev, "start\n");
226
227 if (check_fatal_sensors(dev) == MLX5_SENSOR_FW_SYND_RFR) {
228 /* Get cr-dump and reset FW semaphore */
229 lock = lock_sem_sw_reset(dev, true);
230
231 if (lock == -EBUSY) {
232 delay_ms = MLX5_CRDUMP_WAIT_MS;
233 goto recover_from_sw_reset;
234 }
235 /* Execute SW reset */
236 reset_fw_if_needed(dev);
237 }
238
239recover_from_sw_reset:
240 /* Recover from SW reset */
241 end = jiffies + msecs_to_jiffies(delay_ms);
242 do {
243 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
244 break;
245
246 cond_resched();
247 } while (!time_after(jiffies, end));
248
249 if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
250 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
251 mlx5_get_nic_state(dev), delay_ms);
252 }
253
254 /* Release FW semaphore if you are the lock owner */
255 if (!lock)
256 lock_sem_sw_reset(dev, false);
257
110 mlx5_core_err(dev, "end\n");258 mlx5_core_err(dev, "end\n");
111 259
112unlock:260unlock:
@@ -129,6 +277,20 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) · 16 unmodified lines
129 case MLX5_NIC_IFC_NO_DRAM_NIC:277 case MLX5_NIC_IFC_NO_DRAM_NIC:
130 mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n");278 mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n");
131 break;279 break;
280
281 case MLX5_NIC_IFC_SW_RESET:
282 /* The IFC mode field is 3 bits, so it will read 0x7 in 2 cases:
283 * 1. PCI has been disabled (ie. PCI-AER, PF driver unloaded
284 * and this is a VF), this is not recoverable by SW reset.
285 * Logging of this is handled elsewhere.
286 * 2. FW reset has been issued by another function, driver can
287 * be reloaded to recover after the mode switches to
288 * MLX5_NIC_IFC_DISABLED.
289 */
290 if (dev->priv.health.fatal_error != MLX5_SENSOR_PCI_COMM_ERR)
291 mlx5_core_warn(dev, "NIC SW reset in progress\n");
292 break;
293
132 default:294 default:
133 mlx5_core_warn(dev, "Expected to see disabled NIC but it is has invalid value %d\n",295 mlx5_core_warn(dev, "Expected to see disabled NIC but it is has invalid value %d\n",
134 nic_interface);296 nic_interface);
@@ -137,52 +299,32 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) · 2 unmodified lines
137 mlx5_disable_device(dev);299 mlx5_disable_device(dev);
138}300}
139 301
140static void health_recover(struct work_struct *work)
141{
142 struct mlx5_core_health *health;
143 struct delayed_work *dwork;
144 struct mlx5_core_dev *dev;
145 struct mlx5_priv *priv;
146 u8 nic_state;
147
148 dwork = container_of(work, struct delayed_work, work);
149 health = container_of(dwork, struct mlx5_core_health, recover_work);
150 priv = container_of(health, struct mlx5_priv, health);
151 dev = container_of(priv, struct mlx5_core_dev, priv);
152
153 nic_state = mlx5_get_nic_state(dev);
154 if (nic_state == MLX5_NIC_IFC_INVALID) {
155 mlx5_core_err(dev, "health recovery flow aborted since the nic state is invalid\n");
156 return;
157 }
158
159 mlx5_core_err(dev, "starting health recovery flow\n");
160 mlx5_recover_device(dev);
161}
162
163/* How much time to wait until health resetting the driver (in msecs) */302/* How much time to wait until health resetting the driver (in msecs) */
164#define MLX5_RECOVERY_DELAY_MSECS 60000303#define MLX5_RECOVERY_WAIT_MSECS 60000
165static void health_care(struct work_struct *work)304static int mlx5_health_try_recover(struct mlx5_core_dev *dev)
166{305{
167 unsigned long recover_delay = msecs_to_jiffies(MLX5_RECOVERY_DELAY_MSECS);306 unsigned long end;
168 struct mlx5_core_health *health;
169 struct mlx5_core_dev *dev;
170 struct mlx5_priv *priv;
171 unsigned long flags;
172 307
173 health = container_of(work, struct mlx5_core_health, work);
174 priv = container_of(health, struct mlx5_priv, health);
175 dev = container_of(priv, struct mlx5_core_dev, priv);
176 mlx5_core_warn(dev, "handling bad device here\n");308 mlx5_core_warn(dev, "handling bad device here\n");
177 mlx5_handle_bad_state(dev);309 mlx5_handle_bad_state(dev);
310 end = jiffies + msecs_to_jiffies(MLX5_RECOVERY_WAIT_MSECS);
311 while (sensor_pci_not_working(dev)) {
312 if (time_after(jiffies, end)) {
313 mlx5_core_err(dev,
314 "health recovery flow aborted, PCI reads still not working\n");
315 return -EIO;
316 }
317 msleep(100);
318 }
178 319
179 spin_lock_irqsave(&health->wq_lock, flags);320 mlx5_core_err(dev, "starting health recovery flow\n");
180 if (!test_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags))321 mlx5_recover_device(dev);
181 schedule_delayed_work(&health->recover_work, recover_delay);322 if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state) ||
182 else323 check_fatal_sensors(dev)) {
183 mlx5_core_err(dev,324 mlx5_core_err(dev, "health recovery failed\n");
184 "new health works are not permitted at this stage\n");325 return -EIO;
185 spin_unlock_irqrestore(&health->wq_lock, flags);326 }
327 return 0;
186}328}
187 329
188static const char *hsynd_str(u8 synd)330static const char *hsynd_str(u8 synd)
@@ -246,6 +388,282 @@ static void print_health_info(struct mlx5_core_dev *dev) · 57 unmodified lines
246 mlx5_core_err(dev, "raw fw_ver 0x%08x\n", fw);388 mlx5_core_err(dev, "raw fw_ver 0x%08x\n", fw);
247}389}
248 390
391static int
392mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
393 struct devlink_fmsg *fmsg)
394{
395 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
396 struct mlx5_core_health *health = &dev->priv.health;
397 struct health_buffer __iomem *h = health->health;
398 u8 synd;
399 int err;
400
401 synd = ioread8(&h->synd);
402 err = devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
403 if (err || !synd)
404 return err;
405 return devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
406}
407
408struct mlx5_fw_reporter_ctx {
409 u8 err_synd;
410 int miss_counter;
411};
412
413static int
414mlx5_fw_reporter_ctx_pairs_put(struct devlink_fmsg *fmsg,
415 struct mlx5_fw_reporter_ctx *fw_reporter_ctx)
416{
417 int err;
418
419 err = devlink_fmsg_u8_pair_put(fmsg, "syndrome",
420 fw_reporter_ctx->err_synd);
421 if (err)
422 return err;
423 err = devlink_fmsg_u32_pair_put(fmsg, "fw_miss_counter",
424 fw_reporter_ctx->miss_counter);
425 if (err)
426 return err;
427 return 0;
428}
429
430static int
431mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev,
432 struct devlink_fmsg *fmsg)
433{
434 struct mlx5_core_health *health = &dev->priv.health;
435 struct health_buffer __iomem *h = health->health;
436 int err;
437 int i;
438
439 if (!ioread8(&h->synd))
440 return 0;
441
442 err = devlink_fmsg_pair_nest_start(fmsg, "health buffer");
443 if (err)
444 return err;
445 err = devlink_fmsg_obj_nest_start(fmsg);
446 if (err)
447 return err;
448 err = devlink_fmsg_arr_pair_nest_start(fmsg, "assert_var");
449 if (err)
450 return err;
451
452 for (i = 0; i < ARRAY_SIZE(h->assert_var); i++) {
453 err = devlink_fmsg_u32_put(fmsg, ioread32be(h->assert_var + i));
454 if (err)
455 return err;
456 }
457 err = devlink_fmsg_arr_pair_nest_end(fmsg);
458 if (err)
459 return err;
460 err = devlink_fmsg_u32_pair_put(fmsg, "assert_exit_ptr",
461 ioread32be(&h->assert_exit_ptr));
462 if (err)
463 return err;
464 err = devlink_fmsg_u32_pair_put(fmsg, "assert_callra",
465 ioread32be(&h->assert_callra));
466 if (err)
467 return err;
468 err = devlink_fmsg_u32_pair_put(fmsg, "hw_id", ioread32be(&h->hw_id));
469 if (err)
470 return err;
471 err = devlink_fmsg_u8_pair_put(fmsg, "irisc_index",
472 ioread8(&h->irisc_index));
473 if (err)
474 return err;
475 err = devlink_fmsg_u8_pair_put(fmsg, "synd", ioread8(&h->synd));
476 if (err)
477 return err;
478 err = devlink_fmsg_u32_pair_put(fmsg, "ext_synd",
479 ioread16be(&h->ext_synd));
480 if (err)
481 return err;
482 err = devlink_fmsg_u32_pair_put(fmsg, "raw_fw_ver",
483 ioread32be(&h->fw_ver));
484 if (err)
485 return err;
486 err = devlink_fmsg_obj_nest_end(fmsg);
487 if (err)
488 return err;
489 return devlink_fmsg_pair_nest_end(fmsg);
490}
491
492static int
493mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter,
494 struct devlink_fmsg *fmsg, void *priv_ctx)
495{
496 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
497 int err;
498
499 err = mlx5_fw_tracer_trigger_core_dump_general(dev);
500 if (err)
501 return err;
502
503 if (priv_ctx) {
504 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
505
506 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
507 if (err)
508 return err;
509 }
510
511 err = mlx5_fw_reporter_heath_buffer_data_put(dev, fmsg);
512 if (err)
513 return err;
514 return mlx5_fw_tracer_get_saved_traces_objects(dev->tracer, fmsg);
515}
516
517static void mlx5_fw_reporter_err_work(struct work_struct *work)
518{
519 struct mlx5_fw_reporter_ctx fw_reporter_ctx;
520 struct mlx5_core_health *health;
521
522 health = container_of(work, struct mlx5_core_health, report_work);
523
524 if (IS_ERR_OR_NULL(health->fw_reporter))
525 return;
526
527 fw_reporter_ctx.err_synd = health->synd;
528 fw_reporter_ctx.miss_counter = health->miss_counter;
529 if (fw_reporter_ctx.err_synd) {
530 devlink_health_report(health->fw_reporter,
531 "FW syndrom reported", &fw_reporter_ctx);
532 return;
533 }
534 if (fw_reporter_ctx.miss_counter)
535 devlink_health_report(health->fw_reporter,
536 "FW miss counter reported",
537 &fw_reporter_ctx);
538}
539
540static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = {
541 .name = "fw",
542 .diagnose = mlx5_fw_reporter_diagnose,
543 .dump = mlx5_fw_reporter_dump,
544};
545
546static int
547mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
548 void *priv_ctx)
549{
550 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
551
552 return mlx5_health_try_recover(dev);
553}
554
555#define MLX5_CR_DUMP_CHUNK_SIZE 256
556static int
557mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
558 struct devlink_fmsg *fmsg, void *priv_ctx)
559{
560 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
561 u32 crdump_size = dev->priv.health.crdump_size;
562 u32 *cr_data;
563 u32 data_size;
564 u32 offset;
565 int err;
566
567 if (!mlx5_core_is_pf(dev))
568 return -EPERM;
569
570 cr_data = kvmalloc(crdump_size, GFP_KERNEL);
571 if (!cr_data)
572 return -ENOMEM;
573 err = mlx5_crdump_collect(dev, cr_data);
574 if (err)
575 return err;
576
577 if (priv_ctx) {
578 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
579
580 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
581 if (err)
582 goto free_data;
583 }
584
585 err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data");
586 if (err)
587 goto free_data;
588 for (offset = 0; offset < crdump_size; offset += data_size) {
589 if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE)
590 data_size = crdump_size - offset;
591 else
592 data_size = MLX5_CR_DUMP_CHUNK_SIZE;
593 err = devlink_fmsg_binary_put(fmsg, cr_data, data_size);
594 if (err)
595 goto free_data;
596 }
597 err = devlink_fmsg_arr_pair_nest_end(fmsg);
598
599free_data:
600 kfree(cr_data);
601 return err;
602}
603
604static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
605{
606 struct mlx5_fw_reporter_ctx fw_reporter_ctx;
607 struct mlx5_core_health *health;
608 struct mlx5_core_dev *dev;
609 struct mlx5_priv *priv;
610
611 health = container_of(work, struct mlx5_core_health, fatal_report_work);
612 priv = container_of(health, struct mlx5_priv, health);
613 dev = container_of(priv, struct mlx5_core_dev, priv);
614
615 mlx5_enter_error_state(dev, false);
616 if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) {
617 if (mlx5_health_try_recover(dev))
618 mlx5_core_err(dev, "health recovery failed\n");
619 return;
620 }
621 fw_reporter_ctx.err_synd = health->synd;
622 fw_reporter_ctx.miss_counter = health->miss_counter;
623 devlink_health_report(health->fw_fatal_reporter,
624 "FW fatal error reported", &fw_reporter_ctx);
625}
626
627static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
628 .name = "fw_fatal",
629 .recover = mlx5_fw_fatal_reporter_recover,
630 .dump = mlx5_fw_fatal_reporter_dump,
631};
632
633#define MLX5_REPORTER_FW_GRACEFUL_PERIOD 1200000
634static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev)
635{
636 struct mlx5_core_health *health = &dev->priv.health;
637 struct devlink *devlink = priv_to_devlink(dev);
638
639 health->fw_reporter =
640 devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops,
641 0, false, dev);
642 if (IS_ERR(health->fw_reporter))
643 mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
644 PTR_ERR(health->fw_reporter));
645
646 health->fw_fatal_reporter =
647 devlink_health_reporter_create(devlink,
648 &mlx5_fw_fatal_reporter_ops,
649 MLX5_REPORTER_FW_GRACEFUL_PERIOD,
650 true, dev);
651 if (IS_ERR(health->fw_fatal_reporter))
652 mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
653 PTR_ERR(health->fw_fatal_reporter));
654}
655
656static void mlx5_fw_reporters_destroy(struct mlx5_core_dev *dev)
657{
658 struct mlx5_core_health *health = &dev->priv.health;
659
660 if (!IS_ERR_OR_NULL(health->fw_reporter))
661 devlink_health_reporter_destroy(health->fw_reporter);
662
663 if (!IS_ERR_OR_NULL(health->fw_fatal_reporter))
664 devlink_health_reporter_destroy(health->fw_fatal_reporter);
665}
666
249static unsigned long get_next_poll_jiffies(void)667static unsigned long get_next_poll_jiffies(void)
250{668{
251 unsigned long next;669 unsigned long next;
@@ -264,7 +682,7 @@ void mlx5_trigger_health_work(struct mlx5_core_dev *dev) · 12 unmodified lines
264 682
265 spin_lock_irqsave(&health->wq_lock, flags);683 spin_lock_irqsave(&health->wq_lock, flags);
266 if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))684 if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
267 queue_work(health->wq, &health->work);685 queue_work(health->wq, &health->fatal_report_work);
268 else686 else
269 mlx5_core_err(dev, "new health works are not permitted at this stage\n");687 mlx5_core_err(dev, "new health works are not permitted at this stage\n");
270 spin_unlock_irqrestore(&health->wq_lock, flags);688 spin_unlock_irqrestore(&health->wq_lock, flags);
@@ -274,6 +692,9 @@ static void poll_health(struct timer_list *t) · 3 unmodified lines
274{692{
275 struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);693 struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);
276 struct mlx5_core_health *health = &dev->priv.health;694 struct mlx5_core_health *health = &dev->priv.health;
695 struct health_buffer __iomem *h = health->health;
696 u32 fatal_error;
697 u8 prev_synd;
277 u32 count;698 u32 count;
278 699
279 if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)700 if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
@@ -289,10 +710,19 @@ static void poll_health(struct timer_list *t) · 9 unmodified lines
289 if (health->miss_counter == MAX_MISSES) {710 if (health->miss_counter == MAX_MISSES) {
290 mlx5_core_err(dev, "device's health compromised - reached miss count\n");711 mlx5_core_err(dev, "device's health compromised - reached miss count\n");
291 print_health_info(dev);712 print_health_info(dev);
713 queue_work(health->wq, &health->report_work);
292 }714 }
293 715
294 if (in_fatal(dev) && !health->sick) {716 prev_synd = health->synd;
295 health->sick = true;717 health->synd = ioread8(&h->synd);
718 if (health->synd && health->synd != prev_synd)
719 queue_work(health->wq, &health->report_work);
720
721 fatal_error = check_fatal_sensors(dev);
722
723 if (fatal_error && !health->fatal_error) {
724 mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
725 dev->priv.health.fatal_error = fatal_error;
296 print_health_info(dev);726 print_health_info(dev);
297 mlx5_trigger_health_work(dev);727 mlx5_trigger_health_work(dev);
298 }728 }
@@ -306,9 +736,8 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) · 7 unmodified lines
306 struct mlx5_core_health *health = &dev->priv.health;736 struct mlx5_core_health *health = &dev->priv.health;
307 737
308 timer_setup(&health->timer, poll_health, 0);738 timer_setup(&health->timer, poll_health, 0);
309 health->sick = 0;739 health->fatal_error = MLX5_SENSOR_NO_ERR;
310 clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);740 clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
311 clear_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
312 health->health = &dev->iseg->health;741 health->health = &dev->iseg->health;
313 health->health_counter = &dev->iseg->health_counter;742 health->health_counter = &dev->iseg->health_counter;
314 743
@@ -324,7 +753,6 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health) · 9 unmodified lines
324 if (disable_health) {753 if (disable_health) {
325 spin_lock_irqsave(&health->wq_lock, flags);754 spin_lock_irqsave(&health->wq_lock, flags);
326 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);755 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
327 set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
328 spin_unlock_irqrestore(&health->wq_lock, flags);756 spin_unlock_irqrestore(&health->wq_lock, flags);
329 }757 }
330 758
@@ -338,21 +766,9 @@ void mlx5_drain_health_wq(struct mlx5_core_dev *dev) · 7 unmodified lines
338 766
339 spin_lock_irqsave(&health->wq_lock, flags);767 spin_lock_irqsave(&health->wq_lock, flags);
340 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);768 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
341 set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
342 spin_unlock_irqrestore(&health->wq_lock, flags);769 spin_unlock_irqrestore(&health->wq_lock, flags);
343 cancel_delayed_work_sync(&health->recover_work);770 cancel_work_sync(&health->report_work);
344 cancel_work_sync(&health->work);771 cancel_work_sync(&health->fatal_report_work);
345}
346
347void mlx5_drain_health_recovery(struct mlx5_core_dev *dev)
348{
349 struct mlx5_core_health *health = &dev->priv.health;
350 unsigned long flags;
351
352 spin_lock_irqsave(&health->wq_lock, flags);
353 set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
354 spin_unlock_irqrestore(&health->wq_lock, flags);
355 cancel_delayed_work_sync(&dev->priv.health.recover_work);
356}772}
357 773
358void mlx5_health_flush(struct mlx5_core_dev *dev)774void mlx5_health_flush(struct mlx5_core_dev *dev)
@@ -367,6 +783,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev) · 8 unmodified lines
367 struct mlx5_core_health *health = &dev->priv.health;783 struct mlx5_core_health *health = &dev->priv.health;
368 784
369 destroy_workqueue(health->wq);785 destroy_workqueue(health->wq);
786 mlx5_fw_reporters_destroy(dev);
370}787}
371 788
372int mlx5_health_init(struct mlx5_core_dev *dev)789int mlx5_health_init(struct mlx5_core_dev *dev)
@@ -374,20 +791,26 @@ int mlx5_health_init(struct mlx5_core_dev *dev) · 1 unmodified line
374 struct mlx5_core_health *health;791 struct mlx5_core_health *health;
375 char *name;792 char *name;
376 793
794 mlx5_fw_reporters_create(dev);
795
377 health = &dev->priv.health;796 health = &dev->priv.health;
378 name = kmalloc(64, GFP_KERNEL);797 name = kmalloc(64, GFP_KERNEL);
379 if (!name)798 if (!name)
380 return -ENOMEM;799 goto out_err;
381 800
382 strcpy(name, "mlx5_health");801 strcpy(name, "mlx5_health");
383 strcat(name, dev_name(dev->device));802 strcat(name, dev_name(dev->device));
384 health->wq = create_singlethread_workqueue(name);803 health->wq = create_singlethread_workqueue(name);
385 kfree(name);804 kfree(name);
386 if (!health->wq)805 if (!health->wq)
387 return -ENOMEM;806 goto out_err;
388 spin_lock_init(&health->wq_lock);807 spin_lock_init(&health->wq_lock);
389 INIT_WORK(&health->work, health_care);808 INIT_WORK(&health->fatal_report_work, mlx5_fw_fatal_reporter_err_work);
390 INIT_DELAYED_WORK(&health->recover_work, health_recover);809 INIT_WORK(&health->report_work, mlx5_fw_reporter_err_work);
391 810
392 return 0;811 return 0;
812
813out_err:
814 mlx5_fw_reporters_destroy(dev);
815 return -ENOMEM;
393}816}
drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h+3−0
@@ -41,6 +41,9 @@ int mlx5_core_reserve_gids(struct mlx5_core_dev *dev, unsigned int count); · 40 unmodified lines
41void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count);41void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count);
42int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index);42int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index);
43void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index);43void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index);
44int mlx5_crdump_enable(struct mlx5_core_dev *dev);
45void mlx5_crdump_disable(struct mlx5_core_dev *dev);
46int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data);
44 47
45/* TODO move to lib/events.h */48/* TODO move to lib/events.h */
46 49
drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c+316−0
@@ -0,0 +1,316 @@
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#include <linux/pci.h>
5#include "mlx5_core.h"
6#include "pci_vsc.h"
7
8#define MLX5_EXTRACT_C(source, offset, size) \
9 ((((u32)(source)) >> (offset)) & MLX5_ONES32(size))
10#define MLX5_EXTRACT(src, start, len) \
11 (((len) == 32) ? (src) : MLX5_EXTRACT_C(src, start, len))
12#define MLX5_ONES32(size) \
13 ((size) ? (0xffffffff >> (32 - (size))) : 0)
14#define MLX5_MASK32(offset, size) \
15 (MLX5_ONES32(size) << (offset))
16#define MLX5_MERGE_C(rsrc1, rsrc2, start, len) \
17 ((((rsrc2) << (start)) & (MLX5_MASK32((start), (len)))) | \
18 ((rsrc1) & (~MLX5_MASK32((start), (len)))))
19#define MLX5_MERGE(rsrc1, rsrc2, start, len) \
20 (((len) == 32) ? (rsrc2) : MLX5_MERGE_C(rsrc1, rsrc2, start, len))
21#define vsc_read(dev, offset, val) \
22 pci_read_config_dword((dev)->pdev, (dev)->vsc_addr + (offset), (val))
23#define vsc_write(dev, offset, val) \
24 pci_write_config_dword((dev)->pdev, (dev)->vsc_addr + (offset), (val))
25#define VSC_MAX_RETRIES 2048
26
27enum {
28 VSC_CTRL_OFFSET = 0x4,
29 VSC_COUNTER_OFFSET = 0x8,
30 VSC_SEMAPHORE_OFFSET = 0xc,
31 VSC_ADDR_OFFSET = 0x10,
32 VSC_DATA_OFFSET = 0x14,
33
34 VSC_FLAG_BIT_OFFS = 31,
35 VSC_FLAG_BIT_LEN = 1,
36
37 VSC_SYND_BIT_OFFS = 30,
38 VSC_SYND_BIT_LEN = 1,
39
40 VSC_ADDR_BIT_OFFS = 0,
41 VSC_ADDR_BIT_LEN = 30,
42
43 VSC_SPACE_BIT_OFFS = 0,
44 VSC_SPACE_BIT_LEN = 16,
45
46 VSC_SIZE_VLD_BIT_OFFS = 28,
47 VSC_SIZE_VLD_BIT_LEN = 1,
48
49 VSC_STATUS_BIT_OFFS = 29,
50 VSC_STATUS_BIT_LEN = 3,
51};
52
53void mlx5_pci_vsc_init(struct mlx5_core_dev *dev)
54{
55 if (!mlx5_core_is_pf(dev))
56 return;
57
58 dev->vsc_addr = pci_find_capability(dev->pdev,
59 PCI_CAP_ID_VNDR);
60 if (!dev->vsc_addr)
61 mlx5_core_warn(dev, "Failed to get valid vendor specific ID\n");
62}
63
64int mlx5_vsc_gw_lock(struct mlx5_core_dev *dev)
65{
66 u32 counter = 0;
67 int retries = 0;
68 u32 lock_val;
69 int ret;
70
71 pci_cfg_access_lock(dev->pdev);
72 do {
73 if (retries > VSC_MAX_RETRIES) {
74 ret = -EBUSY;
75 goto pci_unlock;
76 }
77
78 /* Check if semaphore is already locked */
79 ret = vsc_read(dev, VSC_SEMAPHORE_OFFSET, &lock_val);
80 if (ret)
81 goto pci_unlock;
82
83 if (lock_val) {
84 retries++;
85 usleep_range(1000, 2000);
86 continue;
87 }
88
89 /* Read and write counter value, if written value is
90 * the same, semaphore was acquired successfully.
91 */
92 ret = vsc_read(dev, VSC_COUNTER_OFFSET, &counter);
93 if (ret)
94 goto pci_unlock;
95
96 ret = vsc_write(dev, VSC_SEMAPHORE_OFFSET, counter);
97 if (ret)
98 goto pci_unlock;
99
100 ret = vsc_read(dev, VSC_SEMAPHORE_OFFSET, &lock_val);
101 if (ret)
102 goto pci_unlock;
103
104 retries++;
105 } while (counter != lock_val);
106
107 return 0;
108
109pci_unlock:
110 pci_cfg_access_unlock(dev->pdev);
111 return ret;
112}
113
114int mlx5_vsc_gw_unlock(struct mlx5_core_dev *dev)
115{
116 int ret;
117
118 ret = vsc_write(dev, VSC_SEMAPHORE_OFFSET, MLX5_VSC_UNLOCK);
119 pci_cfg_access_unlock(dev->pdev);
120 return ret;
121}
122
123int mlx5_vsc_gw_set_space(struct mlx5_core_dev *dev, u16 space,
124 u32 *ret_space_size)
125{
126 int ret;
127 u32 val = 0;
128
129 if (!mlx5_vsc_accessible(dev))
130 return -EINVAL;
131
132 if (ret_space_size)
133 *ret_space_size = 0;
134
135 /* Get a unique val */
136 ret = vsc_read(dev, VSC_CTRL_OFFSET, &val);
137 if (ret)
138 goto out;
139
140 /* Try to modify the lock */
141 val = MLX5_MERGE(val, space, VSC_SPACE_BIT_OFFS, VSC_SPACE_BIT_LEN);
142 ret = vsc_write(dev, VSC_CTRL_OFFSET, val);
143 if (ret)
144 goto out;
145
146 /* Verify lock was modified */
147 ret = vsc_read(dev, VSC_CTRL_OFFSET, &val);
148 if (ret)
149 goto out;
150
151 if (MLX5_EXTRACT(val, VSC_STATUS_BIT_OFFS, VSC_STATUS_BIT_LEN) == 0)
152 return -EINVAL;
153
154 /* Get space max address if indicated by size valid bit */
155 if (ret_space_size &&
156 MLX5_EXTRACT(val, VSC_SIZE_VLD_BIT_OFFS, VSC_SIZE_VLD_BIT_LEN)) {
157 ret = vsc_read(dev, VSC_ADDR_OFFSET, &val);
158 if (ret) {
159 mlx5_core_warn(dev, "Failed to get max space size\n");
160 goto out;
161 }
162 *ret_space_size = MLX5_EXTRACT(val, VSC_ADDR_BIT_OFFS,
163 VSC_ADDR_BIT_LEN);
164 }
165 return 0;
166
167out:
168 return ret;
169}
170
171static int mlx5_vsc_wait_on_flag(struct mlx5_core_dev *dev, u8 expected_val)
172{
173 int retries = 0;
174 u32 flag;
175 int ret;
176
177 do {
178 if (retries > VSC_MAX_RETRIES)
179 return -EBUSY;
180
181 ret = vsc_read(dev, VSC_ADDR_OFFSET, &flag);
182 if (ret)
183 return ret;
184 flag = MLX5_EXTRACT(flag, VSC_FLAG_BIT_OFFS, VSC_FLAG_BIT_LEN);
185 retries++;
186
187 if ((retries & 0xf) == 0)
188 usleep_range(1000, 2000);
189
190 } while (flag != expected_val);
191
192 return 0;
193}
194
195static int mlx5_vsc_gw_write(struct mlx5_core_dev *dev, unsigned int address,
196 u32 data)
197{
198 int ret;
199
200 if (MLX5_EXTRACT(address, VSC_SYND_BIT_OFFS,
201 VSC_FLAG_BIT_LEN + VSC_SYND_BIT_LEN))
202 return -EINVAL;
203
204 /* Set flag to 0x1 */
205 address = MLX5_MERGE(address, 1, VSC_FLAG_BIT_OFFS, 1);
206 ret = vsc_write(dev, VSC_DATA_OFFSET, data);
207 if (ret)
208 goto out;
209
210 ret = vsc_write(dev, VSC_ADDR_OFFSET, address);
211 if (ret)
212 goto out;
213
214 /* Wait for the flag to be cleared */
215 ret = mlx5_vsc_wait_on_flag(dev, 0);
216
217out:
218 return ret;
219}
220
221static int mlx5_vsc_gw_read(struct mlx5_core_dev *dev, unsigned int address,
222 u32 *data)
223{
224 int ret;
225
226 if (MLX5_EXTRACT(address, VSC_SYND_BIT_OFFS,
227 VSC_FLAG_BIT_LEN + VSC_SYND_BIT_LEN))
228 return -EINVAL;
229
230 ret = vsc_write(dev, VSC_ADDR_OFFSET, address);
231 if (ret)
232 goto out;
233
234 ret = mlx5_vsc_wait_on_flag(dev, 1);
235 if (ret)
236 goto out;
237
238 ret = vsc_read(dev, VSC_DATA_OFFSET, data);
239out:
240 return ret;
241}
242
243static int mlx5_vsc_gw_read_fast(struct mlx5_core_dev *dev,
244 unsigned int read_addr,
245 unsigned int *next_read_addr,
246 u32 *data)
247{
248 int ret;
249
250 ret = mlx5_vsc_gw_read(dev, read_addr, data);
251 if (ret)
252 goto out;
253
254 ret = vsc_read(dev, VSC_ADDR_OFFSET, next_read_addr);
255 if (ret)
256 goto out;
257
258 *next_read_addr = MLX5_EXTRACT(*next_read_addr, VSC_ADDR_BIT_OFFS,
259 VSC_ADDR_BIT_LEN);
260
261 if (*next_read_addr <= read_addr)
262 ret = -EINVAL;
263out:
264 return ret;
265}
266
267int mlx5_vsc_gw_read_block_fast(struct mlx5_core_dev *dev, u32 *data,
268 int length)
269{
270 unsigned int next_read_addr = 0;
271 unsigned int read_addr = 0;
272
273 while (read_addr < length) {
274 if (mlx5_vsc_gw_read_fast(dev, read_addr, &next_read_addr,
275 &data[(read_addr >> 2)]))
276 return read_addr;
277
278 read_addr = next_read_addr;
279 }
280 return length;
281}
282
283int mlx5_vsc_sem_set_space(struct mlx5_core_dev *dev, u16 space,
284 enum mlx5_vsc_state state)
285{
286 u32 data, id = 0;
287 int ret;
288
289 ret = mlx5_vsc_gw_set_space(dev, MLX5_SEMAPHORE_SPACE_DOMAIN, NULL);
290 if (ret) {
291 mlx5_core_warn(dev, "Failed to set gw space %d\n", ret);
292 return ret;
293 }
294
295 if (state == MLX5_VSC_LOCK) {
296 /* Get a unique ID based on the counter */
297 ret = vsc_read(dev, VSC_COUNTER_OFFSET, &id);
298 if (ret)
299 return ret;
300 }
301
302 /* Try to modify lock */
303 ret = mlx5_vsc_gw_write(dev, space, id);
304 if (ret)
305 return ret;
306
307 /* Verify lock was modified */
308 ret = mlx5_vsc_gw_read(dev, space, &data);
309 if (ret)
310 return -EINVAL;
311
312 if (data != id)
313 return -EBUSY;
314
315 return 0;
316}
drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h+32−0
@@ -0,0 +1,32 @@
1/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#ifndef __MLX5_PCI_VSC_H__
5#define __MLX5_PCI_VSC_H__
6
7enum mlx5_vsc_state {
8 MLX5_VSC_UNLOCK,
9 MLX5_VSC_LOCK,
10};
11
12enum {
13 MLX5_VSC_SPACE_SCAN_CRSPACE = 0x7,
14};
15
16void mlx5_pci_vsc_init(struct mlx5_core_dev *dev);
17int mlx5_vsc_gw_lock(struct mlx5_core_dev *dev);
18int mlx5_vsc_gw_unlock(struct mlx5_core_dev *dev);
19int mlx5_vsc_gw_set_space(struct mlx5_core_dev *dev, u16 space,
20 u32 *ret_space_size);
21int mlx5_vsc_gw_read_block_fast(struct mlx5_core_dev *dev, u32 *data,
22 int length);
23
24static inline bool mlx5_vsc_accessible(struct mlx5_core_dev *dev)
25{
26 return !!dev->vsc_addr;
27}
28
29int mlx5_vsc_sem_set_space(struct mlx5_core_dev *dev, u16 space,
30 enum mlx5_vsc_state state);
31
32#endif /* __MLX5_PCI_VSC_H__ */
drivers/net/ethernet/mellanox/mlx5/core/main.c+21−44
@@ -56,6 +56,7 @@ · 55 unmodified lines
56#include "fs_core.h"56#include "fs_core.h"
57#include "lib/mpfs.h"57#include "lib/mpfs.h"
58#include "eswitch.h"58#include "eswitch.h"
59#include "devlink.h"
59#include "lib/mlx5.h"60#include "lib/mlx5.h"
60#include "fpga/core.h"61#include "fpga/core.h"
61#include "fpga/ipsec.h"62#include "fpga/ipsec.h"
@@ -65,6 +66,7 @@ · 3 unmodified lines
65#include "lib/vxlan.h"66#include "lib/vxlan.h"
66#include "lib/geneve.h"67#include "lib/geneve.h"
67#include "lib/devcom.h"68#include "lib/devcom.h"
69#include "lib/pci_vsc.h"
68#include "diag/fw_tracer.h"70#include "diag/fw_tracer.h"
69#include "ecpf.h"71#include "ecpf.h"
70 72
@@ -762,6 +764,8 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev, · 691 unmodified lines
762 goto err_clr_master;764 goto err_clr_master;
763 }765 }
764 766
767 mlx5_pci_vsc_init(dev);
768
765 return 0;769 return 0;
766 770
767err_clr_master:771err_clr_master:
@@ -1187,7 +1191,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) · 419 unmodified lines
1187 int err = 0;1191 int err = 0;
1188 1192
1189 if (cleanup)1193 if (cleanup)
1190 mlx5_drain_health_recovery(dev);1194 mlx5_drain_health_wq(dev);
1191 1195
1192 mutex_lock(&dev->intf_state_mutex);1196 mutex_lock(&dev->intf_state_mutex);
1193 if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) {1197 if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) {
@@ -1214,37 +1218,6 @@ out: · 20 unmodified lines
1214 return err;1218 return err;
1215}1219}
1216 1220
1217static int mlx5_devlink_flash_update(struct devlink *devlink,
1218 const char *file_name,
1219 const char *component,
1220 struct netlink_ext_ack *extack)
1221{
1222 struct mlx5_core_dev *dev = devlink_priv(devlink);
1223 const struct firmware *fw;
1224 int err;
1225
1226 if (component)
1227 return -EOPNOTSUPP;
1228
1229 err = request_firmware_direct(&fw, file_name, &dev->pdev->dev);
1230 if (err)
1231 return err;
1232
1233 return mlx5_firmware_flash(dev, fw, extack);
1234}
1235
1236static const struct devlink_ops mlx5_devlink_ops = {
1237#ifdef CONFIG_MLX5_ESWITCH
1238 .eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
1239 .eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
1240 .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
1241 .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
1242 .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,
1243 .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
1244#endif
1245 .flash_update = mlx5_devlink_flash_update,
1246};
1247
1248static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)1221static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
1249{1222{
1250 struct mlx5_priv *priv = &dev->priv;1223 struct mlx5_priv *priv = &dev->priv;
@@ -1306,9 +1279,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *id) · 55 unmodified lines
1306 struct devlink *devlink;1279 struct devlink *devlink;
1307 int err;1280 int err;
1308 1281
1309 devlink = devlink_alloc(&mlx5_devlink_ops, sizeof(*dev));1282 devlink = mlx5_devlink_alloc();
1310 if (!devlink) {1283 if (!devlink) {
1311 dev_err(&pdev->dev, "kzalloc failed\n");1284 dev_err(&pdev->dev, "devlink alloc failed\n");
1312 return -ENOMEM;1285 return -ENOMEM;
1313 }1286 }
1314 1287
@@ -1336,10 +1309,14 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *id) · 21 unmodified lines
1336 1309
1337 request_module_nowait(MLX5_IB_MOD);1310 request_module_nowait(MLX5_IB_MOD);
1338 1311
1339 err = devlink_register(devlink, &pdev->dev);1312 err = mlx5_devlink_register(devlink, &pdev->dev);
1340 if (err)1313 if (err)
1341 goto clean_load;1314 goto clean_load;
1342 1315
1316 err = mlx5_crdump_enable(dev);
1317 if (err)
1318 dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
1319
1343 pci_save_state(pdev);1320 pci_save_state(pdev);
1344 return 0;1321 return 0;
1345 1322
@@ -1351,7 +1328,7 @@ err_load_one: · 5 unmodified lines
1351pci_init_err:1328pci_init_err:
1352 mlx5_mdev_uninit(dev);1329 mlx5_mdev_uninit(dev);
1353mdev_init_err:1330mdev_init_err:
1354 devlink_free(devlink);1331 mlx5_devlink_free(devlink);
1355 1332
1356 return err;1333 return err;
1357}1334}
@@ -1361,7 +1338,8 @@ static void remove_one(struct pci_dev *pdev) · 3 unmodified lines
1361 struct mlx5_core_dev *dev = pci_get_drvdata(pdev);1338 struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
1362 struct devlink *devlink = priv_to_devlink(dev);1339 struct devlink *devlink = priv_to_devlink(dev);
1363 1340
1364 devlink_unregister(devlink);1341 mlx5_crdump_disable(dev);
1342 mlx5_devlink_unregister(devlink);
1365 mlx5_unregister_device(dev);1343 mlx5_unregister_device(dev);
1366 1344
1367 if (mlx5_unload_one(dev, true)) {1345 if (mlx5_unload_one(dev, true)) {
@@ -1372,7 +1350,7 @@ static void remove_one(struct pci_dev *pdev) · 4 unmodified lines
1372 1350
1373 mlx5_pci_close(dev);1351 mlx5_pci_close(dev);
1374 mlx5_mdev_uninit(dev);1352 mlx5_mdev_uninit(dev);
1375 devlink_free(devlink);1353 mlx5_devlink_free(devlink);
1376}1354}
1377 1355
1378static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,1356static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
@@ -1383,12 +1361,10 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, · 4 unmodified lines
1383 mlx5_core_info(dev, "%s was called\n", __func__);1361 mlx5_core_info(dev, "%s was called\n", __func__);
1384 1362
1385 mlx5_enter_error_state(dev, false);1363 mlx5_enter_error_state(dev, false);
1364 mlx5_error_sw_reset(dev);
1386 mlx5_unload_one(dev, false);1365 mlx5_unload_one(dev, false);
1387 /* In case of kernel call drain the health wq */1366 mlx5_drain_health_wq(dev);
1388 if (state) {1367 mlx5_pci_disable_device(dev);
1389 mlx5_drain_health_wq(dev);
1390 mlx5_pci_disable_device(dev);
1391 }
1392 1368
1393 return state == pci_channel_io_perm_failure ?1369 return state == pci_channel_io_perm_failure ?
1394 PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;1370 PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
@@ -1556,7 +1532,8 @@ MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table); · 161 unmodified lines
1556 1532
1557void mlx5_disable_device(struct mlx5_core_dev *dev)1533void mlx5_disable_device(struct mlx5_core_dev *dev)
1558{1534{
1559 mlx5_pci_err_detected(dev->pdev, 0);1535 mlx5_error_sw_reset(dev);
1536 mlx5_unload_one(dev, false);
1560}1537}
1561 1538
1562void mlx5_recover_device(struct mlx5_core_dev *dev)1539void mlx5_recover_device(struct mlx5_core_dev *dev)
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h+7−1
@@ -111,6 +111,11 @@ enum { · 110 unmodified lines
111 MLX5_DRIVER_SYND = 0xbadd00de,111 MLX5_DRIVER_SYND = 0xbadd00de,
112};112};
113 113
114enum mlx5_semaphore_space_address {
115 MLX5_SEMAPHORE_SPACE_DOMAIN = 0xA,
116 MLX5_SEMAPHORE_SW_RESET = 0x20,
117};
118
114int mlx5_query_hca_caps(struct mlx5_core_dev *dev);119int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
115int mlx5_query_board_id(struct mlx5_core_dev *dev);120int mlx5_query_board_id(struct mlx5_core_dev *dev);
116int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);121int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);
@@ -118,6 +123,7 @@ int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); · 1 unmodified line
118int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev);123int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev);
119int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);124int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);
120void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force);125void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force);
126void mlx5_error_sw_reset(struct mlx5_core_dev *dev);
121void mlx5_disable_device(struct mlx5_core_dev *dev);127void mlx5_disable_device(struct mlx5_core_dev *dev);
122void mlx5_recover_device(struct mlx5_core_dev *dev);128void mlx5_recover_device(struct mlx5_core_dev *dev);
123int mlx5_sriov_init(struct mlx5_core_dev *dev);129int mlx5_sriov_init(struct mlx5_core_dev *dev);
@@ -214,7 +220,7 @@ enum { · 90 unmodified lines
214 MLX5_NIC_IFC_FULL = 0,220 MLX5_NIC_IFC_FULL = 0,
215 MLX5_NIC_IFC_DISABLED = 1,221 MLX5_NIC_IFC_DISABLED = 1,
216 MLX5_NIC_IFC_NO_DRAM_NIC = 2,222 MLX5_NIC_IFC_NO_DRAM_NIC = 2,
217 MLX5_NIC_IFC_INVALID = 3223 MLX5_NIC_IFC_SW_RESET = 7
218};224};
219 225
220u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);226u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
include/linux/mlx5/device.h+9−1
@@ -510,6 +510,10 @@ struct mlx5_cmd_layout { · 509 unmodified lines
510 u8 status_own;510 u8 status_own;
511};511};
512 512
513enum mlx5_fatal_assert_bit_offsets {
514 MLX5_RFR_OFFSET = 31,
515};
516
513struct health_buffer {517struct health_buffer {
514 __be32 assert_var[5];518 __be32 assert_var[5];
515 __be32 rsvd0[3];519 __be32 rsvd0[3];
@@ -518,12 +522,16 @@ struct health_buffer { · 2 unmodified lines
518 __be32 rsvd1[2];522 __be32 rsvd1[2];
519 __be32 fw_ver;523 __be32 fw_ver;
520 __be32 hw_id;524 __be32 hw_id;
521 __be32 rsvd2;525 __be32 rfr;
522 u8 irisc_index;526 u8 irisc_index;
523 u8 synd;527 u8 synd;
524 __be16 ext_synd;528 __be16 ext_synd;
525};529};
526 530
531enum mlx5_initializing_bit_offsets {
532 MLX5_FW_RESET_SUPPORTED_OFFSET = 30,
533};
534
527enum mlx5_cmd_addr_l_sz_offset {535enum mlx5_cmd_addr_l_sz_offset {
528 MLX5_NIC_IFC_OFFSET = 8,536 MLX5_NIC_IFC_OFFSET = 8,
529};537};
include/linux/mlx5/driver.h+10−3
@@ -53,6 +53,7 @@ · 52 unmodified lines
53#include <linux/mlx5/eq.h>53#include <linux/mlx5/eq.h>
54#include <linux/timecounter.h>54#include <linux/timecounter.h>
55#include <linux/ptp_clock_kernel.h>55#include <linux/ptp_clock_kernel.h>
56#include <net/devlink.h>
56 57
57enum {58enum {
58 MLX5_BOARD_ID_LEN = 64,59 MLX5_BOARD_ID_LEN = 64,
@@ -434,13 +435,18 @@ struct mlx5_core_health { · 375 unmodified lines
434 struct timer_list timer;435 struct timer_list timer;
435 u32 prev;436 u32 prev;
436 int miss_counter;437 int miss_counter;
437 bool sick;438 u8 synd;
439 u32 fatal_error;
440 u32 crdump_size;
438 /* wq spinlock to synchronize draining */441 /* wq spinlock to synchronize draining */
439 spinlock_t wq_lock;442 spinlock_t wq_lock;
440 struct workqueue_struct *wq;443 struct workqueue_struct *wq;
441 unsigned long flags;444 unsigned long flags;
442 struct work_struct work;445 struct work_struct fatal_report_work;
446 struct work_struct report_work;
443 struct delayed_work recover_work;447 struct delayed_work recover_work;
448 struct devlink_health_reporter *fw_reporter;
449 struct devlink_health_reporter *fw_fatal_reporter;
444};450};
445 451
446struct mlx5_qp_table {452struct mlx5_qp_table {
@@ -581,6 +587,7 @@ struct mlx5_priv { · 134 unmodified lines
581};587};
582 588
583enum mlx5_device_state {589enum mlx5_device_state {
590 MLX5_DEVICE_STATE_UNINITIALIZED,
584 MLX5_DEVICE_STATE_UP,591 MLX5_DEVICE_STATE_UP,
585 MLX5_DEVICE_STATE_INTERNAL_ERROR,592 MLX5_DEVICE_STATE_INTERNAL_ERROR,
586};593};
@@ -693,6 +700,7 @@ struct mlx5_core_dev { · 106 unmodified lines
693 struct mlx5_clock clock;700 struct mlx5_clock clock;
694 struct mlx5_ib_clock_info *clock_info;701 struct mlx5_ib_clock_info *clock_info;
695 struct mlx5_fw_tracer *tracer;702 struct mlx5_fw_tracer *tracer;
703 u32 vsc_addr;
696};704};
697 705
698struct mlx5_db {706struct mlx5_db {
@@ -904,7 +912,6 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev); · 205 unmodified lines
904void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health);912void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health);
905void mlx5_drain_health_wq(struct mlx5_core_dev *dev);913void mlx5_drain_health_wq(struct mlx5_core_dev *dev);
906void mlx5_trigger_health_work(struct mlx5_core_dev *dev);914void mlx5_trigger_health_work(struct mlx5_core_dev *dev);
907void mlx5_drain_health_recovery(struct mlx5_core_dev *dev);
908int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,915int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
909 struct mlx5_frag_buf *buf, int node);916 struct mlx5_frag_buf *buf, int node);
910int mlx5_buf_alloc(struct mlx5_core_dev *dev,917int mlx5_buf_alloc(struct mlx5_core_dev *dev,
net/core/devlink.c+98−20
@@ -4518,6 +4518,35 @@ nla_put_failure: · 4517 unmodified lines
4518 return err;4518 return err;
4519}4519}
4520 4520
4521static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4522 struct netlink_callback *cb,
4523 enum devlink_command cmd)
4524{
4525 int index = cb->args[0];
4526 int tmp_index = index;
4527 void *hdr;
4528 int err;
4529
4530 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4531 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4532 if (!hdr) {
4533 err = -EMSGSIZE;
4534 goto nla_put_failure;
4535 }
4536
4537 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4538 if ((err && err != -EMSGSIZE) || tmp_index == index)
4539 goto nla_put_failure;
4540
4541 cb->args[0] = index;
4542 genlmsg_end(skb, hdr);
4543 return skb->len;
4544
4545nla_put_failure:
4546 genlmsg_cancel(skb, hdr);
4547 return err;
4548}
4549
4521struct devlink_health_reporter {4550struct devlink_health_reporter {
4522 struct list_head list;4551 struct list_head list;
4523 void *priv;4552 void *priv;
@@ -4750,17 +4779,16 @@ int devlink_health_report(struct devlink_health_reporter *reporter, · 226 unmodified lines
4750EXPORT_SYMBOL_GPL(devlink_health_report);4779EXPORT_SYMBOL_GPL(devlink_health_report);
4751 4780
4752static struct devlink_health_reporter *4781static struct devlink_health_reporter *
4753devlink_health_reporter_get_from_info(struct devlink *devlink,4782devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4754 struct genl_info *info)4783 struct nlattr **attrs)
4755{4784{
4756 struct devlink_health_reporter *reporter;4785 struct devlink_health_reporter *reporter;
4757 char *reporter_name;4786 char *reporter_name;
4758 4787
4759 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])4788 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4760 return NULL;4789 return NULL;
4761 4790
4762 reporter_name =4791 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4763 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4764 mutex_lock(&devlink->reporters_lock);4792 mutex_lock(&devlink->reporters_lock);
4765 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);4793 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4766 if (reporter)4794 if (reporter)
@@ -4769,6 +4797,48 @@ devlink_health_reporter_get_from_info(struct devlink *devlink, · 2 unmodified lines
4769 return reporter;4797 return reporter;
4770}4798}
4771 4799
4800static struct devlink_health_reporter *
4801devlink_health_reporter_get_from_info(struct devlink *devlink,
4802 struct genl_info *info)
4803{
4804 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4805}
4806
4807static struct devlink_health_reporter *
4808devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4809{
4810 struct devlink_health_reporter *reporter;
4811 struct devlink *devlink;
4812 struct nlattr **attrs;
4813 int err;
4814
4815 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4816 if (!attrs)
4817 return NULL;
4818
4819 err = nlmsg_parse_deprecated(cb->nlh,
4820 GENL_HDRLEN + devlink_nl_family.hdrsize,
4821 attrs, DEVLINK_ATTR_MAX,
4822 devlink_nl_family.policy, cb->extack);
4823 if (err)
4824 goto free;
4825
4826 mutex_lock(&devlink_mutex);
4827 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4828 if (IS_ERR(devlink))
4829 goto unlock;
4830
4831 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4832 mutex_unlock(&devlink_mutex);
4833 kfree(attrs);
4834 return reporter;
4835unlock:
4836 mutex_unlock(&devlink_mutex);
4837free:
4838 kfree(attrs);
4839 return NULL;
4840}
4841
4772static void4842static void
4773devlink_health_reporter_put(struct devlink_health_reporter *reporter)4843devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4774{4844{
@@ -5004,32 +5074,40 @@ out: · 229 unmodified lines
5004 return err;5074 return err;
5005}5075}
5006 5076
5007static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,5077static int
5008 struct genl_info *info)5078devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5079 struct netlink_callback *cb)
5009{5080{
5010 struct devlink *devlink = info->user_ptr[0];
5011 struct devlink_health_reporter *reporter;5081 struct devlink_health_reporter *reporter;
5082 u64 start = cb->args[0];
5012 int err;5083 int err;
5013 5084
5014 reporter = devlink_health_reporter_get_from_info(devlink, info);5085 reporter = devlink_health_reporter_get_from_cb(cb);
5015 if (!reporter)5086 if (!reporter)
5016 return -EINVAL;5087 return -EINVAL;
5017 5088
5018 if (!reporter->ops->dump) {5089 if (!reporter->ops->dump) {
5019 devlink_health_reporter_put(reporter);5090 err = -EOPNOTSUPP;
5020 return -EOPNOTSUPP;5091 goto out;
5021 }5092 }
5022
5023 mutex_lock(&reporter->dump_lock);5093 mutex_lock(&reporter->dump_lock);
5024 err = devlink_health_do_dump(reporter, NULL);5094 if (!start) {
5025 if (err)5095 err = devlink_health_do_dump(reporter, NULL);
5026 goto out;5096 if (err)
5027 5097 goto unlock;
5028 err = devlink_fmsg_snd(reporter->dump_fmsg, info,5098 cb->args[1] = reporter->dump_ts;
5029 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);5099 }
5100 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5101 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5102 err = -EAGAIN;
5103 goto unlock;
5104 }
5030 5105
5031out:5106 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5107 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5108unlock:
5032 mutex_unlock(&reporter->dump_lock);5109 mutex_unlock(&reporter->dump_lock);
5110out:
5033 devlink_health_reporter_put(reporter);5111 devlink_health_reporter_put(reporter);
5034 return err;5112 return err;
5035}5113}
@@ -5366,7 +5444,7 @@ static const struct genl_ops devlink_nl_ops[] = { · 330 unmodified lines
5366 {5444 {
5367 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,5445 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
5368 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,5446 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
5369 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,5447 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
5370 .flags = GENL_ADMIN_PERM,5448 .flags = GENL_ADMIN_PERM,
5371 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |5449 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5372 DEVLINK_NL_FLAG_NO_LOCK,5450 DEVLINK_NL_FLAG_NO_LOCK,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t