Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933578AbbLVTao (ORCPT ); Tue, 22 Dec 2015 14:30:44 -0500 Received: from mail-bn1on0055.outbound.protection.outlook.com ([157.56.110.55]:56384 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932135AbbLVTa3 (ORCPT ); Tue, 22 Dec 2015 14:30:29 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Suravee.Suthikulpanit@amd.com; From: Suravee Suthikulpanit To: , , , , CC: , , Suravee Suthikulpanit Subject: [PATCH 6/6] perf/amd/iommu: Enable support for multiple IOMMUs Date: Tue, 22 Dec 2015 13:19:17 -0600 Message-ID: <1450811957-1511-7-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1450811957-1511-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1450811957-1511-1-git-send-email-Suravee.Suthikulpanit@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: BY2PR04CA0009.namprd04.prod.outlook.com (10.255.247.19) To CY1PR12MB0444.namprd12.prod.outlook.com (25.163.91.22) X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0444;2:uMNhlvotmJvAAci57Y4ypJxc4WHcg56pBIF8JrwT9QONEOMQ4HpQx/HKJ55OlsYP63ExeDzQoBk/1IJujnMH16BV07eUFZdgVX/Ygji1ax0iC2z/9DSoDucOiUzjH2k5r95Tq27YolFH+v3isDnW7w==;3:lNtk1b9LrFDw0VSM1vsuFXIU+Lt1ViYk0XFoLwfOdvBjfzxwYGfMWV18OqUTOyovSLLScNPVr2F6mQ3v0o0EtOtkdYff1bi3XebbejrAegkP9WOeH8sjRgl0V0BVuTBR;25:04/KCRutMNiRIR+8XtZlKrcFi04t1TaHOUo8H4j8T4UMAY2K7Nz3fkcaD9aFxEbLOYxJt6QmwJZt0kohbSePECDjQWx1Wa2maL69kGBrb7EetW4w538KPNUU0VICOuAWkRC3+xsnpukO4wv85RnNO1cfQRyyDfeXxE1sPGg31kxFa20JHEdh2W0S0wPpwHZKEfIakNZAUe5yGDgxCQcuRkMF5WcHYJGVGEFBVd+Sl4DIoAc5Iy2FDAvcklhRUEZd X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR12MB0444; X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0444;20:tBlHN6/XD+bnYlQgW/yTeNcL2JKQFjl0UwsBfYo78x/jbQZpYKW3TCMowdwSQiH+qgVtjfnUAw6pTUNEe7pgpENQJY4SdMYfdSlSCHOeVomPwl8JADLxj7FRThRRwpQjQSuRcwvu+jBbMoMSDJeuclZG6DKFHsqitut7I+y73wE9qb/TSTc98nc8R7XeE7FQUK0ThU4+FnWgsp3LG1L6XKoTlT3LAbhH//FqbnsQL9mA6oJi0Tl5EH64hoyyAdecB2fSVWfSLEoBlMbEEvgq+rM0LcAgMxbgCUuLY77UISrn2g8hyXBkGRfMn2D7aKp1iGWUsZ66/4YmCU1djivomL4WsZrTmCYG1SD/jmPpLPqkZIkFttfYyGGz7YjIzpiU75Hfe3kW41RosT6HbQvY2OHddcBGtPFWbzPIVXQmJFrjdT3aLglAkhkYMvsS1Gx5ytx93PiU7n/ATRb3xFmE2Q8VzhRUDeNMX9cj9jAkzjYkYjS+ovB6OvqWVa7m21ls;4:fE72Wgq6sL+hj7JthOJ1oCvk9oWuS/b3PQuqDAsrNWOfJI6d0VbShMO7kKOLjQgsn1xzSGUEPBCZ+5cS0DriKqrj2ts+SfHv9afG5dKawCBz3Ctac7UccBR9e4BhYTmganj9BLQCR8G0IHVkRET/xF++oN38n04CbmuMe0//vmZxX/gDw13LY/k0v/7VDYiD9IvG9GvYtUpZmZSN9ShEu/twNzUzucp1pgOkO8rslpPry0DDKJYbpfp11+V3rsao74nLrSuDajtHm8lwrCvjvo4y6E9w3aP/X9fbkhjMg31hTmdf6EA9ND/8K1ooA978CMYt/Nk8L54G804qTgR+PLAFEEfj8pisgTczigGuXPKd0bVORbrA/DvLqX02ffo+iS4Dhu2D07xfsnnwkJHjPoVqs9u5WrW4r9RItQIcRXs= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(8121501046)(520078)(5005006)(3002001)(10201501046);SRVR:CY1PR12MB0444;BCL:0;PCL:0;RULEID:;SRVR:CY1PR12MB0444; X-Forefront-PRVS: 0798146F16 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(6009001)(189002)(199003)(105586002)(101416001)(53416004)(19580395003)(50466002)(40100003)(19580405001)(106356001)(5001770100001)(42186005)(97736004)(47776003)(50986999)(87976001)(2201001)(3846002)(48376002)(5003940100001)(76176999)(229853001)(66066001)(86362001)(189998001)(2950100001)(6116002)(36756003)(5004730100002)(50226001)(77096005)(586003)(5008740100001)(1096002)(92566002)(122386002);DIR:OUT;SFP:1101;SCL:1;SRVR:CY1PR12MB0444;H:ssuthiku-cz-dev.amd.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;CY1PR12MB0444;23:t7wj4DRrGpLZw5IK0BgTn1QcF8J1hMgK21hGS0hST?= =?us-ascii?Q?oIK1VVDSeEQTQf8uLLNgGpOoPLUICR8hmbWHTm78stLCQP6PawZB85hSxo97?= =?us-ascii?Q?S1uJZnc5qgSjCDV5HQwe+sdmDAsZZvvQv9Y9smTL2pkpSRWIK7IpKAP3cE1R?= =?us-ascii?Q?4DNkCgh7YD616EjWFfEwOdBxrmUbZNY2l6l+l0yYp1M8Zq2/6e1j5nhOWffG?= =?us-ascii?Q?JMJj3j+/unQIAaPKb1yhMrex0I2YzlBcXmcCpXJroVq81nPqgWl8de1HYhXh?= =?us-ascii?Q?+4xqXYX/0ZDav0PVvKvLM0aJ/REpfvkFK4speDBGFAtCbuMp2GTlCtQVNgr4?= =?us-ascii?Q?5BsdCE1NljjhOfyiKuD/bY88tsADcBz/4W3fT0VkkSon4Oqv96ppclV/0I5C?= =?us-ascii?Q?aPg9TGCOokqA7/jQhkIRKxFOHhq3+/g4iaFc5KZlios86o0ls71F++ihUNXa?= =?us-ascii?Q?VcHhwS0idy+gbI26eLsuNxeVnS0MmlOb2wkdgZZJJG5DQTbkFrTzeNt+xIlY?= =?us-ascii?Q?VYEHWHclwNGXf6+82Qy6sU5Ug8xyQQZUaet22sgUDAgJQZ8kk6F5kGTfYV8K?= =?us-ascii?Q?dilwyOfoCAwYVh4BCE2435i/lFs7Bvq3htZTogx9N35jcRezy3wfo6n0/HpL?= =?us-ascii?Q?hWt2krYj8EPwKLgMwYeGi4VqrNnWglOsVMUqmlnHHJpfFGTRo06DTlDj2wti?= =?us-ascii?Q?Shbpfm9CBz59V6g5R16QKXKRRk2nKufK2uCRnPBjcnqRTFh8IZlozm+J5e9T?= =?us-ascii?Q?P+NUI/JyK18U01Qh8D/0CNiL601Gc0w66jvDbdQDFKfYFrGo9WkKWWGmQz/m?= =?us-ascii?Q?o6p1N3TFGd/qs7KFJU74p7o54w8pr96BLrDz4iEQrK3Yi876yLjoIqKqy0Np?= =?us-ascii?Q?nEx3sQ/rVwiTdmVeGtphHSYtFOSjQH7q63m8j04tqb4pwupN7GacbYg5qtrm?= =?us-ascii?Q?6vLBOrtiEJVmuN/Oj7xAWLQJUIVWpchGGBA/nVzPRQSWtfD3zrW/NZcjQdDl?= =?us-ascii?Q?Lo=3D?= X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0444;5:aIyGamiB304Adp0fgDTID71l5/zieExr1HT/AoOorzJHyPlT7l/12sYNiPx2HoV8jqd18ycNI3BfuJR0d/MZqOfSIVajT8I9JpfMgKCkjwpYmBWhEB0GVuuG+XnLkHU7vBD3p0+kpZFvAOV5smsrNw==;24:JUCnBSbGZOqJE8P9+RZPjwIzhQlXqstvg4XLpU7w9bLZgxugg2tP6RF0iXimooLbz67oDxPxze71byExXfWkjkJ9MAYUf6To1mE+DLCBkH8=;20:Z6VEijBlXd9WUxcO1GOl4HnCj9k4dwvy8hF/97pbNamvLNlc0jQzBDxaXLPmWWOqZhSw2MwBauPGe9EQguhS+BNSrSsoAWxqiEUljRGTT/KdT4FHjoAuvyMVh9piuLNXRK/qjeOOzDhFu+prmVwldywXRdo0p/PKRZh71JO0FuubOiVksfmexuSJUoDvIpK5yRtp/uyk/h+z1/iwB7zWRIHLTKffjHhwo820rykk2O947hXMM2fp44g1se5HoXUb X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Dec 2015 19:30:22.0793 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR12MB0444 X-Microsoft-Exchange-Diagnostics: 1;CY1PR12MB0853;2:K7L/DpROxx6GJyTFGH3zcaYt5YPipU5XPV66rN8foVSjVBxX+/cvAhOc49XH86RWlpW42fcTXiBzV55G36D85bEFjtJrpgAXjAmthpg4mcl6/kBTLmzA81M7IeFOKFdzzrPd72MtkB61IObS3bph+Q==;23:4g9gRVwt/FRzsO196m3tWvRFlrFThWTbVEtJex/owzJTnAglIGCT1xVEJgX+kBNIiBt5ZsV6M6WbBBj69P0UwOzgBv36AWOnj2x8NvTbFSfsNDqoeweCsXQyfT55xdOcvfKZ3kPnbwDECo2KewgjhnhLGzBox3eu1W5+cFvYz0m9C2HTHdnGh2b2Qp1Rhm1F X-OriginatorOrg: amd.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9834 Lines: 306 The current amd_iommu_pc_get_set_reg_val() does not support muli-IOMMU system. This patch replace amd_iommu_pc_get_set_reg_val() with amd_iommu_pc_set_reg_val() and amd_iommu_pc_[set|get]_cnt_vals(). This implementation makes an assumption that the counters on all IOMMUs will be programmed the same way (i.e with the same events). Signed-off-by: Suravee Suthikulpanit --- arch/x86/kernel/cpu/perf_event_amd_iommu.c | 80 +++++++++++++++++---------- drivers/iommu/amd_iommu_init.c | 87 ++++++++++++++++++++++++++---- include/linux/perf/perf_event_amd_iommu.h | 8 ++- 3 files changed, 136 insertions(+), 39 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_amd_iommu.c b/arch/x86/kernel/cpu/perf_event_amd_iommu.c index 8af7149..9c60eb3 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_iommu.c +++ b/arch/x86/kernel/cpu/perf_event_amd_iommu.c @@ -264,44 +264,46 @@ static void perf_iommu_enable_event(struct perf_event *ev) u64 reg = 0ULL; reg = csource; - amd_iommu_pc_get_set_reg_val(devid, + amd_iommu_pc_set_reg_val(devid, _GET_BANK(ev), _GET_CNTR(ev) , - IOMMU_PC_COUNTER_SRC_REG, ®, true); + IOMMU_PC_COUNTER_SRC_REG, ®); reg = 0ULL | devid | (_GET_DEVID_MASK(ev) << 32); if (reg) reg |= (1UL << 31); - amd_iommu_pc_get_set_reg_val(devid, + amd_iommu_pc_set_reg_val(devid, _GET_BANK(ev), _GET_CNTR(ev) , - IOMMU_PC_DEVID_MATCH_REG, ®, true); + IOMMU_PC_DEVID_MATCH_REG, ®); reg = 0ULL | _GET_PASID(ev) | (_GET_PASID_MASK(ev) << 32); if (reg) reg |= (1UL << 31); - amd_iommu_pc_get_set_reg_val(devid, + amd_iommu_pc_set_reg_val(devid, _GET_BANK(ev), _GET_CNTR(ev) , - IOMMU_PC_PASID_MATCH_REG, ®, true); + IOMMU_PC_PASID_MATCH_REG, ®); reg = 0ULL | _GET_DOMID(ev) | (_GET_DOMID_MASK(ev) << 32); if (reg) reg |= (1UL << 31); - amd_iommu_pc_get_set_reg_val(devid, + amd_iommu_pc_set_reg_val(devid, _GET_BANK(ev), _GET_CNTR(ev) , - IOMMU_PC_DOMID_MATCH_REG, ®, true); + IOMMU_PC_DOMID_MATCH_REG, ®); } static void perf_iommu_disable_event(struct perf_event *event) { u64 reg = 0ULL; - amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), + amd_iommu_pc_set_reg_val(_GET_DEVID(event), _GET_BANK(event), _GET_CNTR(event), - IOMMU_PC_COUNTER_SRC_REG, ®, true); + IOMMU_PC_COUNTER_SRC_REG, ®); } static void perf_iommu_start(struct perf_event *event, int flags) { struct hw_perf_event *hwc = &event->hw; + struct perf_amd_iommu *perf_iommu = + container_of(event->pmu, struct perf_amd_iommu, pmu); pr_debug("perf: amd_iommu:perf_iommu_start\n"); if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) @@ -311,10 +313,19 @@ static void perf_iommu_start(struct perf_event *event, int flags) hwc->state = 0; if (flags & PERF_EF_RELOAD) { - u64 prev_raw_count = local64_read(&hwc->prev_count); - amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), - _GET_BANK(event), _GET_CNTR(event), - IOMMU_PC_COUNTER_REG, &prev_raw_count, true); + int i; + + for (i = 0; i < amd_iommu_get_num_iommus(); i++) { + int index = get_iommu_bnk_cnt_evt_idx(perf_iommu, i, + _GET_BANK(event), _GET_CNTR(event)); + + perf_iommu_cnts[i] = local64_read( + &perf_iommu->prev_cnts[index]); + } + + amd_iommu_pc_set_cnt_vals(_GET_BANK(event), _GET_CNTR(event), + amd_iommu_get_num_iommus(), + perf_iommu_cnts); } perf_iommu_enable_event(event); @@ -324,29 +335,42 @@ static void perf_iommu_start(struct perf_event *event, int flags) static void perf_iommu_read(struct perf_event *event) { - u64 count = 0ULL; + int i; u64 prev_raw_count = 0ULL; u64 delta = 0ULL; struct hw_perf_event *hwc = &event->hw; + struct perf_amd_iommu *perf_iommu = + container_of(event->pmu, struct perf_amd_iommu, pmu); + pr_debug("perf: amd_iommu:perf_iommu_read\n"); - amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), - _GET_BANK(event), _GET_CNTR(event), - IOMMU_PC_COUNTER_REG, &count, false); + if (amd_iommu_pc_get_cnt_vals(_GET_BANK(event), _GET_CNTR(event), + amd_iommu_get_num_iommus(), + perf_iommu_cnts)) + return; + + local64_set(&hwc->prev_count, 0); + for (i = 0; i < amd_iommu_get_num_iommus(); i++) { + int index = get_iommu_bnk_cnt_evt_idx(perf_iommu, i, + _GET_BANK(event), _GET_CNTR(event)); - /* IOMMU pc counter register is only 48 bits */ - count &= 0xFFFFFFFFFFFFULL; + /* IOMMU pc counter register is only 48 bits */ + perf_iommu_cnts[i] &= 0xFFFFFFFFFFFFULL; - prev_raw_count = local64_read(&hwc->prev_count); - if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, - count) != prev_raw_count) - return; + prev_raw_count = local64_read(&perf_iommu->prev_cnts[index]); + if (prev_raw_count != local64_cmpxchg( + &perf_iommu->prev_cnts[index], + prev_raw_count, perf_iommu_cnts[i])) + return; - /* Handling 48-bit counter overflowing */ - delta = (count << COUNTER_SHIFT) - (prev_raw_count << COUNTER_SHIFT); - delta >>= COUNTER_SHIFT; - local64_add(delta, &event->count); + local64_add(prev_raw_count, &hwc->prev_count); + /* Handling 48-bit counter overflowing */ + delta = (perf_iommu_cnts[i] << COUNTER_SHIFT) - + (prev_raw_count << COUNTER_SHIFT); + delta >>= COUNTER_SHIFT; + local64_add(delta, &event->count); + } } static void perf_iommu_stop(struct perf_event *event, int flags) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 9c62613..86b09ec 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1133,6 +1133,9 @@ static int __init init_iommu_all(struct acpi_table_header *table) return 0; } +static int _amd_iommu_pc_get_set_reg_val(struct amd_iommu *iommu, + u8 bank, u8 cntr, u8 fxn, + u64 *value, bool is_write); static void init_iommu_perf_ctr(struct amd_iommu *iommu) { @@ -1144,8 +1147,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu) amd_iommu_pc_present = true; /* Check if the performance counters can be written to */ - if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) || - (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) || + if ((_amd_iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) || + (_amd_iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) || (val != val2)) { pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); amd_iommu_pc_present = false; @@ -2305,10 +2308,10 @@ u8 amd_iommu_pc_get_max_counters(void) } EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); -int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, - u64 *value, bool is_write) +static int _amd_iommu_pc_get_set_reg_val(struct amd_iommu *iommu, + u8 bank, u8 cntr, u8 fxn, + u64 *value, bool is_write) { - struct amd_iommu *iommu; u32 offset; u32 max_offset_lim; @@ -2316,9 +2319,6 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, if (!amd_iommu_pc_present) return -ENODEV; - /* Locate the iommu associated with the device ID */ - iommu = amd_iommu_rlookup_table[devid]; - /* Check for valid iommu and pc register indexing */ if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7))) return -ENODEV; @@ -2343,4 +2343,73 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, return 0; } -EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); + +int amd_iommu_pc_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, u64 *value) +{ + struct amd_iommu *iommu; + + for_each_iommu(iommu) { + int ret = _amd_iommu_pc_get_set_reg_val(iommu, bank, cntr, + fxn, value, true); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(amd_iommu_pc_set_reg_val); + +int amd_iommu_pc_set_cnt_vals(u8 bank, u8 cntr, int num, u64 *value) +{ + struct amd_iommu *iommu; + int i = 0; + + if (num > amd_iommu_cnt) + return -EINVAL; + + for_each_iommu(iommu) { + int ret = _amd_iommu_pc_get_set_reg_val(iommu, bank, cntr, + IOMMU_PC_COUNTER_REG, + &value[i], true); + if (ret) + return ret; + if (i++ == amd_iommu_cnt) + break; + } + + return 0; +} +EXPORT_SYMBOL(amd_iommu_pc_set_cnt_vals); + +int amd_iommu_pc_get_cnt_vals(u8 bank, u8 cntr, int num, u64 *value) +{ + struct amd_iommu *iommu; + int i = 0, ret; + + if (!num) + return -EINVAL; + + /* + * Here, we read the specified counters on all IOMMU, + * which should have been programmed the same way. + * and aggregate the counter values. + */ + for_each_iommu(iommu) { + u64 tmp; + + if (i >= num) + return -EINVAL; + + ret = _amd_iommu_pc_get_set_reg_val(iommu, bank, cntr, + IOMMU_PC_COUNTER_REG, + &tmp, false); + if (ret) + return ret; + + /* IOMMU pc counter register is only 48 bits */ + value[i] = tmp & 0xFFFFFFFFFFFFULL; + } + + return 0; +} +EXPORT_SYMBOL(amd_iommu_pc_get_cnt_vals); diff --git a/include/linux/perf/perf_event_amd_iommu.h b/include/linux/perf/perf_event_amd_iommu.h index cb820c2..be1a17d 100644 --- a/include/linux/perf/perf_event_amd_iommu.h +++ b/include/linux/perf/perf_event_amd_iommu.h @@ -33,7 +33,11 @@ extern u8 amd_iommu_pc_get_max_banks(void); extern u8 amd_iommu_pc_get_max_counters(void); -extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, - u8 fxn, u64 *value, bool is_write); +extern int amd_iommu_pc_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, + u64 *value); + +extern int amd_iommu_pc_set_cnt_vals(u8 bank, u8 cntr, int num, u64 *value); + +extern int amd_iommu_pc_get_cnt_vals(u8 bank, u8 cntr, int num, u64 *value); #endif /*_PERF_EVENT_AMD_IOMMU_H_*/ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/