| .. | .. |
|---|
| 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 | { |
|---|
| .. | .. |
|---|
| 59 | 58 | default: |
|---|
| 60 | 59 | return false; |
|---|
| 61 | 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 | + int call_status, len, ntypes; |
|---|
| 83 | + |
|---|
| 84 | + spin_lock(&rtas_data_buf_lock); |
|---|
| 85 | + |
|---|
| 86 | + /* |
|---|
| 87 | + * Making system parameter: chips and sockets and cores per chip |
|---|
| 88 | + * default to 1. |
|---|
| 89 | + */ |
|---|
| 90 | + phys_sockets = 1; |
|---|
| 91 | + phys_chipspersocket = 1; |
|---|
| 92 | + phys_coresperchip = 1; |
|---|
| 93 | + |
|---|
| 94 | + call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, |
|---|
| 95 | + NULL, |
|---|
| 96 | + PROCESSOR_MODULE_INFO, |
|---|
| 97 | + __pa(rtas_data_buf), |
|---|
| 98 | + RTAS_DATA_BUF_SIZE); |
|---|
| 99 | + |
|---|
| 100 | + if (call_status != 0) { |
|---|
| 101 | + pr_err("Error calling get-system-parameter %d\n", |
|---|
| 102 | + call_status); |
|---|
| 103 | + } else { |
|---|
| 104 | + len = be16_to_cpup((__be16 *)&rtas_data_buf[0]); |
|---|
| 105 | + if (len < 8) |
|---|
| 106 | + goto out; |
|---|
| 107 | + |
|---|
| 108 | + ntypes = be16_to_cpup((__be16 *)&rtas_data_buf[2]); |
|---|
| 109 | + |
|---|
| 110 | + if (!ntypes) |
|---|
| 111 | + goto out; |
|---|
| 112 | + |
|---|
| 113 | + phys_sockets = be16_to_cpup((__be16 *)&rtas_data_buf[4]); |
|---|
| 114 | + phys_chipspersocket = be16_to_cpup((__be16 *)&rtas_data_buf[6]); |
|---|
| 115 | + phys_coresperchip = be16_to_cpup((__be16 *)&rtas_data_buf[8]); |
|---|
| 116 | + } |
|---|
| 117 | + |
|---|
| 118 | +out: |
|---|
| 119 | + spin_unlock(&rtas_data_buf_lock); |
|---|
| 62 | 120 | } |
|---|
| 63 | 121 | |
|---|
| 64 | 122 | /* Domains for which more than one result element are returned for each event. */ |
|---|
| .. | .. |
|---|
| 390 | 448 | return sprintf(buf, "%s\n", (char *)d->var); |
|---|
| 391 | 449 | } |
|---|
| 392 | 450 | |
|---|
| 451 | +static ssize_t cpumask_show(struct device *dev, |
|---|
| 452 | + struct device_attribute *attr, char *buf) |
|---|
| 453 | +{ |
|---|
| 454 | + return cpumap_print_to_pagebuf(true, buf, &hv_24x7_cpumask); |
|---|
| 455 | +} |
|---|
| 456 | + |
|---|
| 457 | +static ssize_t sockets_show(struct device *dev, |
|---|
| 458 | + struct device_attribute *attr, char *buf) |
|---|
| 459 | +{ |
|---|
| 460 | + return sprintf(buf, "%d\n", phys_sockets); |
|---|
| 461 | +} |
|---|
| 462 | + |
|---|
| 463 | +static ssize_t chipspersocket_show(struct device *dev, |
|---|
| 464 | + struct device_attribute *attr, char *buf) |
|---|
| 465 | +{ |
|---|
| 466 | + return sprintf(buf, "%d\n", phys_chipspersocket); |
|---|
| 467 | +} |
|---|
| 468 | + |
|---|
| 469 | +static ssize_t coresperchip_show(struct device *dev, |
|---|
| 470 | + struct device_attribute *attr, char *buf) |
|---|
| 471 | +{ |
|---|
| 472 | + return sprintf(buf, "%d\n", phys_coresperchip); |
|---|
| 473 | +} |
|---|
| 474 | + |
|---|
| 393 | 475 | static struct attribute *device_str_attr_create_(char *name, char *str) |
|---|
| 394 | 476 | { |
|---|
| 395 | 477 | struct dev_ext_attribute *attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 571 | 653 | struct event_uniq *it; |
|---|
| 572 | 654 | int result; |
|---|
| 573 | 655 | |
|---|
| 574 | | - it = container_of(*new, struct event_uniq, node); |
|---|
| 656 | + it = rb_entry(*new, struct event_uniq, node); |
|---|
| 575 | 657 | result = ev_uniq_ord(name, nl, domain, it->name, it->nl, |
|---|
| 576 | 658 | it->domain); |
|---|
| 577 | 659 | |
|---|
| .. | .. |
|---|
| 1036 | 1118 | (unsigned long long)be32_to_cpu(page_0->length) * 4096); |
|---|
| 1037 | 1119 | static BIN_ATTR_RO(catalog, 0/* real length varies */); |
|---|
| 1038 | 1120 | static DEVICE_ATTR_RO(domains); |
|---|
| 1121 | +static DEVICE_ATTR_RO(sockets); |
|---|
| 1122 | +static DEVICE_ATTR_RO(chipspersocket); |
|---|
| 1123 | +static DEVICE_ATTR_RO(coresperchip); |
|---|
| 1124 | +static DEVICE_ATTR_RO(cpumask); |
|---|
| 1039 | 1125 | |
|---|
| 1040 | 1126 | static struct bin_attribute *if_bin_attrs[] = { |
|---|
| 1041 | 1127 | &bin_attr_catalog, |
|---|
| 1042 | 1128 | NULL, |
|---|
| 1043 | 1129 | }; |
|---|
| 1044 | 1130 | |
|---|
| 1131 | +static struct attribute *cpumask_attrs[] = { |
|---|
| 1132 | + &dev_attr_cpumask.attr, |
|---|
| 1133 | + NULL, |
|---|
| 1134 | +}; |
|---|
| 1135 | + |
|---|
| 1136 | +static struct attribute_group cpumask_attr_group = { |
|---|
| 1137 | + .attrs = cpumask_attrs, |
|---|
| 1138 | +}; |
|---|
| 1139 | + |
|---|
| 1045 | 1140 | static struct attribute *if_attrs[] = { |
|---|
| 1046 | 1141 | &dev_attr_catalog_len.attr, |
|---|
| 1047 | 1142 | &dev_attr_catalog_version.attr, |
|---|
| 1048 | 1143 | &dev_attr_domains.attr, |
|---|
| 1144 | + &dev_attr_sockets.attr, |
|---|
| 1145 | + &dev_attr_chipspersocket.attr, |
|---|
| 1146 | + &dev_attr_coresperchip.attr, |
|---|
| 1049 | 1147 | NULL, |
|---|
| 1050 | 1148 | }; |
|---|
| 1051 | 1149 | |
|---|
| .. | .. |
|---|
| 1061 | 1159 | &event_desc_group, |
|---|
| 1062 | 1160 | &event_long_desc_group, |
|---|
| 1063 | 1161 | &if_group, |
|---|
| 1162 | + &cpumask_attr_group, |
|---|
| 1064 | 1163 | NULL, |
|---|
| 1065 | 1164 | }; |
|---|
| 1066 | 1165 | |
|---|
| .. | .. |
|---|
| 1305 | 1404 | event_get_reserved3(event)); |
|---|
| 1306 | 1405 | return -EINVAL; |
|---|
| 1307 | 1406 | } |
|---|
| 1308 | | - |
|---|
| 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 | 1407 | |
|---|
| 1318 | 1408 | /* no branch sampling */ |
|---|
| 1319 | 1409 | if (has_branch_stack(event)) |
|---|
| .. | .. |
|---|
| 1567 | 1657 | .start_txn = h_24x7_event_start_txn, |
|---|
| 1568 | 1658 | .commit_txn = h_24x7_event_commit_txn, |
|---|
| 1569 | 1659 | .cancel_txn = h_24x7_event_cancel_txn, |
|---|
| 1660 | + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, |
|---|
| 1570 | 1661 | }; |
|---|
| 1662 | + |
|---|
| 1663 | +static int ppc_hv_24x7_cpu_online(unsigned int cpu) |
|---|
| 1664 | +{ |
|---|
| 1665 | + if (cpumask_empty(&hv_24x7_cpumask)) |
|---|
| 1666 | + cpumask_set_cpu(cpu, &hv_24x7_cpumask); |
|---|
| 1667 | + |
|---|
| 1668 | + return 0; |
|---|
| 1669 | +} |
|---|
| 1670 | + |
|---|
| 1671 | +static int ppc_hv_24x7_cpu_offline(unsigned int cpu) |
|---|
| 1672 | +{ |
|---|
| 1673 | + int target; |
|---|
| 1674 | + |
|---|
| 1675 | + /* Check if exiting cpu is used for collecting 24x7 events */ |
|---|
| 1676 | + if (!cpumask_test_and_clear_cpu(cpu, &hv_24x7_cpumask)) |
|---|
| 1677 | + return 0; |
|---|
| 1678 | + |
|---|
| 1679 | + /* Find a new cpu to collect 24x7 events */ |
|---|
| 1680 | + target = cpumask_last(cpu_active_mask); |
|---|
| 1681 | + |
|---|
| 1682 | + if (target < 0 || target >= nr_cpu_ids) { |
|---|
| 1683 | + pr_err("hv_24x7: CPU hotplug init failed\n"); |
|---|
| 1684 | + return -1; |
|---|
| 1685 | + } |
|---|
| 1686 | + |
|---|
| 1687 | + /* Migrate 24x7 events to the new target */ |
|---|
| 1688 | + cpumask_set_cpu(target, &hv_24x7_cpumask); |
|---|
| 1689 | + perf_pmu_migrate_context(&h_24x7_pmu, cpu, target); |
|---|
| 1690 | + |
|---|
| 1691 | + return 0; |
|---|
| 1692 | +} |
|---|
| 1693 | + |
|---|
| 1694 | +static int hv_24x7_cpu_hotplug_init(void) |
|---|
| 1695 | +{ |
|---|
| 1696 | + return cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE, |
|---|
| 1697 | + "perf/powerpc/hv_24x7:online", |
|---|
| 1698 | + ppc_hv_24x7_cpu_online, |
|---|
| 1699 | + ppc_hv_24x7_cpu_offline); |
|---|
| 1700 | +} |
|---|
| 1571 | 1701 | |
|---|
| 1572 | 1702 | static int hv_24x7_init(void) |
|---|
| 1573 | 1703 | { |
|---|
| .. | .. |
|---|
| 1613 | 1743 | if (r) |
|---|
| 1614 | 1744 | return r; |
|---|
| 1615 | 1745 | |
|---|
| 1746 | + /* init cpuhotplug */ |
|---|
| 1747 | + r = hv_24x7_cpu_hotplug_init(); |
|---|
| 1748 | + if (r) |
|---|
| 1749 | + return r; |
|---|
| 1750 | + |
|---|
| 1616 | 1751 | r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1); |
|---|
| 1617 | 1752 | if (r) |
|---|
| 1618 | 1753 | return r; |
|---|
| 1619 | 1754 | |
|---|
| 1755 | + read_24x7_sys_info(); |
|---|
| 1756 | + |
|---|
| 1620 | 1757 | return 0; |
|---|
| 1621 | 1758 | } |
|---|
| 1622 | 1759 | |
|---|