Convert APIC to driver model: now it works with SMP
Hi!
I've undone part of renaming, so that now it actually works with SMP. Sorry.
Pavel
%patch
arch/i386/kernel/apic.c +68 -101
@@ -10,6 +10,8 @@* for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. * Mikael Pettersson : Power Management for UP-APIC. +* Pavel Machek and +* Mikael Pettersson : Converted to driver model. */ #include <linux/config.h>
@@ -23,6 +25,10 @@#include <linux/interrupt.h> #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/pm.h> #include <asm/atomic.h> #include <asm/smp.h>
@@ -304,6 +310,27 @@apic_write_around (APIC_LVT1 , value); } +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; +/* r/w apic fields */ +unsigned int apic_id; +unsigned int apic_taskpri; +unsigned int apic_ldr; +unsigned int apic_dfr; +unsigned int apic_spiv; +unsigned int apic_lvtt; +unsigned int apic_lvtpc; +unsigned int apic_lvt0; +unsigned int apic_lvt1; +unsigned int apic_lvterr; +unsigned int apic_tmict; +unsigned int apic_tdcr; +unsigned int apic_thmr; +} apic_pm_state; +void __init setup_local_APIC (void ) {unsigned long value, ver, maxlvt;
@@ -445,46 +472,24 @@printk ("No ESR for 82489DX.\n" ); } -if (nmi_watchdog ==NMI_LOCAL_APIC ) -setup_apic_nmi_watchdog (); +if (nmi_watchdog ==NMI_LOCAL_APIC ) { +enable_lapic_nmi_watchdog (); + } + + apic_pm_state.active =1 ; }#ifdef CONFIG_PM - -#include <linux/slab.h> -#include <linux/pm.h> - -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; -/* 'perfctr_pmdev' is here because the current (2.4.1) PM -callback system doesn't handle hierarchical dependencies */ -struct pm_dev *perfctr_pmdev; -/* r/w apic fields */ -unsigned int apic_id; -unsigned int apic_taskpri; -unsigned int apic_ldr; -unsigned int apic_dfr; -unsigned int apic_spiv; -unsigned int apic_lvtt; -unsigned int apic_lvtpc; -unsigned int apic_lvt0; -unsigned int apic_lvt1; -unsigned int apic_lvterr; -unsigned int apic_tmict; -unsigned int apic_tdcr; -unsigned int apic_thmr; -} apic_pm_state; - -static void apic_pm_suspend (void *data) +static int lapic_suspend (struct device *dev,u32 state,u32 level) {unsigned int l, h;unsigned long flags; -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_SUSPEND , data); +if (level !=SUSPEND_POWER_DOWN ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + apic_pm_state.apic_id =apic_read (APIC_ID ); apic_pm_state.apic_taskpri =apic_read (APIC_TASKPRI ); apic_pm_state.apic_ldr =apic_read (APIC_LDR );
@@ -505,13 +510,21 @@ l &= ~MSR_IA32_APICBASE_ENABLE ;wrmsr (MSR_IA32_APICBASE , l, h);local_irq_restore (flags); +return 0 ; } -static void apic_pm_resume (void *data) +static int lapic_resume (struct device *dev,u32 level) {unsigned int l, h;unsigned long flags; +if (level !=RESUME_POWER_ON ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + +set_fixmap_nocache (FIX_APIC_BASE ,APIC_DEFAULT_PHYS_BASE );/* FIXME: this is needed for S3 resume, but why? */ +local_irq_save (flags);rdmsr (MSR_IA32_APICBASE , l, h); l &= ~MSR_IA32_APICBASE_BASE ;
@@ -536,74 +549,35 @@apic_write (APIC_ESR ,0 );apic_read (APIC_ESR );local_irq_restore (flags); -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_RESUME , data); -} - -static int apic_pm_callback (struct pm_dev *dev,pm_request_t rqst,void *data) -{ -switch (rqst) { -case PM_SUSPEND : -apic_pm_suspend (data); -break ; -case PM_RESUME : -apic_pm_resume (data); -break ; - } return 0; } -/* perfctr driver should call this instead of pm_register() */ -struct pm_dev *apic_pm_register (pm_dev_t type, -unsigned long id, -pm_callback callback) -{ -struct pm_dev *dev; - -if (!apic_pm_state.active) -return pm_register (type, id, callback); -if (apic_pm_state.perfctr_pmdev) -return NULL ;/* we're busy */ - dev =kmalloc (sizeof (struct pm_dev ),GFP_KERNEL ); -if (dev) { -memset (dev,0 ,sizeof (*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - apic_pm_state.perfctr_pmdev = dev; - } -return dev; -} - -/* perfctr driver should call this instead of pm_unregister() */ -void apic_pm_unregister (struct pm_dev *dev) -{ -if (!apic_pm_state.active) { -pm_unregister (dev); - }else if (dev == apic_pm_state.perfctr_pmdev) { - apic_pm_state.perfctr_pmdev =NULL ; -kfree (dev); - } -} - -static void __init apic_pm_init1 (void ) -{ -/* can't pm_register() at this early stage in the boot process -(causes an immediate reboot), so just set the flag */ - apic_pm_state.active =1 ; -} +static struct device_driver lapic_driver = { + .name ="apic" , + .bus = &system_bus_type, + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +/* not static, needed by child devices */ +struct sys_device device_lapic = { + .name ="apic" , + .id =0 , + .dev = { + .name ="lapic" , + .driver = &lapic_driver, + }, +}; -static void __init apic_pm_init2 (void ) +static int __init init_apic_devicefs (void ) { +driver_register (&lapic_driver);if (apic_pm_state.active) -pm_register (PM_SYS_DEV ,0 , apic_pm_callback); +return sys_device_register (&device_lapic); +return 0 ; } -#else /* CONFIG_PM */ - -static inline void apic_pm_init1 (void ) { } -static inline void apic_pm_init2 (void ) { } - +device_initcall (init_apic_devicefs);#endif /* CONFIG_PM */ /*
@@ -669,9 +643,6 @@ nmi_watchdog =NMI_LOCAL_APIC ;printk ("Found and enabled local APIC!\n" ); - -apic_pm_init1 (); -return 0 ; no_apic:
@@ -682,7 +653,6 @@void __init init_apic_mappings (void ) {unsigned long apic_phys; -/* * If no local APIC can be found then set up a fake all * zeroes page to simulate the local APIC and another
@@ -1150,13 +1120,10 @@ }verify_local_APIC (); -connect_bsp_APIC (); phys_cpu_present_map =1 << boot_cpu_physical_apicid; -apic_pm_init2 (); -setup_local_APIC ();if (nmi_watchdog ==NMI_LOCAL_APIC )
arch/i386/kernel/apm.c +7 -0
@@ -221,6 +221,7 @@#include <linux/kernel.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/device.h> #include <asm/system.h> #include <asm/uaccess.h>
@@ -1237,6 +1238,10 @@ }printk (KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n" ); } + + +device_suspend (3 ,SUSPEND_POWER_DOWN ); +/* serialize with the timer interrupt */ write_seqlock_irq (&xtime_lock);
@@ -1257,6 +1262,7 @@if (err !=APM_SUCCESS )apm_error ("suspend" , err); err = (err ==APM_SUCCESS ) ?0 : -EIO ; +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (APM_NORMAL_RESUME ,NULL ); out:
@@ -1370,6 +1376,7 @@write_seqlock_irq (&xtime_lock);set_time ();write_sequnlock_irq (&xtime_lock); +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (event,NULL ); }
arch/i386/kernel/i386_ksyms.c +0 -4
@@ -163,10 +163,6 @@EXPORT_SYMBOL (flush_tlb_page);#endif -#if defined(CONFIG_X86_LOCAL_APIC ) && defined(CONFIG_PM ) -EXPORT_SYMBOL_GPL (set_nmi_pm_callback); -EXPORT_SYMBOL_GPL (unset_nmi_pm_callback); -#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL (IO_APIC_get_PCI_irq_vector);#endif
arch/i386/kernel/nmi.c +60 -40
190 lines not on this page · raw message
arch/i386/oprofile/nmi_int.c +57 -25
118 lines not on this page · raw message
include/asm-i386/apic.h +5 -1
@@ -78,7 +78,8 @@extern void smp_local_timer_interrupt (struct pt_regs * regs);extern void setup_boot_APIC_clock (void );extern void setup_secondary_APIC_clock (void ); -extern void setup_apic_nmi_watchdog (void ); +extern void enable_lapic_nmi_watchdog (void ); +extern void disable_lapic_nmi_watchdog (void );extern inline void nmi_watchdog_tick (struct pt_regs * regs);extern int APIC_init_uniprocessor (void );extern void disable_APIC_timer (void );
@@ -95,6 +96,9 @@#define NMI_IO_APIC 1#define NMI_LOCAL_APIC 2#define NMI_INVALID 3 +#define NMI_LOCAL_APIC_SUSPENDED_BY_OPROFILE 4 + +extern struct sys_device device_lapic;#endif /* CONFIG_X86_LOCAL_APIC */
%diffstat
arch/i386/kernel/apic.c | 169 ++++++++++++++++-------------------------- arch/i386/kernel/apm.c | 7 + arch/i386/kernel/i386_ksyms.c | 4 arch/i386/kernel/io_apic.c | 15 ++- arch/i386/kernel/nmi.c | 100 ++++++++++++++---------- arch/i386/oprofile/nmi_int.c | 82 ++++++++++++++------ include/asm-i386/apic.h | 6 + 7 files changed, 206 insertions(+), 177 deletions(-)
Signature · 2 lines
When do you have a heart between your knees? [Johanka's followup: and *two* hearts?]
arch/i386/oprofile/nmi_int.c:102: warning: initialization from incompatible pointer type arch/i386/oprofile/nmi_int.c: In function `init_nmi_driverfs':arch/i386/oprofile/nmi_int.c:129: warning: control reaches end of non-void function
arch/i386/oprofile/built-in.o(.data+0x568): undefined reference to `device_lapic'
Config is at:
ftp://ftp.kernel.org/pub/linux/kernel/people/mbligh/config/config.numaq
Quoted 698 lines · --On Sunday, March 30, 2003 21:30:27 +0200 Pavel Machek <[email protected]> wrote:
Hi!
I've undone part of renaming, so that now it actually works with SMP. Sorry.
Pavel
%patch
Index:linux/arch/i386/kernel/apic.c
===================================================================arch/i386/kernel/apic.c +68
-101@@ -10,6 +10,8 @@* for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. * Mikael Pettersson : Power Management for UP-APIC. +* Pavel Machek and +* Mikael Pettersson : Converted to driver model. */ #include <linux/config.h> @@ -23,6 +25,10 @@#include <linux/interrupt.h> #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/pm.h> #include <asm/atomic.h> #include <asm/smp.h> @@ -304,6 +310,27 @@apic_write_around (APIC_LVT1 , value); } +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; +/* r/w apic fields */ +unsigned int apic_id; +unsigned int apic_taskpri; +unsigned int apic_ldr; +unsigned int apic_dfr; +unsigned int apic_spiv; +unsigned int apic_lvtt; +unsigned int apic_lvtpc; +unsigned int apic_lvt0; +unsigned int apic_lvt1; +unsigned int apic_lvterr; +unsigned int apic_tmict; +unsigned int apic_tdcr; +unsigned int apic_thmr; +} apic_pm_state; +void __init setup_local_APIC (void ) {unsigned long value, ver, maxlvt;@@ -445,46 +472,24 @@printk ("No ESR for 82489DX.\n" ); } -if (nmi_watchdog ==NMI_LOCAL_APIC ) -setup_apic_nmi_watchdog (); +if (nmi_watchdog ==NMI_LOCAL_APIC ) { +enable_lapic_nmi_watchdog (); + } + + apic_pm_state.active =1 ; }#ifdef CONFIG_PM - -#include <linux/slab.h> -#include <linux/pm.h> - -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; -/* 'perfctr_pmdev' is here because the current (2.4.1) PM -callback system doesn't handle hierarchical dependencies */ -struct pm_dev *perfctr_pmdev; -/* r/w apic fields */ -unsigned int apic_id; -unsigned int apic_taskpri; -unsigned int apic_ldr; -unsigned int apic_dfr; -unsigned int apic_spiv; -unsigned int apic_lvtt; -unsigned int apic_lvtpc; -unsigned int apic_lvt0; -unsigned int apic_lvt1; -unsigned int apic_lvterr; -unsigned int apic_tmict; -unsigned int apic_tdcr; -unsigned int apic_thmr; -} apic_pm_state; - -static void apic_pm_suspend (void *data) +static int lapic_suspend (struct device *dev,u32 state,u32 level) {unsigned int l, h;unsigned long flags; -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_SUSPEND , data); +if (level !=SUSPEND_POWER_DOWN ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + apic_pm_state.apic_id =apic_read (APIC_ID ); apic_pm_state.apic_taskpri =apic_read (APIC_TASKPRI ); apic_pm_state.apic_ldr =apic_read (APIC_LDR );@@ -505,13 +510,21 @@ l &= ~MSR_IA32_APICBASE_ENABLE ;wrmsr (MSR_IA32_APICBASE , l, h);local_irq_restore (flags); +return 0 ; } -static void apic_pm_resume (void *data) +static int lapic_resume (struct device *dev,u32 level) {unsigned int l, h;unsigned long flags; +if (level !=RESUME_POWER_ON ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + +set_fixmap_nocache (FIX_APIC_BASE ,APIC_DEFAULT_PHYS_BASE );/* FIXME: this is needed for S3 resume, but why? */ +local_irq_save (flags);rdmsr (MSR_IA32_APICBASE , l, h); l &= ~MSR_IA32_APICBASE_BASE ;@@ -536,74 +549,35 @@apic_write (APIC_ESR ,0 );apic_read (APIC_ESR );local_irq_restore (flags); -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_RESUME , data); -} - -static int apic_pm_callback (struct pm_dev *dev,pm_request_t rqst,void *data) -{ -switch (rqst) { -case PM_SUSPEND : -apic_pm_suspend (data); -break ; -case PM_RESUME : -apic_pm_resume (data); -break ; - } return 0; } -/* perfctr driver should call this instead of pm_register() */ -struct pm_dev *apic_pm_register (pm_dev_t type, -unsigned long id, -pm_callback callback) -{ -struct pm_dev *dev; - -if (!apic_pm_state.active) -return pm_register (type, id, callback); -if (apic_pm_state.perfctr_pmdev) -return NULL ;/* we're busy */ - dev =kmalloc (sizeof (struct pm_dev ),GFP_KERNEL ); -if (dev) { -memset (dev,0 ,sizeof (*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - apic_pm_state.perfctr_pmdev = dev; - } -return dev; -} - -/* perfctr driver should call this instead of pm_unregister() */ -void apic_pm_unregister (struct pm_dev *dev) -{ -if (!apic_pm_state.active) { -pm_unregister (dev); - }else if (dev == apic_pm_state.perfctr_pmdev) { - apic_pm_state.perfctr_pmdev =NULL ; -kfree (dev); - } -} - -static void __init apic_pm_init1 (void ) -{ -/* can't pm_register() at this early stage in the boot process -(causes an immediate reboot), so just set the flag */ - apic_pm_state.active =1 ; -} +static struct device_driver lapic_driver = { + .name ="apic" , + .bus = &system_bus_type, + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +/* not static, needed by child devices */ +struct sys_device device_lapic = { + .name ="apic" , + .id =0 , + .dev = { + .name ="lapic" , + .driver = &lapic_driver, + }, +}; -static void __init apic_pm_init2 (void ) +static int __init init_apic_devicefs (void ) { +driver_register (&lapic_driver);if (apic_pm_state.active) -pm_register (PM_SYS_DEV ,0 , apic_pm_callback); +return sys_device_register (&device_lapic); +return 0 ; } -#else /* CONFIG_PM */ - -static inline void apic_pm_init1 (void ) { } -static inline void apic_pm_init2 (void ) { } - +device_initcall (init_apic_devicefs);#endif /* CONFIG_PM */ /* @@ -669,9 +643,6 @@ nmi_watchdog =NMI_LOCAL_APIC ;printk ("Found and enabled local APIC!\n" ); - -apic_pm_init1 (); -return 0 ; no_apic:@@ -682,7 +653,6 @@void __init init_apic_mappings (void ) {unsigned long apic_phys; -/* * If no local APIC can be found then set up a fake all * zeroes page to simulate the local APIC and another @@ -1150,13 +1120,10 @@ }verify_local_APIC (); -connect_bsp_APIC (); phys_cpu_present_map =1 << boot_cpu_physical_apicid; -apic_pm_init2 (); -setup_local_APIC ();if (nmi_watchdog ==NMI_LOCAL_APIC )Index:
linux/arch/i386/kernel/apm.c
===================================================================arch/i386/kernel/apm.c +7
-0@@ -221,6 +221,7 @@#include <linux/kernel.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/device.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -1237,6 +1238,10 @@ }printk (KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n" ); } + + +device_suspend (3 ,SUSPEND_POWER_DOWN ); +/* serialize with the timer interrupt */ write_seqlock_irq (&xtime_lock);@@ -1257,6 +1262,7 @@if (err !=APM_SUCCESS )apm_error ("suspend" , err); err = (err ==APM_SUCCESS ) ?0 : -EIO ; +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (APM_NORMAL_RESUME ,NULL ); out:@@ -1370,6 +1376,7 @@write_seqlock_irq (&xtime_lock);set_time ();write_sequnlock_irq (&xtime_lock); +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (event,NULL ); }Index:
linux/arch/i386/kernel/i386_ksyms.c
===================================================================arch/i386/kernel/i386_ksyms.c +0
-4@@ -163,10 +163,6 @@EXPORT_SYMBOL (flush_tlb_page);#endif -#if defined(CONFIG_X86_LOCAL_APIC ) && defined(CONFIG_PM ) -EXPORT_SYMBOL_GPL (set_nmi_pm_callback); -EXPORT_SYMBOL_GPL (unset_nmi_pm_callback); -#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL (IO_APIC_get_PCI_irq_vector);#endif Index:
linux/arch/i386/kernel/nmi.c
===================================================================arch/i386/kernel/nmi.c +60
-40@@ -9,6 +9,8 @@* Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog. +* Pavel Machek and +* Mikael Pettersson : PM converted to driver model. disable/enable API. */ #include <linux/config.h> @@ -20,6 +22,8 @@#include <linux/interrupt.h> #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <linux/device.h> +#include <linux/module.h> #include <asm/smp.h> #include <asm/mtrr.h> @@ -29,6 +33,7 @@static unsigned int nmi_hz =HZ ;unsigned int nmi_perfctr_msr;/* the MSR to reset in NMI handler */ extern void show_registers (struct pt_regs *regs); +static int nmi_active;#define K7_EVNTSEL_ENABLE (1 << 22)#define K7_EVNTSEL_INT (1 << 20)@@ -117,7 +122,7 @@*/ if ((nmi ==NMI_LOCAL_APIC ) && (boot_cpu_data.x86_vendor ==X86_VENDOR_INTEL ) && - (boot_cpu_data.x86 ==6 || boot_cpu_data.x86 ==15 )) + (boot_cpu_data.x86 ==6 || boot_cpu_data.x86 ==15 )) nmi_watchdog = nmi; if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&@@ -134,14 +139,11 @@__setup ("nmi_watchdog=" , setup_nmi_watchdog); -#ifdef CONFIG_PM - -#include <linux/pm.h> - -struct pm_dev *nmi_pmdev; -static void disable_apic_nmi_watchdog (void ) +void disable_lapic_nmi_watchdog (void ) { +if (!nmi_active) +return ;switch (boot_cpu_data.x86_vendor) {case X86_VENDOR_AMD :wrmsr (MSR_K7_EVNTSEL0 ,0 ,0 );@@ -158,46 +160,60 @@ }break ; } + nmi_active =0 ; } -static int nmi_pm_callback (struct pm_dev *dev,pm_request_t rqst,void *data) +#ifdef CONFIG_PM + +static int nmi_suspend (struct device *dev,u32 state,u32 level) { -switch (rqst) { -case PM_SUSPEND : -disable_apic_nmi_watchdog (); -break ; -case PM_RESUME : -setup_apic_nmi_watchdog (); -break ; - } +if (level !=SUSPEND_POWER_DOWN ) +return 0 ; + +disable_lapic_nmi_watchdog ();return 0 ; } -struct pm_dev *set_nmi_pm_callback (pm_callback callback) +static int nmi_resume (struct device *dev,u32 level) { -apic_pm_unregister (nmi_pmdev); -return apic_pm_register (PM_SYS_DEV ,0 , callback); -} +if (level !=RESUME_POWER_ON ) +return 0 ; -void unset_nmi_pm_callback (struct pm_dev * dev) -{ -apic_pm_unregister (dev); - nmi_pmdev =apic_pm_register (PM_SYS_DEV ,0 , nmi_pm_callback); -} - -static void nmi_pm_init (void ) -{ -if (!nmi_pmdev) - nmi_pmdev =apic_pm_register (PM_SYS_DEV ,0 , nmi_pm_callback); +if (nmi_watchdog ==NMI_LOCAL_APIC ) +enable_lapic_nmi_watchdog (); + +return 0 ; } -#define __pminit/*empty*/ -#else /* CONFIG_PM */ +static struct device_driver nmi_driver = { + .name ="lapic_nmi" , + .bus = &system_bus_type, + .resume = nmi_resume, + .suspend = nmi_suspend, +}; + +static struct sys_device device_nmi = { + .name ="lapic_nmi" , + .id =0 , + .dev = { + .name ="lapic_nmi" , + .driver = &nmi_driver, + .parent = &device_lapic.dev, + } +}; + +extern struct sys_device device_apic; -static inline void nmi_pm_init (void ) { } +static int __init init_nmi_devicefs (void ) +{ +if (nmi_watchdog ==NMI_LOCAL_APIC ) { +driver_register (&nmi_driver); +return sys_device_register (&device_nmi); + } +} -#define __pminit __init +late_initcall (init_nmi_devicefs);#endif /* CONFIG_PM */ @@ -206,7 +222,7 @@* Original code written by Keith Owens. */ -static void __pminit clear_msr_range(unsigned int base, unsigned int n) +static void clear_msr_range (unsigned int base,unsigned int n) {unsigned int i;@@ -214,7 +230,7 @@wrmsr (base+i,0 ,0 ); } -static void __pminit setup_k7_watchdog(void) +static void setup_k7_watchdog (void ) {unsigned int evntsel;@@ -236,7 +252,7 @@wrmsr (MSR_K7_EVNTSEL0 , evntsel,0 ); } -static void __pminit setup_p6_watchdog(void) +static void setup_p6_watchdog (void ) {unsigned int evntsel;@@ -258,7 +274,7 @@wrmsr (MSR_P6_EVNTSEL0 , evntsel,0 ); } -static int __pminit setup_p4_watchdog(void) +static int setup_p4_watchdog (void ) {unsigned int misc_enable, dummy;@@ -288,7 +304,7 @@return 1 ; } -void __pminit setup_apic_nmi_watchdog (void) +void enable_lapic_nmi_watchdog (void ) {switch (boot_cpu_data.x86_vendor) {case X86_VENDOR_AMD :@@ -312,7 +328,7 @@default :return ; } -nmi_pm_init (); + nmi_active =1 ; }static spinlock_t nmi_print_lock =SPIN_LOCK_UNLOCKED ;@@ -400,3 +416,7 @@wrmsr (nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000 ),-1 ); } } + +EXPORT_SYMBOL (nmi_watchdog); +EXPORT_SYMBOL (enable_lapic_nmi_watchdog); +EXPORT_SYMBOL (disable_lapic_nmi_watchdog);Index:
linux/arch/i386/oprofile/nmi_int.c
===================================================================arch/i386/oprofile/nmi_int.c +57
-25@@ -11,6 +11,7 @@#include <linux/notifier.h> #include <linux/smp.h> #include <linux/oprofile.h> +#include <linux/device.h> #include <asm/nmi.h> #include <asm/msr.h> #include <asm/apic.h> @@ -24,27 +25,6 @@static int nmi_start (void );static void nmi_stop (void ); - -static struct pm_dev * oprofile_pmdev; - -/* We're at risk of causing big trouble unless we -* make sure to not cause any NMI interrupts when -* suspended. -*/ -static int oprofile_pm_callback (struct pm_dev * dev, -pm_request_t rqst,void * data) -{ -switch (rqst) { -case PM_SUSPEND : -nmi_stop (); -break ; -case PM_RESUME : -nmi_start (); -break ; - } -return 0 ; -} -static int nmi_callback (struct pt_regs * regs,int cpu) {@@ -86,7 +66,41 @@ saved_lvtpc[cpu] =apic_read (APIC_LVTPC );apic_write (APIC_LVTPC ,APIC_DM_NMI ); } - + +static int nmi_enabled =0 ;/* 0 == registered but off, 1 == registered and on */ + +static int nmi_suspend (struct device *dev,u32 state,u32 level) +{ +if (level !=SUSPEND_POWER_DOWN ) +return 0 ; +if (nmi_enabled ==1 ) +nmi_stop (); +return 0 ; +} + +static int nmi_resume (struct device *dev,u32 level) +{ +if (level !=RESUME_POWER_ON ) +return 0 ; +if (nmi_enabled ==1 ) +nmi_start (); +return 0 ; +} + + +static struct device_driver nmi_driver = { + .name ="oprofile" , + .bus = &system_bus_type, + .resume = nmi_resume, + .suspend = nmi_suspend, +}; + +static struct device device_nmi = { + .name ="oprofile" , + .bus_id ="oprofile" , + .driver = &nmi_driver, + .parent = &device_lapic, +};static int nmi_setup (void ) {@@ -95,12 +109,26 @@* without actually triggering any NMIs as this will * break the core code horrifically. */ +if (nmi_watchdog ==NMI_LOCAL_APIC ) { +disable_lapic_nmi_watchdog (); + nmi_watchdog =NMI_LOCAL_APIC_SUSPENDED_BY_OPROFILE ; + }on_each_cpu (nmi_cpu_setup,NULL ,0 ,1 );set_nmi_callback (nmi_callback); - oprofile_pmdev =set_nmi_pm_callback (oprofile_pm_callback); -return 0 ; + nmi_enabled =1 ; +return 0 ; +} + +static int __init init_nmi_driverfs (void ) +{ +if (nmi_watchdog ==NMI_LOCAL_APIC ) { +printk ("Registering oprofile-nmi\n" ); +driver_register (&nmi_driver); +device_register (&device_nmi); + } } +late_initcall (init_nmi_driverfs);static void nmi_restore_registers (struct op_msrs * msrs) {@@ -145,9 +173,13 @@static void nmi_shutdown (void ) { -unset_nmi_pm_callback (oprofile_pmdev); + nmi_enabled =0 ;unset_nmi_callback ();on_each_cpu (nmi_cpu_shutdown,NULL ,0 ,1 ); +if (nmi_watchdog ==NMI_LOCAL_APIC_SUSPENDED_BY_OPROFILE ) { + nmi_watchdog =NMI_LOCAL_APIC ; +enable_lapic_nmi_watchdog (); + } }Index:
linux/include/asm-i386/apic.h
===================================================================include/asm-i386/apic.h +5
-1@@ -78,7 +78,8 @@extern void smp_local_timer_interrupt (struct pt_regs * regs);extern void setup_boot_APIC_clock (void );extern void setup_secondary_APIC_clock (void ); -extern void setup_apic_nmi_watchdog (void ); +extern void enable_lapic_nmi_watchdog (void ); +extern void disable_lapic_nmi_watchdog (void );extern inline void nmi_watchdog_tick (struct pt_regs * regs);extern int APIC_init_uniprocessor (void );extern void disable_APIC_timer (void );@@ -95,6 +96,9 @@#define NMI_IO_APIC 1#define NMI_LOCAL_APIC 2#define NMI_INVALID 3 +#define NMI_LOCAL_APIC_SUSPENDED_BY_OPROFILE 4 + +extern struct sys_device device_lapic;#endif /* CONFIG_X86_LOCAL_APIC */ %diffstat
arch/i386/kernel/apic.c | 169 ++++++++++++++++-------------------------- arch/i386/kernel/apm.c | 7 + arch/i386/kernel/i386_ksyms.c | 4 arch/i386/kernel/io_apic.c | 15 ++- arch/i386/kernel/nmi.c | 100 ++++++++++++++---------- arch/i386/oprofile/nmi_int.c | 82 ++++++++++++++------ include/asm-i386/apic.h | 6 + 7 files changed, 206 insertions(+), 177 deletions(-)Signature · 2 lines
When do you have a heart between your knees? [Johanka's followup: and *two* hearts?]
Quoted 3 lines · Martin J. Bligh
arch/i386/oprofile/nmi_int.c:102: warning: initialization from incompatible pointer typearch/i386/oprofile/nmi_int.c: In function `init_nmi_driverfs':arch/i386/oprofile/nmi_int.c:129: warning: control reaches end of non-void function
Can you try Mikael's (preferable) patch ?
regards,
john
A message that is not in the archive (sent off-list or not yet received): 23570000.1049211683@[10.10.2.4]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 2 lines · On Tue, Apr 01, 2003 at 05:50:25PM +0200, [email protected] wrote:
Here is my version for 2.5.65. I haven't had time to update it for .66 yet, but there shouldn't be any major patch problems.
Here's an updated patch for .66, tested on my two-way with OProfile, CONFIG_PM=yes
It also fixes the CONFIG_PM=n horkage you saw Martin, and some minor style cleanups in nmi_int.c
regards,
john
arch/i386/kernel/apic.c +47 -66
@@ -10,6 +10,8 @@* for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. * Mikael Pettersson : Power Management for UP-APIC. +* Pavel Machek and +* Mikael Pettersson : PM converted to driver model. */ #include <linux/config.h>
@@ -451,17 +453,14 @@ #ifdef CONFIG_PM -#include <linux/slab.h> -#include <linux/pm.h> +#include <linux/device.h> +#include <linux/module.h> 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; - /* 'perfctr_pmdev' is here because the current (2.4.1) PM - callback system doesn't handle hierarchical dependencies */ - struct pm_dev *perfctr_pmdev; /* r/w apic fields */ unsigned int apic_id; unsigned int apic_taskpri;
@@ -478,13 +477,16 @@unsigned int apic_thmr; } apic_pm_state; -static void apic_pm_suspend (void *data) +static int lapic_suspend (struct device *dev,u32 state,u32 level) {unsigned int l, h;unsigned long flags; -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_SUSPEND , data); +if (level !=SUSPEND_POWER_DOWN ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + apic_pm_state.apic_id =apic_read (APIC_ID ); apic_pm_state.apic_taskpri =apic_read (APIC_TASKPRI ); apic_pm_state.apic_ldr =apic_read (APIC_LDR );
@@ -505,13 +507,22 @@ l &= ~MSR_IA32_APICBASE_ENABLE ;wrmsr (MSR_IA32_APICBASE , l, h);local_irq_restore (flags); +return 0 ; } -static void apic_pm_resume (void *data) +static int lapic_resume (struct device *dev,u32 level) {unsigned int l, h;unsigned long flags; +if (level !=RESUME_POWER_ON ) +return 0 ; +if (!apic_pm_state.active) +return 0 ; + +/* XXX: Pavel needs this for S3 resume, but can't explain why */ +set_fixmap_nocache (FIX_APIC_BASE ,APIC_DEFAULT_PHYS_BASE ); +local_irq_save (flags);rdmsr (MSR_IA32_APICBASE , l, h); l &= ~MSR_IA32_APICBASE_BASE ;
@@ -536,73 +547,45 @@apic_write (APIC_ESR ,0 );apic_read (APIC_ESR );local_irq_restore (flags); -if (apic_pm_state.perfctr_pmdev) -pm_send (apic_pm_state.perfctr_pmdev,PM_RESUME , data); -} - -static int apic_pm_callback (struct pm_dev *dev,pm_request_t rqst,void *data) -{ -switch (rqst) { -case PM_SUSPEND : -apic_pm_suspend (data); -break ; -case PM_RESUME : -apic_pm_resume (data); -break ; - }return 0 ; } -/* perfctr driver should call this instead of pm_register() */ -struct pm_dev *apic_pm_register (pm_dev_t type, -unsigned long id, -pm_callback callback) -{ -struct pm_dev *dev; - -if (!apic_pm_state.active) -return pm_register (type, id, callback); -if (apic_pm_state.perfctr_pmdev) -return NULL ;/* we're busy */ - dev =kmalloc (sizeof (struct pm_dev ),GFP_KERNEL ); -if (dev) { -memset (dev,0 ,sizeof (*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - apic_pm_state.perfctr_pmdev = dev; - } -return dev; -} - -/* perfctr driver should call this instead of pm_unregister() */ -void apic_pm_unregister (struct pm_dev *dev) -{ -if (!apic_pm_state.active) { -pm_unregister (dev); - }else if (dev == apic_pm_state.perfctr_pmdev) { - apic_pm_state.perfctr_pmdev =NULL ; -kfree (dev); - } -} +static struct device_driver lapic_driver = { + .name ="lapic" , + .bus = &system_bus_type, + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +/* not static, needed by child devices */ +struct sys_device device_lapic = { + .name ="lapic" , + .id =0 , + .dev = { + .name ="lapic" , + .driver = &lapic_driver, + }, +}; +EXPORT_SYMBOL (device_lapic); -static void __init apic_pm_init1 (void ) +static void __init apic_pm_activate (void ) { -/* can't pm_register() at this early stage in the boot process -(causes an immediate reboot), so just set the flag */ apic_pm_state.active =1 ; } -static void __init apic_pm_init2 (void ) +static int __init init_lapic_devicefs (void ) { -if (apic_pm_state.active) -pm_register (PM_SYS_DEV ,0 , apic_pm_callback); +if (!cpu_has_apic) +return 0 ; +/* XXX: remove suspend/resume procs if !apic_pm_state.active? */ +driver_register (&lapic_driver); +return sys_device_register (&device_lapic); } +device_initcall (init_lapic_devicefs);#else /* CONFIG_PM */ -static inline void apic_pm_init1 (void ) { } -static inline void apic_pm_init2 (void ) { } +static inline void apic_pm_activate (void ) { }#endif /* CONFIG_PM */
@@ -670,7 +653,7 @@printk ("Found and enabled local APIC!\n" ); -apic_pm_init1 (); +apic_pm_activate ();return 0 ;
@@ -1155,8 +1138,6 @@ phys_cpu_present_map =1 << boot_cpu_physical_apicid; -apic_pm_init2 (); -setup_local_APIC ();if (nmi_watchdog ==NMI_LOCAL_APIC )
arch/i386/kernel/apm.c +6 -0
@@ -218,6 +218,7 @@#include <linux/time.h> #include <linux/sched.h> #include <linux/pm.h> +#include <linux/device.h> #include <linux/kernel.h> #include <linux/smp.h> #include <linux/smp_lock.h>
@@ -1237,6 +1238,9 @@ }printk (KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n" ); } + +device_suspend (3 ,SUSPEND_POWER_DOWN ); +/* serialize with the timer interrupt */ write_seqlock_irq (&xtime_lock);
@@ -1257,6 +1261,7 @@if (err !=APM_SUCCESS )apm_error ("suspend" , err); err = (err ==APM_SUCCESS ) ?0 : -EIO ; +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (APM_NORMAL_RESUME ,NULL ); out:
@@ -1370,6 +1375,7 @@write_seqlock_irq (&xtime_lock);set_time ();write_sequnlock_irq (&xtime_lock); +device_resume (RESUME_POWER_ON );pm_send_all (PM_RESUME , (void *)0 );queue_event (event,NULL ); }
arch/i386/kernel/i386_ksyms.c +0 -4
@@ -163,10 +163,6 @@EXPORT_SYMBOL (flush_tlb_page);#endif -#if defined(CONFIG_X86_LOCAL_APIC ) && defined(CONFIG_PM ) -EXPORT_SYMBOL_GPL (set_nmi_pm_callback); -EXPORT_SYMBOL_GPL (unset_nmi_pm_callback); -#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL (IO_APIC_get_PCI_irq_vector);#endif
arch/i386/kernel/nmi.c +68 -38
185 lines not on this page · raw message
arch/i386/oprofile/nmi_int.c +57 -22
115 lines not on this page · raw message
include/asm-i386/apic.h +5 -2
@@ -79,13 +79,16 @@extern void setup_boot_APIC_clock (void );extern void setup_secondary_APIC_clock (void );extern void setup_apic_nmi_watchdog (void ); +extern void disable_lapic_nmi_watchdog (void ); +extern void enable_lapic_nmi_watchdog (void );extern inline void nmi_watchdog_tick (struct pt_regs * regs);extern int APIC_init_uniprocessor (void );extern void disable_APIC_timer (void );extern void enable_APIC_timer (void ); -extern struct pm_dev *apic_pm_register (pm_dev_t ,unsigned long ,pm_callback ); -extern void apic_pm_unregister (struct pm_dev *); +#ifdef CONFIG_PM +extern struct sys_device device_lapic; +#endif extern int check_nmi_watchdog (void );extern void enable_NMI_through_LVT0 (void * dummy);
include/asm-i386/nmi.h +0 -21
@@ -25,25 +25,4 @@*/ void unset_nmi_callback (void ); -#ifdef CONFIG_PM - -/** Replace the PM callback routine for NMI. */ -struct pm_dev *set_nmi_pm_callback (pm_callback callback); - -/** Unset the PM callback routine back to the default. */ -void unset_nmi_pm_callback (struct pm_dev * dev); - -#else - -static inline struct pm_dev *set_nmi_pm_callback (pm_callback callback) -{ -return 0 ; -} - -static inline void unset_nmi_pm_callback (struct pm_dev * dev) -{ -} - -#endif /* CONFIG_PM */ -#endif /* ASM_NMI_H */
Hi!
Quoted 5 lines
Quoted 3 lines
arch/i386/oprofile/nmi_int.c:102: warning: initialization from incompatible pointer typearch/i386/oprofile/nmi_int.c: In function `init_nmi_driverfs':arch/i386/oprofile/nmi_int.c:129: warning: control reaches end of non-void functionCan you try Mikael's (preferable) patch ?
Well, that patch broke as soon as you enabled oprofile (last time I checked).
Pavel
Signature · 2 lines
When do you have a heart between your knees? [Johanka's followup: and *two* hearts?]
Quoted 10 lines · Pavel Machek
Hi!
Quoted 5 lines
Quoted 3 lines
arch/i386/oprofile/nmi_int.c:102: warning: initialization from incompatible pointer typearch/i386/oprofile/nmi_int.c: In function `init_nmi_driverfs':arch/i386/oprofile/nmi_int.c:129: warning: control reaches end of non-void functionCan you try Mikael's (preferable) patch ?
Well, that patch broke as soon as you enabled oprofile (last time I checked).
John wrote that the latest works for him, with oprofile enabled. Maybe he fixed some detail, I haven't compared it with mine yet.
Quoted 2 lines · On Wed, Apr 02, 2003 at 03:08:15PM +0200, [email protected] wrote:
John wrote that the latest works for him, with oprofile enabled. Maybe he fixed some detail, I haven't compared it with mine yet.
The only fix I made was to let CONFIG_PM=n compile.
regards,
john