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

platform/x86: intel_pmc_core: Ignore GBE LTR on Tiger Lake platforms

Due to a HW limitation, the Latency Tolerance Reporting (LTR) value
programmed in the Tiger Lake GBE controller is not large enough to allow
the platform to enter Package C10, which in turn prevents the platform from
achieving its low power target during suspend-to-idle. Ignore the GBE LTR
value on Tiger Lake. LTR ignore functionality is currently performed solely
by a debugfs write call. Split out the LTR code into its own function that
can be called by both the debugfs writer and by this work around.

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Sasha Neftin <sasha.neftin@intel.com>
Cc: intel-wired-lan@lists.osuosl.org
Reviewed-by: Rajneesh Bhardwaj <irenic.rajneesh@gmail.com>
Link: https://lore.kernel.org/r/20210319201844.3305399-2-david.e.box@linux.intel.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

David E. Box and committed by
Hans de Goede
36974daf a01be40c

+35 -15
+35 -15
drivers/platform/x86/intel_pmc_core.c
··· 863 863 } 864 864 DEFINE_SHOW_ATTRIBUTE(pmc_core_pll); 865 865 866 - static ssize_t pmc_core_ltr_ignore_write(struct file *file, 867 - const char __user *userbuf, 868 - size_t count, loff_t *ppos) 866 + static int pmc_core_send_ltr_ignore(u32 value) 869 867 { 870 868 struct pmc_dev *pmcdev = &pmc; 871 869 const struct pmc_reg_map *map = pmcdev->map; 872 - u32 val, buf_size, fd; 873 - int err; 874 - 875 - buf_size = count < 64 ? count : 64; 876 - 877 - err = kstrtou32_from_user(userbuf, buf_size, 10, &val); 878 - if (err) 879 - return err; 870 + u32 reg; 871 + int err = 0; 880 872 881 873 mutex_lock(&pmcdev->lock); 882 874 883 - if (val > map->ltr_ignore_max) { 875 + if (value > map->ltr_ignore_max) { 884 876 err = -EINVAL; 885 877 goto out_unlock; 886 878 } 887 879 888 - fd = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset); 889 - fd |= (1U << val); 890 - pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, fd); 880 + reg = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset); 881 + reg |= BIT(value); 882 + pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, reg); 891 883 892 884 out_unlock: 893 885 mutex_unlock(&pmcdev->lock); 886 + 887 + return err; 888 + } 889 + 890 + static ssize_t pmc_core_ltr_ignore_write(struct file *file, 891 + const char __user *userbuf, 892 + size_t count, loff_t *ppos) 893 + { 894 + u32 buf_size, value; 895 + int err; 896 + 897 + buf_size = min_t(u32, count, 64); 898 + 899 + err = kstrtou32_from_user(userbuf, buf_size, 10, &value); 900 + if (err) 901 + return err; 902 + 903 + err = pmc_core_send_ltr_ignore(value); 904 + 894 905 return err == 0 ? count : err; 895 906 } 896 907 ··· 1254 1243 platform_set_drvdata(pdev, pmcdev); 1255 1244 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); 1256 1245 dmi_check_system(pmc_core_dmi_table); 1246 + 1247 + /* 1248 + * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when 1249 + * a cable is attached. Tell the PMC to ignore it. 1250 + */ 1251 + if (pmcdev->map == &tgl_reg_map) { 1252 + dev_dbg(&pdev->dev, "ignoring GBE LTR\n"); 1253 + pmc_core_send_ltr_ignore(3); 1254 + } 1257 1255 1258 1256 pmc_core_dbgfs_register(pmcdev); 1259 1257