Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 142251
b: refs/heads/master
c: b24696b
h: refs/heads/master
i:
  142249: 0832c27
  142247: a0cad2a
v: v3
  • Loading branch information
Fenghua Yu authored and David Woodhouse committed Apr 3, 2009
1 parent cd74e73 commit afe64a3
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 56 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eb4a52bc660ea835482c582eaaf4893742cbd160
refs/heads/master: b24696bc55f66fecc30715e003f10fc2555a9271
4 changes: 4 additions & 0 deletions trunk/arch/x86/include/asm/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ extern void native_apic_icr_write(u32 low, u32 id);
extern u64 native_apic_icr_read(void);

#ifdef CONFIG_X86_X2APIC

#define EIM_8BIT_APIC_ID 0
#define EIM_32BIT_APIC_ID 1

/*
* Make previous memory operations globally visible before
* sending the IPI through x2apic wrmsr. We need a serializing instruction or
Expand Down
11 changes: 7 additions & 4 deletions trunk/arch/x86/include/asm/io_apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,13 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
extern void ioapic_init_mappings(void);

#ifdef CONFIG_X86_64
extern int save_IO_APIC_setup(void);
extern void mask_IO_APIC_setup(void);
extern void restore_IO_APIC_setup(void);
extern void reinit_intr_remapped_IO_APIC(int);
extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
extern void reinit_intr_remapped_IO_APIC(int intr_remapping,
struct IO_APIC_route_entry **ioapic_entries);
#endif

extern void probe_nr_irqs_gsi(void);
Expand Down
70 changes: 62 additions & 8 deletions trunk/arch/x86/kernel/apic/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,7 @@ void __init enable_IR_x2apic(void)
#ifdef CONFIG_INTR_REMAP
int ret;
unsigned long flags;
struct IO_APIC_route_entry **ioapic_entries = NULL;

if (!cpu_has_x2apic)
return;
Expand Down Expand Up @@ -1334,17 +1335,23 @@ void __init enable_IR_x2apic(void)
return;
}

ret = save_IO_APIC_setup();
ioapic_entries = alloc_ioapic_entries();
if (!ioapic_entries) {
pr_info("Allocate ioapic_entries failed: %d\n", ret);
goto end;
}

ret = save_IO_APIC_setup(ioapic_entries);
if (ret) {
pr_info("Saving IO-APIC state failed: %d\n", ret);
goto end;
}

local_irq_save(flags);
mask_IO_APIC_setup();
mask_IO_APIC_setup(ioapic_entries);
mask_8259A();

ret = enable_intr_remapping(1);
ret = enable_intr_remapping(EIM_32BIT_APIC_ID);

if (ret && x2apic_preenabled) {
local_irq_restore(flags);
Expand All @@ -1364,9 +1371,9 @@ void __init enable_IR_x2apic(void)
/*
* IR enabling failed
*/
restore_IO_APIC_setup();
restore_IO_APIC_setup(ioapic_entries);
else
reinit_intr_remapped_IO_APIC(x2apic_preenabled);
reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);

unmask_8259A();
local_irq_restore(flags);
Expand All @@ -1379,6 +1386,8 @@ void __init enable_IR_x2apic(void)
pr_info("Enabled Interrupt-remapping\n");
} else
pr_err("Failed to enable Interrupt-remapping and x2apic\n");
if (ioapic_entries)
free_ioapic_entries(ioapic_entries);
#else
if (!cpu_has_x2apic)
return;
Expand Down Expand Up @@ -1954,6 +1963,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)

local_irq_save(flags);
disable_local_APIC();
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
disable_intr_remapping();
#endif
local_irq_restore(flags);
return 0;
}
Expand All @@ -1964,15 +1977,41 @@ static int lapic_resume(struct sys_device *dev)
unsigned long flags;
int maxlvt;

#ifdef CONFIG_INTR_REMAP
int ret;
struct IO_APIC_route_entry **ioapic_entries = NULL;

if (!apic_pm_state.active)
return 0;

maxlvt = lapic_get_maxlvt();

local_irq_save(flags);
if (x2apic) {
ioapic_entries = alloc_ioapic_entries();
if (!ioapic_entries) {
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
return -ENOMEM;
}

ret = save_IO_APIC_setup(ioapic_entries);
if (ret) {
WARN(1, "Saving IO-APIC state failed: %d\n", ret);
free_ioapic_entries(ioapic_entries);
return ret;
}

mask_IO_APIC_setup(ioapic_entries);
mask_8259A();
enable_x2apic();
}
#else
if (!apic_pm_state.active)
return 0;

local_irq_save(flags);
if (x2apic)
enable_x2apic();
#endif

else {
/*
* Make sure the APICBASE points to the right address
Expand All @@ -1986,6 +2025,7 @@ static int lapic_resume(struct sys_device *dev)
wrmsr(MSR_IA32_APICBASE, l, h);
}

maxlvt = lapic_get_maxlvt();
apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
apic_write(APIC_ID, apic_pm_state.apic_id);
apic_write(APIC_DFR, apic_pm_state.apic_dfr);
Expand All @@ -2009,8 +2049,20 @@ static int lapic_resume(struct sys_device *dev)
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);

#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
reenable_intr_remapping(EIM_32BIT_APIC_ID);

if (x2apic) {
unmask_8259A();
restore_IO_APIC_setup(ioapic_entries);
free_ioapic_entries(ioapic_entries);
}
#endif

local_irq_restore(flags);


return 0;
}

Expand Down Expand Up @@ -2048,7 +2100,9 @@ static int __init init_lapic_sysfs(void)
error = sysdev_register(&device_lapic);
return error;
}
device_initcall(init_lapic_sysfs);

/* local apic needs to resume before other devices access its registers. */
core_initcall(init_lapic_sysfs);

#else /* CONFIG_PM */

Expand Down
111 changes: 70 additions & 41 deletions trunk/arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,63 +851,74 @@ __setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */

#ifdef CONFIG_INTR_REMAP
/* I/O APIC RTE contents at the OS boot up */
static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
struct IO_APIC_route_entry **alloc_ioapic_entries(void)
{
int apic;
struct IO_APIC_route_entry **ioapic_entries;

ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
GFP_ATOMIC);
if (!ioapic_entries)
return 0;

for (apic = 0; apic < nr_ioapics; apic++) {
ioapic_entries[apic] =
kzalloc(sizeof(struct IO_APIC_route_entry) *
nr_ioapic_registers[apic], GFP_ATOMIC);
if (!ioapic_entries[apic])
goto nomem;
}

return ioapic_entries;

nomem:
while (--apic >= 0)
kfree(ioapic_entries[apic]);
kfree(ioapic_entries);

return 0;
}

/*
* Saves all the IO-APIC RTE's
*/
int save_IO_APIC_setup(void)
int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
union IO_APIC_reg_01 reg_01;
unsigned long flags;
int apic, pin;

/*
* The number of IO-APIC IRQ registers (== #pins):
*/
for (apic = 0; apic < nr_ioapics; apic++) {
spin_lock_irqsave(&ioapic_lock, flags);
reg_01.raw = io_apic_read(apic, 1);
spin_unlock_irqrestore(&ioapic_lock, flags);
nr_ioapic_registers[apic] = reg_01.bits.entries+1;
}
if (!ioapic_entries)
return -ENOMEM;

for (apic = 0; apic < nr_ioapics; apic++) {
early_ioapic_entries[apic] =
kzalloc(sizeof(struct IO_APIC_route_entry) *
nr_ioapic_registers[apic], GFP_KERNEL);
if (!early_ioapic_entries[apic])
goto nomem;
}
if (!ioapic_entries[apic])
return -ENOMEM;

for (apic = 0; apic < nr_ioapics; apic++)
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
early_ioapic_entries[apic][pin] =
ioapic_entries[apic][pin] =
ioapic_read_entry(apic, pin);
}

return 0;

nomem:
while (apic >= 0)
kfree(early_ioapic_entries[apic--]);
memset(early_ioapic_entries, 0,
ARRAY_SIZE(early_ioapic_entries));

return -ENOMEM;
}

void mask_IO_APIC_setup(void)
/*
* Mask all IO APIC entries.
*/
void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
int apic, pin;

if (!ioapic_entries)
return;

for (apic = 0; apic < nr_ioapics; apic++) {
if (!early_ioapic_entries[apic])
if (!ioapic_entries[apic])
break;

for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
struct IO_APIC_route_entry entry;

entry = early_ioapic_entries[apic][pin];
entry = ioapic_entries[apic][pin];
if (!entry.mask) {
entry.mask = 1;
ioapic_write_entry(apic, pin, entry);
Expand All @@ -916,22 +927,30 @@ void mask_IO_APIC_setup(void)
}
}

void restore_IO_APIC_setup(void)
/*
* Restore IO APIC entries which was saved in ioapic_entries.
*/
int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
{
int apic, pin;

if (!ioapic_entries)
return -ENOMEM;

for (apic = 0; apic < nr_ioapics; apic++) {
if (!early_ioapic_entries[apic])
break;
if (!ioapic_entries[apic])
return -ENOMEM;

for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
ioapic_write_entry(apic, pin,
early_ioapic_entries[apic][pin]);
kfree(early_ioapic_entries[apic]);
early_ioapic_entries[apic] = NULL;
ioapic_entries[apic][pin]);
}
return 0;
}

void reinit_intr_remapped_IO_APIC(int intr_remapping)
void reinit_intr_remapped_IO_APIC(int intr_remapping,
struct IO_APIC_route_entry **ioapic_entries)

{
/*
* for now plain restore of previous settings.
Expand All @@ -940,7 +959,17 @@ void reinit_intr_remapped_IO_APIC(int intr_remapping)
* table entries. for now, do a plain restore, and wait for
* the setup_IO_APIC_irqs() to do proper initialization.
*/
restore_IO_APIC_setup();
restore_IO_APIC_setup(ioapic_entries);
}

void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
{
int apic;

for (apic = 0; apic < nr_ioapics; apic++)
kfree(ioapic_entries[apic]);

kfree(ioapic_entries);
}
#endif

Expand Down
Loading

0 comments on commit afe64a3

Please sign in to comment.