From nobody Mon Jun 29 18:39:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ECA57C433F5 for ; Fri, 4 Feb 2022 00:03:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356130AbiBDADh (ORCPT ); Thu, 3 Feb 2022 19:03:37 -0500 Received: from mga01.intel.com ([192.55.52.88]:8517 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241161AbiBDADb (ORCPT ); Thu, 3 Feb 2022 19:03:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1643933011; x=1675469011; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=rmmSAM16z8RnkHc97boUyZm+0sNhRRp1bzZIQE44To4=; b=GdTHziREg1ais8Ykma320O2KP9i5Z1g3jL4IFNjlos6tnEsC/TvYrj8p nyWpRQbDfuPdqEzDc/O0DTrNd7x313dt0loL+TzF6xLBLZO8NRKbVLY+h 98Eq3TCRkLTE3q9KbWyTwP7GjlkuMyk93gz5XgJHlR7sCEMV53E8Wk3q/ +lRlFbueeRRcPIsEkkAZSetrvIv2GpbAkDr05FsfdkyyvHzLbVmVN0da/ RTnWNIVV+4N3bXfCwHSJkbfYeMJ5+HVwdBSvDkFkbi3RZaxXTXLjSSvKm VvRFMTrjbSuPzZXbRA44ZrIPBO7C3N6oxlR3rsUZu0vT27aVR2rD+1Djd w==; X-IronPort-AV: E=McAfee;i="6200,9189,10247"; a="272779957" X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="272779957" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2022 16:03:30 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="620684669" Received: from spandruv-desk.jf.intel.com ([10.54.75.8]) by FMSMGA003.fm.intel.com with ESMTP; 03 Feb 2022 16:03:30 -0800 From: Srinivas Pandruvada To: hdegoede@redhat.com, markgross@kernel.org Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Srinivas Pandruvada , "Rafael J . Wysocki" Subject: [PATCH 1/4] platform/x86/intel/uncore-freq: Move to uncore-frequency folder Date: Thu, 3 Feb 2022 16:03:03 -0800 Message-Id: <20220204000306.2517447-2-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> References: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Srinivas Pandruvada Move the current driver from platform/x86/intel/uncore-frequency.c to platform/x86/intel/uncore-frequency/uncore-frequency.c. No functional changes are expected. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki --- drivers/platform/x86/intel/Kconfig | 14 ++----------- drivers/platform/x86/intel/Makefile | 4 ++-- .../x86/intel/uncore-frequency/Kconfig | 21 +++++++++++++++++++ .../x86/intel/uncore-frequency/Makefile | 7 +++++++ .../{ =3D> uncore-frequency}/uncore-frequency.c | 0 5 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 drivers/platform/x86/intel/uncore-frequency/Kconfig create mode 100644 drivers/platform/x86/intel/uncore-frequency/Makefile rename drivers/platform/x86/intel/{ =3D> uncore-frequency}/uncore-frequenc= y.c (100%) diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/inte= l/Kconfig index 8e65086bb6c8..ff754b60076e 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -12,6 +12,8 @@ source "drivers/platform/x86/intel/pmt/Kconfig" source "drivers/platform/x86/intel/speed_select_if/Kconfig" source "drivers/platform/x86/intel/telemetry/Kconfig" source "drivers/platform/x86/intel/wmi/Kconfig" +source "drivers/platform/x86/intel/uncore-frequency/Kconfig" + =20 config INTEL_HID_EVENT tristate "Intel HID Event" @@ -159,18 +161,6 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. =20 -config INTEL_UNCORE_FREQ_CONTROL - tristate "Intel Uncore frequency control driver" - depends on X86_64 - help - This driver allows control of Uncore frequency limits on - supported server platforms. - - Uncore frequency controls RING/LLC (last-level cache) clocks. - - To compile this driver as a module, choose M here: the module - will be called intel-uncore-frequency. - config INTEL_VSEC tristate "Intel Vendor Specific Extended Capabilities Driver" depends on PCI diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/int= el/Makefile index 35f2066578b2..1d5ada7b4d32 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_INTEL_PMT_CLASS) +=3D pmt/ obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) +=3D speed_select_if/ obj-$(CONFIG_INTEL_TELEMETRY) +=3D telemetry/ obj-$(CONFIG_INTEL_WMI) +=3D wmi/ +obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) +=3D uncore-frequency/ + =20 # Intel input drivers intel-hid-y :=3D hid.o @@ -48,5 +50,3 @@ intel-smartconnect-y :=3D smartconnect.o obj-$(CONFIG_INTEL_SMARTCONNECT) +=3D intel-smartconnect.o intel_turbo_max_3-y :=3D turbo_max_3.o obj-$(CONFIG_INTEL_TURBO_MAX_3) +=3D intel_turbo_max_3.o -intel-uncore-frequency-y :=3D uncore-frequency.o -obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) +=3D intel-uncore-frequency.o diff --git a/drivers/platform/x86/intel/uncore-frequency/Kconfig b/drivers/= platform/x86/intel/uncore-frequency/Kconfig new file mode 100644 index 000000000000..21b209124916 --- /dev/null +++ b/drivers/platform/x86/intel/uncore-frequency/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Uncore Frquency control drivers +# + +menu "Intel Uncore Frequency Control" + depends on X86_64 || COMPILE_TEST + +config INTEL_UNCORE_FREQ_CONTROL + tristate "Intel Uncore frequency control driver" + depends on X86_64 + help + This driver allows control of Uncore frequency limits on + supported server platforms. + + Uncore frequency controls RING/LLC (last-level cache) clocks. + + To compile this driver as a module, choose M here: the module + will be called intel-uncore-frequency. + +endmenu diff --git a/drivers/platform/x86/intel/uncore-frequency/Makefile b/drivers= /platform/x86/intel/uncore-frequency/Makefile new file mode 100644 index 000000000000..e22186a480e2 --- /dev/null +++ b/drivers/platform/x86/intel/uncore-frequency/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for linux/drivers/platform/x86/intel/uncore-frequency +# + +obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) +=3D intel-uncore-frequency.o +intel-uncore-frequency-y :=3D uncore-frequency.o diff --git a/drivers/platform/x86/intel/uncore-frequency.c b/drivers/platfo= rm/x86/intel/uncore-frequency/uncore-frequency.c similarity index 100% rename from drivers/platform/x86/intel/uncore-frequency.c rename to drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c --=20 2.31.1 From nobody Mon Jun 29 18:39:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07E8AC433EF for ; Fri, 4 Feb 2022 00:03:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356120AbiBDADf (ORCPT ); Thu, 3 Feb 2022 19:03:35 -0500 Received: from mga01.intel.com ([192.55.52.88]:8519 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356102AbiBDADb (ORCPT ); Thu, 3 Feb 2022 19:03:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1643933011; x=1675469011; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UTYky6/Tq2+UP56UrmX4lZezRVFrc80BK0981MS1BeE=; b=F+YOD5CMCsDJVEKUNJB2pbQefeL/pjIXsNjgG3/2p1rJn/5/PnCg6XV0 mihdJvtPH3HET3VF2F35g196JzpIL4uRiiqmbkI/vtfYPiDXoI6+1fZHQ 9wecfUROd/iNs3tSBGC7/JkcLpQgFQVPOj50C3/Y1xkP4K1bQiIO8iBIP J6GNSgX7hc1Vtk0ZRqtInVggO46PvYXVfvmLZuGM2Uo0WalAhmC0X7eX1 fQswoCT7jOL8UVmQRvoiwseG++jpbioJS48KukFm3r+qUwyNVnweeQcY+ DjkEBmmh6ROo7RqXBJjEkBFuzjzw4Qme51AtpU/2BVQasR/fmXoruwVdu g==; X-IronPort-AV: E=McAfee;i="6200,9189,10247"; a="272779958" X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="272779958" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2022 16:03:31 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="620684674" Received: from spandruv-desk.jf.intel.com ([10.54.75.8]) by FMSMGA003.fm.intel.com with ESMTP; 03 Feb 2022 16:03:30 -0800 From: Srinivas Pandruvada To: hdegoede@redhat.com, markgross@kernel.org Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Srinivas Pandruvada , "Rafael J . Wysocki" Subject: [PATCH 2/4] platform/x86/intel/uncore-freq: Use sysfs API to create attributes Date: Thu, 3 Feb 2022 16:03:04 -0800 Message-Id: <20220204000306.2517447-3-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> References: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Srinivas Pandruvada Use of sysfs API is always preferable over using kobject calls to create attributes. Remove usage of kobject_init_and_add() and use sysfs_create_group(). To create relationship between sysfs attribute and uncore instance use device_attribute*, which is defined per uncore instance. To create uniform locking for both read and write attributes take lock in the sysfs callbacks, not in the actual functions where the MSRs are read or updated. No functional changes are expected. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki --- .../intel/uncore-frequency/uncore-frequency.c | 225 +++++++++--------- 1 file changed, 113 insertions(+), 112 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c= b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c index 4cd8254f2e40..35b00608a81d 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Intel Uncore Frequency Setting - * Copyright (c) 2019, Intel Corporation. + * Copyright (c) 2022, Intel Corporation. * All rights reserved. * * Provide interface to set MSR 620 at a granularity of per die. On CPU on= line, @@ -32,22 +32,37 @@ * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init * @control_cpu: Designated CPU for a die to read/write * @valid: Mark the data valid/invalid + * @package_id: Package id for this instance + * @die_id: Die id for this instance + * @name: Sysfs entry name for this instance + * @uncore_attr_group: Attribute group storage + * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz + * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz + * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_ma= x_freq_khz + * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_mi= n_freq_khz + * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs * settings for a die/package. */ struct uncore_data { - struct kobject kobj; - struct completion kobj_unregister; u64 stored_uncore_data; u32 initial_min_freq_khz; u32 initial_max_freq_khz; int control_cpu; bool valid; + int package_id; + int die_id; + char name[32]; + + struct attribute_group uncore_attr_group; + struct device_attribute max_freq_khz_dev_attr; + struct device_attribute min_freq_khz_dev_attr; + struct device_attribute initial_max_freq_khz_dev_attr; + struct device_attribute initial_min_freq_khz_dev_attr; + struct attribute *uncore_attrs[5]; }; =20 -#define to_uncore_data(a) container_of(a, struct uncore_data, kobj) - /* Max instances for uncore data, one for each die */ static int uncore_max_entries __read_mostly; /* Storage for uncore data for all instances */ @@ -61,36 +76,6 @@ static enum cpuhp_state uncore_hp_state __read_mostly; /* Mutex to control all mutual exclusions */ static DEFINE_MUTEX(uncore_lock); =20 -struct uncore_attr { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, - struct attribute *attr, char *buf); - ssize_t (*store)(struct kobject *kobj, - struct attribute *attr, const char *c, ssize_t count); -}; - -#define define_one_uncore_ro(_name) \ -static struct uncore_attr _name =3D \ -__ATTR(_name, 0444, show_##_name, NULL) - -#define define_one_uncore_rw(_name) \ -static struct uncore_attr _name =3D \ -__ATTR(_name, 0644, show_##_name, store_##_name) - -#define show_uncore_data(member_name) \ - static ssize_t show_##member_name(struct kobject *kobj, \ - struct attribute *attr, \ - char *buf) \ - { \ - struct uncore_data *data =3D to_uncore_data(kobj); \ - return scnprintf(buf, PAGE_SIZE, "%u\n", \ - data->member_name); \ - } \ - define_one_uncore_ro(member_name) - -show_uncore_data(initial_min_freq_khz); -show_uncore_data(initial_max_freq_khz); - /* Common function to read MSR 0x620 and read min/max */ static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, unsigned int *max) @@ -118,22 +103,16 @@ static int uncore_write_ratio(struct uncore_data *dat= a, unsigned int input, int ret; u64 cap; =20 - mutex_lock(&uncore_lock); - - if (data->control_cpu < 0) { - ret =3D -ENXIO; - goto finish_write; - } + if (data->control_cpu < 0) + return -ENXIO; =20 input /=3D UNCORE_FREQ_KHZ_MULTIPLIER; - if (!input || input > 0x7F) { - ret =3D -EINVAL; - goto finish_write; - } + if (!input || input > 0x7F) + return -EINVAL; =20 ret =3D rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); if (ret) - goto finish_write; + return ret; =20 if (set_max) { cap &=3D ~0x7F; @@ -145,37 +124,16 @@ static int uncore_write_ratio(struct uncore_data *dat= a, unsigned int input, =20 ret =3D wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); if (ret) - goto finish_write; + return ret; =20 data->stored_uncore_data =3D cap; =20 -finish_write: - mutex_unlock(&uncore_lock); - - return ret; -} - -static ssize_t store_min_max_freq_khz(struct kobject *kobj, - struct attribute *attr, - const char *buf, ssize_t count, - int min_max) -{ - struct uncore_data *data =3D to_uncore_data(kobj); - unsigned int input; - - if (kstrtouint(buf, 10, &input)) - return -EINVAL; - - uncore_write_ratio(data, input, min_max); - - return count; + return 0; } =20 -static ssize_t show_min_max_freq_khz(struct kobject *kobj, - struct attribute *attr, +static ssize_t show_min_max_freq_khz(struct uncore_data *data, char *buf, int min_max) { - struct uncore_data *data =3D to_uncore_data(kobj); unsigned int min, max; int ret; =20 @@ -191,22 +149,40 @@ static ssize_t show_min_max_freq_khz(struct kobject *= kobj, return sprintf(buf, "%u\n", min); } =20 +static ssize_t store_min_max_freq_khz(struct uncore_data *data, + const char *buf, ssize_t count, + int min_max) +{ + unsigned int input; + + if (kstrtouint(buf, 10, &input)) + return -EINVAL; + + mutex_lock(&uncore_lock); + uncore_write_ratio(data, input, min_max); + mutex_unlock(&uncore_lock); + + return count; +} + #define store_uncore_min_max(name, min_max) \ - static ssize_t store_##name(struct kobject *kobj, \ - struct attribute *attr, \ - const char *buf, ssize_t count) \ - { \ + static ssize_t store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ \ - return store_min_max_freq_khz(kobj, attr, buf, count, \ - min_max); \ + return store_min_max_freq_khz(data, buf, count, \ + min_max); \ } =20 #define show_uncore_min_max(name, min_max) \ - static ssize_t show_##name(struct kobject *kobj, \ - struct attribute *attr, char *buf) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ \ - return show_min_max_freq_khz(kobj, attr, buf, min_max); \ + return show_min_max_freq_khz(data, buf, min_max); \ } =20 store_uncore_min_max(min_freq_khz, 0); @@ -215,30 +191,64 @@ store_uncore_min_max(max_freq_khz, 1); show_uncore_min_max(min_freq_khz, 0); show_uncore_min_max(max_freq_khz, 1); =20 -define_one_uncore_rw(min_freq_khz); -define_one_uncore_rw(max_freq_khz); +#define show_uncore_data(member_name) \ + static ssize_t show_##member_name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data,\ + member_name##_dev_attr);\ + \ + return scnprintf(buf, PAGE_SIZE, "%u\n", \ + data->member_name); \ + } \ =20 -static struct attribute *uncore_attrs[] =3D { - &initial_min_freq_khz.attr, - &initial_max_freq_khz.attr, - &max_freq_khz.attr, - &min_freq_khz.attr, - NULL -}; -ATTRIBUTE_GROUPS(uncore); +show_uncore_data(initial_min_freq_khz); +show_uncore_data(initial_max_freq_khz); =20 -static void uncore_sysfs_entry_release(struct kobject *kobj) +#define init_attribute_rw(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D store_##_name; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0644; \ + } while (0) + +#define init_attribute_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D NULL; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0444; \ + } while (0) + +static int create_attr_group(struct uncore_data *data, char *name) { - struct uncore_data *data =3D to_uncore_data(kobj); + int ret, index =3D 0; + + init_attribute_rw(max_freq_khz); + init_attribute_rw(min_freq_khz); + init_attribute_ro(initial_min_freq_khz); + init_attribute_ro(initial_max_freq_khz); + + data->uncore_attrs[index++] =3D &data->max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->initial_min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index] =3D NULL; + + data->uncore_attr_group.name =3D name; + data->uncore_attr_group.attrs =3D data->uncore_attrs; + ret =3D sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group); =20 - complete(&data->kobj_unregister); + return ret; } =20 -static struct kobj_type uncore_ktype =3D { - .release =3D uncore_sysfs_entry_release, - .sysfs_ops =3D &kobj_sysfs_ops, - .default_groups =3D uncore_groups, -}; +static void delete_attr_group(struct uncore_data *data, char *name) +{ + sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group); +} =20 /* Caller provides protection */ static struct uncore_data *uncore_get_instance(unsigned int cpu) @@ -266,21 +276,17 @@ static void uncore_add_die_entry(int cpu) /* control cpu changed */ data->control_cpu =3D cpu; } else { - char str[64]; int ret; =20 memset(data, 0, sizeof(*data)); - sprintf(str, "package_%02d_die_%02d", + sprintf(data->name, "package_%02d_die_%02d", topology_physical_package_id(cpu), topology_die_id(cpu)); =20 uncore_read_ratio(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz); =20 - init_completion(&data->kobj_unregister); - - ret =3D kobject_init_and_add(&data->kobj, &uncore_ktype, - uncore_root_kobj, str); + ret =3D create_attr_group(data, data->name); if (!ret) { data->control_cpu =3D cpu; data->valid =3D true; @@ -296,8 +302,11 @@ static void uncore_remove_die_entry(int cpu) =20 mutex_lock(&uncore_lock); data =3D uncore_get_instance(cpu); - if (data) + if (data) { + delete_attr_group(data, data->name); data->control_cpu =3D -1; + data->valid =3D false; + } mutex_unlock(&uncore_lock); } =20 @@ -433,16 +442,8 @@ module_init(intel_uncore_init) =20 static void __exit intel_uncore_exit(void) { - int i; - unregister_pm_notifier(&uncore_pm_nb); cpuhp_remove_state(uncore_hp_state); - for (i =3D 0; i < uncore_max_entries; ++i) { - if (uncore_instances[i].valid) { - kobject_put(&uncore_instances[i].kobj); - wait_for_completion(&uncore_instances[i].kobj_unregister); - } - } kobject_put(uncore_root_kobj); kfree(uncore_instances); } --=20 2.31.1 From nobody Mon Jun 29 18:39:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC15DC433EF for ; Fri, 4 Feb 2022 00:03:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356162AbiBDADn (ORCPT ); Thu, 3 Feb 2022 19:03:43 -0500 Received: from mga01.intel.com ([192.55.52.88]:8517 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356104AbiBDADc (ORCPT ); Thu, 3 Feb 2022 19:03:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1643933012; x=1675469012; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VffKzQLRtyVZULvG4LXAW7g/t/tYRyIEC1MPKKJZ+6s=; b=J1LcOjT15T7nfTrEa8vD0bfRJpgFEDmzNYqpEvyu9xmdYclofRhHyzS+ GQhAi+ax+iFanzh649iOYPYGIyWPxOaLtK0pR1UeJmWSYqicqIKF883bx qOtTTGG/7fQNKlJmxB5oxeeHSyUR4/MOVuGUAwPaMBWfiVliwqOxMSFBl aGrVn9vz9TDVYt0O/NOrx4S98uA4Dx9q3lvaDT8YrLBpdOw2j4DdOn+PV fXmln6c7W7PIePXBtsZvXbfLnqAfOxCDnoTI1XOyCDJgMa9Ayr2D8Jqsi UzGELpEivT8e0Tc5d/AeK0/7ZvhS0YxQN4B7PmAanExK181NvJZSgGIvy w==; X-IronPort-AV: E=McAfee;i="6200,9189,10247"; a="272779959" X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="272779959" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2022 16:03:31 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="620684679" Received: from spandruv-desk.jf.intel.com ([10.54.75.8]) by FMSMGA003.fm.intel.com with ESMTP; 03 Feb 2022 16:03:31 -0800 From: Srinivas Pandruvada To: hdegoede@redhat.com, markgross@kernel.org Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Srinivas Pandruvada , "Rafael J . Wysocki" Subject: [PATCH 3/4] platform/x86/intel/uncore-freq: Display uncore current frequency Date: Thu, 3 Feb 2022 16:03:05 -0800 Message-Id: <20220204000306.2517447-4-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> References: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Srinivas Pandruvada Add a new sysfs attribute "current_freq_khz" to display current uncore frequency. This value is read from MSR 0x621. Root user permission is required to read uncore current frequency. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki --- .../intel/uncore-frequency/uncore-frequency.c | 71 ++++++++++++++++--- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c= b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c index 35b00608a81d..f5e980163911 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c @@ -22,6 +22,7 @@ #include =20 #define MSR_UNCORE_RATIO_LIMIT 0x620 +#define MSR_UNCORE_PERF_STATUS 0x621 #define UNCORE_FREQ_KHZ_MULTIPLIER 100000 =20 /** @@ -40,6 +41,7 @@ * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_ma= x_freq_khz * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_mi= n_freq_khz + * @current_freq_khz_dev_attr: Storage for device attribute current_freq_k= hz * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs @@ -60,7 +62,8 @@ struct uncore_data { struct device_attribute min_freq_khz_dev_attr; struct device_attribute initial_max_freq_khz_dev_attr; struct device_attribute initial_min_freq_khz_dev_attr; - struct attribute *uncore_attrs[5]; + struct device_attribute current_freq_khz_dev_attr; + struct attribute *uncore_attrs[6]; }; =20 /* Max instances for uncore data, one for each die */ @@ -131,22 +134,32 @@ static int uncore_write_ratio(struct uncore_data *dat= a, unsigned int input, return 0; } =20 -static ssize_t show_min_max_freq_khz(struct uncore_data *data, - char *buf, int min_max) +static int uncore_read_freq(struct uncore_data *data, unsigned int *freq) { - unsigned int min, max; + u64 ratio; + int ret; + + ret =3D rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_PERF_STATUS, &ratio); + if (ret) + return ret; + + *freq =3D (ratio & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; + + return 0; +} + +static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *b= uf) +{ + unsigned int freq; int ret; =20 mutex_lock(&uncore_lock); - ret =3D uncore_read_ratio(data, &min, &max); + ret =3D uncore_read_freq(data, &freq); mutex_unlock(&uncore_lock); if (ret) return ret; =20 - if (min_max) - return sprintf(buf, "%u\n", max); - - return sprintf(buf, "%u\n", min); + return sprintf(buf, "%u\n", freq); } =20 static ssize_t store_min_max_freq_khz(struct uncore_data *data, @@ -165,6 +178,24 @@ static ssize_t store_min_max_freq_khz(struct uncore_da= ta *data, return count; } =20 +static ssize_t show_min_max_freq_khz(struct uncore_data *data, + char *buf, int min_max) +{ + unsigned int min, max; + int ret; + + mutex_lock(&uncore_lock); + ret =3D uncore_read_ratio(data, &min, &max); + mutex_unlock(&uncore_lock); + if (ret) + return ret; + + if (min_max) + return sprintf(buf, "%u\n", max); + + return sprintf(buf, "%u\n", min); +} + #define store_uncore_min_max(name, min_max) \ static ssize_t store_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -185,12 +216,23 @@ static ssize_t store_min_max_freq_khz(struct uncore_d= ata *data, return show_min_max_freq_khz(data, buf, min_max); \ } =20 +#define show_uncore_perf_status(name) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ + \ + return show_perf_status_freq_khz(data, buf); \ + } + store_uncore_min_max(min_freq_khz, 0); store_uncore_min_max(max_freq_khz, 1); =20 show_uncore_min_max(min_freq_khz, 0); show_uncore_min_max(max_freq_khz, 1); =20 +show_uncore_perf_status(current_freq_khz); + #define show_uncore_data(member_name) \ static ssize_t show_##member_name(struct device *dev, \ struct device_attribute *attr, char *buf)\ @@ -223,6 +265,15 @@ show_uncore_data(initial_max_freq_khz); data->_name##_dev_attr.attr.mode =3D 0444; \ } while (0) =20 +#define init_attribute_root_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D NULL; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0400; \ + } while (0) + static int create_attr_group(struct uncore_data *data, char *name) { int ret, index =3D 0; @@ -231,11 +282,13 @@ static int create_attr_group(struct uncore_data *data= , char *name) init_attribute_rw(min_freq_khz); init_attribute_ro(initial_min_freq_khz); init_attribute_ro(initial_max_freq_khz); + init_attribute_root_ro(current_freq_khz); =20 data->uncore_attrs[index++] =3D &data->max_freq_khz_dev_attr.attr; data->uncore_attrs[index++] =3D &data->min_freq_khz_dev_attr.attr; data->uncore_attrs[index++] =3D &data->initial_min_freq_khz_dev_attr.attr; data->uncore_attrs[index++] =3D &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->current_freq_khz_dev_attr.attr; data->uncore_attrs[index] =3D NULL; =20 data->uncore_attr_group.name =3D name; --=20 2.31.1 From nobody Mon Jun 29 18:39:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E87CAC433F5 for ; Fri, 4 Feb 2022 00:03:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232591AbiBDADi (ORCPT ); Thu, 3 Feb 2022 19:03:38 -0500 Received: from mga01.intel.com ([192.55.52.88]:8519 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356105AbiBDADc (ORCPT ); Thu, 3 Feb 2022 19:03:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1643933012; x=1675469012; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XBJrLAs7KKxYfRcp9oEMbke9UiyzZW2mbdY6Qxvyhi8=; b=NQr8NbvsR1qzP8/yqPQXXCYIRaYh5v4n8oxDgpSQN2ta8wngTP+rnR05 WYCbw1v5v4NFTrG2fVqmy+MXLNcmaq27yehni3NQ09iQ0jktVJNBIgWyB uEXzOwTmMIe/2PZoav04QSp2ZFZQZcd/BcXUpfFqnXdEZYIVUVx2okGL3 yqroFskB+Mwp2xynVlwuaQlCcKsq/zxXmQ/DpXifGI06759cwrU6UkAA3 ESVbOXf3nuY8gj6PGe+IpyEXrASBcup1ELnjN8Y+2Mx4PYUkWzgyKhnFg wIW8tMocwlLymEs1QUriHcurOxyHdF4Ns7qGEjMLcnK9lO6258rGQWwfn Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10247"; a="272779962" X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="272779962" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2022 16:03:31 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,340,1635231600"; d="scan'208";a="620684684" Received: from spandruv-desk.jf.intel.com ([10.54.75.8]) by FMSMGA003.fm.intel.com with ESMTP; 03 Feb 2022 16:03:31 -0800 From: Srinivas Pandruvada To: hdegoede@redhat.com, markgross@kernel.org Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Srinivas Pandruvada , "Rafael J . Wysocki" Subject: [PATCH 4/4] platform/x86/intel-uncore-freq: Split common and enumeration part Date: Thu, 3 Feb 2022 16:03:06 -0800 Message-Id: <20220204000306.2517447-5-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> References: <20220204000306.2517447-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Srinivas Pandruvada Split the current driver in two parts: - Common part: All the commom function other than enumeration function. - Enumeration/HW specific part: The current enumeration using CPU model is left in the old module. This uses service of common driver to register sysfs objects. Also provide callbacks for MSR access related to uncore. - Add MODULE_DEVICE_TABLE to uncore-frequency.c No functional changes are expected. Signed-off-by: Srinivas Pandruvada Acked-by: Rafael J. Wysocki --- .../x86/intel/uncore-frequency/Makefile | 2 + .../uncore-frequency-common.c | 252 +++++++++++++ .../uncore-frequency-common.h | 62 ++++ .../intel/uncore-frequency/uncore-frequency.c | 332 +++--------------- 4 files changed, 365 insertions(+), 283 deletions(-) create mode 100644 drivers/platform/x86/intel/uncore-frequency/uncore-freq= uency-common.c create mode 100644 drivers/platform/x86/intel/uncore-frequency/uncore-freq= uency-common.h diff --git a/drivers/platform/x86/intel/uncore-frequency/Makefile b/drivers= /platform/x86/intel/uncore-frequency/Makefile index e22186a480e2..e0f7968e8285 100644 --- a/drivers/platform/x86/intel/uncore-frequency/Makefile +++ b/drivers/platform/x86/intel/uncore-frequency/Makefile @@ -5,3 +5,5 @@ =20 obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) +=3D intel-uncore-frequency.o intel-uncore-frequency-y :=3D uncore-frequency.o +obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) +=3D intel-uncore-frequency-common= .o +intel-uncore-frequency-common-y :=3D uncore-frequency-common.o diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-c= ommon.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-comm= on.c new file mode 100644 index 000000000000..e4d5a7960234 --- /dev/null +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Uncore Frequency Control: Common code implementation + * Copyright (c) 2022, Intel Corporation. + * All rights reserved. + * + */ +#include +#include +#include "uncore-frequency-common.h" + +/* Mutex to control all mutual exclusions */ +static DEFINE_MUTEX(uncore_lock); +/* Root of the all uncore sysfs kobjs */ +static struct kobject *uncore_root_kobj; +/* uncore instance count */ +static int uncore_instance_count; + +/* callbacks for actual HW read/write */ +static int (*uncore_read)(struct uncore_data *data, unsigned int *min, uns= igned int *max); +static int (*uncore_write)(struct uncore_data *data, unsigned int input, u= nsigned int min_max); +static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *fre= q); + +static ssize_t show_min_max_freq_khz(struct uncore_data *data, + char *buf, int min_max) +{ + unsigned int min, max; + int ret; + + mutex_lock(&uncore_lock); + ret =3D uncore_read(data, &min, &max); + mutex_unlock(&uncore_lock); + if (ret) + return ret; + + if (min_max) + return sprintf(buf, "%u\n", max); + + return sprintf(buf, "%u\n", min); +} + +static ssize_t store_min_max_freq_khz(struct uncore_data *data, + const char *buf, ssize_t count, + int min_max) +{ + unsigned int input; + + if (kstrtouint(buf, 10, &input)) + return -EINVAL; + + mutex_lock(&uncore_lock); + uncore_write(data, input, min_max); + mutex_unlock(&uncore_lock); + + return count; +} + +static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *b= uf) +{ + unsigned int freq; + int ret; + + mutex_lock(&uncore_lock); + ret =3D uncore_read_freq(data, &freq); + mutex_unlock(&uncore_lock); + if (ret) + return ret; + + return sprintf(buf, "%u\n", freq); +} + +#define store_uncore_min_max(name, min_max) \ + static ssize_t store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ + \ + return store_min_max_freq_khz(data, buf, count, \ + min_max); \ + } + +#define show_uncore_min_max(name, min_max) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ + \ + return show_min_max_freq_khz(data, buf, min_max); \ + } + +#define show_uncore_perf_status(name) \ + static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ + \ + return show_perf_status_freq_khz(data, buf); \ + } + +store_uncore_min_max(min_freq_khz, 0); +store_uncore_min_max(max_freq_khz, 1); + +show_uncore_min_max(min_freq_khz, 0); +show_uncore_min_max(max_freq_khz, 1); + +show_uncore_perf_status(current_freq_khz); + +#define show_uncore_data(member_name) \ + static ssize_t show_##member_name(struct device *dev, \ + struct device_attribute *attr, char *buf)\ + { \ + struct uncore_data *data =3D container_of(attr, struct uncore_data,\ + member_name##_dev_attr);\ + \ + return scnprintf(buf, PAGE_SIZE, "%u\n", \ + data->member_name); \ + } \ + +show_uncore_data(initial_min_freq_khz); +show_uncore_data(initial_max_freq_khz); + +#define init_attribute_rw(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D store_##_name; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0644; \ + } while (0) + +#define init_attribute_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D NULL; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0444; \ + } while (0) + +#define init_attribute_root_ro(_name) \ + do { \ + sysfs_attr_init(&data->_name##_dev_attr.attr); \ + data->_name##_dev_attr.show =3D show_##_name; \ + data->_name##_dev_attr.store =3D NULL; \ + data->_name##_dev_attr.attr.name =3D #_name; \ + data->_name##_dev_attr.attr.mode =3D 0400; \ + } while (0) + +static int create_attr_group(struct uncore_data *data, char *name) +{ + int ret, index =3D 0; + + init_attribute_rw(max_freq_khz); + init_attribute_rw(min_freq_khz); + init_attribute_ro(initial_min_freq_khz); + init_attribute_ro(initial_max_freq_khz); + init_attribute_root_ro(current_freq_khz); + + data->uncore_attrs[index++] =3D &data->max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->initial_min_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] =3D &data->current_freq_khz_dev_attr.attr; + data->uncore_attrs[index] =3D NULL; + + data->uncore_attr_group.name =3D name; + data->uncore_attr_group.attrs =3D data->uncore_attrs; + ret =3D sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group); + + return ret; +} + +static void delete_attr_group(struct uncore_data *data, char *name) +{ + sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group); +} + +int uncore_freq_add_entry(struct uncore_data *data, int cpu) +{ + int ret =3D 0; + + mutex_lock(&uncore_lock); + if (data->valid) { + /* control cpu changed */ + data->control_cpu =3D cpu; + goto uncore_unlock; + } + + sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_= id); + + uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_kh= z); + + ret =3D create_attr_group(data, data->name); + if (!ret) { + data->control_cpu =3D cpu; + data->valid =3D true; + } + +uncore_unlock: + mutex_unlock(&uncore_lock); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY); + +void uncore_freq_remove_die_entry(struct uncore_data *data) +{ + mutex_lock(&uncore_lock); + delete_attr_group(data, data->name); + data->control_cpu =3D -1; + data->valid =3D false; + mutex_unlock(&uncore_lock); +} +EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY); + +int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *d= ata, unsigned int *min, unsigned int *max), + int (*write_control_freq)(struct uncore_data *data, unsigned int i= nput, unsigned int set_max), + int (*read_freq)(struct uncore_data *data, unsigned int *freq)) +{ + mutex_lock(&uncore_lock); + + uncore_read =3D read_control_freq; + uncore_write =3D write_control_freq; + uncore_read_freq =3D read_freq; + + if (!uncore_root_kobj) + uncore_root_kobj =3D kobject_create_and_add("intel_uncore_frequency", + &cpu_subsys.dev_root->kobj); + if (uncore_root_kobj) + ++uncore_instance_count; + mutex_unlock(&uncore_lock); + + return (!!uncore_root_kobj); +} +EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY); + +void uncore_freq_common_exit(void) +{ + mutex_lock(&uncore_lock); + --uncore_instance_count; + if (!uncore_instance_count) { + kobject_put(uncore_root_kobj); + uncore_root_kobj =3D NULL; + } + mutex_unlock(&uncore_lock); +} +EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY); + + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Uncore Frequency Common Module"); diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-c= ommon.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-comm= on.h new file mode 100644 index 000000000000..f5dcfa2fb285 --- /dev/null +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Intel Uncore Frequency Control: Common defines and prototypes + * Copyright (c) 2022, Intel Corporation. + * All rights reserved. + * + */ + +#ifndef __INTEL_UNCORE_FREQ_COMMON_H +#define __INTEL_UNCORE_FREQ_COMMON_H + +#include + +/** + * struct uncore_data - Encapsulate all uncore data + * @stored_uncore_data: Last user changed MSR 620 value, which will be res= tored + * on system resume. + * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init + * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init + * @control_cpu: Designated CPU for a die to read/write + * @valid: Mark the data valid/invalid + * @package_id: Package id for this instance + * @die_id: Die id for this instance + * @name: Sysfs entry name for this instance + * @uncore_attr_group: Attribute group storage + * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz + * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz + * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_ma= x_freq_khz + * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_mi= n_freq_khz + * @current_freq_khz_dev_attr: Storage for device attribute current_freq_k= hz + * @uncore_attrs: Attribute storage for group creation + * + * This structure is used to encapsulate all data related to uncore sysfs + * settings for a die/package. + */ +struct uncore_data { + u64 stored_uncore_data; + u32 initial_min_freq_khz; + u32 initial_max_freq_khz; + int control_cpu; + bool valid; + int package_id; + int die_id; + char name[32]; + + struct attribute_group uncore_attr_group; + struct device_attribute max_freq_khz_dev_attr; + struct device_attribute min_freq_khz_dev_attr; + struct device_attribute initial_max_freq_khz_dev_attr; + struct device_attribute initial_min_freq_khz_dev_attr; + struct device_attribute current_freq_khz_dev_attr; + struct attribute *uncore_attrs[6]; +}; + +int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *d= ata, unsigned int *min, unsigned int *max), + int (*write_control_freq)(struct uncore_data *data, unsigned int i= nput, unsigned int min_max), + int (*uncore_read_freq)(struct uncore_data *data, unsigned int *fr= eq)); +void uncore_freq_common_exit(void); +int uncore_freq_add_entry(struct uncore_data *data, int cpu); +void uncore_freq_remove_die_entry(struct uncore_data *data); + +#endif diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c= b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c index f5e980163911..791af0e287e4 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c @@ -21,67 +21,23 @@ #include #include =20 -#define MSR_UNCORE_RATIO_LIMIT 0x620 -#define MSR_UNCORE_PERF_STATUS 0x621 -#define UNCORE_FREQ_KHZ_MULTIPLIER 100000 - -/** - * struct uncore_data - Encapsulate all uncore data - * @stored_uncore_data: Last user changed MSR 620 value, which will be res= tored - * on system resume. - * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init - * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init - * @control_cpu: Designated CPU for a die to read/write - * @valid: Mark the data valid/invalid - * @package_id: Package id for this instance - * @die_id: Die id for this instance - * @name: Sysfs entry name for this instance - * @uncore_attr_group: Attribute group storage - * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz - * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz - * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_ma= x_freq_khz - * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_mi= n_freq_khz - * @current_freq_khz_dev_attr: Storage for device attribute current_freq_k= hz - * @uncore_attrs: Attribute storage for group creation - * - * This structure is used to encapsulate all data related to uncore sysfs - * settings for a die/package. - */ -struct uncore_data { - u64 stored_uncore_data; - u32 initial_min_freq_khz; - u32 initial_max_freq_khz; - int control_cpu; - bool valid; - int package_id; - int die_id; - char name[32]; - - struct attribute_group uncore_attr_group; - struct device_attribute max_freq_khz_dev_attr; - struct device_attribute min_freq_khz_dev_attr; - struct device_attribute initial_max_freq_khz_dev_attr; - struct device_attribute initial_min_freq_khz_dev_attr; - struct device_attribute current_freq_khz_dev_attr; - struct attribute *uncore_attrs[6]; -}; +#include "uncore-frequency-common.h" =20 /* Max instances for uncore data, one for each die */ static int uncore_max_entries __read_mostly; /* Storage for uncore data for all instances */ static struct uncore_data *uncore_instances; -/* Root of the all uncore sysfs kobjs */ -static struct kobject *uncore_root_kobj; /* Stores the CPU mask of the target CPUs to use during uncore read/write = */ static cpumask_t uncore_cpu_mask; /* CPU online callback register instance */ static enum cpuhp_state uncore_hp_state __read_mostly; -/* Mutex to control all mutual exclusions */ -static DEFINE_MUTEX(uncore_lock); =20 -/* Common function to read MSR 0x620 and read min/max */ -static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, - unsigned int *max) +#define MSR_UNCORE_RATIO_LIMIT 0x620 +#define MSR_UNCORE_PERF_STATUS 0x621 +#define UNCORE_FREQ_KHZ_MULTIPLIER 100000 + +static int uncore_read_control_freq(struct uncore_data *data, unsigned int= *min, + unsigned int *max) { u64 cap; int ret; @@ -99,25 +55,24 @@ static int uncore_read_ratio(struct uncore_data *data, = unsigned int *min, return 0; } =20 -/* Common function to set min/max ratios to be used by sysfs callbacks */ -static int uncore_write_ratio(struct uncore_data *data, unsigned int input, - int set_max) +static int uncore_write_control_freq(struct uncore_data *data, unsigned in= t input, + unsigned int min_max) { int ret; u64 cap; =20 - if (data->control_cpu < 0) - return -ENXIO; - input /=3D UNCORE_FREQ_KHZ_MULTIPLIER; if (!input || input > 0x7F) return -EINVAL; =20 + if (data->control_cpu < 0) + return -ENXIO; + ret =3D rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); if (ret) return ret; =20 - if (set_max) { + if (min_max) { cap &=3D ~0x7F; cap |=3D input; } else { @@ -139,6 +94,9 @@ static int uncore_read_freq(struct uncore_data *data, un= signed int *freq) u64 ratio; int ret; =20 + if (data->control_cpu < 0) + return -ENXIO; + ret =3D rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_PERF_STATUS, &ratio); if (ret) return ret; @@ -148,161 +106,6 @@ static int uncore_read_freq(struct uncore_data *data,= unsigned int *freq) return 0; } =20 -static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *b= uf) -{ - unsigned int freq; - int ret; - - mutex_lock(&uncore_lock); - ret =3D uncore_read_freq(data, &freq); - mutex_unlock(&uncore_lock); - if (ret) - return ret; - - return sprintf(buf, "%u\n", freq); -} - -static ssize_t store_min_max_freq_khz(struct uncore_data *data, - const char *buf, ssize_t count, - int min_max) -{ - unsigned int input; - - if (kstrtouint(buf, 10, &input)) - return -EINVAL; - - mutex_lock(&uncore_lock); - uncore_write_ratio(data, input, min_max); - mutex_unlock(&uncore_lock); - - return count; -} - -static ssize_t show_min_max_freq_khz(struct uncore_data *data, - char *buf, int min_max) -{ - unsigned int min, max; - int ret; - - mutex_lock(&uncore_lock); - ret =3D uncore_read_ratio(data, &min, &max); - mutex_unlock(&uncore_lock); - if (ret) - return ret; - - if (min_max) - return sprintf(buf, "%u\n", max); - - return sprintf(buf, "%u\n", min); -} - -#define store_uncore_min_max(name, min_max) \ - static ssize_t store_##name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ - { \ - struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ - \ - return store_min_max_freq_khz(data, buf, count, \ - min_max); \ - } - -#define show_uncore_min_max(name, min_max) \ - static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ - { \ - struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ - \ - return show_min_max_freq_khz(data, buf, min_max); \ - } - -#define show_uncore_perf_status(name) \ - static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ - { \ - struct uncore_data *data =3D container_of(attr, struct uncore_data, name= ##_dev_attr);\ - \ - return show_perf_status_freq_khz(data, buf); \ - } - -store_uncore_min_max(min_freq_khz, 0); -store_uncore_min_max(max_freq_khz, 1); - -show_uncore_min_max(min_freq_khz, 0); -show_uncore_min_max(max_freq_khz, 1); - -show_uncore_perf_status(current_freq_khz); - -#define show_uncore_data(member_name) \ - static ssize_t show_##member_name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ - { \ - struct uncore_data *data =3D container_of(attr, struct uncore_data,\ - member_name##_dev_attr);\ - \ - return scnprintf(buf, PAGE_SIZE, "%u\n", \ - data->member_name); \ - } \ - -show_uncore_data(initial_min_freq_khz); -show_uncore_data(initial_max_freq_khz); - -#define init_attribute_rw(_name) \ - do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show =3D show_##_name; \ - data->_name##_dev_attr.store =3D store_##_name; \ - data->_name##_dev_attr.attr.name =3D #_name; \ - data->_name##_dev_attr.attr.mode =3D 0644; \ - } while (0) - -#define init_attribute_ro(_name) \ - do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show =3D show_##_name; \ - data->_name##_dev_attr.store =3D NULL; \ - data->_name##_dev_attr.attr.name =3D #_name; \ - data->_name##_dev_attr.attr.mode =3D 0444; \ - } while (0) - -#define init_attribute_root_ro(_name) \ - do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show =3D show_##_name; \ - data->_name##_dev_attr.store =3D NULL; \ - data->_name##_dev_attr.attr.name =3D #_name; \ - data->_name##_dev_attr.attr.mode =3D 0400; \ - } while (0) - -static int create_attr_group(struct uncore_data *data, char *name) -{ - int ret, index =3D 0; - - init_attribute_rw(max_freq_khz); - init_attribute_rw(min_freq_khz); - init_attribute_ro(initial_min_freq_khz); - init_attribute_ro(initial_max_freq_khz); - init_attribute_root_ro(current_freq_khz); - - data->uncore_attrs[index++] =3D &data->max_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] =3D &data->min_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] =3D &data->initial_min_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] =3D &data->initial_max_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] =3D &data->current_freq_khz_dev_attr.attr; - data->uncore_attrs[index] =3D NULL; - - data->uncore_attr_group.name =3D name; - data->uncore_attr_group.attrs =3D data->uncore_attrs; - ret =3D sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group); - - return ret; -} - -static void delete_attr_group(struct uncore_data *data, char *name) -{ - sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group); -} - /* Caller provides protection */ static struct uncore_data *uncore_get_instance(unsigned int cpu) { @@ -314,57 +117,9 @@ static struct uncore_data *uncore_get_instance(unsigne= d int cpu) return NULL; } =20 -static void uncore_add_die_entry(int cpu) -{ - struct uncore_data *data; - - mutex_lock(&uncore_lock); - data =3D uncore_get_instance(cpu); - if (!data) { - mutex_unlock(&uncore_lock); - return; - } - - if (data->valid) { - /* control cpu changed */ - data->control_cpu =3D cpu; - } else { - int ret; - - memset(data, 0, sizeof(*data)); - sprintf(data->name, "package_%02d_die_%02d", - topology_physical_package_id(cpu), - topology_die_id(cpu)); - - uncore_read_ratio(data, &data->initial_min_freq_khz, - &data->initial_max_freq_khz); - - ret =3D create_attr_group(data, data->name); - if (!ret) { - data->control_cpu =3D cpu; - data->valid =3D true; - } - } - mutex_unlock(&uncore_lock); -} - -/* Last CPU in this die is offline, make control cpu invalid */ -static void uncore_remove_die_entry(int cpu) -{ - struct uncore_data *data; - - mutex_lock(&uncore_lock); - data =3D uncore_get_instance(cpu); - if (data) { - delete_attr_group(data, data->name); - data->control_cpu =3D -1; - data->valid =3D false; - } - mutex_unlock(&uncore_lock); -} - static int uncore_event_cpu_online(unsigned int cpu) { + struct uncore_data *data; int target; =20 /* Check if there is an online cpu in the package for uncore MSR */ @@ -374,15 +129,26 @@ static int uncore_event_cpu_online(unsigned int cpu) =20 /* Use this CPU on this die as a control CPU */ cpumask_set_cpu(cpu, &uncore_cpu_mask); - uncore_add_die_entry(cpu); =20 - return 0; + data =3D uncore_get_instance(cpu); + if (!data) + return 0; + + data->package_id =3D topology_physical_package_id(cpu); + data->die_id =3D topology_die_id(cpu); + + return uncore_freq_add_entry(data, cpu); } =20 static int uncore_event_cpu_offline(unsigned int cpu) { + struct uncore_data *data; int target; =20 + data =3D uncore_get_instance(cpu); + if (!data) + return 0; + /* Check if existing cpu is used for uncore MSRs */ if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) return 0; @@ -392,9 +158,9 @@ static int uncore_event_cpu_offline(unsigned int cpu) =20 if (target < nr_cpu_ids) { cpumask_set_cpu(target, &uncore_cpu_mask); - uncore_add_die_entry(target); + uncore_freq_add_entry(data, target); } else { - uncore_remove_die_entry(cpu); + uncore_freq_remove_die_entry(data); } =20 return 0; @@ -403,24 +169,20 @@ static int uncore_event_cpu_offline(unsigned int cpu) static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode, void *_unused) { - int cpu; + int i; =20 switch (mode) { case PM_POST_HIBERNATION: case PM_POST_RESTORE: case PM_POST_SUSPEND: - for_each_cpu(cpu, &uncore_cpu_mask) { - struct uncore_data *data; - int ret; + for (i =3D 0; i < uncore_max_entries; ++i) { + struct uncore_data *data =3D &uncore_instances[i]; =20 - data =3D uncore_get_instance(cpu); if (!data || !data->valid || !data->stored_uncore_data) - continue; + return 0; =20 - ret =3D wrmsrl_on_cpu(cpu, MSR_UNCORE_RATIO_LIMIT, - data->stored_uncore_data); - if (ret) - return ret; + wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, + data->stored_uncore_data); } break; default: @@ -443,6 +205,7 @@ static const struct x86_cpu_id intel_uncore_cpu_ids[] = =3D { X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), {} }; +MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids); =20 static int __init intel_uncore_init(void) { @@ -460,12 +223,10 @@ static int __init intel_uncore_init(void) if (!uncore_instances) return -ENOMEM; =20 - uncore_root_kobj =3D kobject_create_and_add("intel_uncore_frequency", - &cpu_subsys.dev_root->kobj); - if (!uncore_root_kobj) { - ret =3D -ENOMEM; + ret =3D uncore_freq_common_init(uncore_read_control_freq, uncore_write_co= ntrol_freq, + uncore_read_freq); + if (!ret) goto err_free; - } =20 ret =3D cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "platform/x86/uncore-freq:online", @@ -485,7 +246,7 @@ static int __init intel_uncore_init(void) err_rem_state: cpuhp_remove_state(uncore_hp_state); err_rem_kobj: - kobject_put(uncore_root_kobj); + uncore_freq_common_exit(); err_free: kfree(uncore_instances); =20 @@ -495,12 +256,17 @@ module_init(intel_uncore_init) =20 static void __exit intel_uncore_exit(void) { + int i; + unregister_pm_notifier(&uncore_pm_nb); cpuhp_remove_state(uncore_hp_state); - kobject_put(uncore_root_kobj); + for (i =3D 0; i < uncore_max_entries; ++i) + uncore_freq_remove_die_entry(&uncore_instances[i]); + uncore_freq_common_exit(); kfree(uncore_instances); } module_exit(intel_uncore_exit) =20 +MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver"); --=20 2.31.1