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.

platform/x86:intel/pmc: Show substate requirement for S0ix blockers

Add support to read and show S0ix blocker substate requirements.
Starting from Panther Lake, substate requirement data is provided
based on S0ix blockers instead of all low power mode requirements.
For platforms that support this new feature, add support to display
substate requirements based on S0ix blockers.

Change the "substate_requirements" attribute of Intel PMC Core
driver to show the substate requirements for each S0ix blocker
and the corresponding S0ix blocker value.

Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
Link: https://patch.msgid.link/20250910210629.11198-5-xi.pardee@linux.intel.com
[ij: rename pmc_index -> pmc_idx]
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Xi Pardee and committed by
Ilpo Järvinen
a22bc864 612326e0

+133 -10
+4
drivers/platform/x86/intel/pmc/arl.c
··· 725 725 .dmu_guid = ARL_PMT_DMU_GUID, 726 726 .regmap_list = arl_pmc_info_list, 727 727 .map = &arl_socs_reg_map, 728 + .sub_req_show = &pmc_core_substate_req_regs_fops, 728 729 .suspend = cnl_suspend, 729 730 .resume = arl_resume, 730 731 .init = arl_core_init, 732 + .sub_req = pmc_core_pmt_get_lpm_req, 731 733 }; 732 734 733 735 struct pmc_dev_info arl_h_pmc_dev = { ··· 737 735 .dmu_guid = ARL_PMT_DMU_GUID, 738 736 .regmap_list = arl_pmc_info_list, 739 737 .map = &mtl_socm_reg_map, 738 + .sub_req_show = &pmc_core_substate_req_regs_fops, 740 739 .suspend = cnl_suspend, 741 740 .resume = arl_h_resume, 742 741 .init = arl_h_core_init, 742 + .sub_req = pmc_core_pmt_get_lpm_req, 743 743 };
+111 -10
drivers/platform/x86/intel/pmc/core.c
··· 851 851 } 852 852 } 853 853 854 + static int pmc_core_substate_blk_req_show(struct seq_file *s, void *unused) 855 + { 856 + struct pmc_dev *pmcdev = s->private; 857 + unsigned int pmc_idx; 858 + 859 + for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) { 860 + const struct pmc_bit_map **maps; 861 + unsigned int arr_size, r_idx; 862 + u32 offset, counter; 863 + u32 *lpm_req_regs; 864 + struct pmc *pmc; 865 + 866 + pmc = pmcdev->pmcs[pmc_idx]; 867 + if (!pmc || !pmc->lpm_req_regs) 868 + continue; 869 + 870 + lpm_req_regs = pmc->lpm_req_regs; 871 + maps = pmc->map->s0ix_blocker_maps; 872 + offset = pmc->map->s0ix_blocker_offset; 873 + arr_size = pmc_core_lpm_get_arr_size(maps); 874 + 875 + /* Display the header */ 876 + pmc_core_substate_req_header_show(s, pmc_idx, HEADER_VALUE); 877 + 878 + for (r_idx = 0; r_idx < arr_size; r_idx++) { 879 + const struct pmc_bit_map *map; 880 + 881 + for (map = maps[r_idx]; map->name; map++) { 882 + int mode; 883 + 884 + if (!map->blk) 885 + continue; 886 + 887 + counter = pmc_core_reg_read(pmc, offset); 888 + seq_printf(s, "pmc%u: %34s |", pmc_idx, map->name); 889 + pmc_for_each_mode(mode, pmcdev) { 890 + bool required = *lpm_req_regs & BIT(mode); 891 + 892 + seq_printf(s, " %9s |", required ? "Required" : " "); 893 + } 894 + seq_printf(s, " %9u |\n", counter); 895 + offset += map->blk * S0IX_BLK_SIZE; 896 + lpm_req_regs++; 897 + } 898 + } 899 + } 900 + return 0; 901 + } 902 + 903 + static int pmc_core_substate_blk_req_open(struct inode *inode, struct file *file) 904 + { 905 + return single_open(file, pmc_core_substate_blk_req_show, inode->i_private); 906 + } 907 + 908 + const struct file_operations pmc_core_substate_blk_req_fops = { 909 + .owner = THIS_MODULE, 910 + .open = pmc_core_substate_blk_req_open, 911 + .read = seq_read, 912 + .llseek = seq_lseek, 913 + .release = single_release, 914 + }; 915 + 854 916 static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) 855 917 { 856 918 struct pmc_dev *pmcdev = s->private; ··· 1003 941 } 1004 942 return 0; 1005 943 } 1006 - DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_req_regs); 944 + 945 + static int pmc_core_substate_req_regs_open(struct inode *inode, struct file *file) 946 + { 947 + return single_open(file, pmc_core_substate_req_regs_show, inode->i_private); 948 + } 949 + 950 + const struct file_operations pmc_core_substate_req_regs_fops = { 951 + .owner = THIS_MODULE, 952 + .open = pmc_core_substate_req_regs_open, 953 + .read = seq_read, 954 + .llseek = seq_lseek, 955 + .release = single_release, 956 + }; 1007 957 1008 958 static unsigned int pmc_core_get_crystal_freq(void) 1009 959 { ··· 1348 1274 debugfs_remove_recursive(pmcdev->dbgfs_dir); 1349 1275 } 1350 1276 1351 - static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 1277 + static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 1352 1278 { 1353 1279 struct pmc *primary_pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 1354 1280 struct dentry *dir; ··· 1415 1341 if (primary_pmc->lpm_req_regs) { 1416 1342 debugfs_create_file("substate_requirements", 0444, 1417 1343 pmcdev->dbgfs_dir, pmcdev, 1418 - &pmc_core_substate_req_regs_fops); 1344 + pmc_dev_info->sub_req_show); 1419 1345 } 1420 1346 1421 1347 if (primary_pmc->map->pson_residency_offset && pmc_core_is_pson_residency_enabled(pmcdev)) { ··· 1483 1409 * +----+---------------------------------------------------------+ 1484 1410 * 1485 1411 */ 1486 - static int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, 1487 - struct telem_endpoint *ep) 1412 + int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep) 1488 1413 { 1489 1414 const u8 *lpm_indices; 1490 1415 int num_maps, mode_offset = 0; ··· 1521 1448 return ret; 1522 1449 } 1523 1450 1524 - static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, int func) 1451 + int pmc_core_pmt_get_blk_sub_req(struct pmc_dev *pmcdev, struct pmc *pmc, 1452 + struct telem_endpoint *ep) 1453 + { 1454 + u32 num_blocker, sample_offset; 1455 + unsigned int index; 1456 + u32 *req_offset; 1457 + int ret; 1458 + 1459 + num_blocker = pmc->map->num_s0ix_blocker; 1460 + sample_offset = pmc->map->blocker_req_offset; 1461 + 1462 + pmc->lpm_req_regs = devm_kcalloc(&pmcdev->pdev->dev, num_blocker, 1463 + sizeof(u32), GFP_KERNEL); 1464 + if (!pmc->lpm_req_regs) 1465 + return -ENOMEM; 1466 + 1467 + req_offset = pmc->lpm_req_regs; 1468 + for (index = 0; index < num_blocker; index++, req_offset++) { 1469 + ret = pmt_telem_read32(ep, index + sample_offset, req_offset, 1); 1470 + if (ret) { 1471 + dev_err(&pmcdev->pdev->dev, 1472 + "couldn't read Low Power Mode requirements: %d\n", ret); 1473 + return ret; 1474 + } 1475 + } 1476 + return 0; 1477 + } 1478 + 1479 + static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) 1525 1480 { 1526 1481 struct pci_dev *pcidev __free(pci_dev_put) = NULL; 1527 1482 struct telem_endpoint *ep; ··· 1557 1456 u32 guid; 1558 1457 int ret; 1559 1458 1560 - pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, func)); 1459 + pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func)); 1561 1460 if (!pcidev) 1562 1461 return -ENODEV; 1563 1462 ··· 1578 1477 return -EPROBE_DEFER; 1579 1478 } 1580 1479 1581 - ret = pmc_core_pmt_get_lpm_req(pmcdev, pmc, ep); 1480 + ret = pmc_dev_info->sub_req(pmcdev, pmc, ep); 1582 1481 pmt_telem_unregister_endpoint(ep); 1583 1482 if (ret) 1584 1483 return ret; ··· 1693 1592 pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid); 1694 1593 1695 1594 if (ssram) { 1696 - ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info->pci_func); 1595 + ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info); 1697 1596 if (ret) 1698 1597 goto unmap_regbase; 1699 1598 } ··· 1868 1767 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(primary_pmc); 1869 1768 pmc_core_do_dmi_quirks(primary_pmc); 1870 1769 1871 - pmc_core_dbgfs_register(pmcdev); 1770 + pmc_core_dbgfs_register(pmcdev, pmc_dev_info); 1872 1771 pm_report_max_hw_sleep(FIELD_MAX(SLP_S0_RES_COUNTER_MASK) * 1873 1772 pmc_core_adjust_slp_s0_step(primary_pmc, 1)); 1874 1773
+14
drivers/platform/x86/intel/pmc/core.h
··· 351 351 * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE 352 352 * @slps0_dbg_offset: PWRMBASE offset to SLP_S0_DEBUG_REG* 353 353 * @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter 354 + * @num_s0ix_blocker: Number of S0ix blockers 355 + * @blocker_req_offset: Telemetry offset to S0ix blocker low power mode substate requirement table 354 356 * 355 357 * Each PCH has unique set of register offsets and bit indexes. This structure 356 358 * captures them to have a common implementation. ··· 378 376 const u32 ltr_ignore_max; 379 377 const u32 pm_vric1_offset; 380 378 const u32 s0ix_blocker_offset; 379 + const u32 num_s0ix_blocker; 380 + const u32 blocker_req_offset; 381 381 /* Low Power Mode registers */ 382 382 const int lpm_num_maps; 383 383 const int lpm_num_modes; ··· 485 481 * SSRAM support. 486 482 * @map: Pointer to a pmc_reg_map struct that contains platform 487 483 * specific attributes of the primary PMC 484 + * @sub_req_show: File operations to show substate requirements 488 485 * @suspend: Function to perform platform specific suspend 489 486 * @resume: Function to perform platform specific resume 490 487 * @init: Function to perform platform specific init action 488 + * @sub_req: Function to achieve low power mode substate requirements 491 489 */ 492 490 struct pmc_dev_info { 493 491 u8 pci_func; 494 492 u32 dmu_guid; 495 493 struct pmc_info *regmap_list; 496 494 const struct pmc_reg_map *map; 495 + const struct file_operations *sub_req_show; 497 496 void (*suspend)(struct pmc_dev *pmcdev); 498 497 int (*resume)(struct pmc_dev *pmcdev); 499 498 int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info); 499 + int (*sub_req)(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep); 500 500 }; 501 501 502 502 extern const struct pmc_bit_map msr_map[]; ··· 550 542 551 543 void cnl_suspend(struct pmc_dev *pmcdev); 552 544 int cnl_resume(struct pmc_dev *pmcdev); 545 + int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep); 546 + int pmc_core_pmt_get_blk_sub_req(struct pmc_dev *pmcdev, struct pmc *pmc, 547 + struct telem_endpoint *ep); 548 + 549 + extern const struct file_operations pmc_core_substate_req_regs_fops; 550 + extern const struct file_operations pmc_core_substate_blk_req_fops; 553 551 554 552 #define pmc_for_each_mode(mode, pmcdev) \ 555 553 for (unsigned int __i = 0, __cond; \
+2
drivers/platform/x86/intel/pmc/lnl.c
··· 574 574 .pci_func = 2, 575 575 .regmap_list = lnl_pmc_info_list, 576 576 .map = &lnl_socm_reg_map, 577 + .sub_req_show = &pmc_core_substate_req_regs_fops, 577 578 .suspend = cnl_suspend, 578 579 .resume = lnl_resume, 579 580 .init = lnl_core_init, 581 + .sub_req = pmc_core_pmt_get_lpm_req, 580 582 };
+2
drivers/platform/x86/intel/pmc/mtl.c
··· 997 997 .dmu_guid = MTL_PMT_DMU_GUID, 998 998 .regmap_list = mtl_pmc_info_list, 999 999 .map = &mtl_socm_reg_map, 1000 + .sub_req_show = &pmc_core_substate_req_regs_fops, 1000 1001 .suspend = cnl_suspend, 1001 1002 .resume = mtl_resume, 1002 1003 .init = mtl_core_init, 1004 + .sub_req = pmc_core_pmt_get_lpm_req, 1003 1005 };