Skip to content

Commit

Permalink
[PATCH] kexec: x86_64: restore apic virtual wire mode on shutdown
Browse files Browse the repository at this point in the history
When coming out of apic mode attempt to set the appropriate
apic back into virtual wire mode.  This improves on previous versions
of this patch by by never setting bot the local apic and the ioapic
into veritual wire mode.

This code looks at data from the mptable to see if an ioapic has
an ExtInt input to make this decision.  A future improvement
is to figure out which apic or ioapic was in virtual wire mode
at boot time and to remember it.  That is potentially a more accurate
method, of selecting which apic to place in virutal wire mode.

Signed-off-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Eric W. Biederman authored and Linus Torvalds committed Jun 25, 2005
1 parent 650927e commit 208fb93
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 4 deletions.
38 changes: 37 additions & 1 deletion arch/x86_64/kernel/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void)
}
}

void disconnect_bsp_APIC(void)
void disconnect_bsp_APIC(int virt_wire_setup)
{
if (pic_mode) {
/*
Expand All @@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void)
outb(0x70, 0x22);
outb(0x00, 0x23);
}
else {
/* Go back to Virtual Wire compatibility mode */
unsigned long value;

/* For the spurious interrupt use vector F, and enable it */
value = apic_read(APIC_SPIV);
value &= ~APIC_VECTOR_MASK;
value |= APIC_SPIV_APIC_ENABLED;
value |= 0xf;
apic_write_around(APIC_SPIV, value);

if (!virt_wire_setup) {
/* For LVT0 make it edge triggered, active high, external and enabled */
value = apic_read(APIC_LVT0);
value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
apic_write_around(APIC_LVT0, value);
}
else {
/* Disable LVT0 */
apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
}

/* For LVT1 make it edge triggered, active high, nmi and enabled */
value = apic_read(APIC_LVT1);
value &= ~(
APIC_MODE_MASK | APIC_SEND_PENDING |
APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
apic_write_around(APIC_LVT1, value);
}
}

void disable_local_APIC(void)
Expand Down
36 changes: 34 additions & 2 deletions arch/x86_64/kernel/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type)
/*
* Find the pin to which IRQ[irq] (ISA) is connected
*/
static int __init find_isa_irq_pin(int irq, int type)
static int find_isa_irq_pin(int irq, int type)
{
int i;

Expand Down Expand Up @@ -1132,12 +1132,44 @@ static void __init enable_IO_APIC(void)
*/
void disable_IO_APIC(void)
{
int pin;
/*
* Clear the IO-APIC before rebooting:
*/
clear_IO_APIC();

disconnect_bsp_APIC();
/*
* If the i82559 is routed through an IOAPIC
* Put that IOAPIC in virtual wire mode
* so legacy interrups can be delivered.
*/
pin = find_isa_irq_pin(0, mp_ExtINT);
if (pin != -1) {
struct IO_APIC_route_entry entry;
unsigned long flags;

memset(&entry, 0, sizeof(entry));
entry.mask = 0; /* Enabled */
entry.trigger = 0; /* Edge */
entry.irr = 0;
entry.polarity = 0; /* High */
entry.delivery_status = 0;
entry.dest_mode = 0; /* Physical */
entry.delivery_mode = 7; /* ExtInt */
entry.vector = 0;
entry.dest.physical.physical_dest = 0;


/*
* Add it to the IO-APIC irq-routing table:
*/
spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
spin_unlock_irqrestore(&ioapic_lock, flags);
}

disconnect_bsp_APIC(pin != -1);
}

/*
Expand Down
2 changes: 1 addition & 1 deletion include/asm-x86_64/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static inline void ack_APIC_irq(void)
extern int get_maxlvt (void);
extern void clear_local_APIC (void);
extern void connect_bsp_APIC (void);
extern void disconnect_bsp_APIC (void);
extern void disconnect_bsp_APIC (int virt_wire_setup);
extern void disable_local_APIC (void);
extern int verify_local_APIC (void);
extern void cache_APIC_registers (void);
Expand Down

0 comments on commit 208fb93

Please sign in to comment.