提交 274cfe59 编写于 作者: C Cyrill Gorcunov 提交者: Ingo Molnar

x86: apic - rearrange functions and comments

Rearrange functions and comments to find differences
easier.

Also use apic_printk in setup_boot_APIC_clock for
64bit mode.
Signed-off-by: NCyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: NIngo Molnar <mingo@elte.hu>
上级 24968cfd
...@@ -251,6 +251,9 @@ int lapic_get_maxlvt(void) ...@@ -251,6 +251,9 @@ int lapic_get_maxlvt(void)
* this function twice on the boot CPU, once with a bogus timeout * this function twice on the boot CPU, once with a bogus timeout
* value, second time for real. The other (noncalibrating) CPUs * value, second time for real. The other (noncalibrating) CPUs
* call this function only once, with the real, calibrated value. * call this function only once, with the real, calibrated value.
*
* We do reads before writes even if unnecessary, to get around the
* P5 APIC double write bug.
*/ */
static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
{ {
...@@ -279,6 +282,36 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) ...@@ -279,6 +282,36 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
apic_write(APIC_TMICT, clocks / APIC_DIVISOR); apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
} }
/*
* Setup extended LVT, AMD specific (K8, family 10h)
*
* Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
* MCE interrupts are supported. Thus MCE offset must be set to 0.
*/
#define APIC_EILVT_LVTOFF_MCE 0
#define APIC_EILVT_LVTOFF_IBS 1
static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
{
unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
unsigned int v = (mask << 16) | (msg_type << 8) | vector;
apic_write(reg, v);
}
u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
{
setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_MCE;
}
u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
{
setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_IBS;
}
/* /*
* Program the next event, relative to now * Program the next event, relative to now
*/ */
...@@ -298,7 +331,7 @@ static void lapic_timer_setup(enum clock_event_mode mode, ...@@ -298,7 +331,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
unsigned long flags; unsigned long flags;
unsigned int v; unsigned int v;
/* Lapic used for broadcast ? */ /* Lapic used as dummy for broadcast ? */
if (evt->features & CLOCK_EVT_FEAT_DUMMY) if (evt->features & CLOCK_EVT_FEAT_DUMMY)
return; return;
...@@ -680,35 +713,6 @@ int setup_profiling_timer(unsigned int multiplier) ...@@ -680,35 +713,6 @@ int setup_profiling_timer(unsigned int multiplier)
return -EINVAL; return -EINVAL;
} }
/*
* Setup extended LVT, AMD specific (K8, family 10h)
*
* Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
* MCE interrupts are supported. Thus MCE offset must be set to 0.
*/
#define APIC_EILVT_LVTOFF_MCE 0
#define APIC_EILVT_LVTOFF_IBS 1
static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
{
unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
unsigned int v = (mask << 16) | (msg_type << 8) | vector;
apic_write(reg, v);
}
u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
{
setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_MCE;
}
u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
{
setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_IBS;
}
/* /*
* Local APIC start and shutdown * Local APIC start and shutdown
*/ */
...@@ -1542,6 +1546,11 @@ void __cpuinit generic_processor_info(int apicid, int version) ...@@ -1542,6 +1546,11 @@ void __cpuinit generic_processor_info(int apicid, int version)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static struct { static struct {
/*
* 'active' is true if the local APIC was enabled by us and
* not the BIOS; this signifies that we are also responsible
* for disabling it before entering apm/acpi suspend
*/
int active; int active;
/* r/w apic fields */ /* r/w apic fields */
unsigned int apic_id; unsigned int apic_id;
......
...@@ -81,6 +81,9 @@ static void lapic_timer_setup(enum clock_event_mode mode, ...@@ -81,6 +81,9 @@ static void lapic_timer_setup(enum clock_event_mode mode,
static void lapic_timer_broadcast(cpumask_t mask); static void lapic_timer_broadcast(cpumask_t mask);
static void apic_pm_activate(void); static void apic_pm_activate(void);
/*
* The local apic timer can be used for any function which is CPU local.
*/
static struct clock_event_device lapic_clockevent = { static struct clock_event_device lapic_clockevent = {
.name = "lapic", .name = "lapic",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
...@@ -127,6 +130,11 @@ static int modern_apic(void) ...@@ -127,6 +130,11 @@ static int modern_apic(void)
return lapic_get_version() >= 0x14; return lapic_get_version() >= 0x14;
} }
/*
* Paravirt kernels also might be using these below ops. So we still
* use generic apic_read()/apic_write(), which might be pointing to different
* ops in PARAVIRT case.
*/
void xapic_wait_icr_idle(void) void xapic_wait_icr_idle(void)
{ {
while (apic_read(APIC_ICR) & APIC_ICR_BUSY) while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
...@@ -175,7 +183,6 @@ static struct apic_ops xapic_ops = { ...@@ -175,7 +183,6 @@ static struct apic_ops xapic_ops = {
}; };
struct apic_ops __read_mostly *apic_ops = &xapic_ops; struct apic_ops __read_mostly *apic_ops = &xapic_ops;
EXPORT_SYMBOL_GPL(apic_ops); EXPORT_SYMBOL_GPL(apic_ops);
static void x2apic_wait_icr_idle(void) static void x2apic_wait_icr_idle(void)
...@@ -244,6 +251,10 @@ int lapic_get_maxlvt(void) ...@@ -244,6 +251,10 @@ int lapic_get_maxlvt(void)
return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2; return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
} }
/*
* Local APIC timer
*/
/* Clock divisor is set to 1 */ /* Clock divisor is set to 1 */
#define APIC_DIVISOR 1 #define APIC_DIVISOR 1
...@@ -257,7 +268,6 @@ int lapic_get_maxlvt(void) ...@@ -257,7 +268,6 @@ int lapic_get_maxlvt(void)
* We do reads before writes even if unnecessary, to get around the * We do reads before writes even if unnecessary, to get around the
* P5 APIC double write bug. * P5 APIC double write bug.
*/ */
static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
{ {
unsigned int lvtt_value, tmp_value; unsigned int lvtt_value, tmp_value;
...@@ -474,10 +484,10 @@ static int __init calibrate_APIC_clock(void) ...@@ -474,10 +484,10 @@ static int __init calibrate_APIC_clock(void)
void __init setup_boot_APIC_clock(void) void __init setup_boot_APIC_clock(void)
{ {
/* /*
* The local apic timer can be disabled via the kernel commandline. * The local apic timer can be disabled via the kernel
* Register the lapic timer as a dummy clock event source on SMP * commandline or from the CPU detection code. Register the lapic
* systems, so the broadcast mechanism is used. On UP systems simply * timer as a dummy clock event source on SMP systems, so the
* ignore it. * broadcast mechanism is used. On UP systems simply ignore it.
*/ */
if (disable_apic_timer) { if (disable_apic_timer) {
printk(KERN_INFO "Disabling APIC timer\n"); printk(KERN_INFO "Disabling APIC timer\n");
...@@ -489,7 +499,9 @@ void __init setup_boot_APIC_clock(void) ...@@ -489,7 +499,9 @@ void __init setup_boot_APIC_clock(void)
return; return;
} }
printk(KERN_INFO "Using local APIC timer interrupts.\n"); apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
"calibrating APIC timer ...\n");
if (calibrate_APIC_clock()) { if (calibrate_APIC_clock()) {
/* No broadcast on UP ! */ /* No broadcast on UP ! */
if (num_possible_cpus() > 1) if (num_possible_cpus() > 1)
...@@ -508,6 +520,7 @@ void __init setup_boot_APIC_clock(void) ...@@ -508,6 +520,7 @@ void __init setup_boot_APIC_clock(void)
printk(KERN_WARNING "APIC timer registered as dummy," printk(KERN_WARNING "APIC timer registered as dummy,"
" due to nmi_watchdog=%d!\n", nmi_watchdog); " due to nmi_watchdog=%d!\n", nmi_watchdog);
/* Setup the lapic or request the broadcast */
setup_APIC_timer(); setup_APIC_timer();
} }
...@@ -577,6 +590,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) ...@@ -577,6 +590,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
irq_enter(); irq_enter();
local_apic_timer_interrupt(); local_apic_timer_interrupt();
irq_exit(); irq_exit();
set_irq_regs(old_regs); set_irq_regs(old_regs);
} }
...@@ -1248,6 +1262,13 @@ void __init connect_bsp_APIC(void) ...@@ -1248,6 +1262,13 @@ void __init connect_bsp_APIC(void)
enable_apic_mode(); enable_apic_mode();
} }
/**
* disconnect_bsp_APIC - detach the APIC from the interrupt system
* @virt_wire_setup: indicates, whether virtual wire mode is selected
*
* Virtual wire mode is necessary to deliver legacy interrupts even when the
* APIC is disabled.
*/
void disconnect_bsp_APIC(int virt_wire_setup) void disconnect_bsp_APIC(int virt_wire_setup)
{ {
/* Go back to Virtual Wire compatibility mode */ /* Go back to Virtual Wire compatibility mode */
...@@ -1347,9 +1368,11 @@ int hard_smp_processor_id(void) ...@@ -1347,9 +1368,11 @@ int hard_smp_processor_id(void)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static struct { static struct {
/* 'active' is true if the local APIC was enabled by us and /*
not the BIOS; this signifies that we are also responsible * 'active' is true if the local APIC was enabled by us and
for disabling it before entering apm/acpi suspend */ * not the BIOS; this signifies that we are also responsible
* for disabling it before entering apm/acpi suspend
*/
int active; int active;
/* r/w apic fields */ /* r/w apic fields */
unsigned int apic_id; unsigned int apic_id;
...@@ -1458,6 +1481,11 @@ static int lapic_resume(struct sys_device *dev) ...@@ -1458,6 +1481,11 @@ static int lapic_resume(struct sys_device *dev)
return 0; return 0;
} }
/*
* This device has no shutdown method - fully functioning local APICs
* are needed on every CPU up until machine_halt/restart/poweroff.
*/
static struct sysdev_class lapic_sysclass = { static struct sysdev_class lapic_sysclass = {
.name = "lapic", .name = "lapic",
.resume = lapic_resume, .resume = lapic_resume,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册