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 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 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 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 */ 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 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 82 static bool tout_is_supported(struct mlx5_core_dev *dev) 83 { 84 return !!ioread32be(&dev->iseg->cmd_q_init_to); 85 } 86 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 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 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 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