aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus/arm-ccn.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-09-15 02:24:53 -0400
committerIngo Molnar <mingo@kernel.org>2016-09-15 02:24:53 -0400
commitd4b80afbba49e968623330f1336da8c724da8aad (patch)
treea9478bd77d8b001a6a7119328d34e9666d7bfe93 /drivers/bus/arm-ccn.c
parentfcd709ef20a9d83bdb7524d27cd6719dac8690a0 (diff)
parent4cea8776571b18db7485930cb422faa739580c8c (diff)
Merge branch 'linus' into x86/asm, to pick up recent fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/bus/arm-ccn.c')
-rw-r--r--drivers/bus/arm-ccn.c112
1 files changed, 79 insertions, 33 deletions
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c
index 97a9185af433..884c0305e290 100644
--- a/drivers/bus/arm-ccn.c
+++ b/drivers/bus/arm-ccn.c
@@ -187,6 +187,7 @@ struct arm_ccn {
187 struct arm_ccn_component *xp; 187 struct arm_ccn_component *xp;
188 188
189 struct arm_ccn_dt dt; 189 struct arm_ccn_dt dt;
190 int mn_id;
190}; 191};
191 192
192static DEFINE_MUTEX(arm_ccn_mutex); 193static DEFINE_MUTEX(arm_ccn_mutex);
@@ -212,6 +213,7 @@ static int arm_ccn_node_to_xp_port(int node)
212#define CCN_CONFIG_TYPE(_config) (((_config) >> 8) & 0xff) 213#define CCN_CONFIG_TYPE(_config) (((_config) >> 8) & 0xff)
213#define CCN_CONFIG_EVENT(_config) (((_config) >> 16) & 0xff) 214#define CCN_CONFIG_EVENT(_config) (((_config) >> 16) & 0xff)
214#define CCN_CONFIG_PORT(_config) (((_config) >> 24) & 0x3) 215#define CCN_CONFIG_PORT(_config) (((_config) >> 24) & 0x3)
216#define CCN_CONFIG_BUS(_config) (((_config) >> 24) & 0x3)
215#define CCN_CONFIG_VC(_config) (((_config) >> 26) & 0x7) 217#define CCN_CONFIG_VC(_config) (((_config) >> 26) & 0x7)
216#define CCN_CONFIG_DIR(_config) (((_config) >> 29) & 0x1) 218#define CCN_CONFIG_DIR(_config) (((_config) >> 29) & 0x1)
217#define CCN_CONFIG_MASK(_config) (((_config) >> 30) & 0xf) 219#define CCN_CONFIG_MASK(_config) (((_config) >> 30) & 0xf)
@@ -241,6 +243,7 @@ static CCN_FORMAT_ATTR(xp, "config:0-7");
241static CCN_FORMAT_ATTR(type, "config:8-15"); 243static CCN_FORMAT_ATTR(type, "config:8-15");
242static CCN_FORMAT_ATTR(event, "config:16-23"); 244static CCN_FORMAT_ATTR(event, "config:16-23");
243static CCN_FORMAT_ATTR(port, "config:24-25"); 245static CCN_FORMAT_ATTR(port, "config:24-25");
246static CCN_FORMAT_ATTR(bus, "config:24-25");
244static CCN_FORMAT_ATTR(vc, "config:26-28"); 247static CCN_FORMAT_ATTR(vc, "config:26-28");
245static CCN_FORMAT_ATTR(dir, "config:29-29"); 248static CCN_FORMAT_ATTR(dir, "config:29-29");
246static CCN_FORMAT_ATTR(mask, "config:30-33"); 249static CCN_FORMAT_ATTR(mask, "config:30-33");
@@ -253,6 +256,7 @@ static struct attribute *arm_ccn_pmu_format_attrs[] = {
253 &arm_ccn_pmu_format_attr_type.attr.attr, 256 &arm_ccn_pmu_format_attr_type.attr.attr,
254 &arm_ccn_pmu_format_attr_event.attr.attr, 257 &arm_ccn_pmu_format_attr_event.attr.attr,
255 &arm_ccn_pmu_format_attr_port.attr.attr, 258 &arm_ccn_pmu_format_attr_port.attr.attr,
259 &arm_ccn_pmu_format_attr_bus.attr.attr,
256 &arm_ccn_pmu_format_attr_vc.attr.attr, 260 &arm_ccn_pmu_format_attr_vc.attr.attr,
257 &arm_ccn_pmu_format_attr_dir.attr.attr, 261 &arm_ccn_pmu_format_attr_dir.attr.attr,
258 &arm_ccn_pmu_format_attr_mask.attr.attr, 262 &arm_ccn_pmu_format_attr_mask.attr.attr,
@@ -328,6 +332,7 @@ struct arm_ccn_pmu_event {
328static ssize_t arm_ccn_pmu_event_show(struct device *dev, 332static ssize_t arm_ccn_pmu_event_show(struct device *dev,
329 struct device_attribute *attr, char *buf) 333 struct device_attribute *attr, char *buf)
330{ 334{
335 struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev));
331 struct arm_ccn_pmu_event *event = container_of(attr, 336 struct arm_ccn_pmu_event *event = container_of(attr,
332 struct arm_ccn_pmu_event, attr); 337 struct arm_ccn_pmu_event, attr);
333 ssize_t res; 338 ssize_t res;
@@ -349,10 +354,17 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
349 break; 354 break;
350 case CCN_TYPE_XP: 355 case CCN_TYPE_XP:
351 res += snprintf(buf + res, PAGE_SIZE - res, 356 res += snprintf(buf + res, PAGE_SIZE - res,
352 ",xp=?,port=?,vc=?,dir=?"); 357 ",xp=?,vc=?");
353 if (event->event == CCN_EVENT_WATCHPOINT) 358 if (event->event == CCN_EVENT_WATCHPOINT)
354 res += snprintf(buf + res, PAGE_SIZE - res, 359 res += snprintf(buf + res, PAGE_SIZE - res,
355 ",cmp_l=?,cmp_h=?,mask=?"); 360 ",port=?,dir=?,cmp_l=?,cmp_h=?,mask=?");
361 else
362 res += snprintf(buf + res, PAGE_SIZE - res,
363 ",bus=?");
364
365 break;
366 case CCN_TYPE_MN:
367 res += snprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
356 break; 368 break;
357 default: 369 default:
358 res += snprintf(buf + res, PAGE_SIZE - res, ",node=?"); 370 res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
@@ -383,9 +395,9 @@ static umode_t arm_ccn_pmu_events_is_visible(struct kobject *kobj,
383} 395}
384 396
385static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = { 397static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = {
386 CCN_EVENT_MN(eobarrier, "dir=0,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE), 398 CCN_EVENT_MN(eobarrier, "dir=1,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
387 CCN_EVENT_MN(ecbarrier, "dir=0,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE), 399 CCN_EVENT_MN(ecbarrier, "dir=1,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
388 CCN_EVENT_MN(dvmop, "dir=0,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE), 400 CCN_EVENT_MN(dvmop, "dir=1,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
389 CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY), 401 CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY),
390 CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY), 402 CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY),
391 CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY), 403 CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY),
@@ -733,9 +745,10 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
733 745
734 if (has_branch_stack(event) || event->attr.exclude_user || 746 if (has_branch_stack(event) || event->attr.exclude_user ||
735 event->attr.exclude_kernel || event->attr.exclude_hv || 747 event->attr.exclude_kernel || event->attr.exclude_hv ||
736 event->attr.exclude_idle) { 748 event->attr.exclude_idle || event->attr.exclude_host ||
749 event->attr.exclude_guest) {
737 dev_warn(ccn->dev, "Can't exclude execution levels!\n"); 750 dev_warn(ccn->dev, "Can't exclude execution levels!\n");
738 return -EOPNOTSUPP; 751 return -EINVAL;
739 } 752 }
740 753
741 if (event->cpu < 0) { 754 if (event->cpu < 0) {
@@ -759,6 +772,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
759 772
760 /* Validate node/xp vs topology */ 773 /* Validate node/xp vs topology */
761 switch (type) { 774 switch (type) {
775 case CCN_TYPE_MN:
776 if (node_xp != ccn->mn_id) {
777 dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp);
778 return -EINVAL;
779 }
780 break;
762 case CCN_TYPE_XP: 781 case CCN_TYPE_XP:
763 if (node_xp >= ccn->num_xps) { 782 if (node_xp >= ccn->num_xps) {
764 dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp); 783 dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp);
@@ -886,6 +905,10 @@ static void arm_ccn_pmu_xp_dt_config(struct perf_event *event, int enable)
886 struct arm_ccn_component *xp; 905 struct arm_ccn_component *xp;
887 u32 val, dt_cfg; 906 u32 val, dt_cfg;
888 907
908 /* Nothing to do for cycle counter */
909 if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER)
910 return;
911
889 if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP) 912 if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP)
890 xp = &ccn->xp[CCN_CONFIG_XP(event->attr.config)]; 913 xp = &ccn->xp[CCN_CONFIG_XP(event->attr.config)];
891 else 914 else
@@ -917,38 +940,17 @@ static void arm_ccn_pmu_event_start(struct perf_event *event, int flags)
917 arm_ccn_pmu_read_counter(ccn, hw->idx)); 940 arm_ccn_pmu_read_counter(ccn, hw->idx));
918 hw->state = 0; 941 hw->state = 0;
919 942
920 /*
921 * Pin the timer, so that the overflows are handled by the chosen
922 * event->cpu (this is the same one as presented in "cpumask"
923 * attribute).
924 */
925 if (!ccn->irq)
926 hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
927 HRTIMER_MODE_REL_PINNED);
928
929 /* Set the DT bus input, engaging the counter */ 943 /* Set the DT bus input, engaging the counter */
930 arm_ccn_pmu_xp_dt_config(event, 1); 944 arm_ccn_pmu_xp_dt_config(event, 1);
931} 945}
932 946
933static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags) 947static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags)
934{ 948{
935 struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
936 struct hw_perf_event *hw = &event->hw; 949 struct hw_perf_event *hw = &event->hw;
937 u64 timeout;
938 950
939 /* Disable counting, setting the DT bus to pass-through mode */ 951 /* Disable counting, setting the DT bus to pass-through mode */
940 arm_ccn_pmu_xp_dt_config(event, 0); 952 arm_ccn_pmu_xp_dt_config(event, 0);
941 953
942 if (!ccn->irq)
943 hrtimer_cancel(&ccn->dt.hrtimer);
944
945 /* Let the DT bus drain */
946 timeout = arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) +
947 ccn->num_xps;
948 while (arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) <
949 timeout)
950 cpu_relax();
951
952 if (flags & PERF_EF_UPDATE) 954 if (flags & PERF_EF_UPDATE)
953 arm_ccn_pmu_event_update(event); 955 arm_ccn_pmu_event_update(event);
954 956
@@ -988,7 +990,7 @@ static void arm_ccn_pmu_xp_watchpoint_config(struct perf_event *event)
988 990
989 /* Comparison values */ 991 /* Comparison values */
990 writel(cmp_l & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_L(wp)); 992 writel(cmp_l & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_L(wp));
991 writel((cmp_l >> 32) & 0xefffffff, 993 writel((cmp_l >> 32) & 0x7fffffff,
992 source->base + CCN_XP_DT_CMP_VAL_L(wp) + 4); 994 source->base + CCN_XP_DT_CMP_VAL_L(wp) + 4);
993 writel(cmp_h & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_H(wp)); 995 writel(cmp_h & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_H(wp));
994 writel((cmp_h >> 32) & 0x0fffffff, 996 writel((cmp_h >> 32) & 0x0fffffff,
@@ -996,7 +998,7 @@ static void arm_ccn_pmu_xp_watchpoint_config(struct perf_event *event)
996 998
997 /* Mask */ 999 /* Mask */
998 writel(mask_l & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_L(wp)); 1000 writel(mask_l & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_L(wp));
999 writel((mask_l >> 32) & 0xefffffff, 1001 writel((mask_l >> 32) & 0x7fffffff,
1000 source->base + CCN_XP_DT_CMP_MASK_L(wp) + 4); 1002 source->base + CCN_XP_DT_CMP_MASK_L(wp) + 4);
1001 writel(mask_h & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_H(wp)); 1003 writel(mask_h & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_H(wp));
1002 writel((mask_h >> 32) & 0x0fffffff, 1004 writel((mask_h >> 32) & 0x0fffffff,
@@ -1014,7 +1016,7 @@ static void arm_ccn_pmu_xp_event_config(struct perf_event *event)
1014 hw->event_base = CCN_XP_DT_CONFIG__DT_CFG__XP_PMU_EVENT(hw->config_base); 1016 hw->event_base = CCN_XP_DT_CONFIG__DT_CFG__XP_PMU_EVENT(hw->config_base);
1015 1017
1016 id = (CCN_CONFIG_VC(event->attr.config) << 4) | 1018 id = (CCN_CONFIG_VC(event->attr.config) << 4) |
1017 (CCN_CONFIG_PORT(event->attr.config) << 3) | 1019 (CCN_CONFIG_BUS(event->attr.config) << 3) |
1018 (CCN_CONFIG_EVENT(event->attr.config) << 0); 1020 (CCN_CONFIG_EVENT(event->attr.config) << 0);
1019 1021
1020 val = readl(source->base + CCN_XP_PMU_EVENT_SEL); 1022 val = readl(source->base + CCN_XP_PMU_EVENT_SEL);
@@ -1099,15 +1101,31 @@ static void arm_ccn_pmu_event_config(struct perf_event *event)
1099 spin_unlock(&ccn->dt.config_lock); 1101 spin_unlock(&ccn->dt.config_lock);
1100} 1102}
1101 1103
1104static int arm_ccn_pmu_active_counters(struct arm_ccn *ccn)
1105{
1106 return bitmap_weight(ccn->dt.pmu_counters_mask,
1107 CCN_NUM_PMU_EVENT_COUNTERS + 1);
1108}
1109
1102static int arm_ccn_pmu_event_add(struct perf_event *event, int flags) 1110static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
1103{ 1111{
1104 int err; 1112 int err;
1105 struct hw_perf_event *hw = &event->hw; 1113 struct hw_perf_event *hw = &event->hw;
1114 struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
1106 1115
1107 err = arm_ccn_pmu_event_alloc(event); 1116 err = arm_ccn_pmu_event_alloc(event);
1108 if (err) 1117 if (err)
1109 return err; 1118 return err;
1110 1119
1120 /*
1121 * Pin the timer, so that the overflows are handled by the chosen
1122 * event->cpu (this is the same one as presented in "cpumask"
1123 * attribute).
1124 */
1125 if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 1)
1126 hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
1127 HRTIMER_MODE_REL_PINNED);
1128
1111 arm_ccn_pmu_event_config(event); 1129 arm_ccn_pmu_event_config(event);
1112 1130
1113 hw->state = PERF_HES_STOPPED; 1131 hw->state = PERF_HES_STOPPED;
@@ -1120,9 +1138,14 @@ static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
1120 1138
1121static void arm_ccn_pmu_event_del(struct perf_event *event, int flags) 1139static void arm_ccn_pmu_event_del(struct perf_event *event, int flags)
1122{ 1140{
1141 struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
1142
1123 arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE); 1143 arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE);
1124 1144
1125 arm_ccn_pmu_event_release(event); 1145 arm_ccn_pmu_event_release(event);
1146
1147 if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 0)
1148 hrtimer_cancel(&ccn->dt.hrtimer);
1126} 1149}
1127 1150
1128static void arm_ccn_pmu_event_read(struct perf_event *event) 1151static void arm_ccn_pmu_event_read(struct perf_event *event)
@@ -1130,6 +1153,24 @@ static void arm_ccn_pmu_event_read(struct perf_event *event)
1130 arm_ccn_pmu_event_update(event); 1153 arm_ccn_pmu_event_update(event);
1131} 1154}
1132 1155
1156static void arm_ccn_pmu_enable(struct pmu *pmu)
1157{
1158 struct arm_ccn *ccn = pmu_to_arm_ccn(pmu);
1159
1160 u32 val = readl(ccn->dt.base + CCN_DT_PMCR);
1161 val |= CCN_DT_PMCR__PMU_EN;
1162 writel(val, ccn->dt.base + CCN_DT_PMCR);
1163}
1164
1165static void arm_ccn_pmu_disable(struct pmu *pmu)
1166{
1167 struct arm_ccn *ccn = pmu_to_arm_ccn(pmu);
1168
1169 u32 val = readl(ccn->dt.base + CCN_DT_PMCR);
1170 val &= ~CCN_DT_PMCR__PMU_EN;
1171 writel(val, ccn->dt.base + CCN_DT_PMCR);
1172}
1173
1133static irqreturn_t arm_ccn_pmu_overflow_handler(struct arm_ccn_dt *dt) 1174static irqreturn_t arm_ccn_pmu_overflow_handler(struct arm_ccn_dt *dt)
1134{ 1175{
1135 u32 pmovsr = readl(dt->base + CCN_DT_PMOVSR); 1176 u32 pmovsr = readl(dt->base + CCN_DT_PMOVSR);
@@ -1252,6 +1293,8 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
1252 .start = arm_ccn_pmu_event_start, 1293 .start = arm_ccn_pmu_event_start,
1253 .stop = arm_ccn_pmu_event_stop, 1294 .stop = arm_ccn_pmu_event_stop,
1254 .read = arm_ccn_pmu_event_read, 1295 .read = arm_ccn_pmu_event_read,
1296 .pmu_enable = arm_ccn_pmu_enable,
1297 .pmu_disable = arm_ccn_pmu_disable,
1255 }; 1298 };
1256 1299
1257 /* No overflow interrupt? Have to use a timer instead. */ 1300 /* No overflow interrupt? Have to use a timer instead. */
@@ -1361,6 +1404,8 @@ static int arm_ccn_init_nodes(struct arm_ccn *ccn, int region,
1361 1404
1362 switch (type) { 1405 switch (type) {
1363 case CCN_TYPE_MN: 1406 case CCN_TYPE_MN:
1407 ccn->mn_id = id;
1408 return 0;
1364 case CCN_TYPE_DT: 1409 case CCN_TYPE_DT:
1365 return 0; 1410 return 0;
1366 case CCN_TYPE_XP: 1411 case CCN_TYPE_XP:
@@ -1471,8 +1516,9 @@ static int arm_ccn_probe(struct platform_device *pdev)
1471 /* Can set 'disable' bits, so can acknowledge interrupts */ 1516 /* Can set 'disable' bits, so can acknowledge interrupts */
1472 writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__ENABLE, 1517 writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__ENABLE,
1473 ccn->base + CCN_MN_ERRINT_STATUS); 1518 ccn->base + CCN_MN_ERRINT_STATUS);
1474 err = devm_request_irq(ccn->dev, irq, arm_ccn_irq_handler, 0, 1519 err = devm_request_irq(ccn->dev, irq, arm_ccn_irq_handler,
1475 dev_name(ccn->dev), ccn); 1520 IRQF_NOBALANCING | IRQF_NO_THREAD,
1521 dev_name(ccn->dev), ccn);
1476 if (err) 1522 if (err)
1477 return err; 1523 return err;
1478 1524