Commit 04886c76 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: system tick misaccounting.

Fix system tick misaccounting problem.
parent da822b83
...@@ -515,12 +515,9 @@ io_int_handler: ...@@ -515,12 +515,9 @@ io_int_handler:
SAVE_ALL_BASE SAVE_ALL_BASE
SAVE_ALL __LC_IO_OLD_PSW,0 SAVE_ALL __LC_IO_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
stck __LC_INT_CLOCK
l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
sr %r3,%r3
icm %r3,3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
l %r4,__LC_IO_INT_PARM # load interruption parm
l %r5,__LC_IO_INT_WORD # load interruption word
basr %r14,%r1 # branch to standard irq handler basr %r14,%r1 # branch to standard irq handler
io_return: io_return:
...@@ -609,26 +606,11 @@ ext_int_handler: ...@@ -609,26 +606,11 @@ ext_int_handler:
SAVE_ALL_BASE SAVE_ALL_BASE
SAVE_ALL __LC_EXT_OLD_PSW,0 SAVE_ALL __LC_EXT_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
stck __LC_INT_CLOCK
la %r2,SP_PTREGS(%r15) # address of register-save area
lh %r3,__LC_EXT_INT_CODE # get interruption code
l %r1,BASED(.Ldo_extint) l %r1,BASED(.Ldo_extint)
basr %r14,%r1 basr %r14,%r1
lh %r6,__LC_EXT_INT_CODE # get interruption code
lr %r1,%r6 # calculate index = code & 0xff
n %r1,BASED(.Lc0xff)
sll %r1,2
l %r7,BASED(.Lext_hash)
l %r7,0(%r1,%r7) # get first list entry for hash value
ltr %r7,%r7 # == NULL ?
bz BASED(io_return) # yes, nothing to do, exit
ext_int_loop:
ch %r6,8(%r7) # compare external interrupt code
bne BASED(ext_int_next)
l %r1,4(%r7) # get handler address
la %r2,SP_PTREGS(%r15) # address of register-save area
lr %r3,%r6 # interruption code
basr %r14,%r1 # call handler
ext_int_next:
icm %r7,15,0(%r7) # next list entry
bnz BASED(ext_int_loop)
b BASED(io_return) b BASED(io_return)
/* /*
......
...@@ -552,10 +552,8 @@ pgm_svc_nogo: ...@@ -552,10 +552,8 @@ pgm_svc_nogo:
io_int_handler: io_int_handler:
SAVE_ALL __LC_IO_OLD_PSW,0 SAVE_ALL __LC_IO_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
stck __LC_INT_CLOCK
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
llgh %r3,__LC_SUBCHANNEL_NR # load subchannel number
llgf %r4,__LC_IO_INT_PARM # load interruption parm
llgf %r5,__LC_IO_INT_WORD # load interruption word
brasl %r14,do_IRQ # call standard irq handler brasl %r14,do_IRQ # call standard irq handler
io_return: io_return:
...@@ -640,26 +638,10 @@ io_sigpending: ...@@ -640,26 +638,10 @@ io_sigpending:
ext_int_handler: ext_int_handler:
SAVE_ALL __LC_EXT_OLD_PSW,0 SAVE_ALL __LC_EXT_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
brasl %r14,do_extint stck __LC_INT_CLOCK
llgh %r6,__LC_EXT_INT_CODE # get interruption code
lgr %r1,%r6 # calculate index = code & 0xff
nill %r1,0xff
sll %r1,3
larl %r7,ext_int_hash
lg %r7,0(%r1,%r7) # get first list entry for hash value
ltgr %r7,%r7 # == NULL ?
jz io_return # yes, nothing to do, exit
ext_int_loop:
ch %r6,16(%r7) # compare external interrupt code
jne ext_int_next
lg %r1,8(%r7) # get handler address
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
lgr %r3,%r6 # interruption code llgh %r3,__LC_EXT_INT_CODE # get interruption code
basr %r14,%r1 # call handler brasl %r14,do_extint
ext_int_next:
lg %r7,0(%r7) # next list entry
ltgr %r7,%r7
jnz ext_int_loop
j io_return j io_return
/* /*
......
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
*/ */
ext_int_info_t *ext_int_hash[256] = { 0, }; ext_int_info_t *ext_int_hash[256] = { 0, };
int register_external_interrupt(__u16 code, ext_int_handler_t handler) { int register_external_interrupt(__u16 code, ext_int_handler_t handler)
{
ext_int_info_t *p; ext_int_info_t *p;
int index; int index;
...@@ -42,7 +43,8 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) { ...@@ -42,7 +43,8 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
} }
int register_early_external_interrupt(__u16 code, ext_int_handler_t handler, int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
ext_int_info_t *p) { ext_int_info_t *p)
{
int index; int index;
if (p == NULL) if (p == NULL)
...@@ -55,7 +57,8 @@ int register_early_external_interrupt(__u16 code, ext_int_handler_t handler, ...@@ -55,7 +57,8 @@ int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
return 0; return 0;
} }
int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
{
ext_int_info_t *p, *q; ext_int_info_t *p, *q;
int index; int index;
...@@ -79,7 +82,8 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { ...@@ -79,7 +82,8 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
} }
int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler, int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
ext_int_info_t *p) { ext_int_info_t *p)
{
ext_int_info_t *q; ext_int_info_t *q;
int index; int index;
...@@ -101,9 +105,23 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler, ...@@ -101,9 +105,23 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
return 0; return 0;
} }
void do_extint(void) void do_extint(struct pt_regs *regs, unsigned short code)
{ {
ext_int_info_t *p;
int index;
irq_enter();
if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
account_ticks(regs);
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
index = code & 0xff;
for (p = ext_int_hash[index]; p; p = p->next) {
if (likely(p->code == code)) {
if (likely(p->handler))
p->handler(regs, code);
}
}
irq_exit();
} }
EXPORT_SYMBOL(register_external_interrupt); EXPORT_SYMBOL(register_external_interrupt);
......
...@@ -166,28 +166,29 @@ __calculate_ticks(__u64 elapsed) ...@@ -166,28 +166,29 @@ __calculate_ticks(__u64 elapsed)
* timer_interrupt() needs to keep up the real-time clock, * timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick * as well as call the "do_timer()" routine every clocktick
*/ */
static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) void account_ticks(struct pt_regs *regs)
{ {
__u64 tmp; __u64 tmp;
__u32 ticks; __u32 ticks;
/* Calculate how many ticks have passed. */ /* Calculate how many ticks have passed. */
tmp = get_clock() - S390_lowcore.jiffy_timer; tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than one tick ? */ if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
ticks = __calculate_ticks(tmp); ticks = __calculate_ticks(tmp) + 1;
S390_lowcore.jiffy_timer += S390_lowcore.jiffy_timer +=
CLK_TICKS_PER_JIFFY * (__u64) ticks; CLK_TICKS_PER_JIFFY * (__u64) ticks;
} else if (tmp >= CLK_TICKS_PER_JIFFY) {
ticks = 2;
S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
} else { } else {
ticks = 1; ticks = 1;
S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
} }
/* set clock comparator for next tick */ /* set clock comparator for next tick */
tmp = S390_lowcore.jiffy_timer + CLK_TICKS_PER_JIFFY + CPU_DEVIATION; tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
asm volatile ("SCKC %0" : : "m" (tmp)); asm volatile ("SCKC %0" : : "m" (tmp));
irq_enter();
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
* Do not rely on the boot cpu to do the calls to do_timer. * Do not rely on the boot cpu to do the calls to do_timer.
...@@ -215,8 +216,6 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -215,8 +216,6 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
while (ticks--) while (ticks--)
do_timer(regs); do_timer(regs);
#endif #endif
irq_exit();
} }
/* /*
...@@ -228,7 +227,7 @@ void init_cpu_timer(void) ...@@ -228,7 +227,7 @@ void init_cpu_timer(void)
__u64 timer; __u64 timer;
timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY; timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
S390_lowcore.jiffy_timer = timer; S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
asm volatile ("SCKC %0" : : "m" (timer)); asm volatile ("SCKC %0" : : "m" (timer));
/* allow clock comparator timer interrupt */ /* allow clock comparator timer interrupt */
...@@ -275,7 +274,7 @@ void __init time_init(void) ...@@ -275,7 +274,7 @@ void __init time_init(void)
-xtime.tv_sec, -xtime.tv_nsec); -xtime.tv_sec, -xtime.tv_nsec);
/* request the 0x1004 external interrupt */ /* request the 0x1004 external interrupt */
if (register_early_external_interrupt(0x1004, do_comparator_interrupt, if (register_early_external_interrupt(0x1004, 0,
&ext_int_info_timer) != 0) &ext_int_info_timer) != 0)
panic("Couldn't request external interrupt 0x1004"); panic("Couldn't request external interrupt 0x1004");
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.31 $ * $Revision: 1.32 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -170,7 +170,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code) ...@@ -170,7 +170,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
ip = S390_lowcore.ext_params; ip = S390_lowcore.ext_params;
cpu = smp_processor_id(); cpu = smp_processor_id();
irq_enter();
if (!ip) { /* no intparm: unsolicited interrupt */ if (!ip) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt"); MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
...@@ -218,7 +217,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code) ...@@ -218,7 +217,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
irq_exit();
} }
static int static int
......
...@@ -293,7 +293,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) ...@@ -293,7 +293,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
finished_sccb = ext_int_param & EXT_INT_SCCB_MASK; finished_sccb = ext_int_param & EXT_INT_SCCB_MASK;
evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING | evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING |
EXT_INT_STATECHANGE_PENDING); EXT_INT_STATECHANGE_PENDING);
irq_enter();
req = NULL; req = NULL;
if (finished_sccb != 0U) { if (finished_sccb != 0U) {
list_for_each(l, &sclp_req_queue) { list_for_each(l, &sclp_req_queue) {
...@@ -321,7 +320,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) ...@@ -321,7 +320,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
spin_unlock(&sclp_lock); spin_unlock(&sclp_lock);
/* and start next request on the queue */ /* and start next request on the queue */
sclp_start_request(); sclp_start_request();
irq_exit();
} }
/* /*
......
...@@ -588,13 +588,15 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) ...@@ -588,13 +588,15 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
* *
*/ */
void void
do_IRQ (struct pt_regs regs) do_IRQ (struct pt_regs *regs)
{ {
struct tpi_info *tpi_info; struct tpi_info *tpi_info;
struct subchannel *sch; struct subchannel *sch;
struct irb *irb; struct irb *irb;
irq_enter (); irq_enter ();
if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
account_ticks(regs);
/* /*
* Get interrupt information from lowcore * Get interrupt information from lowcore
*/ */
...@@ -663,7 +665,7 @@ wait_cons_dev (void) ...@@ -663,7 +665,7 @@ wait_cons_dev (void)
do { do {
spin_unlock(&console_subchannel.lock); spin_unlock(&console_subchannel.lock);
if (!cio_tpi()) if (!cio_tpi())
udelay (100); cpu_relax();
spin_lock(&console_subchannel.lock); spin_lock(&console_subchannel.lock);
} while (console_subchannel.schib.scsw.actl != 0); } while (console_subchannel.schib.scsw.actl != 0);
/* /*
......
...@@ -87,6 +87,7 @@ do { \ ...@@ -87,6 +87,7 @@ do { \
extern void do_call_softirq(void); extern void do_call_softirq(void);
extern void account_ticks(struct pt_regs *);
#define invoke_softirq() do_call_softirq() #define invoke_softirq() do_call_softirq()
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#define __LC_IPLDEV 0xC7C #define __LC_IPLDEV 0xC7C
#define __LC_JIFFY_TIMER 0xC80 #define __LC_JIFFY_TIMER 0xC80
#define __LC_CURRENT 0xC90 #define __LC_CURRENT 0xC90
#define __LC_INT_CLOCK 0xC98
#else /* __s390x__ */ #else /* __s390x__ */
#define __LC_KERNEL_STACK 0xD40 #define __LC_KERNEL_STACK 0xD40
#define __LC_ASYNC_STACK 0xD48 #define __LC_ASYNC_STACK 0xD48
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
#define __LC_IPLDEV 0xDB8 #define __LC_IPLDEV 0xDB8
#define __LC_JIFFY_TIMER 0xDC0 #define __LC_JIFFY_TIMER 0xDC0
#define __LC_CURRENT 0xDD8 #define __LC_CURRENT 0xDD8
#define __LC_INT_CLOCK 0xDE8
#endif /* __s390x__ */ #endif /* __s390x__ */
#define __LC_PANIC_MAGIC 0xE00 #define __LC_PANIC_MAGIC 0xE00
...@@ -174,7 +176,8 @@ struct _lowcore ...@@ -174,7 +176,8 @@ struct _lowcore
__u32 percpu_offset; /* 0xc8c */ __u32 percpu_offset; /* 0xc8c */
__u32 current_task; /* 0xc90 */ __u32 current_task; /* 0xc90 */
__u32 softirq_pending; /* 0xc94 */ __u32 softirq_pending; /* 0xc94 */
__u8 pad11[0xe00-0xc98]; /* 0xc98 */ __u64 int_clock; /* 0xc98 */
__u8 pad11[0xe00-0xca0]; /* 0xca0 */
/* 0xe00 is used as indicator for dump tools */ /* 0xe00 is used as indicator for dump tools */
/* whether the kernel died with panic() or not */ /* whether the kernel died with panic() or not */
...@@ -252,7 +255,8 @@ struct _lowcore ...@@ -252,7 +255,8 @@ struct _lowcore
__u64 percpu_offset; /* 0xdd0 */ __u64 percpu_offset; /* 0xdd0 */
__u64 current_task; /* 0xdd8 */ __u64 current_task; /* 0xdd8 */
__u64 softirq_pending; /* 0xde0 */ __u64 softirq_pending; /* 0xde0 */
__u8 pad12[0xe00-0xde8]; /* 0xde8 */ __u64 int_clock; /* 0xde8 */
__u8 pad12[0xe00-0xdf0]; /* 0xdf0 */
/* 0xe00 is used as indicator for dump tools */ /* 0xe00 is used as indicator for dump tools */
/* whether the kernel died with panic() or not */ /* whether the kernel died with panic() or not */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment