root/drivers/net/ethernet/mellanox/mlx5/core/health.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlx5_get_nic_state
  2. mlx5_set_nic_state
  3. sensor_pci_not_working
  4. sensor_fw_synd_rfr
  5. check_fatal_sensors
  6. lock_sem_sw_reset
  7. reset_fw_if_needed
  8. mlx5_enter_error_state
  9. mlx5_error_sw_reset
  10. mlx5_handle_bad_state
  11. mlx5_health_try_recover
  12. hsynd_str
  13. print_health_info
  14. mlx5_fw_reporter_diagnose
  15. mlx5_fw_reporter_ctx_pairs_put
  16. mlx5_fw_reporter_heath_buffer_data_put
  17. mlx5_fw_reporter_dump
  18. mlx5_fw_reporter_err_work
  19. mlx5_fw_fatal_reporter_recover
  20. mlx5_fw_fatal_reporter_dump
  21. mlx5_fw_fatal_reporter_err_work
  22. mlx5_fw_reporters_create
  23. mlx5_fw_reporters_destroy
  24. get_next_poll_jiffies
  25. mlx5_trigger_health_work
  26. poll_health
  27. mlx5_start_health_poll
  28. mlx5_stop_health_poll
  29. mlx5_drain_health_wq
  30. mlx5_health_flush
  31. mlx5_health_cleanup
  32. mlx5_health_init

   1 /*
   2  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
   3  *
   4  * This software is available to you under a choice of one of two
   5  * licenses.  You may choose to be licensed under the terms of the GNU
   6  * General Public License (GPL) Version 2, available from the file
   7  * COPYING in the main directory of this source tree, or the
   8  * OpenIB.org BSD license below:
   9  *
  10  *     Redistribution and use in source and binary forms, with or
  11  *     without modification, are permitted provided that the following
  12  *     conditions are met:
  13  *
  14  *      - Redistributions of source code must retain the above
  15  *        copyright notice, this list of conditions and the following
  16  *        disclaimer.
  17  *
  18  *      - Redistributions in binary form must reproduce the above
  19  *        copyright notice, this list of conditions and the following
  20  *        disclaimer in the documentation and/or other materials
  21  *        provided with the distribution.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  */
  32 
  33 #include <linux/kernel.h>
  34 #include <linux/module.h>
  35 #include <linux/random.h>
  36 #include <linux/vmalloc.h>
  37 #include <linux/hardirq.h>
  38 #include <linux/mlx5/driver.h>
  39 #include <linux/mlx5/cmd.h>
  40 #include "mlx5_core.h"
  41 #include "lib/eq.h"
  42 #include "lib/mlx5.h"
  43 #include "lib/pci_vsc.h"
  44 #include "diag/fw_tracer.h"
  45 
  46 enum {
  47         MLX5_HEALTH_POLL_INTERVAL       = 2 * HZ,
  48         MAX_MISSES                      = 3,
  49 };
  50 
  51 enum {
  52         MLX5_HEALTH_SYNDR_FW_ERR                = 0x1,
  53         MLX5_HEALTH_SYNDR_IRISC_ERR             = 0x7,
  54         MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR  = 0x8,
  55         MLX5_HEALTH_SYNDR_CRC_ERR               = 0x9,
  56         MLX5_HEALTH_SYNDR_FETCH_PCI_ERR         = 0xa,
  57         MLX5_HEALTH_SYNDR_HW_FTL_ERR            = 0xb,
  58         MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR  = 0xc,
  59         MLX5_HEALTH_SYNDR_EQ_ERR                = 0xd,
  60         MLX5_HEALTH_SYNDR_EQ_INV                = 0xe,
  61         MLX5_HEALTH_SYNDR_FFSER_ERR             = 0xf,
  62         MLX5_HEALTH_SYNDR_HIGH_TEMP             = 0x10
  63 };
  64 
  65 enum {
  66         MLX5_DROP_NEW_HEALTH_WORK,
  67 };
  68 
  69 enum  {
  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,
  76 };
  77 
  78 u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
  79 {
  80         return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 7;
  81 }
  82 
  83 void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
  84 {
  85         u32 cur_cmdq_addr_l_sz;
  86 
  87         cur_cmdq_addr_l_sz = ioread32be(&dev->iseg->cmdq_addr_l_sz);
  88         iowrite32be((cur_cmdq_addr_l_sz & 0xFFFFF000) |
  89                     state << MLX5_NIC_IFC_OFFSET,
  90                     &dev->iseg->cmdq_addr_l_sz);
  91 }
  92 
  93 static bool sensor_pci_not_working(struct mlx5_core_dev *dev)
  94 {
  95         struct mlx5_core_health *health = &dev->priv.health;
  96         struct health_buffer __iomem *h = health->health;
  97 
  98         /* Offline PCI reads return 0xffffffff */
  99         return (ioread32be(&h->fw_ver) == 0xffffffff);
 100 }
 101 
 102 static 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 
 114 static 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;
 120         if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
 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;
 126 
 127         return MLX5_SENSOR_NO_ERR;
 128 }
 129 
 130 static 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 
 163 static 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;
 192 }
 193 
 194 void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
 195 {
 196         bool err_detected = false;
 197 
 198         /* Mark the device as fatal in order to abort FW commands */
 199         if ((check_fatal_sensors(dev) || force) &&
 200             dev->state == MLX5_DEVICE_STATE_UP) {
 201                 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 202                 err_detected = true;
 203         }
 204         mutex_lock(&dev->intf_state_mutex);
 205         if (!err_detected && dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
 206                 goto unlock;/* a previous error is still being handled */
 207         if (dev->state == MLX5_DEVICE_STATE_UNINITIALIZED) {
 208                 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 209                 goto unlock;
 210         }
 211 
 212         if (check_fatal_sensors(dev) || force) { /* protected state setting */
 213                 dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 214                 mlx5_cmd_flush(dev);
 215         }
 216 
 217         mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_SYS_ERROR, (void *)1);
 218 unlock:
 219         mutex_unlock(&dev->intf_state_mutex);
 220 }
 221 
 222 #define MLX5_CRDUMP_WAIT_MS     60000
 223 #define MLX5_FW_RESET_WAIT_MS   1000
 224 void mlx5_error_sw_reset(struct mlx5_core_dev *dev)
 225 {
 226         unsigned long end, delay_ms = MLX5_FW_RESET_WAIT_MS;
 227         int lock = -EBUSY;
 228 
 229         mutex_lock(&dev->intf_state_mutex);
 230         if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
 231                 goto unlock;
 232 
 233         mlx5_core_err(dev, "start\n");
 234 
 235         if (check_fatal_sensors(dev) == MLX5_SENSOR_FW_SYND_RFR) {
 236                 /* Get cr-dump and reset FW semaphore */
 237                 lock = lock_sem_sw_reset(dev, true);
 238 
 239                 if (lock == -EBUSY) {
 240                         delay_ms = MLX5_CRDUMP_WAIT_MS;
 241                         goto recover_from_sw_reset;
 242                 }
 243                 /* Execute SW reset */
 244                 reset_fw_if_needed(dev);
 245         }
 246 
 247 recover_from_sw_reset:
 248         /* Recover from SW reset */
 249         end = jiffies + msecs_to_jiffies(delay_ms);
 250         do {
 251                 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
 252                         break;
 253 
 254                 msleep(20);
 255         } while (!time_after(jiffies, end));
 256 
 257         if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
 258                 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
 259                         mlx5_get_nic_state(dev), delay_ms);
 260         }
 261 
 262         /* Release FW semaphore if you are the lock owner */
 263         if (!lock)
 264                 lock_sem_sw_reset(dev, false);
 265 
 266         mlx5_core_err(dev, "end\n");
 267 
 268 unlock:
 269         mutex_unlock(&dev->intf_state_mutex);
 270 }
 271 
 272 static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
 273 {
 274         u8 nic_interface = mlx5_get_nic_state(dev);
 275 
 276         switch (nic_interface) {
 277         case MLX5_NIC_IFC_FULL:
 278                 mlx5_core_warn(dev, "Expected to see disabled NIC but it is full driver\n");
 279                 break;
 280 
 281         case MLX5_NIC_IFC_DISABLED:
 282                 mlx5_core_warn(dev, "starting teardown\n");
 283                 break;
 284 
 285         case MLX5_NIC_IFC_NO_DRAM_NIC:
 286                 mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n");
 287                 break;
 288 
 289         case MLX5_NIC_IFC_SW_RESET:
 290                 /* The IFC mode field is 3 bits, so it will read 0x7 in 2 cases:
 291                  * 1. PCI has been disabled (ie. PCI-AER, PF driver unloaded
 292                  *    and this is a VF), this is not recoverable by SW reset.
 293                  *    Logging of this is handled elsewhere.
 294                  * 2. FW reset has been issued by another function, driver can
 295                  *    be reloaded to recover after the mode switches to
 296                  *    MLX5_NIC_IFC_DISABLED.
 297                  */
 298                 if (dev->priv.health.fatal_error != MLX5_SENSOR_PCI_COMM_ERR)
 299                         mlx5_core_warn(dev, "NIC SW reset in progress\n");
 300                 break;
 301 
 302         default:
 303                 mlx5_core_warn(dev, "Expected to see disabled NIC but it is has invalid value %d\n",
 304                                nic_interface);
 305         }
 306 
 307         mlx5_disable_device(dev);
 308 }
 309 
 310 /* How much time to wait until health resetting the driver (in msecs) */
 311 #define MLX5_RECOVERY_WAIT_MSECS 60000
 312 static int mlx5_health_try_recover(struct mlx5_core_dev *dev)
 313 {
 314         unsigned long end;
 315 
 316         mlx5_core_warn(dev, "handling bad device here\n");
 317         mlx5_handle_bad_state(dev);
 318         end = jiffies + msecs_to_jiffies(MLX5_RECOVERY_WAIT_MSECS);
 319         while (sensor_pci_not_working(dev)) {
 320                 if (time_after(jiffies, end)) {
 321                         mlx5_core_err(dev,
 322                                       "health recovery flow aborted, PCI reads still not working\n");
 323                         return -EIO;
 324                 }
 325                 msleep(100);
 326         }
 327 
 328         mlx5_core_err(dev, "starting health recovery flow\n");
 329         mlx5_recover_device(dev);
 330         if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state) ||
 331             check_fatal_sensors(dev)) {
 332                 mlx5_core_err(dev, "health recovery failed\n");
 333                 return -EIO;
 334         }
 335         return 0;
 336 }
 337 
 338 static const char *hsynd_str(u8 synd)
 339 {
 340         switch (synd) {
 341         case MLX5_HEALTH_SYNDR_FW_ERR:
 342                 return "firmware internal error";
 343         case MLX5_HEALTH_SYNDR_IRISC_ERR:
 344                 return "irisc not responding";
 345         case MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR:
 346                 return "unrecoverable hardware error";
 347         case MLX5_HEALTH_SYNDR_CRC_ERR:
 348                 return "firmware CRC error";
 349         case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR:
 350                 return "ICM fetch PCI error";
 351         case MLX5_HEALTH_SYNDR_HW_FTL_ERR:
 352                 return "HW fatal error\n";
 353         case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR:
 354                 return "async EQ buffer overrun";
 355         case MLX5_HEALTH_SYNDR_EQ_ERR:
 356                 return "EQ error";
 357         case MLX5_HEALTH_SYNDR_EQ_INV:
 358                 return "Invalid EQ referenced";
 359         case MLX5_HEALTH_SYNDR_FFSER_ERR:
 360                 return "FFSER error";
 361         case MLX5_HEALTH_SYNDR_HIGH_TEMP:
 362                 return "High temperature";
 363         default:
 364                 return "unrecognized error";
 365         }
 366 }
 367 
 368 static void print_health_info(struct mlx5_core_dev *dev)
 369 {
 370         struct mlx5_core_health *health = &dev->priv.health;
 371         struct health_buffer __iomem *h = health->health;
 372         char fw_str[18];
 373         u32 fw;
 374         int i;
 375 
 376         /* If the syndrome is 0, the device is OK and no need to print buffer */
 377         if (!ioread8(&h->synd))
 378                 return;
 379 
 380         for (i = 0; i < ARRAY_SIZE(h->assert_var); i++)
 381                 mlx5_core_err(dev, "assert_var[%d] 0x%08x\n", i,
 382                               ioread32be(h->assert_var + i));
 383 
 384         mlx5_core_err(dev, "assert_exit_ptr 0x%08x\n",
 385                       ioread32be(&h->assert_exit_ptr));
 386         mlx5_core_err(dev, "assert_callra 0x%08x\n",
 387                       ioread32be(&h->assert_callra));
 388         sprintf(fw_str, "%d.%d.%d", fw_rev_maj(dev), fw_rev_min(dev), fw_rev_sub(dev));
 389         mlx5_core_err(dev, "fw_ver %s\n", fw_str);
 390         mlx5_core_err(dev, "hw_id 0x%08x\n", ioread32be(&h->hw_id));
 391         mlx5_core_err(dev, "irisc_index %d\n", ioread8(&h->irisc_index));
 392         mlx5_core_err(dev, "synd 0x%x: %s\n", ioread8(&h->synd),
 393                       hsynd_str(ioread8(&h->synd)));
 394         mlx5_core_err(dev, "ext_synd 0x%04x\n", ioread16be(&h->ext_synd));
 395         fw = ioread32be(&h->fw_ver);
 396         mlx5_core_err(dev, "raw fw_ver 0x%08x\n", fw);
 397 }
 398 
 399 static int
 400 mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
 401                           struct devlink_fmsg *fmsg)
 402 {
 403         struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 404         struct mlx5_core_health *health = &dev->priv.health;
 405         struct health_buffer __iomem *h = health->health;
 406         u8 synd;
 407         int err;
 408 
 409         synd = ioread8(&h->synd);
 410         err = devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
 411         if (err || !synd)
 412                 return err;
 413         return devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
 414 }
 415 
 416 struct mlx5_fw_reporter_ctx {
 417         u8 err_synd;
 418         int miss_counter;
 419 };
 420 
 421 static int
 422 mlx5_fw_reporter_ctx_pairs_put(struct devlink_fmsg *fmsg,
 423                                struct mlx5_fw_reporter_ctx *fw_reporter_ctx)
 424 {
 425         int err;
 426 
 427         err = devlink_fmsg_u8_pair_put(fmsg, "syndrome",
 428                                        fw_reporter_ctx->err_synd);
 429         if (err)
 430                 return err;
 431         err = devlink_fmsg_u32_pair_put(fmsg, "fw_miss_counter",
 432                                         fw_reporter_ctx->miss_counter);
 433         if (err)
 434                 return err;
 435         return 0;
 436 }
 437 
 438 static int
 439 mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev,
 440                                        struct devlink_fmsg *fmsg)
 441 {
 442         struct mlx5_core_health *health = &dev->priv.health;
 443         struct health_buffer __iomem *h = health->health;
 444         int err;
 445         int i;
 446 
 447         if (!ioread8(&h->synd))
 448                 return 0;
 449 
 450         err = devlink_fmsg_pair_nest_start(fmsg, "health buffer");
 451         if (err)
 452                 return err;
 453         err = devlink_fmsg_obj_nest_start(fmsg);
 454         if (err)
 455                 return err;
 456         err = devlink_fmsg_arr_pair_nest_start(fmsg, "assert_var");
 457         if (err)
 458                 return err;
 459 
 460         for (i = 0; i < ARRAY_SIZE(h->assert_var); i++) {
 461                 err = devlink_fmsg_u32_put(fmsg, ioread32be(h->assert_var + i));
 462                 if (err)
 463                         return err;
 464         }
 465         err = devlink_fmsg_arr_pair_nest_end(fmsg);
 466         if (err)
 467                 return err;
 468         err = devlink_fmsg_u32_pair_put(fmsg, "assert_exit_ptr",
 469                                         ioread32be(&h->assert_exit_ptr));
 470         if (err)
 471                 return err;
 472         err = devlink_fmsg_u32_pair_put(fmsg, "assert_callra",
 473                                         ioread32be(&h->assert_callra));
 474         if (err)
 475                 return err;
 476         err = devlink_fmsg_u32_pair_put(fmsg, "hw_id", ioread32be(&h->hw_id));
 477         if (err)
 478                 return err;
 479         err = devlink_fmsg_u8_pair_put(fmsg, "irisc_index",
 480                                        ioread8(&h->irisc_index));
 481         if (err)
 482                 return err;
 483         err = devlink_fmsg_u8_pair_put(fmsg, "synd", ioread8(&h->synd));
 484         if (err)
 485                 return err;
 486         err = devlink_fmsg_u32_pair_put(fmsg, "ext_synd",
 487                                         ioread16be(&h->ext_synd));
 488         if (err)
 489                 return err;
 490         err = devlink_fmsg_u32_pair_put(fmsg, "raw_fw_ver",
 491                                         ioread32be(&h->fw_ver));
 492         if (err)
 493                 return err;
 494         err = devlink_fmsg_obj_nest_end(fmsg);
 495         if (err)
 496                 return err;
 497         return devlink_fmsg_pair_nest_end(fmsg);
 498 }
 499 
 500 static int
 501 mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter,
 502                       struct devlink_fmsg *fmsg, void *priv_ctx)
 503 {
 504         struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 505         int err;
 506 
 507         err = mlx5_fw_tracer_trigger_core_dump_general(dev);
 508         if (err)
 509                 return err;
 510 
 511         if (priv_ctx) {
 512                 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
 513 
 514                 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
 515                 if (err)
 516                         return err;
 517         }
 518 
 519         err = mlx5_fw_reporter_heath_buffer_data_put(dev, fmsg);
 520         if (err)
 521                 return err;
 522         return mlx5_fw_tracer_get_saved_traces_objects(dev->tracer, fmsg);
 523 }
 524 
 525 static void mlx5_fw_reporter_err_work(struct work_struct *work)
 526 {
 527         struct mlx5_fw_reporter_ctx fw_reporter_ctx;
 528         struct mlx5_core_health *health;
 529 
 530         health = container_of(work, struct mlx5_core_health, report_work);
 531 
 532         if (IS_ERR_OR_NULL(health->fw_reporter))
 533                 return;
 534 
 535         fw_reporter_ctx.err_synd = health->synd;
 536         fw_reporter_ctx.miss_counter = health->miss_counter;
 537         if (fw_reporter_ctx.err_synd) {
 538                 devlink_health_report(health->fw_reporter,
 539                                       "FW syndrom reported", &fw_reporter_ctx);
 540                 return;
 541         }
 542         if (fw_reporter_ctx.miss_counter)
 543                 devlink_health_report(health->fw_reporter,
 544                                       "FW miss counter reported",
 545                                       &fw_reporter_ctx);
 546 }
 547 
 548 static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = {
 549                 .name = "fw",
 550                 .diagnose = mlx5_fw_reporter_diagnose,
 551                 .dump = mlx5_fw_reporter_dump,
 552 };
 553 
 554 static int
 555 mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
 556                                void *priv_ctx)
 557 {
 558         struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 559 
 560         return mlx5_health_try_recover(dev);
 561 }
 562 
 563 #define MLX5_CR_DUMP_CHUNK_SIZE 256
 564 static int
 565 mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
 566                             struct devlink_fmsg *fmsg, void *priv_ctx)
 567 {
 568         struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
 569         u32 crdump_size = dev->priv.health.crdump_size;
 570         u32 *cr_data;
 571         u32 data_size;
 572         u32 offset;
 573         int err;
 574 
 575         if (!mlx5_core_is_pf(dev))
 576                 return -EPERM;
 577 
 578         cr_data = kvmalloc(crdump_size, GFP_KERNEL);
 579         if (!cr_data)
 580                 return -ENOMEM;
 581         err = mlx5_crdump_collect(dev, cr_data);
 582         if (err)
 583                 goto free_data;
 584 
 585         if (priv_ctx) {
 586                 struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
 587 
 588                 err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
 589                 if (err)
 590                         goto free_data;
 591         }
 592 
 593         err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data");
 594         if (err)
 595                 goto free_data;
 596         for (offset = 0; offset < crdump_size; offset += data_size) {
 597                 if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE)
 598                         data_size = crdump_size - offset;
 599                 else
 600                         data_size = MLX5_CR_DUMP_CHUNK_SIZE;
 601                 err = devlink_fmsg_binary_put(fmsg, (char *)cr_data + offset,
 602                                               data_size);
 603                 if (err)
 604                         goto free_data;
 605         }
 606         err = devlink_fmsg_arr_pair_nest_end(fmsg);
 607 
 608 free_data:
 609         kvfree(cr_data);
 610         return err;
 611 }
 612 
 613 static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
 614 {
 615         struct mlx5_fw_reporter_ctx fw_reporter_ctx;
 616         struct mlx5_core_health *health;
 617         struct mlx5_core_dev *dev;
 618         struct mlx5_priv *priv;
 619 
 620         health = container_of(work, struct mlx5_core_health, fatal_report_work);
 621         priv = container_of(health, struct mlx5_priv, health);
 622         dev = container_of(priv, struct mlx5_core_dev, priv);
 623 
 624         mlx5_enter_error_state(dev, false);
 625         if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) {
 626                 if (mlx5_health_try_recover(dev))
 627                         mlx5_core_err(dev, "health recovery failed\n");
 628                 return;
 629         }
 630         fw_reporter_ctx.err_synd = health->synd;
 631         fw_reporter_ctx.miss_counter = health->miss_counter;
 632         devlink_health_report(health->fw_fatal_reporter,
 633                               "FW fatal error reported", &fw_reporter_ctx);
 634 }
 635 
 636 static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
 637                 .name = "fw_fatal",
 638                 .recover = mlx5_fw_fatal_reporter_recover,
 639                 .dump = mlx5_fw_fatal_reporter_dump,
 640 };
 641 
 642 #define MLX5_REPORTER_FW_GRACEFUL_PERIOD 1200000
 643 static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev)
 644 {
 645         struct mlx5_core_health *health = &dev->priv.health;
 646         struct devlink *devlink = priv_to_devlink(dev);
 647 
 648         health->fw_reporter =
 649                 devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops,
 650                                                0, false, dev);
 651         if (IS_ERR(health->fw_reporter))
 652                 mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
 653                                PTR_ERR(health->fw_reporter));
 654 
 655         health->fw_fatal_reporter =
 656                 devlink_health_reporter_create(devlink,
 657                                                &mlx5_fw_fatal_reporter_ops,
 658                                                MLX5_REPORTER_FW_GRACEFUL_PERIOD,
 659                                                true, dev);
 660         if (IS_ERR(health->fw_fatal_reporter))
 661                 mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
 662                                PTR_ERR(health->fw_fatal_reporter));
 663 }
 664 
 665 static void mlx5_fw_reporters_destroy(struct mlx5_core_dev *dev)
 666 {
 667         struct mlx5_core_health *health = &dev->priv.health;
 668 
 669         if (!IS_ERR_OR_NULL(health->fw_reporter))
 670                 devlink_health_reporter_destroy(health->fw_reporter);
 671 
 672         if (!IS_ERR_OR_NULL(health->fw_fatal_reporter))
 673                 devlink_health_reporter_destroy(health->fw_fatal_reporter);
 674 }
 675 
 676 static unsigned long get_next_poll_jiffies(void)
 677 {
 678         unsigned long next;
 679 
 680         get_random_bytes(&next, sizeof(next));
 681         next %= HZ;
 682         next += jiffies + MLX5_HEALTH_POLL_INTERVAL;
 683 
 684         return next;
 685 }
 686 
 687 void mlx5_trigger_health_work(struct mlx5_core_dev *dev)
 688 {
 689         struct mlx5_core_health *health = &dev->priv.health;
 690         unsigned long flags;
 691 
 692         spin_lock_irqsave(&health->wq_lock, flags);
 693         if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
 694                 queue_work(health->wq, &health->fatal_report_work);
 695         else
 696                 mlx5_core_err(dev, "new health works are not permitted at this stage\n");
 697         spin_unlock_irqrestore(&health->wq_lock, flags);
 698 }
 699 
 700 static void poll_health(struct timer_list *t)
 701 {
 702         struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);
 703         struct mlx5_core_health *health = &dev->priv.health;
 704         struct health_buffer __iomem *h = health->health;
 705         u32 fatal_error;
 706         u8 prev_synd;
 707         u32 count;
 708 
 709         if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
 710                 goto out;
 711 
 712         fatal_error = check_fatal_sensors(dev);
 713 
 714         if (fatal_error && !health->fatal_error) {
 715                 mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
 716                 dev->priv.health.fatal_error = fatal_error;
 717                 print_health_info(dev);
 718                 mlx5_trigger_health_work(dev);
 719                 goto out;
 720         }
 721 
 722         count = ioread32be(health->health_counter);
 723         if (count == health->prev)
 724                 ++health->miss_counter;
 725         else
 726                 health->miss_counter = 0;
 727 
 728         health->prev = count;
 729         if (health->miss_counter == MAX_MISSES) {
 730                 mlx5_core_err(dev, "device's health compromised - reached miss count\n");
 731                 print_health_info(dev);
 732                 queue_work(health->wq, &health->report_work);
 733         }
 734 
 735         prev_synd = health->synd;
 736         health->synd = ioread8(&h->synd);
 737         if (health->synd && health->synd != prev_synd)
 738                 queue_work(health->wq, &health->report_work);
 739 
 740 out:
 741         mod_timer(&health->timer, get_next_poll_jiffies());
 742 }
 743 
 744 void mlx5_start_health_poll(struct mlx5_core_dev *dev)
 745 {
 746         struct mlx5_core_health *health = &dev->priv.health;
 747 
 748         timer_setup(&health->timer, poll_health, 0);
 749         health->fatal_error = MLX5_SENSOR_NO_ERR;
 750         clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
 751         health->health = &dev->iseg->health;
 752         health->health_counter = &dev->iseg->health_counter;
 753 
 754         health->timer.expires = round_jiffies(jiffies + MLX5_HEALTH_POLL_INTERVAL);
 755         add_timer(&health->timer);
 756 }
 757 
 758 void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health)
 759 {
 760         struct mlx5_core_health *health = &dev->priv.health;
 761         unsigned long flags;
 762 
 763         if (disable_health) {
 764                 spin_lock_irqsave(&health->wq_lock, flags);
 765                 set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
 766                 spin_unlock_irqrestore(&health->wq_lock, flags);
 767         }
 768 
 769         del_timer_sync(&health->timer);
 770 }
 771 
 772 void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
 773 {
 774         struct mlx5_core_health *health = &dev->priv.health;
 775         unsigned long flags;
 776 
 777         spin_lock_irqsave(&health->wq_lock, flags);
 778         set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
 779         spin_unlock_irqrestore(&health->wq_lock, flags);
 780         cancel_work_sync(&health->report_work);
 781         cancel_work_sync(&health->fatal_report_work);
 782 }
 783 
 784 void mlx5_health_flush(struct mlx5_core_dev *dev)
 785 {
 786         struct mlx5_core_health *health = &dev->priv.health;
 787 
 788         flush_workqueue(health->wq);
 789 }
 790 
 791 void mlx5_health_cleanup(struct mlx5_core_dev *dev)
 792 {
 793         struct mlx5_core_health *health = &dev->priv.health;
 794 
 795         destroy_workqueue(health->wq);
 796         mlx5_fw_reporters_destroy(dev);
 797 }
 798 
 799 int mlx5_health_init(struct mlx5_core_dev *dev)
 800 {
 801         struct mlx5_core_health *health;
 802         char *name;
 803 
 804         mlx5_fw_reporters_create(dev);
 805 
 806         health = &dev->priv.health;
 807         name = kmalloc(64, GFP_KERNEL);
 808         if (!name)
 809                 goto out_err;
 810 
 811         strcpy(name, "mlx5_health");
 812         strcat(name, dev_name(dev->device));
 813         health->wq = create_singlethread_workqueue(name);
 814         kfree(name);
 815         if (!health->wq)
 816                 goto out_err;
 817         spin_lock_init(&health->wq_lock);
 818         INIT_WORK(&health->fatal_report_work, mlx5_fw_fatal_reporter_err_work);
 819         INIT_WORK(&health->report_work, mlx5_fw_reporter_err_work);
 820 
 821         return 0;
 822 
 823 out_err:
 824         mlx5_fw_reporters_destroy(dev);
 825         return -ENOMEM;
 826 }

/* [<][>][^][v][top][bottom][index][help] */