Lines Matching +full:cmn +full:- +full:600
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2016-2020 Arm Limited
3 // CMN-600 Coherent Mesh Network PMU driver
28 #define CMN_NODEID_Y(reg, bits) (((reg) >> 3) & ((1U << (bits)) - 1))
42 #define CMN_NODE_PTR_Y(ptr, bits) (((ptr) >> 6) & ((1U << (bits)) - 1))
90 /* DTC counters are paired in 64-bit registers on a 16-byte stride. Yuck */
120 /* Similarly for the 40-bit cycle counter */
131 #define CMN_EVENT_TYPE(event) FIELD_GET(CMN_CONFIG_TYPE, (event)->attr.config)
132 #define CMN_EVENT_EVENTID(event) FIELD_GET(CMN_CONFIG_EVENTID, (event)->attr.config)
133 #define CMN_EVENT_OCCUPID(event) FIELD_GET(CMN_CONFIG_OCCUPID, (event)->attr.config)
134 #define CMN_EVENT_BYNODEID(event) FIELD_GET(CMN_CONFIG_BYNODEID, (event)->attr.config)
135 #define CMN_EVENT_NODEID(event) FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config)
145 #define CMN_EVENT_WP_COMBINE(event) FIELD_GET(CMN_CONFIG_WP_COMBINE, (event)->attr.config)
146 #define CMN_EVENT_WP_DEV_SEL(event) FIELD_GET(CMN_CONFIG_WP_DEV_SEL, (event)->attr.config)
147 #define CMN_EVENT_WP_CHN_SEL(event) FIELD_GET(CMN_CONFIG_WP_CHN_SEL, (event)->attr.config)
148 #define CMN_EVENT_WP_GRP(event) FIELD_GET(CMN_CONFIG_WP_GRP, (event)->attr.config)
149 #define CMN_EVENT_WP_EXCLUSIVE(event) FIELD_GET(CMN_CONFIG_WP_EXCLUSIVE, (event)->attr.config)
150 #define CMN_EVENT_WP_VAL(event) FIELD_GET(CMN_CONFIG1_WP_VAL, (event)->attr.config1)
151 #define CMN_EVENT_WP_MASK(event) FIELD_GET(CMN_CONFIG2_WP_MASK, (event)->attr.config2)
153 /* Made-up event IDs for watchpoint direction */
196 /* DN/HN-F/CXHA */
266 for (i = 0, dn = hw->dn; i < hw->num_dns; i++, dn++)
271 return (struct arm_cmn_hw_event *)&event->hw; in to_cmn_hw()
297 static int arm_cmn_xyidbits(const struct arm_cmn *cmn) in arm_cmn_xyidbits() argument
299 return cmn->mesh_x > 4 || cmn->mesh_y > 4 ? 3 : 2; in arm_cmn_xyidbits()
302 static void arm_cmn_init_node_to_xp(const struct arm_cmn *cmn, in arm_cmn_init_node_to_xp() argument
305 int bits = arm_cmn_xyidbits(cmn); in arm_cmn_init_node_to_xp()
306 int x = CMN_NODEID_X(dn->id, bits); in arm_cmn_init_node_to_xp()
307 int y = CMN_NODEID_Y(dn->id, bits); in arm_cmn_init_node_to_xp()
308 int xp_idx = cmn->mesh_x * y + x; in arm_cmn_init_node_to_xp()
310 dn->to_xp = (cmn->xps + xp_idx) - dn; in arm_cmn_init_node_to_xp()
315 return dn->type == CMN_TYPE_XP ? dn : dn + dn->to_xp; in arm_cmn_node_to_xp()
318 static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn, in arm_cmn_node() argument
323 for (i = 0; i < cmn->num_dns; i++) in arm_cmn_node()
324 if (cmn->dns[i].type == type) in arm_cmn_node()
325 return &cmn->dns[i]; in arm_cmn_node()
350 if (eattr->type == CMN_TYPE_DTC) in arm_cmn_event_show()
351 return snprintf(buf, PAGE_SIZE, "type=0x%x\n", eattr->type); in arm_cmn_event_show()
353 if (eattr->type == CMN_TYPE_WP) in arm_cmn_event_show()
356 eattr->type, eattr->eventid); in arm_cmn_event_show()
358 if (arm_cmn_is_occup_event(eattr->type, eattr->eventid)) in arm_cmn_event_show()
360 eattr->type, eattr->eventid, eattr->occupid); in arm_cmn_event_show()
363 eattr->type, eattr->eventid); in arm_cmn_event_show()
371 struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev)); in arm_cmn_event_attr_is_visible() local
376 type = eattr->type; in arm_cmn_event_attr_is_visible()
382 /* Revision-specific differences */ in arm_cmn_event_attr_is_visible()
383 if (cmn->rev < CMN600_R1P2) { in arm_cmn_event_attr_is_visible()
384 if (type == CMN_TYPE_HNF && eattr->eventid == 0x1b) in arm_cmn_event_attr_is_visible()
388 if (!arm_cmn_node(cmn, type)) in arm_cmn_event_attr_is_visible()
391 return attr->mode; in arm_cmn_event_attr_is_visible()
433 * DVM node events conflict with HN-I events in the equivalent PMU
434 * slot, but our lazy short-cut of using the DTM counter index for
504 /* We treat watchpoints as a special made-up class of XP events */
560 int lo = __ffs(fmt->field), hi = __fls(fmt->field); in arm_cmn_format_show()
565 if (!fmt->config) in arm_cmn_format_show()
566 return snprintf(buf, PAGE_SIZE, "config:%d-%d\n", lo, hi); in arm_cmn_format_show()
568 return snprintf(buf, PAGE_SIZE, "config%d:%d-%d\n", fmt->config, lo, hi); in arm_cmn_format_show()
606 struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev)); in arm_cmn_cpumask_show() local
608 return cpumap_print_to_pagebuf(true, buf, cpumask_of(cmn->cpu)); in arm_cmn_cpumask_show()
654 static void arm_cmn_set_state(struct arm_cmn *cmn, u32 state) in arm_cmn_set_state() argument
656 if (!cmn->state) in arm_cmn_set_state()
657 writel_relaxed(0, cmn->dtc[0].base + CMN_DT_PMCR); in arm_cmn_set_state()
658 cmn->state |= state; in arm_cmn_set_state()
661 static void arm_cmn_clear_state(struct arm_cmn *cmn, u32 state) in arm_cmn_clear_state() argument
663 cmn->state &= ~state; in arm_cmn_clear_state()
664 if (!cmn->state) in arm_cmn_clear_state()
666 cmn->dtc[0].base + CMN_DT_PMCR); in arm_cmn_clear_state()
679 static u64 arm_cmn_read_dtm(struct arm_cmn *cmn, struct arm_cmn_hw_event *hw, in arm_cmn_read_dtm() argument
689 int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i); in arm_cmn_read_dtm()
690 u64 reg = readq_relaxed(xp->pmu_base + offset); in arm_cmn_read_dtm()
700 u64 val = readq_relaxed(dtc->base + CMN_DT_PMCCNTR); in arm_cmn_read_cc()
702 writeq_relaxed(CMN_CC_INIT, dtc->base + CMN_DT_PMCCNTR); in arm_cmn_read_cc()
703 return (val - CMN_CC_INIT) & ((CMN_CC_INIT << 1) - 1); in arm_cmn_read_cc()
710 val = readl_relaxed(dtc->base + pmevcnt); in arm_cmn_read_counter()
711 writel_relaxed(CMN_COUNTER_INIT, dtc->base + pmevcnt); in arm_cmn_read_counter()
712 return val - CMN_COUNTER_INIT; in arm_cmn_read_counter()
717 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_init_counter() local
719 unsigned int i, pmevcnt = CMN_DT_PMEVCNT(hw->dtc_idx); in arm_cmn_init_counter()
722 for (i = 0; hw->dtcs_used & (1U << i); i++) { in arm_cmn_init_counter()
723 writel_relaxed(CMN_COUNTER_INIT, cmn->dtc[i].base + pmevcnt); in arm_cmn_init_counter()
724 cmn->dtc[i].counters[hw->dtc_idx] = event; in arm_cmn_init_counter()
727 count = arm_cmn_read_dtm(cmn, hw, false); in arm_cmn_init_counter()
728 local64_set(&event->hw.prev_count, count); in arm_cmn_init_counter()
733 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_read() local
739 if (hw->dtc_idx == CMN_DT_NUM_COUNTERS) { in arm_cmn_event_read()
740 i = __ffs(hw->dtcs_used); in arm_cmn_event_read()
741 delta = arm_cmn_read_cc(cmn->dtc + i); in arm_cmn_event_read()
742 local64_add(delta, &event->count); in arm_cmn_event_read()
745 new = arm_cmn_read_dtm(cmn, hw, false); in arm_cmn_event_read()
746 prev = local64_xchg(&event->hw.prev_count, new); in arm_cmn_event_read()
748 delta = new - prev; in arm_cmn_event_read()
751 for (i = 0; hw->dtcs_used & (1U << i); i++) { in arm_cmn_event_read()
752 new = arm_cmn_read_counter(cmn->dtc + i, hw->dtc_idx); in arm_cmn_event_read()
756 local64_add(delta, &event->count); in arm_cmn_event_read()
761 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_start() local
768 i = __ffs(hw->dtcs_used); in arm_cmn_event_start()
769 writeq_relaxed(CMN_CC_INIT, cmn->dtc[i].base + CMN_DT_PMCCNTR); in arm_cmn_event_start()
770 cmn->dtc[i].cc_active = true; in arm_cmn_event_start()
777 writeq_relaxed(val, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx)); in arm_cmn_event_start()
778 writeq_relaxed(mask, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx)); in arm_cmn_event_start()
781 int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i); in arm_cmn_event_start()
783 dn->event[dtm_idx] = CMN_EVENT_EVENTID(event); in arm_cmn_event_start()
784 writel_relaxed(le32_to_cpu(dn->event_sel), dn->pmu_base + CMN_PMU_EVENT_SEL); in arm_cmn_event_start()
790 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_stop() local
797 i = __ffs(hw->dtcs_used); in arm_cmn_event_stop()
798 cmn->dtc[i].cc_active = false; in arm_cmn_event_stop()
803 writeq_relaxed(0, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx)); in arm_cmn_event_stop()
804 writeq_relaxed(~0ULL, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx)); in arm_cmn_event_stop()
807 int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i); in arm_cmn_event_stop()
809 dn->event[dtm_idx] = 0; in arm_cmn_event_stop()
810 writel_relaxed(le32_to_cpu(dn->event_sel), dn->pmu_base + CMN_PMU_EVENT_SEL); in arm_cmn_event_stop()
837 val->cycles = true; in arm_cmn_val_add_event()
841 val->dtc_count++; in arm_cmn_val_add_event()
848 int wp_idx, xp = arm_cmn_node_to_xp(dn)->logid; in arm_cmn_val_add_event()
850 val->dtm_count[xp]++; in arm_cmn_val_add_event()
851 val->occupid[xp] = occupid; in arm_cmn_val_add_event()
857 val->wp[xp][wp_idx] = CMN_EVENT_WP_COMBINE(event) + 1; in arm_cmn_val_add_event()
865 struct perf_event *sibling, *leader = event->group_leader; in arm_cmn_validate_group()
874 if (event->pmu != leader->pmu && !is_software_event(leader)) in arm_cmn_validate_group()
875 return -EINVAL; in arm_cmn_validate_group()
885 return val.cycles ? -EINVAL : 0; in arm_cmn_validate_group()
888 return -EINVAL; in arm_cmn_validate_group()
896 int wp_idx, wp_cmb, xp = arm_cmn_node_to_xp(dn)->logid; in arm_cmn_validate_group()
899 return -EINVAL; in arm_cmn_validate_group()
902 return -EINVAL; in arm_cmn_validate_group()
909 return -EINVAL; in arm_cmn_validate_group()
913 return -EINVAL; in arm_cmn_validate_group()
921 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_init() local
928 if (event->attr.type != event->pmu->type) in arm_cmn_event_init()
929 return -ENOENT; in arm_cmn_event_init()
931 if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) in arm_cmn_event_init()
932 return -EINVAL; in arm_cmn_event_init()
934 event->cpu = cmn->cpu; in arm_cmn_event_init()
935 if (event->cpu < 0) in arm_cmn_event_init()
936 return -EINVAL; in arm_cmn_event_init()
949 return -EINVAL; in arm_cmn_event_init()
955 hw->dn = arm_cmn_node(cmn, type); in arm_cmn_event_init()
956 for (i = hw->dn - cmn->dns; i < cmn->num_dns && cmn->dns[i].type == type; i++) { in arm_cmn_event_init()
958 hw->num_dns++; in arm_cmn_event_init()
959 } else if (cmn->dns[i].id != nodeid) { in arm_cmn_event_init()
960 hw->dn++; in arm_cmn_event_init()
962 hw->num_dns = 1; in arm_cmn_event_init()
967 if (!hw->num_dns) { in arm_cmn_event_init()
968 int bits = arm_cmn_xyidbits(cmn); in arm_cmn_event_init()
970 dev_dbg(cmn->dev, "invalid node 0x%x (%d,%d,%d,%d) type 0x%x\n", in arm_cmn_event_init()
973 return -EINVAL; in arm_cmn_event_init()
979 hw->dtcs_used = (1U << cmn->num_dtcs) - 1; in arm_cmn_event_init()
984 static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event, in arm_cmn_event_clear() argument
990 while (i--) { in arm_cmn_event_clear()
991 struct arm_cmn_node *xp = arm_cmn_node_to_xp(hw->dn + i); in arm_cmn_event_clear()
992 unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i); in arm_cmn_event_clear()
995 hw->dn[i].wp_event[arm_cmn_wp_idx(event)] = -1; in arm_cmn_event_clear()
998 hw->dn[i].occupid_count--; in arm_cmn_event_clear()
1000 xp->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx); in arm_cmn_event_clear()
1001 writel_relaxed(xp->pmu_config_low, xp->pmu_base + CMN_DTM_PMU_CONFIG); in arm_cmn_event_clear()
1003 memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx)); in arm_cmn_event_clear()
1005 for (i = 0; hw->dtcs_used & (1U << i); i++) in arm_cmn_event_clear()
1006 cmn->dtc[i].counters[hw->dtc_idx] = NULL; in arm_cmn_event_clear()
1011 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_add() local
1013 struct arm_cmn_dtc *dtc = &cmn->dtc[0]; in arm_cmn_event_add()
1020 while (cmn->dtc[i].cycles) in arm_cmn_event_add()
1021 if (++i == cmn->num_dtcs) in arm_cmn_event_add()
1022 return -ENOSPC; in arm_cmn_event_add()
1024 cmn->dtc[i].cycles = event; in arm_cmn_event_add()
1025 hw->dtc_idx = CMN_DT_NUM_COUNTERS; in arm_cmn_event_add()
1026 hw->dtcs_used = 1U << i; in arm_cmn_event_add()
1035 while (dtc->counters[dtc_idx]) in arm_cmn_event_add()
1037 return -ENOSPC; in arm_cmn_event_add()
1039 hw->dtc_idx = dtc_idx; in arm_cmn_event_add()
1048 while (xp->pmu_config_low & CMN__PMEVCNT_PAIRED(dtm_idx)) in arm_cmn_event_add()
1058 if (dn->wp_event[wp_idx] >= 0) in arm_cmn_event_add()
1061 tmp = dn->wp_event[wp_idx ^ 1]; in arm_cmn_event_add()
1063 CMN_EVENT_WP_COMBINE(dtc->counters[tmp])) in arm_cmn_event_add()
1067 dn->wp_event[wp_idx] = dtc_idx; in arm_cmn_event_add()
1068 writel_relaxed(cfg, dn->pmu_base + CMN_DTM_WPn_CONFIG(wp_idx)); in arm_cmn_event_add()
1070 unsigned int port = CMN_NODEID_PID(dn->id); in arm_cmn_event_add()
1071 unsigned int dev = CMN_NODEID_DEVID(dn->id); in arm_cmn_event_add()
1079 if (dn->occupid_count == 0) { in arm_cmn_event_add()
1080 dn->occupid_val = occupid; in arm_cmn_event_add()
1082 dn->pmu_base + CMN_PMU_EVENT_SEL + 4); in arm_cmn_event_add()
1083 } else if (dn->occupid_val != occupid) { in arm_cmn_event_add()
1086 dn->occupid_count++; in arm_cmn_event_add()
1090 arm_cmn_set_index(hw->dtm_idx, i, dtm_idx); in arm_cmn_event_add()
1092 xp->input_sel[dtm_idx] = input_sel; in arm_cmn_event_add()
1094 xp->pmu_config_low &= ~(CMN__PMEVCNT0_GLOBAL_NUM << shift); in arm_cmn_event_add()
1095 xp->pmu_config_low |= FIELD_PREP(CMN__PMEVCNT0_GLOBAL_NUM, dtc_idx) << shift; in arm_cmn_event_add()
1096 xp->pmu_config_low |= CMN__PMEVCNT_PAIRED(dtm_idx); in arm_cmn_event_add()
1097 reg = (u64)le32_to_cpu(xp->pmu_config_high) << 32 | xp->pmu_config_low; in arm_cmn_event_add()
1098 writeq_relaxed(reg, xp->pmu_base + CMN_DTM_PMU_CONFIG); in arm_cmn_event_add()
1110 arm_cmn_event_clear(cmn, event, i); in arm_cmn_event_add()
1111 return -ENOSPC; in arm_cmn_event_add()
1116 struct arm_cmn *cmn = to_cmn(event->pmu); in arm_cmn_event_del() local
1123 cmn->dtc[__ffs(hw->dtcs_used)].cycles = NULL; in arm_cmn_event_del()
1125 arm_cmn_event_clear(cmn, event, hw->num_dns); in arm_cmn_event_del()
1152 struct arm_cmn *cmn; in arm_cmn_pmu_offline_cpu() local
1155 cmn = hlist_entry_safe(node, struct arm_cmn, cpuhp_node); in arm_cmn_pmu_offline_cpu()
1156 if (cpu != cmn->cpu) in arm_cmn_pmu_offline_cpu()
1163 perf_pmu_migrate_context(&cmn->pmu, cpu, target); in arm_cmn_pmu_offline_cpu()
1164 for (i = 0; i < cmn->num_dtcs; i++) in arm_cmn_pmu_offline_cpu()
1165 irq_set_affinity_hint(cmn->dtc[i].irq, cpumask_of(target)); in arm_cmn_pmu_offline_cpu()
1166 cmn->cpu = target; in arm_cmn_pmu_offline_cpu()
1176 u32 status = readl_relaxed(dtc->base + CMN_DT_PMOVSR); in arm_cmn_handle_irq()
1183 if (WARN_ON(!dtc->counters[i])) in arm_cmn_handle_irq()
1186 local64_add(delta, &dtc->counters[i]->count); in arm_cmn_handle_irq()
1192 if (dtc->cc_active && !WARN_ON(!dtc->cycles)) { in arm_cmn_handle_irq()
1194 local64_add(delta, &dtc->cycles->count); in arm_cmn_handle_irq()
1198 writel_relaxed(status, dtc->base + CMN_DT_PMOVSR_CLR); in arm_cmn_handle_irq()
1200 if (!dtc->irq_friend) in arm_cmn_handle_irq()
1202 dtc += dtc->irq_friend; in arm_cmn_handle_irq()
1206 /* We can reasonably accommodate DTCs of the same CMN sharing IRQs */
1207 static int arm_cmn_init_irqs(struct arm_cmn *cmn) in arm_cmn_init_irqs() argument
1211 for (i = 0; i < cmn->num_dtcs; i++) { in arm_cmn_init_irqs()
1212 irq = cmn->dtc[i].irq; in arm_cmn_init_irqs()
1213 for (j = i; j--; ) { in arm_cmn_init_irqs()
1214 if (cmn->dtc[j].irq == irq) { in arm_cmn_init_irqs()
1215 cmn->dtc[j].irq_friend = i - j; in arm_cmn_init_irqs()
1219 err = devm_request_irq(cmn->dev, irq, arm_cmn_handle_irq, in arm_cmn_init_irqs()
1221 dev_name(cmn->dev), &cmn->dtc[i]); in arm_cmn_init_irqs()
1225 err = irq_set_affinity_hint(irq, cpumask_of(cmn->cpu)); in arm_cmn_init_irqs()
1239 xp->wp_event[i] = -1; in arm_cmn_init_dtm()
1240 writeq_relaxed(0, xp->pmu_base + CMN_DTM_WPn_MASK(i)); in arm_cmn_init_dtm()
1241 writeq_relaxed(~0ULL, xp->pmu_base + CMN_DTM_WPn_VAL(i)); in arm_cmn_init_dtm()
1243 xp->pmu_config_low = CMN_DTM_PMU_CONFIG_PMU_EN; in arm_cmn_init_dtm()
1244 xp->dtc = -1; in arm_cmn_init_dtm()
1247 static int arm_cmn_init_dtc(struct arm_cmn *cmn, struct arm_cmn_node *dn, int idx) in arm_cmn_init_dtc() argument
1249 struct arm_cmn_dtc *dtc = cmn->dtc + idx; in arm_cmn_init_dtc()
1252 dtc->base = dn->pmu_base - CMN_PMU_OFFSET; in arm_cmn_init_dtc()
1253 dtc->irq = platform_get_irq(to_platform_device(cmn->dev), idx); in arm_cmn_init_dtc()
1254 if (dtc->irq < 0) in arm_cmn_init_dtc()
1255 return dtc->irq; in arm_cmn_init_dtc()
1257 writel_relaxed(0, dtc->base + CMN_DT_PMCR); in arm_cmn_init_dtc()
1258 writel_relaxed(0x1ff, dtc->base + CMN_DT_PMOVSR_CLR); in arm_cmn_init_dtc()
1259 writel_relaxed(CMN_DT_PMCR_OVFL_INTR_EN, dtc->base + CMN_DT_PMCR); in arm_cmn_init_dtc()
1263 xp->dtc = idx; in arm_cmn_init_dtc()
1273 cmp = dna->type - dnb->type; in arm_cmn_node_cmp()
1275 cmp = dna->logid - dnb->logid; in arm_cmn_node_cmp()
1279 static int arm_cmn_init_dtcs(struct arm_cmn *cmn) in arm_cmn_init_dtcs() argument
1284 cmn->dtc = devm_kcalloc(cmn->dev, cmn->num_dtcs, sizeof(cmn->dtc[0]), GFP_KERNEL); in arm_cmn_init_dtcs()
1285 if (!cmn->dtc) in arm_cmn_init_dtcs()
1286 return -ENOMEM; in arm_cmn_init_dtcs()
1288 sort(cmn->dns, cmn->num_dns, sizeof(cmn->dns[0]), arm_cmn_node_cmp, NULL); in arm_cmn_init_dtcs()
1290 cmn->xps = arm_cmn_node(cmn, CMN_TYPE_XP); in arm_cmn_init_dtcs()
1292 for (dn = cmn->dns; dn < cmn->dns + cmn->num_dns; dn++) { in arm_cmn_init_dtcs()
1293 if (dn->type != CMN_TYPE_XP) in arm_cmn_init_dtcs()
1294 arm_cmn_init_node_to_xp(cmn, dn); in arm_cmn_init_dtcs()
1295 else if (cmn->num_dtcs == 1) in arm_cmn_init_dtcs()
1296 dn->dtc = 0; in arm_cmn_init_dtcs()
1298 if (dn->type == CMN_TYPE_DTC) in arm_cmn_init_dtcs()
1299 arm_cmn_init_dtc(cmn, dn, dtc_idx++); in arm_cmn_init_dtcs()
1301 /* To the PMU, RN-Ds don't add anything over RN-Is, so smoosh them together */ in arm_cmn_init_dtcs()
1302 if (dn->type == CMN_TYPE_RND) in arm_cmn_init_dtcs()
1303 dn->type = CMN_TYPE_RNI; in arm_cmn_init_dtcs()
1306 writel_relaxed(CMN_DT_DTC_CTL_DT_EN, cmn->dtc[0].base + CMN_DT_DTC_CTL); in arm_cmn_init_dtcs()
1311 static void arm_cmn_init_node_info(struct arm_cmn *cmn, u32 offset, struct arm_cmn_node *node) in arm_cmn_init_node_info() argument
1314 u64 reg = readq_relaxed(cmn->base + offset + CMN_NODE_INFO); in arm_cmn_init_node_info()
1316 node->type = FIELD_GET(CMN_NI_NODE_TYPE, reg); in arm_cmn_init_node_info()
1317 node->id = FIELD_GET(CMN_NI_NODE_ID, reg); in arm_cmn_init_node_info()
1318 node->logid = FIELD_GET(CMN_NI_LOGICAL_ID, reg); in arm_cmn_init_node_info()
1320 node->pmu_base = cmn->base + offset + CMN_PMU_OFFSET; in arm_cmn_init_node_info()
1322 if (node->type == CMN_TYPE_CFG) in arm_cmn_init_node_info()
1324 else if (node->type == CMN_TYPE_XP) in arm_cmn_init_node_info()
1329 dev_dbg(cmn->dev, "node%*c%#06hx%*ctype:%-#6x id:%-4hd off:%#x\n", in arm_cmn_init_node_info()
1330 (level * 2) + 1, ' ', node->id, 5 - (level * 2), ' ', in arm_cmn_init_node_info()
1331 node->type, node->logid, offset); in arm_cmn_init_node_info()
1334 static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset) in arm_cmn_discover() argument
1343 cfg_region = cmn->base + rgn_offset; in arm_cmn_discover()
1345 cmn->rev = FIELD_GET(CMN_CFGM_PID2_REVISION, reg); in arm_cmn_discover()
1346 dev_dbg(cmn->dev, "periph_id_2 revision: %d\n", cmn->rev); in arm_cmn_discover()
1348 arm_cmn_init_node_info(cmn, rgn_offset, &cfg); in arm_cmn_discover()
1350 return -ENODEV; in arm_cmn_discover()
1356 cmn->num_xps = child_count; in arm_cmn_discover()
1357 cmn->num_dns = cmn->num_xps; in arm_cmn_discover()
1360 for (i = 0; i < cmn->num_xps; i++) { in arm_cmn_discover()
1364 reg = readq_relaxed(cmn->base + xp_offset[i] + CMN_CHILD_INFO); in arm_cmn_discover()
1365 cmn->num_dns += FIELD_GET(CMN_CI_CHILD_COUNT, reg); in arm_cmn_discover()
1368 /* Cheeky +1 to help terminate pointer-based iteration */ in arm_cmn_discover()
1369 cmn->dns = devm_kcalloc(cmn->dev, cmn->num_dns + 1, in arm_cmn_discover()
1370 sizeof(*cmn->dns), GFP_KERNEL); in arm_cmn_discover()
1371 if (!cmn->dns) in arm_cmn_discover()
1372 return -ENOMEM; in arm_cmn_discover()
1375 dn = cmn->dns; in arm_cmn_discover()
1376 for (i = 0; i < cmn->num_xps; i++) { in arm_cmn_discover()
1377 void __iomem *xp_region = cmn->base + xp_offset[i]; in arm_cmn_discover()
1380 arm_cmn_init_node_info(cmn, xp_offset[i], xp); in arm_cmn_discover()
1388 if (xp->id == (1 << 3)) in arm_cmn_discover()
1389 cmn->mesh_x = xp->logid; in arm_cmn_discover()
1400 * As of CMN-600r1 these could only be RN-SAMs or CXLAs, in arm_cmn_discover()
1407 dev_dbg(cmn->dev, "ignoring external node %llx\n", reg); in arm_cmn_discover()
1411 arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn); in arm_cmn_discover()
1413 switch (dn->type) { in arm_cmn_discover()
1415 cmn->num_dtcs++; in arm_cmn_discover()
1435 dev_err(cmn->dev, "invalid device node type: 0x%x\n", dn->type); in arm_cmn_discover()
1436 return -ENODEV; in arm_cmn_discover()
1442 cmn->num_dns = dn - cmn->dns; in arm_cmn_discover()
1448 if (!cmn->mesh_x) in arm_cmn_discover()
1449 cmn->mesh_x = cmn->num_xps; in arm_cmn_discover()
1450 cmn->mesh_y = cmn->num_xps / cmn->mesh_x; in arm_cmn_discover()
1452 dev_dbg(cmn->dev, "mesh %dx%d, ID width %d\n", in arm_cmn_discover()
1453 cmn->mesh_x, cmn->mesh_y, arm_cmn_xyidbits(cmn)); in arm_cmn_discover()
1458 static int arm_cmn_acpi_probe(struct platform_device *pdev, struct arm_cmn *cmn) in arm_cmn_acpi_probe() argument
1464 return -EINVAL; in arm_cmn_acpi_probe()
1468 return -EINVAL; in arm_cmn_acpi_probe()
1478 cmn->base = devm_ioremap(cmn->dev, cfg->start, resource_size(cfg)); in arm_cmn_acpi_probe()
1479 if (!cmn->base) in arm_cmn_acpi_probe()
1480 return -ENOMEM; in arm_cmn_acpi_probe()
1482 return root->start - cfg->start; in arm_cmn_acpi_probe()
1485 static int arm_cmn_of_probe(struct platform_device *pdev, struct arm_cmn *cmn) in arm_cmn_of_probe() argument
1487 struct device_node *np = pdev->dev.of_node; in arm_cmn_of_probe()
1491 cmn->base = devm_platform_ioremap_resource(pdev, 0); in arm_cmn_of_probe()
1492 if (IS_ERR(cmn->base)) in arm_cmn_of_probe()
1493 return PTR_ERR(cmn->base); in arm_cmn_of_probe()
1495 ret = of_property_read_u32(np, "arm,root-node", &rootnode); in arm_cmn_of_probe()
1504 struct arm_cmn *cmn; in arm_cmn_probe() local
1509 cmn = devm_kzalloc(&pdev->dev, sizeof(*cmn), GFP_KERNEL); in arm_cmn_probe()
1510 if (!cmn) in arm_cmn_probe()
1511 return -ENOMEM; in arm_cmn_probe()
1513 cmn->dev = &pdev->dev; in arm_cmn_probe()
1514 platform_set_drvdata(pdev, cmn); in arm_cmn_probe()
1516 if (has_acpi_companion(cmn->dev)) in arm_cmn_probe()
1517 rootnode = arm_cmn_acpi_probe(pdev, cmn); in arm_cmn_probe()
1519 rootnode = arm_cmn_of_probe(pdev, cmn); in arm_cmn_probe()
1523 err = arm_cmn_discover(cmn, rootnode); in arm_cmn_probe()
1527 err = arm_cmn_init_dtcs(cmn); in arm_cmn_probe()
1531 err = arm_cmn_init_irqs(cmn); in arm_cmn_probe()
1535 cmn->cpu = raw_smp_processor_id(); in arm_cmn_probe()
1536 cmn->pmu = (struct pmu) { in arm_cmn_probe()
1554 name = devm_kasprintf(cmn->dev, GFP_KERNEL, "arm_cmn_%d", atomic_fetch_inc(&id)); in arm_cmn_probe()
1556 return -ENOMEM; in arm_cmn_probe()
1558 err = cpuhp_state_add_instance(arm_cmn_hp_state, &cmn->cpuhp_node); in arm_cmn_probe()
1562 err = perf_pmu_register(&cmn->pmu, name, -1); in arm_cmn_probe()
1564 cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node); in arm_cmn_probe()
1570 struct arm_cmn *cmn = platform_get_drvdata(pdev); in arm_cmn_remove() local
1573 writel_relaxed(0, cmn->dtc[0].base + CMN_DT_DTC_CTL); in arm_cmn_remove()
1575 perf_pmu_unregister(&cmn->pmu); in arm_cmn_remove()
1576 cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node); in arm_cmn_remove()
1578 for (i = 0; i < cmn->num_dtcs; i++) in arm_cmn_remove()
1579 irq_set_affinity_hint(cmn->dtc[i].irq, NULL); in arm_cmn_remove()
1586 { .compatible = "arm,cmn-600", },
1602 .name = "arm-cmn",
1615 "perf/arm/cmn:online", NULL, in arm_cmn_init()
1637 MODULE_DESCRIPTION("Arm CMN-600 PMU driver");