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:
SAVE_ALL_BASE
SAVE_ALL __LC_IO_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9
stck __LC_INT_CLOCK
l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
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
io_return:
......@@ -609,26 +606,11 @@ ext_int_handler:
SAVE_ALL_BASE
SAVE_ALL __LC_EXT_OLD_PSW,0
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)
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)
/*
......
......@@ -552,10 +552,8 @@ pgm_svc_nogo:
io_int_handler:
SAVE_ALL __LC_IO_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9
stck __LC_INT_CLOCK
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
io_return:
......@@ -640,26 +638,10 @@ io_sigpending:
ext_int_handler:
SAVE_ALL __LC_EXT_OLD_PSW,0
GET_THREAD_INFO # load pointer to task_struct to R9
brasl %r14,do_extint
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
stck __LC_INT_CLOCK
la %r2,SP_PTREGS(%r15) # address of register-save area
lgr %r3,%r6 # interruption code
basr %r14,%r1 # call handler
ext_int_next:
lg %r7,0(%r7) # next list entry
ltgr %r7,%r7
jnz ext_int_loop
llgh %r3,__LC_EXT_INT_CODE # get interruption code
brasl %r14,do_extint
j io_return
/*
......
......@@ -26,7 +26,8 @@
*/
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;
int index;
......@@ -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,
ext_int_info_t *p) {
ext_int_info_t *p)
{
int index;
if (p == NULL)
......@@ -55,7 +57,8 @@ int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
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;
int index;
......@@ -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,
ext_int_info_t *p) {
ext_int_info_t *p)
{
ext_int_info_t *q;
int index;
......@@ -101,9 +105,23 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
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]++;
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);
......
......@@ -166,28 +166,29 @@ __calculate_ticks(__u64 elapsed)
* timer_interrupt() needs to keep up the real-time clock,
* 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;
__u32 ticks;
/* Calculate how many ticks have passed. */
tmp = get_clock() - S390_lowcore.jiffy_timer;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than one tick ? */
ticks = __calculate_ticks(tmp);
tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
ticks = __calculate_ticks(tmp) + 1;
S390_lowcore.jiffy_timer +=
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 {
ticks = 1;
S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
}
/* 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));
irq_enter();
#ifdef CONFIG_SMP
/*
* 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)
while (ticks--)
do_timer(regs);
#endif
irq_exit();
}
/*
......@@ -228,7 +227,7 @@ void init_cpu_timer(void)
__u64 timer;
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;
asm volatile ("SCKC %0" : : "m" (timer));
/* allow clock comparator timer interrupt */
......@@ -275,7 +274,7 @@ void __init time_init(void)
-xtime.tv_sec, -xtime.tv_nsec);
/* 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)
panic("Couldn't request external interrupt 0x1004");
......
......@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.31 $
* $Revision: 1.32 $
*/
#include <linux/config.h>
......@@ -170,7 +170,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
ip = S390_lowcore.ext_params;
cpu = smp_processor_id();
irq_enter();
if (!ip) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
......@@ -218,7 +217,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
dasd_schedule_bh(device);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
irq_exit();
}
static int
......
......@@ -293,7 +293,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
finished_sccb = ext_int_param & EXT_INT_SCCB_MASK;
evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING |
EXT_INT_STATECHANGE_PENDING);
irq_enter();
req = NULL;
if (finished_sccb != 0U) {
list_for_each(l, &sclp_req_queue) {
......@@ -321,7 +320,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
spin_unlock(&sclp_lock);
/* and start next request on the queue */
sclp_start_request();
irq_exit();
}
/*
......
......@@ -588,13 +588,15 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
*
*/
void
do_IRQ (struct pt_regs regs)
do_IRQ (struct pt_regs *regs)
{
struct tpi_info *tpi_info;
struct subchannel *sch;
struct irb *irb;
irq_enter ();
if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
account_ticks(regs);
/*
* Get interrupt information from lowcore
*/
......@@ -663,7 +665,7 @@ wait_cons_dev (void)
do {
spin_unlock(&console_subchannel.lock);
if (!cio_tpi())
udelay (100);
cpu_relax();
spin_lock(&console_subchannel.lock);
} while (console_subchannel.schib.scsw.actl != 0);
/*
......
......@@ -87,6 +87,7 @@ do { \
extern void do_call_softirq(void);
extern void account_ticks(struct pt_regs *);
#define invoke_softirq() do_call_softirq()
......
......@@ -66,6 +66,7 @@
#define __LC_IPLDEV 0xC7C
#define __LC_JIFFY_TIMER 0xC80
#define __LC_CURRENT 0xC90
#define __LC_INT_CLOCK 0xC98
#else /* __s390x__ */
#define __LC_KERNEL_STACK 0xD40
#define __LC_ASYNC_STACK 0xD48
......@@ -74,6 +75,7 @@
#define __LC_IPLDEV 0xDB8
#define __LC_JIFFY_TIMER 0xDC0
#define __LC_CURRENT 0xDD8
#define __LC_INT_CLOCK 0xDE8
#endif /* __s390x__ */
#define __LC_PANIC_MAGIC 0xE00
......@@ -174,7 +176,8 @@ struct _lowcore
__u32 percpu_offset; /* 0xc8c */
__u32 current_task; /* 0xc90 */
__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 */
/* whether the kernel died with panic() or not */
......@@ -252,7 +255,8 @@ struct _lowcore
__u64 percpu_offset; /* 0xdd0 */
__u64 current_task; /* 0xdd8 */
__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 */
/* 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