Messages in this thread | | | Subject | APM "SuspendToDisk" implementation problem | Date | Sat, 21 Nov 1998 16:21:04 +0100 (CET) | From | (Andreas Mohr) |
| |
Hello all,
I discovered that Linux doesn't reinitialize the EIDE controllers/HDDs at all when resuming from a "Suspend To Disk". This causes lost 32bit/DMA/PIO mode/Multiple sector read settings. That can cause severe problems sometimes: When you configure "multiple sector read" to 4 with hdparm, Linux expects an interrupt every four sectors. However the EIDE power-on default after an APM resume is 16. Guess what that means... A whole lot of "lost interrupt". Furthermore I just hate having to enter /etc/rc.boot/hwtools manually after every suspend to get my EIDE settings back.
So I decided to begin writing support for IDE APM reconfiguration. Now I'm experiencing problems with "Scheduling in interrupt".
I changed drivers/block/ide.c like that: #ifdef CONFIG_APM #include <linux/apm_bios.h> #endif
/* * Reconfigure the IDE settings that were used * prior to an APM "suspend to disk". */ static int ide_apm_handler(apm_event_t event) { ide_hwif_t *hwif; ide_drive_t *drive; ide_settings_t *setting; int index, unit; static int down = 0;
switch (event) { case APM_SYS_SUSPEND: case APM_USER_SUSPEND: case APM_CRITICAL_SUSPEND: /* FIXME: maybe turn off write cache here for models which get powered down instantly after saving ? */ if (down) { printk(KERN_DEBUG "cs: received extra suspend event\n"); break; } down = 1; break; case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: if (!down) { printk(KERN_DEBUG "cs: received bogus resume event\n"); break; } down = 0; for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; printk("hwif: %p, ", hwif); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &ide_hwifs[index].drives[unit]; printk("drive: %p, ", drive); setting = drive->settings; while (setting) { printk("setting: %p, ", setting); ide_write_setting(drive, setting, ide_read_setting(drive, setting)); setting = setting->next; } } } break; } return 0; }
And I registered this APM event handler:
/* * This gets invoked once during initialization, to set *everything* up */ __initfunc(int ide_init (void)) { init_ide_data (); >>>>> apm_register_callback(ide_apm_handler); <<<<<<
initializing = 1; ide_init_builtin_drivers(); initializing = 0;
return 0; }
Now everytime I let my notebook resume, I get "Scheduling in interrupt" and a DivByZero exception forced by Linux to get a kernel oops/backtrace. Backtrace ("translated", of course :): 0 __down 1 __down_failed 2 ide_do_drive_cmd 3 set_multcount 4 vc_resize 5 ide_write_setting 6 ide_apm_handler <-- my APM event handler
So _something_ in ide_do_drive_cmd seems to be scheduling, and as the APM event handler seems to get invoked by an interrupt, this is of course fatal. How do I prevent scheduling (something like cli/sti, xxx_lock/xxx_unlock) ? Or do I need to implement this functionality in a completely different way ?
-- Andreas Mohr, Wine developer
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |