diff options
61 files changed, 1755 insertions, 2118 deletions
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index c57ce3f1f2e2..73f3aeefd203 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -163,14 +163,11 @@ static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp, if ((mode != 1) && (mode != 5)) return -EINVAL; - retval = pm_send_all(PM_SUSPEND, (void *)3); - if (retval == 0) { if (mode == 5) retval = pm_do_bus_sleep(); else retval = pm_do_suspend(); - pm_send_all(PM_RESUME, (void *)0); } return retval; @@ -183,9 +180,6 @@ static int try_set_cmode(int new_cmode) if (!(clock_cmodes_permitted & (1<<new_cmode))) return -EINVAL; - /* tell all the drivers we're suspending */ - pm_send_all(PM_SUSPEND, (void *)3); - /* now change cmode */ local_irq_disable(); frv_dma_pause_all(); @@ -201,8 +195,6 @@ static int try_set_cmode(int new_cmode) frv_dma_resume_all(); local_irq_enable(); - /* tell all the drivers we're resuming */ - pm_send_all(PM_RESUME, (void *)0); return 0; } diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 54047d69b820..725a52f364b0 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -258,7 +258,6 @@ int au_sleep(void) static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, void __user *buffer, size_t * len, loff_t *ppos) { - int retval = 0; #ifdef SLEEP_TEST_TIMEOUT #define TMPBUFLEN2 16 char buf[TMPBUFLEN2], *p; @@ -278,36 +277,12 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, p = buf; sleep_ticks = simple_strtoul(p, &p, 0); #endif - retval = pm_send_all(PM_SUSPEND, (void *) 2); - - if (retval) - return retval; au_sleep(); - retval = pm_send_all(PM_RESUME, (void *) 0); } - return retval; -} - -static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, - void __user *buffer, size_t * len, loff_t *ppos) -{ - int retval = 0; - - if (!write) { - *len = 0; - } else { - retval = pm_send_all(PM_SUSPEND, (void *) 2); - if (retval) - return retval; - suspend_mode = 1; - - retval = pm_send_all(PM_RESUME, (void *) 0); - } - return retval; + return 0; } - static int pm_do_freq(ctl_table * ctl, int write, struct file *file, void __user *buffer, size_t * len, loff_t *ppos) { @@ -421,14 +396,6 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file, static struct ctl_table pm_table[] = { { - .ctl_name = CTL_UNNUMBERED, - .procname = "suspend", - .data = NULL, - .maxlen = 0, - .mode = 0600, - .proc_handler = &pm_do_suspend - }, - { .ctl_name = CTL_UNNUMBERED, .procname = "sleep", .data = NULL, diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6c70fed0f9a0..05ccdf209df8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -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 diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index f88458e83ef0..84a09eb95cba 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -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 diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 7822a4983da2..09578070bfba 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -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); diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c index ff664a117096..39e247e96172 100644 --- a/arch/x86/boot/video-bios.c +++ b/arch/x86/boot/video-bios.c @@ -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 @@ -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; diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c new file mode 100644 index 000000000000..748e8d06290a --- /dev/null +++ b/arch/x86/boot/video-mode.c @@ -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; +} diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index 419b5c273374..5d5a3f6e8b5c 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c @@ -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) { @@ -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) { @@ -288,6 +294,8 @@ void vesa_store_edid(void) #endif /* CONFIG_FIRMWARE_EDID */ } +#endif /* not _WAKEUP */ + __videocard video_vesa = { .card_name = "VESA", diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index 7259387b7d19..330d6589a2ad 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c @@ -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" }; @@ -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) @@ -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; } diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 696d08f3843c..c1c47ba069ef 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -18,21 +18,6 @@ #include "video.h" #include "vesa.h" -/* - * Mode list variables - */ -static struct card_info cards[]; /* List of cards to probe for */ - -/* - * 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 = 0; /* Screen contents changed during mode flip */ -int graphic_mode; /* Graphic mode with linear frame buffer */ - static void store_cursor_position(void) { u16 curpos; @@ -107,147 +92,6 @@ static void store_mode_params(void) boot_params.screen_info.orig_video_lines = y; } -/* Probe the video drivers and have them generate their mode lists. */ -static 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) */ -static 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 */ - boot_params.hdr.vid_mode = real_mode; - return 0; -} - static unsigned int get_entry(void) { char entry_buf[4]; @@ -486,6 +330,7 @@ void set_video(void) printf("Undefined video mode number: %x\n", mode); mode = ASK_VGA; } + boot_params.hdr.vid_mode = mode; vesa_store_edid(); store_mode_params(); diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile index 19d3d6e9d09b..0ba26d535173 100644 --- a/arch/x86/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -1,7 +1,13 @@ +subdir- := realmode + obj-$(CONFIG_ACPI) += boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o processor.o endif +$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin + +$(obj)/realmode/wakeup.bin: FORCE + $(Q)$(MAKE) $(build)=$(obj)/realmode $@ diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile new file mode 100644 index 000000000000..092900854acc --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/Makefile @@ -0,0 +1,57 @@ +# +# arch/x86/kernel/acpi/realmode/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +targets := wakeup.bin wakeup.elf + +wakeup-y += wakeup.o wakemain.o video-mode.o copy.o + +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +wakeup-y += video-vga.o +wakeup-y += video-vesa.o +wakeup-y += video-bios.o + +targets += $(wakeup-y) + +bootsrc := $(src)/../../../boot + +# --------------------------------------------------------------------------- + +# How to compile the 16-bit code. Note we always compile for -march=i386, +# that way we can complain to the user if the CPU is insufficient. +# Compile with _SETUP since this is similar to the boot-time setup code. +KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ + -I$(srctree)/$(bootsrc) \ + $(cflags-y) \ + -Wall -Wstrict-prototypes \ + -march=i386 -mregparm=3 \ + -include $(srctree)/$(bootsrc)/code16gcc.h \ + -fno-strict-aliasing -fomit-frame-pointer \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-toplevel-reorder,\ + $(call cc-option, -fno-unit-at-a-time)) \ + $(call cc-option, -fno-stack-protector) \ + $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_CFLAGS += $(call cc-option, -m32) +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ + +WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) + +LDFLAGS_wakeup.elf := -T + +CPPFLAGS_wakeup.lds += -P -C + +$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE + $(call if_changed,ld) + +OBJCOPYFLAGS_wakeup.bin := -O binary + +$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE + $(call if_changed,objcopy) diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S new file mode 100644 index 000000000000..dc59ebee69d8 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/copy.S @@ -0,0 +1 @@ +#include "../../../boot/copy.S" diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c new file mode 100644 index 000000000000..7deabc144a27 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-bios.c @@ -0,0 +1 @@ +#include "../../../boot/video-bios.c" diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/kernel/acpi/realmode/video-mode.c new file mode 100644 index 000000000000..328ad209f113 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-mode.c @@ -0,0 +1 @@ +#include "../../../boot/video-mode.c" diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/kernel/acpi/realmode/video-vesa.c new file mode 100644 index 000000000000..9dbb9672226a --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-vesa.c @@ -0,0 +1 @@ +#include "../../../boot/video-vesa.c" diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/kernel/acpi/realmode/video-vga.c new file mode 100644 index 000000000000..bcc81255f374 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-vga.c @@ -0,0 +1 @@ +#include "../../../boot/video-vga.c" diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c new file mode 100644 index 000000000000..883962d9eef2 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakemain.c @@ -0,0 +1,81 @@ +#include "wakeup.h" +#include "boot.h" + +static void udelay(int loops) +{ + while (loops--) + io_delay(); /* Approximately 1 us */ +} + +static void beep(unsigned int hz) +{ + u8 enable; + + if (!hz) { + enable = 0x00; /* Turn off speaker */ + } else { + u16 div = 1193181/hz; + + outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ + io_delay(); + outb(div, 0x42); /* LSB of counter */ + io_delay(); + outb(div >> 8, 0x42); /* MSB of counter */ + io_delay(); + + enable = 0x03; /* Turn on speaker */ + } + inb(0x61); /* Dummy read of System Control Port B */ + io_delay(); + outb(enable, 0x61); /* Enable timer 2 output to speaker */ + io_delay(); +} + +#define DOT_HZ 880 +#define DASH_HZ 587 +#define US_PER_DOT 125000 + +/* Okay, this is totally silly, but it's kind of fun. */ +static void send_morse(const char *pattern) +{ + char s; + + while ((s = *pattern++)) { + switch (s) { + case '.': + beep(DOT_HZ); + udelay(US_PER_DOT); + beep(0); + udelay(US_PER_DOT); + break; + case '-': + beep(DASH_HZ); + udelay(US_PER_DOT * 3); + beep(0); + udelay(US_PER_DOT); + break; + default: /* Assume it's a space */ + udelay(US_PER_DOT * 3); + break; + } + } +} + +void main(void) +{ + /* Kill machine if structures are wrong */ + if (wakeup_header.real_magic != 0x12345678) + while (1); + + if (wakeup_header.realmode_flags & 4) + send_morse("...-"); + + if (wakeup_header.realmode_flags & 1) + asm volatile("lcallw $0xc000,$3"); + + if (wakeup_header.realmode_flags & 2) { + /* Need to call BIOS */ + probe_cards(0); + set_mode(wakeup_header.video_mode); + } +} diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S new file mode 100644 index 000000000000..f9b77fb37e5b --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.S @@ -0,0 +1,113 @@ +/* + * ACPI wakeup real mode startup stub + */ +#include <asm/segment.h> +#include <asm/msr-index.h> +#include <asm/page.h> +#include <asm/pgtable.h> + + .code16 + .section ".header", "a" + +/* This should match the structure in wakeup.h */ + .globl wakeup_header +wakeup_header: +video_mode: .short 0 /* Video mode number */ +pmode_return: .byte 0x66, 0xea /* ljmpl */ + .long 0 /* offset goes here */ + .short __KERNEL_CS +pmode_cr0: .long 0 /* Saved %cr0 */ +pmode_cr3: .long 0 /* Saved %cr3 */ +pmode_cr4: .long 0 /* Saved %cr4 */ +pmode_efer: .quad 0 /* Saved EFER */ +pmode_gdt: .quad 0 +realmode_flags: .long 0 +real_magic: .long 0 +trampoline_segment: .word 0 +signature: .long 0x51ee1111 + + .text + .globl _start + .code16 +wakeup_code: +_start: + cli + cld + + /* Set up segments */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + + movl $wakeup_stack_end, %esp + + /* Clear the EFLAGS */ + pushl $0 + popfl + + /* Check header signature... */ + movl signature, %eax + cmpl $0x51ee1111, %eax + jne bogus_real_magic + + /* Check we really have everything... */ + movl end_signature, %eax + cmpl $0x65a22c82, %eax + jne bogus_real_magic + + /* Call the C code */ + calll main + + /* Do any other stuff... */ + +#ifndef CONFIG_64BIT + /* This could also be done in C code... */ + movl pmode_cr3, %eax + movl %eax, %cr3 + + movl pmode_cr4, %ecx + jecxz 1f + movl %ecx, %cr4 +1: + movl pmode_efer, %eax + movl pmode_efer + 4, %edx + movl %eax, %ecx + orl %edx, %ecx + jz 1f + movl $0xc0000080, %ecx + wrmsr +1: + + lgdtl pmode_gdt + + /* This really couldn't... */ + movl pmode_cr0, %eax + movl %eax, %cr0 + jmp pmode_return +#else + pushw $0 + pushw trampoline_segment + pushw $0 + lret +#endif + +bogus_real_magic: +1: + hlt + jmp 1b + + .data + .balign 4 + .globl HEAP, heap_end +HEAP: + .long wakeup_heap +heap_end: + .long wakeup_stack + + .bss +wakeup_heap: + .space 2048 +wakeup_stack: + .space 2048 +wakeup_stack_end: diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h new file mode 100644 index 000000000000..ef8166fe8020 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.h @@ -0,0 +1,36 @@ +/* + * Definitions for the wakeup data structure at the head of the + * wakeup code. + */ + +#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H +#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H + +#ifndef __ASSEMBLY__ +#include <linux/types.h> + +/* This must match data at wakeup.S */ +struct wakeup_header { + u16 video_mode; /* Video mode number */ + u16 _jmp1; /* ljmpl opcode, 32-bit only */ + u32 pmode_entry; /* Protected mode resume point, 32-bit only */ + u16 _jmp2; /* CS value, 32-bit only */ + u32 pmode_cr0; /* Protected mode cr0 */ + u32 pmode_cr3; /* Protected mode cr3 */ + u32 pmode_cr4; /* Protected mode cr4 */ + u32 pmode_efer_low; /* Protected mode EFER */ + u32 pmode_efer_high; + u64 pmode_gdt; + u32 realmode_flags; + u32 real_magic; + u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ + u32 signature; /* To check we have correct structure */ +} __attribute__((__packed__)); + +extern struct wakeup_header wakeup_header; +#endif + +#define HEADER_OFFSET 0x3f00 +#define WAKEUP_SIZE 0x4000 + +#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S new file mode 100644 index 000000000000..22fab6c4be15 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S @@ -0,0 +1,61 @@ +/* + * wakeup.ld + * + * Linker script for the real-mode wakeup code + */ +#undef i386 +#include "wakeup.h" + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = HEADER_OFFSET; + .header : { + *(.header) + } + + . = 0; + .text : { + *(.text*) + } + + . = ALIGN(16); + .rodata : { + *(.rodata*) + } + + .videocards : { + video_cards = .; + *(.videocards) + video_cards_end = .; + } + + . = ALIGN(16); + .data : { + *(.data*) + } + + .signature : { + end_signature = .; + LONG(0x65a22c82) + } + + . = ALIGN(16); + .bss : { + __bss_start = .; + *(.bss) + __bss_end = .; + } + + . = ALIGN(16); + _end = .; + + /DISCARD/ : { + *(.note*) + } + + . = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!"); +} diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 6bc815cd8cb3..c00413dfa422 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -10,30 +10,72 @@ #include <linux/dmi.h> #include <linux/cpumask.h> -#include <asm/smp.h> +#include "realmode/wakeup.h" +#include "sleep.h" -/* address in low memory of the wakeup routine. */ -unsigned long acpi_wakeup_address = 0; +unsigned long acpi_wakeup_address; unsigned long acpi_realmode_flags; -extern char wakeup_start, wakeup_end; -extern unsigned long acpi_copy_wakeup_routine(unsigned long); +/* address in low memory of the wakeup routine. */ +static unsigned long acpi_realmode; + +#ifdef CONFIG_64BIT +static char temp_stack[10240]; +#endif /** * acpi_save_state_mem - save kernel state * * Create an identity mapped page table and copy the wakeup routine to * low memory. + * + * Note that this is too late to change acpi_wakeup_address. */ int acpi_save_state_mem(void) { - if (!acpi_wakeup_address) { - printk(KERN_ERR "Could not allocate memory during boot, S3 disabled\n"); + struct wakeup_header *header; + + if (!acpi_realmode) { + printk(KERN_ERR "Could not allocate memory during boot, " + "S3 disabled\n"); return -ENOMEM; } - memcpy((void *)acpi_wakeup_address, &wakeup_start, - &wakeup_end - &wakeup_start); - acpi_copy_wakeup_routine(acpi_wakeup_address); + memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE); + + header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET); + if (header->signature != 0x51ee1111) { + printk(KERN_ERR "wakeup header does not match\n"); + return -EINVAL; + } + + header->video_mode = saved_video_mode; + +#ifndef CONFIG_64BIT + store_gdt((struct desc_ptr *)&header->pmode_gdt); + + header->pmode_efer_low = nx_enabled; + if (header->pmode_efer_low & 1) { + /* This is strange, why not save efer, always? */ + rdmsr(MSR_EFER, header->pmode_efer_low, + header->pmode_efer_high); + } +#endif /* !CONFIG_64BIT */ + + header->pmode_cr0 = read_cr0(); + header->pmode_cr4 = read_cr4(); + header->realmode_flags = acpi_realmode_flags; + header->real_magic = 0x12345678; + +#ifndef CONFIG_64BIT + header->pmode_entry = (u32)&wakeup_pmode_return; + header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET); + saved_magic = 0x12345678; +#else /* CONFIG_64BIT */ + header->trampoline_segment = setup_trampoline() >> 4; + init_rsp = (unsigned long)temp_stack + 4096; + initial_code = wakeup_long64; + saved_magic = 0x123456789abcdef0; +#endif /* CONFIG_64BIT */ return 0; } @@ -56,15 +98,20 @@ void acpi_restore_state_mem(void) */ void __init acpi_reserve_bootmem(void) { - if ((&wakeup_end - &wakeup_start) > PAGE_SIZE*2) { + if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) { printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); return; } - acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); - if (!acpi_wakeup_address) + acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE); + + if (!acpi_realmode) { printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); + return; + } + + acpi_wakeup_address = acpi_realmode; } diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h new file mode 100644 index 000000000000..b9a75d929960 --- /dev/null +++ b/arch/x86/kernel/acpi/sleep.h @@ -0,0 +1,18 @@ +/* + * Variables and functions used by the code in sleep.c + */ + +#include <asm/trampoline.h> + +extern char wakeup_code_start, wakeup_code_end; + +extern unsigned long saved_video_mode; +extern long saved_magic; +extern unsigned long init_rsp; +extern void (*initial_code)(void); + +extern int wakeup_pmode_return; +extern char swsusp_pg_dir[PAGE_SIZE]; + +extern unsigned long acpi_copy_wakeup_routine(unsigned long); +extern void wakeup_long64(void); diff --git a/arch/x86/kernel/acpi/sleep_32.c b/arch/x86/kernel/acpi/sleep_32.c deleted file mode 100644 index 63fe5525e026..000000000000 --- a/arch/x86/kernel/acpi/sleep_32.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * sleep.c - x86-specific ACPI sleep support. - * - * Copyright (C) 2001-2003 Patrick Mochel - * Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz> - */ - -#include <linux/acpi.h> -#include <linux/bootmem.h> -#include <linux/dmi.h> -#include <linux/cpumask.h> - -#include <asm/smp.h> - -/* Ouch, we want to delete this. We already have better version in userspace, in - s2ram from suspend.sf.net project */ -static __init int reset_videomode_after_s3(const struct dmi_system_id *d) -{ - acpi_realmode_flags |= 2; - return 0; -} - -static __initdata struct dmi_system_id acpisleep_dmi_table[] = { - { /* Reset video mode after returning from ACPI S3 sleep */ - .callback = reset_videomode_after_s3, - .ident = "Toshiba Satellite 4030cdt", - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), - }, - }, - {} -}; - -static int __init acpisleep_dmi_init(void) -{ - dmi_check_system(acpisleep_dmi_table); - return 0; -} - -core_initcall(acpisleep_dmi_init); diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index f53e3277f8e5..a12e6a9fb659 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S @@ -3,178 +3,12 @@ #include <asm/segment.h> #include <asm/page.h> -# -# wakeup_code runs in real mode, and at unknown address (determined at run-time). -# Therefore it must only use relative jumps/calls. -# -# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled -# -# If physical address of wakeup_code is 0x12345, BIOS should call us with -# cs = 0x1234, eip = 0x05 -# - -#define BEEP \ - inb $97, %al; \ - outb %al, $0x80; \ - movb $3, %al; \ - outb %al, $97; \ - outb %al, $0x80; \ - movb $-74, %al; \ - outb %al, $67; \ - outb %al, $0x80; \ - movb $-119, %al; \ - outb %al, $66; \ - outb %al, $0x80; \ - movb $15, %al; \ - outb %al, $66; - -ALIGN - .align 4096 -ENTRY(wakeup_start) -wakeup_code: - wakeup_code_start = . - .code16 - - cli - cld - - # setup data segment - movw %cs, %ax - movw %ax, %ds # Make ds:0 point to wakeup_start - movw %ax, %ss - - testl $4, realmode_flags - wakeup_code - jz 1f - BEEP -1: - mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board - - pushl $0 # Kill any dangerous flags - popfl - - movl real_magic - wakeup_code, %eax - cmpl $0x12345678, %eax - jne bogus_real_magic - - testl $1, realmode_flags - wakeup_code - jz 1f - lcall $0xc000,$3 - movw %cs, %ax - movw %ax, %ds # Bios might have played with that - movw %ax, %ss -1: - - testl $2, realmode_flags - wakeup_code - jz 1f - mov video_mode - wakeup_code, %ax - call mode_set -1: - - # set up page table - movl $swsusp_pg_dir-__PAGE_OFFSET, %eax - movl %eax, %cr3 - - testl $1, real_efer_save_restore - wakeup_code - jz 4f - # restore efer setting - movl real_save_efer_edx - wakeup_code, %edx - movl real_save_efer_eax - wakeup_code, %eax - mov $0xc0000080, %ecx - wrmsr -4: - # make sure %cr4 is set correctly (features, etc) - movl real_save_cr4 - wakeup_code, %eax - movl %eax, %cr4 - - # need a gdt -- use lgdtl to force 32-bit operands, in case - # the GDT is located past 16 megabytes. - lgdtl real_save_gdt - wakeup_code - - movl real_save_cr0 - wakeup_code, %eax - movl %eax, %cr0 - jmp 1f -1: - movl real_magic - wakeup_code, %eax - cmpl $0x12345678, %eax - jne bogus_real_magic - - testl $8, realmode_flags - wakeup_code - jz 1f - BEEP -1: - ljmpl $__KERNEL_CS, $wakeup_pmode_return - -real_save_gdt: .word 0 - .long 0 -real_save_cr0: .long 0 -real_save_cr3: .long 0 -real_save_cr4: .long 0 -real_magic: .long 0 -video_mode: .long 0 -realmode_flags: .long 0 -real_efer_save_restore: .long 0 -real_save_efer_edx: .long 0 -real_save_efer_eax: .long 0 - -bogus_real_magic: - jmp bogus_real_magic - -/* This code uses an extended set of video mode numbers. These include: - * Aliases for standard modes - * NORMAL_VGA (-1) - * EXTENDED_VGA (-2) - * ASK_VGA (-3) - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack - * of compatibility when extending the table. These are between 0x00 and 0xff. - */ -#define VIDEO_FIRST_MENU 0x0000 - -/* Standard BIOS video modes (BIOS number + 0x0100) */ -#define VIDEO_FIRST_BIOS 0x0100 - -/* VESA BIOS video modes (VESA number + 0x0200) */ -#define VIDEO_FIRST_VESA 0x0200 - -/* Video7 special modes (BIOS number + 0x0900) */ -#define VIDEO_FIRST_V7 0x0900 - -# Setting of user mode (AX=mode ID) => CF=success - -# For now, we only handle VESA modes (0x0200..0x03ff). To handle other -# modes, we should probably compile in the video code from the boot -# directory. -mode_set: - movw %ax, %bx - subb $VIDEO_FIRST_VESA>>8, %bh - cmpb $2, %bh - jb check_vesa - -setbad: - clc - ret - -check_vesa: - orw $0x4000, %bx # Use linear frame buffer - movw $0x4f02, %ax # VESA BIOS mode set call - int $0x10 - cmpw $0x004f, %ax # AL=4f if implemented - jnz setbad # AH=0 if OK - - stc - ret +# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 .code32 ALIGN -.org 0x800 -wakeup_stack_begin: # Stack grows down - -.org 0xff0 # Just below end of page -wakeup_stack: -ENTRY(wakeup_end) - -.org 0x1000 - +ENTRY(wakeup_pmode_return) wakeup_pmode_return: movw $__KERNEL_DS, %ax movw %ax, %ss @@ -187,7 +21,7 @@ wakeup_pmode_return: lgdt saved_gdt lidt saved_idt lldt saved_ldt - ljmp $(__KERNEL_CS),$1f + ljmp $(__KERNEL_CS), $1f 1: movl %cr3, %eax movl %eax, %cr3 @@ -201,82 +35,41 @@ wakeup_pmode_return: jne bogus_magic # jump to place where we left off - movl saved_eip,%eax + movl saved_eip, %eax jmp *%eax bogus_magic: jmp bogus_magic -## -# acpi_copy_wakeup_routine -# -# Copy the above routine to low memory. -# -# Parameters: -# %eax: place to copy wakeup routine to -# -# Returned address is location of code in low memory (past data and stack) -# -ENTRY(acpi_copy_wakeup_routine) - pushl %ebx +save_registers: sgdt saved_gdt sidt saved_idt sldt saved_ldt str saved_tss - movl nx_enabled, %edx - movl %edx, real_efer_save_restore - wakeup_start (%eax) - testl $1, real_efer_save_restore - wakeup_start (%eax) - jz 2f - # save efer setting - pushl %eax - movl %eax, %ebx - mov $0xc0000080, %ecx - rdmsr - movl %edx, real_save_efer_edx - wakeup_start (%ebx) - movl %eax, real_save_efer_eax - wakeup_start (%ebx) - popl %eax -2: - - movl %cr3, %edx - movl %edx, real_save_cr3 - wakeup_start (%eax) - movl %cr4, %edx - movl %edx, real_save_cr4 - wakeup_start (%eax) - movl %cr0, %edx - movl %edx, real_save_cr0 - wakeup_start (%eax) - sgdt real_save_gdt - wakeup_start (%eax) - - movl saved_videomode, %edx - movl %edx, video_mode - wakeup_start (%eax) - movl acpi_realmode_flags, %edx - movl %edx, realmode_flags - wakeup_start (%eax) - movl $0x12345678, real_magic - wakeup_start (%eax) - movl $0x12345678, saved_magic - popl %ebx - ret - -save_registers: leal 4(%esp), %eax movl %eax, saved_context_esp - movl %ebx, saved_context_ebx - movl %ebp, saved_context_ebp - movl %esi, saved_context_esi - movl %edi, saved_context_edi - pushfl ; popl saved_context_eflags - - movl $ret_point, saved_eip + movl %ebx, saved_context_ebx + movl %ebp, saved_context_ebp + movl %esi, saved_context_esi + movl %edi, saved_context_edi + pushfl + popl saved_context_eflags + + movl $ret_point, saved_eip ret restore_registers: - movl saved_context_ebp, %ebp - movl saved_context_ebx, %ebx - movl saved_context_esi, %esi - movl saved_context_edi, %edi - pushl saved_context_eflags ; popfl - ret + movl saved_context_ebp, %ebp + movl saved_context_ebx, %ebx + movl saved_context_esi, %esi + movl saved_context_edi, %edi + pushl saved_context_eflags + popfl + ret ENTRY(do_suspend_lowlevel) call save_processor_state diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 2e1b9e0d0767..bcc293423a70 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -7,191 +7,18 @@ #include <asm/asm-offsets.h> # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 -# -# wakeup_code runs in real mode, and at unknown address (determined at run-time). -# Therefore it must only use relative jumps/calls. -# -# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled -# -# If physical address of wakeup_code is 0x12345, BIOS should call us with -# cs = 0x1234, eip = 0x05 -# - -#define BEEP \ - inb $97, %al; \ - outb %al, $0x80; \ - movb $3, %al; \ - outb %al, $97; \ - outb %al, $0x80; \ - movb $-74, %al; \ - outb %al, $67; \ - outb %al, $0x80; \ - movb $-119, %al; \ - outb %al, $66; \ - outb %al, $0x80; \ - movb $15, %al; \ - outb %al, $66; - - -ALIGN - .align 16 -ENTRY(wakeup_start) -wakeup_code: - wakeup_code_start = . - .code16 - -# Running in *copy* of this code, somewhere in low 1MB. - - cli - cld - # setup data segment - movw %cs, %ax - movw %ax, %ds # Make ds:0 point to wakeup_start - movw %ax, %ss - - # Data segment must be set up before we can see whether to beep. - testl $4, realmode_flags - wakeup_code - jz 1f - BEEP -1: - - # Private stack is needed for ASUS board - mov $(wakeup_stack - wakeup_code), %sp - - pushl $0 # Kill any dangerous flags - popfl - - movl real_magic - wakeup_code, %eax - cmpl $0x12345678, %eax - jne bogus_real_magic - - testl $1, realmode_flags - wakeup_code - jz 1f - lcall $0xc000,$3 - movw %cs, %ax - movw %ax, %ds # Bios might have played with that - movw %ax, %ss -1: - - testl $2, realmode_flags - wakeup_code - jz 1f - mov video_mode - wakeup_code, %ax - call mode_set -1: - - mov %ds, %ax # Find 32bit wakeup_code addr - movzx %ax, %esi # (Convert %ds:gdt to a liner ptr) - shll $4, %esi - # Fix up the vectors - addl %esi, wakeup_32_vector - wakeup_code - addl %esi, wakeup_long64_vector - wakeup_code - addl %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer - - lidtl %ds:idt_48a - wakeup_code - lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is - # appropriate - - movl $1, %eax # protected mode (PE) bit - lmsw %ax # This is it! - jmp 1f -1: - - ljmpl *(wakeup_32_vector - wakeup_code) - - .balign 4 -wakeup_32_vector: - .long wakeup_32 - wakeup_code - .word __KERNEL32_CS, 0 - - .code32 -wakeup_32: -# Running in this code, but at low address; paging is not yet turned on. - - movl $__KERNEL_DS, %eax - movl %eax, %ds - - /* - * Prepare for entering 64bits mode - */ - - /* Enable PAE */ - xorl %eax, %eax - btsl $5, %eax - movl %eax, %cr4 - - /* Setup early boot stage 4 level pagetables */ - leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax - movl %eax, %cr3 - - /* Check if nx is implemented */ - movl $0x80000001, %eax - cpuid - movl %edx,%edi - - /* Enable Long Mode */ - xorl %eax, %eax - btsl $_EFER_LME, %eax - - /* No Execute supported? */ - btl $20,%edi - jnc 1f - btsl $_EFER_NX, %eax - - /* Make changes effective */ -1: movl $MSR_EFER, %ecx - xorl %edx, %edx - wrmsr - - xorl %eax, %eax - btsl $31, %eax /* Enable paging and in turn activate Long Mode */ - btsl $0, %eax /* Enable protected mode */ - - /* Make changes effective */ - movl %eax, %cr0 - - /* At this point: - CR4.PAE must be 1 - CS.L must be 0 - CR3 must point to PML4 - Next instruction must be a branch - This must be on identity-mapped page - */ - /* - * At this point we're in long mode but in 32bit compatibility mode - * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn - * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load - * the new gdt/idt that has __KERNEL_CS with CS.L = 1. - */ - - /* Finally jump in 64bit mode */ - ljmp *(wakeup_long64_vector - wakeup_code)(%esi) - - .balign 4 -wakeup_long64_vector: - .long wakeup_long64 - wakeup_code - .word __KERNEL_CS, 0 .code64 - - /* Hooray, we are in Long 64-bit mode (but still running in - * low memory) - */ -wakeup_long64: /* - * We must switch to a new descriptor in kernel space for the GDT - * because soon the kernel won't have access anymore to the userspace - * addresses where we're currently running on. We have to do that here - * because in 32bit we couldn't load a 64bit linear address. + * Hooray, we are in Long 64-bit mode (but still running in low memory) */ - lgdt cpu_gdt_descr - - movq saved_magic, %rax - movq $0x123456789abcdef0, %rdx - cmpq %rdx, %rax - jne bogus_64_magic +ENTRY(wakeup_long64) +wakeup_long64: + movq saved_magic, %rax + movq $0x123456789abcdef0, %rdx + cmpq %rdx, %rax + jne bogus_64_magic - nop - nop movw $__KERNEL_DS, %ax movw %ax, %ss movw %ax, %ds @@ -208,130 +35,8 @@ wakeup_long64: movq saved_rip, %rax jmp *%rax -.code32 - - .align 64 -gdta: - /* Its good to keep gdt in sync with one in trampoline.S */ - .word 0, 0, 0, 0 # dummy - /* ??? Why I need the accessed bit set in order for this to work? */ - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS - -idt_48a: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L - -gdt_48a: - .word 0x800 # gdt limit=2048, - # 256 GDT entries - .long gdta - wakeup_code # gdt base (relocated in later) - -real_magic: .quad 0 -video_mode: .quad 0 -realmode_flags: .quad 0 - -.code16 -bogus_real_magic: - jmp bogus_real_magic - -.code64 bogus_64_magic: - jmp bogus_64_magic - -/* This code uses an extended set of video mode numbers. These include: - * Aliases for standard modes - * NORMAL_VGA (-1) - * EXTENDED_VGA (-2) - * ASK_VGA (-3) - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack - * of compatibility when extending the table. These are between 0x00 and 0xff. - */ -#define VIDEO_FIRST_MENU 0x0000 - -/* Standard BIOS video modes (BIOS number + 0x0100) */ -#define VIDEO_FIRST_BIOS 0x0100 - -/* VESA BIOS video modes (VESA number + 0x0200) */ -#define VIDEO_FIRST_VESA 0x0200 - -/* Video7 special modes (BIOS number + 0x0900) */ -#define VIDEO_FIRST_V7 0x0900 - -# Setting of user mode (AX=mode ID) => CF=success - -# For now, we only handle VESA modes (0x0200..0x03ff). To handle other -# modes, we should probably compile in the video code from the boot -# directory. -.code16 -mode_set: - movw %ax, %bx - subb $VIDEO_FIRST_VESA>>8, %bh - cmpb $2, %bh - jb check_vesa - -setbad: - clc - ret - -check_vesa: - orw $0x4000, %bx # Use linear frame buffer - movw $0x4f02, %ax # VESA BIOS mode set call - int $0x10 - cmpw $0x004f, %ax # AL=4f if implemented - jnz setbad # AH=0 if OK - - stc - ret - -wakeup_stack_begin: # Stack grows down - -.org 0xff0 -wakeup_stack: # Just below end of page - -.org 0x1000 -ENTRY(wakeup_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 510,8,0 - /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE - -ENTRY(wakeup_end) - -## -# acpi_copy_wakeup_routine -# -# Copy the above routine to low memory. -# -# Parameters: -# %rdi: place to copy wakeup routine to -# -# Returned address is location of code in low memory (past data and stack) -# - .code64 -ENTRY(acpi_copy_wakeup_routine) - pushq %rax - pushq %rdx - - movl saved_video_mode, %edx - movl %edx, video_mode - wakeup_start (,%rdi) - movl acpi_realmode_flags, %edx - movl %edx, realmode_flags - wakeup_start (,%rdi) - movq $0x12345678, real_magic - wakeup_start (,%rdi) - movq $0x123456789abcdef0, %rdx - movq %rdx, saved_magic - - movq saved_magic, %rax - movq $0x123456789abcdef0, %rdx - cmpq %rdx, %rax - jne bogus_64_magic - - # restore the regs we used - popq %rdx - popq %rax -ENTRY(do_suspend_lowlevel_s4bios) - ret + jmp bogus_64_magic .align 2 .p2align 4,,15 @@ -414,7 +119,7 @@ do_suspend_lowlevel: jmp restore_processor_state .LFE5: .Lfe5: - .size do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel + .size do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel .data ALIGN diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S new file mode 100644 index 000000000000..6ff3b5730575 --- /dev/null +++ b/arch/x86/kernel/acpi/wakeup_rm.S @@ -0,0 +1,10 @@ +/* + * Wrapper script for the realmode binary as a transport object + * before copying to low memory. + */ + .section ".rodata","a" + .globl wakeup_code_start, wakeup_code_end +wakeup_code_start: + .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin" +wakeup_code_end: + .size wakeup_code_start, .-wakeup_code_start diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index d4438ef296d8..bc8b57d119a1 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -1189,19 +1189,6 @@ static int suspend(int vetoable) int err; struct apm_user *as; - if (pm_send_all(PM_SUSPEND, (void *)3)) { - /* Vetoed */ - if (vetoable) { - if (apm_info.connection_version > 0x100) - set_system_power_state(APM_STATE_REJECT); - err = -EBUSY; - ignore_sys_suspend = 0; - printk(KERN_WARNING "apm: suspend was vetoed.\n"); - goto out; - } - printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n"); - } - device_suspend(PMSG_SUSPEND); local_irq_disable(); device_power_down(PMSG_SUSPEND); @@ -1224,9 +1211,7 @@ static int suspend(int vetoable) device_power_up(); local_irq_enable(); device_resume(); - pm_send_all(PM_RESUME, (void *)0); queue_event(APM_NORMAL_RESUME, NULL); - out: spin_lock(&user_list_lock); for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; @@ -1337,7 +1322,6 @@ static void check_events(void) if ((event != APM_NORMAL_RESUME) || (ignore_normal_resume == 0)) { device_resume(); - pm_send_all(PM_RESUME, (void *)0); queue_event(event, NULL); } ignore_normal_resume = 0; diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c index 9be697126013..808fd6a83851 100644 --- a/arch/x86/kernel/e820_64.c +++ b/arch/x86/kernel/e820_64.c @@ -27,6 +27,7 @@ #include <asm/setup.h> #include <asm/sections.h> #include <asm/kdebug.h> +#include <asm/trampoline.h> struct e820map e820; @@ -58,8 +59,8 @@ struct early_res { }; static struct early_res early_res[MAX_EARLY_RES] __initdata = { { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ -#ifdef CONFIG_SMP - { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" }, +#ifdef CONFIG_X86_TRAMPOLINE + { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" }, #endif {} }; diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index a007454133a3..65dec0f5dbd0 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -132,10 +132,6 @@ ident_complete: addq %rbp, trampoline_level4_pgt + 0(%rip) addq %rbp, trampoline_level4_pgt + (511*8)(%rip) #endif -#ifdef CONFIG_ACPI_SLEEP - addq %rbp, wakeup_level4_pgt + 0(%rip) - addq %rbp, wakeup_level4_pgt + (511*8)(%rip) -#endif /* Due to ENTRY(), sometimes the empty space gets filled with * zeros. Better take a jmp than relying on empty space being diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 2b3e5d45176b..89f8bdf3f194 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c @@ -189,7 +189,7 @@ EXPORT_SYMBOL(ist_info); extern void early_cpu_init(void); extern int root_mountflags; -unsigned long saved_videomode; +unsigned long saved_video_mode; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 @@ -714,7 +714,7 @@ void __init setup_arch(char **cmdline_p) edid_info = boot_params.edid_info; apm_info.bios = boot_params.apm_bios_info; ist_info = boot_params.ist_info; - saved_videomode = boot_params.hdr.vid_mode; + saved_video_mode = boot_params.hdr.vid_mode; if( boot_params.sys_desc_table.length != 0 ) { set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2); machine_id = boot_params.sys_desc_table.table[0]; diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index f4f7ecfb898c..28e0bd8bf2e0 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -66,6 +66,7 @@ #include <asm/mce.h> #include <asm/ds.h> #include <asm/topology.h> +#include <asm/trampoline.h> #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> @@ -1184,3 +1185,18 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; + +#ifdef CONFIG_X86_TRAMPOLINE +/* + * Currently trivial. Write the real->protected mode + * bootstrap into the page concerned. The caller + * has made sure it's suitably aligned. + */ + +unsigned long setup_trampoline(void) +{ + void *tramp = __va(TRAMPOLINE_BASE); + memcpy(tramp, trampoline_data, trampoline_end - trampoline_data); + return virt_to_phys(tramp); +} +#endif /* CONFIG_X86_TRAMPOLINE */ diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c index 0880f2c388a9..596f4460ed61 100644 --- a/arch/x86/kernel/smpboot_64.c +++ b/arch/x86/kernel/smpboot_64.c @@ -59,6 +59,7 @@ #include <asm/irq.h> #include <asm/hw_irq.h> #include <asm/numa.h> +#include <asm/trampoline.h> /* Number of siblings per CPU package */ int smp_num_siblings = 1; @@ -96,13 +97,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); DEFINE_PER_CPU(cpumask_t, cpu_core_map); EXPORT_PER_CPU_SYMBOL(cpu_core_map); -/* - * Trampoline 80x86 program as an array. - */ - -extern const unsigned char trampoline_data[]; -extern const unsigned char trampoline_end[]; - /* State of each CPU */ DEFINE_PER_CPU(int, cpu_state) = { 0 }; @@ -127,19 +121,6 @@ struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; /* - * Currently trivial. Write the real->protected mode - * bootstrap into the page concerned. The caller - * has made sure it's suitably aligned. - */ - -static unsigned long __cpuinit setup_trampoline(void) -{ - void *tramp = __va(SMP_TRAMPOLINE_BASE); - memcpy(tramp, trampoline_data, trampoline_end - trampoline_data); - return virt_to_phys(tramp); -} - -/* * The bootstrap kernel entry code has set these up. Save them for * a given CPU */ @@ -649,6 +630,9 @@ do_rest: *((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf; Dprintk("3.\n"); + /* Trampoline assumes it is at beggining of segment */ + BUG_ON(start_rip & 0xf); + /* * Be paranoid about clearing APIC errors. */ @@ -687,7 +671,7 @@ do_rest: Dprintk("CPU has booted.\n"); } else { boot_error = 1; - if (*((volatile unsigned char *)phys_to_virt(SMP_TRAMPOLINE_BASE)) + if (*((unsigned char *)phys_to_virt(TRAMPOLINE_BASE)) == 0xA5) /* trampoline started but...? */ printk("Stuck ??\n"); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7222a18a0319..3d9362140831 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -73,38 +73,14 @@ enum ec_event { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ +#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ enum { EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ - EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */ - EC_FLAGS_ADDRESS, /* Address is being written */ - EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ - EC_FLAGS_WDATA, /* Data is being written */ - EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */ -}; - -static int acpi_ec_remove(struct acpi_device *device, int type); -static int acpi_ec_start(struct acpi_device *device); -static int acpi_ec_stop(struct acpi_device *device, int type); -static int acpi_ec_add(struct acpi_device *device); - -static const struct acpi_device_id ec_device_ids[] = { - {"PNP0C09", 0}, - {"", 0}, -}; - -static struct acpi_driver acpi_ec_driver = { - .name = "ec", - .class = ACPI_EC_CLASS, - .ids = ec_device_ids, - .ops = { - .add = acpi_ec_add, - .remove = acpi_ec_remove, - .start = acpi_ec_start, - .stop = acpi_ec_stop, - }, + EC_FLAGS_NO_GPE, /* Don't use GPE mode */ + EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -129,6 +105,8 @@ static struct acpi_ec { struct mutex lock; wait_queue_head_t wait; struct list_head list; + struct delayed_work work; + atomic_t irq_count; u8 handlers_installed; } *boot_ec, *first_ec; @@ -177,65 +155,52 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) return 0; } -static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +static void ec_schedule_ec_poll(struct acpi_ec *ec) { - int ret = 0; + if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) + schedule_delayed_work(&ec->work, + msecs_to_jiffies(ACPI_EC_DELAY)); +} - if (unlikely(event == ACPI_EC_EVENT_OBF_1 && - test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) - force_poll = 1; - if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && - test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) - force_poll = 1; - if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) && - test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags))) - force_poll = 1; +static void ec_switch_to_poll_mode(struct acpi_ec *ec) +{ + set_bit(EC_FLAGS_NO_GPE, &ec->flags); + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); +} + +static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +{ + atomic_set(&ec->irq_count, 0); if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && likely(!force_poll)) { if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), msecs_to_jiffies(ACPI_EC_DELAY))) - goto end; + return 0; clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (acpi_ec_check_status(ec, event)) { - if (event == ACPI_EC_EVENT_OBF_1) { - /* miss OBF_1 GPE, don't expect it */ - pr_info(PREFIX "missing OBF confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags); - } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { - /* miss address GPE, don't expect it anymore */ - pr_info(PREFIX "missing address confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags); - } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) { - /* miss write data GPE, don't expect it */ - pr_info(PREFIX "missing write data confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags); - } else { - /* missing GPEs, switch back to poll mode */ - if (printk_ratelimit()) - pr_info(PREFIX "missing confirmations, " + /* missing GPEs, switch back to poll mode */ + if (printk_ratelimit()) + pr_info(PREFIX "missing confirmations, " "switch off interrupt mode.\n"); - clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); - } - goto end; + ec_switch_to_poll_mode(ec); + ec_schedule_ec_poll(ec); + return 0; } } else { unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); while (time_before(jiffies, delay)) { if (acpi_ec_check_status(ec, event)) - goto end; + return 0; + udelay(ACPI_EC_UDELAY); } } - pr_err(PREFIX "acpi_ec_wait timeout," - " status = %d, expect_event = %d\n", - acpi_ec_read_status(ec), event); - ret = -ETIME; - end: - clear_bit(EC_FLAGS_ADDRESS, &ec->flags); - return ret; + pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", + acpi_ec_read_status(ec), + (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\""); + return -ETIME; } static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, @@ -245,8 +210,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, { int result = 0; set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - acpi_ec_write_cmd(ec, command); pr_debug(PREFIX "transaction start\n"); + acpi_ec_write_cmd(ec, command); for (; wdata_len > 0; --wdata_len) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); if (result) { @@ -254,15 +219,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, "write_cmd timeout, command = %d\n", command); goto end; } - /* mark the address byte written to EC */ - if (rdata_len + wdata_len > 1) - set_bit(EC_FLAGS_ADDRESS, &ec->flags); set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); acpi_ec_write_data(ec, *(wdata++)); } if (!rdata_len) { - set_bit(EC_FLAGS_WDATA, &ec->flags); result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); if (result) { pr_err(PREFIX @@ -527,47 +488,51 @@ static u32 acpi_ec_gpe_handler(void *data) { acpi_status status = AE_OK; struct acpi_ec *ec = data; + u8 state = acpi_ec_read_status(ec); pr_debug(PREFIX "~~~> interrupt\n"); + atomic_inc(&ec->irq_count); + if (atomic_read(&ec->irq_count) > 5) { + pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); + ec_switch_to_poll_mode(ec); + goto end; + } clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) wake_up(&ec->wait); - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { + if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); - } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) { + } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + !test_bit(EC_FLAGS_NO_GPE, &ec->flags) && + in_interrupt()) { /* this is non-query, must be confirmation */ if (printk_ratelimit()) pr_info(PREFIX "non-query interrupt received," " switching to interrupt mode\n"); set_bit(EC_FLAGS_GPE_MODE, &ec->flags); + clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); } - +end: + ec_schedule_ec_poll(ec); return ACPI_SUCCESS(status) ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } +static void do_ec_poll(struct work_struct *work) +{ + struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); + atomic_set(&ec->irq_count, 0); + (void)acpi_ec_gpe_handler(ec); +} + /* -------------------------------------------------------------------------- Address Space Management -------------------------------------------------------------------------- */ static acpi_status -acpi_ec_space_setup(acpi_handle region_handle, - u32 function, void *handler_context, void **return_context) -{ - /* - * The EC object is in the handler context and is needed - * when calling the acpi_ec_space_handler. - */ - *return_context = (function != ACPI_REGION_DEACTIVATE) ? - handler_context : NULL; - - return AE_OK; -} - -static acpi_status acpi_ec_space_handler(u32 function, acpi_physical_address address, u32 bits, acpi_integer *value, void *handler_context, void *region_context) @@ -709,6 +674,8 @@ static struct acpi_ec *make_acpi_ec(void) mutex_init(&ec->lock); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); + INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); + atomic_set(&ec->irq_count, 0); return ec; } @@ -741,17 +708,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); if (ACPI_FAILURE(status)) return status; - /* Find and register all query methods */ - acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, - acpi_ec_register_query_methods, ec, NULL); /* Use the global lock for all EC transactions? */ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); ec->handle = handle; return AE_CTRL_TERMINATE; } +static void ec_poll_stop(struct acpi_ec *ec) +{ + clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); + cancel_delayed_work(&ec->work); +} + static void ec_remove_handlers(struct acpi_ec *ec) { + ec_poll_stop(ec); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err(PREFIX "failed to remove space handler\n"); @@ -771,31 +742,28 @@ static int acpi_ec_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_EC_CLASS); /* Check for boot EC */ - if (boot_ec) { - if (boot_ec->handle == device->handle) { - /* Pre-loaded EC from DSDT, just move pointer */ - ec = boot_ec; - boot_ec = NULL; - goto end; - } else if (boot_ec->handle == ACPI_ROOT_OBJECT) { - /* ECDT-based EC, time to shut it down */ - ec_remove_handlers(boot_ec); - kfree(boot_ec); - first_ec = boot_ec = NULL; + if (boot_ec && + (boot_ec->handle == device->handle || + boot_ec->handle == ACPI_ROOT_OBJECT)) { + ec = boot_ec; + boot_ec = NULL; + } else { + ec = make_acpi_ec(); + if (!ec) + return -ENOMEM; + if (ec_parse_device(device->handle, 0, ec, NULL) != + AE_CTRL_TERMINATE) { + kfree(ec); + return -EINVAL; } } - ec = make_acpi_ec(); - if (!ec) - return -ENOMEM; - - if (ec_parse_device(device->handle, 0, ec, NULL) != - AE_CTRL_TERMINATE) { - kfree(ec); - return -EINVAL; - } ec->handle = device->handle; - end: + + /* Find and register all query methods */ + acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, + acpi_ec_register_query_methods, ec, NULL); + if (!first_ec) first_ec = ec; acpi_driver_data(device) = ec; @@ -870,7 +838,7 @@ static int ec_install_handlers(struct acpi_ec *ec) status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, - &acpi_ec_space_setup, ec); + NULL, ec); if (ACPI_FAILURE(status)) { acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; @@ -897,6 +865,7 @@ static int acpi_ec_start(struct acpi_device *device) /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + ec_schedule_ec_poll(ec); return ret; } @@ -924,6 +893,11 @@ int __init acpi_boot_ec_enable(void) return -EFAULT; } +static const struct acpi_device_id ec_device_ids[] = { + {"PNP0C09", 0}, + {"", 0}, +}; + int __init acpi_ec_ecdt_probe(void) { int ret; @@ -944,6 +918,7 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; + acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); } else { /* This workaround is needed only on some broken machines, * which require early EC, but fail to provide ECDT */ @@ -973,6 +948,39 @@ int __init acpi_ec_ecdt_probe(void) return -ENODEV; } +static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state) +{ + struct acpi_ec *ec = acpi_driver_data(device); + /* Stop using GPE */ + set_bit(EC_FLAGS_NO_GPE, &ec->flags); + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + return 0; +} + +static int acpi_ec_resume(struct acpi_device *device) +{ + struct acpi_ec *ec = acpi_driver_data(device); + /* Enable use of GPE back */ + clear_bit(EC_FLAGS_NO_GPE, &ec->flags); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + return 0; +} + +static struct acpi_driver acpi_ec_driver = { + .name = "ec", + .class = ACPI_EC_CLASS, + .ids = ec_device_ids, + .ops = { + .add = acpi_ec_add, + .remove = acpi_ec_remove, + .start = acpi_ec_start, + .stop = acpi_ec_stop, + .suspend = acpi_ec_suspend, + .resume = acpi_ec_resume, + }, +}; + static int __init acpi_ec_init(void) { int result = 0; diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 0dadd2adc800..9b23c0c36de5 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -248,7 +248,8 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_disable_gpe); - if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { + if (gpe_event_info->flags && + (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK))) { return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index eda0978b57c6..06f8634fe58b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device); static int acpi_bind_one(struct device *dev, acpi_handle handle) { + struct acpi_device *acpi_dev; acpi_status status; if (dev->archdata.acpi_handle) { @@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) } dev->archdata.acpi_handle = handle; + status = acpi_bus_get_device(handle, &acpi_dev); + if (!ACPI_FAILURE(status)) { + int ret; + + ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, + "firmware_node"); + ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, + "physical_node"); + } + return 0; } @@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev) if (!dev->archdata.acpi_handle) return 0; if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { + struct acpi_device *acpi_dev; + /* acpi_get_physical_device increase refcnt by one */ put_device(dev); + + if (!acpi_bus_get_device(dev->archdata.acpi_handle, + &acpi_dev)) { + sysfs_remove_link(&dev->kobj, "firmware_node"); + sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); + } + acpi_detach_data(dev->archdata.acpi_handle, acpi_glue_data_handler); dev->archdata.acpi_handle = NULL; diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 2d496918b3cd..2ab2316447d1 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -192,24 +192,6 @@ acpi_status acpi_enable_subsystem(u32 flags) } } - /* - * Complete the GPE initialization for the GPE blocks defined in the FADT - * (GPE block 0 and 1). - * - * Note1: This is where the _PRW methods are executed for the GPEs. These - * methods can only be executed after the SCI and Global Lock handlers are - * installed and initialized. - * - * Note2: Currently, there seems to be no need to run the _REG methods - * before execution of the _PRW methods and enabling of the GPEs. - */ - if (!(flags & ACPI_NO_EVENT_INIT)) { - status = acpi_ev_install_fadt_gpes(); - if (ACPI_FAILURE(status)) { - return (status); - } - } - return_ACPI_STATUS(status); } @@ -280,6 +262,24 @@ acpi_status acpi_initialize_objects(u32 flags) } /* + * Complete the GPE initialization for the GPE blocks defined in the FADT + * (GPE block 0 and 1). + * + * Note1: This is where the _PRW methods are executed for the GPEs. These + * methods can only be executed after the SCI and Global Lock handlers are + * installed and initialized. + * + * Note2: Currently, there seems to be no need to run the _REG methods + * before execution of the _PRW methods and enabling of the GPEs. + */ + if (!(flags & ACPI_NO_EVENT_INIT)) { + status = acpi_ev_install_fadt_gpes(); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* * Empty the caches (delete the cached objects) on the assumption that * the table load filled them up more than they will be at runtime -- * thus wasting non-paged memory. diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 31a633f65547..b1e2f6edec03 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -1,6 +1,32 @@ extern spinlock_t pnp_lock; void *pnp_alloc(long size); + +int pnp_register_protocol(struct pnp_protocol *protocol); +void pnp_unregister_protocol(struct pnp_protocol *protocol); + +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid); +struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid); + +int pnp_add_device(struct pnp_dev *dev); +struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id); int pnp_interface_attach_device(struct pnp_dev *dev); + +int pnp_add_card(struct pnp_card *card); +struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id); +void pnp_remove_card(struct pnp_card *card); +int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); +void pnp_remove_card_device(struct pnp_dev *dev); + +struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); +struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, + int priority); +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data); +int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data); +int pnp_register_port_resource(struct pnp_option *option, + struct pnp_port *data); +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data); +void pnp_init_resources(struct pnp_dev *dev); + void pnp_fixup_device(struct pnp_dev *dev); void pnp_free_option(struct pnp_option *option); int __pnp_add_device(struct pnp_dev *dev); @@ -10,3 +36,20 @@ int pnp_check_port(struct pnp_dev * dev, int idx); int pnp_check_mem(struct pnp_dev * dev, int idx); int pnp_check_irq(struct pnp_dev * dev, int idx); int pnp_check_dma(struct pnp_dev * dev, int idx); + +int pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags); +int pnp_add_dma_resource(struct pnp_dev *dev, int dma, int flags); +int pnp_add_io_resource(struct pnp_dev *dev, resource_size_t start, resource_size_t len, int flags); +int pnp_add_mem_resource(struct pnp_dev *dev, resource_size_t start, resource_size_t len, int flags); + +#define PNP_MAX_PORT 40 +#define PNP_MAX_MEM 24 +#define PNP_MAX_IRQ 2 +#define PNP_MAX_DMA 2 + +struct pnp_resource_table { + struct resource port_resource[PNP_MAX_PORT]; + struct resource mem_resource[PNP_MAX_MEM]; + struct resource dma_resource[PNP_MAX_DMA]; + struct resource irq_resource[PNP_MAX_IRQ]; +}; diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index da1c9909eb44..a762a4176736 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -5,6 +5,7 @@ */ #include <linux/module.h> +#include <linux/ctype.h> #include <linux/slab.h> #include <linux/pnp.h> #include "base.h" @@ -100,19 +101,33 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv) * @id: pointer to a pnp_id structure * @card: pointer to the desired card */ -int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card) +struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) { - struct pnp_id *ptr; + struct pnp_id *dev_id, *ptr; - id->next = NULL; + dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); + if (!dev_id) + return NULL; + + dev_id->id[0] = id[0]; + dev_id->id[1] = id[1]; + dev_id->id[2] = id[2]; + dev_id->id[3] = tolower(id[3]); + dev_id->id[4] = tolower(id[4]); + dev_id->id[5] = tolower(id[5]); + dev_id->id[6] = tolower(id[6]); + dev_id->id[7] = '\0'; + + dev_id->next = NULL; ptr = card->id; while (ptr && ptr->next) ptr = ptr->next; if (ptr) - ptr->next = id; + ptr->next = dev_id; else - card->id = id; - return 0; + card->id = dev_id; + + return dev_id; } static void pnp_free_card_ids(struct pnp_card *card) @@ -136,6 +151,31 @@ static void pnp_release_card(struct device *dmdev) kfree(card); } +struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid) +{ + struct pnp_card *card; + struct pnp_id *dev_id; + + card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL); + if (!card) + return NULL; + + card->protocol = protocol; + card->number = id; + + card->dev.parent = &card->protocol->dev; + sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, + card->number); + + dev_id = pnp_add_card_id(card, pnpid); + if (!dev_id) { + kfree(card); + return NULL; + } + + return card; +} + static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf) { @@ -191,9 +231,6 @@ int pnp_add_card(struct pnp_card *card) int error; struct list_head *pos, *temp; - sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, - card->number); - card->dev.parent = &card->protocol->dev; card->dev.bus = NULL; card->dev.release = &pnp_release_card; error = device_register(&card->dev); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7d366ca672d3..854dd33f91a7 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -106,9 +106,42 @@ static void pnp_release_device(struct device *dmdev) pnp_free_option(dev->independent); pnp_free_option(dev->dependent); pnp_free_ids(dev); + kfree(dev->res); kfree(dev); } +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid) +{ + struct pnp_dev *dev; + struct pnp_id *dev_id; + + dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->res = kzalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); + if (!dev->res) { + kfree(dev); + return NULL; + } + + dev->protocol = protocol; + dev->number = id; + + dev->dev.parent = &dev->protocol->dev; + sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, + dev->number); + + dev_id = pnp_add_id(dev, pnpid); + if (!dev_id) { + kfree(dev->res); + kfree(dev); + return NULL; + } + + return dev; +} + int __pnp_add_device(struct pnp_dev *dev) { int ret; @@ -145,9 +178,6 @@ int pnp_add_device(struct pnp_dev *dev) if (dev->card) return -EINVAL; - dev->dev.parent = &dev->protocol->dev; - sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, - dev->number); ret = __pnp_add_device(dev); if (ret) return ret; diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 12a1645a2e43..71436e8fc7d2 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -226,22 +226,36 @@ void pnp_unregister_driver(struct pnp_driver *drv) /** * pnp_add_id - adds an EISA id to the specified device - * @id: pointer to a pnp_id structure * @dev: pointer to the desired device + * @id: pointer to an EISA id string */ -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) +struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id) { - struct pnp_id *ptr; + struct pnp_id *dev_id, *ptr; - id->next = NULL; + dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); + if (!dev_id) + return NULL; + + dev_id->id[0] = id[0]; + dev_id->id[1] = id[1]; + dev_id->id[2] = id[2]; + dev_id->id[3] = tolower(id[3]); + dev_id->id[4] = tolower(id[4]); + dev_id->id[5] = tolower(id[5]); + dev_id->id[6] = tolower(id[6]); + dev_id->id[7] = '\0'; + + dev_id->next = NULL; ptr = dev->id; while (ptr && ptr->next) ptr = ptr->next; if (ptr) - ptr->next = id; + ptr->next = dev_id; else - dev->id = id; - return 0; + dev->id = dev_id; + + return dev_id; } EXPORT_SYMBOL(pnp_register_driver); diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 982658477a58..f637446ffdbd 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -243,11 +243,14 @@ static ssize_t pnp_show_options(struct device *dmdev, static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL); +#define set(flags) ((flags & IORESOURCE_UNSET) == 0) + static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); + struct resource *res; int i, ret; pnp_info_buffer_t *buffer; @@ -267,50 +270,46 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, else pnp_printf(buffer, "disabled\n"); - for (i = 0; i < PNP_MAX_PORT; i++) { - if (pnp_port_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (set(res->flags)) { pnp_printf(buffer, "io"); - if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " 0x%llx-0x%llx\n", - (unsigned long long) - pnp_port_start(dev, i), - (unsigned long long)pnp_port_end(dev, - i)); + (unsigned long long) res->start, + (unsigned long long) res->end); } } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (pnp_mem_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (set(res->flags)) { pnp_printf(buffer, "mem"); - if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " 0x%llx-0x%llx\n", - (unsigned long long) - pnp_mem_start(dev, i), - (unsigned long long)pnp_mem_end(dev, - i)); + (unsigned long long) res->start, + (unsigned long long) res->end); } } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (pnp_irq_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) { + if (set(res->flags)) { pnp_printf(buffer, "irq"); - if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " %lld\n", - (unsigned long long)pnp_irq(dev, i)); + (unsigned long long) res->start); } } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (pnp_dma_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) { + if (set(res->flags)) { pnp_printf(buffer, "dma"); - if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " %lld\n", - (unsigned long long)pnp_dma(dev, i)); + (unsigned long long) res->start); } } ret = (buffer->curr - buf); @@ -325,6 +324,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, struct pnp_dev *dev = to_pnp_dev(dmdev); char *buf = (void *)ubuf; int retval = 0; + resource_size_t start, end, length; if (dev->status & PNP_ATTACHED) { retval = -EBUSY; @@ -351,29 +351,28 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, if (!strnicmp(buf, "auto", 4)) { if (dev->active) goto done; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf, "clear", 5)) { if (dev->active) goto done; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); goto done; } if (!strnicmp(buf, "get", 3)) { mutex_lock(&pnp_res_mutex); if (pnp_can_read(dev)) - dev->protocol->get(dev, &dev->res); + dev->protocol->get(dev); mutex_unlock(&pnp_res_mutex); goto done; } if (!strnicmp(buf, "set", 3)) { - int nport = 0, nmem = 0, nirq = 0, ndma = 0; if (dev->active) goto done; buf += 3; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); mutex_lock(&pnp_res_mutex); while (1) { while (isspace(*buf)) @@ -382,76 +381,52 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, buf += 2; while (isspace(*buf)) ++buf; - dev->res.port_resource[nport].start = - simple_strtoul(buf, &buf, 0); + start = simple_strtoul(buf, &buf, 0); while (isspace(*buf)) ++buf; if (*buf == '-') { buf += 1; while (isspace(*buf)) ++buf; - dev->res.port_resource[nport].end = - simple_strtoul(buf, &buf, 0); + end = simple_strtoul(buf, &buf, 0); } else - dev->res.port_resource[nport].end = - dev->res.port_resource[nport].start; - dev->res.port_resource[nport].flags = - IORESOURCE_IO; - nport++; - if (nport >= PNP_MAX_PORT) - break; + end = start; + length = end - start + 1; + pnp_add_io_resource(dev, start, length, 0); continue; } if (!strnicmp(buf, "mem", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.mem_resource[nmem].start = - simple_strtoul(buf, &buf, 0); + start = simple_strtoul(buf, &buf, 0); while (isspace(*buf)) ++buf; if (*buf == '-') { buf += 1; while (isspace(*buf)) ++buf; - dev->res.mem_resource[nmem].end = - simple_strtoul(buf, &buf, 0); + end = simple_strtoul(buf, &buf, 0); } else - dev->res.mem_resource[nmem].end = - dev->res.mem_resource[nmem].start; - dev->res.mem_resource[nmem].flags = - IORESOURCE_MEM; - nmem++; - if (nmem >= PNP_MAX_MEM) - break; + end = start; + length = end - start + 1; + pnp_add_mem_resource(dev, start, length, 0); continue; } if (!strnicmp(buf, "irq", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.irq_resource[nirq].start = - dev->res.irq_resource[nirq].end = - simple_strtoul(buf, &buf, 0); - dev->res.irq_resource[nirq].flags = - IORESOURCE_IRQ; - nirq++; - if (nirq >= PNP_MAX_IRQ) - break; + start = simple_strtoul(buf, &buf, 0); + pnp_add_irq_resource(dev, start, 0); continue; } if (!strnicmp(buf, "dma", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.dma_resource[ndma].start = - dev->res.dma_resource[ndma].end = - simple_strtoul(buf, &buf, 0); - dev->res.dma_resource[ndma].flags = - IORESOURCE_DMA; - ndma++; - if (ndma >= PNP_MAX_DMA) - break; + start = simple_strtoul(buf, &buf, 0); + pnp_add_dma_resource(dev, start, 0); continue; } break; diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 257f5d827d83..c4b95b52612b 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -44,6 +44,8 @@ #include <linux/mutex.h> #include <asm/io.h> +#include "../base.h" + #if 0 #define ISAPNP_REGION_OK #endif @@ -88,6 +90,14 @@ MODULE_LICENSE("GPL"); #define _LTAG_MEM32RANGE 0x85 #define _LTAG_FIXEDMEM32RANGE 0x86 +/* Logical device control and configuration registers */ + +#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */ +#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */ +#define ISAPNP_CFG_PORT 0x60 /* 8 * word */ +#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */ +#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */ + /* * Sizes of ISAPNP logical device configuration register sets. * See PNP-ISA-v1.0a.pdf, Appendix A. @@ -390,23 +400,17 @@ static void __init isapnp_skip_bytes(int count) /* * Parse EISA id. */ -static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor, - unsigned short device) +static void isapnp_to_pnpid(unsigned short vendor, unsigned short device, + char *id) { - struct pnp_id *id; - - if (!dev) - return; - id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!id) - return; - sprintf(id->id, "%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f); - pnp_add_id(id, dev); + id[0] = 'A' + ((vendor >> 2) & 0x3f) - 1; + id[1] = 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1; + id[2] = 'A' + ((vendor >> 8) & 0x1f) - 1; + id[3] = '0' + ((device >> 4) & 0x0f); + id[4] = '0' + (device & 0x0f); + id[5] = '0' + ((device >> 12) & 0x0f); + id[6] = '0' + ((device >> 8) & 0x0f); + id[7] = '\0'; } /* @@ -416,24 +420,25 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card, int size, int number) { unsigned char tmp[6]; + char id[8]; struct pnp_dev *dev; isapnp_peek(tmp, size); - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); + isapnp_to_pnpid((tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2], id); + + dev = pnp_alloc_dev(&isapnp_protocol, number, id); if (!dev) return NULL; - dev->number = number; - isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]); + dev->regs = tmp[4]; dev->card = card; if (size > 5) dev->regs |= tmp[5] << 8; - dev->protocol = &isapnp_protocol; dev->capabilities |= PNP_CONFIGURABLE; dev->capabilities |= PNP_READ; dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_DISABLE; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); return dev; } @@ -613,6 +618,7 @@ static int __init isapnp_create_device(struct pnp_card *card, unsigned char type, tmp[17]; struct pnp_option *option; struct pnp_dev *dev; + char id[8]; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; @@ -652,8 +658,9 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_COMPATDEVID: if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) { isapnp_peek(tmp, 4); - isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], - (tmp[3] << 8) | tmp[2]); + isapnp_to_pnpid((tmp[1] << 8) | tmp[0], + (tmp[3] << 8) | tmp[2], id); + pnp_add_id(dev, id); compat++; size = 0; } @@ -734,9 +741,8 @@ static int __init isapnp_create_device(struct pnp_card *card, isapnp_skip_bytes(size); return 1; default: - printk(KERN_ERR - "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", - type, dev->number, card->number); + dev_err(&dev->dev, "unknown tag 0x%x (card %i), " + "ignored\n", type, card->number); } __skip: if (size > 0) @@ -789,9 +795,8 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card) isapnp_skip_bytes(size); return; default: - printk(KERN_ERR - "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", - type, card->number); + dev_err(&card->dev, "unknown tag 0x%x, ignored\n", + type); } __skip: if (size > 0) @@ -822,25 +827,6 @@ static unsigned char __init isapnp_checksum(unsigned char *data) } /* - * Parse EISA id for ISA PnP card. - */ -static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor, - unsigned short device) -{ - struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - - if (!id) - return; - sprintf(id->id, "%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f); - pnp_add_card_id(id, card); -} - -/* * Build device list for all present ISA PnP devices. */ static int __init isapnp_build_device_list(void) @@ -848,6 +834,7 @@ static int __init isapnp_build_device_list(void) int csn; unsigned char header[9], checksum; struct pnp_card *card; + char id[8]; isapnp_wait(); isapnp_key(); @@ -855,32 +842,30 @@ static int __init isapnp_build_device_list(void) isapnp_wake(csn); isapnp_peek(header, 9); checksum = isapnp_checksum(header); + isapnp_to_pnpid((header[1] << 8) | header[0], + (header[3] << 8) | header[2], id); + card = pnp_alloc_card(&isapnp_protocol, csn, id); + if (!card) + continue; + #if 0 - printk(KERN_DEBUG + dev_info(&card->dev, "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], header[7], header[8]); - printk(KERN_DEBUG "checksum = 0x%x\n", checksum); + dev_info(&card->dev, "checksum = 0x%x\n", checksum); #endif - if ((card = - kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL) - continue; - card->number = csn; INIT_LIST_HEAD(&card->devices); - isapnp_parse_card_id(card, (header[1] << 8) | header[0], - (header[3] << 8) | header[2]); card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4]; isapnp_checksum_value = 0x00; isapnp_parse_resource_map(card); if (isapnp_checksum_value != 0x00) - printk(KERN_ERR - "isapnp: checksum for device %i is not valid (0x%x)\n", - csn, isapnp_checksum_value); + dev_err(&card->dev, "invalid checksum 0x%x\n", + isapnp_checksum_value); card->checksum = isapnp_checksum_value; - card->protocol = &isapnp_protocol; pnp_add_card(card); } @@ -947,8 +932,7 @@ EXPORT_SYMBOL(isapnp_cfg_begin); EXPORT_SYMBOL(isapnp_cfg_end); EXPORT_SYMBOL(isapnp_write_byte); -static int isapnp_read_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int isapnp_read_resources(struct pnp_dev *dev) { int tmp, ret; @@ -958,16 +942,14 @@ static int isapnp_read_resources(struct pnp_dev *dev, ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); if (!ret) continue; - res->port_resource[tmp].start = ret; - res->port_resource[tmp].flags = IORESOURCE_IO; + pnp_add_io_resource(dev, ret, 1, 0); } for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) { ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8; if (!ret) continue; - res->mem_resource[tmp].start = ret; - res->mem_resource[tmp].flags = IORESOURCE_MEM; + pnp_add_mem_resource(dev, ret, 1, 0); } for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) { ret = @@ -975,72 +957,62 @@ static int isapnp_read_resources(struct pnp_dev *dev, 8); if (!ret) continue; - res->irq_resource[tmp].start = - res->irq_resource[tmp].end = ret; - res->irq_resource[tmp].flags = IORESOURCE_IRQ; + pnp_add_irq_resource(dev, ret, 0); } for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) { ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); if (ret == 4) continue; - res->dma_resource[tmp].start = - res->dma_resource[tmp].end = ret; - res->dma_resource[tmp].flags = IORESOURCE_DMA; + pnp_add_dma_resource(dev, ret, 0); } } return 0; } -static int isapnp_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int isapnp_get_resources(struct pnp_dev *dev) { int ret; - pnp_init_resource_table(res); + pnp_init_resources(dev); isapnp_cfg_begin(dev->card->number, dev->number); - ret = isapnp_read_resources(dev, res); + ret = isapnp_read_resources(dev); isapnp_cfg_end(); return ret; } -static int isapnp_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int isapnp_set_resources(struct pnp_dev *dev) { - int tmp; + int i, irq; + struct resource *res; isapnp_cfg_begin(dev->card->number, dev->number); dev->active = 1; - for (tmp = 0; - tmp < ISAPNP_MAX_PORT - && (res->port_resource[tmp]. - flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; - tmp++) - isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1), - res->port_resource[tmp].start); - for (tmp = 0; - tmp < ISAPNP_MAX_IRQ - && (res->irq_resource[tmp]. - flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; - tmp++) { - int irq = res->irq_resource[tmp].start; - if (irq == 2) - irq = 9; - isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq); + for (i = 0; i < ISAPNP_MAX_PORT; i++) { + res = pnp_get_resource(dev, IORESOURCE_IO, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + isapnp_write_word(ISAPNP_CFG_PORT + (i << 1), + res->start); + } + for (i = 0; i < ISAPNP_MAX_IRQ; i++) { + res = pnp_get_resource(dev, IORESOURCE_IRQ, i); + if (res && !(res->flags & IORESOURCE_UNSET)) { + irq = res->start; + if (irq == 2) + irq = 9; + isapnp_write_byte(ISAPNP_CFG_IRQ + (i << 1), irq); + } + } + for (i = 0; i < ISAPNP_MAX_DMA; i++) { + res = pnp_get_resource(dev, IORESOURCE_DMA, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + isapnp_write_byte(ISAPNP_CFG_DMA + i, res->start); + } + for (i = 0; i < ISAPNP_MAX_MEM; i++) { + res = pnp_get_resource(dev, IORESOURCE_MEM, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + isapnp_write_word(ISAPNP_CFG_MEM + (i << 3), + (res->start >> 8) & 0xffff); } - for (tmp = 0; - tmp < ISAPNP_MAX_DMA - && (res->dma_resource[tmp]. - flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; - tmp++) - isapnp_write_byte(ISAPNP_CFG_DMA + tmp, - res->dma_resource[tmp].start); - for (tmp = 0; - tmp < ISAPNP_MAX_MEM - && (res->mem_resource[tmp]. - flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; - tmp++) - isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3), - (res->mem_resource[tmp].start >> 8) & 0xffff); /* FIXME: We aren't handling 32bit mems properly here */ isapnp_activate(dev->number); isapnp_cfg_end(); @@ -1138,13 +1110,13 @@ static int __init isapnp_init(void) protocol_for_each_card(&isapnp_protocol, card) { cards++; if (isapnp_verbose) { - printk(KERN_INFO "isapnp: Card '%s'\n", - card->name[0] ? card->name : "Unknown"); + dev_info(&card->dev, "card '%s'\n", + card->name[0] ? card->name : "unknown"); if (isapnp_verbose < 2) continue; card_for_each_dev(card, dev) { - printk(KERN_INFO "isapnp: Device '%s'\n", - dev->name[0] ? dev->name : "Unknown"); + dev_info(&card->dev, "device '%s'\n", + dev->name[0] ? dev->name : "unknown"); } } } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index c28caf272c11..29273a3fd009 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -19,6 +19,7 @@ DEFINE_MUTEX(pnp_res_mutex); static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { + struct resource *res; resource_size_t *start, *end; unsigned long *flags; @@ -28,13 +29,15 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) return 1; } + res = pnp_get_resource(dev, IORESOURCE_IO, idx); + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) return 1; - start = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - flags = &dev->res.port_resource[idx].flags; + start = &res->start; + end = &res->end; + flags = &res->flags; /* set the initial values */ *flags |= rule->flags | IORESOURCE_IO; @@ -60,6 +63,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) { + struct resource *res; resource_size_t *start, *end; unsigned long *flags; @@ -69,13 +73,15 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) return 1; } + res = pnp_get_resource(dev, IORESOURCE_MEM, idx); + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) return 1; - start = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - flags = &dev->res.mem_resource[idx].flags; + start = &res->start; + end = &res->end; + flags = &res->flags; /* set the initial values */ *flags |= rule->flags | IORESOURCE_MEM; @@ -111,6 +117,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) { + struct resource *res; resource_size_t *start, *end; unsigned long *flags; int i; @@ -126,13 +133,15 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) return 1; } + res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) return 1; - start = &dev->res.irq_resource[idx].start; - end = &dev->res.irq_resource[idx].end; - flags = &dev->res.irq_resource[idx].flags; + start = &res->start; + end = &res->end; + flags = &res->flags; /* set the initial values */ *flags |= rule->flags | IORESOURCE_IRQ; @@ -161,6 +170,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { + struct resource *res; resource_size_t *start, *end; unsigned long *flags; int i; @@ -175,13 +185,15 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) return; } + res = pnp_get_resource(dev, IORESOURCE_DMA, idx); + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) return; - start = &dev->res.dma_resource[idx].start; - end = &dev->res.dma_resource[idx].end; - flags = &dev->res.dma_resource[idx].flags; + start = &res->start; + end = &res->end; + flags = &res->flags; /* set the initial values */ *flags |= rule->flags | IORESOURCE_DMA; @@ -204,8 +216,9 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) * pnp_init_resources - Resets a resource table to default values. * @table: pointer to the desired resource table */ -void pnp_init_resource_table(struct pnp_resource_table *table) +void pnp_init_resources(struct pnp_dev *dev) { + struct pnp_resource_table *table = dev->res; int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { @@ -242,8 +255,9 @@ void pnp_init_resource_table(struct pnp_resource_table *table) * pnp_clean_resources - clears resources that were not manually set * @res: the resources to clean */ -static void pnp_clean_resource_table(struct pnp_resource_table *res) +static void pnp_clean_resource_table(struct pnp_dev *dev) { + struct pnp_resource_table *res = dev->res; int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { @@ -299,7 +313,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) return -ENODEV; mutex_lock(&pnp_res_mutex); - pnp_clean_resource_table(&dev->res); /* start with a fresh slate */ + pnp_clean_resource_table(dev); if (dev->independent) { port = dev->independent->port; mem = dev->independent->mem; @@ -371,65 +385,12 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) return 1; fail: - pnp_clean_resource_table(&dev->res); + pnp_clean_resource_table(dev); mutex_unlock(&pnp_res_mutex); return 0; } /** - * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table - * @dev: pointer to the desired device - * @res: pointer to the new resource config - * @mode: 0 or PNP_CONFIG_FORCE - * - * This function can be used by drivers that want to manually set thier resources. - */ -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, - int mode) -{ - int i; - struct pnp_resource_table *bak; - - if (!pnp_can_configure(dev)) - return -ENODEV; - bak = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!bak) - return -ENOMEM; - *bak = dev->res; - - mutex_lock(&pnp_res_mutex); - dev->res = *res; - if (!(mode & PNP_CONFIG_FORCE)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_check_port(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_check_mem(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (!pnp_check_irq(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (!pnp_check_dma(dev, i)) - goto fail; - } - } - mutex_unlock(&pnp_res_mutex); - - kfree(bak); - return 0; - -fail: - dev->res = *bak; - mutex_unlock(&pnp_res_mutex); - kfree(bak); - return -EINVAL; -} - -/** * pnp_auto_config_dev - automatically assigns resources to a device * @dev: pointer to the desired device */ @@ -473,7 +434,7 @@ int pnp_start_dev(struct pnp_dev *dev) return -EINVAL; } - if (dev->protocol->set(dev, &dev->res) < 0) { + if (dev->protocol->set(dev) < 0) { dev_err(&dev->dev, "activation failed\n"); return -EIO; } @@ -549,30 +510,13 @@ int pnp_disable_dev(struct pnp_dev *dev) /* release the resources so that other devices can use them */ mutex_lock(&pnp_res_mutex); - pnp_clean_resource_table(&dev->res); + pnp_clean_resource_table(dev); mutex_unlock(&pnp_res_mutex); return 0; } -/** - * pnp_resource_change - change one resource - * @resource: pointer to resource to be changed - * @start: start of region - * @size: size of region - */ -void pnp_resource_change(struct resource *resource, resource_size_t start, - resource_size_t size) -{ - resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET); - resource->start = start; - resource->end = start + size - 1; -} - -EXPORT_SYMBOL(pnp_manual_config_dev); EXPORT_SYMBOL(pnp_start_dev); EXPORT_SYMBOL(pnp_stop_dev); EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_disable_dev); -EXPORT_SYMBOL(pnp_resource_change); -EXPORT_SYMBOL(pnp_init_resource_table); diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c283a9a70d83..e6695cf5d320 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -25,6 +25,7 @@ #include <acpi/acpi_bus.h> #include <acpi/actypes.h> +#include "../base.h" #include "pnpacpi.h" static int num = 0; @@ -72,40 +73,25 @@ static int __init ispnpidacpi(char *id) return 1; } -static void __init pnpidacpi_to_pnpid(char *id, char *str) -{ - str[0] = id[0]; - str[1] = id[1]; - str[2] = id[2]; - str[3] = tolower(id[3]); - str[4] = tolower(id[4]); - str[5] = tolower(id[5]); - str[6] = tolower(id[6]); - str[7] = '\0'; -} - -static int pnpacpi_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpacpi_get_resources(struct pnp_dev *dev) { acpi_status status; - status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data, - &dev->res); + status = pnpacpi_parse_allocated_resource(dev); return ACPI_FAILURE(status) ? -ENODEV : 0; } -static int pnpacpi_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpacpi_set_resources(struct pnp_dev *dev) { acpi_handle handle = dev->data; struct acpi_buffer buffer; - int ret = 0; + int ret; acpi_status status; - ret = pnpacpi_build_resource_template(handle, &buffer); + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; - ret = pnpacpi_encode_resources(res, &buffer); + ret = pnpacpi_encode_resources(dev, &buffer); if (ret) { kfree(buffer.pointer); return ret; @@ -163,7 +149,6 @@ static int __init pnpacpi_add_device(struct acpi_device *device) { acpi_handle temp = NULL; acpi_status status; - struct pnp_id *dev_id; struct pnp_dev *dev; status = acpi_get_handle(device->handle, "_CRS", &temp); @@ -171,11 +156,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device) is_exclusive_device(device)) return 0; - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); - if (!dev) { - pnp_err("Out of memory"); + dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device)); + if (!dev) return -ENOMEM; - } + dev->data = device->handle; /* .enabled means the device can decode the resources */ dev->active = device->status.enabled; @@ -191,44 +175,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (ACPI_SUCCESS(status)) dev->capabilities |= PNP_DISABLE; - dev->protocol = &pnpacpi_protocol; - if (strlen(acpi_device_name(device))) strncpy(dev->name, acpi_device_name(device), sizeof(dev->name)); else strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); - dev->number = num; - - /* set the initial values for the PnP device */ - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) - goto err; - pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id); - pnp_add_id(dev_id, dev); - - if (dev->active) { - /* parse allocated resource */ - status = pnpacpi_parse_allocated_resource(device->handle, - &dev->res); - if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { - pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", - dev_id->id); - goto err1; - } - } + if (dev->active) + pnpacpi_parse_allocated_resource(dev); - if (dev->capabilities & PNP_CONFIGURABLE) { - status = pnpacpi_parse_resource_option_data(device->handle, - dev); - if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { - pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", - dev_id->id); - goto err1; - } - } + if (dev->capabilities & PNP_CONFIGURABLE) + pnpacpi_parse_resource_option_data(dev); - /* parse compatible ids */ if (device->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; int i; @@ -236,27 +193,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device) for (i = 0; i < cid_list->count; i++) { if (!ispnpidacpi(cid_list->id[i].value)) continue; - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) - continue; - - pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id); - pnp_add_id(dev_id, dev); + pnp_add_id(dev, cid_list->id[i].value); } } /* clear out the damaged flags */ if (!dev->active) - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); pnp_add_device(dev); num++; return AE_OK; -err1: - kfree(dev_id); -err: - kfree(dev); - return -EINVAL; } static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h index f28e2ed66fa3..db0c4f25c2a3 100644 --- a/drivers/pnp/pnpacpi/pnpacpi.h +++ b/drivers/pnp/pnpacpi/pnpacpi.h @@ -5,8 +5,8 @@ #include <linux/acpi.h> #include <linux/pnp.h> -acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*); -acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*); -int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *); -int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*); +acpi_status pnpacpi_parse_allocated_resource(struct pnp_dev *); +acpi_status pnpacpi_parse_resource_option_data(struct pnp_dev *); +int pnpacpi_encode_resources(struct pnp_dev *, struct acpi_buffer *); +int pnpacpi_build_resource_template(struct pnp_dev *, struct acpi_buffer *); #endif diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 2dcd1960aca8..d8e2d8be0966 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -22,6 +22,7 @@ #include <linux/acpi.h> #include <linux/pci.h> #include "pnpacpi.h" +#include "../base.h" #ifdef CONFIG_IA64 #define valid_IRQ(i) (1) @@ -32,19 +33,26 @@ /* * Allocated Resources */ -static int irq_flags(int triggering, int polarity) +static int irq_flags(int triggering, int polarity, int shareable) { + int flags; + if (triggering == ACPI_LEVEL_SENSITIVE) { if (polarity == ACPI_ACTIVE_LOW) - return IORESOURCE_IRQ_LOWLEVEL; + flags = IORESOURCE_IRQ_LOWLEVEL; else - return IORESOURCE_IRQ_HIGHLEVEL; + flags = IORESOURCE_IRQ_HIGHLEVEL; } else { if (polarity == ACPI_ACTIVE_LOW) - return IORESOURCE_IRQ_LOWEDGE; + flags = IORESOURCE_IRQ_LOWEDGE; else - return IORESOURCE_IRQ_HIGHEDGE; + flags = IORESOURCE_IRQ_HIGHEDGE; } + + if (shareable) + flags |= IORESOURCE_IRQ_SHAREABLE; + + return flags; } static void decode_irq_flags(int flag, int *triggering, int *polarity) @@ -69,27 +77,16 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity) } } -static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, +static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, u32 gsi, int triggering, int polarity, int shareable) { - int i = 0; - int irq; + int irq, flags; int p, t; - static unsigned char warned; if (!valid_IRQ(gsi)) return; - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && - i < PNP_MAX_IRQ) - i++; - if (i >= PNP_MAX_IRQ && !warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of IRQ " - "resources: %d \n", PNP_MAX_IRQ); - warned = 1; - return; - } /* * in IO-APIC mode, use overrided attribute. Two reasons: * 1. BIOS bug in DSDT @@ -100,27 +97,17 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; if (triggering != t || polarity != p) { - pnp_warn("IRQ %d override to %s, %s", + dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", gsi, t ? "edge":"level", p ? "low":"high"); triggering = t; polarity = p; } } + flags = irq_flags(triggering, polarity, shareable); - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag - res->irq_resource[i].flags |= irq_flags(triggering, polarity); irq = acpi_register_gsi(gsi, triggering, polarity); - if (irq < 0) { - res->irq_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - - if (shareable) - res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE; - - res->irq_resource[i].start = irq; - res->irq_resource[i].end = irq; - pcibios_penalize_isa_irq(irq, 1); + if (pnp_add_irq_resource(dev, irq, flags) == 0) + pcibios_penalize_isa_irq(irq, 1); } static int dma_flags(int type, int bus_master, int transfer) @@ -166,88 +153,7 @@ static int dma_flags(int type, int bus_master, int transfer) return flags; } -static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, - u32 dma, int type, - int bus_master, int transfer) -{ - int i = 0; - static unsigned char warned; - - while (i < PNP_MAX_DMA && - !(res->dma_resource[i].flags & IORESOURCE_UNSET)) - i++; - if (i < PNP_MAX_DMA) { - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag - res->dma_resource[i].flags |= - dma_flags(type, bus_master, transfer); - if (dma == -1) { - res->dma_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->dma_resource[i].start = dma; - res->dma_resource[i].end = dma; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA " - "resources: %d \n", PNP_MAX_DMA); - warned = 1; - } -} - -static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res, - u64 io, u64 len, int io_decode) -{ - int i = 0; - static unsigned char warned; - - while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && - i < PNP_MAX_PORT) - i++; - if (i < PNP_MAX_PORT) { - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag - if (io_decode == ACPI_DECODE_16) - res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR; - if (len <= 0 || (io + len - 1) >= 0x10003) { - res->port_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->port_resource[i].start = io; - res->port_resource[i].end = io + len - 1; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of IO " - "resources: %d \n", PNP_MAX_PORT); - warned = 1; - } -} - -static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res, - u64 mem, u64 len, - int write_protect) -{ - int i = 0; - static unsigned char warned; - - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && - (i < PNP_MAX_MEM)) - i++; - if (i < PNP_MAX_MEM) { - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag - if (len <= 0) { - res->mem_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - if (write_protect == ACPI_READ_WRITE_MEMORY) - res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE; - - res->mem_resource[i].start = mem; - res->mem_resource[i].end = mem + len - 1; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of mem " - "resources: %d\n", PNP_MAX_MEM); - warned = 1; - } -} - -static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table, +static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, struct acpi_resource *res) { struct acpi_resource_address64 addr, *p = &addr; @@ -255,7 +161,7 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res status = acpi_resource_to_address64(res, p); if (!ACPI_SUCCESS(status)) { - pnp_warn("PnPACPI: failed to convert resource type %d", + dev_warn(&dev->dev, "failed to convert resource type %d\n", res->type); return; } @@ -264,20 +170,26 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res return; if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(res_table, - p->minimum, p->address_length, - p->info.mem.write_protect); + pnp_add_mem_resource(dev, p->minimum, p->address_length, + p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY ? + IORESOURCE_MEM_WRITEABLE : 0); else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(res_table, - p->minimum, p->address_length, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16); + pnp_add_io_resource(dev, p->minimum, p->address_length, + p->granularity == 0xfff ? 0 : PNP_PORT_FLAG_16BITADDR); } static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { - struct pnp_resource_table *res_table = data; + struct pnp_dev *dev = data; + struct acpi_resource_irq *irq; + struct acpi_resource_dma *dma; + struct acpi_resource_io *io; + struct acpi_resource_fixed_io *fixed_io; + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + struct acpi_resource_extended_irq *extended_irq; int i; switch (res->type) { @@ -286,29 +198,30 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, * Per spec, only one interrupt per descriptor is allowed in * _CRS, but some firmware violates this, so parse them all. */ - for (i = 0; i < res->data.irq.interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(res_table, - res->data.irq.interrupts[i], - res->data.irq.triggering, - res->data.irq.polarity, - res->data.irq.sharable); + irq = &res->data.irq; + for (i = 0; i < irq->interrupt_count; i++) { + pnpacpi_parse_allocated_irqresource(dev, + irq->interrupts[i], + irq->triggering, + irq->polarity, + irq->sharable); } break; case ACPI_RESOURCE_TYPE_DMA: - if (res->data.dma.channel_count > 0) - pnpacpi_parse_allocated_dmaresource(res_table, - res->data.dma.channels[0], - res->data.dma.type, - res->data.dma.bus_master, - res->data.dma.transfer); + dma = &res->data.dma; + if (dma->channel_count > 0) + pnp_add_dma_resource(dev, dma->channels[0], + dma_flags(dma->type, + dma->bus_master, + dma->transfer)); break; case ACPI_RESOURCE_TYPE_IO: - pnpacpi_parse_allocated_ioresource(res_table, - res->data.io.minimum, - res->data.io.address_length, - res->data.io.io_decode); + io = &res->data.io; + pnp_add_io_resource(dev, io->minimum, io->address_length, + io->io_decode == ACPI_DECODE_16 ? + PNP_PORT_FLAG_16BITADDR : 0); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -316,10 +229,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnpacpi_parse_allocated_ioresource(res_table, - res->data.fixed_io.address, - res->data.fixed_io.address_length, - ACPI_DECODE_10); + fixed_io = &res->data.fixed_io; + pnp_add_io_resource(dev, + fixed_io->address, + fixed_io->address_length, 0); break; case ACPI_RESOURCE_TYPE_VENDOR: @@ -329,27 +242,33 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnpacpi_parse_allocated_memresource(res_table, - res->data.memory24.minimum, - res->data.memory24.address_length, - res->data.memory24.write_protect); + memory24 = &res->data.memory24; + pnp_add_mem_resource(dev, + memory24->minimum, + memory24->address_length, + memory24->write_protect == ACPI_READ_WRITE_MEMORY ? + IORESOURCE_MEM_WRITEABLE : 0); break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnpacpi_parse_allocated_memresource(res_table, - res->data.memory32.minimum, - res->data.memory32.address_length, - res->data.memory32.write_protect); + memory32 = &res->data.memory32; + pnp_add_mem_resource(dev, + memory32->minimum, + memory32->address_length, + memory32->write_protect == ACPI_READ_WRITE_MEMORY ? + IORESOURCE_MEM_WRITEABLE : 0); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnpacpi_parse_allocated_memresource(res_table, - res->data.fixed_memory32.address, - res->data.fixed_memory32.address_length, - res->data.fixed_memory32.write_protect); + fixed_memory32 = &res->data.fixed_memory32; + pnp_add_mem_resource(dev, + fixed_memory32->address, + fixed_memory32->address_length, + fixed_memory32->write_protect == ACPI_READ_WRITE_MEMORY ? + IORESOURCE_MEM_WRITEABLE : 0); break; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_allocated_address_space(res_table, res); + pnpacpi_parse_allocated_address_space(dev, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: @@ -358,15 +277,16 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER) + extended_irq = &res->data.extended_irq; + if (extended_irq->producer_consumer == ACPI_PRODUCER) return AE_OK; - for (i = 0; i < res->data.extended_irq.interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(res_table, - res->data.extended_irq.interrupts[i], - res->data.extended_irq.triggering, - res->data.extended_irq.polarity, - res->data.extended_irq.sharable); + for (i = 0; i < extended_irq->interrupt_count; i++) { + pnpacpi_parse_allocated_irqresource(dev, + extended_irq->interrupts[i], + extended_irq->triggering, + extended_irq->polarity, + extended_irq->sharable); } break; @@ -374,21 +294,22 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; default: - pnp_warn("PnPACPI: unknown resource type %d", res->type); + dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", + res->type); return AE_ERROR; } return AE_OK; } -acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, - struct pnp_resource_table * res) +acpi_status pnpacpi_parse_allocated_resource(struct pnp_dev *dev) { - /* Blank the resource table values */ - pnp_init_resource_table(res); + acpi_handle handle = dev->data; + + pnp_init_resources(dev); return acpi_walk_resources(handle, METHOD_NAME__CRS, - pnpacpi_allocated_resource, res); + pnpacpi_allocated_resource, dev); } static __init void pnpacpi_parse_dma_option(struct pnp_option *option, @@ -426,7 +347,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_option *option, for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], irq->map); - irq->flags = irq_flags(p->triggering, p->polarity); + irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(option, irq); } @@ -446,7 +367,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option, for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], irq->map); - irq->flags = irq_flags(p->triggering, p->polarity); + irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(option, irq); } @@ -640,7 +561,8 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_END_DEPENDENT: /*only one EndDependentFn is allowed */ if (!parse_data->option_independent) { - pnp_warn("PnPACPI: more than one EndDependentFn"); + dev_warn(&dev->dev, "more than one EndDependentFn " + "in _PRS\n"); return AE_ERROR; } parse_data->option = parse_data->option_independent; @@ -689,16 +611,17 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, break; default: - pnp_warn("PnPACPI: unknown resource type %d", res->type); + dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", + res->type); return AE_ERROR; } return AE_OK; } -acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle, - struct pnp_dev *dev) +acpi_status __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) { + acpi_handle handle = dev->data; acpi_status status; struct acpipnp_parse_option_s parse_data; @@ -758,9 +681,10 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) return AE_OK; } -int pnpacpi_build_resource_template(acpi_handle handle, +int pnpacpi_build_resource_template(struct pnp_dev *dev, struct acpi_buffer *buffer) { + acpi_handle handle = dev->data; struct acpi_resource *resource; int res_cnt = 0; acpi_status status; @@ -768,7 +692,7 @@ int pnpacpi_build_resource_template(acpi_handle handle, status = acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_count_resources, &res_cnt); if (ACPI_FAILURE(status)) { - pnp_err("Evaluate _CRS failed"); + dev_err(&dev->dev, "can't evaluate _CRS\n"); return -EINVAL; } if (!res_cnt) @@ -777,13 +701,12 @@ int pnpacpi_build_resource_template(acpi_handle handle, buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); if (!buffer->pointer) return -ENOMEM; - pnp_dbg("Res cnt %d", res_cnt); resource = (struct acpi_resource *)buffer->pointer; status = acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_type_resources, &resource); if (ACPI_FAILURE(status)) { kfree(buffer->pointer); - pnp_err("Evaluate _CRS failed"); + dev_err(&dev->dev, "can't evaluate _CRS\n"); return -EINVAL; } /* resource will pointer the end resource now */ @@ -795,126 +718,139 @@ int pnpacpi_build_resource_template(acpi_handle handle, static void pnpacpi_encode_irq(struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_irq *irq = &resource->data.irq; int triggering, polarity; decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); - resource->data.irq.triggering = triggering; - resource->data.irq.polarity = polarity; + irq->triggering = triggering; + irq->polarity = polarity; if (triggering == ACPI_EDGE_SENSITIVE) - resource->data.irq.sharable = ACPI_EXCLUSIVE; + irq->sharable = ACPI_EXCLUSIVE; else - resource->data.irq.sharable = ACPI_SHARED; - resource->data.irq.interrupt_count = 1; - resource->data.irq.interrupts[0] = p->start; + irq->sharable = ACPI_SHARED; + irq->interrupt_count = 1; + irq->interrupts[0] = p->start; } static void pnpacpi_encode_ext_irq(struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; int triggering, polarity; decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); - resource->data.extended_irq.producer_consumer = ACPI_CONSUMER; - resource->data.extended_irq.triggering = triggering; - resource->data.extended_irq.polarity = polarity; + extended_irq->producer_consumer = ACPI_CONSUMER; + extended_irq->triggering = triggering; + extended_irq->polarity = polarity; if (triggering == ACPI_EDGE_SENSITIVE) - resource->data.irq.sharable = ACPI_EXCLUSIVE; + extended_irq->sharable = ACPI_EXCLUSIVE; else - resource->data.irq.sharable = ACPI_SHARED; - resource->data.extended_irq.interrupt_count = 1; - resource->data.extended_irq.interrupts[0] = p->start; + extended_irq->sharable = ACPI_SHARED; + extended_irq->interrupt_count = 1; + extended_irq->interrupts[0] = p->start; } static void pnpacpi_encode_dma(struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_dma *dma = &resource->data.dma; + /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { case IORESOURCE_DMA_TYPEA: - resource->data.dma.type = ACPI_TYPE_A; + dma->type = ACPI_TYPE_A; break; case IORESOURCE_DMA_TYPEB: - resource->data.dma.type = ACPI_TYPE_B; + dma->type = ACPI_TYPE_B; break; case IORESOURCE_DMA_TYPEF: - resource->data.dma.type = ACPI_TYPE_F; + dma->type = ACPI_TYPE_F; break; default: - resource->data.dma.type = ACPI_COMPATIBILITY; + dma->type = ACPI_COMPATIBILITY; } switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { case IORESOURCE_DMA_8BIT: - resource->data.dma.transfer = ACPI_TRANSFER_8; + dma->transfer = ACPI_TRANSFER_8; break; case IORESOURCE_DMA_8AND16BIT: - resource->data.dma.transfer = ACPI_TRANSFER_8_16; + dma->transfer = ACPI_TRANSFER_8_16; break; default: - resource->data.dma.transfer = ACPI_TRANSFER_16; + dma->transfer = ACPI_TRANSFER_16; } - resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); - resource->data.dma.channel_count = 1; - resource->data.dma.channels[0] = p->start; + dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); + dma->channel_count = 1; + dma->channels[0] = p->start; } static void pnpacpi_encode_io(struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_io *io = &resource->data.io; + /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */ - resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ? + io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ? ACPI_DECODE_16 : ACPI_DECODE_10; - resource->data.io.minimum = p->start; - resource->data.io.maximum = p->end; - resource->data.io.alignment = 0; /* Correct? */ - resource->data.io.address_length = p->end - p->start + 1; + io->minimum = p->start; + io->maximum = p->end; + io->alignment = 0; /* Correct? */ + io->address_length = p->end - p->start + 1; } static void pnpacpi_encode_fixed_io(struct acpi_resource *resource, struct resource *p) { - resource->data.fixed_io.address = p->start; - resource->data.fixed_io.address_length = p->end - p->start + 1; + struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; + + fixed_io->address = p->start; + fixed_io->address_length = p->end - p->start + 1; } static void pnpacpi_encode_mem24(struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_memory24 *memory24 = &resource->data.memory24; + /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */ - resource->data.memory24.write_protect = + memory24->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.memory24.minimum = p->start; - resource->data.memory24.maximum = p->end; - resource->data.memory24.alignment = 0; - resource->data.memory24.address_length = p->end - p->start + 1; + memory24->minimum = p->start; + memory24->maximum = p->end; + memory24->alignment = 0; + memory24->address_length = p->end - p->start + 1; } static void pnpacpi_encode_mem32(struct acpi_resource *resource, struct resource *p) { - resource->data.memory32.write_protect = + struct acpi_resource_memory32 *memory32 = &resource->data.memory32; + + memory32->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.memory32.minimum = p->start; - resource->data.memory32.maximum = p->end; - resource->data.memory32.alignment = 0; - resource->data.memory32.address_length = p->end - p->start + 1; + memory32->minimum = p->start; + memory32->maximum = p->end; + memory32->alignment = 0; + memory32->address_length = p->end - p->start + 1; } static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource, struct resource *p) { - resource->data.fixed_memory32.write_protect = + struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; + + fixed_memory32->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.fixed_memory32.address = p->start; - resource->data.fixed_memory32.address_length = p->end - p->start + 1; + fixed_memory32->address = p->start; + fixed_memory32->address_length = p->end - p->start + 1; } -int pnpacpi_encode_resources(struct pnp_resource_table *res_table, - struct acpi_buffer *buffer) +int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) { int i = 0; /* pnpacpi_build_resource_template allocates extra mem */ @@ -922,58 +858,47 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table, struct acpi_resource *resource = buffer->pointer; int port = 0, irq = 0, dma = 0, mem = 0; - pnp_dbg("res cnt %d", res_cnt); while (i < res_cnt) { switch (resource->type) { case ACPI_RESOURCE_TYPE_IRQ: - pnp_dbg("Encode irq"); pnpacpi_encode_irq(resource, - &res_table->irq_resource[irq]); + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case ACPI_RESOURCE_TYPE_DMA: - pnp_dbg("Encode dma"); pnpacpi_encode_dma(resource, - &res_table->dma_resource[dma]); + pnp_get_resource(dev, IORESOURCE_DMA, dma)); dma++; break; case ACPI_RESOURCE_TYPE_IO: - pnp_dbg("Encode io"); pnpacpi_encode_io(resource, - &res_table->port_resource[port]); + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnp_dbg("Encode fixed io"); pnpacpi_encode_fixed_io(resource, - &res_table-> - port_resource[port]); + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnp_dbg("Encode mem24"); pnpacpi_encode_mem24(resource, - &res_table->mem_resource[mem]); + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnp_dbg("Encode mem32"); pnpacpi_encode_mem32(resource, - &res_table->mem_resource[mem]); + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnp_dbg("Encode fixed mem32"); pnpacpi_encode_fixed_mem32(resource, - &res_table-> - mem_resource[mem]); + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - pnp_dbg("Encode ext irq"); pnpacpi_encode_ext_irq(resource, - &res_table->irq_resource[irq]); + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -986,7 +911,8 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table, case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: default: /* other type */ - pnp_warn("unknown resource type %d", resource->type); + dev_warn(&dev->dev, "can't encode unknown resource " + "type %d\n", resource->type); return -EINVAL; } resource++; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index a8a51500e1e9..63795aac2c49 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -69,6 +69,7 @@ #include <asm/system.h> #include <asm/byteorder.h> +#include "../base.h" #include "pnpbios.h" /* @@ -203,8 +204,7 @@ static int pnp_dock_thread(void *unused) #endif /* CONFIG_HOTPLUG */ -static int pnpbios_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpbios_get_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; struct pnp_bios_node *node; @@ -219,14 +219,13 @@ static int pnpbios_get_resources(struct pnp_dev *dev, kfree(node); return -ENODEV; } - pnpbios_read_resources_from_node(res, node); + pnpbios_read_resources_from_node(dev, node); dev->active = pnp_is_active(dev); kfree(node); return 0; } -static int pnpbios_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpbios_set_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; struct pnp_bios_node *node; @@ -242,7 +241,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev, kfree(node); return -ENODEV; } - if (pnpbios_write_resources_to_node(res, node) < 0) { + if (pnpbios_write_resources_to_node(dev, node) < 0) { kfree(node); return -1; } @@ -317,7 +316,6 @@ static int __init insert_device(struct pnp_bios_node *node) { struct list_head *pos; struct pnp_dev *dev; - struct pnp_id *dev_id; char id[8]; /* check if the device is already added */ @@ -327,20 +325,12 @@ static int __init insert_device(struct pnp_bios_node *node) return -1; } - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); - if (!dev) - return -1; + pnpid32_to_pnpid(node->eisa_id, id); - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) { - kfree(dev); - return -1; - } + dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id); + if (!dev) + return -ENOMEM; - dev->number = node->handle; - pnpid32_to_pnpid(node->eisa_id, id); - memcpy(dev_id->id, id, 7); - pnp_add_id(dev_id, dev); pnpbios_parse_data_stream(dev, node); dev->active = pnp_is_active(dev); dev->flags = node->flags; @@ -353,11 +343,10 @@ static int __init insert_device(struct pnp_bios_node *node) dev->capabilities |= PNP_WRITE; if (dev->flags & PNPBIOS_REMOVABLE) dev->capabilities |= PNP_REMOVABLE; - dev->protocol = &pnpbios_protocol; /* clear out the damaged flags */ if (!dev->active) - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); pnp_add_device(dev); pnpbios_interface_attach_device(node); diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h index d8cb2fd1f127..42343fc753ba 100644 --- a/drivers/pnp/pnpbios/pnpbios.h +++ b/drivers/pnp/pnpbios/pnpbios.h @@ -28,8 +28,8 @@ extern int pnp_bios_present(void); extern int pnpbios_dont_use_current_config; extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node); -extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node); -extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node); +extern int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node); +extern int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node); extern void pnpid32_to_pnpid(u32 id, char *str); extern void pnpbios_print_status(const char * module, u16 status); diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index caade3531416..eeade08aaa30 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -16,6 +16,7 @@ inline void pcibios_penalize_isa_irq(int irq, int active) } #endif /* CONFIG_PCI */ +#include "../base.h" #include "pnpbios.h" /* standard resource tags */ @@ -53,88 +54,9 @@ inline void pcibios_penalize_isa_irq(int irq, int active) * Allocated Resources */ -static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res, - int irq) -{ - int i = 0; - - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_IRQ) - i++; - if (i < PNP_MAX_IRQ) { - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag - if (irq == -1) { - res->irq_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->irq_resource[i].start = - res->irq_resource[i].end = (unsigned long)irq; - pcibios_penalize_isa_irq(irq, 1); - } -} - -static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res, - int dma) -{ - int i = 0; - - while (i < PNP_MAX_DMA && - !(res->dma_resource[i].flags & IORESOURCE_UNSET)) - i++; - if (i < PNP_MAX_DMA) { - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag - if (dma == -1) { - res->dma_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->dma_resource[i].start = - res->dma_resource[i].end = (unsigned long)dma; - } -} - -static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res, - int io, int len) -{ - int i = 0; - - while (!(res->port_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_PORT) - i++; - if (i < PNP_MAX_PORT) { - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag - if (len <= 0 || (io + len - 1) >= 0x10003) { - res->port_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->port_resource[i].start = (unsigned long)io; - res->port_resource[i].end = (unsigned long)(io + len - 1); - } -} - -static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res, - int mem, int len) -{ - int i = 0; - - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_MEM) - i++; - if (i < PNP_MAX_MEM) { - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag - if (len <= 0) { - res->mem_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->mem_resource[i].start = (unsigned long)mem; - res->mem_resource[i].end = (unsigned long)(mem + len - 1); - } -} - -static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, - unsigned char *end, - struct - pnp_resource_table - *res) +static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, + unsigned char *p, + unsigned char *end) { unsigned int len, tag; int io, size, mask, i; @@ -142,8 +64,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, if (!p) return NULL; - /* Blank the resource table values */ - pnp_init_resource_table(res); + pnp_init_resources(dev); while ((char *)p < (char *)end) { @@ -163,7 +84,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(short *)&p[4]; size = *(short *)&p[10]; - pnpbios_parse_allocated_memresource(res, io, size); + pnp_add_mem_resource(dev, io, size, 0); break; case LARGE_TAG_ANSISTR: @@ -179,7 +100,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(int *)&p[4]; size = *(int *)&p[16]; - pnpbios_parse_allocated_memresource(res, io, size); + pnp_add_mem_resource(dev, io, size, 0); break; case LARGE_TAG_FIXEDMEM32: @@ -187,7 +108,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(int *)&p[4]; size = *(int *)&p[8]; - pnpbios_parse_allocated_memresource(res, io, size); + pnp_add_mem_resource(dev, io, size, 0); break; case SMALL_TAG_IRQ: @@ -198,7 +119,8 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, for (i = 0; i < 16; i++, mask = mask >> 1) if (mask & 0x01) io = i; - pnpbios_parse_allocated_irqresource(res, io); + if (pnp_add_irq_resource(dev, io, 0) == 0) + pcibios_penalize_isa_irq(io, 1); break; case SMALL_TAG_DMA: @@ -209,7 +131,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, for (i = 0; i < 8; i++, mask = mask >> 1) if (mask & 0x01) io = i; - pnpbios_parse_allocated_dmaresource(res, io); + pnp_add_dma_resource(dev, io, 0); break; case SMALL_TAG_PORT: @@ -217,7 +139,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = p[2] + p[3] * 256; size = p[7]; - pnpbios_parse_allocated_ioresource(res, io, size); + pnp_add_io_resource(dev, io, size, 0); break; case SMALL_TAG_VENDOR: @@ -229,7 +151,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = p[1] + p[2] * 256; size = p[3]; - pnpbios_parse_allocated_ioresource(res, io, size); + pnp_add_io_resource(dev, io, size, 0); break; case SMALL_TAG_END: @@ -239,9 +161,8 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag 0x%x length %d\n", + tag, len); break; } @@ -252,8 +173,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -460,8 +380,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, if (len != 0) goto len_err; if (option_independent == option) - printk(KERN_WARNING - "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n"); + dev_warn(&dev->dev, "missing " + "SMALL_TAG_STARTDEP tag\n"); option = option_independent; break; @@ -470,9 +390,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag 0x%x length %d\n", + tag, len); break; } @@ -483,8 +402,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -548,13 +466,11 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, case SMALL_TAG_COMPATDEVID: /* compatible ID */ if (len != 4) goto len_err; - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) - return NULL; pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24, id); - memcpy(&dev_id->id, id, 7); - pnp_add_id(dev_id, dev); + dev_id = pnp_add_id(dev, id); + if (!dev_id) + return NULL; break; case SMALL_TAG_END: @@ -564,9 +480,8 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag 0x%x length %d\n", + tag, len); break; } @@ -577,8 +492,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -673,11 +587,10 @@ static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res) p[3] = len & 0xff; } -static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, - unsigned char *end, - struct - pnp_resource_table - *res) +static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev + *dev, + unsigned char *p, + unsigned char *end) { unsigned int len, tag; int port = 0, irq = 0, dma = 0, mem = 0; @@ -701,42 +614,48 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, case LARGE_TAG_MEM: if (len != 9) goto len_err; - pnpbios_encode_mem(p, &res->mem_resource[mem]); + pnpbios_encode_mem(p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; - pnpbios_encode_mem32(p, &res->mem_resource[mem]); + pnpbios_encode_mem32(p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; - pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]); + pnpbios_encode_fixed_mem32(p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; - pnpbios_encode_irq(p, &res->irq_resource[irq]); + pnpbios_encode_irq(p, + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case SMALL_TAG_DMA: if (len != 2) goto len_err; - pnpbios_encode_dma(p, &res->dma_resource[dma]); + pnpbios_encode_dma(p, + pnp_get_resource(dev, IORESOURCE_DMA, dma)); dma++; break; case SMALL_TAG_PORT: if (len != 7) goto len_err; - pnpbios_encode_port(p, &res->port_resource[port]); + pnpbios_encode_port(p, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; @@ -747,7 +666,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; - pnpbios_encode_fixed_port(p, &res->port_resource[port]); + pnpbios_encode_fixed_port(p, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; @@ -758,9 +678,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag 0x%x length %d\n", + tag, len); break; } @@ -771,8 +690,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -787,7 +705,7 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev, unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_parse_allocated_resource_data(p, end, &dev->res); + p = pnpbios_parse_allocated_resource_data(dev, p, end); if (!p) return -EIO; p = pnpbios_parse_resource_option_data(p, end, dev); @@ -799,25 +717,25 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev, return 0; } -int pnpbios_read_resources_from_node(struct pnp_resource_table *res, +int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node) { unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_parse_allocated_resource_data(p, end, res); + p = pnpbios_parse_allocated_resource_data(dev, p, end); if (!p) return -EIO; return 0; } -int pnpbios_write_resources_to_node(struct pnp_resource_table *res, +int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node) { unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_encode_allocated_resource_data(p, end, res); + p = pnpbios_encode_allocated_resource_data(dev, p, end); if (!p) return -EIO; return 0; diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 37993206ae5d..3f2d34a85ba3 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -114,6 +114,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) static void quirk_system_pci_resources(struct pnp_dev *dev) { struct pci_dev *pdev = NULL; + struct resource *res; resource_size_t pnp_start, pnp_end, pci_start, pci_end; int i, j; @@ -134,13 +135,15 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) pci_start = pci_resource_start(pdev, i); pci_end = pci_resource_end(pdev, i); - for (j = 0; j < PNP_MAX_MEM; j++) { - if (!pnp_mem_valid(dev, j) || - pnp_mem_len(dev, j) == 0) + for (j = 0; + (res = pnp_get_resource(dev, IORESOURCE_MEM, j)); + j++) { + if (res->flags & IORESOURCE_UNSET || + (res->start == 0 && res->end == 0)) continue; - pnp_start = pnp_mem_start(dev, j); - pnp_end = pnp_mem_end(dev, j); + pnp_start = res->start; + pnp_end = res->end; /* * If the PNP region doesn't overlap the PCI @@ -173,7 +176,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) pci_name(pdev), i, (unsigned long long) pci_start, (unsigned long long) pci_end); - pnp_mem_flags(dev, j) = 0; + res->flags = 0; } } } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index e50ebcffb962..454290b4b4f6 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -215,15 +215,18 @@ void pnp_free_option(struct pnp_option *option) int pnp_check_port(struct pnp_dev *dev, int idx) { - int tmp; + int i; + struct resource *res, *tres; struct pnp_dev *tdev; resource_size_t *port, *end, *tport, *tend; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; + res = pnp_get_resource(dev, IORESOURCE_IO, idx); + + port = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.port_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -234,18 +237,20 @@ int pnp_check_port(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int rport = pnp_reserve_io[tmp << 1]; - int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; + for (i = 0; i < 8; i++) { + int rport = pnp_reserve_io[i << 1]; + int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1; if (ranged_conflict(port, end, &rport, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) { - if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &dev->res.port_resource[tmp].start; - tend = &dev->res.port_resource[tmp].end; + for (i = 0; + i != idx && (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); + i++) { + if (tres->flags & IORESOURCE_IO) { + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -255,13 +260,14 @@ int pnp_check_port(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - if (cannot_compare - (tdev->res.port_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); + i++) { + if (tres->flags & IORESOURCE_IO) { + if (cannot_compare(tres->flags)) continue; - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -273,15 +279,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx) int pnp_check_mem(struct pnp_dev *dev, int idx) { - int tmp; + int i; + struct resource *res, *tres; struct pnp_dev *tdev; resource_size_t *addr, *end, *taddr, *tend; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; + res = pnp_get_resource(dev, IORESOURCE_MEM, idx); + + addr = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.mem_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -292,18 +301,20 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int raddr = pnp_reserve_mem[tmp << 1]; - int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; + for (i = 0; i < 8; i++) { + int raddr = pnp_reserve_mem[i << 1]; + int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1; if (ranged_conflict(addr, end, &raddr, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) { - if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &dev->res.mem_resource[tmp].start; - tend = &dev->res.mem_resource[tmp].end; + for (i = 0; + i != idx && (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); + i++) { + if (tres->flags & IORESOURCE_MEM) { + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -313,13 +324,14 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - if (cannot_compare - (tdev->res.mem_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); + i++) { + if (tres->flags & IORESOURCE_MEM) { + if (cannot_compare(tres->flags)) continue; - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -336,12 +348,17 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id) int pnp_check_irq(struct pnp_dev *dev, int idx) { - int tmp; + int i; + struct resource *res, *tres; struct pnp_dev *tdev; - resource_size_t *irq = &dev->res.irq_resource[idx].start; + resource_size_t *irq; + + res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); + + irq = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.irq_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -349,15 +366,17 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 16; tmp++) { - if (pnp_reserve_irq[tmp] == *irq) + for (i = 0; i < 16; i++) { + if (pnp_reserve_irq[i] == *irq) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { - if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (dev->res.irq_resource[tmp].start == *irq) + for (i = 0; + i != idx && (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); + i++) { + if (tres->flags & IORESOURCE_IRQ) { + if (tres->start == *irq) return 0; } } @@ -388,12 +407,13 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (cannot_compare - (tdev->res.irq_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); + i++) { + if (tres->flags & IORESOURCE_IRQ) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.irq_resource[tmp].start == *irq)) + if (tres->start == *irq) return 0; } } @@ -405,12 +425,17 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) int pnp_check_dma(struct pnp_dev *dev, int idx) { #ifndef CONFIG_IA64 - int tmp; + int i; + struct resource *res, *tres; struct pnp_dev *tdev; - resource_size_t *dma = &dev->res.dma_resource[idx].start; + resource_size_t *dma; + + res = pnp_get_resource(dev, IORESOURCE_DMA, idx); + + dma = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.dma_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -418,15 +443,17 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - if (pnp_reserve_dma[tmp] == *dma) + for (i = 0; i < 8; i++) { + if (pnp_reserve_dma[i] == *dma) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { - if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (dev->res.dma_resource[tmp].start == *dma) + for (i = 0; + i != idx && (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); + i++) { + if (tres->flags & IORESOURCE_DMA) { + if (tres->start == *dma) return 0; } } @@ -443,12 +470,13 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (cannot_compare - (tdev->res.dma_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); + i++) { + if (tres->flags & IORESOURCE_DMA) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.dma_resource[tmp].start == *dma)) + if (tres->start == *dma) return 0; } } @@ -461,6 +489,132 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) #endif } +#define set(flags) ((flags & IORESOURCE_UNSET) == 0) + +int pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags) +{ + struct pnp_resource_table *res = dev->res; + int i = 0; + static unsigned char warned; + + while (set(res->irq_resource[i].flags) && i < PNP_MAX_IRQ) + i++; + if (i >= PNP_MAX_IRQ && !warned) { + dev_err(&dev->dev, "too many IRQs (max %d)\n", PNP_MAX_IRQ); + warned = 1; + return -ENOSPC; + } + + res->irq_resource[i].flags = IORESOURCE_IRQ | flags; + if (irq < 0) { + res->irq_resource[i].flags |= IORESOURCE_DISABLED; + return -EINVAL; + } + res->irq_resource[i].start = irq; + res->irq_resource[i].end = irq; + return 0; +} + +int pnp_add_dma_resource(struct pnp_dev *dev, int dma, int flags) +{ + struct pnp_resource_table *res = dev->res; + int i = 0; + static unsigned char warned; + + while (set(res->dma_resource[i].flags) && i < PNP_MAX_DMA) + i++; + if (i >= PNP_MAX_DMA && !warned) { + dev_err(&dev->dev, "too many DMAs (max %d)\n", PNP_MAX_DMA); + warned = 1; + return -ENOSPC; + } + + res->dma_resource[i].flags = IORESOURCE_DMA | flags; + if (dma < 0) { + res->dma_resource[i].flags |= IORESOURCE_DISABLED; + return -EINVAL; + } + res->dma_resource[i].start = dma; + res->dma_resource[i].end = dma; + return 0; +} + +int pnp_add_io_resource(struct pnp_dev *dev, resource_size_t start, resource_size_t len, int flags) +{ + struct pnp_resource_table *res = dev->res; + resource_size_t end = start + len - 1; + int i = 0; + static unsigned char warned; + + while (set(res->port_resource[i].flags) && i < PNP_MAX_PORT) + i++; + if (i >= PNP_MAX_PORT && !warned) { + dev_err(&dev->dev, "too many PORTs (max %d)\n", PNP_MAX_PORT); + warned = 1; + return -ENOSPC; + } + + res->port_resource[i].flags = IORESOURCE_IO | flags; + if (len <= 0 || end >= 0x10003) { + res->port_resource[i].flags |= IORESOURCE_DISABLED; + return -EINVAL; + } + res->port_resource[i].start = start; + res->port_resource[i].end = end; + return 0; +} + +int pnp_add_mem_resource(struct pnp_dev *dev, resource_size_t start, resource_size_t len, int flags) +{ + struct pnp_resource_table *res = dev->res; + int i = 0; + static unsigned char warned; + + while (set(res->mem_resource[i].flags) && i < PNP_MAX_MEM) + i++; + if (i >= PNP_MAX_MEM && !warned) { + dev_err(&dev->dev, "too many MEMs (max %d)\n", PNP_MAX_MEM); + warned = 1; + return -ENOSPC; + } + + res->mem_resource[i].flags = IORESOURCE_MEM | flags; + if (len <= 0) { + res->mem_resource[i].flags |= IORESOURCE_DISABLED; + return -EINVAL; + } + res->mem_resource[i].start = start; + res->mem_resource[i].end = start + len - 1; + return 0; +} + +struct resource *pnp_get_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num) +{ + struct pnp_resource_table *res = dev->res; + + switch (type) { + case IORESOURCE_IO: + if (num >= PNP_MAX_PORT) + return NULL; + return &res->port_resource[num]; + case IORESOURCE_MEM: + if (num >= PNP_MAX_MEM) + return NULL; + return &res->mem_resource[num]; + case IORESOURCE_IRQ: + if (num >= PNP_MAX_IRQ) + return NULL; + return &res->irq_resource[num]; + case IORESOURCE_DMA: + if (num >= PNP_MAX_DMA) + return NULL; + return &res->dma_resource[num]; + } + return NULL; +} +EXPORT_SYMBOL(pnp_get_resource); + /* format is: pnp_reserve_irq=irq1[,irq2] .... */ static int __init pnp_setup_reserve_irq(char *str) { diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 55c4563986b3..9c2496dbeee4 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -56,14 +56,15 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start, static void reserve_resources_of_dev(struct pnp_dev *dev) { + struct resource *res; int i; - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_port_valid(dev, i)) + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (res->flags & IORESOURCE_UNSET) continue; - if (pnp_port_start(dev, i) == 0) + if (res->start == 0) continue; /* disabled */ - if (pnp_port_start(dev, i) < 0x100) + if (res->start < 0x100) /* * Below 0x100 is only standard PC hardware * (pics, kbd, timer, dma, ...) @@ -73,19 +74,17 @@ static void reserve_resources_of_dev(struct pnp_dev *dev) * So, do nothing */ continue; - if (pnp_port_end(dev, i) < pnp_port_start(dev, i)) + if (res->end < res->start) continue; /* invalid */ - reserve_range(dev, pnp_port_start(dev, i), - pnp_port_end(dev, i), 1); + reserve_range(dev, res->start, res->end, 1); } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_mem_valid(dev, i)) + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (res->flags & IORESOURCE_UNSET) continue; - reserve_range(dev, pnp_mem_start(dev, i), - pnp_mem_end(dev, i), 0); + reserve_range(dev, res->start, res->end, 0); } } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f3ee2ad566b4..f7d8b2c99615 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -855,11 +855,12 @@ cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) * don't define the IRQ. It should always be safe to * hardcode it in these cases */ - return cmos_do_probe(&pnp->dev, &pnp->res.port_resource[0], 8); + return cmos_do_probe(&pnp->dev, + pnp_get_resource(pnp, IORESOURCE_IO, 0), 8); else return cmos_do_probe(&pnp->dev, - &pnp->res.port_resource[0], - pnp->res.irq_resource[0].start); + pnp_get_resource(pnp, IORESOURCE_IO, 0), + pnp_irq(pnp, 0)); } static void __exit cmos_pnp_remove(struct pnp_dev *pnp) diff --git a/include/asm-x86/smp_64.h b/include/asm-x86/smp_64.h index e0a75519ad21..2e2445649f9c 100644 --- a/include/asm-x86/smp_64.h +++ b/include/asm-x86/smp_64.h @@ -47,8 +47,6 @@ static inline int cpu_present_to_apicid(int mps_cpu) #ifdef CONFIG_SMP -#define SMP_TRAMPOLINE_BASE 0x6000 - extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); extern void prefill_possible_map(void); diff --git a/include/asm-x86/trampoline.h b/include/asm-x86/trampoline.h new file mode 100644 index 000000000000..d1c18d74c620 --- /dev/null +++ b/include/asm-x86/trampoline.h @@ -0,0 +1,18 @@ +#ifndef __TRAMPOLINE_HEADER +#define __TRAMPOLINE_HEADER + +#ifndef __ASSEMBLY__ + +#define TRAMPOLINE_BASE 0x6000 + +/* + * Trampoline 80x86 program as an array. + */ +extern const unsigned char trampoline_data[]; +extern const unsigned char trampoline_end[]; + +extern unsigned long setup_trampoline(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* __TRAMPOLINE_HEADER */ diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h index 1e8728a9ee8a..cd5a269fdb5e 100644 --- a/include/linux/isapnp.h +++ b/include/linux/isapnp.h @@ -26,16 +26,6 @@ #include <linux/pnp.h> /* - * Configuration registers (TODO: change by specification) - */ - -#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */ -#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */ -#define ISAPNP_CFG_PORT 0x60 /* 8 * word */ -#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */ -#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */ - -/* * */ diff --git a/include/linux/pnp.h b/include/linux/pnp.h index 29dd55838e84..3325e0bcd9c6 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -13,26 +13,36 @@ #include <linux/errno.h> #include <linux/mod_devicetable.h> -#define PNP_MAX_PORT 40 -#define PNP_MAX_MEM 24 -#define PNP_MAX_IRQ 2 -#define PNP_MAX_DMA 2 #define PNP_NAME_LEN 50 struct pnp_protocol; struct pnp_dev; +struct pnp_resource_table; /* * Resource Management */ +struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int); /* Use these instead of directly reading pnp_dev to get resource information */ -#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start) -#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end) -#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags) -#define pnp_port_valid(dev,bar) \ - ((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \ - == IORESOURCE_IO) + +#define pnp_port_start(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_IO, bar)->start +#define pnp_port_end(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_IO, bar)->end +#define pnp_port_flags(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_IO, bar)->flags + +static inline resource_size_t pnp_port_valid(struct pnp_dev *dev, + unsigned int bar) +{ + struct resource *res = pnp_get_resource(dev, IORESOURCE_IO, bar); + + if (res && !(res->flags & IORESOURCE_UNSET)) + return 1; + return 0; +} + #define pnp_port_len(dev,bar) \ ((pnp_port_start((dev),(bar)) == 0 && \ pnp_port_end((dev),(bar)) == \ @@ -41,12 +51,23 @@ struct pnp_dev; (pnp_port_end((dev),(bar)) - \ pnp_port_start((dev),(bar)) + 1)) -#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start) -#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end) -#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags) -#define pnp_mem_valid(dev,bar) \ - ((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \ - == IORESOURCE_MEM) +#define pnp_mem_start(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_MEM, bar)->start +#define pnp_mem_end(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_MEM, bar)->end +#define pnp_mem_flags(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_MEM, bar)->flags + +static inline resource_size_t pnp_mem_valid(struct pnp_dev *dev, + unsigned int bar) +{ + struct resource *res = pnp_get_resource(dev, IORESOURCE_MEM, bar); + + if (res && !(res->flags & IORESOURCE_UNSET)) + return 1; + return 0; +} + #define pnp_mem_len(dev,bar) \ ((pnp_mem_start((dev),(bar)) == 0 && \ pnp_mem_end((dev),(bar)) == \ @@ -55,17 +76,35 @@ struct pnp_dev; (pnp_mem_end((dev),(bar)) - \ pnp_mem_start((dev),(bar)) + 1)) -#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start) -#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags) -#define pnp_irq_valid(dev,bar) \ - ((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \ - == IORESOURCE_IRQ) +#define pnp_irq(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_IRQ, bar)->start +#define pnp_irq_flags(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_IRQ, bar)->flags -#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start) -#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags) -#define pnp_dma_valid(dev,bar) \ - ((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \ - == IORESOURCE_DMA) +static inline resource_size_t pnp_irq_valid(struct pnp_dev *dev, + unsigned int bar) +{ + struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar); + + if (res && !(res->flags & IORESOURCE_UNSET)) + return 1; + return 0; +} + +#define pnp_dma(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_DMA, bar)->start +#define pnp_dma_flags(dev,bar) \ + pnp_get_resource(dev, IORESOURCE_DMA, bar)->flags + +static inline resource_size_t pnp_dma_valid(struct pnp_dev *dev, + unsigned int bar) +{ + struct resource *res = pnp_get_resource(dev, IORESOURCE_DMA, bar); + + if (res && !(res->flags & IORESOURCE_UNSET)) + return 1; + return 0; +} #define PNP_PORT_FLAG_16BITADDR (1<<0) #define PNP_PORT_FLAG_FIXED (1<<1) @@ -118,13 +157,6 @@ struct pnp_option { struct pnp_option *next; /* used to chain dependent resources */ }; -struct pnp_resource_table { - struct resource port_resource[PNP_MAX_PORT]; - struct resource mem_resource[PNP_MAX_MEM]; - struct resource dma_resource[PNP_MAX_DMA]; - struct resource irq_resource[PNP_MAX_IRQ]; -}; - /* * Device Management */ @@ -194,7 +226,7 @@ struct pnp_dev { int capabilities; struct pnp_option *independent; struct pnp_option *dependent; - struct pnp_resource_table res; + struct pnp_resource_table *res; char name[PNP_NAME_LEN]; /* contains a human-readable name */ unsigned short regs; /* ISAPnP: supported registers */ @@ -328,8 +360,8 @@ struct pnp_protocol { char *name; /* resource control functions */ - int (*get) (struct pnp_dev *dev, struct pnp_resource_table *res); - int (*set) (struct pnp_dev *dev, struct pnp_resource_table *res); + int (*get) (struct pnp_dev *dev); + int (*set) (struct pnp_dev *dev); int (*disable) (struct pnp_dev *dev); /* protocol specific suspend/resume */ @@ -358,20 +390,12 @@ extern struct bus_type pnp_bus_type; #if defined(CONFIG_PNP) /* device management */ -int pnp_register_protocol(struct pnp_protocol *protocol); -void pnp_unregister_protocol(struct pnp_protocol *protocol); -int pnp_add_device(struct pnp_dev *dev); int pnp_device_attach(struct pnp_dev *pnp_dev); void pnp_device_detach(struct pnp_dev *pnp_dev); extern struct list_head pnp_global; extern int pnp_platform_devices; /* multidevice card support */ -int pnp_add_card(struct pnp_card *card); -void pnp_remove_card(struct pnp_card *card); -int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); -void pnp_remove_card_device(struct pnp_dev *dev); -int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card); struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, const char *id, struct pnp_dev *from); void pnp_release_card_device(struct pnp_dev *dev); @@ -380,77 +404,42 @@ void pnp_unregister_card_driver(struct pnp_card_driver *drv); extern struct list_head pnp_cards; /* resource management */ -struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); -struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, - int priority); -int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data); -int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data); -int pnp_register_port_resource(struct pnp_option *option, - struct pnp_port *data); -int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data); -void pnp_init_resource_table(struct pnp_resource_table *table); -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, - int mode); int pnp_auto_config_dev(struct pnp_dev *dev); -int pnp_validate_config(struct pnp_dev *dev); int pnp_start_dev(struct pnp_dev *dev); int pnp_stop_dev(struct pnp_dev *dev); int pnp_activate_dev(struct pnp_dev *dev); int pnp_disable_dev(struct pnp_dev *dev); -void pnp_resource_change(struct resource *resource, resource_size_t start, - resource_size_t size); /* protocol helpers */ int pnp_is_active(struct pnp_dev *dev); int compare_pnp_id(struct pnp_id *pos, const char *id); -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); int pnp_register_driver(struct pnp_driver *drv); void pnp_unregister_driver(struct pnp_driver *drv); #else /* device management */ -static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; } -static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } -static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { } #define pnp_platform_devices 0 /* multidevice card support */ -static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; } -static inline void pnp_remove_card(struct pnp_card *card) { } -static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_remove_card_device(struct pnp_dev *dev) { } -static inline int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card) { return -ENODEV; } static inline struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, const char *id, struct pnp_dev *from) { return NULL; } static inline void pnp_release_card_device(struct pnp_dev *dev) { } static inline int pnp_register_card_driver(struct pnp_card_driver *drv) { return -ENODEV; } static inline void pnp_unregister_card_driver(struct pnp_card_driver *drv) { } /* resource management */ -static inline struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) { return NULL; } -static inline struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; } -static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; } -static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; } -static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; } -static inline void pnp_init_resource_table(struct pnp_resource_table *table) { } -static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; } static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { } /* protocol helpers */ static inline int pnp_is_active(struct pnp_dev *dev) { return 0; } static inline int compare_pnp_id(struct pnp_id *pos, const char *id) { return -ENODEV; } -static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } static inline void pnp_unregister_driver(struct pnp_driver *drv) { } diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 6233f3b4ae66..b45da40e8d25 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -19,16 +19,6 @@ config PM will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. -config PM_LEGACY - bool "Legacy Power Management API (DEPRECATED)" - depends on PM - default n - ---help--- - Support for pm_register() and friends. This old API is obsoleted - by the driver model. - - If unsure, say N. - config PM_DEBUG bool "Power Management Debug Support" depends on PM diff --git a/kernel/power/Makefile b/kernel/power/Makefile index f7dfff28ecdb..597823b5b700 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -4,7 +4,6 @@ EXTRA_CFLAGS += -DDEBUG endif obj-y := main.o -obj-$(CONFIG_PM_LEGACY) += pm.o obj-$(CONFIG_PM_SLEEP) += process.o console.o obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o diff --git a/kernel/power/pm.c b/kernel/power/pm.c deleted file mode 100644 index 60c73fa670d5..000000000000 --- a/kernel/power/pm.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * pm.c - Power management interface - * - * Copyright (C) 2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/pm.h> -#include <linux/pm_legacy.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> - -/* - * Locking notes: - * pm_devs_lock can be a semaphore providing pm ops are not called - * from an interrupt handler (already a bad idea so no change here). Each - * change must be protected so that an unlink of an entry doesn't clash - * with a pm send - which is permitted to sleep in the current architecture - * - * Module unloads clashing with pm events now work out safely, the module - * unload path will block until the event has been sent. It may well block - * until a resume but that will be fine. - */ - -static DEFINE_MUTEX(pm_devs_lock); -static LIST_HEAD(pm_devs); - -/** - * pm_register - register a device with power management - * @type: device type - * @id: device ID - * @callback: callback function - * - * Add a device to the list of devices that wish to be notified about - * power management events. A &pm_dev structure is returned on success, - * on failure the return is %NULL. - * - * The callback function will be called in process context and - * it may sleep. - */ - -struct pm_dev *pm_register(pm_dev_t type, - unsigned long id, - pm_callback callback) -{ - struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL); - if (dev) { - dev->type = type; - dev->id = id; - dev->callback = callback; - - mutex_lock(&pm_devs_lock); - list_add(&dev->entry, &pm_devs); - mutex_unlock(&pm_devs_lock); - } - return dev; -} - -/** - * pm_send - send request to a single device - * @dev: device to send to - * @rqst: power management request - * @data: data for the callback - * - * Issue a power management request to a given device. The - * %PM_SUSPEND and %PM_RESUME events are handled specially. The - * data field must hold the intended next state. No call is made - * if the state matches. - * - * BUGS: what stops two power management requests occurring in parallel - * and conflicting. - * - * WARNING: Calling pm_send directly is not generally recommended, in - * particular there is no locking against the pm_dev going away. The - * caller must maintain all needed locking or have 'inside knowledge' - * on the safety. Also remember that this function is not locked against - * pm_unregister. This means that you must handle SMP races on callback - * execution and unload yourself. - */ - -static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - int status = 0; - unsigned long prev_state, next_state; - - if (in_interrupt()) - BUG(); - - switch (rqst) { - case PM_SUSPEND: - case PM_RESUME: - prev_state = dev->state; - next_state = (unsigned long) data; - if (prev_state != next_state) { - if (dev->callback) - status = (*dev->callback)(dev, rqst, data); - if (!status) { - dev->state = next_state; - dev->prev_state = prev_state; - } - } - else { - dev->prev_state = prev_state; - } - break; - default: - if (dev->callback) - status = (*dev->callback)(dev, rqst, data); - break; - } - return status; -} - -/* - * Undo incomplete request - */ -static void pm_undo_all(struct pm_dev *last) -{ - struct list_head *entry = last->entry.prev; - while (entry != &pm_devs) { - struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); - if (dev->state != dev->prev_state) { - /* previous state was zero (running) resume or - * previous state was non-zero (suspended) suspend - */ - pm_request_t undo = (dev->prev_state - ? PM_SUSPEND:PM_RESUME); - pm_send(dev, undo, (void*) dev->prev_state); - } - entry = entry->prev; - } -} - -/** - * pm_send_all - send request to all managed devices - * @rqst: power management request - * @data: data for the callback - * - * Issue a power management request to a all devices. The - * %PM_SUSPEND events are handled specially. Any device is - * permitted to fail a suspend by returning a non zero (error) - * value from its callback function. If any device vetoes a - * suspend request then all other devices that have suspended - * during the processing of this request are restored to their - * previous state. - * - * WARNING: This function takes the pm_devs_lock. The lock is not dropped until - * the callbacks have completed. This prevents races against pm locking - * functions, races against module unload pm_unregister code. It does - * mean however that you must not issue pm_ functions within the callback - * or you will deadlock and users will hate you. - * - * Zero is returned on success. If a suspend fails then the status - * from the device that vetoes the suspend is returned. - * - * BUGS: what stops two power management requests occurring in parallel - * and conflicting. - */ - -int pm_send_all(pm_request_t rqst, void *data) -{ - struct list_head *entry; - - mutex_lock(&pm_devs_lock); - entry = pm_devs.next; - while (entry != &pm_devs) { - struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); - if (dev->callback) { - int status = pm_send(dev, rqst, data); - if (status) { - /* return devices to previous state on - * failed suspend request - */ - if (rqst == PM_SUSPEND) - pm_undo_all(dev); - mutex_unlock(&pm_devs_lock); - return status; - } - } - entry = entry->next; - } - mutex_unlock(&pm_devs_lock); - return 0; -} - -EXPORT_SYMBOL(pm_register); -EXPORT_SYMBOL(pm_send_all); - |