From patchwork Thu Nov 26 17:18:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 333366 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C6C9C6379D for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0A74721D1A for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404298AbgKZRSi (ORCPT ); Thu, 26 Nov 2020 12:18:38 -0500 Received: from mga01.intel.com ([192.55.52.88]:50836 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2403979AbgKZRSi (ORCPT ); Thu, 26 Nov 2020 12:18:38 -0500 IronPort-SDR: wM3EB7vrPACqrXPxzcoNOmGm3On9Zm/D2trV619NavwV6rv3Ug47U6RCrIdycOi84Sica47QYs xgx2h9qtYeEA== X-IronPort-AV: E=McAfee;i="6000,8403,9817"; a="190462919" X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="190462919" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Nov 2020 09:18:36 -0800 IronPort-SDR: 7kyG9949wS7ubM5V/8tLMYUpEHC9Dy4fjpsnGFt1P5GvXnIdcuvMy43dvtDf79XpWV4GUW7Lov iv4NjxcrHEwA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="313450922" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga008.fm.intel.com with ESMTP; 26 Nov 2020 09:18:35 -0800 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amitk@kernel.org Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Date: Thu, 26 Nov 2020 09:18:26 -0800 Message-Id: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The Processor Thermal PCI device supports multiple features. Currently we export only RAPL. But we need more features from this device exposed for Tiger Lake and Alder Lake based platforms. So re-structure the current MMIO interface, so that more features can be added cleanly. No functional changes are expected with this change. Changes done in this patch: - Using PCI_DEVICE_DATA(), hence names of defines changed - Move RAPL MMIO code to its own module - Move the RAPL MMIO offsets to RAPL MMIO module - Adjust Kconfig dependency of PROC_THERMAL_MMIO_RAPL - Per processor driver data now contains the supported features - Moved all the common data structures and defines to a common header file - This new header file contains all the processor_thermal_* interfaces - Based on the features supported the module interface is called - Each module atleast provides one add and one remove function Signed-off-by: Srinivas Pandruvada --- drivers/thermal/intel/int340x_thermal/Kconfig | 6 +- .../thermal/intel/int340x_thermal/Makefile | 1 + .../processor_thermal_device.c | 261 ++++-------------- .../processor_thermal_device.h | 72 +++++ .../int340x_thermal/processor_thermal_rapl.c | 134 +++++++++ 5 files changed, 263 insertions(+), 211 deletions(-) create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 797907542e43..45c31f3d6054 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -10,6 +10,7 @@ config INT340X_THERMAL select ACPI_THERMAL_REL select ACPI_FAN select INTEL_SOC_DTS_IOSF_CORE + select PROC_THERMAL_MMIO_RAPL if X86_64 && POWERCAP help Newer laptops and tablets that use ACPI may have thermal sensors and other devices with thermal control capabilities outside the core @@ -41,9 +42,6 @@ config INT3406_THERMAL power consumed by display device. config PROC_THERMAL_MMIO_RAPL - bool - depends on 64BIT - depends on POWERCAP + tristate select INTEL_RAPL_CORE - default y endif diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index 287eb0a1476d..86e8d3c87df7 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o +obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 81e8b15ef405..5b8dc5e9ec86 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -12,74 +12,18 @@ #include #include #include -#include #include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" #include "../intel_soc_dts_iosf.h" -/* Broadwell-U/HSB thermal reporting device */ -#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 -#define PCI_DEVICE_ID_PROC_HSB_THERMAL 0x0A03 - -/* Skylake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_SKL_THERMAL 0x1903 - -/* CannonLake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_CNL_THERMAL 0x5a03 -#define PCI_DEVICE_ID_PROC_CFL_THERMAL 0x3E83 - -/* Braswell thermal reporting device */ -#define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC - -/* Broxton thermal reporting device */ -#define PCI_DEVICE_ID_PROC_BXT0_THERMAL 0x0A8C -#define PCI_DEVICE_ID_PROC_BXT1_THERMAL 0x1A8C -#define PCI_DEVICE_ID_PROC_BXTX_THERMAL 0x4A8C -#define PCI_DEVICE_ID_PROC_BXTP_THERMAL 0x5A8C - -/* GeminiLake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_GLK_THERMAL 0x318C - -/* IceLake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_ICL_THERMAL 0x8a03 - -/* JasperLake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4E03 - -/* TigerLake thermal reporting device */ -#define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03 - #define DRV_NAME "proc_thermal" -struct power_config { - u32 index; - u32 min_uw; - u32 max_uw; - u32 tmin_us; - u32 tmax_us; - u32 step_uw; -}; - -struct proc_thermal_device { - struct device *dev; - struct acpi_device *adev; - struct power_config power_limits[2]; - struct int34x_thermal_zone *int340x_zone; - struct intel_soc_dts_sensors *soc_dts; - void __iomem *mmio_base; -}; - enum proc_thermal_emum_mode_type { PROC_THERMAL_NONE, PROC_THERMAL_PCI, PROC_THERMAL_PLATFORM_DEV }; -struct rapl_mmio_regs { - u64 reg_unit; - u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; - int limits[RAPL_DOMAIN_MAX]; -}; - /* * We can have only one type of enumeration, PCI or Platform, * not both. So we don't need instance specific data. @@ -461,84 +405,13 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) return IRQ_HANDLED; } -#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL - #define MCHBAR 0 -/* RAPL Support via MMIO interface */ -static struct rapl_if_priv rapl_mmio_priv; - -static int rapl_mmio_cpu_online(unsigned int cpu) -{ - struct rapl_package *rp; - - /* mmio rapl supports package 0 only for now */ - if (topology_physical_package_id(cpu)) - return 0; - - rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); - if (!rp) { - rp = rapl_add_package(cpu, &rapl_mmio_priv); - if (IS_ERR(rp)) - return PTR_ERR(rp); - } - cpumask_set_cpu(cpu, &rp->cpumask); - return 0; -} - -static int rapl_mmio_cpu_down_prep(unsigned int cpu) +static int proc_thermal_set_mmio_base(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv) { - struct rapl_package *rp; - int lead_cpu; - - rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); - if (!rp) - return 0; - - cpumask_clear_cpu(cpu, &rp->cpumask); - lead_cpu = cpumask_first(&rp->cpumask); - if (lead_cpu >= nr_cpu_ids) - rapl_remove_package(rp); - else if (rp->lead_cpu == cpu) - rp->lead_cpu = lead_cpu; - return 0; -} - -static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) -{ - if (!ra->reg) - return -EINVAL; - - ra->value = readq((void __iomem *)ra->reg); - ra->value &= ra->mask; - return 0; -} - -static int rapl_mmio_write_raw(int cpu, struct reg_action *ra) -{ - u64 val; - - if (!ra->reg) - return -EINVAL; - - val = readq((void __iomem *)ra->reg); - val &= ~ra->mask; - val |= ra->value; - writeq(val, (void __iomem *)ra->reg); - return 0; -} - -static int proc_thermal_rapl_add(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv, - struct rapl_mmio_regs *rapl_regs) -{ - enum rapl_domain_reg_id reg; - enum rapl_domain_type domain; int ret; - if (!rapl_regs) - return 0; - ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME); if (ret) { dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); @@ -547,66 +420,42 @@ static int proc_thermal_rapl_add(struct pci_dev *pdev, proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR]; - for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) { - for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++) - if (rapl_regs->regs[domain][reg]) - rapl_mmio_priv.regs[domain][reg] = - (u64)proc_priv->mmio_base + - rapl_regs->regs[domain][reg]; - rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain]; - } - rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit; + return 0; +} - rapl_mmio_priv.read_raw = rapl_mmio_read_raw; - rapl_mmio_priv.write_raw = rapl_mmio_write_raw; +static int proc_thermal_mmio_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + kernel_ulong_t feature_mask) +{ + int ret; - rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL); - if (IS_ERR(rapl_mmio_priv.control_type)) { - pr_debug("failed to register powercap control_type.\n"); - return PTR_ERR(rapl_mmio_priv.control_type); + if (feature_mask) { + ret = proc_thermal_set_mmio_base(pdev, proc_priv); + if (ret) + return ret; } - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online", - rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep); - if (ret < 0) { - powercap_unregister_control_type(rapl_mmio_priv.control_type); - rapl_mmio_priv.control_type = NULL; - return ret; + if (feature_mask & PROC_THERMAL_FEATURE_RAPL) { + ret = proc_thermal_rapl_add(pdev, proc_priv); + if (ret) { + dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n"); + return ret; + } } - rapl_mmio_priv.pcap_rapl_online = ret; + + proc_priv->mmio_feature_mask = feature_mask; return 0; } -static void proc_thermal_rapl_remove(void) +static void proc_thermal_mmio_remove(struct pci_dev *pdev) { - if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type)) - return; - - cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online); - powercap_unregister_control_type(rapl_mmio_priv.control_type); -} + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); -static const struct rapl_mmio_regs rapl_mmio_hsw = { - .reg_unit = 0x5938, - .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930}, - .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0}, - .limits[RAPL_DOMAIN_PACKAGE] = 2, - .limits[RAPL_DOMAIN_DRAM] = 2, -}; + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) + proc_thermal_rapl_remove(); -#else - -static int proc_thermal_rapl_add(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv, - struct rapl_mmio_regs *rapl_regs) -{ - return 0; } -static void proc_thermal_rapl_remove(void) {} -static const struct rapl_mmio_regs rapl_mmio_hsw; - -#endif /* CONFIG_MMIO_RAPL */ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -629,18 +478,10 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, if (ret) return ret; - ret = proc_thermal_rapl_add(pdev, proc_priv, - (struct rapl_mmio_regs *)id->driver_data); - if (ret) { - dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n"); - proc_thermal_remove(proc_priv); - return ret; - } - pci_set_drvdata(pdev, proc_priv); proc_thermal_emum_mode = PROC_THERMAL_PCI; - if (pdev->device == PCI_DEVICE_ID_PROC_BSW_THERMAL) { + if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) { /* * Enumerate additional DTS sensors available via IOSF. * But we are not treating as a failure condition, if @@ -676,10 +517,18 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, return ret; ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group); - if (ret) + if (ret) { sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); + return ret; + } - return ret; + ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); + if (ret) { + proc_thermal_remove(proc_priv); + return ret; + } + + return 0; } static void proc_thermal_pci_remove(struct pci_dev *pdev) @@ -693,7 +542,8 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev) pci_disable_msi(pdev); } } - proc_thermal_rapl_remove(); + + proc_thermal_mmio_remove(pdev); proc_thermal_remove(proc_priv); } @@ -716,24 +566,21 @@ static int proc_thermal_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL), - .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTX_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CNL_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CFL_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_GLK_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_ICL_THERMAL), - .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_JSL_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_TGL_THERMAL), - .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, }, - { 0, }, + { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { }, }; MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h new file mode 100644 index 000000000000..e20d142a55b4 --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * processor_thermal_device.h + * Copyright (c) 2020, Intel Corporation. + */ + +#ifndef __PROCESSOR_THERMAL_DEVICE_H__ +#define __PROCESSOR_THERMAL_DEVICE_H__ + +#include + +#define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603 +#define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC + +#define PCI_DEVICE_ID_INTEL_BXT0_THERMAL 0x0A8C +#define PCI_DEVICE_ID_INTEL_BXT1_THERMAL 0x1A8C +#define PCI_DEVICE_ID_INTEL_BXTX_THERMAL 0x4A8C +#define PCI_DEVICE_ID_INTEL_BXTP_THERMAL 0x5A8C + +#define PCI_DEVICE_ID_INTEL_CNL_THERMAL 0x5a03 +#define PCI_DEVICE_ID_INTEL_CFL_THERMAL 0x3E83 +#define PCI_DEVICE_ID_INTEL_GLK_THERMAL 0x318C +#define PCI_DEVICE_ID_INTEL_HSB_THERMAL 0x0A03 +#define PCI_DEVICE_ID_INTEL_ICL_THERMAL 0x8a03 +#define PCI_DEVICE_ID_INTEL_JSL_THERMAL 0x4E03 +#define PCI_DEVICE_ID_INTEL_SKL_THERMAL 0x1903 +#define PCI_DEVICE_ID_INTEL_TGL_THERMAL 0x9A03 + +struct power_config { + u32 index; + u32 min_uw; + u32 max_uw; + u32 tmin_us; + u32 tmax_us; + u32 step_uw; +}; + +struct proc_thermal_device { + struct device *dev; + struct acpi_device *adev; + struct power_config power_limits[2]; + struct int34x_thermal_zone *int340x_zone; + struct intel_soc_dts_sensors *soc_dts; + u32 mmio_feature_mask; + void __iomem *mmio_base; +}; + +struct rapl_mmio_regs { + u64 reg_unit; + u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; + int limits[RAPL_DOMAIN_MAX]; +}; + +#define PROC_THERMAL_FEATURE_NONE 0x00 +#define PROC_THERMAL_FEATURE_RAPL 0x01 + +#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) +int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); +void proc_thermal_rapl_remove(void); +#else +static int __maybe_unused proc_thermal_rapl_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv) +{ + return 0; +} + +static void __maybe_unused proc_thermal_rapl_remove(void) +{ +} +#endif + +#endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c new file mode 100644 index 000000000000..a205221ec8df --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * processor thermal device RFIM control + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include +#include +#include "processor_thermal_device.h" + +static struct rapl_if_priv rapl_mmio_priv; + +static const struct rapl_mmio_regs rapl_mmio_default = { + .reg_unit = 0x5938, + .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930}, + .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0}, + .limits[RAPL_DOMAIN_PACKAGE] = 2, + .limits[RAPL_DOMAIN_DRAM] = 2, +}; + +static int rapl_mmio_cpu_online(unsigned int cpu) +{ + struct rapl_package *rp; + + /* mmio rapl supports package 0 only for now */ + if (topology_physical_package_id(cpu)) + return 0; + + rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); + if (!rp) { + rp = rapl_add_package(cpu, &rapl_mmio_priv); + if (IS_ERR(rp)) + return PTR_ERR(rp); + } + cpumask_set_cpu(cpu, &rp->cpumask); + return 0; +} + +static int rapl_mmio_cpu_down_prep(unsigned int cpu) +{ + struct rapl_package *rp; + int lead_cpu; + + rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); + if (!rp) + return 0; + + cpumask_clear_cpu(cpu, &rp->cpumask); + lead_cpu = cpumask_first(&rp->cpumask); + if (lead_cpu >= nr_cpu_ids) + rapl_remove_package(rp); + else if (rp->lead_cpu == cpu) + rp->lead_cpu = lead_cpu; + return 0; +} + +static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) +{ + if (!ra->reg) + return -EINVAL; + + ra->value = readq((void __iomem *)ra->reg); + ra->value &= ra->mask; + return 0; +} + +static int rapl_mmio_write_raw(int cpu, struct reg_action *ra) +{ + u64 val; + + if (!ra->reg) + return -EINVAL; + + val = readq((void __iomem *)ra->reg); + val &= ~ra->mask; + val |= ra->value; + writeq(val, (void __iomem *)ra->reg); + return 0; +} + +int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) +{ + const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default; + enum rapl_domain_reg_id reg; + enum rapl_domain_type domain; + int ret; + + if (!rapl_regs) + return 0; + + for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) { + for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++) + if (rapl_regs->regs[domain][reg]) + rapl_mmio_priv.regs[domain][reg] = + (u64)proc_priv->mmio_base + + rapl_regs->regs[domain][reg]; + rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain]; + } + rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit; + + rapl_mmio_priv.read_raw = rapl_mmio_read_raw; + rapl_mmio_priv.write_raw = rapl_mmio_write_raw; + + rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL); + if (IS_ERR(rapl_mmio_priv.control_type)) { + pr_debug("failed to register powercap control_type.\n"); + return PTR_ERR(rapl_mmio_priv.control_type); + } + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online", + rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep); + if (ret < 0) { + powercap_unregister_control_type(rapl_mmio_priv.control_type); + rapl_mmio_priv.control_type = NULL; + return ret; + } + rapl_mmio_priv.pcap_rapl_online = ret; + + return 0; +} +EXPORT_SYMBOL_GPL(proc_thermal_rapl_add); + +void proc_thermal_rapl_remove(void) +{ + if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type)) + return; + + cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online); + powercap_unregister_control_type(rapl_mmio_priv.control_type); +} +EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove); + +MODULE_LICENSE("GPL v2"); From patchwork Thu Nov 26 17:18:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 333942 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66F81C64E7A for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4CC4C21D1A for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404322AbgKZRSj (ORCPT ); Thu, 26 Nov 2020 12:18:39 -0500 Received: from mga01.intel.com ([192.55.52.88]:50836 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404301AbgKZRSj (ORCPT ); Thu, 26 Nov 2020 12:18:39 -0500 IronPort-SDR: XXluIQGGS9fgnqrkmHdIUzwI2XNkLhkzA9ATBN/EHeg1oM2kWGJnHDYK5FWKAPE6EXmoCMJnJR rFprTO7v2ulw== X-IronPort-AV: E=McAfee;i="6000,8403,9817"; a="190462920" X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="190462920" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Nov 2020 09:18:36 -0800 IronPort-SDR: agqtmU8XYSddHa6r2+CRbg7yhLAbhd8ZMs/JlDF57ZNIJpxfKtLY5Xu089dTvbsGGF7WdhCIRx qOMQHLVWKNxQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="313450927" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga008.fm.intel.com with ESMTP; 26 Nov 2020 09:18:36 -0800 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amitk@kernel.org Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Date: Thu, 26 Nov 2020 09:18:27 -0800 Message-Id: <20201126171829.945969-2-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> References: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Added AlderLake PCI device id to support processor thermal driver. Reuse the feature set (just includes RAPL) from previous generations. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 1 + drivers/thermal/intel/int340x_thermal/processor_thermal_device.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 5b8dc5e9ec86..589ac7deec02 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -566,6 +566,7 @@ static int proc_thermal_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index e20d142a55b4..45214571e00d 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -9,6 +9,7 @@ #include +#define PCI_DEVICE_ID_INTEL_ADL_THERMAL 0x461d #define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603 #define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC From patchwork Thu Nov 26 17:18:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 333365 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A34D9C64E8A for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7AE1721D1A for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404350AbgKZRSo (ORCPT ); Thu, 26 Nov 2020 12:18:44 -0500 Received: from mga01.intel.com ([192.55.52.88]:50836 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2403939AbgKZRSi (ORCPT ); Thu, 26 Nov 2020 12:18:38 -0500 IronPort-SDR: MqZjXS/PLUXeNsknaQSW3u3qXUnTMBFvOFrzw6f8EvcJjofqy16F5AOT7ERwHrroy4qcDnwWyr aroRpT/F8REA== X-IronPort-AV: E=McAfee;i="6000,8403,9817"; a="190462921" X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="190462921" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Nov 2020 09:18:36 -0800 IronPort-SDR: FNOBOM4p//IZN1O62LQ130jn+7hNwcpBNxnmeGYUWv/UTelHr5bcD0Y7DCjOZ2JirSzYPrfMvM 17g+JbDp53RA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="313450931" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga008.fm.intel.com with ESMTP; 26 Nov 2020 09:18:36 -0800 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amitk@kernel.org Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Date: Thu, 26 Nov 2020 09:18:28 -0800 Message-Id: <20201126171829.945969-3-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> References: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Add support for RFIM (Radio Frequency Interference Mitigation) support via processor thermal PCI device. This drivers allows adjustment of FIVR (Fully Integrated Voltage Regulator) and DDR (Double Data Rate) frequencies to avoid RF interference with WiFi and 5G. Switching voltage regulators (VR) generate radiated EMI or RFI at the fundamental frequency and its harmonics. Some harmonics may interfere with very sensitive wireless receivers such as Wi-Fi and cellular that are integrated into host systems like notebook PCs. One of mitigation methods is requesting SOC integrated VR (IVR) switching frequency to a small % and shift away the switching noise harmonic interference from radio channels. OEM or ODMs can use the driver to control SOC IVR operation within the range where it does not impact IVR performance. DRAM devices of DDR IO interface and their power plane can generate EMI at the data rates. Similar to IVR control mechanism, Intel offers a mechanism by which DDR data rates can be changed if several conditions are met: there is strong RFI interference because of DDR; CPU power management has no other restriction in changing DDR data rates; PC ODMs enable this feature (real time DDR RFI Mitigation referred to as DDR-RFIM) for Wi-Fi from BIOS. This change exports two folders under /sys/bus/pci/devices/0000:00:04.0. One folder "fivr" contains all attributes exposed for controling FIVR features. The other folder "dvfs" contains all attributes for DDR features. Changes done to implement: - New module for rfim interfaces - Two new per processor features for DDR and FIVR - Enable feature for Tiger Lake (FIVR only) and Alder Lake The attributes exposed and explanation: FIVR attributes vco_ref_code_lo (RW): The VCO reference code is an 11-bit field and controls the FIVR switching frequency. This is the 3-bit LSB field. vco_ref_code_hi (RW): The VCO reference code is an 11-bit field and controls the FIVR switching frequency. This is the 8-bit MSB field. spread_spectrum_pct (RW): Set the FIVR spread spectrum clocking percentage spread_spectrum_clk_enable (RW): Enable/disable of the FIVR spread spectrum clocking feature rfi_vco_ref_code (RW): This field is a read only status register which reflects the current FIVR switching frequency fivr_fffc_rev (RW): This field indicated the revision of the FIVR HW. DVFS attributes rfi_restriction_run_busy (RW): Request the restriction of specific DDR data rate and set this value 1. Self reset to 0 after operation. rfi_restriction_err_code (RW): Values: 0 :Request is accepted, 1:Feature disabled, 2: the request restricts more points than it is allowed rfi_restriction_data_rate_Delta (RW): Restricted DDR data rate for RFI protection: Lower Limit rfi_restriction_data_rate_Base (RW): Restricted DDR data rate for RFI protection: Upper Limit ddr_data_rate_point_0 (RO): DDR data rate selection 1st point ddr_data_rate_point_1 (RO): DDR data rate selection 2nd point ddr_data_rate_point_2 (RO): DDR data rate selection 3rd point ddr_data_rate_point_3 (RO): DDR data rate selection 4th point rfi_disable (RW): Disable DDR rate change feature Signed-off-by: Srinivas Pandruvada --- .../thermal/intel/int340x_thermal/Makefile | 1 + .../processor_thermal_device.c | 23 +- .../processor_thermal_device.h | 5 + .../int340x_thermal/processor_thermal_rfim.c | 244 ++++++++++++++++++ 4 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index 86e8d3c87df7..f4e2eb7d9606 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 589ac7deec02..b6a7358b989d 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -429,6 +429,8 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev, { int ret; + proc_priv->mmio_feature_mask = feature_mask; + if (feature_mask) { ret = proc_thermal_set_mmio_base(pdev, proc_priv); if (ret) @@ -443,9 +445,21 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev, } } - proc_priv->mmio_feature_mask = feature_mask; + if (feature_mask & PROC_THERMAL_FEATURE_FIVR || + feature_mask & PROC_THERMAL_FEATURE_DVFS) { + ret = proc_thermal_rfim_add(pdev, proc_priv); + if (ret) { + dev_err(&pdev->dev, "failed to add RFIM interface\n"); + goto err_rem_rapl; + } + } return 0; + +err_rem_rapl: + proc_thermal_rapl_remove(); + + return ret; } static void proc_thermal_mmio_remove(struct pci_dev *pdev) @@ -455,6 +469,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) proc_thermal_rapl_remove(); + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR || + proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) + proc_thermal_rfim_remove(pdev); } static int proc_thermal_pci_probe(struct pci_dev *pdev, @@ -566,7 +583,7 @@ static int proc_thermal_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { - { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) }, { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, @@ -580,7 +597,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) }, { }, }; diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index 45214571e00d..4bbb88f6b4a7 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -54,6 +54,8 @@ struct rapl_mmio_regs { #define PROC_THERMAL_FEATURE_NONE 0x00 #define PROC_THERMAL_FEATURE_RAPL 0x01 +#define PROC_THERMAL_FEATURE_FIVR 0x02 +#define PROC_THERMAL_FEATURE_DVFS 0x04 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); @@ -70,4 +72,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void) } #endif +int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); +void proc_thermal_rfim_remove(struct pci_dev *pdev); + #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c new file mode 100644 index 000000000000..aef993a813e2 --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * processor thermal device RFIM control + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include +#include +#include "processor_thermal_device.h" + +struct mmio_reg { + int read_only; + u32 offset; + int bits; + u16 mask; + u16 shift; +}; + +/* These will represent sysfs attribute names */ +static const char * const fivr_strings[] = { + "vco_ref_code_lo", + "vco_ref_code_hi", + "spread_spectrum_pct", + "spread_spectrum_clk_enable", + "rfi_vco_ref_code", + "fivr_fffc_rev", + NULL +}; + +static const struct mmio_reg tgl_fivr_mmio_regs[] = { + { 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */ + { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */ + { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */ + { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */ + { 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */ + { 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */ +}; + +/* These will represent sysfs attribute names */ +static const char * const dvfs_strings[] = { + "rfi_restriction_run_busy", + "rfi_restriction_err_code", + "rfi_restriction_data_rate", + "rfi_restriction_data_rate_base", + "ddr_data_rate_point_0", + "ddr_data_rate_point_1", + "ddr_data_rate_point_2", + "ddr_data_rate_point_3", + "rfi_disable", + NULL +}; + +static const struct mmio_reg adl_dvfs_mmio_regs[] = { + { 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */ + { 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */ + { 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */ + { 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */ + { 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */ + { 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */ + { 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */ + { 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */ + { 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */ +}; + +#define RFIM_SHOW(suffix, table)\ +static ssize_t suffix##_show(struct device *dev,\ + struct device_attribute *attr,\ + char *buf)\ +{\ + struct proc_thermal_device *proc_priv;\ + struct pci_dev *pdev = to_pci_dev(dev);\ + const struct mmio_reg *mmio_regs;\ + const char **match_strs;\ + u32 reg_val;\ + int ret;\ +\ + proc_priv = pci_get_drvdata(pdev);\ + if (table) {\ + match_strs = (const char **)dvfs_strings;\ + mmio_regs = adl_dvfs_mmio_regs;\ + } else { \ + match_strs = (const char **)fivr_strings;\ + mmio_regs = tgl_fivr_mmio_regs;\ + } \ + \ + ret = match_string(match_strs, -1, attr->attr.name);\ + if (ret < 0)\ + return ret;\ + reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ + ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\ + return sprintf(buf, "%u\n", ret);\ +} + +#define RFIM_STORE(suffix, table)\ +static ssize_t suffix##_store(struct device *dev,\ + struct device_attribute *attr,\ + const char *buf, size_t count)\ +{\ + struct proc_thermal_device *proc_priv;\ + struct pci_dev *pdev = to_pci_dev(dev);\ + unsigned int input;\ + const char **match_strs;\ + const struct mmio_reg *mmio_regs;\ + int ret, err;\ + u32 reg_val;\ + u32 mask;\ +\ + proc_priv = pci_get_drvdata(pdev);\ + if (table) {\ + match_strs = (const char **)dvfs_strings;\ + mmio_regs = adl_dvfs_mmio_regs;\ + } else { \ + match_strs = (const char **)fivr_strings;\ + mmio_regs = tgl_fivr_mmio_regs;\ + } \ + \ + ret = match_string(match_strs, -1, attr->attr.name);\ + if (ret < 0)\ + return ret;\ + if (mmio_regs[ret].read_only)\ + return -EPERM;\ + err = kstrtouint(buf, 10, &input);\ + if (err)\ + return err;\ + mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\ + reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ + reg_val &= ~mask;\ + reg_val |= (input << mmio_regs[ret].shift);\ + writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ + return count;\ +} + +RFIM_SHOW(vco_ref_code_lo, 0) +RFIM_SHOW(vco_ref_code_hi, 0) +RFIM_SHOW(spread_spectrum_pct, 0) +RFIM_SHOW(spread_spectrum_clk_enable, 0) +RFIM_SHOW(rfi_vco_ref_code, 0) +RFIM_SHOW(fivr_fffc_rev, 0) + +RFIM_STORE(vco_ref_code_lo, 0) +RFIM_STORE(vco_ref_code_hi, 0) +RFIM_STORE(spread_spectrum_pct, 0) +RFIM_STORE(spread_spectrum_clk_enable, 0) +RFIM_STORE(rfi_vco_ref_code, 0) +RFIM_STORE(fivr_fffc_rev, 0) + +static DEVICE_ATTR_RW(vco_ref_code_lo); +static DEVICE_ATTR_RW(vco_ref_code_hi); +static DEVICE_ATTR_RW(spread_spectrum_pct); +static DEVICE_ATTR_RW(spread_spectrum_clk_enable); +static DEVICE_ATTR_RW(rfi_vco_ref_code); +static DEVICE_ATTR_RW(fivr_fffc_rev); + +static struct attribute *fivr_attrs[] = { + &dev_attr_vco_ref_code_lo.attr, + &dev_attr_vco_ref_code_hi.attr, + &dev_attr_spread_spectrum_pct.attr, + &dev_attr_spread_spectrum_clk_enable.attr, + &dev_attr_rfi_vco_ref_code.attr, + &dev_attr_fivr_fffc_rev.attr, + NULL +}; + +static const struct attribute_group fivr_attribute_group = { + .attrs = fivr_attrs, + .name = "fivr" +}; + +RFIM_SHOW(rfi_restriction_run_busy, 1) +RFIM_SHOW(rfi_restriction_err_code, 1) +RFIM_SHOW(rfi_restriction_data_rate, 1) +RFIM_SHOW(ddr_data_rate_point_0, 1) +RFIM_SHOW(ddr_data_rate_point_1, 1) +RFIM_SHOW(ddr_data_rate_point_2, 1) +RFIM_SHOW(ddr_data_rate_point_3, 1) +RFIM_SHOW(rfi_disable, 1) + +RFIM_STORE(rfi_restriction_run_busy, 1) +RFIM_STORE(rfi_restriction_err_code, 1) +RFIM_STORE(rfi_restriction_data_rate, 1) +RFIM_STORE(rfi_disable, 1) + +static DEVICE_ATTR_RW(rfi_restriction_run_busy); +static DEVICE_ATTR_RW(rfi_restriction_err_code); +static DEVICE_ATTR_RW(rfi_restriction_data_rate); +static DEVICE_ATTR_RO(ddr_data_rate_point_0); +static DEVICE_ATTR_RO(ddr_data_rate_point_1); +static DEVICE_ATTR_RO(ddr_data_rate_point_2); +static DEVICE_ATTR_RO(ddr_data_rate_point_3); +static DEVICE_ATTR_RW(rfi_disable); + +static struct attribute *dvfs_attrs[] = { + &dev_attr_rfi_restriction_run_busy.attr, + &dev_attr_rfi_restriction_err_code.attr, + &dev_attr_rfi_restriction_data_rate.attr, + &dev_attr_ddr_data_rate_point_0.attr, + &dev_attr_ddr_data_rate_point_1.attr, + &dev_attr_ddr_data_rate_point_2.attr, + &dev_attr_ddr_data_rate_point_3.attr, + &dev_attr_rfi_disable.attr, + NULL +}; + +static const struct attribute_group dvfs_attribute_group = { + .attrs = dvfs_attrs, + .name = "dvfs" +}; + +int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) +{ + int ret; + + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { + ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group); + if (ret) + return ret; + } + + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) { + ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group); + if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { + sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); + +void proc_thermal_rfim_remove(struct pci_dev *pdev) +{ + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) + sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); + + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) + sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group); +} +EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); + +MODULE_LICENSE("GPL v2"); From patchwork Thu Nov 26 17:18:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 333943 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C818C63798 for ; Thu, 26 Nov 2020 17:19:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CDA2321D46 for ; Thu, 26 Nov 2020 17:19:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404255AbgKZRSi (ORCPT ); Thu, 26 Nov 2020 12:18:38 -0500 Received: from mga01.intel.com ([192.55.52.88]:50836 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404254AbgKZRSh (ORCPT ); Thu, 26 Nov 2020 12:18:37 -0500 IronPort-SDR: oY99ejYTJRTeTw6LFHTnA32iNY0xmGqRQKqTMBDLxSJZlU2ECzo0tHSvPEyyvZ1GyMBfKPQirO BMZhHL00WnVA== X-IronPort-AV: E=McAfee;i="6000,8403,9817"; a="190462922" X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="190462922" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Nov 2020 09:18:37 -0800 IronPort-SDR: +a5Jo6CwnTAhxNbZhmXnxphLIQqWIDO+aOMUWqST1v6BOffH+DYG++UGXvCloskwDSl2aiNuWL 6SjCFee22iuw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,372,1599548400"; d="scan'208";a="313450935" Received: from spandruv-desk.jf.intel.com ([10.54.75.21]) by fmsmga008.fm.intel.com with ESMTP; 26 Nov 2020 09:18:36 -0800 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amitk@kernel.org Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver Date: Thu, 26 Nov 2020 09:18:29 -0800 Message-Id: <20201126171829.945969-4-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> References: <20201126171829.945969-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Added processor thermal device mail box interface for workload hints setting. These hints will give indication to hardware to better manage power and thermals. The supported hints are: idle semi_active burusty sustained battery_life For example when the system is on battery, the hardware can be less aggressive in power ramp up. This will create an attribute group at /sys/bus/pci/devices/0000:00:04.0/workload_request This folder contains two attributes: workload_available_types : (RO): This shows available workload types workload_type: (RW) : Allows to set and get current workload type setting Signed-off-by: Srinivas Pandruvada --- .../thermal/intel/int340x_thermal/Makefile | 1 + .../processor_thermal_device.c | 17 +- .../processor_thermal_device.h | 4 + .../int340x_thermal/processor_thermal_mbox.c | 212 ++++++++++++++++++ 4 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index f4e2eb7d9606..38a2731e503c 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index b6a7358b989d..9e6f2a895a23 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -454,8 +454,18 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev, } } + if (feature_mask & PROC_THERMAL_FEATURE_MBOX) { + ret = proc_thermal_mbox_add(pdev, proc_priv); + if (ret) { + dev_err(&pdev->dev, "failed to add MBOX interface\n"); + goto err_rem_rfim; + } + } + return 0; +err_rem_rfim: + proc_thermal_rfim_remove(pdev); err_rem_rapl: proc_thermal_rapl_remove(); @@ -472,6 +482,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR || proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) proc_thermal_rfim_remove(pdev); + + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX) + proc_thermal_mbox_remove(pdev); } static int proc_thermal_pci_probe(struct pci_dev *pdev, @@ -583,7 +596,7 @@ static int proc_thermal_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); static const struct pci_device_id proc_thermal_pci_ids[] = { - { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) }, + { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, @@ -597,7 +610,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) }, + { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) }, { }, }; diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index 4bbb88f6b4a7..b9ed64561aaf 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -56,6 +56,7 @@ struct rapl_mmio_regs { #define PROC_THERMAL_FEATURE_RAPL 0x01 #define PROC_THERMAL_FEATURE_FIVR 0x02 #define PROC_THERMAL_FEATURE_DVFS 0x04 +#define PROC_THERMAL_FEATURE_MBOX 0x08 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); @@ -75,4 +76,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void) int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); void proc_thermal_rfim_remove(struct pci_dev *pdev); +int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); +void proc_thermal_mbox_remove(struct pci_dev *pdev); + #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c new file mode 100644 index 000000000000..2c105fed2d7b --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * processor thermal device mailbox driver for Workload type hints + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include +#include +#include "processor_thermal_device.h" + +#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E +#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F + +#define MBOX_OFFSET_DATA 0x5810 +#define MBOX_OFFSET_INTERFACE 0x5818 + +#define MBOX_BUSY_BIT 31 +#define MBOX_RETRY_COUNT 100 + +#define MBOX_DATA_BIT_VALID 31 +#define MBOX_DATA_BIT_AC_DC 30 + +static DEFINE_MUTEX(mbox_lock); + +static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp) +{ + struct proc_thermal_device *proc_priv; + u32 retries, data; + int ret; + + mutex_lock(&mbox_lock); + proc_priv = pci_get_drvdata(pdev); + + /* Poll for rb bit == 0 */ + retries = MBOX_RETRY_COUNT; + do { + data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)); + if (data & BIT_ULL(MBOX_BUSY_BIT)) { + ret = -EBUSY; + continue; + } + ret = 0; + break; + } while (--retries); + + if (ret) + goto unlock_mbox; + + if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_WRITE) + writel(cmd_data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_DATA))); + + /* Write command register */ + data = BIT_ULL(MBOX_BUSY_BIT) | cmd_id; + writel(data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_INTERFACE))); + + /* Poll for rb bit == 0 */ + retries = MBOX_RETRY_COUNT; + do { + data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)); + if (data & BIT_ULL(MBOX_BUSY_BIT)) { + ret = -EBUSY; + continue; + } + + if (data) { + ret = -ENXIO; + goto unlock_mbox; + } + + if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_READ) { + data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA)); + *cmd_resp = data & 0xff; + } + + ret = 0; + break; + } while (--retries); + +unlock_mbox: + mutex_unlock(&mbox_lock); + return ret; +} + +/* List of workload types */ +static const char * const workload_types[] = { + "none", + "idle", + "semi_active", + "burusty", + "sustained", + "battery_life", + NULL +}; + + +static ssize_t workload_available_types_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 0; + int ret = 0; + + while (workload_types[i] != NULL) + ret += sprintf(&buf[ret], "%s ", workload_types[i++]); + + ret += sprintf(&buf[ret], "\n"); + + return ret; +} + +static DEVICE_ATTR_RO(workload_available_types); + +static ssize_t workload_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + char str_preference[15]; + u32 data = 0; + ssize_t ret; + + ret = sscanf(buf, "%14s", str_preference); + if (ret != 1) + return -EINVAL; + + ret = match_string(workload_types, -1, str_preference); + if (ret < 0) + return ret; + + ret &= 0xff; + + if (ret) + data = BIT(MBOX_DATA_BIT_VALID) | BIT(MBOX_DATA_BIT_AC_DC); + + data |= ret; + + ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data, NULL); + if (ret) + return false; + + return count; +} + +static ssize_t workload_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + u8 cmd_resp; + int ret; + + ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp); + if (ret) + return false; + + cmd_resp &= 0xff; + + if (cmd_resp > ARRAY_SIZE(workload_types) - 1) + return -EINVAL; + + return sprintf(buf, "%s\n", workload_types[cmd_resp]); +} + +static DEVICE_ATTR_RW(workload_type); + +static struct attribute *workload_req_attrs[] = { + &dev_attr_workload_available_types.attr, + &dev_attr_workload_type.attr, + NULL +}; + +static const struct attribute_group workload_req_attribute_group = { + .attrs = workload_req_attrs, + .name = "workload_request" +}; + + + +static bool workload_req_created; + +int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) +{ + u8 cmd_resp; + int ret; + + /* Check if there is a mailbox support, if fails return success */ + ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp); + if (ret) + return 0; + + ret = sysfs_create_group(&pdev->dev.kobj, &workload_req_attribute_group); + if (ret) + return ret; + + workload_req_created = true; + + return 0; +} +EXPORT_SYMBOL_GPL(proc_thermal_mbox_add); + +void proc_thermal_mbox_remove(struct pci_dev *pdev) +{ + if (workload_req_created) + sysfs_remove_group(&pdev->dev.kobj, &workload_req_attribute_group); + + workload_req_created = false; + +} +EXPORT_SYMBOL_GPL(proc_thermal_mbox_remove); + +MODULE_LICENSE("GPL v2");