1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3
4 #include <linux/mlx5/driver.h>
5 #include "lib/tout.h"
6
7 struct mlx5_timeouts {
8 u64 to[MAX_TIMEOUT_TYPES];
9 };
10
11 static const u32 tout_def_sw_val[MAX_TIMEOUT_TYPES] = {
12 [MLX5_TO_FW_PRE_INIT_TIMEOUT_MS] = 120000,
13 [MLX5_TO_FW_PRE_INIT_ON_RECOVERY_TIMEOUT_MS] = 7200000,
14 [MLX5_TO_FW_PRE_INIT_WARN_MESSAGE_INTERVAL_MS] = 20000,
15 [MLX5_TO_FW_PRE_INIT_WAIT_MS] = 2,
16 [MLX5_TO_FW_INIT_MS] = 2000,
17 [MLX5_TO_CMD_MS] = 60000,
18 [MLX5_TO_PCI_TOGGLE_MS] = 2000,
19 [MLX5_TO_HEALTH_POLL_INTERVAL_MS] = 2000,
20 [MLX5_TO_FULL_CRDUMP_MS] = 60000,
21 [MLX5_TO_FW_RESET_MS] = 60000,
22 [MLX5_TO_FLUSH_ON_ERROR_MS] = 2000,
23 [MLX5_TO_PCI_SYNC_UPDATE_MS] = 5000,
24 [MLX5_TO_TEARDOWN_MS] = 3000,
25 [MLX5_TO_FSM_REACTIVATE_MS] = 5000,
26 [MLX5_TO_RECLAIM_PAGES_MS] = 5000,
27 [MLX5_TO_RECLAIM_VFS_PAGES_MS] = 120000,
28 [MLX5_TO_RESET_UNLOAD_MS] = 300000
29 };
30
tout_set(struct mlx5_core_dev * dev,u64 val,enum mlx5_timeouts_types type)31 static void tout_set(struct mlx5_core_dev *dev, u64 val, enum mlx5_timeouts_types type)
32 {
33 dev->timeouts->to[type] = val;
34 }
35
mlx5_tout_init(struct mlx5_core_dev * dev)36 int mlx5_tout_init(struct mlx5_core_dev *dev)
37 {
38 int i;
39
40 dev->timeouts = kmalloc(sizeof(*dev->timeouts), GFP_KERNEL);
41 if (!dev->timeouts)
42 return -ENOMEM;
43
44 for (i = 0; i < MAX_TIMEOUT_TYPES; i++)
45 tout_set(dev, tout_def_sw_val[i], i);
46
47 return 0;
48 }
49
mlx5_tout_cleanup(struct mlx5_core_dev * dev)50 void mlx5_tout_cleanup(struct mlx5_core_dev *dev)
51 {
52 kfree(dev->timeouts);
53 }
54
55 /* Time register consists of two fields to_multiplier(time out multiplier)
56 * and to_value(time out value). to_value is the quantity of the time units and
57 * to_multiplier is the type and should be one off these four values.
58 * 0x0: millisecond
59 * 0x1: seconds
60 * 0x2: minutes
61 * 0x3: hours
62 * this function converts the time stored in the two register fields into
63 * millisecond.
64 */
tout_convert_reg_field_to_ms(u32 to_mul,u32 to_val)65 static u64 tout_convert_reg_field_to_ms(u32 to_mul, u32 to_val)
66 {
67 u64 msec = to_val;
68
69 to_mul &= 0x3;
70 /* convert hours/minutes/seconds to miliseconds */
71 if (to_mul)
72 msec *= 1000 * int_pow(60, to_mul - 1);
73
74 return msec;
75 }
76
tout_convert_iseg_to_ms(u32 iseg_to)77 static u64 tout_convert_iseg_to_ms(u32 iseg_to)
78 {
79 return tout_convert_reg_field_to_ms(iseg_to >> 29, iseg_to & 0xfffff);
80 }
81
tout_is_supported(struct mlx5_core_dev * dev)82 static bool tout_is_supported(struct mlx5_core_dev *dev)
83 {
84 return !!ioread32be(&dev->iseg->cmd_q_init_to);
85 }
86
mlx5_tout_query_iseg(struct mlx5_core_dev * dev)87 void mlx5_tout_query_iseg(struct mlx5_core_dev *dev)
88 {
89 u32 to;
90
91 if (!tout_is_supported(dev))
92 return;
93
94 to = ioread32be(&dev->iseg->cmd_q_init_to);
95 tout_set(dev, tout_convert_iseg_to_ms(to), MLX5_TO_FW_INIT_MS);
96
97 to = ioread32be(&dev->iseg->cmd_exec_to);
98 tout_set(dev, tout_convert_iseg_to_ms(to), MLX5_TO_CMD_MS);
99 }
100
_mlx5_tout_ms(struct mlx5_core_dev * dev,enum mlx5_timeouts_types type)101 u64 _mlx5_tout_ms(struct mlx5_core_dev *dev, enum mlx5_timeouts_types type)
102 {
103 return dev->timeouts->to[type];
104 }
105
106 #define MLX5_TIMEOUT_QUERY(fld, reg_out) \
107 ({ \
108 struct mlx5_ifc_default_timeout_bits *time_field; \
109 u32 to_multi, to_value; \
110 u64 to_val_ms; \
111 \
112 time_field = MLX5_ADDR_OF(dtor_reg, reg_out, fld); \
113 to_multi = MLX5_GET(default_timeout, time_field, to_multiplier); \
114 to_value = MLX5_GET(default_timeout, time_field, to_value); \
115 to_val_ms = tout_convert_reg_field_to_ms(to_multi, to_value); \
116 to_val_ms; \
117 })
118
119 #define MLX5_TIMEOUT_FILL(fld, reg_out, dev, to_type, to_extra) \
120 ({ \
121 u64 fw_to = MLX5_TIMEOUT_QUERY(fld, reg_out); \
122 if (fw_to) \
123 tout_set(dev, fw_to + (to_extra), to_type); \
124 fw_to; \
125 })
126
tout_query_dtor(struct mlx5_core_dev * dev)127 static int tout_query_dtor(struct mlx5_core_dev *dev)
128 {
129 u64 pcie_toggle_to_val, tear_down_to_val;
130 u32 out[MLX5_ST_SZ_DW(dtor_reg)] = {};
131 u32 in[MLX5_ST_SZ_DW(dtor_reg)] = {};
132 int err;
133
134 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_DTOR, 0, 0);
135 if (err)
136 return err;
137
138 pcie_toggle_to_val = MLX5_TIMEOUT_FILL(pcie_toggle_to, out, dev, MLX5_TO_PCI_TOGGLE_MS, 0);
139 MLX5_TIMEOUT_FILL(fw_reset_to, out, dev, MLX5_TO_FW_RESET_MS, pcie_toggle_to_val);
140
141 tear_down_to_val = MLX5_TIMEOUT_FILL(tear_down_to, out, dev, MLX5_TO_TEARDOWN_MS, 0);
142 MLX5_TIMEOUT_FILL(pci_sync_update_to, out, dev, MLX5_TO_PCI_SYNC_UPDATE_MS,
143 tear_down_to_val);
144
145 MLX5_TIMEOUT_FILL(health_poll_to, out, dev, MLX5_TO_HEALTH_POLL_INTERVAL_MS, 0);
146 MLX5_TIMEOUT_FILL(full_crdump_to, out, dev, MLX5_TO_FULL_CRDUMP_MS, 0);
147 MLX5_TIMEOUT_FILL(flush_on_err_to, out, dev, MLX5_TO_FLUSH_ON_ERROR_MS, 0);
148 MLX5_TIMEOUT_FILL(fsm_reactivate_to, out, dev, MLX5_TO_FSM_REACTIVATE_MS, 0);
149 MLX5_TIMEOUT_FILL(reclaim_pages_to, out, dev, MLX5_TO_RECLAIM_PAGES_MS, 0);
150 MLX5_TIMEOUT_FILL(reclaim_vfs_pages_to, out, dev, MLX5_TO_RECLAIM_VFS_PAGES_MS, 0);
151 MLX5_TIMEOUT_FILL(reset_unload_to, out, dev, MLX5_TO_RESET_UNLOAD_MS, 0);
152
153 return 0;
154 }
155
mlx5_tout_query_dtor(struct mlx5_core_dev * dev)156 int mlx5_tout_query_dtor(struct mlx5_core_dev *dev)
157 {
158 if (tout_is_supported(dev))
159 return tout_query_dtor(dev);
160
161 return 0;
162 }
163