0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/kernel.h>
0034 #include <linux/random.h>
0035 #include <linux/vmalloc.h>
0036 #include <linux/hardirq.h>
0037 #include <linux/mlx5/driver.h>
0038 #include <linux/kern_levels.h>
0039 #include "mlx5_core.h"
0040 #include "lib/eq.h"
0041 #include "lib/mlx5.h"
0042 #include "lib/pci_vsc.h"
0043 #include "lib/tout.h"
0044 #include "diag/fw_tracer.h"
0045
0046 enum {
0047 MAX_MISSES = 3,
0048 };
0049
0050 enum {
0051 MLX5_HEALTH_SYNDR_FW_ERR = 0x1,
0052 MLX5_HEALTH_SYNDR_IRISC_ERR = 0x7,
0053 MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR = 0x8,
0054 MLX5_HEALTH_SYNDR_CRC_ERR = 0x9,
0055 MLX5_HEALTH_SYNDR_FETCH_PCI_ERR = 0xa,
0056 MLX5_HEALTH_SYNDR_HW_FTL_ERR = 0xb,
0057 MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR = 0xc,
0058 MLX5_HEALTH_SYNDR_EQ_ERR = 0xd,
0059 MLX5_HEALTH_SYNDR_EQ_INV = 0xe,
0060 MLX5_HEALTH_SYNDR_FFSER_ERR = 0xf,
0061 MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10
0062 };
0063
0064 enum {
0065 MLX5_DROP_NEW_HEALTH_WORK,
0066 };
0067
0068 enum {
0069 MLX5_SENSOR_NO_ERR = 0,
0070 MLX5_SENSOR_PCI_COMM_ERR = 1,
0071 MLX5_SENSOR_PCI_ERR = 2,
0072 MLX5_SENSOR_NIC_DISABLED = 3,
0073 MLX5_SENSOR_NIC_SW_RESET = 4,
0074 MLX5_SENSOR_FW_SYND_RFR = 5,
0075 };
0076
0077 enum {
0078 MLX5_SEVERITY_MASK = 0x7,
0079 MLX5_SEVERITY_VALID_MASK = 0x8,
0080 };
0081
0082 u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
0083 {
0084 return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 7;
0085 }
0086
0087 void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
0088 {
0089 u32 cur_cmdq_addr_l_sz;
0090
0091 cur_cmdq_addr_l_sz = ioread32be(&dev->iseg->cmdq_addr_l_sz);
0092 iowrite32be((cur_cmdq_addr_l_sz & 0xFFFFF000) |
0093 state << MLX5_NIC_IFC_OFFSET,
0094 &dev->iseg->cmdq_addr_l_sz);
0095 }
0096
0097 static bool sensor_pci_not_working(struct mlx5_core_dev *dev)
0098 {
0099 struct mlx5_core_health *health = &dev->priv.health;
0100 struct health_buffer __iomem *h = health->health;
0101
0102
0103 return (ioread32be(&h->fw_ver) == 0xffffffff);
0104 }
0105
0106 static int mlx5_health_get_rfr(u8 rfr_severity)
0107 {
0108 return rfr_severity >> MLX5_RFR_BIT_OFFSET;
0109 }
0110
0111 static bool sensor_fw_synd_rfr(struct mlx5_core_dev *dev)
0112 {
0113 struct mlx5_core_health *health = &dev->priv.health;
0114 struct health_buffer __iomem *h = health->health;
0115 u8 synd = ioread8(&h->synd);
0116 u8 rfr;
0117
0118 rfr = mlx5_health_get_rfr(ioread8(&h->rfr_severity));
0119
0120 if (rfr && synd)
0121 mlx5_core_dbg(dev, "FW requests reset, synd: %d\n", synd);
0122 return rfr && synd;
0123 }
0124
0125 u32 mlx5_health_check_fatal_sensors(struct mlx5_core_dev *dev)
0126 {
0127 if (sensor_pci_not_working(dev))
0128 return MLX5_SENSOR_PCI_COMM_ERR;
0129 if (pci_channel_offline(dev->pdev))
0130 return MLX5_SENSOR_PCI_ERR;
0131 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
0132 return MLX5_SENSOR_NIC_DISABLED;
0133 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_SW_RESET)
0134 return MLX5_SENSOR_NIC_SW_RESET;
0135 if (sensor_fw_synd_rfr(dev))
0136 return MLX5_SENSOR_FW_SYND_RFR;
0137
0138 return MLX5_SENSOR_NO_ERR;
0139 }
0140
0141 static int lock_sem_sw_reset(struct mlx5_core_dev *dev, bool lock)
0142 {
0143 enum mlx5_vsc_state state;
0144 int ret;
0145
0146 if (!mlx5_core_is_pf(dev))
0147 return -EBUSY;
0148
0149
0150
0151
0152
0153 ret = mlx5_vsc_gw_lock(dev);
0154 if (ret == -EBUSY)
0155 return -EINVAL;
0156 if (ret)
0157 return ret;
0158
0159 state = lock ? MLX5_VSC_LOCK : MLX5_VSC_UNLOCK;
0160
0161
0162
0163
0164 ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, state);
0165 if (ret)
0166 mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
0167
0168
0169 mlx5_vsc_gw_unlock(dev);
0170
0171 return ret;
0172 }
0173
0174 static bool reset_fw_if_needed(struct mlx5_core_dev *dev)
0175 {
0176 bool supported = (ioread32be(&dev->iseg->initializing) >>
0177 MLX5_FW_RESET_SUPPORTED_OFFSET) & 1;
0178 u32 fatal_error;
0179
0180 if (!supported)
0181 return false;
0182
0183
0184
0185
0186
0187
0188 fatal_error = mlx5_health_check_fatal_sensors(dev);
0189 if (fatal_error == MLX5_SENSOR_PCI_COMM_ERR ||
0190 fatal_error == MLX5_SENSOR_NIC_DISABLED ||
0191 fatal_error == MLX5_SENSOR_NIC_SW_RESET) {
0192 mlx5_core_warn(dev, "Not issuing FW reset. Either it's already done or won't help.");
0193 return false;
0194 }
0195
0196 mlx5_core_warn(dev, "Issuing FW Reset\n");
0197
0198
0199
0200 mlx5_set_nic_state(dev, MLX5_NIC_IFC_SW_RESET);
0201
0202 return true;
0203 }
0204
0205 static void enter_error_state(struct mlx5_core_dev *dev, bool force)
0206 {
0207 if (mlx5_health_check_fatal_sensors(dev) || force) {
0208 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
0209 mlx5_cmd_flush(dev);
0210 }
0211
0212 mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_SYS_ERROR, (void *)1);
0213 }
0214
0215 void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
0216 {
0217 bool err_detected = false;
0218
0219
0220 if ((mlx5_health_check_fatal_sensors(dev) || force) &&
0221 dev->state == MLX5_DEVICE_STATE_UP) {
0222 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
0223 err_detected = true;
0224 }
0225 mutex_lock(&dev->intf_state_mutex);
0226 if (!err_detected && dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
0227 goto unlock;
0228
0229 enter_error_state(dev, force);
0230 unlock:
0231 mutex_unlock(&dev->intf_state_mutex);
0232 }
0233
0234 void mlx5_error_sw_reset(struct mlx5_core_dev *dev)
0235 {
0236 unsigned long end, delay_ms = mlx5_tout_ms(dev, PCI_TOGGLE);
0237 int lock = -EBUSY;
0238
0239 mutex_lock(&dev->intf_state_mutex);
0240 if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
0241 goto unlock;
0242
0243 mlx5_core_err(dev, "start\n");
0244
0245 if (mlx5_health_check_fatal_sensors(dev) == MLX5_SENSOR_FW_SYND_RFR) {
0246
0247 lock = lock_sem_sw_reset(dev, true);
0248
0249 if (lock == -EBUSY) {
0250 delay_ms = mlx5_tout_ms(dev, FULL_CRDUMP);
0251 goto recover_from_sw_reset;
0252 }
0253
0254 reset_fw_if_needed(dev);
0255 }
0256
0257 recover_from_sw_reset:
0258
0259 end = jiffies + msecs_to_jiffies(delay_ms);
0260 do {
0261 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
0262 break;
0263
0264 msleep(20);
0265 } while (!time_after(jiffies, end));
0266
0267 if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
0268 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
0269 mlx5_get_nic_state(dev), delay_ms);
0270 }
0271
0272
0273 if (!lock)
0274 lock_sem_sw_reset(dev, false);
0275
0276 mlx5_core_err(dev, "end\n");
0277
0278 unlock:
0279 mutex_unlock(&dev->intf_state_mutex);
0280 }
0281
0282 static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
0283 {
0284 u8 nic_interface = mlx5_get_nic_state(dev);
0285
0286 switch (nic_interface) {
0287 case MLX5_NIC_IFC_FULL:
0288 mlx5_core_warn(dev, "Expected to see disabled NIC but it is full driver\n");
0289 break;
0290
0291 case MLX5_NIC_IFC_DISABLED:
0292 mlx5_core_warn(dev, "starting teardown\n");
0293 break;
0294
0295 case MLX5_NIC_IFC_NO_DRAM_NIC:
0296 mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n");
0297 break;
0298
0299 case MLX5_NIC_IFC_SW_RESET:
0300
0301
0302
0303
0304
0305
0306
0307
0308 if (dev->priv.health.fatal_error != MLX5_SENSOR_PCI_COMM_ERR)
0309 mlx5_core_warn(dev, "NIC SW reset in progress\n");
0310 break;
0311
0312 default:
0313 mlx5_core_warn(dev, "Expected to see disabled NIC but it is has invalid value %d\n",
0314 nic_interface);
0315 }
0316
0317 mlx5_disable_device(dev);
0318 }
0319
0320 int mlx5_health_wait_pci_up(struct mlx5_core_dev *dev)
0321 {
0322 unsigned long end;
0323
0324 end = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, FW_RESET));
0325 while (sensor_pci_not_working(dev)) {
0326 if (time_after(jiffies, end))
0327 return -ETIMEDOUT;
0328 msleep(100);
0329 }
0330 return 0;
0331 }
0332
0333 static int mlx5_health_try_recover(struct mlx5_core_dev *dev)
0334 {
0335 mlx5_core_warn(dev, "handling bad device here\n");
0336 mlx5_handle_bad_state(dev);
0337 if (mlx5_health_wait_pci_up(dev)) {
0338 mlx5_core_err(dev, "health recovery flow aborted, PCI reads still not working\n");
0339 return -EIO;
0340 }
0341 mlx5_core_err(dev, "starting health recovery flow\n");
0342 if (mlx5_recover_device(dev) || mlx5_health_check_fatal_sensors(dev)) {
0343 mlx5_core_err(dev, "health recovery failed\n");
0344 return -EIO;
0345 }
0346
0347 mlx5_core_info(dev, "health recovery succeeded\n");
0348 return 0;
0349 }
0350
0351 static const char *hsynd_str(u8 synd)
0352 {
0353 switch (synd) {
0354 case MLX5_HEALTH_SYNDR_FW_ERR:
0355 return "firmware internal error";
0356 case MLX5_HEALTH_SYNDR_IRISC_ERR:
0357 return "irisc not responding";
0358 case MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR:
0359 return "unrecoverable hardware error";
0360 case MLX5_HEALTH_SYNDR_CRC_ERR:
0361 return "firmware CRC error";
0362 case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR:
0363 return "ICM fetch PCI error";
0364 case MLX5_HEALTH_SYNDR_HW_FTL_ERR:
0365 return "HW fatal error\n";
0366 case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR:
0367 return "async EQ buffer overrun";
0368 case MLX5_HEALTH_SYNDR_EQ_ERR:
0369 return "EQ error";
0370 case MLX5_HEALTH_SYNDR_EQ_INV:
0371 return "Invalid EQ referenced";
0372 case MLX5_HEALTH_SYNDR_FFSER_ERR:
0373 return "FFSER error";
0374 case MLX5_HEALTH_SYNDR_HIGH_TEMP:
0375 return "High temperature";
0376 default:
0377 return "unrecognized error";
0378 }
0379 }
0380
0381 static const char *mlx5_loglevel_str(int level)
0382 {
0383 switch (level) {
0384 case LOGLEVEL_EMERG:
0385 return "EMERGENCY";
0386 case LOGLEVEL_ALERT:
0387 return "ALERT";
0388 case LOGLEVEL_CRIT:
0389 return "CRITICAL";
0390 case LOGLEVEL_ERR:
0391 return "ERROR";
0392 case LOGLEVEL_WARNING:
0393 return "WARNING";
0394 case LOGLEVEL_NOTICE:
0395 return "NOTICE";
0396 case LOGLEVEL_INFO:
0397 return "INFO";
0398 case LOGLEVEL_DEBUG:
0399 return "DEBUG";
0400 }
0401 return "Unknown log level";
0402 }
0403
0404 static int mlx5_health_get_severity(u8 rfr_severity)
0405 {
0406 return rfr_severity & MLX5_SEVERITY_VALID_MASK ?
0407 rfr_severity & MLX5_SEVERITY_MASK : LOGLEVEL_ERR;
0408 }
0409
0410 static void print_health_info(struct mlx5_core_dev *dev)
0411 {
0412 struct mlx5_core_health *health = &dev->priv.health;
0413 struct health_buffer __iomem *h = health->health;
0414 u8 rfr_severity;
0415 int severity;
0416 int i;
0417
0418
0419 if (!ioread8(&h->synd))
0420 return;
0421
0422 if (ioread32be(&h->fw_ver) == 0xFFFFFFFF) {
0423 mlx5_log(dev, LOGLEVEL_ERR, "PCI slot is unavailable\n");
0424 return;
0425 }
0426
0427 rfr_severity = ioread8(&h->rfr_severity);
0428 severity = mlx5_health_get_severity(rfr_severity);
0429 mlx5_log(dev, severity, "Health issue observed, %s, severity(%d) %s:\n",
0430 hsynd_str(ioread8(&h->synd)), severity, mlx5_loglevel_str(severity));
0431
0432 for (i = 0; i < ARRAY_SIZE(h->assert_var); i++)
0433 mlx5_log(dev, severity, "assert_var[%d] 0x%08x\n", i,
0434 ioread32be(h->assert_var + i));
0435
0436 mlx5_log(dev, severity, "assert_exit_ptr 0x%08x\n", ioread32be(&h->assert_exit_ptr));
0437 mlx5_log(dev, severity, "assert_callra 0x%08x\n", ioread32be(&h->assert_callra));
0438 mlx5_log(dev, severity, "fw_ver %d.%d.%d", fw_rev_maj(dev), fw_rev_min(dev),
0439 fw_rev_sub(dev));
0440 mlx5_log(dev, severity, "time %u\n", ioread32be(&h->time));
0441 mlx5_log(dev, severity, "hw_id 0x%08x\n", ioread32be(&h->hw_id));
0442 mlx5_log(dev, severity, "rfr %d\n", mlx5_health_get_rfr(rfr_severity));
0443 mlx5_log(dev, severity, "severity %d (%s)\n", severity, mlx5_loglevel_str(severity));
0444 mlx5_log(dev, severity, "irisc_index %d\n", ioread8(&h->irisc_index));
0445 mlx5_log(dev, severity, "synd 0x%x: %s\n", ioread8(&h->synd),
0446 hsynd_str(ioread8(&h->synd)));
0447 mlx5_log(dev, severity, "ext_synd 0x%04x\n", ioread16be(&h->ext_synd));
0448 mlx5_log(dev, severity, "raw fw_ver 0x%08x\n", ioread32be(&h->fw_ver));
0449 }
0450
0451 static int
0452 mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
0453 struct devlink_fmsg *fmsg,
0454 struct netlink_ext_ack *extack)
0455 {
0456 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
0457 struct mlx5_core_health *health = &dev->priv.health;
0458 struct health_buffer __iomem *h = health->health;
0459 u8 synd;
0460 int err;
0461
0462 synd = ioread8(&h->synd);
0463 err = devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
0464 if (err || !synd)
0465 return err;
0466 return devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
0467 }
0468
0469 struct mlx5_fw_reporter_ctx {
0470 u8 err_synd;
0471 int miss_counter;
0472 };
0473
0474 static int
0475 mlx5_fw_reporter_ctx_pairs_put(struct devlink_fmsg *fmsg,
0476 struct mlx5_fw_reporter_ctx *fw_reporter_ctx)
0477 {
0478 int err;
0479
0480 err = devlink_fmsg_u8_pair_put(fmsg, "syndrome",
0481 fw_reporter_ctx->err_synd);
0482 if (err)
0483 return err;
0484 err = devlink_fmsg_u32_pair_put(fmsg, "fw_miss_counter",
0485 fw_reporter_ctx->miss_counter);
0486 if (err)
0487 return err;
0488 return 0;
0489 }
0490
0491 static int
0492 mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev,
0493 struct devlink_fmsg *fmsg)
0494 {
0495 struct mlx5_core_health *health = &dev->priv.health;
0496 struct health_buffer __iomem *h = health->health;
0497 u8 rfr_severity;
0498 int err;
0499 int i;
0500
0501 if (!ioread8(&h->synd))
0502 return 0;
0503
0504 err = devlink_fmsg_pair_nest_start(fmsg, "health buffer");
0505 if (err)
0506 return err;
0507 err = devlink_fmsg_obj_nest_start(fmsg);
0508 if (err)
0509 return err;
0510 err = devlink_fmsg_arr_pair_nest_start(fmsg, "assert_var");
0511 if (err)
0512 return err;
0513
0514 for (i = 0; i < ARRAY_SIZE(h->assert_var); i++) {
0515 err = devlink_fmsg_u32_put(fmsg, ioread32be(h->assert_var + i));
0516 if (err)
0517 return err;
0518 }
0519 err = devlink_fmsg_arr_pair_nest_end(fmsg);
0520 if (err)
0521 return err;
0522 err = devlink_fmsg_u32_pair_put(fmsg, "assert_exit_ptr",
0523 ioread32be(&h->assert_exit_ptr));
0524 if (err)
0525 return err;
0526 err = devlink_fmsg_u32_pair_put(fmsg, "assert_callra",
0527 ioread32be(&h->assert_callra));
0528 if (err)
0529 return err;
0530 err = devlink_fmsg_u32_pair_put(fmsg, "time", ioread32be(&h->time));
0531 if (err)
0532 return err;
0533 err = devlink_fmsg_u32_pair_put(fmsg, "hw_id", ioread32be(&h->hw_id));
0534 if (err)
0535 return err;
0536 rfr_severity = ioread8(&h->rfr_severity);
0537 err = devlink_fmsg_u8_pair_put(fmsg, "rfr", mlx5_health_get_rfr(rfr_severity));
0538 if (err)
0539 return err;
0540 err = devlink_fmsg_u8_pair_put(fmsg, "severity", mlx5_health_get_severity(rfr_severity));
0541 if (err)
0542 return err;
0543 err = devlink_fmsg_u8_pair_put(fmsg, "irisc_index",
0544 ioread8(&h->irisc_index));
0545 if (err)
0546 return err;
0547 err = devlink_fmsg_u8_pair_put(fmsg, "synd", ioread8(&h->synd));
0548 if (err)
0549 return err;
0550 err = devlink_fmsg_u32_pair_put(fmsg, "ext_synd",
0551 ioread16be(&h->ext_synd));
0552 if (err)
0553 return err;
0554 err = devlink_fmsg_u32_pair_put(fmsg, "raw_fw_ver",
0555 ioread32be(&h->fw_ver));
0556 if (err)
0557 return err;
0558 err = devlink_fmsg_obj_nest_end(fmsg);
0559 if (err)
0560 return err;
0561 return devlink_fmsg_pair_nest_end(fmsg);
0562 }
0563
0564 static int
0565 mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter,
0566 struct devlink_fmsg *fmsg, void *priv_ctx,
0567 struct netlink_ext_ack *extack)
0568 {
0569 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
0570 int err;
0571
0572 err = mlx5_fw_tracer_trigger_core_dump_general(dev);
0573 if (err)
0574 return err;
0575
0576 if (priv_ctx) {
0577 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
0578
0579 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
0580 if (err)
0581 return err;
0582 }
0583
0584 err = mlx5_fw_reporter_heath_buffer_data_put(dev, fmsg);
0585 if (err)
0586 return err;
0587 return mlx5_fw_tracer_get_saved_traces_objects(dev->tracer, fmsg);
0588 }
0589
0590 static void mlx5_fw_reporter_err_work(struct work_struct *work)
0591 {
0592 struct mlx5_fw_reporter_ctx fw_reporter_ctx;
0593 struct mlx5_core_health *health;
0594
0595 health = container_of(work, struct mlx5_core_health, report_work);
0596
0597 if (IS_ERR_OR_NULL(health->fw_reporter))
0598 return;
0599
0600 fw_reporter_ctx.err_synd = health->synd;
0601 fw_reporter_ctx.miss_counter = health->miss_counter;
0602 if (fw_reporter_ctx.err_synd) {
0603 devlink_health_report(health->fw_reporter,
0604 "FW syndrom reported", &fw_reporter_ctx);
0605 return;
0606 }
0607 if (fw_reporter_ctx.miss_counter)
0608 devlink_health_report(health->fw_reporter,
0609 "FW miss counter reported",
0610 &fw_reporter_ctx);
0611 }
0612
0613 static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = {
0614 .name = "fw",
0615 .diagnose = mlx5_fw_reporter_diagnose,
0616 .dump = mlx5_fw_reporter_dump,
0617 };
0618
0619 static int
0620 mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
0621 void *priv_ctx,
0622 struct netlink_ext_ack *extack)
0623 {
0624 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
0625
0626 return mlx5_health_try_recover(dev);
0627 }
0628
0629 static int
0630 mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
0631 struct devlink_fmsg *fmsg, void *priv_ctx,
0632 struct netlink_ext_ack *extack)
0633 {
0634 struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
0635 u32 crdump_size = dev->priv.health.crdump_size;
0636 u32 *cr_data;
0637 int err;
0638
0639 if (!mlx5_core_is_pf(dev))
0640 return -EPERM;
0641
0642 cr_data = kvmalloc(crdump_size, GFP_KERNEL);
0643 if (!cr_data)
0644 return -ENOMEM;
0645 err = mlx5_crdump_collect(dev, cr_data);
0646 if (err)
0647 goto free_data;
0648
0649 if (priv_ctx) {
0650 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
0651
0652 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
0653 if (err)
0654 goto free_data;
0655 }
0656
0657 err = devlink_fmsg_binary_pair_put(fmsg, "crdump_data", cr_data, crdump_size);
0658
0659 free_data:
0660 kvfree(cr_data);
0661 return err;
0662 }
0663
0664 static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
0665 {
0666 struct mlx5_fw_reporter_ctx fw_reporter_ctx;
0667 struct mlx5_core_health *health;
0668 struct mlx5_core_dev *dev;
0669 struct devlink *devlink;
0670 struct mlx5_priv *priv;
0671
0672 health = container_of(work, struct mlx5_core_health, fatal_report_work);
0673 priv = container_of(health, struct mlx5_priv, health);
0674 dev = container_of(priv, struct mlx5_core_dev, priv);
0675 devlink = priv_to_devlink(dev);
0676
0677 enter_error_state(dev, false);
0678 if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) {
0679 devl_lock(devlink);
0680 if (mlx5_health_try_recover(dev))
0681 mlx5_core_err(dev, "health recovery failed\n");
0682 devl_unlock(devlink);
0683 return;
0684 }
0685 fw_reporter_ctx.err_synd = health->synd;
0686 fw_reporter_ctx.miss_counter = health->miss_counter;
0687 if (devlink_health_report(health->fw_fatal_reporter,
0688 "FW fatal error reported", &fw_reporter_ctx) == -ECANCELED) {
0689
0690
0691
0692
0693
0694 mlx5_core_err(dev, "Driver is in error state. Unloading\n");
0695 mlx5_unload_one(dev);
0696 }
0697 }
0698
0699 static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
0700 .name = "fw_fatal",
0701 .recover = mlx5_fw_fatal_reporter_recover,
0702 .dump = mlx5_fw_fatal_reporter_dump,
0703 };
0704
0705 #define MLX5_REPORTER_FW_GRACEFUL_PERIOD 1200000
0706 static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev)
0707 {
0708 struct mlx5_core_health *health = &dev->priv.health;
0709 struct devlink *devlink = priv_to_devlink(dev);
0710
0711 health->fw_reporter =
0712 devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops,
0713 0, dev);
0714 if (IS_ERR(health->fw_reporter))
0715 mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
0716 PTR_ERR(health->fw_reporter));
0717
0718 health->fw_fatal_reporter =
0719 devlink_health_reporter_create(devlink,
0720 &mlx5_fw_fatal_reporter_ops,
0721 MLX5_REPORTER_FW_GRACEFUL_PERIOD,
0722 dev);
0723 if (IS_ERR(health->fw_fatal_reporter))
0724 mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
0725 PTR_ERR(health->fw_fatal_reporter));
0726 }
0727
0728 static void mlx5_fw_reporters_destroy(struct mlx5_core_dev *dev)
0729 {
0730 struct mlx5_core_health *health = &dev->priv.health;
0731
0732 if (!IS_ERR_OR_NULL(health->fw_reporter))
0733 devlink_health_reporter_destroy(health->fw_reporter);
0734
0735 if (!IS_ERR_OR_NULL(health->fw_fatal_reporter))
0736 devlink_health_reporter_destroy(health->fw_fatal_reporter);
0737 }
0738
0739 static unsigned long get_next_poll_jiffies(struct mlx5_core_dev *dev)
0740 {
0741 unsigned long next;
0742
0743 get_random_bytes(&next, sizeof(next));
0744 next %= HZ;
0745 next += jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, HEALTH_POLL_INTERVAL));
0746
0747 return next;
0748 }
0749
0750 void mlx5_trigger_health_work(struct mlx5_core_dev *dev)
0751 {
0752 struct mlx5_core_health *health = &dev->priv.health;
0753 unsigned long flags;
0754
0755 spin_lock_irqsave(&health->wq_lock, flags);
0756 if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
0757 queue_work(health->wq, &health->fatal_report_work);
0758 else
0759 mlx5_core_err(dev, "new health works are not permitted at this stage\n");
0760 spin_unlock_irqrestore(&health->wq_lock, flags);
0761 }
0762
0763 #define MLX5_MSEC_PER_HOUR (MSEC_PER_SEC * 60 * 60)
0764 static void mlx5_health_log_ts_update(struct work_struct *work)
0765 {
0766 struct delayed_work *dwork = to_delayed_work(work);
0767 u32 out[MLX5_ST_SZ_DW(mrtc_reg)] = {};
0768 u32 in[MLX5_ST_SZ_DW(mrtc_reg)] = {};
0769 struct mlx5_core_health *health;
0770 struct mlx5_core_dev *dev;
0771 struct mlx5_priv *priv;
0772 u64 now_us;
0773
0774 health = container_of(dwork, struct mlx5_core_health, update_fw_log_ts_work);
0775 priv = container_of(health, struct mlx5_priv, health);
0776 dev = container_of(priv, struct mlx5_core_dev, priv);
0777
0778 now_us = ktime_to_us(ktime_get_real());
0779
0780 MLX5_SET(mrtc_reg, in, time_h, now_us >> 32);
0781 MLX5_SET(mrtc_reg, in, time_l, now_us & 0xFFFFFFFF);
0782 mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_MRTC, 0, 1);
0783
0784 queue_delayed_work(health->wq, &health->update_fw_log_ts_work,
0785 msecs_to_jiffies(MLX5_MSEC_PER_HOUR));
0786 }
0787
0788 static void poll_health(struct timer_list *t)
0789 {
0790 struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);
0791 struct mlx5_core_health *health = &dev->priv.health;
0792 struct health_buffer __iomem *h = health->health;
0793 u32 fatal_error;
0794 u8 prev_synd;
0795 u32 count;
0796
0797 if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
0798 goto out;
0799
0800 fatal_error = mlx5_health_check_fatal_sensors(dev);
0801
0802 if (fatal_error && !health->fatal_error) {
0803 mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
0804 dev->priv.health.fatal_error = fatal_error;
0805 print_health_info(dev);
0806 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
0807 mlx5_trigger_health_work(dev);
0808 return;
0809 }
0810
0811 count = ioread32be(health->health_counter);
0812 if (count == health->prev)
0813 ++health->miss_counter;
0814 else
0815 health->miss_counter = 0;
0816
0817 health->prev = count;
0818 if (health->miss_counter == MAX_MISSES) {
0819 mlx5_core_err(dev, "device's health compromised - reached miss count\n");
0820 print_health_info(dev);
0821 queue_work(health->wq, &health->report_work);
0822 }
0823
0824 prev_synd = health->synd;
0825 health->synd = ioread8(&h->synd);
0826 if (health->synd && health->synd != prev_synd)
0827 queue_work(health->wq, &health->report_work);
0828
0829 out:
0830 mod_timer(&health->timer, get_next_poll_jiffies(dev));
0831 }
0832
0833 void mlx5_start_health_poll(struct mlx5_core_dev *dev)
0834 {
0835 u64 poll_interval_ms = mlx5_tout_ms(dev, HEALTH_POLL_INTERVAL);
0836 struct mlx5_core_health *health = &dev->priv.health;
0837
0838 timer_setup(&health->timer, poll_health, 0);
0839 health->fatal_error = MLX5_SENSOR_NO_ERR;
0840 clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
0841 health->health = &dev->iseg->health;
0842 health->health_counter = &dev->iseg->health_counter;
0843
0844 health->timer.expires = jiffies + msecs_to_jiffies(poll_interval_ms);
0845 add_timer(&health->timer);
0846
0847 if (mlx5_core_is_pf(dev) && MLX5_CAP_MCAM_REG(dev, mrtc))
0848 queue_delayed_work(health->wq, &health->update_fw_log_ts_work, 0);
0849 }
0850
0851 void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health)
0852 {
0853 struct mlx5_core_health *health = &dev->priv.health;
0854 unsigned long flags;
0855
0856 if (disable_health) {
0857 spin_lock_irqsave(&health->wq_lock, flags);
0858 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
0859 spin_unlock_irqrestore(&health->wq_lock, flags);
0860 }
0861
0862 del_timer_sync(&health->timer);
0863 }
0864
0865 void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
0866 {
0867 struct mlx5_core_health *health = &dev->priv.health;
0868 unsigned long flags;
0869
0870 spin_lock_irqsave(&health->wq_lock, flags);
0871 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
0872 spin_unlock_irqrestore(&health->wq_lock, flags);
0873 cancel_delayed_work_sync(&health->update_fw_log_ts_work);
0874 cancel_work_sync(&health->report_work);
0875 cancel_work_sync(&health->fatal_report_work);
0876 }
0877
0878 void mlx5_health_flush(struct mlx5_core_dev *dev)
0879 {
0880 struct mlx5_core_health *health = &dev->priv.health;
0881
0882 flush_workqueue(health->wq);
0883 }
0884
0885 void mlx5_health_cleanup(struct mlx5_core_dev *dev)
0886 {
0887 struct mlx5_core_health *health = &dev->priv.health;
0888
0889 cancel_delayed_work_sync(&health->update_fw_log_ts_work);
0890 destroy_workqueue(health->wq);
0891 mlx5_fw_reporters_destroy(dev);
0892 }
0893
0894 int mlx5_health_init(struct mlx5_core_dev *dev)
0895 {
0896 struct mlx5_core_health *health;
0897 char *name;
0898
0899 mlx5_fw_reporters_create(dev);
0900
0901 health = &dev->priv.health;
0902 name = kmalloc(64, GFP_KERNEL);
0903 if (!name)
0904 goto out_err;
0905
0906 strcpy(name, "mlx5_health");
0907 strcat(name, dev_name(dev->device));
0908 health->wq = create_singlethread_workqueue(name);
0909 kfree(name);
0910 if (!health->wq)
0911 goto out_err;
0912 spin_lock_init(&health->wq_lock);
0913 INIT_WORK(&health->fatal_report_work, mlx5_fw_fatal_reporter_err_work);
0914 INIT_WORK(&health->report_work, mlx5_fw_reporter_err_work);
0915 INIT_DELAYED_WORK(&health->update_fw_log_ts_work, mlx5_health_log_ts_update);
0916
0917 return 0;
0918
0919 out_err:
0920 mlx5_fw_reporters_destroy(dev);
0921 return -ENOMEM;
0922 }