Skip to content

Commit 8fa08f8

Browse files
rmurphy-armwilldeacon
authored andcommitted
perf/arm-ni: Add NoC S3 support
NoC S3 and its SI L1 sibling look largely similar to their predecessors, but add the notion of subfeatures to the discovery process, which we now use to find the event muxes for each device node. Plus, as ever, more mildly annoying shuffling around of some of the PMU registers (this time it's the counters...) Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will@kernel.org>
1 parent decc368 commit 8fa08f8

1 file changed

Lines changed: 71 additions & 21 deletions

File tree

drivers/perf/arm-ni.c

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121

2222
#define NI_CHILD_NODE_INFO 0x004
2323
#define NI_CHILD_PTR(n) (0x008 + (n) * 4)
24+
#define NI_NUM_SUB_FEATURES 0x100
25+
#define NI_SUB_FEATURE_TYPE(n) (0x108 + (n) * 8)
26+
#define NI_SUB_FEATURE_PTR(n) (0x10c + (n) * 8)
27+
28+
#define NI_SUB_FEATURE_TYPE_FCU 0x2
2429

2530
#define NI700_PMUSELA 0x00c
2631

@@ -33,9 +38,10 @@
3338
#define NI_PIDR2_VERSION GENMASK(7, 4)
3439

3540
/* PMU node */
36-
#define NI_PMEVCNTR(n) (0x008 + (n) * 8)
37-
#define NI_PMCCNTR_L 0x0f8
38-
#define NI_PMCCNTR_U 0x0fc
41+
#define NI700_PMEVCNTR(n) (0x008 + (n) * 8)
42+
#define NI700_PMCCNTR_L 0x0f8
43+
#define NI_PMEVCNTR(n) (0x200 + (n) * 8)
44+
#define NI_PMCCNTR_L 0x2f8
3945
#define NI_PMEVTYPER(n) (0x400 + (n) * 4)
4046
#define NI_PMEVTYPER_NODE_TYPE GENMASK(12, 9)
4147
#define NI_PMEVTYPER_NODE_ID GENMASK(8, 0)
@@ -66,6 +72,8 @@
6672
enum ni_part {
6773
PART_NI_700 = 0x43b,
6874
PART_NI_710AE = 0x43d,
75+
PART_NOC_S3 = 0x43f,
76+
PART_SI_L1 = 0x455,
6977
};
7078

7179
enum ni_node_type {
@@ -79,6 +87,10 @@ enum ni_node_type {
7987
NI_HSNI,
8088
NI_HMNI,
8189
NI_PMNI,
90+
NI_TSNI,
91+
NI_TMNI,
92+
NI_CMNI = 0x0e,
93+
NI_MCN = 0x63,
8294
};
8395

8496
struct arm_ni_node {
@@ -179,6 +191,9 @@ static struct attribute *arm_ni_event_attrs[] = {
179191
NI_EVENT_ATTR(hsni, NI_HSNI),
180192
NI_EVENT_ATTR(hmni, NI_HMNI),
181193
NI_EVENT_ATTR(pmni, NI_PMNI),
194+
NI_EVENT_ATTR(tsni, NI_TSNI),
195+
NI_EVENT_ATTR(tmni, NI_TMNI),
196+
NI_EVENT_ATTR(cmni, NI_CMNI),
182197
NULL
183198
};
184199

@@ -332,16 +347,16 @@ static int arm_ni_event_init(struct perf_event *event)
332347
return -EINVAL;
333348
}
334349

335-
static u64 arm_ni_read_ccnt(struct arm_ni_cd *cd)
350+
static u64 arm_ni_read_ccnt(void __iomem *pmccntr)
336351
{
337352
u64 l, u_old, u_new;
338353
int retries = 3; /* 1st time unlucky, 2nd improbable, 3rd just broken */
339354

340-
u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U);
355+
u_new = readl_relaxed(pmccntr + 4);
341356
do {
342357
u_old = u_new;
343-
l = readl_relaxed(cd->pmu_base + NI_PMCCNTR_L);
344-
u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U);
358+
l = readl_relaxed(pmccntr);
359+
u_new = readl_relaxed(pmccntr + 4);
345360
} while (u_new != u_old && --retries);
346361
WARN_ON(!retries);
347362

@@ -350,17 +365,16 @@ static u64 arm_ni_read_ccnt(struct arm_ni_cd *cd)
350365

351366
static void arm_ni_event_read(struct perf_event *event)
352367
{
353-
struct arm_ni_cd *cd = pmu_to_cd(event->pmu);
354368
struct hw_perf_event *hw = &event->hw;
355369
u64 count, prev;
356370
bool ccnt = hw->idx == NI_CCNT_IDX;
357371

358372
do {
359373
prev = local64_read(&hw->prev_count);
360374
if (ccnt)
361-
count = arm_ni_read_ccnt(cd);
375+
count = arm_ni_read_ccnt((void __iomem *)event->hw.event_base);
362376
else
363-
count = readl_relaxed(cd->pmu_base + NI_PMEVCNTR(hw->idx));
377+
count = readl_relaxed((void __iomem *)event->hw.event_base);
364378
} while (local64_cmpxchg(&hw->prev_count, prev, count) != prev);
365379

366380
count -= prev;
@@ -385,16 +399,21 @@ static void arm_ni_event_stop(struct perf_event *event, int flags)
385399
arm_ni_event_read(event);
386400
}
387401

388-
static void arm_ni_init_ccnt(struct arm_ni_cd *cd)
402+
static void arm_ni_init_ccnt(struct hw_perf_event *hw)
403+
{
404+
local64_set(&hw->prev_count, S64_MIN);
405+
lo_hi_writeq_relaxed(S64_MIN, (void __iomem *)hw->event_base);
406+
}
407+
408+
static void arm_ni_init_evcnt(struct hw_perf_event *hw)
389409
{
390-
local64_set(&cd->ccnt->hw.prev_count, S64_MIN);
391-
lo_hi_writeq_relaxed(S64_MIN, cd->pmu_base + NI_PMCCNTR_L);
410+
local64_set(&hw->prev_count, S32_MIN);
411+
writel_relaxed(S32_MIN, (void __iomem *)hw->event_base);
392412
}
393413

394-
static void arm_ni_init_evcnt(struct arm_ni_cd *cd, int idx)
414+
static bool arm_ni_is_7xx(const struct arm_ni *ni)
395415
{
396-
local64_set(&cd->evcnt[idx]->hw.prev_count, S32_MIN);
397-
writel_relaxed(S32_MIN, cd->pmu_base + NI_PMEVCNTR(idx));
416+
return ni->part == PART_NI_700 || ni->part == PART_NI_710AE;
398417
}
399418

400419
static int arm_ni_event_add(struct perf_event *event, int flags)
@@ -403,14 +422,17 @@ static int arm_ni_event_add(struct perf_event *event, int flags)
403422
struct hw_perf_event *hw = &event->hw;
404423
struct arm_ni_unit *unit;
405424
enum ni_node_type type = NI_EVENT_TYPE(event);
425+
bool is_7xx = arm_ni_is_7xx(cd_to_ni(cd));
406426
u32 reg;
407427

408428
if (type == NI_PMU) {
409429
if (cd->ccnt)
410430
return -ENOSPC;
411431
hw->idx = NI_CCNT_IDX;
432+
hw->event_base = (unsigned long)cd->pmu_base +
433+
is_7xx ? NI700_PMCCNTR_L : NI_PMCCNTR_L;
412434
cd->ccnt = event;
413-
arm_ni_init_ccnt(cd);
435+
arm_ni_init_ccnt(hw);
414436
} else {
415437
hw->idx = 0;
416438
while (cd->evcnt[hw->idx]) {
@@ -420,7 +442,9 @@ static int arm_ni_event_add(struct perf_event *event, int flags)
420442
cd->evcnt[hw->idx] = event;
421443
unit = (void *)hw->config_base;
422444
unit->event[hw->idx] = NI_EVENT_EVENTID(event);
423-
arm_ni_init_evcnt(cd, hw->idx);
445+
hw->event_base = (unsigned long)cd->pmu_base +
446+
is_7xx ? NI700_PMEVCNTR(hw->idx) : NI_PMEVCNTR(hw->idx);
447+
arm_ni_init_evcnt(hw);
424448
lo_hi_writeq_relaxed(le64_to_cpu(unit->pmusel), unit->pmusela);
425449

426450
reg = FIELD_PREP(NI_PMEVTYPER_NODE_TYPE, type) |
@@ -457,7 +481,7 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
457481
ret = IRQ_HANDLED;
458482
if (!(WARN_ON(!cd->ccnt))) {
459483
arm_ni_event_read(cd->ccnt);
460-
arm_ni_init_ccnt(cd);
484+
arm_ni_init_ccnt(&cd->ccnt->hw);
461485
}
462486
}
463487
for (int i = 0; i < NI_NUM_COUNTERS; i++) {
@@ -466,7 +490,7 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
466490
ret = IRQ_HANDLED;
467491
if (!(WARN_ON(!cd->evcnt[i]))) {
468492
arm_ni_event_read(cd->evcnt[i]);
469-
arm_ni_init_evcnt(cd, i);
493+
arm_ni_init_evcnt(&cd->evcnt[i]->hw);
470494
}
471495
}
472496
writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
@@ -476,6 +500,25 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
476500
}
477501
}
478502

503+
static void __iomem *arm_ni_get_pmusel(struct arm_ni *ni, void __iomem *unit_base)
504+
{
505+
u32 type, ptr, num;
506+
507+
if (arm_ni_is_7xx(ni))
508+
return unit_base + NI700_PMUSELA;
509+
510+
num = readl_relaxed(unit_base + NI_NUM_SUB_FEATURES);
511+
for (int i = 0; i < num; i++) {
512+
type = readl_relaxed(unit_base + NI_SUB_FEATURE_TYPE(i));
513+
if (type != NI_SUB_FEATURE_TYPE_FCU)
514+
continue;
515+
ptr = readl_relaxed(unit_base + NI_SUB_FEATURE_PTR(i));
516+
return ni->base + ptr;
517+
}
518+
/* Should be impossible */
519+
return NULL;
520+
}
521+
479522
static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start)
480523
{
481524
struct arm_ni_cd *cd = ni->cds + node->id;
@@ -512,13 +555,18 @@ static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_s
512555
case NI_HSNI:
513556
case NI_HMNI:
514557
case NI_PMNI:
515-
unit->pmusela = unit_base + NI700_PMUSELA;
558+
case NI_TSNI:
559+
case NI_TMNI:
560+
case NI_CMNI:
561+
unit->pmusela = arm_ni_get_pmusel(ni, unit_base);
516562
writel_relaxed(1, unit->pmusela);
517563
if (readl_relaxed(unit->pmusela) != 1)
518564
dev_info(ni->dev, "No access to node 0x%04x%04x\n", unit->id, unit->type);
519565
else
520566
unit->ns = true;
521567
break;
568+
case NI_MCN:
569+
break;
522570
default:
523571
/*
524572
* e.g. FMU - thankfully bits 3:2 of FMU_ERR_FR0 are RES0 so
@@ -649,6 +697,8 @@ static int arm_ni_probe(struct platform_device *pdev)
649697
switch (part) {
650698
case PART_NI_700:
651699
case PART_NI_710AE:
700+
case PART_NOC_S3:
701+
case PART_SI_L1:
652702
break;
653703
default:
654704
dev_WARN(&pdev->dev, "Unknown part number: 0x%03x, this may go badly\n", part);

0 commit comments

Comments
 (0)