
From: Qizhi Zhang <zhangqizhi3@h-partners.com> driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICZCFN ---------------------------------------------------------------------- This reverts commit 78684f415d8da8b7064d1c81c458fd0f3abd0708. Signed-off-by: Qizhi Zhang <zhangqizhi3@h-partners.com> --- drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 384 ++++++++++--------- drivers/perf/hisilicon/hisi_uncore_pmu.h | 2 +- 2 files changed, 195 insertions(+), 191 deletions(-) diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index d41a686a3597..00ed571a3030 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -56,9 +56,7 @@ #define L3C_V1_NR_EVENTS 0x59 #define L3C_V2_NR_EVENTS 0xFF -#define L3C_MAX_EXT 2 - -HISI_PMU_EVENT_ATTR_EXTRACTOR(ext, config, 17, 16); +HISI_PMU_EVENT_ATTR_EXTRACTOR(ext, config, 16, 16); HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8); HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11); HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16); @@ -67,11 +65,12 @@ HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config2, 15, 0); struct hisi_l3c_pmu { struct hisi_pmu l3c_pmu; + unsigned long feature; +#define L3C_PMU_FEAT_EXT 0x1 /* MMIO and IRQ resources for extension events */ - void __iomem *ext_base[L3C_MAX_EXT]; - int ext_irq[L3C_MAX_EXT]; - int ext_num; + void __iomem *ext_base; + int ext_irq; }; #define to_hisi_l3c_pmu(_l3c_pmu) \ @@ -81,60 +80,50 @@ struct hisi_l3c_pmu { * The hardware counter idx used in counter enable/disable, * interrupt enable/disable and status check, etc. */ -#define L3C_HW_IDX(_cntr_idx) ((_cntr_idx) % L3C_NR_COUNTERS) - -/* Range of ext counters in used mask. */ -#define L3C_CNTR_EXT_L(_ext) (((_ext) + 1) * L3C_NR_COUNTERS) -#define L3C_CNTR_EXT_H(_ext) (((_ext) + 2) * L3C_NR_COUNTERS) - -struct hisi_l3c_pmu_ext { - bool support_ext; -}; - -static bool support_ext(struct hisi_l3c_pmu *pmu) -{ - struct hisi_l3c_pmu_ext *l3c_pmu_ext = pmu->l3c_pmu.dev_info->private; - - return l3c_pmu_ext->support_ext; -} +#define L3C_HW_IDX(_idx) ((_idx) % L3C_NR_COUNTERS) static int hisi_l3c_pmu_get_event_idx(struct perf_event *event) { struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); - struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); unsigned long *used_mask = l3c_pmu->pmu_events.used_mask; - int ext = hisi_get_ext(event); + u32 num_counters = l3c_pmu->num_counters; + struct hisi_l3c_pmu *hisi_l3c_pmu; int idx; + hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); + /* * For an L3C PMU that supports extension events, we can monitor - * maximum 2 * num_counters to 3 * num_counters events, depending on - * the number of ext regions supported by hardware. Thus use bit - * [0, num_counters - 1] for normal events and bit - * [ext * num_counters, (ext + 1) * num_counters - 1] for extension - * events. The idx allocation will keep unchanged for normal events and - * we can also use the idx to distinguish whether it's an extension - * event or not. + * maximum 2 * num_counters events. Thus use bit [0, num_counters - 1] + * for normal events and bit [num_counters, 2 * num_counters - 1] for + * extension events. The idx allocation will keep unchanged for normal + * events and we can also use the idx to distinguish whether it's an + * extension event or not. * * Since normal events and extension events locates on the different * address space, save the base address to the event->hw.event_base. */ - if (ext && !support_ext(hisi_l3c_pmu)) - return -EOPNOTSUPP; + if (hisi_get_ext(event)) { + if (!(hisi_l3c_pmu->feature & L3C_PMU_FEAT_EXT)) + return -EOPNOTSUPP; - if (ext) - event->hw.event_base = (unsigned long)hisi_l3c_pmu->ext_base[ext - 1]; - else + event->hw.event_base = (unsigned long)hisi_l3c_pmu->ext_base; + idx = find_next_zero_bit(used_mask, num_counters, L3C_NR_COUNTERS); + } else { event->hw.event_base = (unsigned long)l3c_pmu->base; + idx = find_next_zero_bit(used_mask, L3C_NR_COUNTERS, 0); + if (idx == L3C_NR_COUNTERS) + idx = num_counters; + } - ext -= 1; - idx = find_next_zero_bit(used_mask, L3C_CNTR_EXT_H(ext), L3C_CNTR_EXT_L(ext)); - - if (idx >= L3C_CNTR_EXT_H(ext)) + if (idx == num_counters) return -EAGAIN; set_bit(idx, used_mask); + WARN_ON(hisi_get_ext(event) && idx < L3C_NR_COUNTERS); + WARN_ON(!hisi_get_ext(event) && idx >= L3C_NR_COUNTERS); + return idx; } @@ -333,23 +322,12 @@ static void hisi_l3c_pmu_disable_filter(struct perf_event *event) } } -static int hisi_l3c_pmu_check_filter(struct perf_event *event) -{ - struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); - struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - int ext = hisi_get_ext(event); - - if (ext < 0 || ext > hisi_l3c_pmu->ext_num) - return -EINVAL; - return 0; -} - /* * Select the counter register offset using the counter index */ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx) { - return L3C_CNTR0_LOWER + L3C_HW_IDX(cntr_idx) * 8; + return (L3C_CNTR0_LOWER + (L3C_HW_IDX(cntr_idx) * 8)); } static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu, @@ -386,7 +364,7 @@ static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx, /* Write event code to L3C_EVENT_TYPEx Register */ val = hisi_l3c_pmu_event_readl(hwc, reg); val &= ~(L3C_EVTYPE_NONE << shift); - val |= type << shift; + val |= (type << shift); hisi_l3c_pmu_event_writel(hwc, reg, val); } @@ -394,30 +372,22 @@ static void hisi_l3c_pmu_start_counters(struct hisi_pmu *l3c_pmu) { struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); unsigned long *used_mask = l3c_pmu->pmu_events.used_mask; - unsigned long used_cntr = find_first_bit(used_mask, l3c_pmu->num_counters); u32 val; - int i; /* - * Check if any counter belongs to the normal range (instead of ext - * range). If so, enable it. + * Set perf_enable bit in L3C_PERF_CTRL register to start counting + * for all enabled counters. */ - if (used_cntr < L3C_NR_COUNTERS) { + if (find_first_bit(used_mask, l3c_pmu->num_counters) < L3C_NR_COUNTERS) { val = readl(l3c_pmu->base + L3C_PERF_CTRL); val |= L3C_PERF_CTRL_EN; writel(val, l3c_pmu->base + L3C_PERF_CTRL); } - /* If not, do enable it on ext ranges. */ - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) { - /* Find used counter in this ext range, skip the range if not. */ - used_cntr = find_next_bit(used_mask, L3C_CNTR_EXT_H(i), L3C_CNTR_EXT_L(i)); - if (used_cntr >= L3C_CNTR_EXT_H(i)) - continue; - - val = readl(hisi_l3c_pmu->ext_base[i] + L3C_PERF_CTRL); + if (find_next_bit(used_mask, l3c_pmu->num_counters, L3C_NR_COUNTERS) != l3c_pmu->num_counters) { + val = readl(hisi_l3c_pmu->ext_base + L3C_PERF_CTRL); val |= L3C_PERF_CTRL_EN; - writel(val, hisi_l3c_pmu->ext_base[i] + L3C_PERF_CTRL); + writel(val, hisi_l3c_pmu->ext_base + L3C_PERF_CTRL); } } @@ -425,30 +395,22 @@ static void hisi_l3c_pmu_stop_counters(struct hisi_pmu *l3c_pmu) { struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); unsigned long *used_mask = l3c_pmu->pmu_events.used_mask; - unsigned long used_cntr = find_first_bit(used_mask, l3c_pmu->num_counters); u32 val; - int i; /* - * Check if any counter belongs to the normal range (instead of ext - * range). If so, stop it. + * Clear perf_enable bit in L3C_PERF_CTRL register to stop counting + * for all enabled counters. */ - if (used_cntr < L3C_NR_COUNTERS) { + if (find_first_bit(used_mask, l3c_pmu->num_counters) < L3C_NR_COUNTERS) { val = readl(l3c_pmu->base + L3C_PERF_CTRL); val &= ~(L3C_PERF_CTRL_EN); writel(val, l3c_pmu->base + L3C_PERF_CTRL); } - /* If not, do stop it on ext ranges. */ - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) { - /* Find used counter in this ext range, skip the range if not. */ - used_cntr = find_next_bit(used_mask, L3C_CNTR_EXT_H(i), L3C_CNTR_EXT_L(i)); - if (used_cntr >= L3C_CNTR_EXT_H(i)) - continue; - - val = readl(hisi_l3c_pmu->ext_base[i] + L3C_PERF_CTRL); - val &= ~L3C_PERF_CTRL_EN; - writel(val, hisi_l3c_pmu->ext_base[i] + L3C_PERF_CTRL); + if (find_next_bit(used_mask, l3c_pmu->num_counters, L3C_NR_COUNTERS) != l3c_pmu->num_counters) { + val = readl(hisi_l3c_pmu->ext_base + L3C_PERF_CTRL); + val &= ~(L3C_PERF_CTRL_EN); + writel(val, hisi_l3c_pmu->ext_base + L3C_PERF_CTRL); } } @@ -459,7 +421,7 @@ static void hisi_l3c_pmu_enable_counter(struct hisi_pmu *l3c_pmu, /* Enable counter index in L3C_EVENT_CTRL register */ val = hisi_l3c_pmu_event_readl(hwc, L3C_EVENT_CTRL); - val |= 1 << L3C_HW_IDX(hwc->idx); + val |= (1 << L3C_HW_IDX(hwc->idx)); hisi_l3c_pmu_event_writel(hwc, L3C_EVENT_CTRL, val); } @@ -492,25 +454,18 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu, val = hisi_l3c_pmu_event_readl(hwc, L3C_INT_MASK); /* Write 1 to mask interrupt */ - val |= 1 << L3C_HW_IDX(hwc->idx); + val |= (1 << L3C_HW_IDX(hwc->idx)); hisi_l3c_pmu_event_writel(hwc, L3C_INT_MASK, val); } static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu) { struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - u32 ext_int, status, status_ext = 0; - int i; + u32 status, status_ext = 0; status = readl(l3c_pmu->base + L3C_INT_STATUS); - - if (!support_ext(hisi_l3c_pmu)) - return status; - - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) { - ext_int = readl(hisi_l3c_pmu->ext_base[i] + L3C_INT_STATUS); - status_ext |= ext_int << (L3C_NR_COUNTERS * i); - } + if (hisi_l3c_pmu->feature & L3C_PMU_FEAT_EXT) + status_ext = readl(hisi_l3c_pmu->ext_base + L3C_INT_STATUS); return status | (status_ext << L3C_NR_COUNTERS); } @@ -541,6 +496,10 @@ static int hisi_l3c_pmu_init_data(struct platform_device *pdev, return -EINVAL; } + l3c_pmu->dev_info = device_get_match_data(&pdev->dev); + if (!l3c_pmu->dev_info) + return -ENODEV; + l3c_pmu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(l3c_pmu->base)) { dev_err(&pdev->dev, "ioremap failed for l3c_pmu resource\n"); @@ -555,44 +514,35 @@ static int hisi_l3c_pmu_init_data(struct platform_device *pdev, static int hisi_l3c_pmu_init_ext(struct hisi_pmu *l3c_pmu, struct platform_device *pdev) { struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - int ret, irq, ext_num, i; char *irqname; + int ret, irq; - /* HiSilicon L3C PMU supporting ext should have more than 1 irq resources. */ - ext_num = platform_irq_count(pdev); - if (ext_num < L3C_MAX_EXT) - return -ENODEV; + hisi_l3c_pmu->ext_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(hisi_l3c_pmu->ext_base)) + return PTR_ERR(hisi_l3c_pmu->ext_base); + irq = platform_get_irq(pdev, 1); /* - * The number of ext supported equals the number of irq - 1, since one - * of the irqs belongs to the normal part of PMU. + * We may don't need to handle -EPROBDEFER since we should have already + * handle it when probling irq[0]. */ - hisi_l3c_pmu->ext_num = ext_num - 1; - - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) { - hisi_l3c_pmu->ext_base[i] = devm_platform_ioremap_resource(pdev, i + 1); - if (IS_ERR(hisi_l3c_pmu->ext_base[i])) - return PTR_ERR(hisi_l3c_pmu->ext_base[i]); - - irq = platform_get_irq(pdev, i + 1); - if (irq < 0) - return irq; - - irqname = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s ext%d", - dev_name(&pdev->dev), i + 1); - if (!irqname) - return -ENOMEM; - - ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr, - IRQF_NOBALANCING | IRQF_NO_THREAD, - irqname, l3c_pmu); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, - "Fail to request EXT IRQ: %d.\n", irq); - - hisi_l3c_pmu->ext_irq[i] = irq; + if (irq < 0) + return irq; + + irqname = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s ext", dev_name(&pdev->dev)); + if (!irqname) + return -ENOMEM; + + ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr, + IRQF_NOBALANCING | IRQF_NO_THREAD, + irqname, l3c_pmu); + if (ret < 0) { + dev_err(&pdev->dev, + "Fail to request EXT IRQ: %d ret: %d.\n", irq, ret); + return ret; } + hisi_l3c_pmu->ext_irq = irq; return 0; } @@ -624,6 +574,7 @@ static struct attribute *hisi_l3c_pmu_v3_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-7"), HISI_PMU_FORMAT_ATTR(ext, "config:16"), HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"), + HISI_PMU_FORMAT_ATTR(tt_cacheable, "config1:17"), HISI_PMU_FORMAT_ATTR(tt_core, "config2:0-15"), NULL }; @@ -673,22 +624,93 @@ struct hisi_l3c_pmu_v3_event { bool ext; }; +static ssize_t hisi_l3c_pmu_event_show(struct device *dev, + struct device_attribute *attr, char *page) +{ + struct hisi_l3c_pmu_v3_event *event; + struct dev_ext_attribute *eattr; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + event = eattr->var; + + if (!event->ext) + return sysfs_emit(page, "event=0x%lx\n", event->event_id); + else + return sysfs_emit(page, "event=0x%lx,ext=1\n", event->event_id); +} + +#define HISI_L3C_PMU_EVENT_ATTR(_name, _event, _ext) \ +static struct hisi_l3c_pmu_v3_event hisi_l3c_##_name = { _event, _ext }; \ +static struct dev_ext_attribute hisi_l3c_##_name##_attr = \ + { __ATTR(_name, 0444, hisi_l3c_pmu_event_show, NULL), (void *) &hisi_l3c_##_name } + +HISI_L3C_PMU_EVENT_ATTR(rd_cpipe, 0x00, true); +HISI_L3C_PMU_EVENT_ATTR(rd_hit_cpipe, 0x01, true); +HISI_L3C_PMU_EVENT_ATTR(wr_cpipe, 0x02, true); +HISI_L3C_PMU_EVENT_ATTR(wr_hit_cpipe, 0x03, true); +HISI_L3C_PMU_EVENT_ATTR(io_rd_cpipe, 0x04, true); +HISI_L3C_PMU_EVENT_ATTR(io_rd_hit_cpipe, 0x05, true); +HISI_L3C_PMU_EVENT_ATTR(io_wr_cpipe, 0x06, true); +HISI_L3C_PMU_EVENT_ATTR(io_wr_hit_cpipe, 0x07, true); +HISI_L3C_PMU_EVENT_ATTR(victim_num, 0x0c, true); +HISI_L3C_PMU_EVENT_ATTR(rd_spipe, 0x18, false); +HISI_L3C_PMU_EVENT_ATTR(rd_hit_spipe, 0x19, false); +HISI_L3C_PMU_EVENT_ATTR(wr_spipe, 0x1a, false); +HISI_L3C_PMU_EVENT_ATTR(wr_hit_spipe, 0x1b, false); +HISI_L3C_PMU_EVENT_ATTR(io_rd_spipe, 0x1c, false); +HISI_L3C_PMU_EVENT_ATTR(io_rd_hit_spipe, 0x1d, false); +HISI_L3C_PMU_EVENT_ATTR(io_wr_spipe, 0x1e, false); +HISI_L3C_PMU_EVENT_ATTR(io_wr_hit_spipe, 0x1f, false); +HISI_L3C_PMU_EVENT_ATTR(cycles, 0x7f, false); +HISI_L3C_PMU_EVENT_ATTR(l3c_ref, 0xbc, false); +HISI_L3C_PMU_EVENT_ATTR(l3c2ring, 0xbd, true); + static struct attribute *hisi_l3c_pmu_v3_events_attr[] = { - HISI_PMU_EVENT_ATTR(rd_spipe, 0x18), - HISI_PMU_EVENT_ATTR(rd_hit_spipe, 0x19), - HISI_PMU_EVENT_ATTR(wr_spipe, 0x1a), - HISI_PMU_EVENT_ATTR(wr_hit_spipe, 0x1b), - HISI_PMU_EVENT_ATTR(io_rd_spipe, 0x1c), - HISI_PMU_EVENT_ATTR(io_rd_hit_spipe, 0x1d), - HISI_PMU_EVENT_ATTR(io_wr_spipe, 0x1e), - HISI_PMU_EVENT_ATTR(io_wr_hit_spipe, 0x1f), - HISI_PMU_EVENT_ATTR(cycles, 0x7f), - HISI_PMU_EVENT_ATTR(l3c_ref, 0xbc), + &hisi_l3c_rd_cpipe_attr.attr.attr, + &hisi_l3c_rd_hit_cpipe_attr.attr.attr, + &hisi_l3c_wr_cpipe_attr.attr.attr, + &hisi_l3c_wr_hit_cpipe_attr.attr.attr, + &hisi_l3c_io_rd_cpipe_attr.attr.attr, + &hisi_l3c_io_rd_hit_cpipe_attr.attr.attr, + &hisi_l3c_io_wr_cpipe_attr.attr.attr, + &hisi_l3c_io_wr_hit_cpipe_attr.attr.attr, + &hisi_l3c_victim_num_attr.attr.attr, + &hisi_l3c_rd_spipe_attr.attr.attr, + &hisi_l3c_rd_hit_spipe_attr.attr.attr, + &hisi_l3c_wr_spipe_attr.attr.attr, + &hisi_l3c_wr_hit_spipe_attr.attr.attr, + &hisi_l3c_io_rd_spipe_attr.attr.attr, + &hisi_l3c_io_rd_hit_spipe_attr.attr.attr, + &hisi_l3c_io_wr_spipe_attr.attr.attr, + &hisi_l3c_io_wr_hit_spipe_attr.attr.attr, + &hisi_l3c_cycles_attr.attr.attr, + &hisi_l3c_l3c_ref_attr.attr.attr, + &hisi_l3c_l3c2ring_attr.attr.attr, NULL }; +static umode_t hisi_l3c_pmu_v3_events_visible(struct kobject *kobj, + struct attribute *attr, int unused) +{ + struct device *dev = kobj_to_dev(kobj); + struct pmu *pmu = dev_get_drvdata(dev); + struct hisi_pmu *l3c_pmu = to_hisi_pmu(pmu); + struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); + struct hisi_l3c_pmu_v3_event *event; + struct dev_ext_attribute *ext_attr; + + ext_attr = container_of(attr, struct dev_ext_attribute, attr.attr); + event = ext_attr->var; + + if (!event->ext || (hisi_l3c_pmu->feature & L3C_PMU_FEAT_EXT)) + return attr->mode; + + return 0; +} + static const struct attribute_group hisi_l3c_pmu_v3_events_group = { .name = "events", + .is_visible = hisi_l3c_pmu_v3_events_visible, .attrs = hisi_l3c_pmu_v3_events_attr, }; @@ -716,33 +738,23 @@ static const struct attribute_group *hisi_l3c_pmu_v3_attr_groups[] = { NULL }; -static struct hisi_l3c_pmu_ext hisi_l3c_pmu_support_ext = { - .support_ext = true, -}; - -static struct hisi_l3c_pmu_ext hisi_l3c_pmu_not_support_ext = { - .support_ext = false, -}; - static const struct hisi_pmu_dev_info hisi_l3c_pmu_v1 = { .attr_groups = hisi_l3c_pmu_v1_attr_groups, .counter_bits = 48, .check_event = L3C_V1_NR_EVENTS, - .private = &hisi_l3c_pmu_not_support_ext, }; static const struct hisi_pmu_dev_info hisi_l3c_pmu_v2 = { .attr_groups = hisi_l3c_pmu_v2_attr_groups, .counter_bits = 64, .check_event = L3C_V2_NR_EVENTS, - .private = &hisi_l3c_pmu_not_support_ext, }; static const struct hisi_pmu_dev_info hisi_l3c_pmu_v3 = { .attr_groups = hisi_l3c_pmu_v3_attr_groups, .counter_bits = 64, .check_event = L3C_V2_NR_EVENTS, - .private = &hisi_l3c_pmu_support_ext, + .private = (void *) L3C_PMU_FEAT_EXT, }; static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { @@ -760,14 +772,12 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = { .clear_int_status = hisi_l3c_pmu_clear_int_status, .enable_filter = hisi_l3c_pmu_enable_filter, .disable_filter = hisi_l3c_pmu_disable_filter, - .check_filter = hisi_l3c_pmu_check_filter, }; static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev, struct hisi_pmu *l3c_pmu) { struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - struct hisi_l3c_pmu_ext *l3c_pmu_dev_ext; int ret; ret = hisi_l3c_pmu_init_data(pdev, l3c_pmu); @@ -786,17 +796,20 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev, l3c_pmu->dev = &pdev->dev; l3c_pmu->on_cpu = -1; - l3c_pmu_dev_ext = l3c_pmu->dev_info->private; - if (l3c_pmu_dev_ext->support_ext) { + if ((unsigned long)l3c_pmu->dev_info->private & L3C_PMU_FEAT_EXT) { ret = hisi_l3c_pmu_init_ext(l3c_pmu, pdev); - if (ret) - return ret; - /* - * The extension events have their own counters with the - * same number of the normal events counters. So we can - * have at maximum num_counters * 2 events monitored. - */ - l3c_pmu->num_counters += hisi_l3c_pmu->ext_num * L3C_NR_COUNTERS; + if (ret) { + dev_warn(&pdev->dev, "ext event is unavailable, ret = %d\n", ret); + } else { + /* + * The extension events have their own counters with the + * same number of the normal events counters. So we can + * have at maximum num_counters * 2 events monitored. + */ + l3c_pmu->num_counters <<= 1; + + hisi_l3c_pmu->feature |= L3C_PMU_FEAT_EXT; + } } return 0; @@ -816,10 +829,6 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev) l3c_pmu = &hisi_l3c_pmu->l3c_pmu; platform_set_drvdata(pdev, l3c_pmu); - l3c_pmu->dev_info = device_get_match_data(&pdev->dev); - if (!l3c_pmu->dev_info) - return -ENODEV; - ret = hisi_l3c_pmu_dev_probe(pdev, l3c_pmu); if (ret) return ret; @@ -884,47 +893,42 @@ static struct platform_driver hisi_l3c_pmu_driver = { static int hisi_l3c_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) { struct hisi_pmu *l3c_pmu = hlist_entry_safe(node, struct hisi_pmu, node); - struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - int ret, i; + struct hisi_l3c_pmu *hisi_l3c_pmu; + int ret; + + hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); + /* + * Invoking the framework's online function for doing the core logic + * of CPU, interrupt and perf context migrating. Then return directly + * if we don't support L3C_PMU_FEAT_EXT. Otherwise migrate the ext_irq + * using the migrated CPU. + * + * Same logic for CPU offline. + */ ret = hisi_uncore_pmu_online_cpu(cpu, node); - if (ret) + if (!(hisi_l3c_pmu->feature & L3C_PMU_FEAT_EXT) || + l3c_pmu->on_cpu >= nr_cpu_ids) return ret; - /* Avoid L3C pmu not supporting ext from ext irq migrating. */ - if (!support_ext(hisi_l3c_pmu)) - return 0; - - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) - WARN_ON(irq_set_affinity(hisi_l3c_pmu->ext_irq[i], - cpumask_of(l3c_pmu->on_cpu))); - - return 0; + WARN_ON(irq_set_affinity(hisi_l3c_pmu->ext_irq, cpumask_of(l3c_pmu->on_cpu))); + return ret; } static int hisi_l3c_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) { struct hisi_pmu *l3c_pmu = hlist_entry_safe(node, struct hisi_pmu, node); - struct hisi_l3c_pmu *hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); - int ret, i; + struct hisi_l3c_pmu *hisi_l3c_pmu; + int ret; + hisi_l3c_pmu = to_hisi_l3c_pmu(l3c_pmu); ret = hisi_uncore_pmu_offline_cpu(cpu, node); - if (ret) + if (!(hisi_l3c_pmu->feature & L3C_PMU_FEAT_EXT) || + l3c_pmu->on_cpu >= nr_cpu_ids) return ret; - /* If failed to find any available CPU, skip irq migration. */ - if (l3c_pmu->on_cpu < 0) - return 0; - - /* Avoid L3C pmu not supporting ext from ext irq migrating. */ - if (!support_ext(hisi_l3c_pmu)) - return 0; - - for (i = 0; i < hisi_l3c_pmu->ext_num; i++) - WARN_ON(irq_set_affinity(hisi_l3c_pmu->ext_irq[i], - cpumask_of(l3c_pmu->on_cpu))); - - return 0; + WARN_ON(irq_set_affinity(hisi_l3c_pmu->ext_irq, cpumask_of(l3c_pmu->on_cpu))); + return ret; } static int __init hisi_l3c_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index bdf17d1a3099..31225c2ccdce 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -24,7 +24,7 @@ #define pr_fmt(fmt) "hisi_pmu: " fmt #define HISI_PMU_V2 0x30 -#define HISI_MAX_COUNTERS 0x18 +#define HISI_MAX_COUNTERS 0x10 #define to_hisi_pmu(p) (container_of(p, struct hisi_pmu, pmu)) #define HISI_PMU_ATTR(_name, _func, _config) \ -- 2.33.0