hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/perf/xgene_pmu.c
....@@ -1,26 +1,15 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * APM X-Gene SoC PMU (Performance Monitor Unit)
34 *
45 * Copyright (c) 2016, Applied Micro Circuits Corporation
56 * Author: Hoan Tran <hotran@apm.com>
67 * Tai Nguyen <ttnguyen@apm.com>
7
- *
8
- * This program is free software; you can redistribute it and/or modify it
9
- * under the terms of the GNU General Public License as published by the
10
- * Free Software Foundation; either version 2 of the License, or (at your
11
- * option) any later version.
12
- *
13
- * This program is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License
19
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
208 */
219
2210 #include <linux/acpi.h>
2311 #include <linux/clk.h>
12
+#include <linux/cpuhotplug.h>
2413 #include <linux/cpumask.h>
2514 #include <linux/interrupt.h>
2615 #include <linux/io.h>
....@@ -130,12 +119,14 @@
130119
131120 struct xgene_pmu {
132121 struct device *dev;
122
+ struct hlist_node node;
133123 int version;
134124 void __iomem *pcppmu_csr;
135125 u32 mcb_active_mask;
136126 u32 mc_active_mask;
137127 u32 l3c_active_mask;
138128 cpumask_t cpu;
129
+ int irq;
139130 raw_spinlock_t lock;
140131 const struct xgene_pmu_ops *ops;
141132 struct list_head l3cpmus;
....@@ -914,11 +905,6 @@
914905 if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
915906 return -EINVAL;
916907
917
- /* SOC counters do not have usr/os/guest/host bits */
918
- if (event->attr.exclude_user || event->attr.exclude_kernel ||
919
- event->attr.exclude_host || event->attr.exclude_guest)
920
- return -EINVAL;
921
-
922908 if (event->cpu < 0)
923909 return -EINVAL;
924910 /*
....@@ -1054,7 +1040,6 @@
10541040 static void xgene_perf_stop(struct perf_event *event, int flags)
10551041 {
10561042 struct hw_perf_event *hw = &event->hw;
1057
- u64 config;
10581043
10591044 if (hw->state & PERF_HES_UPTODATE)
10601045 return;
....@@ -1066,7 +1051,6 @@
10661051 if (hw->state & PERF_HES_UPTODATE)
10671052 return;
10681053
1069
- config = hw->config;
10701054 xgene_perf_read(event);
10711055 hw->state |= PERF_HES_UPTODATE;
10721056 }
....@@ -1133,6 +1117,7 @@
11331117 .start = xgene_perf_start,
11341118 .stop = xgene_perf_stop,
11351119 .read = xgene_perf_read,
1120
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
11361121 };
11371122
11381123 /* Hardware counter init */
....@@ -1297,25 +1282,21 @@
12971282 struct platform_device *pdev)
12981283 {
12991284 void __iomem *csw_csr, *mcba_csr, *mcbb_csr;
1300
- struct resource *res;
13011285 unsigned int reg;
13021286
1303
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1304
- csw_csr = devm_ioremap_resource(&pdev->dev, res);
1287
+ csw_csr = devm_platform_ioremap_resource(pdev, 1);
13051288 if (IS_ERR(csw_csr)) {
13061289 dev_err(&pdev->dev, "ioremap failed for CSW CSR resource\n");
13071290 return PTR_ERR(csw_csr);
13081291 }
13091292
1310
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1311
- mcba_csr = devm_ioremap_resource(&pdev->dev, res);
1293
+ mcba_csr = devm_platform_ioremap_resource(pdev, 2);
13121294 if (IS_ERR(mcba_csr)) {
13131295 dev_err(&pdev->dev, "ioremap failed for MCBA CSR resource\n");
13141296 return PTR_ERR(mcba_csr);
13151297 }
13161298
1317
- res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1318
- mcbb_csr = devm_ioremap_resource(&pdev->dev, res);
1299
+ mcbb_csr = devm_platform_ioremap_resource(pdev, 3);
13191300 if (IS_ERR(mcbb_csr)) {
13201301 dev_err(&pdev->dev, "ioremap failed for MCBB CSR resource\n");
13211302 return PTR_ERR(mcbb_csr);
....@@ -1347,13 +1328,11 @@
13471328 struct platform_device *pdev)
13481329 {
13491330 void __iomem *csw_csr;
1350
- struct resource *res;
13511331 unsigned int reg;
13521332 u32 mcb0routing;
13531333 u32 mcb1routing;
13541334
1355
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1356
- csw_csr = devm_ioremap_resource(&pdev->dev, res);
1335
+ csw_csr = devm_platform_ioremap_resource(pdev, 1);
13571336 if (IS_ERR(csw_csr)) {
13581337 dev_err(&pdev->dev, "ioremap failed for CSW CSR resource\n");
13591338 return PTR_ERR(csw_csr);
....@@ -1808,6 +1787,53 @@
18081787 MODULE_DEVICE_TABLE(acpi, xgene_pmu_acpi_match);
18091788 #endif
18101789
1790
+static int xgene_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
1791
+{
1792
+ struct xgene_pmu *xgene_pmu = hlist_entry_safe(node, struct xgene_pmu,
1793
+ node);
1794
+
1795
+ if (cpumask_empty(&xgene_pmu->cpu))
1796
+ cpumask_set_cpu(cpu, &xgene_pmu->cpu);
1797
+
1798
+ /* Overflow interrupt also should use the same CPU */
1799
+ WARN_ON(irq_set_affinity(xgene_pmu->irq, &xgene_pmu->cpu));
1800
+
1801
+ return 0;
1802
+}
1803
+
1804
+static int xgene_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
1805
+{
1806
+ struct xgene_pmu *xgene_pmu = hlist_entry_safe(node, struct xgene_pmu,
1807
+ node);
1808
+ struct xgene_pmu_dev_ctx *ctx;
1809
+ unsigned int target;
1810
+
1811
+ if (!cpumask_test_and_clear_cpu(cpu, &xgene_pmu->cpu))
1812
+ return 0;
1813
+ target = cpumask_any_but(cpu_online_mask, cpu);
1814
+ if (target >= nr_cpu_ids)
1815
+ return 0;
1816
+
1817
+ list_for_each_entry(ctx, &xgene_pmu->mcpmus, next) {
1818
+ perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
1819
+ }
1820
+ list_for_each_entry(ctx, &xgene_pmu->mcbpmus, next) {
1821
+ perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
1822
+ }
1823
+ list_for_each_entry(ctx, &xgene_pmu->l3cpmus, next) {
1824
+ perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
1825
+ }
1826
+ list_for_each_entry(ctx, &xgene_pmu->iobpmus, next) {
1827
+ perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
1828
+ }
1829
+
1830
+ cpumask_set_cpu(target, &xgene_pmu->cpu);
1831
+ /* Overflow interrupt also should use the same CPU */
1832
+ WARN_ON(irq_set_affinity(xgene_pmu->irq, &xgene_pmu->cpu));
1833
+
1834
+ return 0;
1835
+}
1836
+
18111837 static int xgene_pmu_probe(struct platform_device *pdev)
18121838 {
18131839 const struct xgene_pmu_data *dev_data;
....@@ -1816,6 +1842,14 @@
18161842 struct resource *res;
18171843 int irq, rc;
18181844 int version;
1845
+
1846
+ /* Install a hook to update the reader CPU in case it goes offline */
1847
+ rc = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE,
1848
+ "CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE",
1849
+ xgene_pmu_online_cpu,
1850
+ xgene_pmu_offline_cpu);
1851
+ if (rc)
1852
+ return rc;
18191853
18201854 xgene_pmu = devm_kzalloc(&pdev->dev, sizeof(*xgene_pmu), GFP_KERNEL);
18211855 if (!xgene_pmu)
....@@ -1863,10 +1897,9 @@
18631897 }
18641898
18651899 irq = platform_get_irq(pdev, 0);
1866
- if (irq < 0) {
1867
- dev_err(&pdev->dev, "No IRQ resource\n");
1900
+ if (irq < 0)
18681901 return -EINVAL;
1869
- }
1902
+
18701903 rc = devm_request_irq(&pdev->dev, irq, xgene_pmu_isr,
18711904 IRQF_NOBALANCING | IRQF_NO_THREAD,
18721905 dev_name(&pdev->dev), xgene_pmu);
....@@ -1874,6 +1907,8 @@
18741907 dev_err(&pdev->dev, "Could not request IRQ %d\n", irq);
18751908 return rc;
18761909 }
1910
+
1911
+ xgene_pmu->irq = irq;
18771912
18781913 raw_spin_lock_init(&xgene_pmu->lock);
18791914
....@@ -1885,13 +1920,11 @@
18851920 xgene_pmu->mc_active_mask = 0x1;
18861921 }
18871922
1888
- /* Pick one core to use for cpumask attributes */
1889
- cpumask_set_cpu(smp_processor_id(), &xgene_pmu->cpu);
1890
-
1891
- /* Make sure that the overflow interrupt is handled by this CPU */
1892
- rc = irq_set_affinity(irq, &xgene_pmu->cpu);
1923
+ /* Add this instance to the list used by the hotplug callback */
1924
+ rc = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE,
1925
+ &xgene_pmu->node);
18931926 if (rc) {
1894
- dev_err(&pdev->dev, "Failed to set interrupt affinity!\n");
1927
+ dev_err(&pdev->dev, "Error %d registering hotplug", rc);
18951928 return rc;
18961929 }
18971930
....@@ -1899,13 +1932,18 @@
18991932 rc = xgene_pmu_probe_pmu_dev(xgene_pmu, pdev);
19001933 if (rc) {
19011934 dev_err(&pdev->dev, "No PMU perf devices found!\n");
1902
- return rc;
1935
+ goto out_unregister;
19031936 }
19041937
19051938 /* Enable interrupt */
19061939 xgene_pmu->ops->unmask_int(xgene_pmu);
19071940
19081941 return 0;
1942
+
1943
+out_unregister:
1944
+ cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE,
1945
+ &xgene_pmu->node);
1946
+ return rc;
19091947 }
19101948
19111949 static void
....@@ -1926,6 +1964,8 @@
19261964 xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->iobpmus);
19271965 xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcbpmus);
19281966 xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcpmus);
1967
+ cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE,
1968
+ &xgene_pmu->node);
19291969
19301970 return 0;
19311971 }
....@@ -1937,6 +1977,7 @@
19371977 .name = "xgene-pmu",
19381978 .of_match_table = xgene_pmu_of_match,
19391979 .acpi_match_table = ACPI_PTR(xgene_pmu_acpi_match),
1980
+ .suppress_bind_attrs = true,
19401981 },
19411982 };
19421983