SMP - clock calibration spurious IRQ deadlock fix
- this patch fixes a deadlock which may occur if we get a spurious interrupt while calibrating clocks during the boot time. Since we never handle interrupts while in the kernel (BKL locked) the interrupt code locks the lock. This is a different situation, a corner case, boot time only. We do not return to userspace but to the kernel, so the BKL is not unlocked. So we need irq handler which leaves the BKL unlocked. The clock handler does it already, this patch adds a dummy spurious irq handler for the same reason. It is better to handle the situation this way to keep the normal runtime code simple.
This commit is contained in:
parent
c468f4efa5
commit
5c0927e108
2 changed files with 20 additions and 1 deletions
|
@ -49,6 +49,7 @@
|
||||||
#define XT_WINI_IRQ 5 /* xt winchester */
|
#define XT_WINI_IRQ 5 /* xt winchester */
|
||||||
#define FLOPPY_IRQ 6 /* floppy disk */
|
#define FLOPPY_IRQ 6 /* floppy disk */
|
||||||
#define PRINTER_IRQ 7
|
#define PRINTER_IRQ 7
|
||||||
|
#define SPURIOUS_IRQ 7
|
||||||
#define CMOS_CLOCK_IRQ 8
|
#define CMOS_CLOCK_IRQ 8
|
||||||
#define KBD_AUX_IRQ 12 /* AUX (PS/2 mouse) port in kbd controller */
|
#define KBD_AUX_IRQ 12 /* AUX (PS/2 mouse) port in kbd controller */
|
||||||
#define AT_WINI_0_IRQ 14 /* at winchester controller 0 */
|
#define AT_WINI_0_IRQ 14 /* at winchester controller 0 */
|
||||||
|
|
|
@ -428,13 +428,22 @@ PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE int spurious_irq_handler(irq_hook_t * UNUSED(hook))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Do nothing, only unlock the kernel so we do not deadlock!
|
||||||
|
*/
|
||||||
|
BKL_UNLOCK();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
PRIVATE void apic_calibrate_clocks(unsigned cpu)
|
PRIVATE void apic_calibrate_clocks(unsigned cpu)
|
||||||
{
|
{
|
||||||
u32_t lvtt, val, lapic_delta;
|
u32_t lvtt, val, lapic_delta;
|
||||||
u64_t tsc_delta;
|
u64_t tsc_delta;
|
||||||
u64_t cpu_freq;
|
u64_t cpu_freq;
|
||||||
|
|
||||||
irq_hook_t calib_clk;
|
irq_hook_t calib_clk, spurious_irq;
|
||||||
|
|
||||||
BOOT_VERBOSE(printf("Calibrating clock\n"));
|
BOOT_VERBOSE(printf("Calibrating clock\n"));
|
||||||
/*
|
/*
|
||||||
|
@ -467,6 +476,14 @@ PRIVATE void apic_calibrate_clocks(unsigned cpu)
|
||||||
/* set the probe, we use the legacy timer, IRQ 0 */
|
/* set the probe, we use the legacy timer, IRQ 0 */
|
||||||
put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
|
put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A spurious interrupt may occur during the clock calibration. Since we
|
||||||
|
* do this calibration in kernel, we need a special handler which will
|
||||||
|
* leave the BKL unlocked like the clock handler. This is a corner case,
|
||||||
|
* boot time only situation
|
||||||
|
*/
|
||||||
|
put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler);
|
||||||
|
|
||||||
/* set the PIC timer to get some time */
|
/* set the PIC timer to get some time */
|
||||||
init_8253A_timer(system_hz);
|
init_8253A_timer(system_hz);
|
||||||
|
|
||||||
|
@ -489,6 +506,7 @@ PRIVATE void apic_calibrate_clocks(unsigned cpu)
|
||||||
|
|
||||||
/* remove the probe */
|
/* remove the probe */
|
||||||
rm_irq_handler(&calib_clk);
|
rm_irq_handler(&calib_clk);
|
||||||
|
rm_irq_handler(&spurious_irq);
|
||||||
|
|
||||||
lapic_delta = lapic_tctr0 - lapic_tctr1;
|
lapic_delta = lapic_tctr0 - lapic_tctr1;
|
||||||
tsc_delta = sub64(tsc1, tsc0);
|
tsc_delta = sub64(tsc1, tsc0);
|
||||||
|
|
Loading…
Reference in a new issue