diff options
-rw-r--r-- | arch/s390/include/asm/idle.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/irq.h | 13 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 1 | ||||
-rw-r--r-- | arch/s390/lib/delay.c | 30 |
6 files changed, 35 insertions, 17 deletions
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h index 113cd963dbbe..51ff96d9f287 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 ff95d15a2384..33d26424c2f5 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 5900877bb19c..9e1cdcf8d124 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 d653a87d66b5..857b6526d298 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 3eecd0f7adb2..b7019ab74070 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 246a7eb4b680..501dcd4ca4a0 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) |