.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Hypervisor supplied "24x7" performance counter support |
---|
3 | 4 | * |
---|
4 | 5 | * Author: Cody P Schafer <cody@linux.vnet.ibm.com> |
---|
5 | 6 | * Copyright 2014 IBM Corporation. |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * as published by the Free Software Foundation; either version |
---|
10 | | - * 2 of the License, or (at your option) any later version. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #define pr_fmt(fmt) "hv-24x7: " fmt |
---|
.. | .. |
---|
24 | 20 | #include <asm/io.h> |
---|
25 | 21 | #include <linux/byteorder/generic.h> |
---|
26 | 22 | |
---|
| 23 | +#include <asm/rtas.h> |
---|
27 | 24 | #include "hv-24x7.h" |
---|
28 | 25 | #include "hv-24x7-catalog.h" |
---|
29 | 26 | #include "hv-common.h" |
---|
.. | .. |
---|
33 | 30 | |
---|
34 | 31 | /* Whether we have to aggregate result data for some domains. */ |
---|
35 | 32 | static bool aggregate_result_elements; |
---|
| 33 | + |
---|
| 34 | +static cpumask_t hv_24x7_cpumask; |
---|
36 | 35 | |
---|
37 | 36 | static bool domain_is_valid(unsigned domain) |
---|
38 | 37 | { |
---|
.. | .. |
---|
58 | 57 | #undef DOMAIN |
---|
59 | 58 | default: |
---|
60 | 59 | return false; |
---|
| 60 | + } |
---|
| 61 | +} |
---|
| 62 | + |
---|
| 63 | +/* |
---|
| 64 | + * The Processor Module Information system parameter allows transferring |
---|
| 65 | + * of certain processor module information from the platform to the OS. |
---|
| 66 | + * Refer PAPR+ document to get parameter token value as '43'. |
---|
| 67 | + */ |
---|
| 68 | + |
---|
| 69 | +#define PROCESSOR_MODULE_INFO 43 |
---|
| 70 | + |
---|
| 71 | +static u32 phys_sockets; /* Physical sockets */ |
---|
| 72 | +static u32 phys_chipspersocket; /* Physical chips per socket*/ |
---|
| 73 | +static u32 phys_coresperchip; /* Physical cores per chip */ |
---|
| 74 | + |
---|
| 75 | +/* |
---|
| 76 | + * read_24x7_sys_info() |
---|
| 77 | + * Retrieve the number of sockets and chips per socket and cores per |
---|
| 78 | + * chip details through the get-system-parameter rtas call. |
---|
| 79 | + */ |
---|
| 80 | +void read_24x7_sys_info(void) |
---|
| 81 | +{ |
---|
| 82 | + const s32 token = rtas_token("ibm,get-system-parameter"); |
---|
| 83 | + int call_status; |
---|
| 84 | + |
---|
| 85 | + /* |
---|
| 86 | + * Making system parameter: chips and sockets and cores per chip |
---|
| 87 | + * default to 1. |
---|
| 88 | + */ |
---|
| 89 | + phys_sockets = 1; |
---|
| 90 | + phys_chipspersocket = 1; |
---|
| 91 | + phys_coresperchip = 1; |
---|
| 92 | + |
---|
| 93 | + do { |
---|
| 94 | + spin_lock(&rtas_data_buf_lock); |
---|
| 95 | + call_status = rtas_call(token, 3, 1, NULL, PROCESSOR_MODULE_INFO, |
---|
| 96 | + __pa(rtas_data_buf), RTAS_DATA_BUF_SIZE); |
---|
| 97 | + if (call_status == 0) { |
---|
| 98 | + int ntypes = be16_to_cpup((__be16 *)&rtas_data_buf[2]); |
---|
| 99 | + int len = be16_to_cpup((__be16 *)&rtas_data_buf[0]); |
---|
| 100 | + |
---|
| 101 | + if (len >= 8 && ntypes != 0) { |
---|
| 102 | + phys_sockets = be16_to_cpup((__be16 *)&rtas_data_buf[4]); |
---|
| 103 | + phys_chipspersocket = be16_to_cpup((__be16 *)&rtas_data_buf[6]); |
---|
| 104 | + phys_coresperchip = be16_to_cpup((__be16 *)&rtas_data_buf[8]); |
---|
| 105 | + } |
---|
| 106 | + } |
---|
| 107 | + spin_unlock(&rtas_data_buf_lock); |
---|
| 108 | + } while (rtas_busy_delay(call_status)); |
---|
| 109 | + |
---|
| 110 | + if (call_status != 0) { |
---|
| 111 | + pr_err("Error calling get-system-parameter %d\n", |
---|
| 112 | + call_status); |
---|
61 | 113 | } |
---|
62 | 114 | } |
---|
63 | 115 | |
---|
.. | .. |
---|
390 | 442 | return sprintf(buf, "%s\n", (char *)d->var); |
---|
391 | 443 | } |
---|
392 | 444 | |
---|
| 445 | +static ssize_t cpumask_show(struct device *dev, |
---|
| 446 | + struct device_attribute *attr, char *buf) |
---|
| 447 | +{ |
---|
| 448 | + return cpumap_print_to_pagebuf(true, buf, &hv_24x7_cpumask); |
---|
| 449 | +} |
---|
| 450 | + |
---|
| 451 | +static ssize_t sockets_show(struct device *dev, |
---|
| 452 | + struct device_attribute *attr, char *buf) |
---|
| 453 | +{ |
---|
| 454 | + return sprintf(buf, "%d\n", phys_sockets); |
---|
| 455 | +} |
---|
| 456 | + |
---|
| 457 | +static ssize_t chipspersocket_show(struct device *dev, |
---|
| 458 | + struct device_attribute *attr, char *buf) |
---|
| 459 | +{ |
---|
| 460 | + return sprintf(buf, "%d\n", phys_chipspersocket); |
---|
| 461 | +} |
---|
| 462 | + |
---|
| 463 | +static ssize_t coresperchip_show(struct device *dev, |
---|
| 464 | + struct device_attribute *attr, char *buf) |
---|
| 465 | +{ |
---|
| 466 | + return sprintf(buf, "%d\n", phys_coresperchip); |
---|
| 467 | +} |
---|
| 468 | + |
---|
393 | 469 | static struct attribute *device_str_attr_create_(char *name, char *str) |
---|
394 | 470 | { |
---|
395 | 471 | struct dev_ext_attribute *attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
---|
.. | .. |
---|
571 | 647 | struct event_uniq *it; |
---|
572 | 648 | int result; |
---|
573 | 649 | |
---|
574 | | - it = container_of(*new, struct event_uniq, node); |
---|
| 650 | + it = rb_entry(*new, struct event_uniq, node); |
---|
575 | 651 | result = ev_uniq_ord(name, nl, domain, it->name, it->nl, |
---|
576 | 652 | it->domain); |
---|
577 | 653 | |
---|
.. | .. |
---|
1036 | 1112 | (unsigned long long)be32_to_cpu(page_0->length) * 4096); |
---|
1037 | 1113 | static BIN_ATTR_RO(catalog, 0/* real length varies */); |
---|
1038 | 1114 | static DEVICE_ATTR_RO(domains); |
---|
| 1115 | +static DEVICE_ATTR_RO(sockets); |
---|
| 1116 | +static DEVICE_ATTR_RO(chipspersocket); |
---|
| 1117 | +static DEVICE_ATTR_RO(coresperchip); |
---|
| 1118 | +static DEVICE_ATTR_RO(cpumask); |
---|
1039 | 1119 | |
---|
1040 | 1120 | static struct bin_attribute *if_bin_attrs[] = { |
---|
1041 | 1121 | &bin_attr_catalog, |
---|
1042 | 1122 | NULL, |
---|
1043 | 1123 | }; |
---|
1044 | 1124 | |
---|
| 1125 | +static struct attribute *cpumask_attrs[] = { |
---|
| 1126 | + &dev_attr_cpumask.attr, |
---|
| 1127 | + NULL, |
---|
| 1128 | +}; |
---|
| 1129 | + |
---|
| 1130 | +static struct attribute_group cpumask_attr_group = { |
---|
| 1131 | + .attrs = cpumask_attrs, |
---|
| 1132 | +}; |
---|
| 1133 | + |
---|
1045 | 1134 | static struct attribute *if_attrs[] = { |
---|
1046 | 1135 | &dev_attr_catalog_len.attr, |
---|
1047 | 1136 | &dev_attr_catalog_version.attr, |
---|
1048 | 1137 | &dev_attr_domains.attr, |
---|
| 1138 | + &dev_attr_sockets.attr, |
---|
| 1139 | + &dev_attr_chipspersocket.attr, |
---|
| 1140 | + &dev_attr_coresperchip.attr, |
---|
1049 | 1141 | NULL, |
---|
1050 | 1142 | }; |
---|
1051 | 1143 | |
---|
.. | .. |
---|
1061 | 1153 | &event_desc_group, |
---|
1062 | 1154 | &event_long_desc_group, |
---|
1063 | 1155 | &if_group, |
---|
| 1156 | + &cpumask_attr_group, |
---|
1064 | 1157 | NULL, |
---|
1065 | 1158 | }; |
---|
1066 | 1159 | |
---|
.. | .. |
---|
1306 | 1399 | return -EINVAL; |
---|
1307 | 1400 | } |
---|
1308 | 1401 | |
---|
1309 | | - /* unsupported modes and filters */ |
---|
1310 | | - if (event->attr.exclude_user || |
---|
1311 | | - event->attr.exclude_kernel || |
---|
1312 | | - event->attr.exclude_hv || |
---|
1313 | | - event->attr.exclude_idle || |
---|
1314 | | - event->attr.exclude_host || |
---|
1315 | | - event->attr.exclude_guest) |
---|
1316 | | - return -EINVAL; |
---|
1317 | | - |
---|
1318 | 1402 | /* no branch sampling */ |
---|
1319 | 1403 | if (has_branch_stack(event)) |
---|
1320 | 1404 | return -EOPNOTSUPP; |
---|
.. | .. |
---|
1326 | 1410 | } |
---|
1327 | 1411 | |
---|
1328 | 1412 | domain = event_get_domain(event); |
---|
1329 | | - if (domain >= HV_PERF_DOMAIN_MAX) { |
---|
| 1413 | + if (domain == 0 || domain >= HV_PERF_DOMAIN_MAX) { |
---|
1330 | 1414 | pr_devel("invalid domain %d\n", domain); |
---|
1331 | 1415 | return -EINVAL; |
---|
1332 | 1416 | } |
---|
.. | .. |
---|
1567 | 1651 | .start_txn = h_24x7_event_start_txn, |
---|
1568 | 1652 | .commit_txn = h_24x7_event_commit_txn, |
---|
1569 | 1653 | .cancel_txn = h_24x7_event_cancel_txn, |
---|
| 1654 | + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, |
---|
1570 | 1655 | }; |
---|
| 1656 | + |
---|
| 1657 | +static int ppc_hv_24x7_cpu_online(unsigned int cpu) |
---|
| 1658 | +{ |
---|
| 1659 | + if (cpumask_empty(&hv_24x7_cpumask)) |
---|
| 1660 | + cpumask_set_cpu(cpu, &hv_24x7_cpumask); |
---|
| 1661 | + |
---|
| 1662 | + return 0; |
---|
| 1663 | +} |
---|
| 1664 | + |
---|
| 1665 | +static int ppc_hv_24x7_cpu_offline(unsigned int cpu) |
---|
| 1666 | +{ |
---|
| 1667 | + int target; |
---|
| 1668 | + |
---|
| 1669 | + /* Check if exiting cpu is used for collecting 24x7 events */ |
---|
| 1670 | + if (!cpumask_test_and_clear_cpu(cpu, &hv_24x7_cpumask)) |
---|
| 1671 | + return 0; |
---|
| 1672 | + |
---|
| 1673 | + /* Find a new cpu to collect 24x7 events */ |
---|
| 1674 | + target = cpumask_last(cpu_active_mask); |
---|
| 1675 | + |
---|
| 1676 | + if (target < 0 || target >= nr_cpu_ids) { |
---|
| 1677 | + pr_err("hv_24x7: CPU hotplug init failed\n"); |
---|
| 1678 | + return -1; |
---|
| 1679 | + } |
---|
| 1680 | + |
---|
| 1681 | + /* Migrate 24x7 events to the new target */ |
---|
| 1682 | + cpumask_set_cpu(target, &hv_24x7_cpumask); |
---|
| 1683 | + perf_pmu_migrate_context(&h_24x7_pmu, cpu, target); |
---|
| 1684 | + |
---|
| 1685 | + return 0; |
---|
| 1686 | +} |
---|
| 1687 | + |
---|
| 1688 | +static int hv_24x7_cpu_hotplug_init(void) |
---|
| 1689 | +{ |
---|
| 1690 | + return cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE, |
---|
| 1691 | + "perf/powerpc/hv_24x7:online", |
---|
| 1692 | + ppc_hv_24x7_cpu_online, |
---|
| 1693 | + ppc_hv_24x7_cpu_offline); |
---|
| 1694 | +} |
---|
1571 | 1695 | |
---|
1572 | 1696 | static int hv_24x7_init(void) |
---|
1573 | 1697 | { |
---|
.. | .. |
---|
1613 | 1737 | if (r) |
---|
1614 | 1738 | return r; |
---|
1615 | 1739 | |
---|
| 1740 | + /* init cpuhotplug */ |
---|
| 1741 | + r = hv_24x7_cpu_hotplug_init(); |
---|
| 1742 | + if (r) |
---|
| 1743 | + return r; |
---|
| 1744 | + |
---|
1616 | 1745 | r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1); |
---|
1617 | 1746 | if (r) |
---|
1618 | 1747 | return r; |
---|
1619 | 1748 | |
---|
| 1749 | + read_24x7_sys_info(); |
---|
| 1750 | + |
---|
1620 | 1751 | return 0; |
---|
1621 | 1752 | } |
---|
1622 | 1753 | |
---|