From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754765AbcC1Fcm (ORCPT ); Mon, 28 Mar 2016 01:32:42 -0400 Received: from mail-bl2on0067.outbound.protection.outlook.com ([65.55.169.67]:35836 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754628AbcC1FcC convert rfc822-to-8bit (ORCPT ); Mon, 28 Mar 2016 01:32:02 -0400 Authentication-Results: spf=none (sender IP is 165.204.84.222) smtp.mailfrom=amd.com; alien8.de; dkim=none (message not signed) header.d=none;alien8.de; dmarc=permerror action=none header.from=amd.com; X-WSS-ID: 0O4QI16-08-Y0A-02 X-M-MSG: From: Huang Rui To: Guenter Roeck , Jean Delvare CC: , , , Borislav Petkov , Huang Rui Subject: [PATCH v5 4/6] hwmon: (fam15h_power) Introduce a cpu accumulated power reporting algorithm Date: Mon, 28 Mar 2016 13:32:14 +0800 Message-ID: <1459143136-2412-5-git-send-email-ray.huang@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1459143136-2412-1-git-send-email-ray.huang@amd.com> References: <1459143136-2412-1-git-send-email-ray.huang@amd.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8BIT X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:165.204.84.222;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(428002)(189002)(199003)(2906002)(87936001)(1096002)(92566002)(1220700001)(189998001)(5008740100001)(86362001)(36756003)(586003)(53416004)(4326007)(23676002)(5003600100002)(33646002)(76176999)(11100500001)(81166005)(101416001)(47776003)(77096005)(50986999)(50466002)(19580405001)(19580395003)(50226001)(5001770100001)(105586002)(106466001)(5820100001)(229853001)(2950100001);DIR:OUT;SFP:1101;SCL:1;SRVR:BLUPR12MB0708;H:atltwp02.amd.com;FPR:;SPF:None;MLV:sfv;MX:1;A:1;LANG:en; X-MS-Office365-Filtering-Correlation-Id: 56e1139b-627f-4646-9401-08d356ca482f X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0708;2:D8ilHgyq1lQ1fDHl8HPR2IB1x3WsxIj3Ubd2UOtdEQ2fhJ848WbMc8LV02xll45GE16GgBXQGfCoKeVYIgBylReSOuTiOvxaL5YYuGi9WkJmDuXC4FuYuGiVgcY1A1Y0lpNJRWpQYjoHqdSa8yDC5cWGUz3tky0fWlSRp1nFepQTcT9uztnTYkJT843DHLkx;3:w9f6Jb0xBz5CX6oAK7iYBFvfLDbTZakUBU08JQKWR2AE90KALn676TW6Wf/2BHCo1SqaMoDXYB0ywdNcwG2Ta6lCHTdJbpOseNo0xi/rfeDvZaa5+SOhw7HrxjjZvKissumgwiyvnB27elSZnNMLCfcOLeFjUTbR58M0KXedtVnIp3wkE9rzjVGt2PJ9A546DiVgNUVMqyf7d8x/os06aKIDU5R4Xa5nN0EjAxWd27o= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0708; X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0708;25:nWmMwVWRqgh2MXsXAm/hJglNLP+w3iCv28q2hIewZNbbvsEF5qbLbDJBF668Lrk25wSZS1jOo73A0VLLulnYIC+BXk/pZx8d+0I+/EBHMq3TIB63e/++AaQ4MvJVDswAWOyjbF4tewjKRYg4NzIFFRFMJlLU2lB5uPMRrS2ciYqPhb0rpY9PduyJ/lTclKzS1Zqlw71zmLVQf7sKN3miFSdyNgZyIcSj9tDOYx4yjCFfBfQ1mTkahlRWnKwk4/1HjLuQijFZjqCXWIyWU+4daFaI1OPkvOxp7hGQpLeSiio7SkYPvDltJ7fFyyMGiicUZ+AFUJ1fKH0/cggCC8coZ3reIHTnjGRwaxPegQNBl4qJducbKHp06TPk9EuBusZOBZp4AHpszOCqvADZCgYdmE317TX+lkdZ8qotp4pYkpX7OIZ/ytB27UysgxztEFG3Pqe3Dp76gwwKW1bicPyCAePaL5pUh6aTGg3/wq6at9+Yhz1UOldsO0F54MY9C5nZ27oS5K7zbiO3r/zkN3LFkiXxSmZHepEkiLLMYgePgG7End7iORyRbYtaIENcJlnNvPgnZl9bCo1/WNdHgJUx6Q== X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0708;20:2EamCrZn5uABZt2DkptEpmwZgh6U1v4BkByGOt1aE+Gs1N4aL2SKdAszBqrKQgaV0f9RbkE0lyavfjOMhRhdFyXk2rhH0kXWzNmLtL6disBuJ7eVVn9b+ih9MPiD/s1mJezh4rlwv6WSnfHbifCdOy+L7nBcq63P9q1xBl+09ASLh3Fndkdftx6FcnUyQvEBWVkMaXel/l+pMbKo2WuxvlO0Rrxsj24hD2RdY6Wf+6r2v485avjNVRK1PIdeqjbDYqoMVuor2fo2P5eeeprtIyC2/jxRijrOHR/ncNE8fIH4R+mberkwSu0dKCKh38blEpjg2iGqen9Q/GGu/Z5vXxIBjrRUE4chs3f0X3870mkti1Gni4ti9zfTHOgoF88Ow8S5HhhGwFZrdkwKfXrMFiY8qI0kxV/bIbRvGlomCX2qbQ/JU4nyz+XVX+IBelt11EajaREVlWrS8m7sHC5vGNuw73oLDev4zNyjKMpwOyETYJTZOtYSe1H9VE4u4DyB X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(13015025)(5005006)(13018025)(13023025)(8121501046)(13017025)(13024025)(10201501046)(3002001);SRVR:BLUPR12MB0708;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0708; X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0708;4:0DJ5dIRvfDSc8XjNVAuaViZUnbNLWaC4vM1JSOD/fQO2o9KFVBFg0whWmbFQI/fQF+KHyBZhJmvziQU7H8Nkla6seVnAj47xZJaSrAqoFxQYGZTAz83/8qPIL7W8Blan7NJTyjwX8RorfRm8ExhTIlPb3igSW+irJP/qvKdKjD62ekqjpowT1PfZtyiZCMlSs7+HwkpqiIG0yGMtd0EILOn4w9PKRtqCE0hjgJwjpuiCcVPch0Xv/GpiLndLWe8U8hZhxhE/Q5ofnuU8xEBzDKA/HNRyHWAxksBjJVxVrbd8vbwmaj+AHh+sy++lNN82qKWYB27OUk7J6dwi+hA9nA61gEBHXuFA4Z++jHe3Ghj3esaqmkG4u48kIXwGmZzUCh4yCU9cpZHjBh7e7a+maWRBI7GquaywGPvHC2g8Nbu1QO1GNqI39CCPzXwMiZNSshPBJj84he1mfECdqDZxjQ== X-Forefront-PRVS: 0895DF8FFD X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtCTFVQUjEyTUIwNzA4OzIzOk9BZnJqNERsK3hiSC9VcGgxd3pPZzFINVRl?= =?utf-8?B?ajlHTEhUNEo5NW45M25JYkJlcnFEUUV4eVl0SjhoUDRUdnhYb25YQ3Nvd2lF?= =?utf-8?B?aVFPc1ZseWs2Q2pHcHo5VHM2MmRwejRZMXV5c2FpSkt0L2VPQTgrY1ZrM1Za?= =?utf-8?B?dnk5ci91cXh3MndETGFYOEdWRGZObU1WQ2p2NS90T0VQcEczeEMzOFhWMDla?= =?utf-8?B?dXhUMklaWlRDdHlYYWlIZUdCekxFdzU4VnFVTHFHUlZ6VkVsdlJQMWZ6RlZt?= =?utf-8?B?WWorbitiU2ppclVvekY1ZVlKWXNOVUtNVGZVcVlWWnJLc2JDODZrYVliTE1s?= =?utf-8?B?ekpTSzVhRkVuOXVRZlExZXZURFRmSlFUODFlVnFlZXQ1N21vcWc3UzhXblI5?= =?utf-8?B?VVFYRjBXZUVuV2lvNXRMTmRhQ3RYYkNHSEdLemtESDEwL3hzQ0p4ZmZ4N3RD?= =?utf-8?B?NnFudGdGS3R4SlZwbnE3TGZHNzNna2VUUmlqR0FPWlU0OW84QVBYZGM5anNh?= =?utf-8?B?NmpsVFNZalM1bUJTSzVOTkNBKy9GdnJHaDRPTHVJMHkrVDJ6ZXJkM3dxMzF4?= =?utf-8?B?UWtXc0tWbHM1c01qREtKN09oOFFZY1pBME0yNVY2WkVPaHNjOU56bkNrZWox?= =?utf-8?B?c0F2Sm9SS0xrQlVyYTRsR3F3aFRIRDdUbnFGZDZCd2s4KzhoK0VrV2tLdG9Y?= =?utf-8?B?ZGJ1dUYvQWxoVzR3cTVJKzM4elJVR2xLRUpCOXErTVRKUlQ2QTZROTNHU2lQ?= =?utf-8?B?NExCNkRVNUh4YXIwaE5EZ1ZROE5WVVlIUUhrSk5tWG1mY2pqRmQrZnh3N3VI?= =?utf-8?B?OTYrNTFEdU1nNzdscmpSV1BuL0VkSUVPU1QrbEhYMUFrMHNXZHRrTnZTZWtG?= =?utf-8?B?VU1aSUplZzRLTGhFcnZBWlp0UFVMS0FySjVhR2RITFE4NEJjUmxTWHhXVEpP?= =?utf-8?B?RHpFQVc4cDRMYWVuM3g5Q1lPbUkrU1RrenhWeG8zdDVaaTd1T0YzQnFrOVUw?= =?utf-8?B?ZFJ5Uk1sTmsxNkNQNmxmcm9BeHc5VTkzYVUzWGI1bHFLRzlEanFWM3ZjTTNz?= =?utf-8?B?UjNZeUExd1d0Tm9mb0Ewbi9SNVhaYW1ZbVdWYWgxTGdEUWsvOGFWZG4zM3hE?= =?utf-8?B?dzk1SUFwL3dmM08zSW83N1paQStuc1ArUzgrQkpHUnN3a3JQTTNjM2Zzd3lq?= =?utf-8?B?VWdoU2hLVzlDalNvNXkxalVCemVWV3JTZnBoa3ZRL3N6QkdnRWp4V0RBZ0Ni?= =?utf-8?B?ckRVcUk5Zkk4QWF2eitDZ1M4S0dLcXBIeWRsTkM4aHlUaWYxaEh4MVRYQU83?= =?utf-8?Q?uImVp92ahOAf2UBnEW485M5vUq/O1d/4=3D?= X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0708;5:jyz9O/dV2XlsuHz0uuS49zeSeCVbQt1b/9tG6+Zyp9bezxKGkZ+Fwk+hv1qXpPuAV1QQISu3DGi/wT7Jnz9WqiEn6W1hbLx7vaoukHkIaGadq6DWFaKEq3ljBFVSuJAvSmgxZzmXg1Deb09B8S1x1A==;24:ihcspDjsHVUzdWHZ+F6g6EdhY5uauyNBKDzVLgSswsCRGaA3122NH4gWLXRB5rpcaScjY9o7Qz19O46gPXLMFr9dgkMp3EN8Besx2gIlkR4=;20:qOsVCOb8tLn9D9J41AXgPiz5f7FEShftVG8t4nnwusTv40WitW/6rgHfVH9UDYt7ziWZqCPqg/fpAUD/rJRz2rjhCVICr1AMGqllWsReBgBKbRVTeTHfxawqnVvTUUizEYYIUseQmVrii9DdjvbR4K3aHl2VoUJ+K/QIAJXXQIVfSuY9dpcPaBzgQrIZlFFzc/a1HHOTxccxtkaLfxwykUz8Sroap1Cq2Sziq6Qu0AYmJaOrL/gDJ7rUaHYKhR09 SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Mar 2016 05:31:57.7113 (UTC) X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.222];Helo=[atltwp02.amd.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BLUPR12MB0708 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch introduces an algorithm that computes the average power by reading a delta value of “core power accumulator” register during measurement interval, and then dividing delta value by the length of the time interval. User is able to use power1_average entry to measure the processor power consumption and power1_average_interval entry to set the interval. A simple example: ray@hr-ub:~/tip$ sensors fam15h_power-pci-00c4 Adapter: PCI adapter power1: 19.58 mW (avg = 2.55 mW, interval = 0.01 s) (crit = 15.00 W) ... The result is current average processor power consumption in 10 millisecond. The unit of the result is uWatt. Suggested-by: Guenter Roeck Signed-off-by: Huang Rui Cc: Borislav Petkov --- drivers/hwmon/fam15h_power.c | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index de6f52b..003564b 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -48,6 +50,9 @@ MODULE_LICENSE("GPL"); #define FAM15H_NUM_GROUPS 2 #define MAX_CUS 8 +/* set maximum interval as 1 second */ +#define MAX_INTERVAL 1000 + #define MSR_F15H_CU_PWR_ACCUMULATOR 0xc001007a #define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b #define MSR_F15H_PTSC 0xc0010280 @@ -68,6 +73,9 @@ struct fam15h_power_data { u64 cu_acc_power[MAX_CUS]; /* performance timestamp counter */ u64 cpu_sw_pwr_ptsc[MAX_CUS]; + /* online/offline status of current compute unit */ + int cu_on[MAX_CUS]; + unsigned long power_period; }; static ssize_t show_power(struct device *dev, @@ -149,6 +157,8 @@ static void do_read_registers_on_cu(void *_data) rdmsrl_safe(MSR_F15H_CU_PWR_ACCUMULATOR, &data->cu_acc_power[cu]); rdmsrl_safe(MSR_F15H_PTSC, &data->cpu_sw_pwr_ptsc[cu]); + + data->cu_on[cu] = 1; } /* @@ -165,6 +175,8 @@ static int read_registers(struct fam15h_power_data *data) if (!ret) return -ENOMEM; + memset(data->cu_on, 0, sizeof(int) * MAX_CUS); + get_online_cpus(); this_cpu = get_cpu(); @@ -192,18 +204,117 @@ static int read_registers(struct fam15h_power_data *data) return 0; } +static ssize_t acc_show_power(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + u64 prev_cu_acc_power[MAX_CUS], prev_ptsc[MAX_CUS], + jdelta[MAX_CUS]; + u64 tdelta, avg_acc; + int cu, cu_num, ret; + signed long leftover; + + /* + * With the new x86 topology modelling, x86_max_cores is the + * compute unit number. + */ + cu_num = boot_cpu_data.x86_max_cores; + + ret = read_registers(data); + if (ret) + return 0; + + for (cu = 0; cu < cu_num; cu++) { + prev_cu_acc_power[cu] = data->cu_acc_power[cu]; + prev_ptsc[cu] = data->cpu_sw_pwr_ptsc[cu]; + } + + leftover = schedule_timeout_interruptible(msecs_to_jiffies(data->power_period)); + if (leftover) + return 0; + + ret = read_registers(data); + if (ret) + return 0; + + for (cu = 0, avg_acc = 0; cu < cu_num; cu++) { + /* check if current compute unit is online */ + if (data->cu_on[cu] == 0) + continue; + + if (data->cu_acc_power[cu] < prev_cu_acc_power[cu]) { + jdelta[cu] = data->max_cu_acc_power + data->cu_acc_power[cu]; + jdelta[cu] -= prev_cu_acc_power[cu]; + } else { + jdelta[cu] = data->cu_acc_power[cu] - prev_cu_acc_power[cu]; + } + tdelta = data->cpu_sw_pwr_ptsc[cu] - prev_ptsc[cu]; + jdelta[cu] *= data->cpu_pwr_sample_ratio * 1000; + do_div(jdelta[cu], tdelta); + + /* the unit is microWatt */ + avg_acc += jdelta[cu]; + } + + return sprintf(buf, "%llu\n", (unsigned long long)avg_acc); +} +static DEVICE_ATTR(power1_average, S_IRUGO, acc_show_power, NULL); + +static ssize_t acc_show_power_period(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lu\n", data->power_period); +} + +static ssize_t acc_set_power_period(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + unsigned long temp; + int ret; + + ret = kstrtoul(buf, 10, &temp); + if (ret) + return ret; + + if (temp > MAX_INTERVAL) + return -EINVAL; + + /* the interval value should be greater than 0 */ + if (temp <= 0) + return -EINVAL; + + data->power_period = temp; + + return count; +} +static DEVICE_ATTR(power1_average_interval, S_IRUGO | S_IWUSR, + acc_show_power_period, acc_set_power_period); + static int fam15h_power_init_attrs(struct pci_dev *pdev, struct fam15h_power_data *data) { int n = FAM15H_MIN_NUM_ATTRS; struct attribute **fam15h_power_attrs; struct cpuinfo_x86 *c = &boot_cpu_data; + u32 cpuid; if (c->x86 == 0x15 && (c->x86_model <= 0xf || (c->x86_model >= 0x60 && c->x86_model <= 0x7f))) n += 1; + cpuid = cpuid_edx(0x80000007); + + /* check if processor supports accumulated power */ + if (cpuid & BIT(12)) + n += 2; + fam15h_power_attrs = devm_kcalloc(&pdev->dev, n, sizeof(*fam15h_power_attrs), GFP_KERNEL); @@ -218,6 +329,11 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev, (c->x86_model >= 0x60 && c->x86_model <= 0x7f))) fam15h_power_attrs[n++] = &dev_attr_power1_input.attr; + if (cpuid & BIT(12)) { + fam15h_power_attrs[n++] = &dev_attr_power1_average.attr; + fam15h_power_attrs[n++] = &dev_attr_power1_average_interval.attr; + } + data->group.attrs = fam15h_power_attrs; return 0; @@ -330,6 +446,9 @@ static int fam15h_power_init_data(struct pci_dev *f4, data->max_cu_acc_power = tmp; + /* set default interval as 10 ms */ + data->power_period = 10; + return read_registers(data); } -- 1.9.1