Skip to content

Commit

Permalink
x86: move suspend wakeup code to C
Browse files Browse the repository at this point in the history
Move wakeup code to .c, so that video mode setting code can be shared
between boot and wakeup. Remove nasty assembly code in 64-bit case by
re-using trampoline code. Stack setup was fixed to clear high 16bits
of %esp, maybe that fixes some machines.

.c code sharing and morse code was done H. Peter Anvin, Sam Ravnborg
reviewed kbuild related stuff, and it seems okay to him. Rafael did
some cleanups.

[rjw:
* Made the patch stop breaking compilation on x86-32
* Added arch/x86/kernel/acpi/sleep.h
* Got rid of compiler warnings in arch/x86/kernel/acpi/sleep.c
* Fixed 32-bit compilation on x86-64 systems
* Added include/asm-x86/trampoline.h and fixed the non-SMP
  compilation on 64-bit x86
* Removed arch/x86/kernel/acpi/sleep_32.c which was not used
* Fixed some breakage caused by the integration of smpboot.c done
  under us in the meantime]

Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Pavel Machek authored and Ingo Molnar committed Apr 17, 2008
1 parent f49688d commit e44b7b7
Show file tree
Hide file tree
Showing 34 changed files with 711 additions and 773 deletions.
2 changes: 1 addition & 1 deletion arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ config X86_BIOS_REBOOT

config X86_TRAMPOLINE
bool
depends on X86_SMP || (X86_VOYAGER && SMP)
depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
default y

config KTIME_SCALAR
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/boot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ subdir- := compressed

setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
setup-y += printf.o string.o tty.o video.o version.o
setup-y += printf.o string.o tty.o video.o video-mode.o version.o
setup-$(CONFIG_X86_APM_BOOT) += apm.o
setup-$(CONFIG_X86_VOYAGER) += voyager.o

Expand Down
5 changes: 5 additions & 0 deletions arch/x86/boot/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ int getchar_timeout(void);
/* video.c */
void set_video(void);

/* video-mode.c */
int set_mode(u16 mode);
int mode_defined(u16 mode);
void probe_cards(int unsafe);

/* video-vesa.c */
void vesa_store_edid(void);

Expand Down
6 changes: 6 additions & 0 deletions arch/x86/boot/video-bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ static int set_bios_mode(u8 mode)
if (new_mode == mode)
return 0; /* Mode change OK */

#ifndef _WAKEUP
if (new_mode != boot_params.screen_info.orig_video_mode) {
/* Mode setting failed, but we didn't end up where we
started. That's bad. Try to revert to the original
Expand All @@ -59,13 +60,18 @@ static int set_bios_mode(u8 mode)
: "+a" (ax)
: : "ebx", "ecx", "edx", "esi", "edi");
}
#endif
return -1;
}

static int bios_probe(void)
{
u8 mode;
#ifdef _WAKEUP
u8 saved_mode = 0x03;
#else
u8 saved_mode = boot_params.screen_info.orig_video_mode;
#endif
u16 crtc;
struct mode_info *mi;
int nmodes = 0;
Expand Down
173 changes: 173 additions & 0 deletions arch/x86/boot/video-mode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007-2008 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */

/*
* arch/i386/boot/video-mode.c
*
* Set the video mode. This is separated out into a different
* file in order to be shared with the ACPI wakeup code.
*/

#include "boot.h"
#include "video.h"
#include "vesa.h"

/*
* Common variables
*/
int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
u16 video_segment;
int force_x, force_y; /* Don't query the BIOS for cols/rows */

int do_restore; /* Screen contents changed during mode flip */
int graphic_mode; /* Graphic mode with linear frame buffer */

/* Probe the video drivers and have them generate their mode lists. */
void probe_cards(int unsafe)
{
struct card_info *card;
static u8 probed[2];

if (probed[unsafe])
return;

probed[unsafe] = 1;

for (card = video_cards; card < video_cards_end; card++) {
if (card->unsafe == unsafe) {
if (card->probe)
card->nmodes = card->probe();
else
card->nmodes = 0;
}
}
}

/* Test if a mode is defined */
int mode_defined(u16 mode)
{
struct card_info *card;
struct mode_info *mi;
int i;

for (card = video_cards; card < video_cards_end; card++) {
mi = card->modes;
for (i = 0; i < card->nmodes; i++, mi++) {
if (mi->mode == mode)
return 1;
}
}

return 0;
}

/* Set mode (without recalc) */
static int raw_set_mode(u16 mode, u16 *real_mode)
{
int nmode, i;
struct card_info *card;
struct mode_info *mi;

/* Drop the recalc bit if set */
mode &= ~VIDEO_RECALC;

/* Scan for mode based on fixed ID, position, or resolution */
nmode = 0;
for (card = video_cards; card < video_cards_end; card++) {
mi = card->modes;
for (i = 0; i < card->nmodes; i++, mi++) {
int visible = mi->x || mi->y;

if ((mode == nmode && visible) ||
mode == mi->mode ||
mode == (mi->y << 8)+mi->x) {
*real_mode = mi->mode;
return card->set_mode(mi);
}

if (visible)
nmode++;
}
}

/* Nothing found? Is it an "exceptional" (unprobed) mode? */
for (card = video_cards; card < video_cards_end; card++) {
if (mode >= card->xmode_first &&
mode < card->xmode_first+card->xmode_n) {
struct mode_info mix;
*real_mode = mix.mode = mode;
mix.x = mix.y = 0;
return card->set_mode(&mix);
}
}

/* Otherwise, failure... */
return -1;
}

/*
* Recalculate the vertical video cutoff (hack!)
*/
static void vga_recalc_vertical(void)
{
unsigned int font_size, rows;
u16 crtc;
u8 pt, ov;

set_fs(0);
font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */

rows *= font_size; /* Visible scan lines */
rows--; /* ... minus one */

crtc = vga_crtc();

pt = in_idx(crtc, 0x11);
pt &= ~0x80; /* Unlock CR0-7 */
out_idx(pt, crtc, 0x11);

out_idx((u8)rows, crtc, 0x12); /* Lower height register */

ov = in_idx(crtc, 0x07); /* Overflow register */
ov &= 0xbd;
ov |= (rows >> (8-1)) & 0x02;
ov |= (rows >> (9-6)) & 0x40;
out_idx(ov, crtc, 0x07);
}

/* Set mode (with recalc if specified) */
int set_mode(u16 mode)
{
int rv;
u16 real_mode;

/* Very special mode numbers... */
if (mode == VIDEO_CURRENT_MODE)
return 0; /* Nothing to do... */
else if (mode == NORMAL_VGA)
mode = VIDEO_80x25;
else if (mode == EXTENDED_VGA)
mode = VIDEO_8POINT;

rv = raw_set_mode(mode, &real_mode);
if (rv)
return rv;

if (mode & VIDEO_RECALC)
vga_recalc_vertical();

/* Save the canonical mode number for the kernel, not
an alias, size specification or menu position */
#ifndef _WAKEUP
boot_params.hdr.vid_mode = real_mode;
#endif
return 0;
}
8 changes: 8 additions & 0 deletions arch/x86/boot/video-vesa.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ static struct vesa_mode_info vminfo;

__videocard video_vesa;

#ifndef _WAKEUP
static void vesa_store_mode_params_graphics(void);
#else /* _WAKEUP */
static inline void vesa_store_mode_params_graphics(void) {}
#endif /* _WAKEUP */

static int vesa_probe(void)
{
Expand Down Expand Up @@ -165,6 +169,8 @@ static int vesa_set_mode(struct mode_info *mode)
}


#ifndef _WAKEUP

/* Switch DAC to 8-bit mode */
static void vesa_dac_set_8bits(void)
{
Expand Down Expand Up @@ -288,6 +294,8 @@ void vesa_store_edid(void)
#endif /* CONFIG_FIRMWARE_EDID */
}

#endif /* not _WAKEUP */

__videocard video_vesa =
{
.card_name = "VESA",
Expand Down
12 changes: 10 additions & 2 deletions arch/x86/boot/video-vga.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ static int vga_set_mode(struct mode_info *mode)
*/
static int vga_probe(void)
{
u16 ega_bx;

static const char *card_name[] = {
"CGA/MDA/HGC", "EGA", "VGA"
};
Expand All @@ -226,12 +228,16 @@ static int vga_probe(void)
u8 vga_flag;

asm(INT10
: "=b" (boot_params.screen_info.orig_video_ega_bx)
: "=b" (ega_bx)
: "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
: "ecx", "edx", "esi", "edi");

#ifndef _WAKEUP
boot_params.screen_info.orig_video_ega_bx = ega_bx;
#endif

/* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) {
if ((u8)ega_bx != 0x10) {
/* EGA/VGA */
asm(INT10
: "=a" (vga_flag)
Expand All @@ -240,7 +246,9 @@ static int vga_probe(void)

if (vga_flag == 0x1a) {
adapter = ADAPTER_VGA;
#ifndef _WAKEUP
boot_params.screen_info.orig_video_isVGA = 1;
#endif
} else {
adapter = ADAPTER_EGA;
}
Expand Down
Loading

0 comments on commit e44b7b7

Please sign in to comment.