From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752439AbbJTCrE (ORCPT ); Mon, 19 Oct 2015 22:47:04 -0400 Received: from mail-bn1bon0054.outbound.protection.outlook.com ([157.56.111.54]:42496 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752404AbbJTCq7 convert rfc822-to-8bit (ORCPT ); Mon, 19 Oct 2015 22:46:59 -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: 0NWHYZS-08-8W6-02 X-M-MSG: From: Huang Rui To: Borislav Petkov , Guenter Roeck , "Peter Zijlstra" , Jean Delvare , "Andy Lutomirski" , Andreas Herrmann , Thomas Gleixner , "Ingo Molnar" , "Rafael J. Wysocki" , "Len Brown" , John Stultz , =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Weisbecker?= CC: , , , Andreas Herrmann , Aravind Gopalakrishnan , Borislav Petkov , Fengguang Wu , Aaron Lu , Tony Li , Huang Rui Subject: [PATCH v2 07/10] hwmon: (fam15h_power) Introduce a cpu accumulated power reporting algorithm Date: Tue, 20 Oct 2015 10:28:26 +0800 Message-ID: <1445308109-17970-8-git-send-email-ray.huang@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1445308109-17970-1-git-send-email-ray.huang@amd.com> References: <1445308109-17970-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;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(428002)(189002)(199003)(5007970100001)(23676002)(97736004)(229853001)(87936001)(5001770100001)(50226001)(105586002)(86362001)(5820100001)(101416001)(76176999)(50986999)(5003600100002)(50466002)(53416004)(5008740100001)(33646002)(47776003)(64706001)(77096005)(92566002)(2950100001)(46102003)(36756003)(106466001)(19580395003)(19580405001)(189998001)(921003)(1121003);DIR:OUT;SFP:1101;SCL:1;SRVR:CY1PR12MB0714;H:atltwp02.amd.com;FPR:;SPF:None;PTR:InfoDomainNonexistent;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0714;2:zHO/OoMwlam6/iJfQPQt5iIfli3L8LhNHpg3vTYWSSxnM5LFKaKwV5Ni5M+5RXuAfp0YKy47Ya0KkFWn46oIS8MWKiTjPc/1wO9/6JH/DbvHuvV/+m1R2h6YCA4UyoxZzr80sDqC7WZLZ+s5zW8aCMIm4dKCUVxANtChOlIqBxY=;3:AbzCDg+6Zh8NEEOr/F5pJzw++hTmaWXwfYET+ln/3wXYFEAGl1yb4FubJA5fWIsw88cacNoCJKiwwRxUqFeyPy6Z6H8QVrZa+OlgEeyQAKFdaBYAjkWN4HxMKIaN6kFgqIwP2i55QSL+2RxSb2jCkisMX2T4fxnR+kNZ3buAWDm45hUrac+1L56BeB8GaSgJJLhaWIhos365rv7Kc7sVi2NUo00wn/wDKZp+0rczR1DpBUTTF35HHmlk8Bj8d6ku;25:PaEDgzYvbmRs2Qnxlhu4KnhrPDBJrhVL9UQcM5yJCxxZsMnbCJEW2iz/hDldCvET5/+j1sPpTVt975aaivYJPdah9mP5KkCFIedOnJPGn/ggkab72CSkzeHR+EZ+F7T5QqKjtTHZegCE94kO983WYSo5+5AV8TV8MAynOekjvYuhCNdY4WT3/xU9hwui68Alt0mQCLUhR/xJyK6BMaSRFl+F5/lwPG7xCTGWAeGqaXXOsX1noHZvyRKiYcllu69z6F0BSD8nGo1KL2+GJaNOPA== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR12MB0714; X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0714;20:jsjrhB1VwCFXwKXTcWfjGBPOZiBEFVh/nA17f6HYP5SiY1E4lUl3RB4NKb7ONJ5Nx9vgH+DFxmUxmVQx2PgFHo4cMf0v7ogCWvHBqMICQa8cEiFa5sWFqOwSbgH/rIK6EwDj//x1ATuPriBkvarmokbt0/BwmJUwzIx8J13XY9UooQ162HAFPYPZ1LNhdsiZ1kHbh2uzrER3WNtt624ki/MuxVcBnUqrVQPFGQ8k2BIkn8wjpCZVgZQnGqKlqbzc0HwcmO/UKvU+jSZwpalWFVCEOgE8+634zGxjT3R45cHDR4XM/0eUXwovuVh83Yt3N+YQ/39wI/ZXgH8+OM9QTRkzDu+nVkB4YwICPrTZfnxo8AxWBtpjqJQP4ApdxdTPqlkfZX3Q7PFxY07/CjOV5pkVynP6EHOadu231/CM1oY0z84EV7lpuYQW+kDH8RUxouhLrCQ+9wKe1GJvn7XB4XV9Faf5w81luNVolYKc4L3g1zgsQiXNe+m2wAJrRt8v;4:claeEarZPqPMEofcLKQKBwpCPzw4Flc17hWrfIvW7sRK1MOJi4/28WtvZtOZZrdGDwxoBKDuaepDfJa47ctf8rxSDy7jdMD2DpySqWbj3bOY3+iVV7bpI1ZP/H3EzP+qVfJ6g7RUqRPPBk9CzCs8uxNjD55242mJAu76aoDZulDJnn7gEle8AKwrBN8szqrkuIxsxtbjXiFppXLSNjT5P6YeBAy/Ej9arHSguOeg03KDUMd4tRf+7IegL6TJWOfms44fJRMZYBwCYQhE86SpggF+ETgpQzjxGK9qn0V4Y3cRqxL8DQGKv204bpR9NcfGBpRULyV6ypjH+Vd+gm8UhnpnwlceZ/LwoFXgPvcnUKk= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(5005006)(520078)(8121501046)(3002001);SRVR:CY1PR12MB0714;BCL:0;PCL:0;RULEID:;SRVR:CY1PR12MB0714; X-Forefront-PRVS: 073515755F X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtDWTFQUjEyTUIwNzE0OzIzOkcvTDFVazNRQU9Zc2tqNjBTZ05DNEF6T1pF?= =?utf-8?B?ZWNYYXdDaTMzSzFickM2RU5kLzBxeEJlSG0vaE00d0ZKK1FheHJsL2N2V0NV?= =?utf-8?B?c3IxYXBKbGt6eW5leTZudExoUlBZQmNhQUU1OEJNWXV1ZFIwd0h1T004bzVj?= =?utf-8?B?YUs1QUczb0huVVp3VUo3ckttL0VTaUVYWW1sdHp5YW9OOFJRd0VBSklJdGJB?= =?utf-8?B?c254QU9YS3FoUUoxTW1pZ1F0VWk5TFpBVE1DZ3pVQzkxYUw4WXphNTRzTElF?= =?utf-8?B?VDEzSEQ1TE11L1ZWU2EvWHRUVjVDRnY4WmYrdHZ2VnBVdkRoQUNuTThKWFI3?= =?utf-8?B?eFpPaHFnRkJpYVdUR1VGQ21GeU5CR2xLUXJ1aGg3YVZiRVh0R1VsZWF6eEt5?= =?utf-8?B?MmdNODBocW4xaXF1SXRqMWwzb3ZjeDM0NEd3ZUpkVy9aYXVlZm9jcUN1SlJ2?= =?utf-8?B?Kzk3Sk5qdWdYVERpOXhwSFpENW5CdXJXbnZUbFY3aXhGZHk0bEZGRjAyL0NF?= =?utf-8?B?SmNSNWM3V2wxU1I2NnVWS2ZWU00wRmtrTWsycWdYWnErUUhaa0R2TGtwSFlC?= =?utf-8?B?aUZGWlBldFV6L281YTFJQk1GeUloSU9pazcwWkhkR2FQWkFFaXZqRTU5RFlj?= =?utf-8?B?TVlkNFpDRUtNbDdPeitLOFdOdUNFVzQzeUFZdjhLSzVJdnc4YStBNGVtbURJ?= =?utf-8?B?UHFKMC8wWWMvTTNBNHVxRjdhSyt1N0hGM1JURmp5dGlRV2YweFFSZ2FYRWk4?= =?utf-8?B?Y29adkNhNFVyMTd4RUFKVnNVRWIxakliVElhOVcxYzlEd29BYjBuVG9UbUpK?= =?utf-8?B?cTVjdEg5RnhMWDNsakdVZUI3OUp4TzdkanZrRllxcHJRUExEZWtjNEpWdUVI?= =?utf-8?B?b1dST1lvdnJiMEU0VkJOY2VCUEhmY1RuODl2NGp4MkxrK3VaR052dGM4eUhK?= =?utf-8?B?R2JlRzZNSTlJVzhadkhGMXBBSjlwT1VTakxYbjJhODhrSVZZV3ZMRHVaaWNz?= =?utf-8?B?VHN6SFE3a0l6MmYvSDJYblJyKytJUk05RE9OU3pqaWZBZUxUbzBzN0dEOE93?= =?utf-8?B?eGdkaG9YcHd1UlRabTNsb2pGWXFKQzhFbXZhR3ppNy9jRTFET1RVeHhUdngx?= =?utf-8?B?eWZzaXdpbDZzYlYyS1o0aEkvbjU2UTZDOHN3aTkwZml2aVpuVWtmeHdVZ3JS?= =?utf-8?B?MVFueTJGY3NCeGh5bTY2UjV1Q3B1ekJSZXpzNnZTWEM0MEQzN1FvN0VvTURG?= =?utf-8?B?Zm03WnJua3hJQ0xTa2FkTGplNFg0MjBkbG0xRE1DUCtEdi9oUjl6aTZPT1RP?= =?utf-8?Q?fkrUTWCsHqML+zvxl1YN2wTSD5ieTclk=3D?= X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0714;5:17sp6K9Kb2+/v2fEvZrVep9PXiwd+Hyh49N9pq2bPn7+cIzL0s4zDqVVAYzlkzp342IzCaPyzl8rx8eUBgEoakET5LZ4KVt4gYUmxKTe3hTHwDCyMS6snYI8IW0OQoj/7fYkrKGWqwwiQVhqQu4svg==;24:PyKi/aQxbZnyEv/FgvNgUsyqqCIQ8LuD0K5bjYEGKHz1VHhSyh2oBp40/yydiUBsv+L5GqKujFSwQeXJHq3uIPHBNYO4vfkUBtTZpchaX90=;20:n/mXHtY1xKQ2/w8+e6UJ8FCOXTeNIhtBWQSFG9L7W28Bx94mP1hXhLzbRNMuhHcTUur2zC5hutnyiJvbIn3FmXOcCaWrjuYsY0BECMuw3CAKXhGhEgeCrWPzIPegNAtpacSK842fbJfx5D4hnF8Wyfodlq/dMv/UJ8wB0bScISQ5niuFSdrNJUzSYZxnkCg14OcV8dzY/SzfYi3ZiivhICus/Il+WjQ7fmh2HX0gY/Dx6/ArULnW+FkcO4BmcK5w SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Oct 2015 02:31:05.8629 (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: CY1PR12MB0714 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: 23.73 mW (avg = 634.63 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 Cc: Peter Zijlstra Cc: Ingo Molnar --- drivers/hwmon/fam15h_power.c | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 6321f73..a5a539e 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include @@ -64,6 +67,10 @@ 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; + struct mutex acc_pwr_mutex; }; static ssize_t show_power(struct device *dev, @@ -132,11 +139,15 @@ static void do_read_registers_on_cu(void *_data) cores_per_cu = amd_get_cores_per_cu(); cu = cpu / cores_per_cu; + mutex_lock(&data->acc_pwr_mutex); WARN_ON(rdmsrl_safe(MSR_F15H_CU_PWR_ACCUMULATOR, &data->cu_acc_power[cu])); WARN_ON(rdmsrl_safe(MSR_F15H_PTSC, &data->cpu_sw_pwr_ptsc[cu])); + + data->cu_on[cu] = 1; + mutex_unlock(&data->acc_pwr_mutex); } static int read_registers(struct fam15h_power_data *data) @@ -148,6 +159,10 @@ static int read_registers(struct fam15h_power_data *data) cores_per_cu = amd_get_cores_per_cu(); cu_num = boot_cpu_data.x86_max_cores / cores_per_cu; + mutex_lock(&data->acc_pwr_mutex); + memset(data->cu_on, 0, sizeof(int) * MAX_CUS); + mutex_unlock(&data->acc_pwr_mutex); + WARN_ON_ONCE(cu_num > MAX_CUS); ret = zalloc_cpumask_var(&mask, GFP_KERNEL); @@ -184,18 +199,113 @@ 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, cores_per_cu, ret; + signed long leftover; + + cores_per_cu = amd_get_cores_per_cu(); + cu_num = boot_cpu_data.x86_max_cores / cores_per_cu; + + ret = read_registers(data); + if (ret) + return 0; + + cu = 0; + while(cu++ < cu_num) { + 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; + + mutex_lock(&data->acc_pwr_mutex); + data->power_period = temp; + mutex_unlock(&data->acc_pwr_mutex); + + 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 <= 0x6f))) 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); @@ -210,6 +320,11 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev, (c->x86_model >= 0x60 && c->x86_model <= 0x6f))) 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->fam15h_power_group.attrs = fam15h_power_attrs; return 0; @@ -322,6 +437,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; + ret = read_registers(data); return ret; @@ -349,6 +467,8 @@ static int fam15h_power_probe(struct pci_dev *pdev, if (!data) return -ENOMEM; + mutex_init(&data->acc_pwr_mutex); + ret = fam15h_power_init_data(pdev, data); if (ret) return ret; -- 1.9.1