Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mei: me: emit error only if reset was unexpected

GSC devices perform legal firmware initiated resets due to state transition
that may appear as unexpected to the driver. Lower the log level for those
devices to debug level and save the firmware status registers.
When the device comes out of the reset it is possible to check whether the
resets was due to a firmware error or an exception
and only than produce a warning.

Signed-off-by: Vitaly Lubart <vitaly.lubart@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Link: https://lore.kernel.org/r/20231015080540.95922-1-tomas.winkler@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vitaly Lubart and committed by
Greg Kroah-Hartman
34a674e9 3b54a111

+133 -5
+3
drivers/misc/mei/hw-me-regs.h
··· 123 123 # define PCI_CFG_HFS_1_OPMODE_MSK 0xf0000 /* OP MODE Mask: SPS <= 4.0 */ 124 124 # define PCI_CFG_HFS_1_OPMODE_SPS 0xf0000 /* SPS SKU : SPS <= 4.0 */ 125 125 #define PCI_CFG_HFS_2 0x48 126 + # define PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR 0x1000000 /* CMoff->CMx wake after an error */ 127 + # define PCI_CFG_HFS_2_PM_CM_RESET_ERROR 0x5000000 /* CME reset due to exception */ 128 + # define PCI_CFG_HFS_2_PM_EVENT_MASK 0xf000000 126 129 #define PCI_CFG_HFS_3 0x60 127 130 # define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070 128 131 # define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000
+58 -3
drivers/misc/mei/hw-me.c
··· 443 443 struct mei_me_hw *hw = to_me_hw(dev); 444 444 u32 fwsts5 = 0; 445 445 446 - if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) 446 + if (!kind_is_gsc(dev) && !kind_is_gscfi(dev)) 447 447 return; 448 448 449 449 hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5); 450 450 trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); 451 + 452 + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { 453 + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT) 454 + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_PERFORMED; 455 + } else { 456 + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; 457 + } 458 + 459 + if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) 460 + return; 461 + 451 462 if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { 452 463 dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5); 453 464 dev->pxp_mode = MEI_DEV_PXP_READY; ··· 494 483 } 495 484 496 485 /** 486 + * mei_me_check_fw_reset - check for the firmware reset error and exception conditions 487 + * 488 + * @dev: mei device 489 + */ 490 + static void mei_me_check_fw_reset(struct mei_device *dev) 491 + { 492 + struct mei_fw_status fw_status; 493 + char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0}; 494 + int ret; 495 + u32 fw_pm_event = 0; 496 + 497 + if (!dev->saved_fw_status_flag) 498 + goto end; 499 + 500 + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) { 501 + ret = mei_fw_status(dev, &fw_status); 502 + if (!ret) { 503 + fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK; 504 + if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR && 505 + fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR) 506 + goto end; 507 + } else { 508 + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); 509 + } 510 + } 511 + 512 + mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str)); 513 + dev_warn(dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", 514 + fw_pm_event, dev->saved_dev_state, fw_sts_str); 515 + 516 + end: 517 + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) 518 + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE; 519 + dev->saved_fw_status_flag = false; 520 + } 521 + 522 + /** 497 523 * mei_me_hw_start - hw start routine 498 524 * 499 525 * @dev: mei device ··· 540 492 { 541 493 int ret = mei_me_hw_ready_wait(dev); 542 494 495 + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) 496 + mei_me_check_fw_reset(dev); 543 497 if (ret) 544 498 return ret; 545 499 dev_dbg(dev->dev, "hw is ready\n"); ··· 1350 1300 1351 1301 /* check if ME wants a reset */ 1352 1302 if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { 1353 - dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d pxp = %d\n", 1354 - dev->dev_state, dev->pxp_mode); 1303 + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { 1304 + dev_dbg(dev->dev, "FW not ready: resetting: dev_state = %d\n", 1305 + dev->dev_state); 1306 + } else { 1307 + dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d\n", 1308 + dev->dev_state); 1309 + } 1355 1310 if (dev->dev_state == MEI_DEV_POWERING_DOWN || 1356 1311 dev->dev_state == MEI_DEV_POWER_DOWN) 1357 1312 mei_cl_all_disconnect(dev);
+25 -2
drivers/misc/mei/init.c
··· 89 89 } 90 90 EXPORT_SYMBOL_GPL(mei_cancel_work); 91 91 92 + static void mei_save_fw_status(struct mei_device *dev) 93 + { 94 + struct mei_fw_status fw_status; 95 + int ret; 96 + 97 + ret = mei_fw_status(dev, &fw_status); 98 + if (ret) { 99 + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); 100 + return; 101 + } 102 + 103 + dev->saved_dev_state = dev->dev_state; 104 + dev->saved_fw_status_flag = true; 105 + memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status)); 106 + } 107 + 92 108 /** 93 109 * mei_reset - resets host and fw. 94 110 * ··· 125 109 char fw_sts_str[MEI_FW_STATUS_STR_SZ]; 126 110 127 111 mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); 128 - dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", 129 - mei_dev_state_str(state), fw_sts_str); 112 + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { 113 + dev_dbg(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", 114 + mei_dev_state_str(state), fw_sts_str); 115 + mei_save_fw_status(dev); 116 + } else { 117 + dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", 118 + mei_dev_state_str(state), fw_sts_str); 119 + } 130 120 } 131 121 132 122 mei_clear_interrupts(dev); ··· 416 394 dev->open_handle_count = 0; 417 395 418 396 dev->pxp_mode = MEI_DEV_PXP_DEFAULT; 397 + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; 419 398 420 399 /* 421 400 * Reserving the first client ID
+47
drivers/misc/mei/mei_dev.h
··· 82 82 MEI_DEV_PXP_READY = 3, 83 83 }; 84 84 85 + /** 86 + * enum mei_dev_reset_to_pxp - reset to PXP mode performed 87 + * 88 + * @MEI_DEV_RESET_TO_PXP_DEFAULT: before reset 89 + * @MEI_DEV_RESET_TO_PXP_PERFORMED: reset performed 90 + * @MEI_DEV_RESET_TO_PXP_DONE: reset processed 91 + */ 92 + enum mei_dev_reset_to_pxp { 93 + MEI_DEV_RESET_TO_PXP_DEFAULT = 0, 94 + MEI_DEV_RESET_TO_PXP_PERFORMED = 1, 95 + MEI_DEV_RESET_TO_PXP_DONE = 2, 96 + }; 97 + 85 98 const char *mei_dev_state_str(int state); 86 99 87 100 enum mei_file_transaction_states { ··· 547 534 * 548 535 * @dbgfs_dir : debugfs mei root directory 549 536 * 537 + * @saved_fw_status : saved firmware status 538 + * @saved_dev_state : saved device state 539 + * @saved_fw_status_flag : flag indicating that firmware status was saved 540 + * @gsc_reset_to_pxp : state of reset to the PXP mode 541 + * 550 542 * @ops: : hw specific operations 551 543 * @hw : hw specific data 552 544 */ ··· 647 629 #if IS_ENABLED(CONFIG_DEBUG_FS) 648 630 struct dentry *dbgfs_dir; 649 631 #endif /* CONFIG_DEBUG_FS */ 632 + 633 + struct mei_fw_status saved_fw_status; 634 + enum mei_dev_state saved_dev_state; 635 + bool saved_fw_status_flag; 636 + enum mei_dev_reset_to_pxp gsc_reset_to_pxp; 650 637 651 638 const struct mei_hw_ops *ops; 652 639 char hw[] __aligned(sizeof(void *)); ··· 897 874 return ret; 898 875 } 899 876 877 + /** 878 + * kind_is_gsc - checks whether the device is gsc 879 + * 880 + * @dev: the device structure 881 + * 882 + * Return: whether the device is gsc 883 + */ 884 + static inline bool kind_is_gsc(struct mei_device *dev) 885 + { 886 + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ 887 + return dev->kind && (strcmp(dev->kind, "gsc") == 0); 888 + } 900 889 890 + /** 891 + * kind_is_gscfi - checks whether the device is gscfi 892 + * 893 + * @dev: the device structure 894 + * 895 + * Return: whether the device is gscfi 896 + */ 897 + static inline bool kind_is_gscfi(struct mei_device *dev) 898 + { 899 + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ 900 + return dev->kind && (strcmp(dev->kind, "gscfi") == 0); 901 + } 901 902 #endif