diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 192 |
1 files changed, 96 insertions, 96 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 06c196d7e59c..fabf01eff771 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/ftrace.h> | 24 | #include <linux/ftrace.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/sysdev.h> | 27 | #include <linux/syscore_ops.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/timex.h> | 29 | #include <linux/timex.h> |
30 | #include <linux/dmar.h> | 30 | #include <linux/dmar.h> |
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/i8259.h> | 43 | #include <asm/i8259.h> |
44 | #include <asm/proto.h> | 44 | #include <asm/proto.h> |
45 | #include <asm/apic.h> | 45 | #include <asm/apic.h> |
46 | #include <asm/io_apic.h> | ||
46 | #include <asm/desc.h> | 47 | #include <asm/desc.h> |
47 | #include <asm/hpet.h> | 48 | #include <asm/hpet.h> |
48 | #include <asm/idle.h> | 49 | #include <asm/idle.h> |
@@ -78,12 +79,21 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid); | |||
78 | EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid); | 79 | EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid); |
79 | 80 | ||
80 | #ifdef CONFIG_X86_32 | 81 | #ifdef CONFIG_X86_32 |
82 | |||
83 | /* | ||
84 | * On x86_32, the mapping between cpu and logical apicid may vary | ||
85 | * depending on apic in use. The following early percpu variable is | ||
86 | * used for the mapping. This is where the behaviors of x86_64 and 32 | ||
87 | * actually diverge. Let's keep it ugly for now. | ||
88 | */ | ||
89 | DEFINE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid, BAD_APICID); | ||
90 | |||
81 | /* | 91 | /* |
82 | * Knob to control our willingness to enable the local APIC. | 92 | * Knob to control our willingness to enable the local APIC. |
83 | * | 93 | * |
84 | * +1=force-enable | 94 | * +1=force-enable |
85 | */ | 95 | */ |
86 | static int force_enable_local_apic; | 96 | static int force_enable_local_apic __initdata; |
87 | /* | 97 | /* |
88 | * APIC command line parameters | 98 | * APIC command line parameters |
89 | */ | 99 | */ |
@@ -153,7 +163,7 @@ early_param("nox2apic", setup_nox2apic); | |||
153 | unsigned long mp_lapic_addr; | 163 | unsigned long mp_lapic_addr; |
154 | int disable_apic; | 164 | int disable_apic; |
155 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ | 165 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ |
156 | static int disable_apic_timer __cpuinitdata; | 166 | static int disable_apic_timer __initdata; |
157 | /* Local APIC timer works in C2 */ | 167 | /* Local APIC timer works in C2 */ |
158 | int local_apic_timer_c2_ok; | 168 | int local_apic_timer_c2_ok; |
159 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); | 169 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); |
@@ -177,29 +187,8 @@ static struct resource lapic_resource = { | |||
177 | 187 | ||
178 | static unsigned int calibration_result; | 188 | static unsigned int calibration_result; |
179 | 189 | ||
180 | static int lapic_next_event(unsigned long delta, | ||
181 | struct clock_event_device *evt); | ||
182 | static void lapic_timer_setup(enum clock_event_mode mode, | ||
183 | struct clock_event_device *evt); | ||
184 | static void lapic_timer_broadcast(const struct cpumask *mask); | ||
185 | static void apic_pm_activate(void); | 190 | static void apic_pm_activate(void); |
186 | 191 | ||
187 | /* | ||
188 | * The local apic timer can be used for any function which is CPU local. | ||
189 | */ | ||
190 | static struct clock_event_device lapic_clockevent = { | ||
191 | .name = "lapic", | ||
192 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | ||
193 | | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, | ||
194 | .shift = 32, | ||
195 | .set_mode = lapic_timer_setup, | ||
196 | .set_next_event = lapic_next_event, | ||
197 | .broadcast = lapic_timer_broadcast, | ||
198 | .rating = 100, | ||
199 | .irq = -1, | ||
200 | }; | ||
201 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | ||
202 | |||
203 | static unsigned long apic_phys; | 192 | static unsigned long apic_phys; |
204 | 193 | ||
205 | /* | 194 | /* |
@@ -238,7 +227,7 @@ static int modern_apic(void) | |||
238 | * right after this call apic become NOOP driven | 227 | * right after this call apic become NOOP driven |
239 | * so apic->write/read doesn't do anything | 228 | * so apic->write/read doesn't do anything |
240 | */ | 229 | */ |
241 | void apic_disable(void) | 230 | static void __init apic_disable(void) |
242 | { | 231 | { |
243 | pr_info("APIC: switched to apic NOOP\n"); | 232 | pr_info("APIC: switched to apic NOOP\n"); |
244 | apic = &apic_noop; | 233 | apic = &apic_noop; |
@@ -282,23 +271,6 @@ u64 native_apic_icr_read(void) | |||
282 | return icr1 | ((u64)icr2 << 32); | 271 | return icr1 | ((u64)icr2 << 32); |
283 | } | 272 | } |
284 | 273 | ||
285 | /** | ||
286 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 | ||
287 | */ | ||
288 | void __cpuinit enable_NMI_through_LVT0(void) | ||
289 | { | ||
290 | unsigned int v; | ||
291 | |||
292 | /* unmask and set to NMI */ | ||
293 | v = APIC_DM_NMI; | ||
294 | |||
295 | /* Level triggered for 82489DX (32bit mode) */ | ||
296 | if (!lapic_is_integrated()) | ||
297 | v |= APIC_LVT_LEVEL_TRIGGER; | ||
298 | |||
299 | apic_write(APIC_LVT0, v); | ||
300 | } | ||
301 | |||
302 | #ifdef CONFIG_X86_32 | 274 | #ifdef CONFIG_X86_32 |
303 | /** | 275 | /** |
304 | * get_physical_broadcast - Get number of physical broadcast IDs | 276 | * get_physical_broadcast - Get number of physical broadcast IDs |
@@ -508,6 +480,23 @@ static void lapic_timer_broadcast(const struct cpumask *mask) | |||
508 | #endif | 480 | #endif |
509 | } | 481 | } |
510 | 482 | ||
483 | |||
484 | /* | ||
485 | * The local apic timer can be used for any function which is CPU local. | ||
486 | */ | ||
487 | static struct clock_event_device lapic_clockevent = { | ||
488 | .name = "lapic", | ||
489 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | ||
490 | | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, | ||
491 | .shift = 32, | ||
492 | .set_mode = lapic_timer_setup, | ||
493 | .set_next_event = lapic_next_event, | ||
494 | .broadcast = lapic_timer_broadcast, | ||
495 | .rating = 100, | ||
496 | .irq = -1, | ||
497 | }; | ||
498 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | ||
499 | |||
511 | /* | 500 | /* |
512 | * Setup the local APIC timer for this CPU. Copy the initialized values | 501 | * Setup the local APIC timer for this CPU. Copy the initialized values |
513 | * of the boot CPU and register the clock event in the framework. | 502 | * of the boot CPU and register the clock event in the framework. |
@@ -1209,7 +1198,7 @@ void __cpuinit setup_local_APIC(void) | |||
1209 | rdtscll(tsc); | 1198 | rdtscll(tsc); |
1210 | 1199 | ||
1211 | if (disable_apic) { | 1200 | if (disable_apic) { |
1212 | arch_disable_smp_support(); | 1201 | disable_ioapic_support(); |
1213 | return; | 1202 | return; |
1214 | } | 1203 | } |
1215 | 1204 | ||
@@ -1237,6 +1226,19 @@ void __cpuinit setup_local_APIC(void) | |||
1237 | */ | 1226 | */ |
1238 | apic->init_apic_ldr(); | 1227 | apic->init_apic_ldr(); |
1239 | 1228 | ||
1229 | #ifdef CONFIG_X86_32 | ||
1230 | /* | ||
1231 | * APIC LDR is initialized. If logical_apicid mapping was | ||
1232 | * initialized during get_smp_config(), make sure it matches the | ||
1233 | * actual value. | ||
1234 | */ | ||
1235 | i = early_per_cpu(x86_cpu_to_logical_apicid, cpu); | ||
1236 | WARN_ON(i != BAD_APICID && i != logical_smp_processor_id()); | ||
1237 | /* always use the value from LDR */ | ||
1238 | early_per_cpu(x86_cpu_to_logical_apicid, cpu) = | ||
1239 | logical_smp_processor_id(); | ||
1240 | #endif | ||
1241 | |||
1240 | /* | 1242 | /* |
1241 | * Set Task Priority to 'accept all'. We never change this | 1243 | * Set Task Priority to 'accept all'. We never change this |
1242 | * later on. | 1244 | * later on. |
@@ -1381,12 +1383,17 @@ void __cpuinit end_local_APIC_setup(void) | |||
1381 | #endif | 1383 | #endif |
1382 | 1384 | ||
1383 | apic_pm_activate(); | 1385 | apic_pm_activate(); |
1386 | } | ||
1387 | |||
1388 | void __init bsp_end_local_APIC_setup(void) | ||
1389 | { | ||
1390 | end_local_APIC_setup(); | ||
1384 | 1391 | ||
1385 | /* | 1392 | /* |
1386 | * Now that local APIC setup is completed for BP, configure the fault | 1393 | * Now that local APIC setup is completed for BP, configure the fault |
1387 | * handling for interrupt remapping. | 1394 | * handling for interrupt remapping. |
1388 | */ | 1395 | */ |
1389 | if (!smp_processor_id() && intr_remapping_enabled) | 1396 | if (intr_remapping_enabled) |
1390 | enable_drhd_fault_handling(); | 1397 | enable_drhd_fault_handling(); |
1391 | 1398 | ||
1392 | } | 1399 | } |
@@ -1443,7 +1450,7 @@ int __init enable_IR(void) | |||
1443 | void __init enable_IR_x2apic(void) | 1450 | void __init enable_IR_x2apic(void) |
1444 | { | 1451 | { |
1445 | unsigned long flags; | 1452 | unsigned long flags; |
1446 | struct IO_APIC_route_entry **ioapic_entries = NULL; | 1453 | struct IO_APIC_route_entry **ioapic_entries; |
1447 | int ret, x2apic_enabled = 0; | 1454 | int ret, x2apic_enabled = 0; |
1448 | int dmar_table_init_ret; | 1455 | int dmar_table_init_ret; |
1449 | 1456 | ||
@@ -1532,7 +1539,7 @@ static int __init detect_init_APIC(void) | |||
1532 | } | 1539 | } |
1533 | #else | 1540 | #else |
1534 | 1541 | ||
1535 | static int apic_verify(void) | 1542 | static int __init apic_verify(void) |
1536 | { | 1543 | { |
1537 | u32 features, h, l; | 1544 | u32 features, h, l; |
1538 | 1545 | ||
@@ -1557,7 +1564,7 @@ static int apic_verify(void) | |||
1557 | return 0; | 1564 | return 0; |
1558 | } | 1565 | } |
1559 | 1566 | ||
1560 | int apic_force_enable(void) | 1567 | int __init apic_force_enable(unsigned long addr) |
1561 | { | 1568 | { |
1562 | u32 h, l; | 1569 | u32 h, l; |
1563 | 1570 | ||
@@ -1573,7 +1580,7 @@ int apic_force_enable(void) | |||
1573 | if (!(l & MSR_IA32_APICBASE_ENABLE)) { | 1580 | if (!(l & MSR_IA32_APICBASE_ENABLE)) { |
1574 | pr_info("Local APIC disabled by BIOS -- reenabling.\n"); | 1581 | pr_info("Local APIC disabled by BIOS -- reenabling.\n"); |
1575 | l &= ~MSR_IA32_APICBASE_BASE; | 1582 | l &= ~MSR_IA32_APICBASE_BASE; |
1576 | l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; | 1583 | l |= MSR_IA32_APICBASE_ENABLE | addr; |
1577 | wrmsr(MSR_IA32_APICBASE, l, h); | 1584 | wrmsr(MSR_IA32_APICBASE, l, h); |
1578 | enabled_via_apicbase = 1; | 1585 | enabled_via_apicbase = 1; |
1579 | } | 1586 | } |
@@ -1614,7 +1621,7 @@ static int __init detect_init_APIC(void) | |||
1614 | "you can enable it with \"lapic\"\n"); | 1621 | "you can enable it with \"lapic\"\n"); |
1615 | return -1; | 1622 | return -1; |
1616 | } | 1623 | } |
1617 | if (apic_force_enable()) | 1624 | if (apic_force_enable(APIC_DEFAULT_PHYS_BASE)) |
1618 | return -1; | 1625 | return -1; |
1619 | } else { | 1626 | } else { |
1620 | if (apic_verify()) | 1627 | if (apic_verify()) |
@@ -1756,7 +1763,7 @@ int __init APIC_init_uniprocessor(void) | |||
1756 | enable_IO_APIC(); | 1763 | enable_IO_APIC(); |
1757 | #endif | 1764 | #endif |
1758 | 1765 | ||
1759 | end_local_APIC_setup(); | 1766 | bsp_end_local_APIC_setup(); |
1760 | 1767 | ||
1761 | #ifdef CONFIG_X86_IO_APIC | 1768 | #ifdef CONFIG_X86_IO_APIC |
1762 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | 1769 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) |
@@ -1925,17 +1932,6 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1925 | { | 1932 | { |
1926 | int cpu; | 1933 | int cpu; |
1927 | 1934 | ||
1928 | /* | ||
1929 | * Validate version | ||
1930 | */ | ||
1931 | if (version == 0x0) { | ||
1932 | pr_warning("BIOS bug, APIC version is 0 for CPU#%d! " | ||
1933 | "fixing up to 0x10. (tell your hw vendor)\n", | ||
1934 | version); | ||
1935 | version = 0x10; | ||
1936 | } | ||
1937 | apic_version[apicid] = version; | ||
1938 | |||
1939 | if (num_processors >= nr_cpu_ids) { | 1935 | if (num_processors >= nr_cpu_ids) { |
1940 | int max = nr_cpu_ids; | 1936 | int max = nr_cpu_ids; |
1941 | int thiscpu = max + disabled_cpus; | 1937 | int thiscpu = max + disabled_cpus; |
@@ -1949,22 +1945,34 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1949 | } | 1945 | } |
1950 | 1946 | ||
1951 | num_processors++; | 1947 | num_processors++; |
1952 | cpu = cpumask_next_zero(-1, cpu_present_mask); | ||
1953 | |||
1954 | if (version != apic_version[boot_cpu_physical_apicid]) | ||
1955 | WARN_ONCE(1, | ||
1956 | "ACPI: apic version mismatch, bootcpu: %x cpu %d: %x\n", | ||
1957 | apic_version[boot_cpu_physical_apicid], cpu, version); | ||
1958 | |||
1959 | physid_set(apicid, phys_cpu_present_map); | ||
1960 | if (apicid == boot_cpu_physical_apicid) { | 1948 | if (apicid == boot_cpu_physical_apicid) { |
1961 | /* | 1949 | /* |
1962 | * x86_bios_cpu_apicid is required to have processors listed | 1950 | * x86_bios_cpu_apicid is required to have processors listed |
1963 | * in same order as logical cpu numbers. Hence the first | 1951 | * in same order as logical cpu numbers. Hence the first |
1964 | * entry is BSP, and so on. | 1952 | * entry is BSP, and so on. |
1953 | * boot_cpu_init() already hold bit 0 in cpu_present_mask | ||
1954 | * for BSP. | ||
1965 | */ | 1955 | */ |
1966 | cpu = 0; | 1956 | cpu = 0; |
1957 | } else | ||
1958 | cpu = cpumask_next_zero(-1, cpu_present_mask); | ||
1959 | |||
1960 | /* | ||
1961 | * Validate version | ||
1962 | */ | ||
1963 | if (version == 0x0) { | ||
1964 | pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n", | ||
1965 | cpu, apicid); | ||
1966 | version = 0x10; | ||
1967 | } | 1967 | } |
1968 | apic_version[apicid] = version; | ||
1969 | |||
1970 | if (version != apic_version[boot_cpu_physical_apicid]) { | ||
1971 | pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", | ||
1972 | apic_version[boot_cpu_physical_apicid], cpu, version); | ||
1973 | } | ||
1974 | |||
1975 | physid_set(apicid, phys_cpu_present_map); | ||
1968 | if (apicid > max_physical_apicid) | 1976 | if (apicid > max_physical_apicid) |
1969 | max_physical_apicid = apicid; | 1977 | max_physical_apicid = apicid; |
1970 | 1978 | ||
@@ -1972,7 +1980,10 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1972 | early_per_cpu(x86_cpu_to_apicid, cpu) = apicid; | 1980 | early_per_cpu(x86_cpu_to_apicid, cpu) = apicid; |
1973 | early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid; | 1981 | early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid; |
1974 | #endif | 1982 | #endif |
1975 | 1983 | #ifdef CONFIG_X86_32 | |
1984 | early_per_cpu(x86_cpu_to_logical_apicid, cpu) = | ||
1985 | apic->x86_32_early_logical_apicid(cpu); | ||
1986 | #endif | ||
1976 | set_cpu_possible(cpu, true); | 1987 | set_cpu_possible(cpu, true); |
1977 | set_cpu_present(cpu, true); | 1988 | set_cpu_present(cpu, true); |
1978 | } | 1989 | } |
@@ -1993,10 +2004,14 @@ void default_init_apic_ldr(void) | |||
1993 | } | 2004 | } |
1994 | 2005 | ||
1995 | #ifdef CONFIG_X86_32 | 2006 | #ifdef CONFIG_X86_32 |
1996 | int default_apicid_to_node(int logical_apicid) | 2007 | int default_x86_32_numa_cpu_node(int cpu) |
1997 | { | 2008 | { |
1998 | #ifdef CONFIG_SMP | 2009 | #ifdef CONFIG_NUMA |
1999 | return apicid_2_node[hard_smp_processor_id()]; | 2010 | int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); |
2011 | |||
2012 | if (apicid != BAD_APICID) | ||
2013 | return __apicid_to_node[apicid]; | ||
2014 | return NUMA_NO_NODE; | ||
2000 | #else | 2015 | #else |
2001 | return 0; | 2016 | return 0; |
2002 | #endif | 2017 | #endif |
@@ -2031,7 +2046,7 @@ static struct { | |||
2031 | unsigned int apic_thmr; | 2046 | unsigned int apic_thmr; |
2032 | } apic_pm_state; | 2047 | } apic_pm_state; |
2033 | 2048 | ||
2034 | static int lapic_suspend(struct sys_device *dev, pm_message_t state) | 2049 | static int lapic_suspend(void) |
2035 | { | 2050 | { |
2036 | unsigned long flags; | 2051 | unsigned long flags; |
2037 | int maxlvt; | 2052 | int maxlvt; |
@@ -2069,23 +2084,21 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
2069 | return 0; | 2084 | return 0; |
2070 | } | 2085 | } |
2071 | 2086 | ||
2072 | static int lapic_resume(struct sys_device *dev) | 2087 | static void lapic_resume(void) |
2073 | { | 2088 | { |
2074 | unsigned int l, h; | 2089 | unsigned int l, h; |
2075 | unsigned long flags; | 2090 | unsigned long flags; |
2076 | int maxlvt; | 2091 | int maxlvt, ret; |
2077 | int ret = 0; | ||
2078 | struct IO_APIC_route_entry **ioapic_entries = NULL; | 2092 | struct IO_APIC_route_entry **ioapic_entries = NULL; |
2079 | 2093 | ||
2080 | if (!apic_pm_state.active) | 2094 | if (!apic_pm_state.active) |
2081 | return 0; | 2095 | return; |
2082 | 2096 | ||
2083 | local_irq_save(flags); | 2097 | local_irq_save(flags); |
2084 | if (intr_remapping_enabled) { | 2098 | if (intr_remapping_enabled) { |
2085 | ioapic_entries = alloc_ioapic_entries(); | 2099 | ioapic_entries = alloc_ioapic_entries(); |
2086 | if (!ioapic_entries) { | 2100 | if (!ioapic_entries) { |
2087 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); | 2101 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); |
2088 | ret = -ENOMEM; | ||
2089 | goto restore; | 2102 | goto restore; |
2090 | } | 2103 | } |
2091 | 2104 | ||
@@ -2147,8 +2160,6 @@ static int lapic_resume(struct sys_device *dev) | |||
2147 | } | 2160 | } |
2148 | restore: | 2161 | restore: |
2149 | local_irq_restore(flags); | 2162 | local_irq_restore(flags); |
2150 | |||
2151 | return ret; | ||
2152 | } | 2163 | } |
2153 | 2164 | ||
2154 | /* | 2165 | /* |
@@ -2156,17 +2167,11 @@ restore: | |||
2156 | * are needed on every CPU up until machine_halt/restart/poweroff. | 2167 | * are needed on every CPU up until machine_halt/restart/poweroff. |
2157 | */ | 2168 | */ |
2158 | 2169 | ||
2159 | static struct sysdev_class lapic_sysclass = { | 2170 | static struct syscore_ops lapic_syscore_ops = { |
2160 | .name = "lapic", | ||
2161 | .resume = lapic_resume, | 2171 | .resume = lapic_resume, |
2162 | .suspend = lapic_suspend, | 2172 | .suspend = lapic_suspend, |
2163 | }; | 2173 | }; |
2164 | 2174 | ||
2165 | static struct sys_device device_lapic = { | ||
2166 | .id = 0, | ||
2167 | .cls = &lapic_sysclass, | ||
2168 | }; | ||
2169 | |||
2170 | static void __cpuinit apic_pm_activate(void) | 2175 | static void __cpuinit apic_pm_activate(void) |
2171 | { | 2176 | { |
2172 | apic_pm_state.active = 1; | 2177 | apic_pm_state.active = 1; |
@@ -2174,16 +2179,11 @@ static void __cpuinit apic_pm_activate(void) | |||
2174 | 2179 | ||
2175 | static int __init init_lapic_sysfs(void) | 2180 | static int __init init_lapic_sysfs(void) |
2176 | { | 2181 | { |
2177 | int error; | ||
2178 | |||
2179 | if (!cpu_has_apic) | ||
2180 | return 0; | ||
2181 | /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ | 2182 | /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ |
2183 | if (cpu_has_apic) | ||
2184 | register_syscore_ops(&lapic_syscore_ops); | ||
2182 | 2185 | ||
2183 | error = sysdev_class_register(&lapic_sysclass); | 2186 | return 0; |
2184 | if (!error) | ||
2185 | error = sysdev_register(&device_lapic); | ||
2186 | return error; | ||
2187 | } | 2187 | } |
2188 | 2188 | ||
2189 | /* local apic needs to resume before other devices access its registers. */ | 2189 | /* local apic needs to resume before other devices access its registers. */ |