diff options
Diffstat (limited to 'drivers/bus/arm-ccn.c')
-rw-r--r-- | drivers/bus/arm-ccn.c | 112 |
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 | ||
192 | static DEFINE_MUTEX(arm_ccn_mutex); | 193 | static 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"); | |||
241 | static CCN_FORMAT_ATTR(type, "config:8-15"); | 243 | static CCN_FORMAT_ATTR(type, "config:8-15"); |
242 | static CCN_FORMAT_ATTR(event, "config:16-23"); | 244 | static CCN_FORMAT_ATTR(event, "config:16-23"); |
243 | static CCN_FORMAT_ATTR(port, "config:24-25"); | 245 | static CCN_FORMAT_ATTR(port, "config:24-25"); |
246 | static CCN_FORMAT_ATTR(bus, "config:24-25"); | ||
244 | static CCN_FORMAT_ATTR(vc, "config:26-28"); | 247 | static CCN_FORMAT_ATTR(vc, "config:26-28"); |
245 | static CCN_FORMAT_ATTR(dir, "config:29-29"); | 248 | static CCN_FORMAT_ATTR(dir, "config:29-29"); |
246 | static CCN_FORMAT_ATTR(mask, "config:30-33"); | 249 | static 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 { | |||
328 | static ssize_t arm_ccn_pmu_event_show(struct device *dev, | 332 | static 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 | ||
385 | static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = { | 397 | static 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 | ||
933 | static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags) | 947 | static 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 | ||
1104 | static 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 | |||
1102 | static int arm_ccn_pmu_event_add(struct perf_event *event, int flags) | 1110 | static 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 | ||
1121 | static void arm_ccn_pmu_event_del(struct perf_event *event, int flags) | 1139 | static 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 | ||
1128 | static void arm_ccn_pmu_event_read(struct perf_event *event) | 1151 | static 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 | ||
1156 | static 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 | |||
1165 | static 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 | |||
1133 | static irqreturn_t arm_ccn_pmu_overflow_handler(struct arm_ccn_dt *dt) | 1174 | static 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 | ||