mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-04 08:08:54 +00:00
Merge branch 'for-next/perf' into for-next/core
* for-next/perf: drivers/perf: arm_spe: Fix consistency of SYS_PMSCR_EL1.CX perf: RISC-V: Add of_node_put() when breaking out of for_each_of_cpu_node() docs: perf: Include hns3-pmu.rst in toctree to fix 'htmldocs' WARNING drivers/perf: hisi: add driver for HNS3 PMU drivers/perf: hisi: Add description for HNS3 PMU driver drivers/perf: riscv_pmu_sbi: perf format perf/arm-cci: Use the bitmap API to allocate bitmaps drivers/perf: riscv_pmu: Add riscv pmu pm notifier perf: hisi: Extract hisi_pmu_init perf/marvell_cn10k: Fix TAD PMU register offset perf/marvell_cn10k: Remove useless license text when SPDX-License-Identifier is already used arm64: cpufeature: Allow different PMU versions in ID_DFR0_EL1 perf/arm-cci: fix typo in comment drivers/perf:Directly use ida_alloc()/free() drivers/perf: Directly use ida_alloc()/free()
This commit is contained in:
commit
288e21b6b2
23 changed files with 1993 additions and 105 deletions
136
Documentation/admin-guide/perf/hns3-pmu.rst
Normal file
136
Documentation/admin-guide/perf/hns3-pmu.rst
Normal file
|
@ -0,0 +1,136 @@
|
|||
======================================
|
||||
HNS3 Performance Monitoring Unit (PMU)
|
||||
======================================
|
||||
|
||||
HNS3(HiSilicon network system 3) Performance Monitoring Unit (PMU) is an
|
||||
End Point device to collect performance statistics of HiSilicon SoC NIC.
|
||||
On Hip09, each SICL(Super I/O cluster) has one PMU device.
|
||||
|
||||
HNS3 PMU supports collection of performance statistics such as bandwidth,
|
||||
latency, packet rate and interrupt rate.
|
||||
|
||||
Each HNS3 PMU supports 8 hardware events.
|
||||
|
||||
HNS3 PMU driver
|
||||
===============
|
||||
|
||||
The HNS3 PMU driver registers a perf PMU with the name of its sicl id.::
|
||||
|
||||
/sys/devices/hns3_pmu_sicl_<sicl_id>
|
||||
|
||||
PMU driver provides description of available events, filter modes, format,
|
||||
identifier and cpumask in sysfs.
|
||||
|
||||
The "events" directory describes the event code of all supported events
|
||||
shown in perf list.
|
||||
|
||||
The "filtermode" directory describes the supported filter modes of each
|
||||
event.
|
||||
|
||||
The "format" directory describes all formats of the config (events) and
|
||||
config1 (filter options) fields of the perf_event_attr structure.
|
||||
|
||||
The "identifier" file shows version of PMU hardware device.
|
||||
|
||||
The "bdf_min" and "bdf_max" files show the supported bdf range of each
|
||||
pmu device.
|
||||
|
||||
The "hw_clk_freq" file shows the hardware clock frequency of each pmu
|
||||
device.
|
||||
|
||||
Example usage of checking event code and subevent code::
|
||||
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_time
|
||||
config=0x00204
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_packet_num
|
||||
config=0x10204
|
||||
|
||||
Each performance statistic has a pair of events to get two values to
|
||||
calculate real performance data in userspace.
|
||||
|
||||
The bits 0~15 of config (here 0x0204) are the true hardware event code. If
|
||||
two events have same value of bits 0~15 of config, that means they are
|
||||
event pair. And the bit 16 of config indicates getting counter 0 or
|
||||
counter 1 of hardware event.
|
||||
|
||||
After getting two values of event pair in usersapce, the formula of
|
||||
computation to calculate real performance data is:::
|
||||
|
||||
counter 0 / counter 1
|
||||
|
||||
Example usage of checking supported filter mode::
|
||||
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/filtermode/bw_ssu_rpu_byte_num
|
||||
filter mode supported: global/port/port-tc/func/func-queue/
|
||||
|
||||
Example usage of perf::
|
||||
|
||||
$# perf list
|
||||
hns3_pmu_sicl_0/bw_ssu_rpu_byte_num/ [kernel PMU event]
|
||||
hns3_pmu_sicl_0/bw_ssu_rpu_time/ [kernel PMU event]
|
||||
------------------------------------------
|
||||
|
||||
$# perf stat -g -e hns3_pmu_sicl_0/bw_ssu_rpu_byte_num,global=1/ -e hns3_pmu_sicl_0/bw_ssu_rpu_time,global=1/ -I 1000
|
||||
or
|
||||
$# perf stat -g -e hns3_pmu_sicl_0/config=0x00002,global=1/ -e hns3_pmu_sicl_0/config=0x10002,global=1/ -I 1000
|
||||
|
||||
|
||||
Filter modes
|
||||
--------------
|
||||
|
||||
1. global mode
|
||||
PMU collect performance statistics for all HNS3 PCIe functions of IO DIE.
|
||||
Set the "global" filter option to 1 will enable this mode.
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,global=1/ -I 1000
|
||||
|
||||
2. port mode
|
||||
PMU collect performance statistic of one whole physical port. The port id
|
||||
is same as mac id. The "tc" filter option must be set to 0xF in this mode,
|
||||
here tc stands for traffic class.
|
||||
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,port=0,tc=0xF/ -I 1000
|
||||
|
||||
3. port-tc mode
|
||||
PMU collect performance statistic of one tc of physical port. The port id
|
||||
is same as mac id. The "tc" filter option must be set to 0 ~ 7 in this
|
||||
mode.
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,port=0,tc=0/ -I 1000
|
||||
|
||||
4. func mode
|
||||
PMU collect performance statistic of one PF/VF. The function id is BDF of
|
||||
PF/VF, its conversion formula::
|
||||
|
||||
func = (bus << 8) + (device << 3) + (function)
|
||||
|
||||
for example:
|
||||
BDF func
|
||||
35:00.0 0x3500
|
||||
35:00.1 0x3501
|
||||
35:01.0 0x3508
|
||||
|
||||
In this mode, the "queue" filter option must be set to 0xFFFF.
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,bdf=0x3500,queue=0xFFFF/ -I 1000
|
||||
|
||||
5. func-queue mode
|
||||
PMU collect performance statistic of one queue of PF/VF. The function id
|
||||
is BDF of PF/VF, the "queue" filter option must be set to the exact queue
|
||||
id of function.
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,bdf=0x3500,queue=0/ -I 1000
|
||||
|
||||
6. func-intr mode
|
||||
PMU collect performance statistic of one interrupt of PF/VF. The function
|
||||
id is BDF of PF/VF, the "intr" filter option must be set to the exact
|
||||
interrupt id of function.
|
||||
Example usage of perf::
|
||||
|
||||
$# perf stat -a -e hns3_pmu_sicl_0/config=0x00301,bdf=0x3500,intr=0/ -I 1000
|
|
@ -9,6 +9,7 @@ Performance monitor support
|
|||
|
||||
hisi-pmu
|
||||
hisi-pcie-pmu
|
||||
hns3-pmu
|
||||
imx-ddr
|
||||
qcom_l2_pmu
|
||||
qcom_l3_pmu
|
||||
|
|
|
@ -8944,6 +8944,12 @@ F: Documentation/admin-guide/perf/hisi-pcie-pmu.rst
|
|||
F: Documentation/admin-guide/perf/hisi-pmu.rst
|
||||
F: drivers/perf/hisilicon
|
||||
|
||||
HISILICON HNS3 PMU DRIVER
|
||||
M: Guangbin Huang <huangguangbin2@huawei.com>
|
||||
S: Supported
|
||||
F: Documentation/admin-guide/perf/hns3-pmu.rst
|
||||
F: drivers/perf/hisilicon/hns3_pmu.c
|
||||
|
||||
HISILICON QM AND ZIP Controller DRIVER
|
||||
M: Zhou Wang <wangzhou1@hisilicon.com>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
|
|
|
@ -562,7 +562,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = {
|
|||
|
||||
static const struct arm64_ftr_bits ftr_id_dfr0[] = {
|
||||
/* [31:28] TraceFilt */
|
||||
S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_PERFMON_SHIFT, 4, 0xf),
|
||||
S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_PERFMON_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MPROFDBG_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MMAPTRC_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_COPTRC_SHIFT, 4, 0),
|
||||
|
|
|
@ -1139,7 +1139,7 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
|
|||
|
||||
/*
|
||||
* To handle interrupt latency, we always reprogram the period
|
||||
* regardlesss of PERF_EF_RELOAD.
|
||||
* regardless of PERF_EF_RELOAD.
|
||||
*/
|
||||
if (pmu_flags & PERF_EF_RELOAD)
|
||||
WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
|
||||
|
@ -1261,7 +1261,7 @@ static int validate_group(struct perf_event *event)
|
|||
*/
|
||||
.used_mask = mask,
|
||||
};
|
||||
memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
|
||||
bitmap_zero(mask, cci_pmu->num_cntrs);
|
||||
|
||||
if (!validate_event(event->pmu, &fake_pmu, leader))
|
||||
return -EINVAL;
|
||||
|
@ -1629,10 +1629,9 @@ static struct cci_pmu *cci_pmu_alloc(struct device *dev)
|
|||
GFP_KERNEL);
|
||||
if (!cci_pmu->hw_events.events)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
cci_pmu->hw_events.used_mask = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
|
||||
sizeof(*cci_pmu->hw_events.used_mask),
|
||||
GFP_KERNEL);
|
||||
cci_pmu->hw_events.used_mask = devm_bitmap_zalloc(dev,
|
||||
CCI_PMU_MAX_HW_CNTRS(model),
|
||||
GFP_KERNEL);
|
||||
if (!cci_pmu->hw_events.used_mask)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
|
@ -1250,7 +1250,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
|
|||
ccn->dt.cmp_mask[CCN_IDX_MASK_OPCODE].h = ~(0x1f << 9);
|
||||
|
||||
/* Get a convenient /sys/event_source/devices/ name */
|
||||
ccn->dt.id = ida_simple_get(&arm_ccn_pmu_ida, 0, 0, GFP_KERNEL);
|
||||
ccn->dt.id = ida_alloc(&arm_ccn_pmu_ida, GFP_KERNEL);
|
||||
if (ccn->dt.id == 0) {
|
||||
name = "ccn";
|
||||
} else {
|
||||
|
@ -1312,7 +1312,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
|
|||
&ccn->dt.node);
|
||||
error_set_affinity:
|
||||
error_choose_name:
|
||||
ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
|
||||
ida_free(&arm_ccn_pmu_ida, ccn->dt.id);
|
||||
for (i = 0; i < ccn->num_xps; i++)
|
||||
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
|
||||
writel(0, ccn->dt.base + CCN_DT_PMCR);
|
||||
|
@ -1329,7 +1329,7 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
|
|||
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
|
||||
writel(0, ccn->dt.base + CCN_DT_PMCR);
|
||||
perf_pmu_unregister(&ccn->dt.pmu);
|
||||
ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
|
||||
ida_free(&arm_ccn_pmu_ida, ccn->dt.id);
|
||||
}
|
||||
|
||||
static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn,
|
||||
|
|
|
@ -39,6 +39,24 @@
|
|||
#include <asm/mmu.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
/*
|
||||
* Cache if the event is allowed to trace Context information.
|
||||
* This allows us to perform the check, i.e, perfmon_capable(),
|
||||
* in the context of the event owner, once, during the event_init().
|
||||
*/
|
||||
#define SPE_PMU_HW_FLAGS_CX BIT(0)
|
||||
|
||||
static void set_spe_event_has_cx(struct perf_event *event)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
|
||||
event->hw.flags |= SPE_PMU_HW_FLAGS_CX;
|
||||
}
|
||||
|
||||
static bool get_spe_event_has_cx(struct perf_event *event)
|
||||
{
|
||||
return !!(event->hw.flags & SPE_PMU_HW_FLAGS_CX);
|
||||
}
|
||||
|
||||
#define ARM_SPE_BUF_PAD_BYTE 0
|
||||
|
||||
struct arm_spe_pmu_buf {
|
||||
|
@ -272,7 +290,7 @@ static u64 arm_spe_event_to_pmscr(struct perf_event *event)
|
|||
if (!attr->exclude_kernel)
|
||||
reg |= BIT(SYS_PMSCR_EL1_E1SPE_SHIFT);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
|
||||
if (get_spe_event_has_cx(event))
|
||||
reg |= BIT(SYS_PMSCR_EL1_CX_SHIFT);
|
||||
|
||||
return reg;
|
||||
|
@ -709,10 +727,10 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
|
|||
!(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
set_spe_event_has_cx(event);
|
||||
reg = arm_spe_event_to_pmscr(event);
|
||||
if (!perfmon_capable() &&
|
||||
(reg & (BIT(SYS_PMSCR_EL1_PA_SHIFT) |
|
||||
BIT(SYS_PMSCR_EL1_CX_SHIFT) |
|
||||
BIT(SYS_PMSCR_EL1_PCT_SHIFT))))
|
||||
return -EACCES;
|
||||
|
||||
|
|
|
@ -611,7 +611,7 @@ static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base,
|
|||
.dev = dev,
|
||||
};
|
||||
|
||||
pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL);
|
||||
pmu->id = ida_alloc(&ddr_ida, GFP_KERNEL);
|
||||
return pmu->id;
|
||||
}
|
||||
|
||||
|
@ -765,7 +765,7 @@ static int ddr_perf_probe(struct platform_device *pdev)
|
|||
cpuhp_instance_err:
|
||||
cpuhp_remove_multi_state(pmu->cpuhp_state);
|
||||
cpuhp_state_err:
|
||||
ida_simple_remove(&ddr_ida, pmu->id);
|
||||
ida_free(&ddr_ida, pmu->id);
|
||||
dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -779,7 +779,7 @@ static int ddr_perf_remove(struct platform_device *pdev)
|
|||
|
||||
perf_pmu_unregister(&pmu->pmu);
|
||||
|
||||
ida_simple_remove(&ddr_ida, pmu->id);
|
||||
ida_free(&ddr_ida, pmu->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,3 +14,13 @@ config HISI_PCIE_PMU
|
|||
RCiEP devices.
|
||||
Adds the PCIe PMU into perf events system for monitoring latency,
|
||||
bandwidth etc.
|
||||
|
||||
config HNS3_PMU
|
||||
tristate "HNS3 PERF PMU"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
depends on PCI
|
||||
help
|
||||
Provide support for HNS3 performance monitoring unit (PMU) RCiEP
|
||||
devices.
|
||||
Adds the HNS3 PMU into perf events system for monitoring latency,
|
||||
bandwidth etc.
|
||||
|
|
|
@ -4,3 +4,4 @@ obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
|
|||
hisi_uncore_pa_pmu.o hisi_uncore_cpa_pmu.o
|
||||
|
||||
obj-$(CONFIG_HISI_PCIE_PMU) += hisi_pcie_pmu.o
|
||||
obj-$(CONFIG_HNS3_PMU) += hns3_pmu.o
|
||||
|
|
|
@ -516,21 +516,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
|
|||
"hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
|
||||
ddrc_pmu->index_id);
|
||||
|
||||
ddrc_pmu->pmu = (struct pmu) {
|
||||
.name = name,
|
||||
.module = THIS_MODULE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = hisi_uncore_pmu_event_init,
|
||||
.pmu_enable = hisi_uncore_pmu_enable,
|
||||
.pmu_disable = hisi_uncore_pmu_disable,
|
||||
.add = hisi_uncore_pmu_add,
|
||||
.del = hisi_uncore_pmu_del,
|
||||
.start = hisi_uncore_pmu_start,
|
||||
.stop = hisi_uncore_pmu_stop,
|
||||
.read = hisi_uncore_pmu_read,
|
||||
.attr_groups = ddrc_pmu->pmu_events.attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
};
|
||||
hisi_pmu_init(&ddrc_pmu->pmu, name, ddrc_pmu->pmu_events.attr_groups, THIS_MODULE);
|
||||
|
||||
ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1);
|
||||
if (ret) {
|
||||
|
|
|
@ -519,21 +519,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
|
|||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u",
|
||||
hha_pmu->sccl_id, hha_pmu->index_id);
|
||||
hha_pmu->pmu = (struct pmu) {
|
||||
.name = name,
|
||||
.module = THIS_MODULE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = hisi_uncore_pmu_event_init,
|
||||
.pmu_enable = hisi_uncore_pmu_enable,
|
||||
.pmu_disable = hisi_uncore_pmu_disable,
|
||||
.add = hisi_uncore_pmu_add,
|
||||
.del = hisi_uncore_pmu_del,
|
||||
.start = hisi_uncore_pmu_start,
|
||||
.stop = hisi_uncore_pmu_stop,
|
||||
.read = hisi_uncore_pmu_read,
|
||||
.attr_groups = hha_pmu->pmu_events.attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
};
|
||||
hisi_pmu_init(&hha_pmu->pmu, name, hha_pmu->pmu_events.attr_groups, THIS_MODULE);
|
||||
|
||||
ret = perf_pmu_register(&hha_pmu->pmu, name, -1);
|
||||
if (ret) {
|
||||
|
|
|
@ -557,21 +557,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
|
|||
*/
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
|
||||
l3c_pmu->sccl_id, l3c_pmu->ccl_id);
|
||||
l3c_pmu->pmu = (struct pmu) {
|
||||
.name = name,
|
||||
.module = THIS_MODULE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = hisi_uncore_pmu_event_init,
|
||||
.pmu_enable = hisi_uncore_pmu_enable,
|
||||
.pmu_disable = hisi_uncore_pmu_disable,
|
||||
.add = hisi_uncore_pmu_add,
|
||||
.del = hisi_uncore_pmu_del,
|
||||
.start = hisi_uncore_pmu_start,
|
||||
.stop = hisi_uncore_pmu_stop,
|
||||
.read = hisi_uncore_pmu_read,
|
||||
.attr_groups = l3c_pmu->pmu_events.attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
};
|
||||
hisi_pmu_init(&l3c_pmu->pmu, name, l3c_pmu->pmu_events.attr_groups, THIS_MODULE);
|
||||
|
||||
ret = perf_pmu_register(&l3c_pmu->pmu, name, -1);
|
||||
if (ret) {
|
||||
|
|
|
@ -412,21 +412,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
pa_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = hisi_uncore_pmu_event_init,
|
||||
.pmu_enable = hisi_uncore_pmu_enable,
|
||||
.pmu_disable = hisi_uncore_pmu_disable,
|
||||
.add = hisi_uncore_pmu_add,
|
||||
.del = hisi_uncore_pmu_del,
|
||||
.start = hisi_uncore_pmu_start,
|
||||
.stop = hisi_uncore_pmu_stop,
|
||||
.read = hisi_uncore_pmu_read,
|
||||
.attr_groups = pa_pmu->pmu_events.attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
};
|
||||
|
||||
hisi_pmu_init(&pa_pmu->pmu, name, pa_pmu->pmu_events.attr_groups, THIS_MODULE);
|
||||
ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
|
||||
if (ret) {
|
||||
dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
|
||||
|
|
|
@ -531,4 +531,22 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_offline_cpu);
|
||||
|
||||
void hisi_pmu_init(struct pmu *pmu, const char *name,
|
||||
const struct attribute_group **attr_groups, struct module *module)
|
||||
{
|
||||
pmu->name = name;
|
||||
pmu->module = module;
|
||||
pmu->task_ctx_nr = perf_invalid_context;
|
||||
pmu->event_init = hisi_uncore_pmu_event_init;
|
||||
pmu->pmu_enable = hisi_uncore_pmu_enable;
|
||||
pmu->pmu_disable = hisi_uncore_pmu_disable;
|
||||
pmu->add = hisi_uncore_pmu_add;
|
||||
pmu->del = hisi_uncore_pmu_del;
|
||||
pmu->start = hisi_uncore_pmu_start;
|
||||
pmu->stop = hisi_uncore_pmu_stop;
|
||||
pmu->read = hisi_uncore_pmu_read;
|
||||
pmu->attr_groups = attr_groups;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_pmu_init);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -121,4 +121,6 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
|
|||
int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
|
||||
struct platform_device *pdev);
|
||||
|
||||
void hisi_pmu_init(struct pmu *pmu, const char *name,
|
||||
const struct attribute_group **attr_groups, struct module *module);
|
||||
#endif /* __HISI_UNCORE_PMU_H__ */
|
||||
|
|
|
@ -445,20 +445,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
sllc_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = hisi_uncore_pmu_event_init,
|
||||
.pmu_enable = hisi_uncore_pmu_enable,
|
||||
.pmu_disable = hisi_uncore_pmu_disable,
|
||||
.add = hisi_uncore_pmu_add,
|
||||
.del = hisi_uncore_pmu_del,
|
||||
.start = hisi_uncore_pmu_start,
|
||||
.stop = hisi_uncore_pmu_stop,
|
||||
.read = hisi_uncore_pmu_read,
|
||||
.attr_groups = sllc_pmu->pmu_events.attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
};
|
||||
hisi_pmu_init(&sllc_pmu->pmu, name, sllc_pmu->pmu_events.attr_groups, THIS_MODULE);
|
||||
|
||||
ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
|
||||
if (ret) {
|
||||
|
|
1671
drivers/perf/hisilicon/hns3_pmu.c
Normal file
1671
drivers/perf/hisilicon/hns3_pmu.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,10 +2,6 @@
|
|||
/* Marvell CN10K LLC-TAD perf driver
|
||||
*
|
||||
* Copyright (C) 2021 Marvell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "tad_pmu: " fmt
|
||||
|
@ -18,9 +14,9 @@
|
|||
#include <linux/perf_event.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define TAD_PFC_OFFSET 0x0
|
||||
#define TAD_PFC_OFFSET 0x800
|
||||
#define TAD_PFC(counter) (TAD_PFC_OFFSET | (counter << 3))
|
||||
#define TAD_PRF_OFFSET 0x100
|
||||
#define TAD_PRF_OFFSET 0x900
|
||||
#define TAD_PRF(counter) (TAD_PRF_OFFSET | (counter << 3))
|
||||
#define TAD_PRF_CNTSEL_MASK 0xFF
|
||||
#define TAD_MAX_COUNTERS 8
|
||||
|
@ -100,9 +96,7 @@ static void tad_pmu_event_counter_start(struct perf_event *event, int flags)
|
|||
* which sets TAD()_PRF()[CNTSEL] != 0
|
||||
*/
|
||||
for (i = 0; i < tad_pmu->region_cnt; i++) {
|
||||
reg_val = readq_relaxed(tad_pmu->regions[i].base +
|
||||
TAD_PRF(counter_idx));
|
||||
reg_val |= (event_idx & 0xFF);
|
||||
reg_val = event_idx & 0xFF;
|
||||
writeq_relaxed(reg_val, tad_pmu->regions[i].base +
|
||||
TAD_PRF(counter_idx));
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ u64 riscv_pmu_event_update(struct perf_event *event)
|
|||
return delta;
|
||||
}
|
||||
|
||||
static void riscv_pmu_stop(struct perf_event *event, int flags)
|
||||
void riscv_pmu_stop(struct perf_event *event, int flags)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
|
||||
|
@ -175,7 +175,7 @@ int riscv_pmu_event_set_period(struct perf_event *event)
|
|||
return overflow;
|
||||
}
|
||||
|
||||
static void riscv_pmu_start(struct perf_event *event, int flags)
|
||||
void riscv_pmu_start(struct perf_event *event, int flags)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
|
||||
|
|
|
@ -17,10 +17,30 @@
|
|||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
PMU_FORMAT_ATTR(event, "config:0-47");
|
||||
PMU_FORMAT_ATTR(firmware, "config:63");
|
||||
|
||||
static struct attribute *riscv_arch_formats_attr[] = {
|
||||
&format_attr_event.attr,
|
||||
&format_attr_firmware.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group riscv_pmu_format_group = {
|
||||
.name = "format",
|
||||
.attrs = riscv_arch_formats_attr,
|
||||
};
|
||||
|
||||
static const struct attribute_group *riscv_pmu_attr_groups[] = {
|
||||
&riscv_pmu_format_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
union sbi_pmu_ctr_info {
|
||||
unsigned long value;
|
||||
struct {
|
||||
|
@ -666,12 +686,15 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
|
|||
child = of_get_compatible_child(cpu, "riscv,cpu-intc");
|
||||
if (!child) {
|
||||
pr_err("Failed to find INTC node\n");
|
||||
of_node_put(cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
domain = irq_find_host(child);
|
||||
of_node_put(child);
|
||||
if (domain)
|
||||
if (domain) {
|
||||
of_node_put(cpu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!domain) {
|
||||
pr_err("Failed to find INTC IRQ root domain\n");
|
||||
|
@ -693,6 +716,73 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_PM
|
||||
static int riscv_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
|
||||
void *v)
|
||||
{
|
||||
struct riscv_pmu *rvpmu = container_of(b, struct riscv_pmu, riscv_pm_nb);
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
|
||||
int enabled = bitmap_weight(cpuc->used_hw_ctrs, RISCV_MAX_COUNTERS);
|
||||
struct perf_event *event;
|
||||
int idx;
|
||||
|
||||
if (!enabled)
|
||||
return NOTIFY_OK;
|
||||
|
||||
for (idx = 0; idx < RISCV_MAX_COUNTERS; idx++) {
|
||||
event = cpuc->events[idx];
|
||||
if (!event)
|
||||
continue;
|
||||
|
||||
switch (cmd) {
|
||||
case CPU_PM_ENTER:
|
||||
/*
|
||||
* Stop and update the counter
|
||||
*/
|
||||
riscv_pmu_stop(event, PERF_EF_UPDATE);
|
||||
break;
|
||||
case CPU_PM_EXIT:
|
||||
case CPU_PM_ENTER_FAILED:
|
||||
/*
|
||||
* Restore and enable the counter.
|
||||
*
|
||||
* Requires RCU read locking to be functional,
|
||||
* wrap the call within RCU_NONIDLE to make the
|
||||
* RCU subsystem aware this cpu is not idle from
|
||||
* an RCU perspective for the riscv_pmu_start() call
|
||||
* duration.
|
||||
*/
|
||||
RCU_NONIDLE(riscv_pmu_start(event, PERF_EF_RELOAD));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int riscv_pm_pmu_register(struct riscv_pmu *pmu)
|
||||
{
|
||||
pmu->riscv_pm_nb.notifier_call = riscv_pm_pmu_notify;
|
||||
return cpu_pm_register_notifier(&pmu->riscv_pm_nb);
|
||||
}
|
||||
|
||||
static void riscv_pm_pmu_unregister(struct riscv_pmu *pmu)
|
||||
{
|
||||
cpu_pm_unregister_notifier(&pmu->riscv_pm_nb);
|
||||
}
|
||||
#else
|
||||
static inline int riscv_pm_pmu_register(struct riscv_pmu *pmu) { return 0; }
|
||||
static inline void riscv_pm_pmu_unregister(struct riscv_pmu *pmu) { }
|
||||
#endif
|
||||
|
||||
static void riscv_pmu_destroy(struct riscv_pmu *pmu)
|
||||
{
|
||||
riscv_pm_pmu_unregister(pmu);
|
||||
cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
|
||||
}
|
||||
|
||||
static int pmu_sbi_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct riscv_pmu *pmu = NULL;
|
||||
|
@ -720,6 +810,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
|
|||
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
|
||||
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
|
||||
}
|
||||
pmu->pmu.attr_groups = riscv_pmu_attr_groups;
|
||||
pmu->num_counters = num_counters;
|
||||
pmu->ctr_start = pmu_sbi_ctr_start;
|
||||
pmu->ctr_stop = pmu_sbi_ctr_stop;
|
||||
|
@ -733,14 +824,19 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = riscv_pm_pmu_register(pmu);
|
||||
if (ret)
|
||||
goto out_unregister;
|
||||
|
||||
ret = perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW);
|
||||
if (ret) {
|
||||
cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unregister:
|
||||
riscv_pmu_destroy(pmu);
|
||||
|
||||
out_free:
|
||||
kfree(pmu);
|
||||
return ret;
|
||||
|
|
|
@ -230,6 +230,7 @@ enum cpuhp_state {
|
|||
CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_HISI_PCIE_PMU_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_L2X0_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
|
||||
CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
|
||||
|
|
|
@ -56,9 +56,13 @@ struct riscv_pmu {
|
|||
|
||||
struct cpu_hw_events __percpu *hw_events;
|
||||
struct hlist_node node;
|
||||
struct notifier_block riscv_pm_nb;
|
||||
};
|
||||
|
||||
#define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu))
|
||||
|
||||
void riscv_pmu_start(struct perf_event *event, int flags);
|
||||
void riscv_pmu_stop(struct perf_event *event, int flags);
|
||||
unsigned long riscv_pmu_ctr_read_csr(unsigned long csr);
|
||||
int riscv_pmu_event_set_period(struct perf_event *event);
|
||||
uint64_t riscv_pmu_ctr_get_width_mask(struct perf_event *event);
|
||||
|
|
Loading…
Reference in a new issue