summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/include/asm/idle.h2
-rw-r--r--arch/s390/include/asm/irq.h13
-rw-r--r--arch/s390/include/asm/processor.h2
-rw-r--r--arch/s390/kernel/entry.S4
-rw-r--r--arch/s390/kernel/entry.h1
-rw-r--r--arch/s390/lib/delay.c30
6 files changed, 35 insertions, 17 deletions
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h
index 113cd96..51ff96d 100644
--- a/arch/s390/include/asm/idle.h
+++ b/arch/s390/include/asm/idle.h
@@ -24,4 +24,6 @@ struct s390_idle_data {
extern struct device_attribute dev_attr_idle_count;
extern struct device_attribute dev_attr_idle_time_us;
+void psw_idle(struct s390_idle_data *, unsigned long);
+
#endif /* _S390_IDLE_H */
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index ff95d15..33d2642 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -96,6 +96,19 @@ enum irq_subclass {
IRQ_SUBCLASS_SERVICE_SIGNAL = 9,
};
+#define CR0_IRQ_SUBCLASS_MASK \
+ ((1UL << (63 - 30)) /* Warning Track */ | \
+ (1UL << (63 - 48)) /* Malfunction Alert */ | \
+ (1UL << (63 - 49)) /* Emergency Signal */ | \
+ (1UL << (63 - 50)) /* External Call */ | \
+ (1UL << (63 - 52)) /* Clock Comparator */ | \
+ (1UL << (63 - 53)) /* CPU Timer */ | \
+ (1UL << (63 - 54)) /* Service Signal */ | \
+ (1UL << (63 - 57)) /* Interrupt Key */ | \
+ (1UL << (63 - 58)) /* Measurement Alert */ | \
+ (1UL << (63 - 59)) /* Timing Alert */ | \
+ (1UL << (63 - 62))) /* IUCV */
+
void irq_subclass_register(enum irq_subclass subclass);
void irq_subclass_unregister(enum irq_subclass subclass);
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 5900877..9e1cdcf 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -15,11 +15,13 @@
#define CIF_ASCE 1 /* user asce needs fixup / uaccess */
#define CIF_NOHZ_DELAY 2 /* delay HZ disable for a tick */
#define CIF_FPU 3 /* restore vector registers */
+#define CIF_IGNORE_IRQ 4 /* ignore interrupt (for udelay) */
#define _CIF_MCCK_PENDING (1<<CIF_MCCK_PENDING)
#define _CIF_ASCE (1<<CIF_ASCE)
#define _CIF_NOHZ_DELAY (1<<CIF_NOHZ_DELAY)
#define _CIF_FPU (1<<CIF_FPU)
+#define _CIF_IGNORE_IRQ (1<<CIF_IGNORE_IRQ)
#ifndef __ASSEMBLY__
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index d653a87..857b652 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -563,6 +563,8 @@ ENTRY(io_int_handler)
stmg %r8,%r9,__PT_PSW(%r11)
mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
+ TSTMSK __LC_CPU_FLAGS,_CIF_IGNORE_IRQ
+ jo .Lio_restore
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
.Lio_loop:
@@ -738,6 +740,8 @@ ENTRY(ext_int_handler)
mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
mvc __PT_INT_PARM_LONG(8,%r11),0(%r1)
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
+ TSTMSK __LC_CPU_FLAGS,_CIF_IGNORE_IRQ
+ jo .Lio_restore
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
lgr %r2,%r11 # pass pointer to pt_regs
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index 3eecd0f..b7019ab 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -16,7 +16,6 @@ void io_int_handler(void);
void mcck_int_handler(void);
void restart_int_handler(void);
void restart_call_handler(void);
-void psw_idle(struct s390_idle_data *, unsigned long);
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 246a7eb..501dcd4 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -12,8 +12,10 @@
#include <linux/module.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/vtimer.h>
#include <asm/div64.h>
+#include <asm/idle.h>
void __delay(unsigned long loops)
{
@@ -30,26 +32,22 @@ EXPORT_SYMBOL(__delay);
static void __udelay_disabled(unsigned long long usecs)
{
- unsigned long cr0, cr6, new;
- u64 clock_saved, end;
+ unsigned long cr0, cr0_new, psw_mask;
+ struct s390_idle_data idle;
+ u64 end;
end = get_tod_clock() + (usecs << 12);
- clock_saved = local_tick_disable();
__ctl_store(cr0, 0, 0);
- __ctl_store(cr6, 6, 6);
- new = (cr0 & 0xffff00e0) | 0x00000800;
- __ctl_load(new , 0, 0);
- new = 0;
- __ctl_load(new, 6, 6);
- lockdep_off();
- do {
- set_clock_comparator(end);
- enabled_wait();
- } while (get_tod_clock_fast() < end);
- lockdep_on();
+ cr0_new = cr0 & ~CR0_IRQ_SUBCLASS_MASK;
+ cr0_new |= (1UL << (63 - 52)); /* enable clock comparator irq */
+ __ctl_load(cr0_new, 0, 0);
+ psw_mask = __extract_psw() | PSW_MASK_EXT | PSW_MASK_WAIT;
+ set_clock_comparator(end);
+ set_cpu_flag(CIF_IGNORE_IRQ);
+ psw_idle(&idle, psw_mask);
+ clear_cpu_flag(CIF_IGNORE_IRQ);
+ set_clock_comparator(S390_lowcore.clock_comparator);
__ctl_load(cr0, 0, 0);
- __ctl_load(cr6, 6, 6);
- local_tick_enable(clock_saved);
}
static void __udelay_enabled(unsigned long long usecs)