hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/powerpc/perf/hv-24x7.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Hypervisor supplied "24x7" performance counter support
34 *
45 * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
56 * 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.
117 */
128
139 #define pr_fmt(fmt) "hv-24x7: " fmt
....@@ -24,6 +20,7 @@
2420 #include <asm/io.h>
2521 #include <linux/byteorder/generic.h>
2622
23
+#include <asm/rtas.h>
2724 #include "hv-24x7.h"
2825 #include "hv-24x7-catalog.h"
2926 #include "hv-common.h"
....@@ -33,6 +30,8 @@
3330
3431 /* Whether we have to aggregate result data for some domains. */
3532 static bool aggregate_result_elements;
33
+
34
+static cpumask_t hv_24x7_cpumask;
3635
3736 static bool domain_is_valid(unsigned domain)
3837 {
....@@ -58,6 +57,59 @@
5857 #undef DOMAIN
5958 default:
6059 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);
61113 }
62114 }
63115
....@@ -390,6 +442,30 @@
390442 return sprintf(buf, "%s\n", (char *)d->var);
391443 }
392444
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
+
393469 static struct attribute *device_str_attr_create_(char *name, char *str)
394470 {
395471 struct dev_ext_attribute *attr = kzalloc(sizeof(*attr), GFP_KERNEL);
....@@ -571,7 +647,7 @@
571647 struct event_uniq *it;
572648 int result;
573649
574
- it = container_of(*new, struct event_uniq, node);
650
+ it = rb_entry(*new, struct event_uniq, node);
575651 result = ev_uniq_ord(name, nl, domain, it->name, it->nl,
576652 it->domain);
577653
....@@ -1036,16 +1112,32 @@
10361112 (unsigned long long)be32_to_cpu(page_0->length) * 4096);
10371113 static BIN_ATTR_RO(catalog, 0/* real length varies */);
10381114 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);
10391119
10401120 static struct bin_attribute *if_bin_attrs[] = {
10411121 &bin_attr_catalog,
10421122 NULL,
10431123 };
10441124
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
+
10451134 static struct attribute *if_attrs[] = {
10461135 &dev_attr_catalog_len.attr,
10471136 &dev_attr_catalog_version.attr,
10481137 &dev_attr_domains.attr,
1138
+ &dev_attr_sockets.attr,
1139
+ &dev_attr_chipspersocket.attr,
1140
+ &dev_attr_coresperchip.attr,
10491141 NULL,
10501142 };
10511143
....@@ -1061,6 +1153,7 @@
10611153 &event_desc_group,
10621154 &event_long_desc_group,
10631155 &if_group,
1156
+ &cpumask_attr_group,
10641157 NULL,
10651158 };
10661159
....@@ -1306,15 +1399,6 @@
13061399 return -EINVAL;
13071400 }
13081401
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
-
13181402 /* no branch sampling */
13191403 if (has_branch_stack(event))
13201404 return -EOPNOTSUPP;
....@@ -1326,7 +1410,7 @@
13261410 }
13271411
13281412 domain = event_get_domain(event);
1329
- if (domain >= HV_PERF_DOMAIN_MAX) {
1413
+ if (domain == 0 || domain >= HV_PERF_DOMAIN_MAX) {
13301414 pr_devel("invalid domain %d\n", domain);
13311415 return -EINVAL;
13321416 }
....@@ -1567,7 +1651,47 @@
15671651 .start_txn = h_24x7_event_start_txn,
15681652 .commit_txn = h_24x7_event_commit_txn,
15691653 .cancel_txn = h_24x7_event_cancel_txn,
1654
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
15701655 };
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
+}
15711695
15721696 static int hv_24x7_init(void)
15731697 {
....@@ -1613,10 +1737,17 @@
16131737 if (r)
16141738 return r;
16151739
1740
+ /* init cpuhotplug */
1741
+ r = hv_24x7_cpu_hotplug_init();
1742
+ if (r)
1743
+ return r;
1744
+
16161745 r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
16171746 if (r)
16181747 return r;
16191748
1749
+ read_24x7_sys_info();
1750
+
16201751 return 0;
16211752 }
16221753