Lines Matching +full:cpu +full:- +full:cfg
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2022-2024 Arm Limited
3 // NI-700 Network-on-Chip PMU driver
9 #include <linux/io-64-nonatomic-lo-hi.h>
62 #define NI_EVENT_TYPE(event) FIELD_GET(NI_CONFIG_TYPE, (event)->attr.config)
63 #define NI_EVENT_NODEID(event) FIELD_GET(NI_CONFIG_NODEID, (event)->attr.config)
64 #define NI_EVENT_EVENTID(event) FIELD_GET(NI_CONFIG_EVENTID, (event)->attr.config)
119 int cpu; member
125 #define cd_to_ni(cd) container_of((cd), struct arm_ni, cds[(cd)->id])
129 for (struct arm_ni_cd *c = n->cds; c < n->cds + n->num_cds; c++) if (c->pmu_base)
132 for (struct arm_ni_unit *u = cd->units; u < cd->units + cd->num_units; u++)
152 if (eattr->type == NI_PMU) in arm_ni_event_show()
153 return sysfs_emit(buf, "type=0x%x\n", eattr->type); in arm_ni_event_show()
155 return sysfs_emit(buf, "type=0x%x,eventid=?,nodeid=?\n", eattr->type); in arm_ni_event_show()
168 if (unit->type == eattr->type && unit->ns) in arm_ni_event_attr_is_visible()
169 return attr->mode; in arm_ni_event_attr_is_visible()
207 return sysfs_emit(buf, "config:%*pbl\n", 64, &fmt->field); in arm_ni_format_show()
227 return cpumap_print_to_pagebuf(true, buf, cpumask_of(ni->cpu)); in arm_ni_cpumask_show()
237 u32 reg = readl_relaxed(ni->base + NI_PERIPHERAL_ID2); in arm_ni_identifier_show()
240 return sysfs_emit(buf, "%03x%02x\n", ni->part, version); in arm_ni_identifier_show()
265 writel_relaxed(NI_PMCR_ENABLE, pmu_to_cd(pmu)->pmu_base + NI_PMCR); in arm_ni_pmu_enable()
270 writel_relaxed(0, pmu_to_cd(pmu)->pmu_base + NI_PMCR); in arm_ni_pmu_disable()
284 val->ccnt++; in arm_ni_val_count_event()
285 return val->ccnt <= 1; in arm_ni_val_count_event()
288 val->evcnt++; in arm_ni_val_count_event()
289 return val->evcnt <= NI_NUM_COUNTERS; in arm_ni_val_count_event()
294 struct perf_event *sibling, *leader = event->group_leader; in arm_ni_validate_group()
302 return -EINVAL; in arm_ni_validate_group()
306 return -EINVAL; in arm_ni_validate_group()
313 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_init()
315 if (event->attr.type != event->pmu->type) in arm_ni_event_init()
316 return -ENOENT; in arm_ni_event_init()
319 return -EINVAL; in arm_ni_event_init()
321 event->cpu = cd_to_ni(cd)->cpu; in arm_ni_event_init()
326 if (unit->type == NI_EVENT_TYPE(event) && in arm_ni_event_init()
327 unit->id == NI_EVENT_NODEID(event) && unit->ns) { in arm_ni_event_init()
328 event->hw.config_base = (unsigned long)unit; in arm_ni_event_init()
332 return -EINVAL; in arm_ni_event_init()
340 u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U); in arm_ni_read_ccnt()
343 l = readl_relaxed(cd->pmu_base + NI_PMCCNTR_L); in arm_ni_read_ccnt()
344 u_new = readl_relaxed(cd->pmu_base + NI_PMCCNTR_U); in arm_ni_read_ccnt()
345 } while (u_new != u_old && --retries); in arm_ni_read_ccnt()
353 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_read()
354 struct hw_perf_event *hw = &event->hw; in arm_ni_event_read()
356 bool ccnt = hw->idx == NI_CCNT_IDX; in arm_ni_event_read()
359 prev = local64_read(&hw->prev_count); in arm_ni_event_read()
363 count = readl_relaxed(cd->pmu_base + NI_PMEVCNTR(hw->idx)); in arm_ni_event_read()
364 } while (local64_cmpxchg(&hw->prev_count, prev, count) != prev); in arm_ni_event_read()
366 count -= prev; in arm_ni_event_read()
369 local64_add(count, &event->count); in arm_ni_event_read()
374 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_start()
376 writel_relaxed(1U << event->hw.idx, cd->pmu_base + NI_PMCNTENSET); in arm_ni_event_start()
381 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_stop()
383 writel_relaxed(1U << event->hw.idx, cd->pmu_base + NI_PMCNTENCLR); in arm_ni_event_stop()
390 local64_set(&cd->ccnt->hw.prev_count, S64_MIN); in arm_ni_init_ccnt()
391 lo_hi_writeq_relaxed(S64_MIN, cd->pmu_base + NI_PMCCNTR_L); in arm_ni_init_ccnt()
396 local64_set(&cd->evcnt[idx]->hw.prev_count, S32_MIN); in arm_ni_init_evcnt()
397 writel_relaxed(S32_MIN, cd->pmu_base + NI_PMEVCNTR(idx)); in arm_ni_init_evcnt()
402 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_add()
403 struct hw_perf_event *hw = &event->hw; in arm_ni_event_add()
409 if (cd->ccnt) in arm_ni_event_add()
410 return -ENOSPC; in arm_ni_event_add()
411 hw->idx = NI_CCNT_IDX; in arm_ni_event_add()
412 cd->ccnt = event; in arm_ni_event_add()
415 hw->idx = 0; in arm_ni_event_add()
416 while (cd->evcnt[hw->idx]) { in arm_ni_event_add()
417 if (++hw->idx == NI_NUM_COUNTERS) in arm_ni_event_add()
418 return -ENOSPC; in arm_ni_event_add()
420 cd->evcnt[hw->idx] = event; in arm_ni_event_add()
421 unit = (void *)hw->config_base; in arm_ni_event_add()
422 unit->event[hw->idx] = NI_EVENT_EVENTID(event); in arm_ni_event_add()
423 arm_ni_init_evcnt(cd, hw->idx); in arm_ni_event_add()
424 lo_hi_writeq_relaxed(le64_to_cpu(unit->pmusel), unit->pmusela); in arm_ni_event_add()
428 writel_relaxed(reg, cd->pmu_base + NI_PMEVTYPER(hw->idx)); in arm_ni_event_add()
437 struct arm_ni_cd *cd = pmu_to_cd(event->pmu); in arm_ni_event_del()
438 struct hw_perf_event *hw = &event->hw; in arm_ni_event_del()
442 if (hw->idx == NI_CCNT_IDX) in arm_ni_event_del()
443 cd->ccnt = NULL; in arm_ni_event_del()
445 cd->evcnt[hw->idx] = NULL; in arm_ni_event_del()
454 u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR); in arm_ni_handle_irq()
458 if (!(WARN_ON(!cd->ccnt))) { in arm_ni_handle_irq()
459 arm_ni_event_read(cd->ccnt); in arm_ni_handle_irq()
467 if (!(WARN_ON(!cd->evcnt[i]))) { in arm_ni_handle_irq()
468 arm_ni_event_read(cd->evcnt[i]); in arm_ni_handle_irq()
472 writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR); in arm_ni_handle_irq()
473 if (!cd->irq_friend) in arm_ni_handle_irq()
475 cd += cd->irq_friend; in arm_ni_handle_irq()
481 struct arm_ni_cd *cd = ni->cds + node->id; in arm_ni_init_cd()
484 cd->id = node->id; in arm_ni_init_cd()
485 cd->num_units = node->num_components; in arm_ni_init_cd()
486 cd->units = devm_kcalloc(ni->dev, cd->num_units, sizeof(*(cd->units)), GFP_KERNEL); in arm_ni_init_cd()
487 if (!cd->units) in arm_ni_init_cd()
488 return -ENOMEM; in arm_ni_init_cd()
490 for (int i = 0; i < cd->num_units; i++) { in arm_ni_init_cd()
491 u32 reg = readl_relaxed(node->base + NI_CHILD_PTR(i)); in arm_ni_init_cd()
492 void __iomem *unit_base = ni->base + reg; in arm_ni_init_cd()
493 struct arm_ni_unit *unit = cd->units + i; in arm_ni_init_cd()
496 unit->type = FIELD_GET(NI_NODE_TYPE_NODE_TYPE, reg); in arm_ni_init_cd()
497 unit->id = FIELD_GET(NI_NODE_TYPE_NODE_ID, reg); in arm_ni_init_cd()
499 switch (unit->type) { in arm_ni_init_cd()
503 dev_info(ni->dev, "No access to PMU %d\n", cd->id); in arm_ni_init_cd()
504 devm_kfree(ni->dev, cd->units); in arm_ni_init_cd()
507 unit->ns = true; in arm_ni_init_cd()
508 cd->pmu_base = unit_base; in arm_ni_init_cd()
515 unit->pmusela = unit_base + NI700_PMUSELA; in arm_ni_init_cd()
516 writel_relaxed(1, unit->pmusela); in arm_ni_init_cd()
517 if (readl_relaxed(unit->pmusela) != 1) in arm_ni_init_cd()
518 dev_info(ni->dev, "No access to node 0x%04x%04x\n", unit->id, unit->type); in arm_ni_init_cd()
520 unit->ns = true; in arm_ni_init_cd()
524 * e.g. FMU - thankfully bits 3:2 of FMU_ERR_FR0 are RES0 so in arm_ni_init_cd()
527 dev_dbg(ni->dev, "Mystery node 0x%04x%04x\n", unit->id, unit->type); in arm_ni_init_cd()
532 res_start += cd->pmu_base - ni->base; in arm_ni_init_cd()
533 if (!devm_request_mem_region(ni->dev, res_start, SZ_4K, dev_name(ni->dev))) { in arm_ni_init_cd()
534 dev_err(ni->dev, "Failed to request PMU region 0x%llx\n", res_start); in arm_ni_init_cd()
535 return -EBUSY; in arm_ni_init_cd()
539 cd->pmu_base + NI_PMCR); in arm_ni_init_cd()
540 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMCNTENCLR); in arm_ni_init_cd()
541 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMOVSCLR); in arm_ni_init_cd()
543 cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id); in arm_ni_init_cd()
544 if (cd->irq < 0) in arm_ni_init_cd()
545 return cd->irq; in arm_ni_init_cd()
547 cd->pmu = (struct pmu) { in arm_ni_init_cd()
549 .parent = ni->dev, in arm_ni_init_cd()
563 name = devm_kasprintf(ni->dev, GFP_KERNEL, "arm_ni_%d_cd_%d", ni->id, cd->id); in arm_ni_init_cd()
565 return -ENOMEM; in arm_ni_init_cd()
567 return perf_pmu_register(&cd->pmu, name, -1); in arm_ni_init_cd()
575 writel_relaxed(0, cd->pmu_base + NI_PMCR); in arm_ni_remove()
576 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENCLR); in arm_ni_remove()
577 perf_pmu_unregister(&cd->pmu); in arm_ni_remove()
579 cpuhp_state_remove_instance_nocalls(arm_ni_hp_state, &ni->cpuhp_node); in arm_ni_remove()
586 node->base = base; in arm_ni_probe_domain()
587 node->type = FIELD_GET(NI_NODE_TYPE_NODE_TYPE, reg); in arm_ni_probe_domain()
588 node->id = FIELD_GET(NI_NODE_TYPE_NODE_ID, reg); in arm_ni_probe_domain()
589 node->num_components = readl_relaxed(base + NI_CHILD_NODE_INFO); in arm_ni_probe_domain()
597 for (struct arm_ni_cd *prev = cd; prev-- > ni->cds; ) { in arm_ni_init_irqs()
598 if (prev->irq == cd->irq) { in arm_ni_init_irqs()
599 prev->irq_friend = cd - prev; in arm_ni_init_irqs()
603 err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq, in arm_ni_init_irqs()
605 dev_name(ni->dev), cd); in arm_ni_init_irqs()
609 irq_set_affinity(cd->irq, cpumask_of(ni->cpu)); in arm_ni_init_irqs()
611 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET); in arm_ni_init_irqs()
615 if (!cd->irq_friend) in arm_ni_init_irqs()
616 enable_irq(cd->irq); in arm_ni_init_irqs()
622 struct arm_ni_node cfg, vd, pd, cd; in arm_ni_probe() local
636 base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); in arm_ni_probe()
638 return -ENOMEM; in arm_ni_probe()
640 arm_ni_probe_domain(base, &cfg); in arm_ni_probe()
641 if (cfg.type != NI_GLOBAL) in arm_ni_probe()
642 return -ENODEV; in arm_ni_probe()
644 reg = readl_relaxed(cfg.base + NI_PERIPHERAL_ID0); in arm_ni_probe()
646 reg = readl_relaxed(cfg.base + NI_PERIPHERAL_ID1); in arm_ni_probe()
654 dev_WARN(&pdev->dev, "Unknown part number: 0x%03x, this may go badly\n", part); in arm_ni_probe()
659 for (int v = 0; v < cfg.num_components; v++) { in arm_ni_probe()
660 reg = readl_relaxed(cfg.base + NI_CHILD_PTR(v)); in arm_ni_probe()
669 ni = devm_kzalloc(&pdev->dev, struct_size(ni, cds, num_cds), GFP_KERNEL); in arm_ni_probe()
671 return -ENOMEM; in arm_ni_probe()
673 ni->dev = &pdev->dev; in arm_ni_probe()
674 ni->base = base; in arm_ni_probe()
675 ni->num_cds = num_cds; in arm_ni_probe()
676 ni->part = part; in arm_ni_probe()
677 ni->id = atomic_fetch_inc(&id); in arm_ni_probe()
678 ni->cpu = cpumask_local_spread(0, dev_to_node(ni->dev)); in arm_ni_probe()
681 ret = cpuhp_state_add_instance_nocalls(arm_ni_hp_state, &ni->cpuhp_node); in arm_ni_probe()
685 for (int v = 0; v < cfg.num_components; v++) { in arm_ni_probe()
686 reg = readl_relaxed(cfg.base + NI_CHILD_PTR(v)); in arm_ni_probe()
694 ret = arm_ni_init_cd(ni, &cd, res->start); in arm_ni_probe()
696 ni->cds[cd.id].pmu_base = NULL; in arm_ni_probe()
713 { .compatible = "arm,ni-700" },
729 .name = "arm-ni",
738 static void arm_ni_pmu_migrate(struct arm_ni *ni, unsigned int cpu) in arm_ni_pmu_migrate() argument
741 perf_pmu_migrate_context(&cd->pmu, ni->cpu, cpu); in arm_ni_pmu_migrate()
742 irq_set_affinity(cd->irq, cpumask_of(cpu)); in arm_ni_pmu_migrate()
744 ni->cpu = cpu; in arm_ni_pmu_migrate()
747 static int arm_ni_pmu_online_cpu(unsigned int cpu, struct hlist_node *cpuhp_node) in arm_ni_pmu_online_cpu() argument
753 node = dev_to_node(ni->dev); in arm_ni_pmu_online_cpu()
754 if (cpu_to_node(ni->cpu) != node && cpu_to_node(cpu) == node) in arm_ni_pmu_online_cpu()
755 arm_ni_pmu_migrate(ni, cpu); in arm_ni_pmu_online_cpu()
759 static int arm_ni_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_node) in arm_ni_pmu_offline_cpu() argument
766 if (cpu != ni->cpu) in arm_ni_pmu_offline_cpu()
769 node = dev_to_node(ni->dev); in arm_ni_pmu_offline_cpu()
770 target = cpumask_any_and_but(cpumask_of_node(node), cpu_online_mask, cpu); in arm_ni_pmu_offline_cpu()
772 target = cpumask_any_but(cpu_online_mask, cpu); in arm_ni_pmu_offline_cpu()
808 MODULE_DESCRIPTION("Arm NI-700 PMU driver");