Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Robin Murphy and committed by
Will Deacon
8fa08f88 decc3684

+71 -21
+71 -21
drivers/perf/arm-ni.c
··· 21 21 22 22 #define NI_CHILD_NODE_INFO 0x004 23 23 #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 24 29 25 30 #define NI700_PMUSELA 0x00c 26 31 ··· 38 33 #define NI_PIDR2_VERSION GENMASK(7, 4) 39 34 40 35 /* PMU node */ 41 - #define NI_PMEVCNTR(n) (0x008 + (n) * 8) 42 - #define NI_PMCCNTR_L 0x0f8 43 - #define NI_PMCCNTR_U 0x0fc 36 + #define NI700_PMEVCNTR(n) (0x008 + (n) * 8) 37 + #define NI700_PMCCNTR_L 0x0f8 38 + #define NI_PMEVCNTR(n) (0x200 + (n) * 8) 39 + #define NI_PMCCNTR_L 0x2f8 44 40 #define NI_PMEVTYPER(n) (0x400 + (n) * 4) 45 41 #define NI_PMEVTYPER_NODE_TYPE GENMASK(12, 9) 46 42 #define NI_PMEVTYPER_NODE_ID GENMASK(8, 0) ··· 72 66 enum ni_part { 73 67 PART_NI_700 = 0x43b, 74 68 PART_NI_710AE = 0x43d, 69 + PART_NOC_S3 = 0x43f, 70 + PART_SI_L1 = 0x455, 75 71 }; 76 72 77 73 enum ni_node_type { ··· 87 79 NI_HSNI, 88 80 NI_HMNI, 89 81 NI_PMNI, 82 + NI_TSNI, 83 + NI_TMNI, 84 + NI_CMNI = 0x0e, 85 + NI_MCN = 0x63, 90 86 }; 91 87 92 88 struct arm_ni_node { ··· 191 179 NI_EVENT_ATTR(hsni, NI_HSNI), 192 180 NI_EVENT_ATTR(hmni, NI_HMNI), 193 181 NI_EVENT_ATTR(pmni, NI_PMNI), 182 + NI_EVENT_ATTR(tsni, NI_TSNI), 183 + NI_EVENT_ATTR(tmni, NI_TMNI), 184 + NI_EVENT_ATTR(cmni, NI_CMNI), 194 185 NULL 195 186 }; 196 187 ··· 347 332 return -EINVAL; 348 333 } 349 334 350 - static u64 arm_ni_read_ccnt(struct arm_ni_cd *cd) 335 + static u64 arm_ni_read_ccnt(void __iomem *pmccntr) 351 336 { 352 337 u64 l, u_old, u_new; 353 338 int retries = 3; /* 1st time unlucky, 2nd improbable, 3rd just broken */ 354 339 355 - u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U); 340 + u_new = readl_relaxed(pmccntr + 4); 356 341 do { 357 342 u_old = u_new; 358 - l = readl_relaxed(cd->pmu_base + NI_PMCCNTR_L); 359 - u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U); 343 + l = readl_relaxed(pmccntr); 344 + u_new = readl_relaxed(pmccntr + 4); 360 345 } while (u_new != u_old && --retries); 361 346 WARN_ON(!retries); 362 347 ··· 365 350 366 351 static void arm_ni_event_read(struct perf_event *event) 367 352 { 368 - struct arm_ni_cd *cd = pmu_to_cd(event->pmu); 369 353 struct hw_perf_event *hw = &event->hw; 370 354 u64 count, prev; 371 355 bool ccnt = hw->idx == NI_CCNT_IDX; ··· 372 358 do { 373 359 prev = local64_read(&hw->prev_count); 374 360 if (ccnt) 375 - count = arm_ni_read_ccnt(cd); 361 + count = arm_ni_read_ccnt((void __iomem *)event->hw.event_base); 376 362 else 377 - count = readl_relaxed(cd->pmu_base + NI_PMEVCNTR(hw->idx)); 363 + count = readl_relaxed((void __iomem *)event->hw.event_base); 378 364 } while (local64_cmpxchg(&hw->prev_count, prev, count) != prev); 379 365 380 366 count -= prev; ··· 399 385 arm_ni_event_read(event); 400 386 } 401 387 402 - static void arm_ni_init_ccnt(struct arm_ni_cd *cd) 388 + static void arm_ni_init_ccnt(struct hw_perf_event *hw) 403 389 { 404 - local64_set(&cd->ccnt->hw.prev_count, S64_MIN); 405 - lo_hi_writeq_relaxed(S64_MIN, cd->pmu_base + NI_PMCCNTR_L); 390 + local64_set(&hw->prev_count, S64_MIN); 391 + lo_hi_writeq_relaxed(S64_MIN, (void __iomem *)hw->event_base); 406 392 } 407 393 408 - static void arm_ni_init_evcnt(struct arm_ni_cd *cd, int idx) 394 + static void arm_ni_init_evcnt(struct hw_perf_event *hw) 409 395 { 410 - local64_set(&cd->evcnt[idx]->hw.prev_count, S32_MIN); 411 - writel_relaxed(S32_MIN, cd->pmu_base + NI_PMEVCNTR(idx)); 396 + local64_set(&hw->prev_count, S32_MIN); 397 + writel_relaxed(S32_MIN, (void __iomem *)hw->event_base); 398 + } 399 + 400 + static bool arm_ni_is_7xx(const struct arm_ni *ni) 401 + { 402 + return ni->part == PART_NI_700 || ni->part == PART_NI_710AE; 412 403 } 413 404 414 405 static int arm_ni_event_add(struct perf_event *event, int flags) ··· 422 403 struct hw_perf_event *hw = &event->hw; 423 404 struct arm_ni_unit *unit; 424 405 enum ni_node_type type = NI_EVENT_TYPE(event); 406 + bool is_7xx = arm_ni_is_7xx(cd_to_ni(cd)); 425 407 u32 reg; 426 408 427 409 if (type == NI_PMU) { 428 410 if (cd->ccnt) 429 411 return -ENOSPC; 430 412 hw->idx = NI_CCNT_IDX; 413 + hw->event_base = (unsigned long)cd->pmu_base + 414 + is_7xx ? NI700_PMCCNTR_L : NI_PMCCNTR_L; 431 415 cd->ccnt = event; 432 - arm_ni_init_ccnt(cd); 416 + arm_ni_init_ccnt(hw); 433 417 } else { 434 418 hw->idx = 0; 435 419 while (cd->evcnt[hw->idx]) { ··· 442 420 cd->evcnt[hw->idx] = event; 443 421 unit = (void *)hw->config_base; 444 422 unit->event[hw->idx] = NI_EVENT_EVENTID(event); 445 - arm_ni_init_evcnt(cd, hw->idx); 423 + hw->event_base = (unsigned long)cd->pmu_base + 424 + is_7xx ? NI700_PMEVCNTR(hw->idx) : NI_PMEVCNTR(hw->idx); 425 + arm_ni_init_evcnt(hw); 446 426 lo_hi_writeq_relaxed(le64_to_cpu(unit->pmusel), unit->pmusela); 447 427 448 428 reg = FIELD_PREP(NI_PMEVTYPER_NODE_TYPE, type) | ··· 481 457 ret = IRQ_HANDLED; 482 458 if (!(WARN_ON(!cd->ccnt))) { 483 459 arm_ni_event_read(cd->ccnt); 484 - arm_ni_init_ccnt(cd); 460 + arm_ni_init_ccnt(&cd->ccnt->hw); 485 461 } 486 462 } 487 463 for (int i = 0; i < NI_NUM_COUNTERS; i++) { ··· 490 466 ret = IRQ_HANDLED; 491 467 if (!(WARN_ON(!cd->evcnt[i]))) { 492 468 arm_ni_event_read(cd->evcnt[i]); 493 - arm_ni_init_evcnt(cd, i); 469 + arm_ni_init_evcnt(&cd->evcnt[i]->hw); 494 470 } 495 471 } 496 472 writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR); ··· 498 474 return ret; 499 475 cd += cd->irq_friend; 500 476 } 477 + } 478 + 479 + static void __iomem *arm_ni_get_pmusel(struct arm_ni *ni, void __iomem *unit_base) 480 + { 481 + u32 type, ptr, num; 482 + 483 + if (arm_ni_is_7xx(ni)) 484 + return unit_base + NI700_PMUSELA; 485 + 486 + num = readl_relaxed(unit_base + NI_NUM_SUB_FEATURES); 487 + for (int i = 0; i < num; i++) { 488 + type = readl_relaxed(unit_base + NI_SUB_FEATURE_TYPE(i)); 489 + if (type != NI_SUB_FEATURE_TYPE_FCU) 490 + continue; 491 + ptr = readl_relaxed(unit_base + NI_SUB_FEATURE_PTR(i)); 492 + return ni->base + ptr; 493 + } 494 + /* Should be impossible */ 495 + return NULL; 501 496 } 502 497 503 498 static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start) ··· 555 512 case NI_HSNI: 556 513 case NI_HMNI: 557 514 case NI_PMNI: 558 - unit->pmusela = unit_base + NI700_PMUSELA; 515 + case NI_TSNI: 516 + case NI_TMNI: 517 + case NI_CMNI: 518 + unit->pmusela = arm_ni_get_pmusel(ni, unit_base); 559 519 writel_relaxed(1, unit->pmusela); 560 520 if (readl_relaxed(unit->pmusela) != 1) 561 521 dev_info(ni->dev, "No access to node 0x%04x%04x\n", unit->id, unit->type); 562 522 else 563 523 unit->ns = true; 524 + break; 525 + case NI_MCN: 564 526 break; 565 527 default: 566 528 /* ··· 697 649 switch (part) { 698 650 case PART_NI_700: 699 651 case PART_NI_710AE: 652 + case PART_NOC_S3: 653 + case PART_SI_L1: 700 654 break; 701 655 default: 702 656 dev_WARN(&pdev->dev, "Unknown part number: 0x%03x, this may go badly\n", part);