diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c index e7e8cb999911604c93fd629e005f85f327c64fa8..d9369310589ba20d53dba7f12273d8579ceb9e2c 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c @@ -22,14 +22,15 @@ #define PA_TT_CTRL 0x1c08 #define PA_TGTID_CTRL 0x1c14 #define PA_SRCID_CTRL 0x1c18 + /* H32 PA interrupt registers */ #define PA_INT_MASK 0x1c70 #define PA_INT_STATUS 0x1c78 #define PA_INT_CLEAR 0x1c7c -/* H60 PA interrupt registers */ + #define H60PA_INT_STATUS 0x1c70 #define H60PA_INT_MASK 0x1c74 -/* End interrupt registers */ + #define PA_EVENT_TYPE0 0x1c80 #define PA_PMU_VERSION 0x1cf0 #define PA_EVENT_CNT0_L 0x1d00 @@ -52,9 +53,9 @@ HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33); HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44); struct hisi_pa_pmu_int_regs { - u32 mask; - u32 clear; - u32 status; + u32 mask_offset; + u32 clear_offset; + u32 status_offset; }; static void hisi_pa_pmu_enable_tracetag(struct perf_event *event) @@ -230,51 +231,44 @@ static void hisi_pa_pmu_disable_counter(struct hisi_pmu *pa_pmu, static void hisi_pa_pmu_enable_counter_int(struct hisi_pmu *pa_pmu, struct hw_perf_event *hwc) { - struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->present; + struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->private; u32 val; /* Write 0 to enable interrupt */ - val = readl(pa_pmu->base + regs->mask); + val = readl(pa_pmu->base + regs->mask_offset); val &= ~(1 << hwc->idx); - writel(val, pa_pmu->base + regs->mask); + writel(val, pa_pmu->base + regs->mask_offset); } static void hisi_pa_pmu_disable_counter_int(struct hisi_pmu *pa_pmu, struct hw_perf_event *hwc) { - struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->present; + struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->private; u32 val; /* Write 1 to mask interrupt */ - val = readl(pa_pmu->base + regs->mask); + val = readl(pa_pmu->base + regs->mask_offset); val |= 1 << hwc->idx; - writel(val, pa_pmu->base + regs->mask); + writel(val, pa_pmu->base + regs->mask_offset); } static u32 hisi_pa_pmu_get_int_status(struct hisi_pmu *pa_pmu) { - struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->present; + struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->private; - return readl(pa_pmu->base + regs->status); + return readl(pa_pmu->base + regs->status_offset); } static void hisi_pa_pmu_clear_int_status(struct hisi_pmu *pa_pmu, int idx) { - struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->present; + struct hisi_pa_pmu_int_regs *regs = pa_pmu->dev_info->private; - writel(1 << idx, pa_pmu->base + regs->clear); + writel(1 << idx, pa_pmu->base + regs->clear_offset); } static int hisi_pa_pmu_init_data(struct platform_device *pdev, struct hisi_pmu *pa_pmu) { - const struct hisi_pmu_dev_info *pa_pmu_info; - int idx; - - pa_pmu_info = device_get_match_data(&pdev->dev); - if (!pa_pmu_info) - return -ENODEV; - /* * As PA PMU is in a SICL, use the SICL_ID and the index ID * to identify the PA PMU. @@ -294,6 +288,10 @@ static int hisi_pa_pmu_init_data(struct platform_device *pdev, pa_pmu->ccl_id = -1; pa_pmu->sccl_id = -1; + pa_pmu->dev_info = device_get_match_data(&pdev->dev); + if (!pa_pmu->dev_info) + return -ENODEV; + pa_pmu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pa_pmu->base)) { dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n"); @@ -302,11 +300,6 @@ static int hisi_pa_pmu_init_data(struct platform_device *pdev, pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION); - idx = hisi_uncore_pmu_ver2idx(pa_pmu); - pa_pmu->dev_info = &pa_pmu_info[idx]; - if (!pa_pmu->dev_info || !pa_pmu->dev_info->name) - return -EINVAL; - return 0; } @@ -382,10 +375,16 @@ static struct attribute *hisi_pa_pmu_identifier_attrs[] = { NULL }; -static const struct attribute_group hisi_pa_pmu_identifier_group = { +static struct attribute_group hisi_pa_pmu_identifier_group = { .attrs = hisi_pa_pmu_identifier_attrs, }; +static struct hisi_pa_pmu_int_regs hisi_pa_pmu_regs = { + .mask_offset = PA_INT_MASK, + .clear_offset = PA_INT_CLEAR, + .status_offset = PA_INT_STATUS, +}; + static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = { &hisi_pa_pmu_v2_format_group, &hisi_pa_pmu_v2_events_group, @@ -394,6 +393,12 @@ static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = { NULL }; +static const struct hisi_pmu_dev_info hisi_h32pa_v2 = { + .name = "pa", + .attr_groups = hisi_pa_pmu_v2_attr_groups, + .private = &hisi_pa_pmu_regs, +}; + static const struct attribute_group *hisi_pa_pmu_v3_attr_groups[] = { &hisi_pa_pmu_v2_format_group, &hisi_pa_pmu_v3_events_group, @@ -402,24 +407,16 @@ static const struct attribute_group *hisi_pa_pmu_v3_attr_groups[] = { NULL }; -static struct hisi_pa_pmu_int_regs hisi_pa_pmu_regs = { - .mask = PA_INT_MASK, - .clear = PA_INT_CLEAR, - .status = PA_INT_STATUS, +static const struct hisi_pmu_dev_info hisi_h32pa_v3 = { + .name = "pa", + .attr_groups = hisi_pa_pmu_v3_attr_groups, + .private = &hisi_pa_pmu_regs, }; -static const struct hisi_pmu_dev_info hisi_h32pa[] = { - [1] = { - .name = "pa", - .attr_groups = hisi_pa_pmu_v2_attr_groups, - .present = &hisi_pa_pmu_regs, - }, - [2] = { - .name = "pa", - .attr_groups = hisi_pa_pmu_v3_attr_groups, - .present = &hisi_pa_pmu_regs, - }, - {} +static struct hisi_pa_pmu_int_regs hisi_h60pa_pmu_regs = { + .mask_offset = H60PA_INT_MASK, + .clear_offset = H60PA_INT_STATUS, /* Clear on write */ + .status_offset = H60PA_INT_STATUS, }; static const struct attribute_group *hisi_h60pa_pmu_attr_groups[] = { @@ -430,19 +427,10 @@ static const struct attribute_group *hisi_h60pa_pmu_attr_groups[] = { NULL }; -static struct hisi_pa_pmu_int_regs hisi_h60pa_pmu_regs = { - .mask = H60PA_INT_MASK, - .clear = H60PA_INT_STATUS, /* Clear on write */ - .status = H60PA_INT_STATUS, -}; - -static const struct hisi_pmu_dev_info hisi_h60pa[] = { - [1] = { - .name = "h60pa", - .attr_groups = hisi_h60pa_pmu_attr_groups, - .present = &hisi_h60pa_pmu_regs, - }, - {} +static const struct hisi_pmu_dev_info hisi_h60pa = { + .name = "h60pa", + .attr_groups = hisi_h60pa_pmu_attr_groups, + .private = &hisi_h60pa_pmu_regs, }; static const struct hisi_uncore_ops hisi_uncore_pa_ops = { @@ -537,8 +525,9 @@ static int hisi_pa_pmu_remove(struct platform_device *pdev) } static const struct acpi_device_id hisi_pa_pmu_acpi_match[] = { - { "HISI0273", (kernel_ulong_t)hisi_h32pa }, - { "HISI0274", (kernel_ulong_t)hisi_h60pa }, + { "HISI0273", (kernel_ulong_t)&hisi_h32pa_v2 }, + { "HISI0275", (kernel_ulong_t)&hisi_h32pa_v3 }, + { "HISI0274", (kernel_ulong_t)&hisi_h60pa }, {} }; MODULE_DEVICE_TABLE(acpi, hisi_pa_pmu_acpi_match); diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index 0fb9c2ed05029f7556dbf725e4b894baa8aedf00..80e6f16d585fa22d4a62068788ee35b4ae519bbf 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -225,9 +225,8 @@ int hisi_uncore_pmu_event_init(struct perf_event *event) hwc->idx = -1; hwc->config_base = event->attr.config; - if (hisi_pmu->ops->check_format) - if (hisi_pmu->ops->check_format(event)) - return -EINVAL; + if (hisi_pmu->ops->check_filter && hisi_pmu->ops->check_filter(event)) + return -EINVAL; /* Enforce to use the same CPU for all events in this PMU */ event->cpu = hisi_pmu->on_cpu; diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index 88106c84119a779f0dc69f1e60a332603176d3ec..9cf06c80acf45a812042702ef8faaf70472a119a 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -23,6 +23,7 @@ #undef pr_fmt #define pr_fmt(fmt) "hisi_pmu: " fmt +#define HISI_PMU_V2 0x30 #define HISI_MAX_COUNTERS 0x10 #define to_hisi_pmu(p) (container_of(p, struct hisi_pmu, pmu)) @@ -42,13 +43,6 @@ return FIELD_GET(GENMASK_ULL(hi, lo), event->attr.config); \ } -enum hisi_pmu_version { - HISI_PMU_V1, - HISI_PMU_V2 = 0x30, - HISI_PMU_V3 = 0x40, - HISI_PMU_MAX -}; - #define HISI_GET_EVENTID(ev) (ev->hw.config_base & 0xff) #define HISI_PMU_EVTYPE_BITS 8 @@ -57,7 +51,7 @@ enum hisi_pmu_version { struct hisi_pmu; struct hisi_uncore_ops { - int (*check_format)(struct perf_event *event); + int (*check_filter)(struct perf_event *event); void (*write_evtype)(struct hisi_pmu *, int, u32); int (*get_event_idx)(struct perf_event *); u64 (*read_counter)(struct hisi_pmu *, struct hw_perf_event *); @@ -78,7 +72,7 @@ struct hisi_uncore_ops { struct hisi_pmu_dev_info { const char *name; const struct attribute_group **attr_groups; - void *present; + void *private; }; struct hisi_pmu_hwevents { @@ -112,7 +106,7 @@ struct hisi_pmu { int counter_bits; /* check event code range */ int check_event; - enum hisi_pmu_version identifier; + u32 identifier; }; int hisi_uncore_pmu_get_event_idx(struct perf_event *event); @@ -142,22 +136,4 @@ int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu, struct platform_device *pdev); void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module); - -int hisi_uncore_pmu_ver2idx(struct hisi_pmu *pmu) -{ - int idx; - - switch (pmu->identifier) { - case HISI_PMU_V1: - idx = 0; break; - case HISI_PMU_V2: - idx = 1; break; - case HISI_PMU_V3: - /* When running on later version, returns the largest supported version */ - default: - idx = 2; - } - - return idx; -} #endif /* __HISI_UNCORE_PMU_H__ */ diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c index ff9c63f66abc3f6aee34c4ed308255bf3cc18f17..63da05e5831c1f98d9aef4ee2fbaddf223ae8297 100644 --- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c @@ -4,7 +4,7 @@ * * Copyright (C) 2023 HiSilicon Limited * - * This code is based on the uncore PMUs like arm-cci and arm-ccn. + * This code is based on the uncore PMUs like hisi_uncore_l3c_pmu. */ #include #include @@ -34,11 +34,9 @@ static enum cpuhp_state hisi_uc_pmu_online; #define HISI_UC_EVENT_URING_MSK GENMASK(28, 27) #define HISI_UC_EVENT_GLB_EN BIT(26) #define HISI_UC_VERSION_REG 0x1cf0 -#define HISI_UC_EVTYPE0_REG 0x1d00 -#define HISI_UC_EVTYPE_REG(n) (HISI_UC_EVTYPE0_REG + (n) * 4) +#define HISI_UC_EVTYPE_REGn(n) (0x1d00 + (n) * 4) #define HISI_UC_EVTYPE_MASK GENMASK(7, 0) -#define HISI_UC_CNTR0_REG 0x1e00 -#define HISI_UC_CNTR_REG(n) (HISI_UC_CNTR0_REG + (n) * 8) +#define HISI_UC_CNTR_REGn(n) (0x1e00 + (n) * 8) #define HISI_UC_NR_COUNTERS 0x8 #define HISI_UC_V2_NR_EVENTS 0xFF @@ -53,13 +51,13 @@ HISI_PMU_EVENT_ATTR_EXTRACTOR(uring_channel, config1, 5, 4); HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid, config1, 19, 6); HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_en, config1, 20, 20); -static int hisi_uc_pmu_check_format(struct perf_event *event) +static int hisi_uc_pmu_check_filter(struct perf_event *event) { struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu); if (hisi_get_srcid_en(event) && !hisi_get_rd_req_en(event)) { dev_err(uc_pmu->dev, - "Failed to set srcid: depending on read request enabled!\n"); + "rcid_en depends on rd_req_en being enabled!\n"); return -EINVAL; } @@ -237,10 +235,10 @@ static void hisi_uc_pmu_write_evtype(struct hisi_pmu *uc_pmu, int idx, u32 type) * There are 2 32-bit event select registers for the * 8 hardware counters, each event code is 8-bit wide. */ - val = readl(uc_pmu->base + HISI_UC_EVTYPE_REG(idx / 4)); + val = readl(uc_pmu->base + HISI_UC_EVTYPE_REGn(idx / 4)); val &= ~(HISI_UC_EVTYPE_MASK << HISI_PMU_EVTYPE_SHIFT(idx)); val |= (type << HISI_PMU_EVTYPE_SHIFT(idx)); - writel(val, uc_pmu->base + HISI_UC_EVTYPE_REG(idx / 4)); + writel(val, uc_pmu->base + HISI_UC_EVTYPE_REGn(idx / 4)); } static void hisi_uc_pmu_start_counters(struct hisi_pmu *uc_pmu) @@ -286,13 +284,13 @@ static void hisi_uc_pmu_disable_counter(struct hisi_pmu *uc_pmu, static u64 hisi_uc_pmu_read_counter(struct hisi_pmu *uc_pmu, struct hw_perf_event *hwc) { - return readq(uc_pmu->base + HISI_UC_CNTR_REG(hwc->idx)); + return readq(uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); } static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu, struct hw_perf_event *hwc, u64 val) { - writeq(val, uc_pmu->base + HISI_UC_CNTR_REG(hwc->idx)); + writeq(val, uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx)); } static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu *uc_pmu, @@ -301,7 +299,6 @@ static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu *uc_pmu, u32 val; val = readl(uc_pmu->base + HISI_UC_INT_MASK_REG); - /* Write 0 to enable interrupt */ val &= ~(1 << hwc->idx); writel(val, uc_pmu->base + HISI_UC_INT_MASK_REG); } @@ -312,7 +309,6 @@ static void hisi_uc_pmu_disable_counter_int(struct hisi_pmu *uc_pmu, u32 val; val = readl(uc_pmu->base + HISI_UC_INT_MASK_REG); - /* Write 1 to mask interrupt */ val |= (1 << hwc->idx); writel(val, uc_pmu->base + HISI_UC_INT_MASK_REG); } @@ -331,8 +327,9 @@ static int hisi_uc_pmu_init_data(struct platform_device *pdev, struct hisi_pmu *uc_pmu) { /* - * Use the SCCL_ID and CCL_ID to identify the UC PMU, while - * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1]. + * Use SCCL (Super CPU Cluster) ID and CCL (CPU Cluster) ID to + * identify the topology information of UC PMU devices in the chip. + * They have some CCLs per SCCL and then 4 UC PMU per CCL. */ if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id", &uc_pmu->sccl_id)) { @@ -434,7 +431,7 @@ static const struct attribute_group *hisi_uc_pmu_attr_groups[] = { }; static const struct hisi_uncore_ops hisi_uncore_uc_pmu_ops = { - .check_format = hisi_uc_pmu_check_format, + .check_filter = hisi_uc_pmu_check_filter, .write_evtype = hisi_uc_pmu_write_evtype, .get_event_idx = hisi_uncore_pmu_get_event_idx, .start_counters = hisi_uc_pmu_start_counters, @@ -537,6 +534,11 @@ static struct platform_driver hisi_uc_pmu_driver = { .driver = { .name = "hisi_uc_pmu", .acpi_match_table = hisi_uc_pmu_acpi_match, + /* + * We have not worked out a safe bind/unbind process, + * Forcefully unbinding during sampling will lead to a + * kernel panic, so this is not supported yet. + */ .suppress_bind_attrs = true, }, .probe = hisi_uc_pmu_probe,