diff options
90 files changed, 3874 insertions, 2968 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7b44e492cf68..da13d6d1b2b0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -610,6 +610,29 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 610 | See drivers/char/README.epca and | 610 | See drivers/char/README.epca and |
| 611 | Documentation/digiepca.txt. | 611 | Documentation/digiepca.txt. |
| 612 | 612 | ||
| 613 | disable_mtrr_cleanup [X86] | ||
| 614 | enable_mtrr_cleanup [X86] | ||
| 615 | The kernel tries to adjust MTRR layout from continuous | ||
| 616 | to discrete, to make X server driver able to add WB | ||
| 617 | entry later. This parameter enables/disables that. | ||
| 618 | |||
| 619 | mtrr_chunk_size=nn[KMG] [X86] | ||
| 620 | used for mtrr cleanup. It is largest continous chunk | ||
| 621 | that could hold holes aka. UC entries. | ||
| 622 | |||
| 623 | mtrr_gran_size=nn[KMG] [X86] | ||
| 624 | Used for mtrr cleanup. It is granularity of mtrr block. | ||
| 625 | Default is 1. | ||
| 626 | Large value could prevent small alignment from | ||
| 627 | using up MTRRs. | ||
| 628 | |||
| 629 | mtrr_spare_reg_nr=n [X86] | ||
| 630 | Format: <integer> | ||
| 631 | Range: 0,7 : spare reg number | ||
| 632 | Default : 1 | ||
| 633 | Used for mtrr cleanup. It is spare mtrr entries number. | ||
| 634 | Set to 2 or more if your graphical card needs more. | ||
| 635 | |||
| 613 | disable_mtrr_trim [X86, Intel and AMD only] | 636 | disable_mtrr_trim [X86, Intel and AMD only] |
| 614 | By default the kernel will trim any uncacheable | 637 | By default the kernel will trim any uncacheable |
| 615 | memory out of your available memory pool based on | 638 | memory out of your available memory pool based on |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7dc46ba26fbf..640dc62a7fa0 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -230,6 +230,27 @@ config SMP | |||
| 230 | 230 | ||
| 231 | If you don't know what to do here, say N. | 231 | If you don't know what to do here, say N. |
| 232 | 232 | ||
| 233 | config X86_FIND_SMP_CONFIG | ||
| 234 | def_bool y | ||
| 235 | depends on X86_MPPARSE || X86_VOYAGER || X86_VISWS | ||
| 236 | depends on X86_32 | ||
| 237 | |||
| 238 | if ACPI | ||
| 239 | config X86_MPPARSE | ||
| 240 | def_bool y | ||
| 241 | bool "Enable MPS table" | ||
| 242 | depends on X86_LOCAL_APIC && !X86_VISWS | ||
| 243 | help | ||
| 244 | For old smp systems that do not have proper acpi support. Newer systems | ||
| 245 | (esp with 64bit cpus) with acpi support, MADT and DSDT will override it | ||
| 246 | endif | ||
| 247 | |||
| 248 | if !ACPI | ||
| 249 | config X86_MPPARSE | ||
| 250 | def_bool y | ||
| 251 | depends on X86_LOCAL_APIC && !X86_VISWS | ||
| 252 | endif | ||
| 253 | |||
| 233 | choice | 254 | choice |
| 234 | prompt "Subarchitecture Type" | 255 | prompt "Subarchitecture Type" |
| 235 | default X86_PC | 256 | default X86_PC |
| @@ -261,36 +282,6 @@ config X86_VOYAGER | |||
| 261 | If you do not specifically know you have a Voyager based machine, | 282 | If you do not specifically know you have a Voyager based machine, |
| 262 | say N here, otherwise the kernel you build will not be bootable. | 283 | say N here, otherwise the kernel you build will not be bootable. |
| 263 | 284 | ||
| 264 | config X86_NUMAQ | ||
| 265 | bool "NUMAQ (IBM/Sequent)" | ||
| 266 | depends on SMP && X86_32 && PCI | ||
| 267 | select NUMA | ||
| 268 | help | ||
| 269 | This option is used for getting Linux to run on a (IBM/Sequent) NUMA | ||
| 270 | multiquad box. This changes the way that processors are bootstrapped, | ||
| 271 | and uses Clustered Logical APIC addressing mode instead of Flat Logical. | ||
| 272 | You will need a new lynxer.elf file to flash your firmware with - send | ||
| 273 | email to <Martin.Bligh@us.ibm.com>. | ||
| 274 | |||
| 275 | config X86_SUMMIT | ||
| 276 | bool "Summit/EXA (IBM x440)" | ||
| 277 | depends on X86_32 && SMP | ||
| 278 | help | ||
| 279 | This option is needed for IBM systems that use the Summit/EXA chipset. | ||
| 280 | In particular, it is needed for the x440. | ||
| 281 | |||
| 282 | If you don't have one of these computers, you should say N here. | ||
| 283 | If you want to build a NUMA kernel, you must select ACPI. | ||
| 284 | |||
| 285 | config X86_BIGSMP | ||
| 286 | bool "Support for other sub-arch SMP systems with more than 8 CPUs" | ||
| 287 | depends on X86_32 && SMP | ||
| 288 | help | ||
| 289 | This option is needed for the systems that have more than 8 CPUs | ||
| 290 | and if the system is not of any sub-arch type above. | ||
| 291 | |||
| 292 | If you don't have such a system, you should say N here. | ||
| 293 | |||
| 294 | config X86_VISWS | 285 | config X86_VISWS |
| 295 | bool "SGI 320/540 (Visual Workstation)" | 286 | bool "SGI 320/540 (Visual Workstation)" |
| 296 | depends on X86_32 && !PCI | 287 | depends on X86_32 && !PCI |
| @@ -304,12 +295,33 @@ config X86_VISWS | |||
| 304 | and vice versa. See <file:Documentation/sgi-visws.txt> for details. | 295 | and vice versa. See <file:Documentation/sgi-visws.txt> for details. |
| 305 | 296 | ||
| 306 | config X86_GENERICARCH | 297 | config X86_GENERICARCH |
| 307 | bool "Generic architecture (Summit, bigsmp, ES7000, default)" | 298 | bool "Generic architecture" |
| 308 | depends on X86_32 | 299 | depends on X86_32 |
| 309 | help | 300 | help |
| 310 | This option compiles in the Summit, bigsmp, ES7000, default subarchitectures. | 301 | This option compiles in the NUMAQ, Summit, bigsmp, ES7000, default |
| 311 | It is intended for a generic binary kernel. | 302 | subarchitectures. It is intended for a generic binary kernel. |
| 312 | If you want a NUMA kernel, select ACPI. We need SRAT for NUMA. | 303 | if you select them all, kernel will probe it one by one. and will |
| 304 | fallback to default. | ||
| 305 | |||
| 306 | if X86_GENERICARCH | ||
| 307 | |||
| 308 | config X86_NUMAQ | ||
| 309 | bool "NUMAQ (IBM/Sequent)" | ||
| 310 | depends on SMP && X86_32 && PCI && X86_MPPARSE | ||
| 311 | select NUMA | ||
| 312 | help | ||
| 313 | This option is used for getting Linux to run on a NUMAQ (IBM/Sequent) | ||
| 314 | NUMA multiquad box. This changes the way that processors are | ||
| 315 | bootstrapped, and uses Clustered Logical APIC addressing mode instead | ||
| 316 | of Flat Logical. You will need a new lynxer.elf file to flash your | ||
| 317 | firmware with - send email to <Martin.Bligh@us.ibm.com>. | ||
| 318 | |||
| 319 | config X86_SUMMIT | ||
| 320 | bool "Summit/EXA (IBM x440)" | ||
| 321 | depends on X86_32 && SMP | ||
| 322 | help | ||
| 323 | This option is needed for IBM systems that use the Summit/EXA chipset. | ||
| 324 | In particular, it is needed for the x440. | ||
| 313 | 325 | ||
| 314 | config X86_ES7000 | 326 | config X86_ES7000 |
| 315 | bool "Support for Unisys ES7000 IA32 series" | 327 | bool "Support for Unisys ES7000 IA32 series" |
| @@ -317,8 +329,15 @@ config X86_ES7000 | |||
| 317 | help | 329 | help |
| 318 | Support for Unisys ES7000 systems. Say 'Y' here if this kernel is | 330 | Support for Unisys ES7000 systems. Say 'Y' here if this kernel is |
| 319 | supposed to run on an IA32-based Unisys ES7000 system. | 331 | supposed to run on an IA32-based Unisys ES7000 system. |
| 320 | Only choose this option if you have such a system, otherwise you | 332 | |
| 321 | should say N here. | 333 | config X86_BIGSMP |
| 334 | bool "Support for big SMP systems with more than 8 CPUs" | ||
| 335 | depends on X86_32 && SMP | ||
| 336 | help | ||
| 337 | This option is needed for the systems that have more than 8 CPUs | ||
| 338 | and if the system is not of any sub-arch type above. | ||
| 339 | |||
| 340 | endif | ||
| 322 | 341 | ||
| 323 | config X86_RDC321X | 342 | config X86_RDC321X |
| 324 | bool "RDC R-321x SoC" | 343 | bool "RDC R-321x SoC" |
| @@ -432,7 +451,7 @@ config MEMTEST | |||
| 432 | 451 | ||
| 433 | config ACPI_SRAT | 452 | config ACPI_SRAT |
| 434 | def_bool y | 453 | def_bool y |
| 435 | depends on X86_32 && ACPI && NUMA && (X86_SUMMIT || X86_GENERICARCH) | 454 | depends on X86_32 && ACPI && NUMA && X86_GENERICARCH |
| 436 | select ACPI_NUMA | 455 | select ACPI_NUMA |
| 437 | 456 | ||
| 438 | config HAVE_ARCH_PARSE_SRAT | 457 | config HAVE_ARCH_PARSE_SRAT |
| @@ -441,11 +460,11 @@ config HAVE_ARCH_PARSE_SRAT | |||
| 441 | 460 | ||
| 442 | config X86_SUMMIT_NUMA | 461 | config X86_SUMMIT_NUMA |
| 443 | def_bool y | 462 | def_bool y |
| 444 | depends on X86_32 && NUMA && (X86_SUMMIT || X86_GENERICARCH) | 463 | depends on X86_32 && NUMA && X86_GENERICARCH |
| 445 | 464 | ||
| 446 | config X86_CYCLONE_TIMER | 465 | config X86_CYCLONE_TIMER |
| 447 | def_bool y | 466 | def_bool y |
| 448 | depends on X86_32 && X86_SUMMIT || X86_GENERICARCH | 467 | depends on X86_GENERICARCH |
| 449 | 468 | ||
| 450 | config ES7000_CLUSTERED_APIC | 469 | config ES7000_CLUSTERED_APIC |
| 451 | def_bool y | 470 | def_bool y |
| @@ -910,9 +929,9 @@ config X86_PAE | |||
| 910 | config NUMA | 929 | config NUMA |
| 911 | bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)" | 930 | bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)" |
| 912 | depends on SMP | 931 | depends on SMP |
| 913 | depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || (X86_SUMMIT || X86_GENERICARCH) && ACPI) && EXPERIMENTAL) | 932 | depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL) |
| 914 | default n if X86_PC | 933 | default n if X86_PC |
| 915 | default y if (X86_NUMAQ || X86_SUMMIT) | 934 | default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP) |
| 916 | help | 935 | help |
| 917 | Enable NUMA (Non Uniform Memory Access) support. | 936 | Enable NUMA (Non Uniform Memory Access) support. |
| 918 | The kernel will try to allocate memory used by a CPU on the | 937 | The kernel will try to allocate memory used by a CPU on the |
| @@ -1089,6 +1108,40 @@ config MTRR | |||
| 1089 | 1108 | ||
| 1090 | See <file:Documentation/mtrr.txt> for more information. | 1109 | See <file:Documentation/mtrr.txt> for more information. |
| 1091 | 1110 | ||
| 1111 | config MTRR_SANITIZER | ||
| 1112 | def_bool y | ||
| 1113 | prompt "MTRR cleanup support" | ||
| 1114 | depends on MTRR | ||
| 1115 | help | ||
| 1116 | Convert MTRR layout from continuous to discrete, so some X driver | ||
| 1117 | could add WB entries. | ||
| 1118 | |||
| 1119 | Say N here if you see bootup problems (boot crash, boot hang, | ||
| 1120 | spontaneous reboots). | ||
| 1121 | |||
| 1122 | Could be disabled with disable_mtrr_cleanup. Also mtrr_chunk_size | ||
| 1123 | could be used to send largest mtrr entry size for continuous block | ||
| 1124 | to hold holes (aka. UC entries) | ||
| 1125 | |||
| 1126 | If unsure, say Y. | ||
| 1127 | |||
| 1128 | config MTRR_SANITIZER_ENABLE_DEFAULT | ||
| 1129 | int "MTRR cleanup enable value (0-1)" | ||
| 1130 | range 0 1 | ||
| 1131 | default "0" | ||
| 1132 | depends on MTRR_SANITIZER | ||
| 1133 | help | ||
| 1134 | Enable mtrr cleanup default value | ||
| 1135 | |||
| 1136 | config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT | ||
| 1137 | int "MTRR cleanup spare reg num (0-7)" | ||
| 1138 | range 0 7 | ||
| 1139 | default "1" | ||
| 1140 | depends on MTRR_SANITIZER | ||
| 1141 | help | ||
| 1142 | mtrr cleanup spare entries default, it can be changed via | ||
| 1143 | mtrr_spare_reg_nr= | ||
| 1144 | |||
| 1092 | config X86_PAT | 1145 | config X86_PAT |
| 1093 | bool | 1146 | bool |
| 1094 | prompt "x86 PAT support" | 1147 | prompt "x86 PAT support" |
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 38a15333f725..f0684bb74faf 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -137,15 +137,6 @@ config 4KSTACKS | |||
| 137 | on the VM subsystem for higher order allocations. This option | 137 | on the VM subsystem for higher order allocations. This option |
| 138 | will also use IRQ stacks to compensate for the reduced stackspace. | 138 | will also use IRQ stacks to compensate for the reduced stackspace. |
| 139 | 139 | ||
| 140 | config X86_FIND_SMP_CONFIG | ||
| 141 | def_bool y | ||
| 142 | depends on X86_LOCAL_APIC || X86_VOYAGER | ||
| 143 | depends on X86_32 | ||
| 144 | |||
| 145 | config X86_MPPARSE | ||
| 146 | def_bool y | ||
| 147 | depends on (X86_32 && (X86_LOCAL_APIC && !X86_VISWS)) || X86_64 | ||
| 148 | |||
| 149 | config DOUBLEFAULT | 140 | config DOUBLEFAULT |
| 150 | default y | 141 | default y |
| 151 | bool "Enable doublefault exception handler" if EMBEDDED | 142 | bool "Enable doublefault exception handler" if EMBEDDED |
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 5df0d1e330b1..b03d24b44bf9 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
| @@ -117,29 +117,11 @@ mcore-$(CONFIG_X86_VOYAGER) := arch/x86/mach-voyager/ | |||
| 117 | mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-x86/mach-visws | 117 | mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-x86/mach-visws |
| 118 | mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws/ | 118 | mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws/ |
| 119 | 119 | ||
| 120 | # NUMAQ subarch support | ||
| 121 | mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-x86/mach-numaq | ||
| 122 | mcore-$(CONFIG_X86_NUMAQ) := arch/x86/mach-default/ | ||
| 123 | |||
| 124 | # BIGSMP subarch support | ||
| 125 | mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-x86/mach-bigsmp | ||
| 126 | mcore-$(CONFIG_X86_BIGSMP) := arch/x86/mach-default/ | ||
| 127 | |||
| 128 | #Summit subarch support | ||
| 129 | mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-x86/mach-summit | ||
| 130 | mcore-$(CONFIG_X86_SUMMIT) := arch/x86/mach-default/ | ||
| 131 | |||
| 132 | # generic subarchitecture | 120 | # generic subarchitecture |
| 133 | mflags-$(CONFIG_X86_GENERICARCH):= -Iinclude/asm-x86/mach-generic | 121 | mflags-$(CONFIG_X86_GENERICARCH):= -Iinclude/asm-x86/mach-generic |
| 134 | fcore-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ | 122 | fcore-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ |
| 135 | mcore-$(CONFIG_X86_GENERICARCH) := arch/x86/mach-default/ | 123 | mcore-$(CONFIG_X86_GENERICARCH) := arch/x86/mach-default/ |
| 136 | 124 | ||
| 137 | |||
| 138 | # ES7000 subarch support | ||
| 139 | mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-x86/mach-es7000 | ||
| 140 | fcore-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ | ||
| 141 | mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default/ | ||
| 142 | |||
| 143 | # RDC R-321x subarch support | 125 | # RDC R-321x subarch support |
| 144 | mflags-$(CONFIG_X86_RDC321X) := -Iinclude/asm-x86/mach-rdc321x | 126 | mflags-$(CONFIG_X86_RDC321X) := -Iinclude/asm-x86/mach-rdc321x |
| 145 | mcore-$(CONFIG_X86_RDC321X) := arch/x86/mach-default/ | 127 | mcore-$(CONFIG_X86_RDC321X) := arch/x86/mach-default/ |
| @@ -160,6 +142,7 @@ KBUILD_AFLAGS += $(mflags-y) | |||
| 160 | 142 | ||
| 161 | head-y := arch/x86/kernel/head_$(BITS).o | 143 | head-y := arch/x86/kernel/head_$(BITS).o |
| 162 | head-y += arch/x86/kernel/head$(BITS).o | 144 | head-y += arch/x86/kernel/head$(BITS).o |
| 145 | head-y += arch/x86/kernel/head.o | ||
| 163 | head-y += arch/x86/kernel/init_task.o | 146 | head-y += arch/x86/kernel/init_task.o |
| 164 | 147 | ||
| 165 | libs-y += arch/x86/lib/ | 148 | libs-y += arch/x86/lib/ |
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 11629e903aa5..bc5553b496f7 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
| @@ -218,10 +218,6 @@ static char *vidmem; | |||
| 218 | static int vidport; | 218 | static int vidport; |
| 219 | static int lines, cols; | 219 | static int lines, cols; |
| 220 | 220 | ||
| 221 | #ifdef CONFIG_X86_NUMAQ | ||
| 222 | void *xquad_portio; | ||
| 223 | #endif | ||
| 224 | |||
| 225 | #include "../../../../lib/inflate.c" | 221 | #include "../../../../lib/inflate.c" |
| 226 | 222 | ||
| 227 | static void *malloc(int size) | 223 | static void *malloc(int size) |
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index acad32eb4290..53165c97336b 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include "boot.h" | 15 | #include "boot.h" |
| 16 | #include <linux/kernel.h> | ||
| 16 | 17 | ||
| 17 | #define SMAP 0x534d4150 /* ASCII "SMAP" */ | 18 | #define SMAP 0x534d4150 /* ASCII "SMAP" */ |
| 18 | 19 | ||
| @@ -53,7 +54,7 @@ static int detect_memory_e820(void) | |||
| 53 | 54 | ||
| 54 | count++; | 55 | count++; |
| 55 | desc++; | 56 | desc++; |
| 56 | } while (next && count < E820MAX); | 57 | } while (next && count < ARRAY_SIZE(boot_params.e820_map)); |
| 57 | 58 | ||
| 58 | return boot_params.e820_entries = count; | 59 | return boot_params.e820_entries = count; |
| 59 | } | 60 | } |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 53557cbe4bfa..d1d4ee895270 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | extra-y := head_$(BITS).o head$(BITS).o init_task.o vmlinux.lds | 5 | extra-y := head_$(BITS).o head$(BITS).o head.o init_task.o vmlinux.lds |
| 6 | 6 | ||
| 7 | CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE) | 7 | CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE) |
| 8 | 8 | ||
| @@ -22,7 +22,7 @@ obj-y += setup_$(BITS).o i8259.o irqinit_$(BITS).o setup.o | |||
| 22 | obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o | 22 | obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o |
| 23 | obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o | 23 | obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o |
| 24 | obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o setup64.o | 24 | obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o setup64.o |
| 25 | obj-y += bootflag.o e820_$(BITS).o | 25 | obj-y += bootflag.o e820.o |
| 26 | obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o | 26 | obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o |
| 27 | obj-y += alternative.o i8253.o pci-nommu.o | 27 | obj-y += alternative.o i8253.o pci-nommu.o |
| 28 | obj-y += tsc_$(BITS).o io_delay.o rtc.o | 28 | obj-y += tsc_$(BITS).o io_delay.o rtc.o |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ff1a7b49a460..6516359922ba 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
| @@ -83,6 +83,8 @@ int acpi_lapic; | |||
| 83 | int acpi_ioapic; | 83 | int acpi_ioapic; |
| 84 | int acpi_strict; | 84 | int acpi_strict; |
| 85 | 85 | ||
| 86 | static int disable_irq0_through_ioapic __initdata; | ||
| 87 | |||
| 86 | u8 acpi_sci_flags __initdata; | 88 | u8 acpi_sci_flags __initdata; |
| 87 | int acpi_sci_override_gsi __initdata; | 89 | int acpi_sci_override_gsi __initdata; |
| 88 | int acpi_skip_timer_override __initdata; | 90 | int acpi_skip_timer_override __initdata; |
| @@ -338,8 +340,6 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e | |||
| 338 | 340 | ||
| 339 | #ifdef CONFIG_X86_IO_APIC | 341 | #ifdef CONFIG_X86_IO_APIC |
| 340 | 342 | ||
| 341 | struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS]; | ||
| 342 | |||
| 343 | static int __init | 343 | static int __init |
| 344 | acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) | 344 | acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) |
| 345 | { | 345 | { |
| @@ -858,6 +858,372 @@ static int __init acpi_parse_madt_lapic_entries(void) | |||
| 858 | #endif /* CONFIG_X86_LOCAL_APIC */ | 858 | #endif /* CONFIG_X86_LOCAL_APIC */ |
| 859 | 859 | ||
| 860 | #ifdef CONFIG_X86_IO_APIC | 860 | #ifdef CONFIG_X86_IO_APIC |
| 861 | #define MP_ISA_BUS 0 | ||
| 862 | |||
| 863 | #ifdef CONFIG_X86_ES7000 | ||
| 864 | extern int es7000_plat; | ||
| 865 | #endif | ||
| 866 | |||
| 867 | static struct { | ||
| 868 | int apic_id; | ||
| 869 | int gsi_base; | ||
| 870 | int gsi_end; | ||
| 871 | DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); | ||
| 872 | } mp_ioapic_routing[MAX_IO_APICS]; | ||
| 873 | |||
| 874 | static int mp_find_ioapic(int gsi) | ||
| 875 | { | ||
| 876 | int i = 0; | ||
| 877 | |||
| 878 | /* Find the IOAPIC that manages this GSI. */ | ||
| 879 | for (i = 0; i < nr_ioapics; i++) { | ||
| 880 | if ((gsi >= mp_ioapic_routing[i].gsi_base) | ||
| 881 | && (gsi <= mp_ioapic_routing[i].gsi_end)) | ||
| 882 | return i; | ||
| 883 | } | ||
| 884 | |||
| 885 | printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); | ||
| 886 | return -1; | ||
| 887 | } | ||
| 888 | |||
| 889 | static u8 __init uniq_ioapic_id(u8 id) | ||
| 890 | { | ||
| 891 | #ifdef CONFIG_X86_32 | ||
| 892 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && | ||
| 893 | !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) | ||
| 894 | return io_apic_get_unique_id(nr_ioapics, id); | ||
| 895 | else | ||
| 896 | return id; | ||
| 897 | #else | ||
| 898 | int i; | ||
| 899 | DECLARE_BITMAP(used, 256); | ||
| 900 | bitmap_zero(used, 256); | ||
| 901 | for (i = 0; i < nr_ioapics; i++) { | ||
| 902 | struct mp_config_ioapic *ia = &mp_ioapics[i]; | ||
| 903 | __set_bit(ia->mp_apicid, used); | ||
| 904 | } | ||
| 905 | if (!test_bit(id, used)) | ||
| 906 | return id; | ||
| 907 | return find_first_zero_bit(used, 256); | ||
| 908 | #endif | ||
| 909 | } | ||
| 910 | |||
| 911 | static int bad_ioapic(unsigned long address) | ||
| 912 | { | ||
| 913 | if (nr_ioapics >= MAX_IO_APICS) { | ||
| 914 | printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " | ||
| 915 | "(found %d)\n", MAX_IO_APICS, nr_ioapics); | ||
| 916 | panic("Recompile kernel with bigger MAX_IO_APICS!\n"); | ||
| 917 | } | ||
| 918 | if (!address) { | ||
| 919 | printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" | ||
| 920 | " found in table, skipping!\n"); | ||
| 921 | return 1; | ||
| 922 | } | ||
| 923 | return 0; | ||
| 924 | } | ||
| 925 | |||
| 926 | void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | ||
| 927 | { | ||
| 928 | int idx = 0; | ||
| 929 | |||
| 930 | if (bad_ioapic(address)) | ||
| 931 | return; | ||
| 932 | |||
| 933 | idx = nr_ioapics; | ||
| 934 | |||
| 935 | mp_ioapics[idx].mp_type = MP_IOAPIC; | ||
| 936 | mp_ioapics[idx].mp_flags = MPC_APIC_USABLE; | ||
| 937 | mp_ioapics[idx].mp_apicaddr = address; | ||
| 938 | |||
| 939 | set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); | ||
| 940 | mp_ioapics[idx].mp_apicid = uniq_ioapic_id(id); | ||
| 941 | #ifdef CONFIG_X86_32 | ||
| 942 | mp_ioapics[idx].mp_apicver = io_apic_get_version(idx); | ||
| 943 | #else | ||
| 944 | mp_ioapics[idx].mp_apicver = 0; | ||
| 945 | #endif | ||
| 946 | /* | ||
| 947 | * Build basic GSI lookup table to facilitate gsi->io_apic lookups | ||
| 948 | * and to prevent reprogramming of IOAPIC pins (PCI GSIs). | ||
| 949 | */ | ||
| 950 | mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mp_apicid; | ||
| 951 | mp_ioapic_routing[idx].gsi_base = gsi_base; | ||
| 952 | mp_ioapic_routing[idx].gsi_end = gsi_base + | ||
| 953 | io_apic_get_redir_entries(idx); | ||
| 954 | |||
| 955 | printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, " | ||
| 956 | "GSI %d-%d\n", idx, mp_ioapics[idx].mp_apicid, | ||
| 957 | mp_ioapics[idx].mp_apicver, mp_ioapics[idx].mp_apicaddr, | ||
| 958 | mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end); | ||
| 959 | |||
| 960 | nr_ioapics++; | ||
| 961 | } | ||
| 962 | |||
| 963 | static void assign_to_mp_irq(struct mp_config_intsrc *m, | ||
| 964 | struct mp_config_intsrc *mp_irq) | ||
| 965 | { | ||
| 966 | memcpy(mp_irq, m, sizeof(struct mp_config_intsrc)); | ||
| 967 | } | ||
| 968 | |||
| 969 | static int mp_irq_cmp(struct mp_config_intsrc *mp_irq, | ||
| 970 | struct mp_config_intsrc *m) | ||
| 971 | { | ||
| 972 | return memcmp(mp_irq, m, sizeof(struct mp_config_intsrc)); | ||
| 973 | } | ||
| 974 | |||
| 975 | static void save_mp_irq(struct mp_config_intsrc *m) | ||
| 976 | { | ||
| 977 | int i; | ||
| 978 | |||
| 979 | for (i = 0; i < mp_irq_entries; i++) { | ||
| 980 | if (!mp_irq_cmp(&mp_irqs[i], m)) | ||
| 981 | return; | ||
| 982 | } | ||
| 983 | |||
| 984 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
| 985 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | ||
| 986 | panic("Max # of irq sources exceeded!!\n"); | ||
| 987 | } | ||
| 988 | |||
| 989 | void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) | ||
| 990 | { | ||
| 991 | int ioapic; | ||
| 992 | int pin; | ||
| 993 | struct mp_config_intsrc mp_irq; | ||
| 994 | |||
| 995 | /* Skip the 8254 timer interrupt (IRQ 0) if requested. */ | ||
| 996 | if (bus_irq == 0 && disable_irq0_through_ioapic) | ||
| 997 | return; | ||
| 998 | |||
| 999 | /* | ||
| 1000 | * Convert 'gsi' to 'ioapic.pin'. | ||
| 1001 | */ | ||
| 1002 | ioapic = mp_find_ioapic(gsi); | ||
| 1003 | if (ioapic < 0) | ||
| 1004 | return; | ||
| 1005 | pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
| 1006 | |||
| 1007 | /* | ||
| 1008 | * TBD: This check is for faulty timer entries, where the override | ||
| 1009 | * erroneously sets the trigger to level, resulting in a HUGE | ||
| 1010 | * increase of timer interrupts! | ||
| 1011 | */ | ||
| 1012 | if ((bus_irq == 0) && (trigger == 3)) | ||
| 1013 | trigger = 1; | ||
| 1014 | |||
| 1015 | mp_irq.mp_type = MP_INTSRC; | ||
| 1016 | mp_irq.mp_irqtype = mp_INT; | ||
| 1017 | mp_irq.mp_irqflag = (trigger << 2) | polarity; | ||
| 1018 | mp_irq.mp_srcbus = MP_ISA_BUS; | ||
| 1019 | mp_irq.mp_srcbusirq = bus_irq; /* IRQ */ | ||
| 1020 | mp_irq.mp_dstapic = mp_ioapics[ioapic].mp_apicid; /* APIC ID */ | ||
| 1021 | mp_irq.mp_dstirq = pin; /* INTIN# */ | ||
| 1022 | |||
| 1023 | save_mp_irq(&mp_irq); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | void __init mp_config_acpi_legacy_irqs(void) | ||
| 1027 | { | ||
| 1028 | int i; | ||
| 1029 | int ioapic; | ||
| 1030 | unsigned int dstapic; | ||
| 1031 | struct mp_config_intsrc mp_irq; | ||
| 1032 | |||
| 1033 | #if defined (CONFIG_MCA) || defined (CONFIG_EISA) | ||
| 1034 | /* | ||
| 1035 | * Fabricate the legacy ISA bus (bus #31). | ||
| 1036 | */ | ||
| 1037 | mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; | ||
| 1038 | #endif | ||
| 1039 | set_bit(MP_ISA_BUS, mp_bus_not_pci); | ||
| 1040 | Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); | ||
| 1041 | |||
| 1042 | #ifdef CONFIG_X86_ES7000 | ||
| 1043 | /* | ||
| 1044 | * Older generations of ES7000 have no legacy identity mappings | ||
| 1045 | */ | ||
| 1046 | if (es7000_plat == 1) | ||
| 1047 | return; | ||
| 1048 | #endif | ||
| 1049 | |||
| 1050 | /* | ||
| 1051 | * Locate the IOAPIC that manages the ISA IRQs (0-15). | ||
| 1052 | */ | ||
| 1053 | ioapic = mp_find_ioapic(0); | ||
| 1054 | if (ioapic < 0) | ||
| 1055 | return; | ||
| 1056 | dstapic = mp_ioapics[ioapic].mp_apicid; | ||
| 1057 | |||
| 1058 | /* | ||
| 1059 | * Use the default configuration for the IRQs 0-15. Unless | ||
| 1060 | * overridden by (MADT) interrupt source override entries. | ||
| 1061 | */ | ||
| 1062 | for (i = 0; i < 16; i++) { | ||
| 1063 | int idx; | ||
| 1064 | |||
| 1065 | /* Skip the 8254 timer interrupt (IRQ 0) if requested. */ | ||
| 1066 | if (i == 0 && disable_irq0_through_ioapic) | ||
| 1067 | continue; | ||
| 1068 | |||
| 1069 | for (idx = 0; idx < mp_irq_entries; idx++) { | ||
| 1070 | struct mp_config_intsrc *irq = mp_irqs + idx; | ||
| 1071 | |||
| 1072 | /* Do we already have a mapping for this ISA IRQ? */ | ||
| 1073 | if (irq->mp_srcbus == MP_ISA_BUS | ||
| 1074 | && irq->mp_srcbusirq == i) | ||
| 1075 | break; | ||
| 1076 | |||
| 1077 | /* Do we already have a mapping for this IOAPIC pin */ | ||
| 1078 | if (irq->mp_dstapic == dstapic && | ||
| 1079 | irq->mp_dstirq == i) | ||
| 1080 | break; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | if (idx != mp_irq_entries) { | ||
| 1084 | printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); | ||
| 1085 | continue; /* IRQ already used */ | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | mp_irq.mp_type = MP_INTSRC; | ||
| 1089 | mp_irq.mp_irqflag = 0; /* Conforming */ | ||
| 1090 | mp_irq.mp_srcbus = MP_ISA_BUS; | ||
| 1091 | mp_irq.mp_dstapic = dstapic; | ||
| 1092 | mp_irq.mp_irqtype = mp_INT; | ||
| 1093 | mp_irq.mp_srcbusirq = i; /* Identity mapped */ | ||
| 1094 | mp_irq.mp_dstirq = i; | ||
| 1095 | |||
| 1096 | save_mp_irq(&mp_irq); | ||
| 1097 | } | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | int mp_register_gsi(u32 gsi, int triggering, int polarity) | ||
| 1101 | { | ||
| 1102 | int ioapic; | ||
| 1103 | int ioapic_pin; | ||
| 1104 | #ifdef CONFIG_X86_32 | ||
| 1105 | #define MAX_GSI_NUM 4096 | ||
| 1106 | #define IRQ_COMPRESSION_START 64 | ||
| 1107 | |||
| 1108 | static int pci_irq = IRQ_COMPRESSION_START; | ||
| 1109 | /* | ||
| 1110 | * Mapping between Global System Interrupts, which | ||
| 1111 | * represent all possible interrupts, and IRQs | ||
| 1112 | * assigned to actual devices. | ||
| 1113 | */ | ||
| 1114 | static int gsi_to_irq[MAX_GSI_NUM]; | ||
| 1115 | #else | ||
| 1116 | |||
| 1117 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) | ||
| 1118 | return gsi; | ||
| 1119 | #endif | ||
| 1120 | |||
| 1121 | /* Don't set up the ACPI SCI because it's already set up */ | ||
| 1122 | if (acpi_gbl_FADT.sci_interrupt == gsi) | ||
| 1123 | return gsi; | ||
| 1124 | |||
| 1125 | ioapic = mp_find_ioapic(gsi); | ||
| 1126 | if (ioapic < 0) { | ||
| 1127 | printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); | ||
| 1128 | return gsi; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
| 1132 | |||
| 1133 | #ifdef CONFIG_X86_32 | ||
| 1134 | if (ioapic_renumber_irq) | ||
| 1135 | gsi = ioapic_renumber_irq(ioapic, gsi); | ||
| 1136 | #endif | ||
| 1137 | |||
| 1138 | /* | ||
| 1139 | * Avoid pin reprogramming. PRTs typically include entries | ||
| 1140 | * with redundant pin->gsi mappings (but unique PCI devices); | ||
| 1141 | * we only program the IOAPIC on the first. | ||
| 1142 | */ | ||
| 1143 | if (ioapic_pin > MP_MAX_IOAPIC_PIN) { | ||
| 1144 | printk(KERN_ERR "Invalid reference to IOAPIC pin " | ||
| 1145 | "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, | ||
| 1146 | ioapic_pin); | ||
| 1147 | return gsi; | ||
| 1148 | } | ||
| 1149 | if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) { | ||
| 1150 | Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n", | ||
| 1151 | mp_ioapic_routing[ioapic].apic_id, ioapic_pin); | ||
| 1152 | #ifdef CONFIG_X86_32 | ||
| 1153 | return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]); | ||
| 1154 | #else | ||
| 1155 | return gsi; | ||
| 1156 | #endif | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed); | ||
| 1160 | #ifdef CONFIG_X86_32 | ||
| 1161 | /* | ||
| 1162 | * For GSI >= 64, use IRQ compression | ||
| 1163 | */ | ||
| 1164 | if ((gsi >= IRQ_COMPRESSION_START) | ||
| 1165 | && (triggering == ACPI_LEVEL_SENSITIVE)) { | ||
| 1166 | /* | ||
| 1167 | * For PCI devices assign IRQs in order, avoiding gaps | ||
| 1168 | * due to unused I/O APIC pins. | ||
| 1169 | */ | ||
| 1170 | int irq = gsi; | ||
| 1171 | if (gsi < MAX_GSI_NUM) { | ||
| 1172 | /* | ||
| 1173 | * Retain the VIA chipset work-around (gsi > 15), but | ||
| 1174 | * avoid a problem where the 8254 timer (IRQ0) is setup | ||
| 1175 | * via an override (so it's not on pin 0 of the ioapic), | ||
| 1176 | * and at the same time, the pin 0 interrupt is a PCI | ||
| 1177 | * type. The gsi > 15 test could cause these two pins | ||
| 1178 | * to be shared as IRQ0, and they are not shareable. | ||
| 1179 | * So test for this condition, and if necessary, avoid | ||
| 1180 | * the pin collision. | ||
| 1181 | */ | ||
| 1182 | gsi = pci_irq++; | ||
| 1183 | /* | ||
| 1184 | * Don't assign IRQ used by ACPI SCI | ||
| 1185 | */ | ||
| 1186 | if (gsi == acpi_gbl_FADT.sci_interrupt) | ||
| 1187 | gsi = pci_irq++; | ||
| 1188 | gsi_to_irq[irq] = gsi; | ||
| 1189 | } else { | ||
| 1190 | printk(KERN_ERR "GSI %u is too high\n", gsi); | ||
| 1191 | return gsi; | ||
| 1192 | } | ||
| 1193 | } | ||
| 1194 | #endif | ||
| 1195 | io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, | ||
| 1196 | triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, | ||
| 1197 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | ||
| 1198 | return gsi; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, | ||
| 1202 | u32 gsi, int triggering, int polarity) | ||
| 1203 | { | ||
| 1204 | #ifdef CONFIG_X86_MPPARSE | ||
| 1205 | struct mp_config_intsrc mp_irq; | ||
| 1206 | int ioapic; | ||
| 1207 | |||
| 1208 | if (!acpi_ioapic) | ||
| 1209 | return 0; | ||
| 1210 | |||
| 1211 | /* print the entry should happen on mptable identically */ | ||
| 1212 | mp_irq.mp_type = MP_INTSRC; | ||
| 1213 | mp_irq.mp_irqtype = mp_INT; | ||
| 1214 | mp_irq.mp_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | | ||
| 1215 | (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); | ||
| 1216 | mp_irq.mp_srcbus = number; | ||
| 1217 | mp_irq.mp_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); | ||
| 1218 | ioapic = mp_find_ioapic(gsi); | ||
| 1219 | mp_irq.mp_dstapic = mp_ioapic_routing[ioapic].apic_id; | ||
| 1220 | mp_irq.mp_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
| 1221 | |||
| 1222 | save_mp_irq(&mp_irq); | ||
| 1223 | #endif | ||
| 1224 | return 0; | ||
| 1225 | } | ||
| 1226 | |||
| 861 | /* | 1227 | /* |
| 862 | * Parse IOAPIC related entries in MADT | 1228 | * Parse IOAPIC related entries in MADT |
| 863 | * returns 0 on success, < 0 on error | 1229 | * returns 0 on success, < 0 on error |
| @@ -1059,6 +1425,17 @@ static int __init force_acpi_ht(const struct dmi_system_id *d) | |||
| 1059 | } | 1425 | } |
| 1060 | 1426 | ||
| 1061 | /* | 1427 | /* |
| 1428 | * Don't register any I/O APIC entries for the 8254 timer IRQ. | ||
| 1429 | */ | ||
| 1430 | static int __init | ||
| 1431 | dmi_disable_irq0_through_ioapic(const struct dmi_system_id *d) | ||
| 1432 | { | ||
| 1433 | pr_notice("%s detected: disabling IRQ 0 through I/O APIC\n", d->ident); | ||
| 1434 | disable_irq0_through_ioapic = 1; | ||
| 1435 | return 0; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | /* | ||
| 1062 | * If your system is blacklisted here, but you find that acpi=force | 1439 | * If your system is blacklisted here, but you find that acpi=force |
| 1063 | * works for you, please contact acpi-devel@sourceforge.net | 1440 | * works for you, please contact acpi-devel@sourceforge.net |
| 1064 | */ | 1441 | */ |
| @@ -1225,6 +1602,32 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = { | |||
| 1225 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), | 1602 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), |
| 1226 | }, | 1603 | }, |
| 1227 | }, | 1604 | }, |
| 1605 | /* | ||
| 1606 | * HP laptops which use a DSDT reporting as HP/SB400/10000, | ||
| 1607 | * which includes some code which overrides all temperature | ||
| 1608 | * trip points to 16C if the INTIN2 input of the I/O APIC | ||
| 1609 | * is enabled. This input is incorrectly designated the | ||
| 1610 | * ISA IRQ 0 via an interrupt source override even though | ||
| 1611 | * it is wired to the output of the master 8259A and INTIN0 | ||
| 1612 | * is not connected at all. Abandon any attempts to route | ||
| 1613 | * IRQ 0 through the I/O APIC therefore. | ||
| 1614 | */ | ||
| 1615 | { | ||
| 1616 | .callback = dmi_disable_irq0_through_ioapic, | ||
| 1617 | .ident = "HP NX6125 laptop", | ||
| 1618 | .matches = { | ||
| 1619 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
| 1620 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"), | ||
| 1621 | }, | ||
| 1622 | }, | ||
| 1623 | { | ||
| 1624 | .callback = dmi_disable_irq0_through_ioapic, | ||
| 1625 | .ident = "HP NX6325 laptop", | ||
| 1626 | .matches = { | ||
| 1627 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
| 1628 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), | ||
| 1629 | }, | ||
| 1630 | }, | ||
| 1228 | {} | 1631 | {} |
| 1229 | }; | 1632 | }; |
| 1230 | 1633 | ||
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index e819362c7068..600470d464fa 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c | |||
| @@ -328,7 +328,7 @@ void __init early_gart_iommu_check(void) | |||
| 328 | E820_RAM)) { | 328 | E820_RAM)) { |
| 329 | /* reserve it, so we can reuse it in second kernel */ | 329 | /* reserve it, so we can reuse it in second kernel */ |
| 330 | printk(KERN_INFO "update e820 for GART\n"); | 330 | printk(KERN_INFO "update e820 for GART\n"); |
| 331 | add_memory_region(aper_base, aper_size, E820_RESERVED); | 331 | e820_add_region(aper_base, aper_size, E820_RESERVED); |
| 332 | update_e820(); | 332 | update_e820(); |
| 333 | } | 333 | } |
| 334 | } | 334 | } |
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index ce4538ebb7fe..570c362eca8c 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
| @@ -79,6 +79,11 @@ char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE}; | |||
| 79 | */ | 79 | */ |
| 80 | int apic_verbosity; | 80 | int apic_verbosity; |
| 81 | 81 | ||
| 82 | int pic_mode; | ||
| 83 | |||
| 84 | /* Have we found an MP table */ | ||
| 85 | int smp_found_config; | ||
| 86 | |||
| 82 | static unsigned int calibration_result; | 87 | static unsigned int calibration_result; |
| 83 | 88 | ||
| 84 | static int lapic_next_event(unsigned long delta, | 89 | static int lapic_next_event(unsigned long delta, |
| @@ -1202,7 +1207,7 @@ void __init init_apic_mappings(void) | |||
| 1202 | 1207 | ||
| 1203 | for (i = 0; i < nr_ioapics; i++) { | 1208 | for (i = 0; i < nr_ioapics; i++) { |
| 1204 | if (smp_found_config) { | 1209 | if (smp_found_config) { |
| 1205 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; | 1210 | ioapic_phys = mp_ioapics[i].mp_apicaddr; |
| 1206 | if (!ioapic_phys) { | 1211 | if (!ioapic_phys) { |
| 1207 | printk(KERN_ERR | 1212 | printk(KERN_ERR |
| 1208 | "WARNING: bogus zero IO-APIC " | 1213 | "WARNING: bogus zero IO-APIC " |
| @@ -1517,6 +1522,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1517 | */ | 1522 | */ |
| 1518 | cpu = 0; | 1523 | cpu = 0; |
| 1519 | 1524 | ||
| 1525 | if (apicid > max_physical_apicid) | ||
| 1526 | max_physical_apicid = apicid; | ||
| 1527 | |||
| 1520 | /* | 1528 | /* |
| 1521 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y | 1529 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y |
| 1522 | * but we need to work other dependencies like SMP_SUSPEND etc | 1530 | * but we need to work other dependencies like SMP_SUSPEND etc |
| @@ -1524,7 +1532,7 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1524 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) | 1532 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) |
| 1525 | * - Ashok Raj <ashok.raj@intel.com> | 1533 | * - Ashok Raj <ashok.raj@intel.com> |
| 1526 | */ | 1534 | */ |
| 1527 | if (num_processors > 8) { | 1535 | if (max_physical_apicid >= 8) { |
| 1528 | switch (boot_cpu_data.x86_vendor) { | 1536 | switch (boot_cpu_data.x86_vendor) { |
| 1529 | case X86_VENDOR_INTEL: | 1537 | case X86_VENDOR_INTEL: |
| 1530 | if (!APIC_XAPIC(version)) { | 1538 | if (!APIC_XAPIC(version)) { |
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 3ef7752aa8e5..d7406aa1c985 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c | |||
| @@ -56,6 +56,9 @@ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); | |||
| 56 | */ | 56 | */ |
| 57 | int apic_verbosity; | 57 | int apic_verbosity; |
| 58 | 58 | ||
| 59 | /* Have we found an MP table */ | ||
| 60 | int smp_found_config; | ||
| 61 | |||
| 59 | static struct resource lapic_resource = { | 62 | static struct resource lapic_resource = { |
| 60 | .name = "Local APIC", | 63 | .name = "Local APIC", |
| 61 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, | 64 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, |
| @@ -1068,6 +1071,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1068 | */ | 1071 | */ |
| 1069 | cpu = 0; | 1072 | cpu = 0; |
| 1070 | } | 1073 | } |
| 1074 | if (apicid > max_physical_apicid) | ||
| 1075 | max_physical_apicid = apicid; | ||
| 1076 | |||
| 1071 | /* are we being called early in kernel startup? */ | 1077 | /* are we being called early in kernel startup? */ |
| 1072 | if (x86_cpu_to_apicid_early_ptr) { | 1078 | if (x86_cpu_to_apicid_early_ptr) { |
| 1073 | u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr; | 1079 | u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr; |
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 5d241ce94a44..509bd3d9eacd 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c | |||
| @@ -37,7 +37,7 @@ static struct fixed_range_block fixed_range_blocks[] = { | |||
| 37 | static unsigned long smp_changes_mask; | 37 | static unsigned long smp_changes_mask; |
| 38 | static struct mtrr_state mtrr_state = {}; | 38 | static struct mtrr_state mtrr_state = {}; |
| 39 | static int mtrr_state_set; | 39 | static int mtrr_state_set; |
| 40 | static u64 tom2; | 40 | u64 mtrr_tom2; |
| 41 | 41 | ||
| 42 | #undef MODULE_PARAM_PREFIX | 42 | #undef MODULE_PARAM_PREFIX |
| 43 | #define MODULE_PARAM_PREFIX "mtrr." | 43 | #define MODULE_PARAM_PREFIX "mtrr." |
| @@ -139,8 +139,8 @@ u8 mtrr_type_lookup(u64 start, u64 end) | |||
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | if (tom2) { | 142 | if (mtrr_tom2) { |
| 143 | if (start >= (1ULL<<32) && (end < tom2)) | 143 | if (start >= (1ULL<<32) && (end < mtrr_tom2)) |
| 144 | return MTRR_TYPE_WRBACK; | 144 | return MTRR_TYPE_WRBACK; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| @@ -158,6 +158,20 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) | |||
| 158 | rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); | 158 | rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | /* fill the MSR pair relating to a var range */ | ||
| 162 | void fill_mtrr_var_range(unsigned int index, | ||
| 163 | u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi) | ||
| 164 | { | ||
| 165 | struct mtrr_var_range *vr; | ||
| 166 | |||
| 167 | vr = mtrr_state.var_ranges; | ||
| 168 | |||
| 169 | vr[index].base_lo = base_lo; | ||
| 170 | vr[index].base_hi = base_hi; | ||
| 171 | vr[index].mask_lo = mask_lo; | ||
| 172 | vr[index].mask_hi = mask_hi; | ||
| 173 | } | ||
| 174 | |||
| 161 | static void | 175 | static void |
| 162 | get_fixed_ranges(mtrr_type * frs) | 176 | get_fixed_ranges(mtrr_type * frs) |
| 163 | { | 177 | { |
| @@ -213,13 +227,13 @@ void __init get_mtrr_state(void) | |||
| 213 | mtrr_state.enabled = (lo & 0xc00) >> 10; | 227 | mtrr_state.enabled = (lo & 0xc00) >> 10; |
| 214 | 228 | ||
| 215 | if (amd_special_default_mtrr()) { | 229 | if (amd_special_default_mtrr()) { |
| 216 | unsigned lo, hi; | 230 | unsigned low, high; |
| 217 | /* TOP_MEM2 */ | 231 | /* TOP_MEM2 */ |
| 218 | rdmsr(MSR_K8_TOP_MEM2, lo, hi); | 232 | rdmsr(MSR_K8_TOP_MEM2, low, high); |
| 219 | tom2 = hi; | 233 | mtrr_tom2 = high; |
| 220 | tom2 <<= 32; | 234 | mtrr_tom2 <<= 32; |
| 221 | tom2 |= lo; | 235 | mtrr_tom2 |= low; |
| 222 | tom2 &= 0xffffff8000000ULL; | 236 | mtrr_tom2 &= 0xffffff800000ULL; |
| 223 | } | 237 | } |
| 224 | if (mtrr_show) { | 238 | if (mtrr_show) { |
| 225 | int high_width; | 239 | int high_width; |
| @@ -251,9 +265,9 @@ void __init get_mtrr_state(void) | |||
| 251 | else | 265 | else |
| 252 | printk(KERN_INFO "MTRR %u disabled\n", i); | 266 | printk(KERN_INFO "MTRR %u disabled\n", i); |
| 253 | } | 267 | } |
| 254 | if (tom2) { | 268 | if (mtrr_tom2) { |
| 255 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n", | 269 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n", |
| 256 | tom2, tom2>>20); | 270 | mtrr_tom2, mtrr_tom2>>20); |
| 257 | } | 271 | } |
| 258 | } | 272 | } |
| 259 | mtrr_state_set = 1; | 273 | mtrr_state_set = 1; |
| @@ -328,7 +342,7 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) | |||
| 328 | 342 | ||
| 329 | if (lo != msrwords[0] || hi != msrwords[1]) { | 343 | if (lo != msrwords[0] || hi != msrwords[1]) { |
| 330 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && | 344 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && |
| 331 | boot_cpu_data.x86 == 15 && | 345 | (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) && |
| 332 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) | 346 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) |
| 333 | k8_enable_fixed_iorrs(); | 347 | k8_enable_fixed_iorrs(); |
| 334 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); | 348 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); |
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 6a1e278d9323..105afe12beb0 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/smp.h> | 37 | #include <linux/smp.h> |
| 38 | #include <linux/cpu.h> | 38 | #include <linux/cpu.h> |
| 39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
| 40 | #include <linux/sort.h> | ||
| 40 | 41 | ||
| 41 | #include <asm/e820.h> | 42 | #include <asm/e820.h> |
| 42 | #include <asm/mtrr.h> | 43 | #include <asm/mtrr.h> |
| @@ -609,6 +610,787 @@ static struct sysdev_driver mtrr_sysdev_driver = { | |||
| 609 | .resume = mtrr_restore, | 610 | .resume = mtrr_restore, |
| 610 | }; | 611 | }; |
| 611 | 612 | ||
| 613 | /* should be related to MTRR_VAR_RANGES nums */ | ||
| 614 | #define RANGE_NUM 256 | ||
| 615 | |||
| 616 | struct res_range { | ||
| 617 | unsigned long start; | ||
| 618 | unsigned long end; | ||
| 619 | }; | ||
| 620 | |||
| 621 | static int __init | ||
| 622 | add_range(struct res_range *range, int nr_range, unsigned long start, | ||
| 623 | unsigned long end) | ||
| 624 | { | ||
| 625 | /* out of slots */ | ||
| 626 | if (nr_range >= RANGE_NUM) | ||
| 627 | return nr_range; | ||
| 628 | |||
| 629 | range[nr_range].start = start; | ||
| 630 | range[nr_range].end = end; | ||
| 631 | |||
| 632 | nr_range++; | ||
| 633 | |||
| 634 | return nr_range; | ||
| 635 | } | ||
| 636 | |||
| 637 | static int __init | ||
| 638 | add_range_with_merge(struct res_range *range, int nr_range, unsigned long start, | ||
| 639 | unsigned long end) | ||
| 640 | { | ||
| 641 | int i; | ||
| 642 | |||
| 643 | /* try to merge it with old one */ | ||
| 644 | for (i = 0; i < nr_range; i++) { | ||
| 645 | unsigned long final_start, final_end; | ||
| 646 | unsigned long common_start, common_end; | ||
| 647 | |||
| 648 | if (!range[i].end) | ||
| 649 | continue; | ||
| 650 | |||
| 651 | common_start = max(range[i].start, start); | ||
| 652 | common_end = min(range[i].end, end); | ||
| 653 | if (common_start > common_end + 1) | ||
| 654 | continue; | ||
| 655 | |||
| 656 | final_start = min(range[i].start, start); | ||
| 657 | final_end = max(range[i].end, end); | ||
| 658 | |||
| 659 | range[i].start = final_start; | ||
| 660 | range[i].end = final_end; | ||
| 661 | return nr_range; | ||
| 662 | } | ||
| 663 | |||
| 664 | /* need to add that */ | ||
| 665 | return add_range(range, nr_range, start, end); | ||
| 666 | } | ||
| 667 | |||
| 668 | static void __init | ||
| 669 | subtract_range(struct res_range *range, unsigned long start, unsigned long end) | ||
| 670 | { | ||
| 671 | int i, j; | ||
| 672 | |||
| 673 | for (j = 0; j < RANGE_NUM; j++) { | ||
| 674 | if (!range[j].end) | ||
| 675 | continue; | ||
| 676 | |||
| 677 | if (start <= range[j].start && end >= range[j].end) { | ||
| 678 | range[j].start = 0; | ||
| 679 | range[j].end = 0; | ||
| 680 | continue; | ||
| 681 | } | ||
| 682 | |||
| 683 | if (start <= range[j].start && end < range[j].end && | ||
| 684 | range[j].start < end + 1) { | ||
| 685 | range[j].start = end + 1; | ||
| 686 | continue; | ||
| 687 | } | ||
| 688 | |||
| 689 | |||
| 690 | if (start > range[j].start && end >= range[j].end && | ||
| 691 | range[j].end > start - 1) { | ||
| 692 | range[j].end = start - 1; | ||
| 693 | continue; | ||
| 694 | } | ||
| 695 | |||
| 696 | if (start > range[j].start && end < range[j].end) { | ||
| 697 | /* find the new spare */ | ||
| 698 | for (i = 0; i < RANGE_NUM; i++) { | ||
| 699 | if (range[i].end == 0) | ||
| 700 | break; | ||
| 701 | } | ||
| 702 | if (i < RANGE_NUM) { | ||
| 703 | range[i].end = range[j].end; | ||
| 704 | range[i].start = end + 1; | ||
| 705 | } else { | ||
| 706 | printk(KERN_ERR "run of slot in ranges\n"); | ||
| 707 | } | ||
| 708 | range[j].end = start - 1; | ||
| 709 | continue; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | static int __init cmp_range(const void *x1, const void *x2) | ||
| 715 | { | ||
| 716 | const struct res_range *r1 = x1; | ||
| 717 | const struct res_range *r2 = x2; | ||
| 718 | long start1, start2; | ||
| 719 | |||
| 720 | start1 = r1->start; | ||
| 721 | start2 = r2->start; | ||
| 722 | |||
| 723 | return start1 - start2; | ||
| 724 | } | ||
| 725 | |||
| 726 | struct var_mtrr_range_state { | ||
| 727 | unsigned long base_pfn; | ||
| 728 | unsigned long size_pfn; | ||
| 729 | mtrr_type type; | ||
| 730 | }; | ||
| 731 | |||
| 732 | struct var_mtrr_range_state __initdata range_state[RANGE_NUM]; | ||
| 733 | static int __initdata debug_print; | ||
| 734 | |||
| 735 | static int __init | ||
| 736 | x86_get_mtrr_mem_range(struct res_range *range, int nr_range, | ||
| 737 | unsigned long extra_remove_base, | ||
| 738 | unsigned long extra_remove_size) | ||
| 739 | { | ||
| 740 | unsigned long i, base, size; | ||
| 741 | mtrr_type type; | ||
| 742 | |||
| 743 | for (i = 0; i < num_var_ranges; i++) { | ||
| 744 | type = range_state[i].type; | ||
| 745 | if (type != MTRR_TYPE_WRBACK) | ||
| 746 | continue; | ||
| 747 | base = range_state[i].base_pfn; | ||
| 748 | size = range_state[i].size_pfn; | ||
| 749 | nr_range = add_range_with_merge(range, nr_range, base, | ||
| 750 | base + size - 1); | ||
| 751 | } | ||
| 752 | if (debug_print) { | ||
| 753 | printk(KERN_DEBUG "After WB checking\n"); | ||
| 754 | for (i = 0; i < nr_range; i++) | ||
| 755 | printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n", | ||
| 756 | range[i].start, range[i].end + 1); | ||
| 757 | } | ||
| 758 | |||
| 759 | /* take out UC ranges */ | ||
| 760 | for (i = 0; i < num_var_ranges; i++) { | ||
| 761 | type = range_state[i].type; | ||
| 762 | if (type != MTRR_TYPE_UNCACHABLE) | ||
| 763 | continue; | ||
| 764 | size = range_state[i].size_pfn; | ||
| 765 | if (!size) | ||
| 766 | continue; | ||
| 767 | base = range_state[i].base_pfn; | ||
| 768 | subtract_range(range, base, base + size - 1); | ||
| 769 | } | ||
| 770 | if (extra_remove_size) | ||
| 771 | subtract_range(range, extra_remove_base, | ||
| 772 | extra_remove_base + extra_remove_size - 1); | ||
| 773 | |||
| 774 | /* get new range num */ | ||
| 775 | nr_range = 0; | ||
| 776 | for (i = 0; i < RANGE_NUM; i++) { | ||
| 777 | if (!range[i].end) | ||
| 778 | continue; | ||
| 779 | nr_range++; | ||
| 780 | } | ||
| 781 | if (debug_print) { | ||
| 782 | printk(KERN_DEBUG "After UC checking\n"); | ||
| 783 | for (i = 0; i < nr_range; i++) | ||
| 784 | printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n", | ||
| 785 | range[i].start, range[i].end + 1); | ||
| 786 | } | ||
| 787 | |||
| 788 | /* sort the ranges */ | ||
| 789 | sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL); | ||
| 790 | if (debug_print) { | ||
| 791 | printk(KERN_DEBUG "After sorting\n"); | ||
| 792 | for (i = 0; i < nr_range; i++) | ||
| 793 | printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n", | ||
| 794 | range[i].start, range[i].end + 1); | ||
| 795 | } | ||
| 796 | |||
| 797 | /* clear those is not used */ | ||
| 798 | for (i = nr_range; i < RANGE_NUM; i++) | ||
| 799 | memset(&range[i], 0, sizeof(range[i])); | ||
| 800 | |||
| 801 | return nr_range; | ||
| 802 | } | ||
| 803 | |||
| 804 | static struct res_range __initdata range[RANGE_NUM]; | ||
| 805 | |||
| 806 | #ifdef CONFIG_MTRR_SANITIZER | ||
| 807 | |||
| 808 | static unsigned long __init sum_ranges(struct res_range *range, int nr_range) | ||
| 809 | { | ||
| 810 | unsigned long sum; | ||
| 811 | int i; | ||
| 812 | |||
| 813 | sum = 0; | ||
| 814 | for (i = 0; i < nr_range; i++) | ||
| 815 | sum += range[i].end + 1 - range[i].start; | ||
| 816 | |||
| 817 | return sum; | ||
| 818 | } | ||
| 819 | |||
| 820 | static int enable_mtrr_cleanup __initdata = | ||
| 821 | CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT; | ||
| 822 | |||
| 823 | static int __init disable_mtrr_cleanup_setup(char *str) | ||
| 824 | { | ||
| 825 | if (enable_mtrr_cleanup != -1) | ||
| 826 | enable_mtrr_cleanup = 0; | ||
| 827 | return 0; | ||
| 828 | } | ||
| 829 | early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup); | ||
| 830 | |||
| 831 | static int __init enable_mtrr_cleanup_setup(char *str) | ||
| 832 | { | ||
| 833 | if (enable_mtrr_cleanup != -1) | ||
| 834 | enable_mtrr_cleanup = 1; | ||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup); | ||
| 838 | |||
| 839 | struct var_mtrr_state { | ||
| 840 | unsigned long range_startk; | ||
| 841 | unsigned long range_sizek; | ||
| 842 | unsigned long chunk_sizek; | ||
| 843 | unsigned long gran_sizek; | ||
| 844 | unsigned int reg; | ||
| 845 | }; | ||
| 846 | |||
| 847 | static void __init | ||
| 848 | set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, | ||
| 849 | unsigned char type, unsigned int address_bits) | ||
| 850 | { | ||
| 851 | u32 base_lo, base_hi, mask_lo, mask_hi; | ||
| 852 | u64 base, mask; | ||
| 853 | |||
| 854 | if (!sizek) { | ||
| 855 | fill_mtrr_var_range(reg, 0, 0, 0, 0); | ||
| 856 | return; | ||
| 857 | } | ||
| 858 | |||
| 859 | mask = (1ULL << address_bits) - 1; | ||
| 860 | mask &= ~((((u64)sizek) << 10) - 1); | ||
| 861 | |||
| 862 | base = ((u64)basek) << 10; | ||
| 863 | |||
| 864 | base |= type; | ||
| 865 | mask |= 0x800; | ||
| 866 | |||
| 867 | base_lo = base & ((1ULL<<32) - 1); | ||
| 868 | base_hi = base >> 32; | ||
| 869 | |||
| 870 | mask_lo = mask & ((1ULL<<32) - 1); | ||
| 871 | mask_hi = mask >> 32; | ||
| 872 | |||
| 873 | fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi); | ||
| 874 | } | ||
| 875 | |||
| 876 | static void __init | ||
| 877 | save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, | ||
| 878 | unsigned char type) | ||
| 879 | { | ||
| 880 | range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10); | ||
| 881 | range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10); | ||
| 882 | range_state[reg].type = type; | ||
| 883 | } | ||
| 884 | |||
| 885 | static void __init | ||
| 886 | set_var_mtrr_all(unsigned int address_bits) | ||
| 887 | { | ||
| 888 | unsigned long basek, sizek; | ||
| 889 | unsigned char type; | ||
| 890 | unsigned int reg; | ||
| 891 | |||
| 892 | for (reg = 0; reg < num_var_ranges; reg++) { | ||
| 893 | basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10); | ||
| 894 | sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10); | ||
| 895 | type = range_state[reg].type; | ||
| 896 | |||
| 897 | set_var_mtrr(reg, basek, sizek, type, address_bits); | ||
| 898 | } | ||
| 899 | } | ||
| 900 | |||
| 901 | static unsigned int __init | ||
| 902 | range_to_mtrr(unsigned int reg, unsigned long range_startk, | ||
| 903 | unsigned long range_sizek, unsigned char type) | ||
| 904 | { | ||
| 905 | if (!range_sizek || (reg >= num_var_ranges)) | ||
| 906 | return reg; | ||
| 907 | |||
| 908 | while (range_sizek) { | ||
| 909 | unsigned long max_align, align; | ||
| 910 | unsigned long sizek; | ||
| 911 | |||
| 912 | /* Compute the maximum size I can make a range */ | ||
| 913 | if (range_startk) | ||
| 914 | max_align = ffs(range_startk) - 1; | ||
| 915 | else | ||
| 916 | max_align = 32; | ||
| 917 | align = fls(range_sizek) - 1; | ||
| 918 | if (align > max_align) | ||
| 919 | align = max_align; | ||
| 920 | |||
| 921 | sizek = 1 << align; | ||
| 922 | if (debug_print) | ||
| 923 | printk(KERN_DEBUG "Setting variable MTRR %d, " | ||
| 924 | "base: %ldMB, range: %ldMB, type %s\n", | ||
| 925 | reg, range_startk >> 10, sizek >> 10, | ||
| 926 | (type == MTRR_TYPE_UNCACHABLE)?"UC": | ||
| 927 | ((type == MTRR_TYPE_WRBACK)?"WB":"Other") | ||
| 928 | ); | ||
| 929 | save_var_mtrr(reg++, range_startk, sizek, type); | ||
| 930 | range_startk += sizek; | ||
| 931 | range_sizek -= sizek; | ||
| 932 | if (reg >= num_var_ranges) | ||
| 933 | break; | ||
| 934 | } | ||
| 935 | return reg; | ||
| 936 | } | ||
| 937 | |||
| 938 | static unsigned __init | ||
| 939 | range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek, | ||
| 940 | unsigned long sizek) | ||
| 941 | { | ||
| 942 | unsigned long hole_basek, hole_sizek; | ||
| 943 | unsigned long second_basek, second_sizek; | ||
| 944 | unsigned long range0_basek, range0_sizek; | ||
| 945 | unsigned long range_basek, range_sizek; | ||
| 946 | unsigned long chunk_sizek; | ||
| 947 | unsigned long gran_sizek; | ||
| 948 | |||
| 949 | hole_basek = 0; | ||
| 950 | hole_sizek = 0; | ||
| 951 | second_basek = 0; | ||
| 952 | second_sizek = 0; | ||
| 953 | chunk_sizek = state->chunk_sizek; | ||
| 954 | gran_sizek = state->gran_sizek; | ||
| 955 | |||
| 956 | /* align with gran size, prevent small block used up MTRRs */ | ||
| 957 | range_basek = ALIGN(state->range_startk, gran_sizek); | ||
| 958 | if ((range_basek > basek) && basek) | ||
| 959 | return second_sizek; | ||
| 960 | state->range_sizek -= (range_basek - state->range_startk); | ||
| 961 | range_sizek = ALIGN(state->range_sizek, gran_sizek); | ||
| 962 | |||
| 963 | while (range_sizek > state->range_sizek) { | ||
| 964 | range_sizek -= gran_sizek; | ||
| 965 | if (!range_sizek) | ||
| 966 | return 0; | ||
| 967 | } | ||
| 968 | state->range_sizek = range_sizek; | ||
| 969 | |||
| 970 | /* try to append some small hole */ | ||
| 971 | range0_basek = state->range_startk; | ||
| 972 | range0_sizek = ALIGN(state->range_sizek, chunk_sizek); | ||
| 973 | if (range0_sizek == state->range_sizek) { | ||
| 974 | if (debug_print) | ||
| 975 | printk(KERN_DEBUG "rangeX: %016lx - %016lx\n", | ||
| 976 | range0_basek<<10, | ||
| 977 | (range0_basek + state->range_sizek)<<10); | ||
| 978 | state->reg = range_to_mtrr(state->reg, range0_basek, | ||
| 979 | state->range_sizek, MTRR_TYPE_WRBACK); | ||
| 980 | return 0; | ||
| 981 | } | ||
| 982 | |||
| 983 | range0_sizek -= chunk_sizek; | ||
| 984 | if (range0_sizek && sizek) { | ||
| 985 | while (range0_basek + range0_sizek > (basek + sizek)) { | ||
| 986 | range0_sizek -= chunk_sizek; | ||
| 987 | if (!range0_sizek) | ||
| 988 | break; | ||
| 989 | } | ||
| 990 | } | ||
| 991 | |||
| 992 | if (range0_sizek) { | ||
| 993 | if (debug_print) | ||
| 994 | printk(KERN_DEBUG "range0: %016lx - %016lx\n", | ||
| 995 | range0_basek<<10, | ||
| 996 | (range0_basek + range0_sizek)<<10); | ||
| 997 | state->reg = range_to_mtrr(state->reg, range0_basek, | ||
| 998 | range0_sizek, MTRR_TYPE_WRBACK); | ||
| 999 | |||
| 1000 | } | ||
| 1001 | |||
| 1002 | range_basek = range0_basek + range0_sizek; | ||
| 1003 | range_sizek = chunk_sizek; | ||
| 1004 | |||
| 1005 | if (range_basek + range_sizek > basek && | ||
| 1006 | range_basek + range_sizek <= (basek + sizek)) { | ||
| 1007 | /* one hole */ | ||
| 1008 | second_basek = basek; | ||
| 1009 | second_sizek = range_basek + range_sizek - basek; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | /* if last piece, only could one hole near end */ | ||
| 1013 | if ((second_basek || !basek) && | ||
| 1014 | range_sizek - (state->range_sizek - range0_sizek) - second_sizek < | ||
| 1015 | (chunk_sizek >> 1)) { | ||
| 1016 | /* | ||
| 1017 | * one hole in middle (second_sizek is 0) or at end | ||
| 1018 | * (second_sizek is 0 ) | ||
| 1019 | */ | ||
| 1020 | hole_sizek = range_sizek - (state->range_sizek - range0_sizek) | ||
| 1021 | - second_sizek; | ||
| 1022 | hole_basek = range_basek + range_sizek - hole_sizek | ||
| 1023 | - second_sizek; | ||
| 1024 | } else { | ||
| 1025 | /* fallback for big hole, or several holes */ | ||
| 1026 | range_sizek = state->range_sizek - range0_sizek; | ||
| 1027 | second_basek = 0; | ||
| 1028 | second_sizek = 0; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | if (debug_print) | ||
| 1032 | printk(KERN_DEBUG "range: %016lx - %016lx\n", range_basek<<10, | ||
| 1033 | (range_basek + range_sizek)<<10); | ||
| 1034 | state->reg = range_to_mtrr(state->reg, range_basek, range_sizek, | ||
| 1035 | MTRR_TYPE_WRBACK); | ||
| 1036 | if (hole_sizek) { | ||
| 1037 | if (debug_print) | ||
| 1038 | printk(KERN_DEBUG "hole: %016lx - %016lx\n", | ||
| 1039 | hole_basek<<10, (hole_basek + hole_sizek)<<10); | ||
| 1040 | state->reg = range_to_mtrr(state->reg, hole_basek, hole_sizek, | ||
| 1041 | MTRR_TYPE_UNCACHABLE); | ||
| 1042 | |||
| 1043 | } | ||
| 1044 | |||
| 1045 | return second_sizek; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static void __init | ||
| 1049 | set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn, | ||
| 1050 | unsigned long size_pfn) | ||
| 1051 | { | ||
| 1052 | unsigned long basek, sizek; | ||
| 1053 | unsigned long second_sizek = 0; | ||
| 1054 | |||
| 1055 | if (state->reg >= num_var_ranges) | ||
| 1056 | return; | ||
| 1057 | |||
| 1058 | basek = base_pfn << (PAGE_SHIFT - 10); | ||
| 1059 | sizek = size_pfn << (PAGE_SHIFT - 10); | ||
| 1060 | |||
| 1061 | /* See if I can merge with the last range */ | ||
| 1062 | if ((basek <= 1024) || | ||
| 1063 | (state->range_startk + state->range_sizek == basek)) { | ||
| 1064 | unsigned long endk = basek + sizek; | ||
| 1065 | state->range_sizek = endk - state->range_startk; | ||
| 1066 | return; | ||
| 1067 | } | ||
| 1068 | /* Write the range mtrrs */ | ||
| 1069 | if (state->range_sizek != 0) | ||
| 1070 | second_sizek = range_to_mtrr_with_hole(state, basek, sizek); | ||
| 1071 | |||
| 1072 | /* Allocate an msr */ | ||
| 1073 | state->range_startk = basek + second_sizek; | ||
| 1074 | state->range_sizek = sizek - second_sizek; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /* mininum size of mtrr block that can take hole */ | ||
| 1078 | static u64 mtrr_chunk_size __initdata = (256ULL<<20); | ||
| 1079 | |||
| 1080 | static int __init parse_mtrr_chunk_size_opt(char *p) | ||
| 1081 | { | ||
| 1082 | if (!p) | ||
| 1083 | return -EINVAL; | ||
| 1084 | mtrr_chunk_size = memparse(p, &p); | ||
| 1085 | return 0; | ||
| 1086 | } | ||
| 1087 | early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt); | ||
| 1088 | |||
| 1089 | /* granity of mtrr of block */ | ||
| 1090 | static u64 mtrr_gran_size __initdata; | ||
| 1091 | |||
| 1092 | static int __init parse_mtrr_gran_size_opt(char *p) | ||
| 1093 | { | ||
| 1094 | if (!p) | ||
| 1095 | return -EINVAL; | ||
| 1096 | mtrr_gran_size = memparse(p, &p); | ||
| 1097 | return 0; | ||
| 1098 | } | ||
| 1099 | early_param("mtrr_gran_size", parse_mtrr_gran_size_opt); | ||
| 1100 | |||
| 1101 | static int nr_mtrr_spare_reg __initdata = | ||
| 1102 | CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT; | ||
| 1103 | |||
| 1104 | static int __init parse_mtrr_spare_reg(char *arg) | ||
| 1105 | { | ||
| 1106 | if (arg) | ||
| 1107 | nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0); | ||
| 1108 | return 0; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg); | ||
| 1112 | |||
| 1113 | static int __init | ||
| 1114 | x86_setup_var_mtrrs(struct res_range *range, int nr_range, | ||
| 1115 | u64 chunk_size, u64 gran_size) | ||
| 1116 | { | ||
| 1117 | struct var_mtrr_state var_state; | ||
| 1118 | int i; | ||
| 1119 | int num_reg; | ||
| 1120 | |||
| 1121 | var_state.range_startk = 0; | ||
| 1122 | var_state.range_sizek = 0; | ||
| 1123 | var_state.reg = 0; | ||
| 1124 | var_state.chunk_sizek = chunk_size >> 10; | ||
| 1125 | var_state.gran_sizek = gran_size >> 10; | ||
| 1126 | |||
| 1127 | memset(range_state, 0, sizeof(range_state)); | ||
| 1128 | |||
| 1129 | /* Write the range etc */ | ||
| 1130 | for (i = 0; i < nr_range; i++) | ||
| 1131 | set_var_mtrr_range(&var_state, range[i].start, | ||
| 1132 | range[i].end - range[i].start + 1); | ||
| 1133 | |||
| 1134 | /* Write the last range */ | ||
| 1135 | if (var_state.range_sizek != 0) | ||
| 1136 | range_to_mtrr_with_hole(&var_state, 0, 0); | ||
| 1137 | |||
| 1138 | num_reg = var_state.reg; | ||
| 1139 | /* Clear out the extra MTRR's */ | ||
| 1140 | while (var_state.reg < num_var_ranges) { | ||
| 1141 | save_var_mtrr(var_state.reg, 0, 0, 0); | ||
| 1142 | var_state.reg++; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | return num_reg; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | struct mtrr_cleanup_result { | ||
| 1149 | unsigned long gran_sizek; | ||
| 1150 | unsigned long chunk_sizek; | ||
| 1151 | unsigned long lose_cover_sizek; | ||
| 1152 | unsigned int num_reg; | ||
| 1153 | int bad; | ||
| 1154 | }; | ||
| 1155 | |||
| 1156 | /* | ||
| 1157 | * gran_size: 1M, 2M, ..., 2G | ||
| 1158 | * chunk size: gran_size, ..., 4G | ||
| 1159 | * so we need (2+13)*6 | ||
| 1160 | */ | ||
| 1161 | #define NUM_RESULT 90 | ||
| 1162 | #define PSHIFT (PAGE_SHIFT - 10) | ||
| 1163 | |||
| 1164 | static struct mtrr_cleanup_result __initdata result[NUM_RESULT]; | ||
| 1165 | static struct res_range __initdata range_new[RANGE_NUM]; | ||
| 1166 | static unsigned long __initdata min_loss_pfn[RANGE_NUM]; | ||
| 1167 | |||
| 1168 | static int __init mtrr_cleanup(unsigned address_bits) | ||
| 1169 | { | ||
| 1170 | unsigned long extra_remove_base, extra_remove_size; | ||
| 1171 | unsigned long i, base, size, def, dummy; | ||
| 1172 | mtrr_type type; | ||
| 1173 | int nr_range, nr_range_new; | ||
| 1174 | u64 chunk_size, gran_size; | ||
| 1175 | unsigned long range_sums, range_sums_new; | ||
| 1176 | int index_good; | ||
| 1177 | int num_reg_good; | ||
| 1178 | |||
| 1179 | /* extra one for all 0 */ | ||
| 1180 | int num[MTRR_NUM_TYPES + 1]; | ||
| 1181 | |||
| 1182 | if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) | ||
| 1183 | return 0; | ||
| 1184 | rdmsr(MTRRdefType_MSR, def, dummy); | ||
| 1185 | def &= 0xff; | ||
| 1186 | if (def != MTRR_TYPE_UNCACHABLE) | ||
| 1187 | return 0; | ||
| 1188 | |||
| 1189 | /* get it and store it aside */ | ||
| 1190 | memset(range_state, 0, sizeof(range_state)); | ||
| 1191 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1192 | mtrr_if->get(i, &base, &size, &type); | ||
| 1193 | range_state[i].base_pfn = base; | ||
| 1194 | range_state[i].size_pfn = size; | ||
| 1195 | range_state[i].type = type; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | /* check entries number */ | ||
| 1199 | memset(num, 0, sizeof(num)); | ||
| 1200 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1201 | type = range_state[i].type; | ||
| 1202 | size = range_state[i].size_pfn; | ||
| 1203 | if (type >= MTRR_NUM_TYPES) | ||
| 1204 | continue; | ||
| 1205 | if (!size) | ||
| 1206 | type = MTRR_NUM_TYPES; | ||
| 1207 | num[type]++; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | /* check if we got UC entries */ | ||
| 1211 | if (!num[MTRR_TYPE_UNCACHABLE]) | ||
| 1212 | return 0; | ||
| 1213 | |||
| 1214 | /* check if we only had WB and UC */ | ||
| 1215 | if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] != | ||
| 1216 | num_var_ranges - num[MTRR_NUM_TYPES]) | ||
| 1217 | return 0; | ||
| 1218 | |||
| 1219 | memset(range, 0, sizeof(range)); | ||
| 1220 | extra_remove_size = 0; | ||
| 1221 | if (mtrr_tom2) { | ||
| 1222 | extra_remove_base = 1 << (32 - PAGE_SHIFT); | ||
| 1223 | extra_remove_size = | ||
| 1224 | (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base; | ||
| 1225 | } | ||
| 1226 | nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base, | ||
| 1227 | extra_remove_size); | ||
| 1228 | range_sums = sum_ranges(range, nr_range); | ||
| 1229 | printk(KERN_INFO "total RAM coverred: %ldM\n", | ||
| 1230 | range_sums >> (20 - PAGE_SHIFT)); | ||
| 1231 | |||
| 1232 | if (mtrr_chunk_size && mtrr_gran_size) { | ||
| 1233 | int num_reg; | ||
| 1234 | |||
| 1235 | debug_print = 1; | ||
| 1236 | /* convert ranges to var ranges state */ | ||
| 1237 | num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size, | ||
| 1238 | mtrr_gran_size); | ||
| 1239 | |||
| 1240 | /* we got new setting in range_state, check it */ | ||
| 1241 | memset(range_new, 0, sizeof(range_new)); | ||
| 1242 | nr_range_new = x86_get_mtrr_mem_range(range_new, 0, | ||
| 1243 | extra_remove_base, | ||
| 1244 | extra_remove_size); | ||
| 1245 | range_sums_new = sum_ranges(range_new, nr_range_new); | ||
| 1246 | |||
| 1247 | i = 0; | ||
| 1248 | result[i].chunk_sizek = mtrr_chunk_size >> 10; | ||
| 1249 | result[i].gran_sizek = mtrr_gran_size >> 10; | ||
| 1250 | result[i].num_reg = num_reg; | ||
| 1251 | if (range_sums < range_sums_new) { | ||
| 1252 | result[i].lose_cover_sizek = | ||
| 1253 | (range_sums_new - range_sums) << PSHIFT; | ||
| 1254 | result[i].bad = 1; | ||
| 1255 | } else | ||
| 1256 | result[i].lose_cover_sizek = | ||
| 1257 | (range_sums - range_sums_new) << PSHIFT; | ||
| 1258 | |||
| 1259 | printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t", | ||
| 1260 | result[i].bad?"*BAD*":" ", result[i].gran_sizek >> 10, | ||
| 1261 | result[i].chunk_sizek >> 10); | ||
| 1262 | printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ldM \n", | ||
| 1263 | result[i].num_reg, result[i].bad?"-":"", | ||
| 1264 | result[i].lose_cover_sizek >> 10); | ||
| 1265 | if (!result[i].bad) { | ||
| 1266 | set_var_mtrr_all(address_bits); | ||
| 1267 | return 1; | ||
| 1268 | } | ||
| 1269 | printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, " | ||
| 1270 | "will find optimal one\n"); | ||
| 1271 | debug_print = 0; | ||
| 1272 | memset(result, 0, sizeof(result[0])); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | i = 0; | ||
| 1276 | memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn)); | ||
| 1277 | memset(result, 0, sizeof(result)); | ||
| 1278 | for (gran_size = (1ULL<<20); gran_size < (1ULL<<32); gran_size <<= 1) { | ||
| 1279 | for (chunk_size = gran_size; chunk_size < (1ULL<<33); | ||
| 1280 | chunk_size <<= 1) { | ||
| 1281 | int num_reg; | ||
| 1282 | |||
| 1283 | if (debug_print) | ||
| 1284 | printk(KERN_INFO | ||
| 1285 | "\ngran_size: %lldM chunk_size_size: %lldM\n", | ||
| 1286 | gran_size >> 20, chunk_size >> 20); | ||
| 1287 | if (i >= NUM_RESULT) | ||
| 1288 | continue; | ||
| 1289 | |||
| 1290 | /* convert ranges to var ranges state */ | ||
| 1291 | num_reg = x86_setup_var_mtrrs(range, nr_range, | ||
| 1292 | chunk_size, gran_size); | ||
| 1293 | |||
| 1294 | /* we got new setting in range_state, check it */ | ||
| 1295 | memset(range_new, 0, sizeof(range_new)); | ||
| 1296 | nr_range_new = x86_get_mtrr_mem_range(range_new, 0, | ||
| 1297 | extra_remove_base, extra_remove_size); | ||
| 1298 | range_sums_new = sum_ranges(range_new, nr_range_new); | ||
| 1299 | |||
| 1300 | result[i].chunk_sizek = chunk_size >> 10; | ||
| 1301 | result[i].gran_sizek = gran_size >> 10; | ||
| 1302 | result[i].num_reg = num_reg; | ||
| 1303 | if (range_sums < range_sums_new) { | ||
| 1304 | result[i].lose_cover_sizek = | ||
| 1305 | (range_sums_new - range_sums) << PSHIFT; | ||
| 1306 | result[i].bad = 1; | ||
| 1307 | } else | ||
| 1308 | result[i].lose_cover_sizek = | ||
| 1309 | (range_sums - range_sums_new) << PSHIFT; | ||
| 1310 | |||
| 1311 | /* double check it */ | ||
| 1312 | if (!result[i].bad && !result[i].lose_cover_sizek) { | ||
| 1313 | if (nr_range_new != nr_range || | ||
| 1314 | memcmp(range, range_new, sizeof(range))) | ||
| 1315 | result[i].bad = 1; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | if (!result[i].bad && (range_sums - range_sums_new < | ||
| 1319 | min_loss_pfn[num_reg])) { | ||
| 1320 | min_loss_pfn[num_reg] = | ||
| 1321 | range_sums - range_sums_new; | ||
| 1322 | } | ||
| 1323 | i++; | ||
| 1324 | } | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | /* print out all */ | ||
| 1328 | for (i = 0; i < NUM_RESULT; i++) { | ||
| 1329 | printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t", | ||
| 1330 | result[i].bad?"*BAD* ":" ", result[i].gran_sizek >> 10, | ||
| 1331 | result[i].chunk_sizek >> 10); | ||
| 1332 | printk(KERN_CONT "num_reg: %d \tlose RAM: %s%ldM\n", | ||
| 1333 | result[i].num_reg, result[i].bad?"-":"", | ||
| 1334 | result[i].lose_cover_sizek >> 10); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | /* try to find the optimal index */ | ||
| 1338 | if (nr_mtrr_spare_reg >= num_var_ranges) | ||
| 1339 | nr_mtrr_spare_reg = num_var_ranges - 1; | ||
| 1340 | num_reg_good = -1; | ||
| 1341 | for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { | ||
| 1342 | if (!min_loss_pfn[i]) { | ||
| 1343 | num_reg_good = i; | ||
| 1344 | break; | ||
| 1345 | } | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | index_good = -1; | ||
| 1349 | if (num_reg_good != -1) { | ||
| 1350 | for (i = 0; i < NUM_RESULT; i++) { | ||
| 1351 | if (!result[i].bad && | ||
| 1352 | result[i].num_reg == num_reg_good && | ||
| 1353 | !result[i].lose_cover_sizek) { | ||
| 1354 | index_good = i; | ||
| 1355 | break; | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | if (index_good != -1) { | ||
| 1361 | printk(KERN_INFO "Found optimal setting for mtrr clean up\n"); | ||
| 1362 | i = index_good; | ||
| 1363 | printk(KERN_INFO "gran_size: %ldM \tchunk_size: %ldM \t", | ||
| 1364 | result[i].gran_sizek >> 10, | ||
| 1365 | result[i].chunk_sizek >> 10); | ||
| 1366 | printk(KERN_CONT "num_reg: %d \tlose RAM: %ldM\n", | ||
| 1367 | result[i].num_reg, | ||
| 1368 | result[i].lose_cover_sizek >> 10); | ||
| 1369 | /* convert ranges to var ranges state */ | ||
| 1370 | chunk_size = result[i].chunk_sizek; | ||
| 1371 | chunk_size <<= 10; | ||
| 1372 | gran_size = result[i].gran_sizek; | ||
| 1373 | gran_size <<= 10; | ||
| 1374 | debug_print = 1; | ||
| 1375 | x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size); | ||
| 1376 | set_var_mtrr_all(address_bits); | ||
| 1377 | return 1; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n"); | ||
| 1381 | printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n"); | ||
| 1382 | |||
| 1383 | return 0; | ||
| 1384 | } | ||
| 1385 | #else | ||
| 1386 | static int __init mtrr_cleanup(unsigned address_bits) | ||
| 1387 | { | ||
| 1388 | return 0; | ||
| 1389 | } | ||
| 1390 | #endif | ||
| 1391 | |||
| 1392 | static int __initdata changed_by_mtrr_cleanup; | ||
| 1393 | |||
| 612 | static int disable_mtrr_trim; | 1394 | static int disable_mtrr_trim; |
| 613 | 1395 | ||
| 614 | static int __init disable_mtrr_trim_setup(char *str) | 1396 | static int __init disable_mtrr_trim_setup(char *str) |
| @@ -648,6 +1430,19 @@ int __init amd_special_default_mtrr(void) | |||
| 648 | return 0; | 1430 | return 0; |
| 649 | } | 1431 | } |
| 650 | 1432 | ||
| 1433 | static u64 __init real_trim_memory(unsigned long start_pfn, | ||
| 1434 | unsigned long limit_pfn) | ||
| 1435 | { | ||
| 1436 | u64 trim_start, trim_size; | ||
| 1437 | trim_start = start_pfn; | ||
| 1438 | trim_start <<= PAGE_SHIFT; | ||
| 1439 | trim_size = limit_pfn; | ||
| 1440 | trim_size <<= PAGE_SHIFT; | ||
| 1441 | trim_size -= trim_start; | ||
| 1442 | |||
| 1443 | return e820_update_range(trim_start, trim_size, E820_RAM, | ||
| 1444 | E820_RESERVED); | ||
| 1445 | } | ||
| 651 | /** | 1446 | /** |
| 652 | * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs | 1447 | * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs |
| 653 | * @end_pfn: ending page frame number | 1448 | * @end_pfn: ending page frame number |
| @@ -663,8 +1458,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 663 | { | 1458 | { |
| 664 | unsigned long i, base, size, highest_pfn = 0, def, dummy; | 1459 | unsigned long i, base, size, highest_pfn = 0, def, dummy; |
| 665 | mtrr_type type; | 1460 | mtrr_type type; |
| 666 | u64 trim_start, trim_size; | 1461 | int nr_range; |
| 1462 | u64 total_trim_size; | ||
| 667 | 1463 | ||
| 1464 | /* extra one for all 0 */ | ||
| 1465 | int num[MTRR_NUM_TYPES + 1]; | ||
| 668 | /* | 1466 | /* |
| 669 | * Make sure we only trim uncachable memory on machines that | 1467 | * Make sure we only trim uncachable memory on machines that |
| 670 | * support the Intel MTRR architecture: | 1468 | * support the Intel MTRR architecture: |
| @@ -676,14 +1474,22 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 676 | if (def != MTRR_TYPE_UNCACHABLE) | 1474 | if (def != MTRR_TYPE_UNCACHABLE) |
| 677 | return 0; | 1475 | return 0; |
| 678 | 1476 | ||
| 679 | if (amd_special_default_mtrr()) | 1477 | /* get it and store it aside */ |
| 680 | return 0; | 1478 | memset(range_state, 0, sizeof(range_state)); |
| 1479 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1480 | mtrr_if->get(i, &base, &size, &type); | ||
| 1481 | range_state[i].base_pfn = base; | ||
| 1482 | range_state[i].size_pfn = size; | ||
| 1483 | range_state[i].type = type; | ||
| 1484 | } | ||
| 681 | 1485 | ||
| 682 | /* Find highest cached pfn */ | 1486 | /* Find highest cached pfn */ |
| 683 | for (i = 0; i < num_var_ranges; i++) { | 1487 | for (i = 0; i < num_var_ranges; i++) { |
| 684 | mtrr_if->get(i, &base, &size, &type); | 1488 | type = range_state[i].type; |
| 685 | if (type != MTRR_TYPE_WRBACK) | 1489 | if (type != MTRR_TYPE_WRBACK) |
| 686 | continue; | 1490 | continue; |
| 1491 | base = range_state[i].base_pfn; | ||
| 1492 | size = range_state[i].size_pfn; | ||
| 687 | if (highest_pfn < base + size) | 1493 | if (highest_pfn < base + size) |
| 688 | highest_pfn = base + size; | 1494 | highest_pfn = base + size; |
| 689 | } | 1495 | } |
| @@ -698,22 +1504,65 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 698 | return 0; | 1504 | return 0; |
| 699 | } | 1505 | } |
| 700 | 1506 | ||
| 701 | if (highest_pfn < end_pfn) { | 1507 | /* check entries number */ |
| 1508 | memset(num, 0, sizeof(num)); | ||
| 1509 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1510 | type = range_state[i].type; | ||
| 1511 | if (type >= MTRR_NUM_TYPES) | ||
| 1512 | continue; | ||
| 1513 | size = range_state[i].size_pfn; | ||
| 1514 | if (!size) | ||
| 1515 | type = MTRR_NUM_TYPES; | ||
| 1516 | num[type]++; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | /* no entry for WB? */ | ||
| 1520 | if (!num[MTRR_TYPE_WRBACK]) | ||
| 1521 | return 0; | ||
| 1522 | |||
| 1523 | /* check if we only had WB and UC */ | ||
| 1524 | if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] != | ||
| 1525 | num_var_ranges - num[MTRR_NUM_TYPES]) | ||
| 1526 | return 0; | ||
| 1527 | |||
| 1528 | memset(range, 0, sizeof(range)); | ||
| 1529 | nr_range = 0; | ||
| 1530 | if (mtrr_tom2) { | ||
| 1531 | range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT)); | ||
| 1532 | range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1; | ||
| 1533 | if (highest_pfn < range[nr_range].end + 1) | ||
| 1534 | highest_pfn = range[nr_range].end + 1; | ||
| 1535 | nr_range++; | ||
| 1536 | } | ||
| 1537 | nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0); | ||
| 1538 | |||
| 1539 | total_trim_size = 0; | ||
| 1540 | /* check the head */ | ||
| 1541 | if (range[0].start) | ||
| 1542 | total_trim_size += real_trim_memory(0, range[0].start); | ||
| 1543 | /* check the holes */ | ||
| 1544 | for (i = 0; i < nr_range - 1; i++) { | ||
| 1545 | if (range[i].end + 1 < range[i+1].start) | ||
| 1546 | total_trim_size += real_trim_memory(range[i].end + 1, | ||
| 1547 | range[i+1].start); | ||
| 1548 | } | ||
| 1549 | /* check the top */ | ||
| 1550 | i = nr_range - 1; | ||
| 1551 | if (range[i].end + 1 < end_pfn) | ||
| 1552 | total_trim_size += real_trim_memory(range[i].end + 1, | ||
| 1553 | end_pfn); | ||
| 1554 | |||
| 1555 | if (total_trim_size) { | ||
| 702 | printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" | 1556 | printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" |
| 703 | " all of memory, losing %luMB of RAM.\n", | 1557 | " all of memory, losing %lluMB of RAM.\n", |
| 704 | (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT)); | 1558 | total_trim_size >> 20); |
| 705 | 1559 | ||
| 706 | WARN_ON(1); | 1560 | if (!changed_by_mtrr_cleanup) |
| 1561 | WARN_ON(1); | ||
| 707 | 1562 | ||
| 708 | printk(KERN_INFO "update e820 for mtrr\n"); | 1563 | printk(KERN_INFO "update e820 for mtrr\n"); |
| 709 | trim_start = highest_pfn; | ||
| 710 | trim_start <<= PAGE_SHIFT; | ||
| 711 | trim_size = end_pfn; | ||
| 712 | trim_size <<= PAGE_SHIFT; | ||
| 713 | trim_size -= trim_start; | ||
| 714 | update_memory_range(trim_start, trim_size, E820_RAM, | ||
| 715 | E820_RESERVED); | ||
| 716 | update_e820(); | 1564 | update_e820(); |
| 1565 | |||
| 717 | return 1; | 1566 | return 1; |
| 718 | } | 1567 | } |
| 719 | 1568 | ||
| @@ -729,18 +1578,21 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 729 | */ | 1578 | */ |
| 730 | void __init mtrr_bp_init(void) | 1579 | void __init mtrr_bp_init(void) |
| 731 | { | 1580 | { |
| 1581 | u32 phys_addr; | ||
| 732 | init_ifs(); | 1582 | init_ifs(); |
| 733 | 1583 | ||
| 1584 | phys_addr = 32; | ||
| 1585 | |||
| 734 | if (cpu_has_mtrr) { | 1586 | if (cpu_has_mtrr) { |
| 735 | mtrr_if = &generic_mtrr_ops; | 1587 | mtrr_if = &generic_mtrr_ops; |
| 736 | size_or_mask = 0xff000000; /* 36 bits */ | 1588 | size_or_mask = 0xff000000; /* 36 bits */ |
| 737 | size_and_mask = 0x00f00000; | 1589 | size_and_mask = 0x00f00000; |
| 1590 | phys_addr = 36; | ||
| 738 | 1591 | ||
| 739 | /* This is an AMD specific MSR, but we assume(hope?) that | 1592 | /* This is an AMD specific MSR, but we assume(hope?) that |
| 740 | Intel will implement it to when they extend the address | 1593 | Intel will implement it to when they extend the address |
| 741 | bus of the Xeon. */ | 1594 | bus of the Xeon. */ |
| 742 | if (cpuid_eax(0x80000000) >= 0x80000008) { | 1595 | if (cpuid_eax(0x80000000) >= 0x80000008) { |
| 743 | u32 phys_addr; | ||
| 744 | phys_addr = cpuid_eax(0x80000008) & 0xff; | 1596 | phys_addr = cpuid_eax(0x80000008) & 0xff; |
| 745 | /* CPUID workaround for Intel 0F33/0F34 CPU */ | 1597 | /* CPUID workaround for Intel 0F33/0F34 CPU */ |
| 746 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && | 1598 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && |
| @@ -758,6 +1610,7 @@ void __init mtrr_bp_init(void) | |||
| 758 | don't support PAE */ | 1610 | don't support PAE */ |
| 759 | size_or_mask = 0xfff00000; /* 32 bits */ | 1611 | size_or_mask = 0xfff00000; /* 32 bits */ |
| 760 | size_and_mask = 0; | 1612 | size_and_mask = 0; |
| 1613 | phys_addr = 32; | ||
| 761 | } | 1614 | } |
| 762 | } else { | 1615 | } else { |
| 763 | switch (boot_cpu_data.x86_vendor) { | 1616 | switch (boot_cpu_data.x86_vendor) { |
| @@ -791,8 +1644,15 @@ void __init mtrr_bp_init(void) | |||
| 791 | if (mtrr_if) { | 1644 | if (mtrr_if) { |
| 792 | set_num_var_ranges(); | 1645 | set_num_var_ranges(); |
| 793 | init_table(); | 1646 | init_table(); |
| 794 | if (use_intel()) | 1647 | if (use_intel()) { |
| 795 | get_mtrr_state(); | 1648 | get_mtrr_state(); |
| 1649 | |||
| 1650 | if (mtrr_cleanup(phys_addr)) { | ||
| 1651 | changed_by_mtrr_cleanup = 1; | ||
| 1652 | mtrr_if->set_all(); | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | } | ||
| 796 | } | 1656 | } |
| 797 | } | 1657 | } |
| 798 | 1658 | ||
| @@ -829,9 +1689,10 @@ static int __init mtrr_init_finialize(void) | |||
| 829 | { | 1689 | { |
| 830 | if (!mtrr_if) | 1690 | if (!mtrr_if) |
| 831 | return 0; | 1691 | return 0; |
| 832 | if (use_intel()) | 1692 | if (use_intel()) { |
| 833 | mtrr_state_warn(); | 1693 | if (!changed_by_mtrr_cleanup) |
| 834 | else { | 1694 | mtrr_state_warn(); |
| 1695 | } else { | ||
| 835 | /* The CPUs haven't MTRR and seem to not support SMP. They have | 1696 | /* The CPUs haven't MTRR and seem to not support SMP. They have |
| 836 | * specific drivers, we use a tricky method to support | 1697 | * specific drivers, we use a tricky method to support |
| 837 | * suspend/resume for them. | 1698 | * suspend/resume for them. |
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index 2cc77eb6fea3..2dc4ec656b23 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h | |||
| @@ -81,6 +81,8 @@ void set_mtrr_done(struct set_mtrr_context *ctxt); | |||
| 81 | void set_mtrr_cache_disable(struct set_mtrr_context *ctxt); | 81 | void set_mtrr_cache_disable(struct set_mtrr_context *ctxt); |
| 82 | void set_mtrr_prepare_save(struct set_mtrr_context *ctxt); | 82 | void set_mtrr_prepare_save(struct set_mtrr_context *ctxt); |
| 83 | 83 | ||
| 84 | void fill_mtrr_var_range(unsigned int index, | ||
| 85 | u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi); | ||
| 84 | void get_mtrr_state(void); | 86 | void get_mtrr_state(void); |
| 85 | 87 | ||
| 86 | extern void set_mtrr_ops(struct mtrr_ops * ops); | 88 | extern void set_mtrr_ops(struct mtrr_ops * ops); |
| @@ -92,6 +94,7 @@ extern struct mtrr_ops * mtrr_if; | |||
| 92 | #define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1) | 94 | #define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1) |
| 93 | 95 | ||
| 94 | extern unsigned int num_var_ranges; | 96 | extern unsigned int num_var_ranges; |
| 97 | extern u64 mtrr_tom2; | ||
| 95 | 98 | ||
| 96 | void mtrr_state_warn(void); | 99 | void mtrr_state_warn(void); |
| 97 | const char *mtrr_attrib_to_str(int x); | 100 | const char *mtrr_attrib_to_str(int x); |
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820.c index 124480c0008d..7b613d2efb04 100644 --- a/arch/x86/kernel/e820_64.c +++ b/arch/x86/kernel/e820.c | |||
| @@ -17,171 +17,30 @@ | |||
| 17 | #include <linux/kexec.h> | 17 | #include <linux/kexec.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
| 20 | #include <linux/suspend.h> | ||
| 21 | #include <linux/pfn.h> | 20 | #include <linux/pfn.h> |
| 21 | #include <linux/suspend.h> | ||
| 22 | 22 | ||
| 23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
| 24 | #include <asm/page.h> | 24 | #include <asm/page.h> |
| 25 | #include <asm/e820.h> | 25 | #include <asm/e820.h> |
| 26 | #include <asm/proto.h> | 26 | #include <asm/proto.h> |
| 27 | #include <asm/setup.h> | 27 | #include <asm/setup.h> |
| 28 | #include <asm/sections.h> | ||
| 29 | #include <asm/kdebug.h> | ||
| 30 | #include <asm/trampoline.h> | 28 | #include <asm/trampoline.h> |
| 31 | 29 | ||
| 32 | struct e820map e820; | 30 | struct e820map e820; |
| 33 | 31 | ||
| 34 | /* | 32 | /* For PCI or other memory-mapped resources */ |
| 35 | * PFN of last memory page. | 33 | unsigned long pci_mem_start = 0xaeedbabe; |
| 36 | */ | 34 | #ifdef CONFIG_PCI |
| 37 | unsigned long end_pfn; | 35 | EXPORT_SYMBOL(pci_mem_start); |
| 38 | |||
| 39 | /* | ||
| 40 | * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. | ||
| 41 | * The direct mapping extends to max_pfn_mapped, so that we can directly access | ||
| 42 | * apertures, ACPI and other tables without having to play with fixmaps. | ||
| 43 | */ | ||
| 44 | unsigned long max_pfn_mapped; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Last pfn which the user wants to use. | ||
| 48 | */ | ||
| 49 | static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Early reserved memory areas. | ||
| 53 | */ | ||
| 54 | #define MAX_EARLY_RES 20 | ||
| 55 | |||
| 56 | struct early_res { | ||
| 57 | unsigned long start, end; | ||
| 58 | char name[16]; | ||
| 59 | }; | ||
| 60 | static struct early_res early_res[MAX_EARLY_RES] __initdata = { | ||
| 61 | { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ | ||
| 62 | #ifdef CONFIG_X86_TRAMPOLINE | ||
| 63 | { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" }, | ||
| 64 | #endif | 36 | #endif |
| 65 | {} | ||
| 66 | }; | ||
| 67 | |||
| 68 | void __init reserve_early(unsigned long start, unsigned long end, char *name) | ||
| 69 | { | ||
| 70 | int i; | ||
| 71 | struct early_res *r; | ||
| 72 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 73 | r = &early_res[i]; | ||
| 74 | if (end > r->start && start < r->end) | ||
| 75 | panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n", | ||
| 76 | start, end - 1, name?name:"", r->start, r->end - 1, r->name); | ||
| 77 | } | ||
| 78 | if (i >= MAX_EARLY_RES) | ||
| 79 | panic("Too many early reservations"); | ||
| 80 | r = &early_res[i]; | ||
| 81 | r->start = start; | ||
| 82 | r->end = end; | ||
| 83 | if (name) | ||
| 84 | strncpy(r->name, name, sizeof(r->name) - 1); | ||
| 85 | } | ||
| 86 | |||
| 87 | void __init free_early(unsigned long start, unsigned long end) | ||
| 88 | { | ||
| 89 | struct early_res *r; | ||
| 90 | int i, j; | ||
| 91 | |||
| 92 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 93 | r = &early_res[i]; | ||
| 94 | if (start == r->start && end == r->end) | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | if (i >= MAX_EARLY_RES || !early_res[i].end) | ||
| 98 | panic("free_early on not reserved area: %lx-%lx!", start, end); | ||
| 99 | 37 | ||
| 100 | for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++) | ||
| 101 | ; | ||
| 102 | |||
| 103 | memmove(&early_res[i], &early_res[i + 1], | ||
| 104 | (j - 1 - i) * sizeof(struct early_res)); | ||
| 105 | |||
| 106 | early_res[j - 1].end = 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | void __init early_res_to_bootmem(unsigned long start, unsigned long end) | ||
| 110 | { | ||
| 111 | int i; | ||
| 112 | unsigned long final_start, final_end; | ||
| 113 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 114 | struct early_res *r = &early_res[i]; | ||
| 115 | final_start = max(start, r->start); | ||
| 116 | final_end = min(end, r->end); | ||
| 117 | if (final_start >= final_end) | ||
| 118 | continue; | ||
| 119 | printk(KERN_INFO " early res: %d [%lx-%lx] %s\n", i, | ||
| 120 | final_start, final_end - 1, r->name); | ||
| 121 | reserve_bootmem_generic(final_start, final_end - final_start); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | /* Check for already reserved areas */ | ||
| 126 | static inline int __init | ||
| 127 | bad_addr(unsigned long *addrp, unsigned long size, unsigned long align) | ||
| 128 | { | ||
| 129 | int i; | ||
| 130 | unsigned long addr = *addrp, last; | ||
| 131 | int changed = 0; | ||
| 132 | again: | ||
| 133 | last = addr + size; | ||
| 134 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 135 | struct early_res *r = &early_res[i]; | ||
| 136 | if (last >= r->start && addr < r->end) { | ||
| 137 | *addrp = addr = round_up(r->end, align); | ||
| 138 | changed = 1; | ||
| 139 | goto again; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | return changed; | ||
| 143 | } | ||
| 144 | |||
| 145 | /* Check for already reserved areas */ | ||
| 146 | static inline int __init | ||
| 147 | bad_addr_size(unsigned long *addrp, unsigned long *sizep, unsigned long align) | ||
| 148 | { | ||
| 149 | int i; | ||
| 150 | unsigned long addr = *addrp, last; | ||
| 151 | unsigned long size = *sizep; | ||
| 152 | int changed = 0; | ||
| 153 | again: | ||
| 154 | last = addr + size; | ||
| 155 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 156 | struct early_res *r = &early_res[i]; | ||
| 157 | if (last > r->start && addr < r->start) { | ||
| 158 | size = r->start - addr; | ||
| 159 | changed = 1; | ||
| 160 | goto again; | ||
| 161 | } | ||
| 162 | if (last > r->end && addr < r->end) { | ||
| 163 | addr = round_up(r->end, align); | ||
| 164 | size = last - addr; | ||
| 165 | changed = 1; | ||
| 166 | goto again; | ||
| 167 | } | ||
| 168 | if (last <= r->end && addr >= r->start) { | ||
| 169 | (*sizep)++; | ||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | if (changed) { | ||
| 174 | *addrp = addr; | ||
| 175 | *sizep = size; | ||
| 176 | } | ||
| 177 | return changed; | ||
| 178 | } | ||
| 179 | /* | 38 | /* |
| 180 | * This function checks if any part of the range <start,end> is mapped | 39 | * This function checks if any part of the range <start,end> is mapped |
| 181 | * with type. | 40 | * with type. |
| 182 | */ | 41 | */ |
| 183 | int | 42 | int |
| 184 | e820_any_mapped(unsigned long start, unsigned long end, unsigned type) | 43 | e820_any_mapped(u64 start, u64 end, unsigned type) |
| 185 | { | 44 | { |
| 186 | int i; | 45 | int i; |
| 187 | 46 | ||
| @@ -204,8 +63,7 @@ EXPORT_SYMBOL_GPL(e820_any_mapped); | |||
| 204 | * Note: this function only works correct if the e820 table is sorted and | 63 | * Note: this function only works correct if the e820 table is sorted and |
| 205 | * not-overlapping, which is the case | 64 | * not-overlapping, which is the case |
| 206 | */ | 65 | */ |
| 207 | int __init e820_all_mapped(unsigned long start, unsigned long end, | 66 | int __init e820_all_mapped(u64 start, u64 end, unsigned type) |
| 208 | unsigned type) | ||
| 209 | { | 67 | { |
| 210 | int i; | 68 | int i; |
| 211 | 69 | ||
| @@ -234,214 +92,13 @@ int __init e820_all_mapped(unsigned long start, unsigned long end, | |||
| 234 | } | 92 | } |
| 235 | 93 | ||
| 236 | /* | 94 | /* |
| 237 | * Find a free area with specified alignment in a specific range. | ||
| 238 | */ | ||
| 239 | unsigned long __init find_e820_area(unsigned long start, unsigned long end, | ||
| 240 | unsigned long size, unsigned long align) | ||
| 241 | { | ||
| 242 | int i; | ||
| 243 | |||
| 244 | for (i = 0; i < e820.nr_map; i++) { | ||
| 245 | struct e820entry *ei = &e820.map[i]; | ||
| 246 | unsigned long addr, last; | ||
| 247 | unsigned long ei_last; | ||
| 248 | |||
| 249 | if (ei->type != E820_RAM) | ||
| 250 | continue; | ||
| 251 | addr = round_up(ei->addr, align); | ||
| 252 | ei_last = ei->addr + ei->size; | ||
| 253 | if (addr < start) | ||
| 254 | addr = round_up(start, align); | ||
| 255 | if (addr >= ei_last) | ||
| 256 | continue; | ||
| 257 | while (bad_addr(&addr, size, align) && addr+size <= ei_last) | ||
| 258 | ; | ||
| 259 | last = addr + size; | ||
| 260 | if (last > ei_last) | ||
| 261 | continue; | ||
| 262 | if (last > end) | ||
| 263 | continue; | ||
| 264 | return addr; | ||
| 265 | } | ||
| 266 | return -1UL; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* | ||
| 270 | * Find next free range after *start | ||
| 271 | */ | ||
| 272 | unsigned long __init find_e820_area_size(unsigned long start, | ||
| 273 | unsigned long *sizep, | ||
| 274 | unsigned long align) | ||
| 275 | { | ||
| 276 | int i; | ||
| 277 | |||
| 278 | for (i = 0; i < e820.nr_map; i++) { | ||
| 279 | struct e820entry *ei = &e820.map[i]; | ||
| 280 | unsigned long addr, last; | ||
| 281 | unsigned long ei_last; | ||
| 282 | |||
| 283 | if (ei->type != E820_RAM) | ||
| 284 | continue; | ||
| 285 | addr = round_up(ei->addr, align); | ||
| 286 | ei_last = ei->addr + ei->size; | ||
| 287 | if (addr < start) | ||
| 288 | addr = round_up(start, align); | ||
| 289 | if (addr >= ei_last) | ||
| 290 | continue; | ||
| 291 | *sizep = ei_last - addr; | ||
| 292 | while (bad_addr_size(&addr, sizep, align) && | ||
| 293 | addr + *sizep <= ei_last) | ||
| 294 | ; | ||
| 295 | last = addr + *sizep; | ||
| 296 | if (last > ei_last) | ||
| 297 | continue; | ||
| 298 | return addr; | ||
| 299 | } | ||
| 300 | return -1UL; | ||
| 301 | |||
| 302 | } | ||
| 303 | /* | ||
| 304 | * Find the highest page frame number we have available | ||
| 305 | */ | ||
| 306 | unsigned long __init e820_end_of_ram(void) | ||
| 307 | { | ||
| 308 | unsigned long end_pfn; | ||
| 309 | |||
| 310 | end_pfn = find_max_pfn_with_active_regions(); | ||
| 311 | |||
| 312 | if (end_pfn > max_pfn_mapped) | ||
| 313 | max_pfn_mapped = end_pfn; | ||
| 314 | if (max_pfn_mapped > MAXMEM>>PAGE_SHIFT) | ||
| 315 | max_pfn_mapped = MAXMEM>>PAGE_SHIFT; | ||
| 316 | if (end_pfn > end_user_pfn) | ||
| 317 | end_pfn = end_user_pfn; | ||
| 318 | if (end_pfn > max_pfn_mapped) | ||
| 319 | end_pfn = max_pfn_mapped; | ||
| 320 | |||
| 321 | printk(KERN_INFO "max_pfn_mapped = %lu\n", max_pfn_mapped); | ||
| 322 | return end_pfn; | ||
| 323 | } | ||
| 324 | |||
| 325 | /* | ||
| 326 | * Mark e820 reserved areas as busy for the resource manager. | ||
| 327 | */ | ||
| 328 | void __init e820_reserve_resources(void) | ||
| 329 | { | ||
| 330 | int i; | ||
| 331 | struct resource *res; | ||
| 332 | |||
| 333 | res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map); | ||
| 334 | for (i = 0; i < e820.nr_map; i++) { | ||
| 335 | switch (e820.map[i].type) { | ||
| 336 | case E820_RAM: res->name = "System RAM"; break; | ||
| 337 | case E820_ACPI: res->name = "ACPI Tables"; break; | ||
| 338 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; | ||
| 339 | default: res->name = "reserved"; | ||
| 340 | } | ||
| 341 | res->start = e820.map[i].addr; | ||
| 342 | res->end = res->start + e820.map[i].size - 1; | ||
| 343 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
| 344 | insert_resource(&iomem_resource, res); | ||
| 345 | res++; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | /* | ||
| 350 | * Find the ranges of physical addresses that do not correspond to | ||
| 351 | * e820 RAM areas and mark the corresponding pages as nosave for software | ||
| 352 | * suspend and suspend to RAM. | ||
| 353 | * | ||
| 354 | * This function requires the e820 map to be sorted and without any | ||
| 355 | * overlapping entries and assumes the first e820 area to be RAM. | ||
| 356 | */ | ||
| 357 | void __init e820_mark_nosave_regions(void) | ||
| 358 | { | ||
| 359 | int i; | ||
| 360 | unsigned long paddr; | ||
| 361 | |||
| 362 | paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE); | ||
| 363 | for (i = 1; i < e820.nr_map; i++) { | ||
| 364 | struct e820entry *ei = &e820.map[i]; | ||
| 365 | |||
| 366 | if (paddr < ei->addr) | ||
| 367 | register_nosave_region(PFN_DOWN(paddr), | ||
| 368 | PFN_UP(ei->addr)); | ||
| 369 | |||
| 370 | paddr = round_down(ei->addr + ei->size, PAGE_SIZE); | ||
| 371 | if (ei->type != E820_RAM) | ||
| 372 | register_nosave_region(PFN_UP(ei->addr), | ||
| 373 | PFN_DOWN(paddr)); | ||
| 374 | |||
| 375 | if (paddr >= (end_pfn << PAGE_SHIFT)) | ||
| 376 | break; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /* | ||
| 381 | * Finds an active region in the address range from start_pfn to end_pfn and | ||
| 382 | * returns its range in ei_startpfn and ei_endpfn for the e820 entry. | ||
| 383 | */ | ||
| 384 | static int __init e820_find_active_region(const struct e820entry *ei, | ||
| 385 | unsigned long start_pfn, | ||
| 386 | unsigned long end_pfn, | ||
| 387 | unsigned long *ei_startpfn, | ||
| 388 | unsigned long *ei_endpfn) | ||
| 389 | { | ||
| 390 | *ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; | ||
| 391 | *ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT; | ||
| 392 | |||
| 393 | /* Skip map entries smaller than a page */ | ||
| 394 | if (*ei_startpfn >= *ei_endpfn) | ||
| 395 | return 0; | ||
| 396 | |||
| 397 | /* Check if max_pfn_mapped should be updated */ | ||
| 398 | if (ei->type != E820_RAM && *ei_endpfn > max_pfn_mapped) | ||
| 399 | max_pfn_mapped = *ei_endpfn; | ||
| 400 | |||
| 401 | /* Skip if map is outside the node */ | ||
| 402 | if (ei->type != E820_RAM || *ei_endpfn <= start_pfn || | ||
| 403 | *ei_startpfn >= end_pfn) | ||
| 404 | return 0; | ||
| 405 | |||
| 406 | /* Check for overlaps */ | ||
| 407 | if (*ei_startpfn < start_pfn) | ||
| 408 | *ei_startpfn = start_pfn; | ||
| 409 | if (*ei_endpfn > end_pfn) | ||
| 410 | *ei_endpfn = end_pfn; | ||
| 411 | |||
| 412 | /* Obey end_user_pfn to save on memmap */ | ||
| 413 | if (*ei_startpfn >= end_user_pfn) | ||
| 414 | return 0; | ||
| 415 | if (*ei_endpfn > end_user_pfn) | ||
| 416 | *ei_endpfn = end_user_pfn; | ||
| 417 | |||
| 418 | return 1; | ||
| 419 | } | ||
| 420 | |||
| 421 | /* Walk the e820 map and register active regions within a node */ | ||
| 422 | void __init | ||
| 423 | e820_register_active_regions(int nid, unsigned long start_pfn, | ||
| 424 | unsigned long end_pfn) | ||
| 425 | { | ||
| 426 | unsigned long ei_startpfn; | ||
| 427 | unsigned long ei_endpfn; | ||
| 428 | int i; | ||
| 429 | |||
| 430 | for (i = 0; i < e820.nr_map; i++) | ||
| 431 | if (e820_find_active_region(&e820.map[i], | ||
| 432 | start_pfn, end_pfn, | ||
| 433 | &ei_startpfn, &ei_endpfn)) | ||
| 434 | add_active_range(nid, ei_startpfn, ei_endpfn); | ||
| 435 | } | ||
| 436 | |||
| 437 | /* | ||
| 438 | * Add a memory region to the kernel e820 map. | 95 | * Add a memory region to the kernel e820 map. |
| 439 | */ | 96 | */ |
| 440 | void __init add_memory_region(unsigned long start, unsigned long size, int type) | 97 | void __init e820_add_region(u64 start, u64 size, int type) |
| 441 | { | 98 | { |
| 442 | int x = e820.nr_map; | 99 | int x = e820.nr_map; |
| 443 | 100 | ||
| 444 | if (x == E820MAX) { | 101 | if (x == ARRAY_SIZE(e820.map)) { |
| 445 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | 102 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); |
| 446 | return; | 103 | return; |
| 447 | } | 104 | } |
| @@ -452,28 +109,7 @@ void __init add_memory_region(unsigned long start, unsigned long size, int type) | |||
| 452 | e820.nr_map++; | 109 | e820.nr_map++; |
| 453 | } | 110 | } |
| 454 | 111 | ||
| 455 | /* | 112 | void __init e820_print_map(char *who) |
| 456 | * Find the hole size (in bytes) in the memory range. | ||
| 457 | * @start: starting address of the memory range to scan | ||
| 458 | * @end: ending address of the memory range to scan | ||
| 459 | */ | ||
| 460 | unsigned long __init e820_hole_size(unsigned long start, unsigned long end) | ||
| 461 | { | ||
| 462 | unsigned long start_pfn = start >> PAGE_SHIFT; | ||
| 463 | unsigned long end_pfn = end >> PAGE_SHIFT; | ||
| 464 | unsigned long ei_startpfn, ei_endpfn, ram = 0; | ||
| 465 | int i; | ||
| 466 | |||
| 467 | for (i = 0; i < e820.nr_map; i++) { | ||
| 468 | if (e820_find_active_region(&e820.map[i], | ||
| 469 | start_pfn, end_pfn, | ||
| 470 | &ei_startpfn, &ei_endpfn)) | ||
| 471 | ram += ei_endpfn - ei_startpfn; | ||
| 472 | } | ||
| 473 | return end - start - (ram << PAGE_SHIFT); | ||
| 474 | } | ||
| 475 | |||
| 476 | static void __init e820_print_map(char *who) | ||
| 477 | { | 113 | { |
| 478 | int i; | 114 | int i; |
| 479 | 115 | ||
| @@ -506,19 +142,75 @@ static void __init e820_print_map(char *who) | |||
| 506 | * Sanitize the BIOS e820 map. | 142 | * Sanitize the BIOS e820 map. |
| 507 | * | 143 | * |
| 508 | * Some e820 responses include overlapping entries. The following | 144 | * Some e820 responses include overlapping entries. The following |
| 509 | * replaces the original e820 map with a new one, removing overlaps. | 145 | * replaces the original e820 map with a new one, removing overlaps, |
| 146 | * and resolving conflicting memory types in favor of highest | ||
| 147 | * numbered type. | ||
| 510 | * | 148 | * |
| 149 | * The input parameter biosmap points to an array of 'struct | ||
| 150 | * e820entry' which on entry has elements in the range [0, *pnr_map) | ||
| 151 | * valid, and which has space for up to max_nr_map entries. | ||
| 152 | * On return, the resulting sanitized e820 map entries will be in | ||
| 153 | * overwritten in the same location, starting at biosmap. | ||
| 154 | * | ||
| 155 | * The integer pointed to by pnr_map must be valid on entry (the | ||
| 156 | * current number of valid entries located at biosmap) and will | ||
| 157 | * be updated on return, with the new number of valid entries | ||
| 158 | * (something no more than max_nr_map.) | ||
| 159 | * | ||
| 160 | * The return value from sanitize_e820_map() is zero if it | ||
| 161 | * successfully 'sanitized' the map entries passed in, and is -1 | ||
| 162 | * if it did nothing, which can happen if either of (1) it was | ||
| 163 | * only passed one map entry, or (2) any of the input map entries | ||
| 164 | * were invalid (start + size < start, meaning that the size was | ||
| 165 | * so big the described memory range wrapped around through zero.) | ||
| 166 | * | ||
| 167 | * Visually we're performing the following | ||
| 168 | * (1,2,3,4 = memory types)... | ||
| 169 | * | ||
| 170 | * Sample memory map (w/overlaps): | ||
| 171 | * ____22__________________ | ||
| 172 | * ______________________4_ | ||
| 173 | * ____1111________________ | ||
| 174 | * _44_____________________ | ||
| 175 | * 11111111________________ | ||
| 176 | * ____________________33__ | ||
| 177 | * ___________44___________ | ||
| 178 | * __________33333_________ | ||
| 179 | * ______________22________ | ||
| 180 | * ___________________2222_ | ||
| 181 | * _________111111111______ | ||
| 182 | * _____________________11_ | ||
| 183 | * _________________4______ | ||
| 184 | * | ||
| 185 | * Sanitized equivalent (no overlap): | ||
| 186 | * 1_______________________ | ||
| 187 | * _44_____________________ | ||
| 188 | * ___1____________________ | ||
| 189 | * ____22__________________ | ||
| 190 | * ______11________________ | ||
| 191 | * _________1______________ | ||
| 192 | * __________3_____________ | ||
| 193 | * ___________44___________ | ||
| 194 | * _____________33_________ | ||
| 195 | * _______________2________ | ||
| 196 | * ________________1_______ | ||
| 197 | * _________________4______ | ||
| 198 | * ___________________2____ | ||
| 199 | * ____________________33__ | ||
| 200 | * ______________________4_ | ||
| 511 | */ | 201 | */ |
| 512 | static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map) | 202 | |
| 203 | int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, | ||
| 204 | int *pnr_map) | ||
| 513 | { | 205 | { |
| 514 | struct change_member { | 206 | struct change_member { |
| 515 | struct e820entry *pbios; /* pointer to original bios entry */ | 207 | struct e820entry *pbios; /* pointer to original bios entry */ |
| 516 | unsigned long long addr; /* address for this change point */ | 208 | unsigned long long addr; /* address for this change point */ |
| 517 | }; | 209 | }; |
| 518 | static struct change_member change_point_list[2*E820MAX] __initdata; | 210 | static struct change_member change_point_list[2*E820_X_MAX] __initdata; |
| 519 | static struct change_member *change_point[2*E820MAX] __initdata; | 211 | static struct change_member *change_point[2*E820_X_MAX] __initdata; |
| 520 | static struct e820entry *overlap_list[E820MAX] __initdata; | 212 | static struct e820entry *overlap_list[E820_X_MAX] __initdata; |
| 521 | static struct e820entry new_bios[E820MAX] __initdata; | 213 | static struct e820entry new_bios[E820_X_MAX] __initdata; |
| 522 | struct change_member *change_tmp; | 214 | struct change_member *change_tmp; |
| 523 | unsigned long current_type, last_type; | 215 | unsigned long current_type, last_type; |
| 524 | unsigned long long last_addr; | 216 | unsigned long long last_addr; |
| @@ -528,48 +220,12 @@ static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map) | |||
| 528 | int old_nr, new_nr, chg_nr; | 220 | int old_nr, new_nr, chg_nr; |
| 529 | int i; | 221 | int i; |
| 530 | 222 | ||
| 531 | /* | ||
| 532 | Visually we're performing the following | ||
| 533 | (1,2,3,4 = memory types)... | ||
| 534 | |||
| 535 | Sample memory map (w/overlaps): | ||
| 536 | ____22__________________ | ||
| 537 | ______________________4_ | ||
| 538 | ____1111________________ | ||
| 539 | _44_____________________ | ||
| 540 | 11111111________________ | ||
| 541 | ____________________33__ | ||
| 542 | ___________44___________ | ||
| 543 | __________33333_________ | ||
| 544 | ______________22________ | ||
| 545 | ___________________2222_ | ||
| 546 | _________111111111______ | ||
| 547 | _____________________11_ | ||
| 548 | _________________4______ | ||
| 549 | |||
| 550 | Sanitized equivalent (no overlap): | ||
| 551 | 1_______________________ | ||
| 552 | _44_____________________ | ||
| 553 | ___1____________________ | ||
| 554 | ____22__________________ | ||
| 555 | ______11________________ | ||
| 556 | _________1______________ | ||
| 557 | __________3_____________ | ||
| 558 | ___________44___________ | ||
| 559 | _____________33_________ | ||
| 560 | _______________2________ | ||
| 561 | ________________1_______ | ||
| 562 | _________________4______ | ||
| 563 | ___________________2____ | ||
| 564 | ____________________33__ | ||
| 565 | ______________________4_ | ||
| 566 | */ | ||
| 567 | |||
| 568 | /* if there's only one memory region, don't bother */ | 223 | /* if there's only one memory region, don't bother */ |
| 569 | if (*pnr_map < 2) | 224 | if (*pnr_map < 2) |
| 570 | return -1; | 225 | return -1; |
| 571 | 226 | ||
| 572 | old_nr = *pnr_map; | 227 | old_nr = *pnr_map; |
| 228 | BUG_ON(old_nr > max_nr_map); | ||
| 573 | 229 | ||
| 574 | /* bail out if we find any unreasonable addresses in bios map */ | 230 | /* bail out if we find any unreasonable addresses in bios map */ |
| 575 | for (i = 0; i < old_nr; i++) | 231 | for (i = 0; i < old_nr; i++) |
| @@ -681,7 +337,7 @@ static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map) | |||
| 681 | * no more space left for new | 337 | * no more space left for new |
| 682 | * bios entries ? | 338 | * bios entries ? |
| 683 | */ | 339 | */ |
| 684 | if (++new_bios_entry >= E820MAX) | 340 | if (++new_bios_entry >= max_nr_map) |
| 685 | break; | 341 | break; |
| 686 | } | 342 | } |
| 687 | if (current_type != 0) { | 343 | if (current_type != 0) { |
| @@ -703,22 +359,9 @@ static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map) | |||
| 703 | return 0; | 359 | return 0; |
| 704 | } | 360 | } |
| 705 | 361 | ||
| 706 | /* | 362 | static int __init __copy_e820_map(struct e820entry *biosmap, int nr_map) |
| 707 | * Copy the BIOS e820 map into a safe place. | ||
| 708 | * | ||
| 709 | * Sanity-check it while we're at it.. | ||
| 710 | * | ||
| 711 | * If we're lucky and live on a modern system, the setup code | ||
| 712 | * will have given us a memory map that we can use to properly | ||
| 713 | * set up memory. If we aren't, we'll fake a memory map. | ||
| 714 | */ | ||
| 715 | static int __init copy_e820_map(struct e820entry *biosmap, int nr_map) | ||
| 716 | { | 363 | { |
| 717 | /* Only one memory region (or negative)? Ignore it */ | 364 | while (nr_map) { |
| 718 | if (nr_map < 2) | ||
| 719 | return -1; | ||
| 720 | |||
| 721 | do { | ||
| 722 | u64 start = biosmap->addr; | 365 | u64 start = biosmap->addr; |
| 723 | u64 size = biosmap->size; | 366 | u64 size = biosmap->size; |
| 724 | u64 end = start + size; | 367 | u64 end = start + size; |
| @@ -728,111 +371,37 @@ static int __init copy_e820_map(struct e820entry *biosmap, int nr_map) | |||
| 728 | if (start > end) | 371 | if (start > end) |
| 729 | return -1; | 372 | return -1; |
| 730 | 373 | ||
| 731 | add_memory_region(start, size, type); | 374 | e820_add_region(start, size, type); |
| 732 | } while (biosmap++, --nr_map); | ||
| 733 | return 0; | ||
| 734 | } | ||
| 735 | |||
| 736 | static void early_panic(char *msg) | ||
| 737 | { | ||
| 738 | early_printk(msg); | ||
| 739 | panic(msg); | ||
| 740 | } | ||
| 741 | |||
| 742 | /* We're not void only for x86 32-bit compat */ | ||
| 743 | char * __init machine_specific_memory_setup(void) | ||
| 744 | { | ||
| 745 | char *who = "BIOS-e820"; | ||
| 746 | /* | ||
| 747 | * Try to copy the BIOS-supplied E820-map. | ||
| 748 | * | ||
| 749 | * Otherwise fake a memory map; one section from 0k->640k, | ||
| 750 | * the next section from 1mb->appropriate_mem_k | ||
| 751 | */ | ||
| 752 | sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries); | ||
| 753 | if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0) | ||
| 754 | early_panic("Cannot find a valid memory map"); | ||
| 755 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | ||
| 756 | e820_print_map(who); | ||
| 757 | |||
| 758 | /* In case someone cares... */ | ||
| 759 | return who; | ||
| 760 | } | ||
| 761 | |||
| 762 | static int __init parse_memopt(char *p) | ||
| 763 | { | ||
| 764 | if (!p) | ||
| 765 | return -EINVAL; | ||
| 766 | end_user_pfn = memparse(p, &p); | ||
| 767 | end_user_pfn >>= PAGE_SHIFT; | ||
| 768 | return 0; | ||
| 769 | } | ||
| 770 | early_param("mem", parse_memopt); | ||
| 771 | |||
| 772 | static int userdef __initdata; | ||
| 773 | |||
| 774 | static int __init parse_memmap_opt(char *p) | ||
| 775 | { | ||
| 776 | char *oldp; | ||
| 777 | unsigned long long start_at, mem_size; | ||
| 778 | |||
| 779 | if (!strcmp(p, "exactmap")) { | ||
| 780 | #ifdef CONFIG_CRASH_DUMP | ||
| 781 | /* | ||
| 782 | * If we are doing a crash dump, we still need to know | ||
| 783 | * the real mem size before original memory map is | ||
| 784 | * reset. | ||
| 785 | */ | ||
| 786 | e820_register_active_regions(0, 0, -1UL); | ||
| 787 | saved_max_pfn = e820_end_of_ram(); | ||
| 788 | remove_all_active_ranges(); | ||
| 789 | #endif | ||
| 790 | max_pfn_mapped = 0; | ||
| 791 | e820.nr_map = 0; | ||
| 792 | userdef = 1; | ||
| 793 | return 0; | ||
| 794 | } | ||
| 795 | |||
| 796 | oldp = p; | ||
| 797 | mem_size = memparse(p, &p); | ||
| 798 | if (p == oldp) | ||
| 799 | return -EINVAL; | ||
| 800 | 375 | ||
| 801 | userdef = 1; | 376 | biosmap++; |
| 802 | if (*p == '@') { | 377 | nr_map--; |
| 803 | start_at = memparse(p+1, &p); | ||
| 804 | add_memory_region(start_at, mem_size, E820_RAM); | ||
| 805 | } else if (*p == '#') { | ||
| 806 | start_at = memparse(p+1, &p); | ||
| 807 | add_memory_region(start_at, mem_size, E820_ACPI); | ||
| 808 | } else if (*p == '$') { | ||
| 809 | start_at = memparse(p+1, &p); | ||
| 810 | add_memory_region(start_at, mem_size, E820_RESERVED); | ||
| 811 | } else { | ||
| 812 | end_user_pfn = (mem_size >> PAGE_SHIFT); | ||
| 813 | } | 378 | } |
| 814 | return *p == '\0' ? 0 : -EINVAL; | 379 | return 0; |
| 815 | } | 380 | } |
| 816 | early_param("memmap", parse_memmap_opt); | ||
| 817 | 381 | ||
| 818 | void __init finish_e820_parsing(void) | 382 | /* |
| 383 | * Copy the BIOS e820 map into a safe place. | ||
| 384 | * | ||
| 385 | * Sanity-check it while we're at it.. | ||
| 386 | * | ||
| 387 | * If we're lucky and live on a modern system, the setup code | ||
| 388 | * will have given us a memory map that we can use to properly | ||
| 389 | * set up memory. If we aren't, we'll fake a memory map. | ||
| 390 | */ | ||
| 391 | int __init copy_e820_map(struct e820entry *biosmap, int nr_map) | ||
| 819 | { | 392 | { |
| 820 | if (userdef) { | 393 | /* Only one memory region (or negative)? Ignore it */ |
| 821 | char nr = e820.nr_map; | 394 | if (nr_map < 2) |
| 822 | 395 | return -1; | |
| 823 | if (sanitize_e820_map(e820.map, &nr) < 0) | ||
| 824 | early_panic("Invalid user supplied memory map"); | ||
| 825 | e820.nr_map = nr; | ||
| 826 | 396 | ||
| 827 | printk(KERN_INFO "user-defined physical RAM map:\n"); | 397 | return __copy_e820_map(biosmap, nr_map); |
| 828 | e820_print_map("user"); | ||
| 829 | } | ||
| 830 | } | 398 | } |
| 831 | 399 | ||
| 832 | void __init update_memory_range(u64 start, u64 size, unsigned old_type, | 400 | u64 __init e820_update_range(u64 start, u64 size, unsigned old_type, |
| 833 | unsigned new_type) | 401 | unsigned new_type) |
| 834 | { | 402 | { |
| 835 | int i; | 403 | int i; |
| 404 | u64 real_updated_size = 0; | ||
| 836 | 405 | ||
| 837 | BUG_ON(old_type == new_type); | 406 | BUG_ON(old_type == new_type); |
| 838 | 407 | ||
| @@ -842,8 +411,10 @@ void __init update_memory_range(u64 start, u64 size, unsigned old_type, | |||
| 842 | if (ei->type != old_type) | 411 | if (ei->type != old_type) |
| 843 | continue; | 412 | continue; |
| 844 | /* totally covered? */ | 413 | /* totally covered? */ |
| 845 | if (ei->addr >= start && ei->size <= size) { | 414 | if (ei->addr >= start && |
| 415 | (ei->addr + ei->size) <= (start + size)) { | ||
| 846 | ei->type = new_type; | 416 | ei->type = new_type; |
| 417 | real_updated_size += ei->size; | ||
| 847 | continue; | 418 | continue; |
| 848 | } | 419 | } |
| 849 | /* partially covered */ | 420 | /* partially covered */ |
| @@ -851,26 +422,25 @@ void __init update_memory_range(u64 start, u64 size, unsigned old_type, | |||
| 851 | final_end = min(start + size, ei->addr + ei->size); | 422 | final_end = min(start + size, ei->addr + ei->size); |
| 852 | if (final_start >= final_end) | 423 | if (final_start >= final_end) |
| 853 | continue; | 424 | continue; |
| 854 | add_memory_region(final_start, final_end - final_start, | 425 | e820_add_region(final_start, final_end - final_start, |
| 855 | new_type); | 426 | new_type); |
| 427 | real_updated_size += final_end - final_start; | ||
| 856 | } | 428 | } |
| 429 | return real_updated_size; | ||
| 857 | } | 430 | } |
| 858 | 431 | ||
| 859 | void __init update_e820(void) | 432 | void __init update_e820(void) |
| 860 | { | 433 | { |
| 861 | u8 nr_map; | 434 | int nr_map; |
| 862 | 435 | ||
| 863 | nr_map = e820.nr_map; | 436 | nr_map = e820.nr_map; |
| 864 | if (sanitize_e820_map(e820.map, &nr_map)) | 437 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map)) |
| 865 | return; | 438 | return; |
| 866 | e820.nr_map = nr_map; | 439 | e820.nr_map = nr_map; |
| 867 | printk(KERN_INFO "modified physical RAM map:\n"); | 440 | printk(KERN_INFO "modified physical RAM map:\n"); |
| 868 | e820_print_map("modified"); | 441 | e820_print_map("modified"); |
| 869 | } | 442 | } |
| 870 | 443 | ||
| 871 | unsigned long pci_mem_start = 0xaeedbabe; | ||
| 872 | EXPORT_SYMBOL(pci_mem_start); | ||
| 873 | |||
| 874 | /* | 444 | /* |
| 875 | * Search for the biggest gap in the low 32 bits of the e820 | 445 | * Search for the biggest gap in the low 32 bits of the e820 |
| 876 | * memory space. We pass this space to PCI to assign MMIO resources | 446 | * memory space. We pass this space to PCI to assign MMIO resources |
| @@ -880,7 +450,7 @@ EXPORT_SYMBOL(pci_mem_start); | |||
| 880 | __init void e820_setup_gap(void) | 450 | __init void e820_setup_gap(void) |
| 881 | { | 451 | { |
| 882 | unsigned long gapstart, gapsize, round; | 452 | unsigned long gapstart, gapsize, round; |
| 883 | unsigned long last; | 453 | unsigned long long last; |
| 884 | int i; | 454 | int i; |
| 885 | int found = 0; | 455 | int found = 0; |
| 886 | 456 | ||
| @@ -909,6 +479,7 @@ __init void e820_setup_gap(void) | |||
| 909 | last = start; | 479 | last = start; |
| 910 | } | 480 | } |
| 911 | 481 | ||
| 482 | #ifdef CONFIG_X86_64 | ||
| 912 | if (!found) { | 483 | if (!found) { |
| 913 | gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024; | 484 | gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024; |
| 914 | printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit " | 485 | printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit " |
| @@ -916,6 +487,7 @@ __init void e820_setup_gap(void) | |||
| 916 | KERN_ERR "PCI: Unassigned devices with 32bit resource " | 487 | KERN_ERR "PCI: Unassigned devices with 32bit resource " |
| 917 | "registers may break!\n"); | 488 | "registers may break!\n"); |
| 918 | } | 489 | } |
| 490 | #endif | ||
| 919 | 491 | ||
| 920 | /* | 492 | /* |
| 921 | * See how much we want to round up: start off with | 493 | * See how much we want to round up: start off with |
| @@ -932,6 +504,586 @@ __init void e820_setup_gap(void) | |||
| 932 | pci_mem_start, gapstart, gapsize); | 504 | pci_mem_start, gapstart, gapsize); |
| 933 | } | 505 | } |
| 934 | 506 | ||
| 507 | /** | ||
| 508 | * Because of the size limitation of struct boot_params, only first | ||
| 509 | * 128 E820 memory entries are passed to kernel via | ||
| 510 | * boot_params.e820_map, others are passed via SETUP_E820_EXT node of | ||
| 511 | * linked list of struct setup_data, which is parsed here. | ||
| 512 | */ | ||
| 513 | void __init parse_e820_ext(struct setup_data *sdata, unsigned long pa_data) | ||
| 514 | { | ||
| 515 | u32 map_len; | ||
| 516 | int entries; | ||
| 517 | struct e820entry *extmap; | ||
| 518 | |||
| 519 | entries = sdata->len / sizeof(struct e820entry); | ||
| 520 | map_len = sdata->len + sizeof(struct setup_data); | ||
| 521 | if (map_len > PAGE_SIZE) | ||
| 522 | sdata = early_ioremap(pa_data, map_len); | ||
| 523 | extmap = (struct e820entry *)(sdata->data); | ||
| 524 | __copy_e820_map(extmap, entries); | ||
| 525 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | ||
| 526 | if (map_len > PAGE_SIZE) | ||
| 527 | early_iounmap(sdata, map_len); | ||
| 528 | printk(KERN_INFO "extended physical RAM map:\n"); | ||
| 529 | e820_print_map("extended"); | ||
| 530 | } | ||
| 531 | |||
| 532 | #if defined(CONFIG_X86_64) || \ | ||
| 533 | (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION)) | ||
| 534 | /** | ||
| 535 | * Find the ranges of physical addresses that do not correspond to | ||
| 536 | * e820 RAM areas and mark the corresponding pages as nosave for | ||
| 537 | * hibernation (32 bit) or software suspend and suspend to RAM (64 bit). | ||
| 538 | * | ||
| 539 | * This function requires the e820 map to be sorted and without any | ||
| 540 | * overlapping entries and assumes the first e820 area to be RAM. | ||
| 541 | */ | ||
| 542 | void __init e820_mark_nosave_regions(unsigned long limit_pfn) | ||
| 543 | { | ||
| 544 | int i; | ||
| 545 | unsigned long pfn; | ||
| 546 | |||
| 547 | pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size); | ||
| 548 | for (i = 1; i < e820.nr_map; i++) { | ||
| 549 | struct e820entry *ei = &e820.map[i]; | ||
| 550 | |||
| 551 | if (pfn < PFN_UP(ei->addr)) | ||
| 552 | register_nosave_region(pfn, PFN_UP(ei->addr)); | ||
| 553 | |||
| 554 | pfn = PFN_DOWN(ei->addr + ei->size); | ||
| 555 | if (ei->type != E820_RAM) | ||
| 556 | register_nosave_region(PFN_UP(ei->addr), pfn); | ||
| 557 | |||
| 558 | if (pfn >= limit_pfn) | ||
| 559 | break; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | #endif | ||
| 563 | |||
| 564 | /* | ||
| 565 | * Early reserved memory areas. | ||
| 566 | */ | ||
| 567 | #define MAX_EARLY_RES 20 | ||
| 568 | |||
| 569 | struct early_res { | ||
| 570 | u64 start, end; | ||
| 571 | char name[16]; | ||
| 572 | }; | ||
| 573 | static struct early_res early_res[MAX_EARLY_RES] __initdata = { | ||
| 574 | { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ | ||
| 575 | #if defined(CONFIG_X86_64) && defined(CONFIG_X86_TRAMPOLINE) | ||
| 576 | { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" }, | ||
| 577 | #endif | ||
| 578 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) | ||
| 579 | /* | ||
| 580 | * But first pinch a few for the stack/trampoline stuff | ||
| 581 | * FIXME: Don't need the extra page at 4K, but need to fix | ||
| 582 | * trampoline before removing it. (see the GDT stuff) | ||
| 583 | */ | ||
| 584 | { PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE" }, | ||
| 585 | /* | ||
| 586 | * Has to be in very low memory so we can execute | ||
| 587 | * real-mode AP code. | ||
| 588 | */ | ||
| 589 | { TRAMPOLINE_BASE, TRAMPOLINE_BASE + PAGE_SIZE, "TRAMPOLINE" }, | ||
| 590 | #endif | ||
| 591 | {} | ||
| 592 | }; | ||
| 593 | |||
| 594 | static int __init find_overlapped_early(u64 start, u64 end) | ||
| 595 | { | ||
| 596 | int i; | ||
| 597 | struct early_res *r; | ||
| 598 | |||
| 599 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 600 | r = &early_res[i]; | ||
| 601 | if (end > r->start && start < r->end) | ||
| 602 | break; | ||
| 603 | } | ||
| 604 | |||
| 605 | return i; | ||
| 606 | } | ||
| 607 | |||
| 608 | void __init reserve_early(u64 start, u64 end, char *name) | ||
| 609 | { | ||
| 610 | int i; | ||
| 611 | struct early_res *r; | ||
| 612 | |||
| 613 | i = find_overlapped_early(start, end); | ||
| 614 | if (i >= MAX_EARLY_RES) | ||
| 615 | panic("Too many early reservations"); | ||
| 616 | r = &early_res[i]; | ||
| 617 | if (r->end) | ||
| 618 | panic("Overlapping early reservations " | ||
| 619 | "%llx-%llx %s to %llx-%llx %s\n", | ||
| 620 | start, end - 1, name?name:"", r->start, | ||
| 621 | r->end - 1, r->name); | ||
| 622 | r->start = start; | ||
| 623 | r->end = end; | ||
| 624 | if (name) | ||
| 625 | strncpy(r->name, name, sizeof(r->name) - 1); | ||
| 626 | } | ||
| 627 | |||
| 628 | void __init free_early(u64 start, u64 end) | ||
| 629 | { | ||
| 630 | struct early_res *r; | ||
| 631 | int i, j; | ||
| 632 | |||
| 633 | i = find_overlapped_early(start, end); | ||
| 634 | r = &early_res[i]; | ||
| 635 | if (i >= MAX_EARLY_RES || r->end != end || r->start != start) | ||
| 636 | panic("free_early on not reserved area: %llx-%llx!", | ||
| 637 | start, end - 1); | ||
| 638 | |||
| 639 | for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++) | ||
| 640 | ; | ||
| 641 | |||
| 642 | memmove(&early_res[i], &early_res[i + 1], | ||
| 643 | (j - 1 - i) * sizeof(struct early_res)); | ||
| 644 | |||
| 645 | early_res[j - 1].end = 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | void __init early_res_to_bootmem(u64 start, u64 end) | ||
| 649 | { | ||
| 650 | int i; | ||
| 651 | u64 final_start, final_end; | ||
| 652 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 653 | struct early_res *r = &early_res[i]; | ||
| 654 | final_start = max(start, r->start); | ||
| 655 | final_end = min(end, r->end); | ||
| 656 | if (final_start >= final_end) | ||
| 657 | continue; | ||
| 658 | printk(KERN_INFO " early res: %d [%llx-%llx] %s\n", i, | ||
| 659 | final_start, final_end - 1, r->name); | ||
| 660 | reserve_bootmem_generic(final_start, final_end - final_start, | ||
| 661 | BOOTMEM_DEFAULT); | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | /* Check for already reserved areas */ | ||
| 666 | static inline int __init bad_addr(u64 *addrp, u64 size, u64 align) | ||
| 667 | { | ||
| 668 | int i; | ||
| 669 | u64 addr = *addrp; | ||
| 670 | int changed = 0; | ||
| 671 | struct early_res *r; | ||
| 672 | again: | ||
| 673 | i = find_overlapped_early(addr, addr + size); | ||
| 674 | r = &early_res[i]; | ||
| 675 | if (i < MAX_EARLY_RES && r->end) { | ||
| 676 | *addrp = addr = round_up(r->end, align); | ||
| 677 | changed = 1; | ||
| 678 | goto again; | ||
| 679 | } | ||
| 680 | return changed; | ||
| 681 | } | ||
| 682 | |||
| 683 | /* Check for already reserved areas */ | ||
| 684 | static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align) | ||
| 685 | { | ||
| 686 | int i; | ||
| 687 | u64 addr = *addrp, last; | ||
| 688 | u64 size = *sizep; | ||
| 689 | int changed = 0; | ||
| 690 | again: | ||
| 691 | last = addr + size; | ||
| 692 | for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { | ||
| 693 | struct early_res *r = &early_res[i]; | ||
| 694 | if (last > r->start && addr < r->start) { | ||
| 695 | size = r->start - addr; | ||
| 696 | changed = 1; | ||
| 697 | goto again; | ||
| 698 | } | ||
| 699 | if (last > r->end && addr < r->end) { | ||
| 700 | addr = round_up(r->end, align); | ||
| 701 | size = last - addr; | ||
| 702 | changed = 1; | ||
| 703 | goto again; | ||
| 704 | } | ||
| 705 | if (last <= r->end && addr >= r->start) { | ||
| 706 | (*sizep)++; | ||
| 707 | return 0; | ||
| 708 | } | ||
| 709 | } | ||
| 710 | if (changed) { | ||
| 711 | *addrp = addr; | ||
| 712 | *sizep = size; | ||
| 713 | } | ||
| 714 | return changed; | ||
| 715 | } | ||
| 716 | |||
| 717 | /* | ||
| 718 | * Find a free area with specified alignment in a specific range. | ||
| 719 | */ | ||
| 720 | u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align) | ||
| 721 | { | ||
| 722 | int i; | ||
| 723 | |||
| 724 | for (i = 0; i < e820.nr_map; i++) { | ||
| 725 | struct e820entry *ei = &e820.map[i]; | ||
| 726 | u64 addr, last; | ||
| 727 | u64 ei_last; | ||
| 728 | |||
| 729 | if (ei->type != E820_RAM) | ||
| 730 | continue; | ||
| 731 | addr = round_up(ei->addr, align); | ||
| 732 | ei_last = ei->addr + ei->size; | ||
| 733 | if (addr < start) | ||
| 734 | addr = round_up(start, align); | ||
| 735 | if (addr >= ei_last) | ||
| 736 | continue; | ||
| 737 | while (bad_addr(&addr, size, align) && addr+size <= ei_last) | ||
| 738 | ; | ||
| 739 | last = addr + size; | ||
| 740 | if (last > ei_last) | ||
| 741 | continue; | ||
| 742 | if (last > end) | ||
| 743 | continue; | ||
| 744 | return addr; | ||
| 745 | } | ||
| 746 | return -1ULL; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* | ||
| 750 | * Find next free range after *start | ||
| 751 | */ | ||
| 752 | u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align) | ||
| 753 | { | ||
| 754 | int i; | ||
| 755 | |||
| 756 | for (i = 0; i < e820.nr_map; i++) { | ||
| 757 | struct e820entry *ei = &e820.map[i]; | ||
| 758 | u64 addr, last; | ||
| 759 | u64 ei_last; | ||
| 760 | |||
| 761 | if (ei->type != E820_RAM) | ||
| 762 | continue; | ||
| 763 | addr = round_up(ei->addr, align); | ||
| 764 | ei_last = ei->addr + ei->size; | ||
| 765 | if (addr < start) | ||
| 766 | addr = round_up(start, align); | ||
| 767 | if (addr >= ei_last) | ||
| 768 | continue; | ||
| 769 | *sizep = ei_last - addr; | ||
| 770 | while (bad_addr_size(&addr, sizep, align) && | ||
| 771 | addr + *sizep <= ei_last) | ||
| 772 | ; | ||
| 773 | last = addr + *sizep; | ||
| 774 | if (last > ei_last) | ||
| 775 | continue; | ||
| 776 | return addr; | ||
| 777 | } | ||
| 778 | return -1UL; | ||
| 779 | |||
| 780 | } | ||
| 781 | |||
| 782 | /* | ||
| 783 | * pre allocated 4k and reserved it in e820 | ||
| 784 | */ | ||
| 785 | u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) | ||
| 786 | { | ||
| 787 | u64 size = 0; | ||
| 788 | u64 addr; | ||
| 789 | u64 start; | ||
| 790 | |||
| 791 | start = startt; | ||
| 792 | while (size < sizet) | ||
| 793 | start = find_e820_area_size(start, &size, align); | ||
| 794 | |||
| 795 | if (size < sizet) | ||
| 796 | return 0; | ||
| 797 | |||
| 798 | addr = round_down(start + size - sizet, align); | ||
| 799 | e820_update_range(addr, sizet, E820_RAM, E820_RESERVED); | ||
| 800 | printk(KERN_INFO "update e820 for early_reserve_e820\n"); | ||
| 801 | update_e820(); | ||
| 802 | |||
| 803 | return addr; | ||
| 804 | } | ||
| 805 | |||
| 806 | #ifdef CONFIG_X86_32 | ||
| 807 | # ifdef CONFIG_X86_PAE | ||
| 808 | # define MAX_ARCH_PFN (1ULL<<(36-PAGE_SHIFT)) | ||
| 809 | # else | ||
| 810 | # define MAX_ARCH_PFN (1ULL<<(32-PAGE_SHIFT)) | ||
| 811 | # endif | ||
| 812 | #else /* CONFIG_X86_32 */ | ||
| 813 | # define MAX_ARCH_PFN MAXMEM>>PAGE_SHIFT | ||
| 814 | #endif | ||
| 815 | |||
| 816 | /* | ||
| 817 | * Last pfn which the user wants to use. | ||
| 818 | */ | ||
| 819 | unsigned long __initdata end_user_pfn = MAX_ARCH_PFN; | ||
| 820 | |||
| 821 | /* | ||
| 822 | * Find the highest page frame number we have available | ||
| 823 | */ | ||
| 824 | unsigned long __init e820_end_of_ram(void) | ||
| 825 | { | ||
| 826 | unsigned long last_pfn; | ||
| 827 | unsigned long max_arch_pfn = MAX_ARCH_PFN; | ||
| 828 | |||
| 829 | last_pfn = find_max_pfn_with_active_regions(); | ||
| 830 | |||
| 831 | if (last_pfn > max_arch_pfn) | ||
| 832 | last_pfn = max_arch_pfn; | ||
| 833 | if (last_pfn > end_user_pfn) | ||
| 834 | last_pfn = end_user_pfn; | ||
| 835 | |||
| 836 | printk(KERN_INFO "last_pfn = %lu max_arch_pfn = %lu\n", | ||
| 837 | last_pfn, max_arch_pfn); | ||
| 838 | return last_pfn; | ||
| 839 | } | ||
| 840 | |||
| 841 | /* | ||
| 842 | * Finds an active region in the address range from start_pfn to last_pfn and | ||
| 843 | * returns its range in ei_startpfn and ei_endpfn for the e820 entry. | ||
| 844 | */ | ||
| 845 | int __init e820_find_active_region(const struct e820entry *ei, | ||
| 846 | unsigned long start_pfn, | ||
| 847 | unsigned long last_pfn, | ||
| 848 | unsigned long *ei_startpfn, | ||
| 849 | unsigned long *ei_endpfn) | ||
| 850 | { | ||
| 851 | u64 align = PAGE_SIZE; | ||
| 852 | |||
| 853 | *ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT; | ||
| 854 | *ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT; | ||
| 855 | |||
| 856 | /* Skip map entries smaller than a page */ | ||
| 857 | if (*ei_startpfn >= *ei_endpfn) | ||
| 858 | return 0; | ||
| 859 | |||
| 860 | /* Skip if map is outside the node */ | ||
| 861 | if (ei->type != E820_RAM || *ei_endpfn <= start_pfn || | ||
| 862 | *ei_startpfn >= last_pfn) | ||
| 863 | return 0; | ||
| 864 | |||
| 865 | /* Check for overlaps */ | ||
| 866 | if (*ei_startpfn < start_pfn) | ||
| 867 | *ei_startpfn = start_pfn; | ||
| 868 | if (*ei_endpfn > last_pfn) | ||
| 869 | *ei_endpfn = last_pfn; | ||
| 870 | |||
| 871 | /* Obey end_user_pfn to save on memmap */ | ||
| 872 | if (*ei_startpfn >= end_user_pfn) | ||
| 873 | return 0; | ||
| 874 | if (*ei_endpfn > end_user_pfn) | ||
| 875 | *ei_endpfn = end_user_pfn; | ||
| 876 | |||
| 877 | return 1; | ||
| 878 | } | ||
| 879 | |||
| 880 | /* Walk the e820 map and register active regions within a node */ | ||
| 881 | void __init e820_register_active_regions(int nid, unsigned long start_pfn, | ||
| 882 | unsigned long last_pfn) | ||
| 883 | { | ||
| 884 | unsigned long ei_startpfn; | ||
| 885 | unsigned long ei_endpfn; | ||
| 886 | int i; | ||
| 887 | |||
| 888 | for (i = 0; i < e820.nr_map; i++) | ||
| 889 | if (e820_find_active_region(&e820.map[i], | ||
| 890 | start_pfn, last_pfn, | ||
| 891 | &ei_startpfn, &ei_endpfn)) | ||
| 892 | add_active_range(nid, ei_startpfn, ei_endpfn); | ||
| 893 | } | ||
| 894 | |||
| 895 | /* | ||
| 896 | * Find the hole size (in bytes) in the memory range. | ||
| 897 | * @start: starting address of the memory range to scan | ||
| 898 | * @end: ending address of the memory range to scan | ||
| 899 | */ | ||
| 900 | u64 __init e820_hole_size(u64 start, u64 end) | ||
| 901 | { | ||
| 902 | unsigned long start_pfn = start >> PAGE_SHIFT; | ||
| 903 | unsigned long last_pfn = end >> PAGE_SHIFT; | ||
| 904 | unsigned long ei_startpfn, ei_endpfn, ram = 0; | ||
| 905 | int i; | ||
| 906 | |||
| 907 | for (i = 0; i < e820.nr_map; i++) { | ||
| 908 | if (e820_find_active_region(&e820.map[i], | ||
| 909 | start_pfn, last_pfn, | ||
| 910 | &ei_startpfn, &ei_endpfn)) | ||
| 911 | ram += ei_endpfn - ei_startpfn; | ||
| 912 | } | ||
| 913 | return end - start - ((u64)ram << PAGE_SHIFT); | ||
| 914 | } | ||
| 915 | |||
| 916 | static void early_panic(char *msg) | ||
| 917 | { | ||
| 918 | early_printk(msg); | ||
| 919 | panic(msg); | ||
| 920 | } | ||
| 921 | |||
| 922 | /* "mem=nopentium" disables the 4MB page tables. */ | ||
| 923 | static int __init parse_memopt(char *p) | ||
| 924 | { | ||
| 925 | u64 mem_size; | ||
| 926 | |||
| 927 | if (!p) | ||
| 928 | return -EINVAL; | ||
| 929 | |||
| 930 | #ifdef CONFIG_X86_32 | ||
| 931 | if (!strcmp(p, "nopentium")) { | ||
| 932 | setup_clear_cpu_cap(X86_FEATURE_PSE); | ||
| 933 | return 0; | ||
| 934 | } | ||
| 935 | #endif | ||
| 936 | |||
| 937 | mem_size = memparse(p, &p); | ||
| 938 | end_user_pfn = mem_size>>PAGE_SHIFT; | ||
| 939 | return 0; | ||
| 940 | } | ||
| 941 | early_param("mem", parse_memopt); | ||
| 942 | |||
| 943 | static int userdef __initdata; | ||
| 944 | |||
| 945 | static int __init parse_memmap_opt(char *p) | ||
| 946 | { | ||
| 947 | char *oldp; | ||
| 948 | u64 start_at, mem_size; | ||
| 949 | |||
| 950 | if (!strcmp(p, "exactmap")) { | ||
| 951 | #ifdef CONFIG_CRASH_DUMP | ||
| 952 | /* | ||
| 953 | * If we are doing a crash dump, we still need to know | ||
| 954 | * the real mem size before original memory map is | ||
| 955 | * reset. | ||
| 956 | */ | ||
| 957 | e820_register_active_regions(0, 0, -1UL); | ||
| 958 | saved_max_pfn = e820_end_of_ram(); | ||
| 959 | remove_all_active_ranges(); | ||
| 960 | #endif | ||
| 961 | e820.nr_map = 0; | ||
| 962 | userdef = 1; | ||
| 963 | return 0; | ||
| 964 | } | ||
| 965 | |||
| 966 | oldp = p; | ||
| 967 | mem_size = memparse(p, &p); | ||
| 968 | if (p == oldp) | ||
| 969 | return -EINVAL; | ||
| 970 | |||
| 971 | userdef = 1; | ||
| 972 | if (*p == '@') { | ||
| 973 | start_at = memparse(p+1, &p); | ||
| 974 | e820_add_region(start_at, mem_size, E820_RAM); | ||
| 975 | } else if (*p == '#') { | ||
| 976 | start_at = memparse(p+1, &p); | ||
| 977 | e820_add_region(start_at, mem_size, E820_ACPI); | ||
| 978 | } else if (*p == '$') { | ||
| 979 | start_at = memparse(p+1, &p); | ||
| 980 | e820_add_region(start_at, mem_size, E820_RESERVED); | ||
| 981 | } else { | ||
| 982 | end_user_pfn = (mem_size >> PAGE_SHIFT); | ||
| 983 | } | ||
| 984 | return *p == '\0' ? 0 : -EINVAL; | ||
| 985 | } | ||
| 986 | early_param("memmap", parse_memmap_opt); | ||
| 987 | |||
| 988 | void __init finish_e820_parsing(void) | ||
| 989 | { | ||
| 990 | if (userdef) { | ||
| 991 | int nr = e820.nr_map; | ||
| 992 | |||
| 993 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0) | ||
| 994 | early_panic("Invalid user supplied memory map"); | ||
| 995 | e820.nr_map = nr; | ||
| 996 | |||
| 997 | printk(KERN_INFO "user-defined physical RAM map:\n"); | ||
| 998 | e820_print_map("user"); | ||
| 999 | } | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | /* | ||
| 1003 | * Mark e820 reserved areas as busy for the resource manager. | ||
| 1004 | */ | ||
| 1005 | void __init e820_reserve_resources(void) | ||
| 1006 | { | ||
| 1007 | int i; | ||
| 1008 | struct resource *res; | ||
| 1009 | |||
| 1010 | res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map); | ||
| 1011 | for (i = 0; i < e820.nr_map; i++) { | ||
| 1012 | switch (e820.map[i].type) { | ||
| 1013 | case E820_RAM: res->name = "System RAM"; break; | ||
| 1014 | case E820_ACPI: res->name = "ACPI Tables"; break; | ||
| 1015 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; | ||
| 1016 | default: res->name = "reserved"; | ||
| 1017 | } | ||
| 1018 | res->start = e820.map[i].addr; | ||
| 1019 | res->end = res->start + e820.map[i].size - 1; | ||
| 1020 | #ifndef CONFIG_RESOURCES_64BIT | ||
| 1021 | if (res->end > 0x100000000ULL) { | ||
| 1022 | res++; | ||
| 1023 | continue; | ||
| 1024 | } | ||
| 1025 | #endif | ||
| 1026 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
| 1027 | insert_resource(&iomem_resource, res); | ||
| 1028 | res++; | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | char *__init default_machine_specific_memory_setup(void) | ||
| 1033 | { | ||
| 1034 | char *who = "BIOS-e820"; | ||
| 1035 | int new_nr; | ||
| 1036 | /* | ||
| 1037 | * Try to copy the BIOS-supplied E820-map. | ||
| 1038 | * | ||
| 1039 | * Otherwise fake a memory map; one section from 0k->640k, | ||
| 1040 | * the next section from 1mb->appropriate_mem_k | ||
| 1041 | */ | ||
| 1042 | new_nr = boot_params.e820_entries; | ||
| 1043 | sanitize_e820_map(boot_params.e820_map, | ||
| 1044 | ARRAY_SIZE(boot_params.e820_map), | ||
| 1045 | &new_nr); | ||
| 1046 | boot_params.e820_entries = new_nr; | ||
| 1047 | if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0) { | ||
| 1048 | u64 mem_size; | ||
| 1049 | |||
| 1050 | /* compare results from other methods and take the greater */ | ||
| 1051 | if (boot_params.alt_mem_k | ||
| 1052 | < boot_params.screen_info.ext_mem_k) { | ||
| 1053 | mem_size = boot_params.screen_info.ext_mem_k; | ||
| 1054 | who = "BIOS-88"; | ||
| 1055 | } else { | ||
| 1056 | mem_size = boot_params.alt_mem_k; | ||
| 1057 | who = "BIOS-e801"; | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | e820.nr_map = 0; | ||
| 1061 | e820_add_region(0, LOWMEMSIZE(), E820_RAM); | ||
| 1062 | e820_add_region(HIGH_MEMORY, mem_size << 10, E820_RAM); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /* In case someone cares... */ | ||
| 1066 | return who; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | char *__init __attribute__((weak)) machine_specific_memory_setup(void) | ||
| 1070 | { | ||
| 1071 | return default_machine_specific_memory_setup(); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | /* Overridden in paravirt.c if CONFIG_PARAVIRT */ | ||
| 1075 | char * __init __attribute__((weak)) memory_setup(void) | ||
| 1076 | { | ||
| 1077 | return machine_specific_memory_setup(); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | void __init setup_memory_map(void) | ||
| 1081 | { | ||
| 1082 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | ||
| 1083 | e820_print_map(memory_setup()); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | #ifdef CONFIG_X86_64 | ||
| 935 | int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) | 1087 | int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) |
| 936 | { | 1088 | { |
| 937 | int i; | 1089 | int i; |
| @@ -950,3 +1102,4 @@ int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) | |||
| 950 | max_pfn << PAGE_SHIFT) - *addr; | 1102 | max_pfn << PAGE_SHIFT) - *addr; |
| 951 | return i + 1; | 1103 | return i + 1; |
| 952 | } | 1104 | } |
| 1105 | #endif | ||
diff --git a/arch/x86/kernel/e820_32.c b/arch/x86/kernel/e820_32.c deleted file mode 100644 index ed733e7cf4e6..000000000000 --- a/arch/x86/kernel/e820_32.c +++ /dev/null | |||
| @@ -1,775 +0,0 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/types.h> | ||
| 3 | #include <linux/init.h> | ||
| 4 | #include <linux/bootmem.h> | ||
| 5 | #include <linux/ioport.h> | ||
| 6 | #include <linux/string.h> | ||
| 7 | #include <linux/kexec.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/pfn.h> | ||
| 11 | #include <linux/uaccess.h> | ||
| 12 | #include <linux/suspend.h> | ||
| 13 | |||
| 14 | #include <asm/pgtable.h> | ||
| 15 | #include <asm/page.h> | ||
| 16 | #include <asm/e820.h> | ||
| 17 | #include <asm/setup.h> | ||
| 18 | |||
| 19 | struct e820map e820; | ||
| 20 | struct change_member { | ||
| 21 | struct e820entry *pbios; /* pointer to original bios entry */ | ||
| 22 | unsigned long long addr; /* address for this change point */ | ||
| 23 | }; | ||
| 24 | static struct change_member change_point_list[2*E820MAX] __initdata; | ||
| 25 | static struct change_member *change_point[2*E820MAX] __initdata; | ||
| 26 | static struct e820entry *overlap_list[E820MAX] __initdata; | ||
| 27 | static struct e820entry new_bios[E820MAX] __initdata; | ||
| 28 | /* For PCI or other memory-mapped resources */ | ||
| 29 | unsigned long pci_mem_start = 0x10000000; | ||
| 30 | #ifdef CONFIG_PCI | ||
| 31 | EXPORT_SYMBOL(pci_mem_start); | ||
| 32 | #endif | ||
| 33 | extern int user_defined_memmap; | ||
| 34 | |||
| 35 | static struct resource system_rom_resource = { | ||
| 36 | .name = "System ROM", | ||
| 37 | .start = 0xf0000, | ||
| 38 | .end = 0xfffff, | ||
| 39 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 40 | }; | ||
| 41 | |||
| 42 | static struct resource extension_rom_resource = { | ||
| 43 | .name = "Extension ROM", | ||
| 44 | .start = 0xe0000, | ||
| 45 | .end = 0xeffff, | ||
| 46 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct resource adapter_rom_resources[] = { { | ||
| 50 | .name = "Adapter ROM", | ||
| 51 | .start = 0xc8000, | ||
| 52 | .end = 0, | ||
| 53 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 54 | }, { | ||
| 55 | .name = "Adapter ROM", | ||
| 56 | .start = 0, | ||
| 57 | .end = 0, | ||
| 58 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 59 | }, { | ||
| 60 | .name = "Adapter ROM", | ||
| 61 | .start = 0, | ||
| 62 | .end = 0, | ||
| 63 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 64 | }, { | ||
| 65 | .name = "Adapter ROM", | ||
| 66 | .start = 0, | ||
| 67 | .end = 0, | ||
| 68 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 69 | }, { | ||
| 70 | .name = "Adapter ROM", | ||
| 71 | .start = 0, | ||
| 72 | .end = 0, | ||
| 73 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 74 | }, { | ||
| 75 | .name = "Adapter ROM", | ||
| 76 | .start = 0, | ||
| 77 | .end = 0, | ||
| 78 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 79 | } }; | ||
| 80 | |||
| 81 | static struct resource video_rom_resource = { | ||
| 82 | .name = "Video ROM", | ||
| 83 | .start = 0xc0000, | ||
| 84 | .end = 0xc7fff, | ||
| 85 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 86 | }; | ||
| 87 | |||
| 88 | #define ROMSIGNATURE 0xaa55 | ||
| 89 | |||
| 90 | static int __init romsignature(const unsigned char *rom) | ||
| 91 | { | ||
| 92 | const unsigned short * const ptr = (const unsigned short *)rom; | ||
| 93 | unsigned short sig; | ||
| 94 | |||
| 95 | return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int __init romchecksum(const unsigned char *rom, unsigned long length) | ||
| 99 | { | ||
| 100 | unsigned char sum, c; | ||
| 101 | |||
| 102 | for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) | ||
| 103 | sum += c; | ||
| 104 | return !length && !sum; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void __init probe_roms(void) | ||
| 108 | { | ||
| 109 | const unsigned char *rom; | ||
| 110 | unsigned long start, length, upper; | ||
| 111 | unsigned char c; | ||
| 112 | int i; | ||
| 113 | |||
| 114 | /* video rom */ | ||
| 115 | upper = adapter_rom_resources[0].start; | ||
| 116 | for (start = video_rom_resource.start; start < upper; start += 2048) { | ||
| 117 | rom = isa_bus_to_virt(start); | ||
| 118 | if (!romsignature(rom)) | ||
| 119 | continue; | ||
| 120 | |||
| 121 | video_rom_resource.start = start; | ||
| 122 | |||
| 123 | if (probe_kernel_address(rom + 2, c) != 0) | ||
| 124 | continue; | ||
| 125 | |||
| 126 | /* 0 < length <= 0x7f * 512, historically */ | ||
| 127 | length = c * 512; | ||
| 128 | |||
| 129 | /* if checksum okay, trust length byte */ | ||
| 130 | if (length && romchecksum(rom, length)) | ||
| 131 | video_rom_resource.end = start + length - 1; | ||
| 132 | |||
| 133 | request_resource(&iomem_resource, &video_rom_resource); | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | start = (video_rom_resource.end + 1 + 2047) & ~2047UL; | ||
| 138 | if (start < upper) | ||
| 139 | start = upper; | ||
| 140 | |||
| 141 | /* system rom */ | ||
| 142 | request_resource(&iomem_resource, &system_rom_resource); | ||
| 143 | upper = system_rom_resource.start; | ||
| 144 | |||
| 145 | /* check for extension rom (ignore length byte!) */ | ||
| 146 | rom = isa_bus_to_virt(extension_rom_resource.start); | ||
| 147 | if (romsignature(rom)) { | ||
| 148 | length = extension_rom_resource.end - extension_rom_resource.start + 1; | ||
| 149 | if (romchecksum(rom, length)) { | ||
| 150 | request_resource(&iomem_resource, &extension_rom_resource); | ||
| 151 | upper = extension_rom_resource.start; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | /* check for adapter roms on 2k boundaries */ | ||
| 156 | for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { | ||
| 157 | rom = isa_bus_to_virt(start); | ||
| 158 | if (!romsignature(rom)) | ||
| 159 | continue; | ||
| 160 | |||
| 161 | if (probe_kernel_address(rom + 2, c) != 0) | ||
| 162 | continue; | ||
| 163 | |||
| 164 | /* 0 < length <= 0x7f * 512, historically */ | ||
| 165 | length = c * 512; | ||
| 166 | |||
| 167 | /* but accept any length that fits if checksum okay */ | ||
| 168 | if (!length || start + length > upper || !romchecksum(rom, length)) | ||
| 169 | continue; | ||
| 170 | |||
| 171 | adapter_rom_resources[i].start = start; | ||
| 172 | adapter_rom_resources[i].end = start + length - 1; | ||
| 173 | request_resource(&iomem_resource, &adapter_rom_resources[i]); | ||
| 174 | |||
| 175 | start = adapter_rom_resources[i++].end & ~2047UL; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Request address space for all standard RAM and ROM resources | ||
| 181 | * and also for regions reported as reserved by the e820. | ||
| 182 | */ | ||
| 183 | void __init init_iomem_resources(struct resource *code_resource, | ||
| 184 | struct resource *data_resource, | ||
| 185 | struct resource *bss_resource) | ||
| 186 | { | ||
| 187 | int i; | ||
| 188 | |||
| 189 | probe_roms(); | ||
| 190 | for (i = 0; i < e820.nr_map; i++) { | ||
| 191 | struct resource *res; | ||
| 192 | #ifndef CONFIG_RESOURCES_64BIT | ||
| 193 | if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) | ||
| 194 | continue; | ||
| 195 | #endif | ||
| 196 | res = kzalloc(sizeof(struct resource), GFP_ATOMIC); | ||
| 197 | switch (e820.map[i].type) { | ||
| 198 | case E820_RAM: res->name = "System RAM"; break; | ||
| 199 | case E820_ACPI: res->name = "ACPI Tables"; break; | ||
| 200 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; | ||
| 201 | default: res->name = "reserved"; | ||
| 202 | } | ||
| 203 | res->start = e820.map[i].addr; | ||
| 204 | res->end = res->start + e820.map[i].size - 1; | ||
| 205 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
| 206 | if (request_resource(&iomem_resource, res)) { | ||
| 207 | kfree(res); | ||
| 208 | continue; | ||
| 209 | } | ||
| 210 | if (e820.map[i].type == E820_RAM) { | ||
| 211 | /* | ||
| 212 | * We don't know which RAM region contains kernel data, | ||
| 213 | * so we try it repeatedly and let the resource manager | ||
| 214 | * test it. | ||
| 215 | */ | ||
| 216 | request_resource(res, code_resource); | ||
| 217 | request_resource(res, data_resource); | ||
| 218 | request_resource(res, bss_resource); | ||
| 219 | #ifdef CONFIG_KEXEC | ||
| 220 | if (crashk_res.start != crashk_res.end) | ||
| 221 | request_resource(res, &crashk_res); | ||
| 222 | #endif | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | #if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION) | ||
| 228 | /** | ||
| 229 | * e820_mark_nosave_regions - Find the ranges of physical addresses that do not | ||
| 230 | * correspond to e820 RAM areas and mark the corresponding pages as nosave for | ||
| 231 | * hibernation. | ||
| 232 | * | ||
| 233 | * This function requires the e820 map to be sorted and without any | ||
| 234 | * overlapping entries and assumes the first e820 area to be RAM. | ||
| 235 | */ | ||
| 236 | void __init e820_mark_nosave_regions(void) | ||
| 237 | { | ||
| 238 | int i; | ||
| 239 | unsigned long pfn; | ||
| 240 | |||
| 241 | pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size); | ||
| 242 | for (i = 1; i < e820.nr_map; i++) { | ||
| 243 | struct e820entry *ei = &e820.map[i]; | ||
| 244 | |||
| 245 | if (pfn < PFN_UP(ei->addr)) | ||
| 246 | register_nosave_region(pfn, PFN_UP(ei->addr)); | ||
| 247 | |||
| 248 | pfn = PFN_DOWN(ei->addr + ei->size); | ||
| 249 | if (ei->type != E820_RAM) | ||
| 250 | register_nosave_region(PFN_UP(ei->addr), pfn); | ||
| 251 | |||
| 252 | if (pfn >= max_low_pfn) | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | #endif | ||
| 257 | |||
| 258 | void __init add_memory_region(unsigned long long start, | ||
| 259 | unsigned long long size, int type) | ||
| 260 | { | ||
| 261 | int x; | ||
| 262 | |||
| 263 | x = e820.nr_map; | ||
| 264 | |||
| 265 | if (x == E820MAX) { | ||
| 266 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | ||
| 267 | return; | ||
| 268 | } | ||
| 269 | |||
| 270 | e820.map[x].addr = start; | ||
| 271 | e820.map[x].size = size; | ||
| 272 | e820.map[x].type = type; | ||
| 273 | e820.nr_map++; | ||
| 274 | } /* add_memory_region */ | ||
| 275 | |||
| 276 | /* | ||
| 277 | * Sanitize the BIOS e820 map. | ||
| 278 | * | ||
| 279 | * Some e820 responses include overlapping entries. The following | ||
| 280 | * replaces the original e820 map with a new one, removing overlaps. | ||
| 281 | * | ||
| 282 | */ | ||
| 283 | int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) | ||
| 284 | { | ||
| 285 | struct change_member *change_tmp; | ||
| 286 | unsigned long current_type, last_type; | ||
| 287 | unsigned long long last_addr; | ||
| 288 | int chgidx, still_changing; | ||
| 289 | int overlap_entries; | ||
| 290 | int new_bios_entry; | ||
| 291 | int old_nr, new_nr, chg_nr; | ||
| 292 | int i; | ||
| 293 | |||
| 294 | /* | ||
| 295 | Visually we're performing the following (1,2,3,4 = memory types)... | ||
| 296 | |||
| 297 | Sample memory map (w/overlaps): | ||
| 298 | ____22__________________ | ||
| 299 | ______________________4_ | ||
| 300 | ____1111________________ | ||
| 301 | _44_____________________ | ||
| 302 | 11111111________________ | ||
| 303 | ____________________33__ | ||
| 304 | ___________44___________ | ||
| 305 | __________33333_________ | ||
| 306 | ______________22________ | ||
| 307 | ___________________2222_ | ||
| 308 | _________111111111______ | ||
| 309 | _____________________11_ | ||
| 310 | _________________4______ | ||
| 311 | |||
| 312 | Sanitized equivalent (no overlap): | ||
| 313 | 1_______________________ | ||
| 314 | _44_____________________ | ||
| 315 | ___1____________________ | ||
| 316 | ____22__________________ | ||
| 317 | ______11________________ | ||
| 318 | _________1______________ | ||
| 319 | __________3_____________ | ||
| 320 | ___________44___________ | ||
| 321 | _____________33_________ | ||
| 322 | _______________2________ | ||
| 323 | ________________1_______ | ||
| 324 | _________________4______ | ||
| 325 | ___________________2____ | ||
| 326 | ____________________33__ | ||
| 327 | ______________________4_ | ||
| 328 | */ | ||
| 329 | /* if there's only one memory region, don't bother */ | ||
| 330 | if (*pnr_map < 2) { | ||
| 331 | return -1; | ||
| 332 | } | ||
| 333 | |||
| 334 | old_nr = *pnr_map; | ||
| 335 | |||
| 336 | /* bail out if we find any unreasonable addresses in bios map */ | ||
| 337 | for (i=0; i<old_nr; i++) | ||
| 338 | if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) { | ||
| 339 | return -1; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* create pointers for initial change-point information (for sorting) */ | ||
| 343 | for (i=0; i < 2*old_nr; i++) | ||
| 344 | change_point[i] = &change_point_list[i]; | ||
| 345 | |||
| 346 | /* record all known change-points (starting and ending addresses), | ||
| 347 | omitting those that are for empty memory regions */ | ||
| 348 | chgidx = 0; | ||
| 349 | for (i=0; i < old_nr; i++) { | ||
| 350 | if (biosmap[i].size != 0) { | ||
| 351 | change_point[chgidx]->addr = biosmap[i].addr; | ||
| 352 | change_point[chgidx++]->pbios = &biosmap[i]; | ||
| 353 | change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; | ||
| 354 | change_point[chgidx++]->pbios = &biosmap[i]; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | chg_nr = chgidx; /* true number of change-points */ | ||
| 358 | |||
| 359 | /* sort change-point list by memory addresses (low -> high) */ | ||
| 360 | still_changing = 1; | ||
| 361 | while (still_changing) { | ||
| 362 | still_changing = 0; | ||
| 363 | for (i=1; i < chg_nr; i++) { | ||
| 364 | /* if <current_addr> > <last_addr>, swap */ | ||
| 365 | /* or, if current=<start_addr> & last=<end_addr>, swap */ | ||
| 366 | if ((change_point[i]->addr < change_point[i-1]->addr) || | ||
| 367 | ((change_point[i]->addr == change_point[i-1]->addr) && | ||
| 368 | (change_point[i]->addr == change_point[i]->pbios->addr) && | ||
| 369 | (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) | ||
| 370 | ) | ||
| 371 | { | ||
| 372 | change_tmp = change_point[i]; | ||
| 373 | change_point[i] = change_point[i-1]; | ||
| 374 | change_point[i-1] = change_tmp; | ||
| 375 | still_changing=1; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /* create a new bios memory map, removing overlaps */ | ||
| 381 | overlap_entries=0; /* number of entries in the overlap table */ | ||
| 382 | new_bios_entry=0; /* index for creating new bios map entries */ | ||
| 383 | last_type = 0; /* start with undefined memory type */ | ||
| 384 | last_addr = 0; /* start with 0 as last starting address */ | ||
| 385 | /* loop through change-points, determining affect on the new bios map */ | ||
| 386 | for (chgidx=0; chgidx < chg_nr; chgidx++) | ||
| 387 | { | ||
| 388 | /* keep track of all overlapping bios entries */ | ||
| 389 | if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) | ||
| 390 | { | ||
| 391 | /* add map entry to overlap list (> 1 entry implies an overlap) */ | ||
| 392 | overlap_list[overlap_entries++]=change_point[chgidx]->pbios; | ||
| 393 | } | ||
| 394 | else | ||
| 395 | { | ||
| 396 | /* remove entry from list (order independent, so swap with last) */ | ||
| 397 | for (i=0; i<overlap_entries; i++) | ||
| 398 | { | ||
| 399 | if (overlap_list[i] == change_point[chgidx]->pbios) | ||
| 400 | overlap_list[i] = overlap_list[overlap_entries-1]; | ||
| 401 | } | ||
| 402 | overlap_entries--; | ||
| 403 | } | ||
| 404 | /* if there are overlapping entries, decide which "type" to use */ | ||
| 405 | /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ | ||
| 406 | current_type = 0; | ||
| 407 | for (i=0; i<overlap_entries; i++) | ||
| 408 | if (overlap_list[i]->type > current_type) | ||
| 409 | current_type = overlap_list[i]->type; | ||
| 410 | /* continue building up new bios map based on this information */ | ||
| 411 | if (current_type != last_type) { | ||
| 412 | if (last_type != 0) { | ||
| 413 | new_bios[new_bios_entry].size = | ||
| 414 | change_point[chgidx]->addr - last_addr; | ||
| 415 | /* move forward only if the new size was non-zero */ | ||
| 416 | if (new_bios[new_bios_entry].size != 0) | ||
| 417 | if (++new_bios_entry >= E820MAX) | ||
| 418 | break; /* no more space left for new bios entries */ | ||
| 419 | } | ||
| 420 | if (current_type != 0) { | ||
| 421 | new_bios[new_bios_entry].addr = change_point[chgidx]->addr; | ||
| 422 | new_bios[new_bios_entry].type = current_type; | ||
| 423 | last_addr=change_point[chgidx]->addr; | ||
| 424 | } | ||
| 425 | last_type = current_type; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | new_nr = new_bios_entry; /* retain count for new bios entries */ | ||
| 429 | |||
| 430 | /* copy new bios mapping into original location */ | ||
| 431 | memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); | ||
| 432 | *pnr_map = new_nr; | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | /* | ||
| 438 | * Copy the BIOS e820 map into a safe place. | ||
| 439 | * | ||
| 440 | * Sanity-check it while we're at it.. | ||
| 441 | * | ||
| 442 | * If we're lucky and live on a modern system, the setup code | ||
| 443 | * will have given us a memory map that we can use to properly | ||
| 444 | * set up memory. If we aren't, we'll fake a memory map. | ||
| 445 | * | ||
| 446 | * We check to see that the memory map contains at least 2 elements | ||
| 447 | * before we'll use it, because the detection code in setup.S may | ||
| 448 | * not be perfect and most every PC known to man has two memory | ||
| 449 | * regions: one from 0 to 640k, and one from 1mb up. (The IBM | ||
| 450 | * thinkpad 560x, for example, does not cooperate with the memory | ||
| 451 | * detection code.) | ||
| 452 | */ | ||
| 453 | int __init copy_e820_map(struct e820entry *biosmap, int nr_map) | ||
| 454 | { | ||
| 455 | /* Only one memory region (or negative)? Ignore it */ | ||
| 456 | if (nr_map < 2) | ||
| 457 | return -1; | ||
| 458 | |||
| 459 | do { | ||
| 460 | u64 start = biosmap->addr; | ||
| 461 | u64 size = biosmap->size; | ||
| 462 | u64 end = start + size; | ||
| 463 | u32 type = biosmap->type; | ||
| 464 | |||
| 465 | /* Overflow in 64 bits? Ignore the memory map. */ | ||
| 466 | if (start > end) | ||
| 467 | return -1; | ||
| 468 | |||
| 469 | add_memory_region(start, size, type); | ||
| 470 | } while (biosmap++, --nr_map); | ||
| 471 | |||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | /* | ||
| 476 | * Find the highest page frame number we have available | ||
| 477 | */ | ||
| 478 | void __init propagate_e820_map(void) | ||
| 479 | { | ||
| 480 | int i; | ||
| 481 | |||
| 482 | max_pfn = 0; | ||
| 483 | |||
| 484 | for (i = 0; i < e820.nr_map; i++) { | ||
| 485 | unsigned long start, end; | ||
| 486 | /* RAM? */ | ||
| 487 | if (e820.map[i].type != E820_RAM) | ||
| 488 | continue; | ||
| 489 | start = PFN_UP(e820.map[i].addr); | ||
| 490 | end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); | ||
| 491 | if (start >= end) | ||
| 492 | continue; | ||
| 493 | if (end > max_pfn) | ||
| 494 | max_pfn = end; | ||
| 495 | memory_present(0, start, end); | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | /* | ||
| 500 | * Register fully available low RAM pages with the bootmem allocator. | ||
| 501 | */ | ||
| 502 | void __init register_bootmem_low_pages(unsigned long max_low_pfn) | ||
| 503 | { | ||
| 504 | int i; | ||
| 505 | |||
| 506 | for (i = 0; i < e820.nr_map; i++) { | ||
| 507 | unsigned long curr_pfn, last_pfn, size; | ||
| 508 | /* | ||
| 509 | * Reserve usable low memory | ||
| 510 | */ | ||
| 511 | if (e820.map[i].type != E820_RAM) | ||
| 512 | continue; | ||
| 513 | /* | ||
| 514 | * We are rounding up the start address of usable memory: | ||
| 515 | */ | ||
| 516 | curr_pfn = PFN_UP(e820.map[i].addr); | ||
| 517 | if (curr_pfn >= max_low_pfn) | ||
| 518 | continue; | ||
| 519 | /* | ||
| 520 | * ... and at the end of the usable range downwards: | ||
| 521 | */ | ||
| 522 | last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); | ||
| 523 | |||
| 524 | if (last_pfn > max_low_pfn) | ||
| 525 | last_pfn = max_low_pfn; | ||
| 526 | |||
| 527 | /* | ||
| 528 | * .. finally, did all the rounding and playing | ||
| 529 | * around just make the area go away? | ||
| 530 | */ | ||
| 531 | if (last_pfn <= curr_pfn) | ||
| 532 | continue; | ||
| 533 | |||
| 534 | size = last_pfn - curr_pfn; | ||
| 535 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | void __init e820_register_memory(void) | ||
| 540 | { | ||
| 541 | unsigned long gapstart, gapsize, round; | ||
| 542 | unsigned long long last; | ||
| 543 | int i; | ||
| 544 | |||
| 545 | /* | ||
| 546 | * Search for the biggest gap in the low 32 bits of the e820 | ||
| 547 | * memory space. | ||
| 548 | */ | ||
| 549 | last = 0x100000000ull; | ||
| 550 | gapstart = 0x10000000; | ||
| 551 | gapsize = 0x400000; | ||
| 552 | i = e820.nr_map; | ||
| 553 | while (--i >= 0) { | ||
| 554 | unsigned long long start = e820.map[i].addr; | ||
| 555 | unsigned long long end = start + e820.map[i].size; | ||
| 556 | |||
| 557 | /* | ||
| 558 | * Since "last" is at most 4GB, we know we'll | ||
| 559 | * fit in 32 bits if this condition is true | ||
| 560 | */ | ||
| 561 | if (last > end) { | ||
| 562 | unsigned long gap = last - end; | ||
| 563 | |||
| 564 | if (gap > gapsize) { | ||
| 565 | gapsize = gap; | ||
| 566 | gapstart = end; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | if (start < last) | ||
| 570 | last = start; | ||
| 571 | } | ||
| 572 | |||
| 573 | /* | ||
| 574 | * See how much we want to round up: start off with | ||
| 575 | * rounding to the next 1MB area. | ||
| 576 | */ | ||
| 577 | round = 0x100000; | ||
| 578 | while ((gapsize >> 4) > round) | ||
| 579 | round += round; | ||
| 580 | /* Fun with two's complement */ | ||
| 581 | pci_mem_start = (gapstart + round) & -round; | ||
| 582 | |||
| 583 | printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", | ||
| 584 | pci_mem_start, gapstart, gapsize); | ||
| 585 | } | ||
| 586 | |||
| 587 | void __init print_memory_map(char *who) | ||
| 588 | { | ||
| 589 | int i; | ||
| 590 | |||
| 591 | for (i = 0; i < e820.nr_map; i++) { | ||
| 592 | printk(" %s: %016Lx - %016Lx ", who, | ||
| 593 | e820.map[i].addr, | ||
| 594 | e820.map[i].addr + e820.map[i].size); | ||
| 595 | switch (e820.map[i].type) { | ||
| 596 | case E820_RAM: printk("(usable)\n"); | ||
| 597 | break; | ||
| 598 | case E820_RESERVED: | ||
| 599 | printk("(reserved)\n"); | ||
| 600 | break; | ||
| 601 | case E820_ACPI: | ||
| 602 | printk("(ACPI data)\n"); | ||
| 603 | break; | ||
| 604 | case E820_NVS: | ||
| 605 | printk("(ACPI NVS)\n"); | ||
| 606 | break; | ||
| 607 | default: printk("type %u\n", e820.map[i].type); | ||
| 608 | break; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | void __init limit_regions(unsigned long long size) | ||
| 614 | { | ||
| 615 | unsigned long long current_addr; | ||
| 616 | int i; | ||
| 617 | |||
| 618 | print_memory_map("limit_regions start"); | ||
| 619 | for (i = 0; i < e820.nr_map; i++) { | ||
| 620 | current_addr = e820.map[i].addr + e820.map[i].size; | ||
| 621 | if (current_addr < size) | ||
| 622 | continue; | ||
| 623 | |||
| 624 | if (e820.map[i].type != E820_RAM) | ||
| 625 | continue; | ||
| 626 | |||
| 627 | if (e820.map[i].addr >= size) { | ||
| 628 | /* | ||
| 629 | * This region starts past the end of the | ||
| 630 | * requested size, skip it completely. | ||
| 631 | */ | ||
| 632 | e820.nr_map = i; | ||
| 633 | } else { | ||
| 634 | e820.nr_map = i + 1; | ||
| 635 | e820.map[i].size -= current_addr - size; | ||
| 636 | } | ||
| 637 | print_memory_map("limit_regions endfor"); | ||
| 638 | return; | ||
| 639 | } | ||
| 640 | print_memory_map("limit_regions endfunc"); | ||
| 641 | } | ||
| 642 | |||
| 643 | /* | ||
| 644 | * This function checks if any part of the range <start,end> is mapped | ||
| 645 | * with type. | ||
| 646 | */ | ||
| 647 | int | ||
| 648 | e820_any_mapped(u64 start, u64 end, unsigned type) | ||
| 649 | { | ||
| 650 | int i; | ||
| 651 | for (i = 0; i < e820.nr_map; i++) { | ||
| 652 | const struct e820entry *ei = &e820.map[i]; | ||
| 653 | if (type && ei->type != type) | ||
| 654 | continue; | ||
| 655 | if (ei->addr >= end || ei->addr + ei->size <= start) | ||
| 656 | continue; | ||
| 657 | return 1; | ||
| 658 | } | ||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | EXPORT_SYMBOL_GPL(e820_any_mapped); | ||
| 662 | |||
| 663 | /* | ||
| 664 | * This function checks if the entire range <start,end> is mapped with type. | ||
| 665 | * | ||
| 666 | * Note: this function only works correct if the e820 table is sorted and | ||
| 667 | * not-overlapping, which is the case | ||
| 668 | */ | ||
| 669 | int __init | ||
| 670 | e820_all_mapped(unsigned long s, unsigned long e, unsigned type) | ||
| 671 | { | ||
| 672 | u64 start = s; | ||
| 673 | u64 end = e; | ||
| 674 | int i; | ||
| 675 | for (i = 0; i < e820.nr_map; i++) { | ||
| 676 | struct e820entry *ei = &e820.map[i]; | ||
| 677 | if (type && ei->type != type) | ||
| 678 | continue; | ||
| 679 | /* is the region (part) in overlap with the current region ?*/ | ||
| 680 | if (ei->addr >= end || ei->addr + ei->size <= start) | ||
| 681 | continue; | ||
| 682 | /* if the region is at the beginning of <start,end> we move | ||
| 683 | * start to the end of the region since it's ok until there | ||
| 684 | */ | ||
| 685 | if (ei->addr <= start) | ||
| 686 | start = ei->addr + ei->size; | ||
| 687 | /* if start is now at or beyond end, we're done, full | ||
| 688 | * coverage */ | ||
| 689 | if (start >= end) | ||
| 690 | return 1; /* we're done */ | ||
| 691 | } | ||
| 692 | return 0; | ||
| 693 | } | ||
| 694 | |||
| 695 | static int __init parse_memmap(char *arg) | ||
| 696 | { | ||
| 697 | if (!arg) | ||
| 698 | return -EINVAL; | ||
| 699 | |||
| 700 | if (strcmp(arg, "exactmap") == 0) { | ||
| 701 | #ifdef CONFIG_CRASH_DUMP | ||
| 702 | /* If we are doing a crash dump, we | ||
| 703 | * still need to know the real mem | ||
| 704 | * size before original memory map is | ||
| 705 | * reset. | ||
| 706 | */ | ||
| 707 | propagate_e820_map(); | ||
| 708 | saved_max_pfn = max_pfn; | ||
| 709 | #endif | ||
| 710 | e820.nr_map = 0; | ||
| 711 | user_defined_memmap = 1; | ||
| 712 | } else { | ||
| 713 | /* If the user specifies memory size, we | ||
| 714 | * limit the BIOS-provided memory map to | ||
| 715 | * that size. exactmap can be used to specify | ||
| 716 | * the exact map. mem=number can be used to | ||
| 717 | * trim the existing memory map. | ||
| 718 | */ | ||
| 719 | unsigned long long start_at, mem_size; | ||
| 720 | |||
| 721 | mem_size = memparse(arg, &arg); | ||
| 722 | if (*arg == '@') { | ||
| 723 | start_at = memparse(arg+1, &arg); | ||
| 724 | add_memory_region(start_at, mem_size, E820_RAM); | ||
| 725 | } else if (*arg == '#') { | ||
| 726 | start_at = memparse(arg+1, &arg); | ||
| 727 | add_memory_region(start_at, mem_size, E820_ACPI); | ||
| 728 | } else if (*arg == '$') { | ||
| 729 | start_at = memparse(arg+1, &arg); | ||
| 730 | add_memory_region(start_at, mem_size, E820_RESERVED); | ||
| 731 | } else { | ||
| 732 | limit_regions(mem_size); | ||
| 733 | user_defined_memmap = 1; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | return 0; | ||
| 737 | } | ||
| 738 | early_param("memmap", parse_memmap); | ||
| 739 | void __init update_memory_range(u64 start, u64 size, unsigned old_type, | ||
| 740 | unsigned new_type) | ||
| 741 | { | ||
| 742 | int i; | ||
| 743 | |||
| 744 | BUG_ON(old_type == new_type); | ||
| 745 | |||
| 746 | for (i = 0; i < e820.nr_map; i++) { | ||
| 747 | struct e820entry *ei = &e820.map[i]; | ||
| 748 | u64 final_start, final_end; | ||
| 749 | if (ei->type != old_type) | ||
| 750 | continue; | ||
| 751 | /* totally covered? */ | ||
| 752 | if (ei->addr >= start && ei->size <= size) { | ||
| 753 | ei->type = new_type; | ||
| 754 | continue; | ||
| 755 | } | ||
| 756 | /* partially covered */ | ||
| 757 | final_start = max(start, ei->addr); | ||
| 758 | final_end = min(start + size, ei->addr + ei->size); | ||
| 759 | if (final_start >= final_end) | ||
| 760 | continue; | ||
| 761 | add_memory_region(final_start, final_end - final_start, | ||
| 762 | new_type); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | void __init update_e820(void) | ||
| 766 | { | ||
| 767 | u8 nr_map; | ||
| 768 | |||
| 769 | nr_map = e820.nr_map; | ||
| 770 | if (sanitize_e820_map(e820.map, &nr_map)) | ||
| 771 | return; | ||
| 772 | e820.nr_map = nr_map; | ||
| 773 | printk(KERN_INFO "modified physical RAM map:\n"); | ||
| 774 | print_memory_map("modified"); | ||
| 775 | } | ||
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c index 77d424cf68b3..473c89fe5073 100644 --- a/arch/x86/kernel/efi.c +++ b/arch/x86/kernel/efi.c | |||
| @@ -213,6 +213,48 @@ unsigned long efi_get_time(void) | |||
| 213 | eft.minute, eft.second); | 213 | eft.minute, eft.second); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* | ||
| 217 | * Tell the kernel about the EFI memory map. This might include | ||
| 218 | * more than the max 128 entries that can fit in the e820 legacy | ||
| 219 | * (zeropage) memory map. | ||
| 220 | */ | ||
| 221 | |||
| 222 | static void __init add_efi_memmap(void) | ||
| 223 | { | ||
| 224 | void *p; | ||
| 225 | |||
| 226 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | ||
| 227 | efi_memory_desc_t *md = p; | ||
| 228 | unsigned long long start = md->phys_addr; | ||
| 229 | unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; | ||
| 230 | int e820_type; | ||
| 231 | |||
| 232 | if (md->attribute & EFI_MEMORY_WB) | ||
| 233 | e820_type = E820_RAM; | ||
| 234 | else | ||
| 235 | e820_type = E820_RESERVED; | ||
| 236 | e820_add_region(start, size, e820_type); | ||
| 237 | } | ||
| 238 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | ||
| 239 | } | ||
| 240 | |||
| 241 | void __init efi_reserve_early(void) | ||
| 242 | { | ||
| 243 | unsigned long pmap; | ||
| 244 | |||
| 245 | pmap = boot_params.efi_info.efi_memmap; | ||
| 246 | #ifdef CONFIG_X86_64 | ||
| 247 | pmap += (__u64)boot_params.efi_info.efi_memmap_hi << 32; | ||
| 248 | #endif | ||
| 249 | memmap.phys_map = (void *)pmap; | ||
| 250 | memmap.nr_map = boot_params.efi_info.efi_memmap_size / | ||
| 251 | boot_params.efi_info.efi_memdesc_size; | ||
| 252 | memmap.desc_version = boot_params.efi_info.efi_memdesc_version; | ||
| 253 | memmap.desc_size = boot_params.efi_info.efi_memdesc_size; | ||
| 254 | reserve_early(pmap, pmap + memmap.nr_map * memmap.desc_size, | ||
| 255 | "EFI memmap"); | ||
| 256 | } | ||
| 257 | |||
| 216 | #if EFI_DEBUG | 258 | #if EFI_DEBUG |
| 217 | static void __init print_efi_memmap(void) | 259 | static void __init print_efi_memmap(void) |
| 218 | { | 260 | { |
| @@ -242,21 +284,11 @@ void __init efi_init(void) | |||
| 242 | int i = 0; | 284 | int i = 0; |
| 243 | void *tmp; | 285 | void *tmp; |
| 244 | 286 | ||
| 245 | #ifdef CONFIG_X86_32 | ||
| 246 | efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; | 287 | efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; |
| 247 | memmap.phys_map = (void *)boot_params.efi_info.efi_memmap; | 288 | #ifdef CONFIG_X86_64 |
| 248 | #else | 289 | efi_phys.systab = (void *)efi_phys.systab + |
| 249 | efi_phys.systab = (efi_system_table_t *) | 290 | ((__u64)boot_params.efi_info.efi_systab_hi<<32); |
| 250 | (boot_params.efi_info.efi_systab | | ||
| 251 | ((__u64)boot_params.efi_info.efi_systab_hi<<32)); | ||
| 252 | memmap.phys_map = (void *) | ||
| 253 | (boot_params.efi_info.efi_memmap | | ||
| 254 | ((__u64)boot_params.efi_info.efi_memmap_hi<<32)); | ||
| 255 | #endif | 291 | #endif |
| 256 | memmap.nr_map = boot_params.efi_info.efi_memmap_size / | ||
| 257 | boot_params.efi_info.efi_memdesc_size; | ||
| 258 | memmap.desc_version = boot_params.efi_info.efi_memdesc_version; | ||
| 259 | memmap.desc_size = boot_params.efi_info.efi_memdesc_size; | ||
| 260 | 292 | ||
| 261 | efi.systab = early_ioremap((unsigned long)efi_phys.systab, | 293 | efi.systab = early_ioremap((unsigned long)efi_phys.systab, |
| 262 | sizeof(efi_system_table_t)); | 294 | sizeof(efi_system_table_t)); |
| @@ -370,6 +402,7 @@ void __init efi_init(void) | |||
| 370 | if (memmap.desc_size != sizeof(efi_memory_desc_t)) | 402 | if (memmap.desc_size != sizeof(efi_memory_desc_t)) |
| 371 | printk(KERN_WARNING "Kernel-defined memdesc" | 403 | printk(KERN_WARNING "Kernel-defined memdesc" |
| 372 | "doesn't match the one from EFI!\n"); | 404 | "doesn't match the one from EFI!\n"); |
| 405 | add_efi_memmap(); | ||
| 373 | 406 | ||
| 374 | /* Setup for EFI runtime service */ | 407 | /* Setup for EFI runtime service */ |
| 375 | reboot_type = BOOT_EFI; | 408 | reboot_type = BOOT_EFI; |
diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c index d0060fdcccac..652c5287215f 100644 --- a/arch/x86/kernel/efi_64.c +++ b/arch/x86/kernel/efi_64.c | |||
| @@ -97,13 +97,7 @@ void __init efi_call_phys_epilog(void) | |||
| 97 | early_runtime_code_mapping_set_exec(0); | 97 | early_runtime_code_mapping_set_exec(0); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void __init efi_reserve_bootmem(void) | 100 | void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size) |
| 101 | { | ||
| 102 | reserve_bootmem_generic((unsigned long)memmap.phys_map, | ||
| 103 | memmap.nr_map * memmap.desc_size); | ||
| 104 | } | ||
| 105 | |||
| 106 | void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size) | ||
| 107 | { | 101 | { |
| 108 | static unsigned pages_mapped __initdata; | 102 | static unsigned pages_mapped __initdata; |
| 109 | unsigned i, pages; | 103 | unsigned i, pages; |
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c index cbaaf69bedb2..1fa8be5bd217 100644 --- a/arch/x86/kernel/genapic_64.c +++ b/arch/x86/kernel/genapic_64.c | |||
| @@ -51,7 +51,7 @@ void __init setup_apic_routing(void) | |||
| 51 | else | 51 | else |
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | if (num_possible_cpus() <= 8) | 54 | if (max_physical_apicid < 8) |
| 55 | genapic = &apic_flat; | 55 | genapic = &apic_flat; |
| 56 | else | 56 | else |
| 57 | genapic = &apic_physflat; | 57 | genapic = &apic_physflat; |
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c new file mode 100644 index 000000000000..a727c0b9819c --- /dev/null +++ b/arch/x86/kernel/head.c | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/init.h> | ||
| 3 | |||
| 4 | #include <asm/setup.h> | ||
| 5 | #include <asm/bios_ebda.h> | ||
| 6 | |||
| 7 | #define BIOS_LOWMEM_KILOBYTES 0x413 | ||
| 8 | |||
| 9 | /* | ||
| 10 | * The BIOS places the EBDA/XBDA at the top of conventional | ||
| 11 | * memory, and usually decreases the reported amount of | ||
| 12 | * conventional memory (int 0x12) too. This also contains a | ||
| 13 | * workaround for Dell systems that neglect to reserve EBDA. | ||
| 14 | * The same workaround also avoids a problem with the AMD768MPX | ||
| 15 | * chipset: reserve a page before VGA to prevent PCI prefetch | ||
| 16 | * into it (errata #56). Usually the page is reserved anyways, | ||
| 17 | * unless you have no PS/2 mouse plugged in. | ||
| 18 | */ | ||
| 19 | void __init reserve_ebda_region(void) | ||
| 20 | { | ||
| 21 | unsigned int lowmem, ebda_addr; | ||
| 22 | |||
| 23 | /* To determine the position of the EBDA and the */ | ||
| 24 | /* end of conventional memory, we need to look at */ | ||
| 25 | /* the BIOS data area. In a paravirtual environment */ | ||
| 26 | /* that area is absent. We'll just have to assume */ | ||
| 27 | /* that the paravirt case can handle memory setup */ | ||
| 28 | /* correctly, without our help. */ | ||
| 29 | if (paravirt_enabled()) | ||
| 30 | return; | ||
| 31 | |||
| 32 | /* end of low (conventional) memory */ | ||
| 33 | lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); | ||
| 34 | lowmem <<= 10; | ||
| 35 | |||
| 36 | /* start of EBDA area */ | ||
| 37 | ebda_addr = get_bios_ebda(); | ||
| 38 | |||
| 39 | /* Fixup: bios puts an EBDA in the top 64K segment */ | ||
| 40 | /* of conventional memory, but does not adjust lowmem. */ | ||
| 41 | if ((lowmem - ebda_addr) <= 0x10000) | ||
| 42 | lowmem = ebda_addr; | ||
| 43 | |||
| 44 | /* Fixup: bios does not report an EBDA at all. */ | ||
| 45 | /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ | ||
| 46 | if ((ebda_addr == 0) && (lowmem >= 0x9f000)) | ||
| 47 | lowmem = 0x9f000; | ||
| 48 | |||
| 49 | /* Paranoia: should never happen, but... */ | ||
| 50 | if ((lowmem == 0) || (lowmem >= 0x100000)) | ||
| 51 | lowmem = 0x9f000; | ||
| 52 | |||
| 53 | /* reserve all memory between lowmem and the 1MB mark */ | ||
| 54 | reserve_early(lowmem, 0x100000, "BIOS reserved"); | ||
| 55 | } | ||
| 56 | |||
| 57 | void __init reserve_setup_data(void) | ||
| 58 | { | ||
| 59 | struct setup_data *data; | ||
| 60 | u64 pa_data; | ||
| 61 | char buf[32]; | ||
| 62 | |||
| 63 | if (boot_params.hdr.version < 0x0209) | ||
| 64 | return; | ||
| 65 | pa_data = boot_params.hdr.setup_data; | ||
| 66 | while (pa_data) { | ||
| 67 | data = early_ioremap(pa_data, sizeof(*data)); | ||
| 68 | sprintf(buf, "setup data %x", data->type); | ||
| 69 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); | ||
| 70 | pa_data = data->next; | ||
| 71 | early_iounmap(data, sizeof(*data)); | ||
| 72 | } | ||
| 73 | } | ||
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 3db059058927..fa1d25dd83e3 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c | |||
| @@ -8,7 +8,34 @@ | |||
| 8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
| 9 | #include <linux/start_kernel.h> | 9 | #include <linux/start_kernel.h> |
| 10 | 10 | ||
| 11 | #include <asm/setup.h> | ||
| 12 | #include <asm/sections.h> | ||
| 13 | #include <asm/e820.h> | ||
| 14 | #include <asm/bios_ebda.h> | ||
| 15 | |||
| 11 | void __init i386_start_kernel(void) | 16 | void __init i386_start_kernel(void) |
| 12 | { | 17 | { |
| 18 | reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS"); | ||
| 19 | |||
| 20 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 21 | /* Reserve INITRD */ | ||
| 22 | if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { | ||
| 23 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; | ||
| 24 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; | ||
| 25 | u64 ramdisk_end = ramdisk_image + ramdisk_size; | ||
| 26 | reserve_early(ramdisk_image, ramdisk_end, "RAMDISK"); | ||
| 27 | } | ||
| 28 | #endif | ||
| 29 | reserve_early(init_pg_tables_start, init_pg_tables_end, | ||
| 30 | "INIT_PG_TABLE"); | ||
| 31 | |||
| 32 | reserve_ebda_region(); | ||
| 33 | |||
| 34 | /* | ||
| 35 | * At this point everything still needed from the boot loader | ||
| 36 | * or BIOS or kernel text should be early reserved or marked not | ||
| 37 | * RAM in e820. All other memory is free game. | ||
| 38 | */ | ||
| 39 | |||
| 13 | start_kernel(); | 40 | start_kernel(); |
| 14 | } | 41 | } |
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index e25c57b8aa84..5fbed459ff3b 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
| @@ -51,74 +51,6 @@ static void __init copy_bootdata(char *real_mode_data) | |||
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | #define BIOS_LOWMEM_KILOBYTES 0x413 | ||
| 55 | |||
| 56 | /* | ||
| 57 | * The BIOS places the EBDA/XBDA at the top of conventional | ||
| 58 | * memory, and usually decreases the reported amount of | ||
| 59 | * conventional memory (int 0x12) too. This also contains a | ||
| 60 | * workaround for Dell systems that neglect to reserve EBDA. | ||
| 61 | * The same workaround also avoids a problem with the AMD768MPX | ||
| 62 | * chipset: reserve a page before VGA to prevent PCI prefetch | ||
| 63 | * into it (errata #56). Usually the page is reserved anyways, | ||
| 64 | * unless you have no PS/2 mouse plugged in. | ||
| 65 | */ | ||
| 66 | static void __init reserve_ebda_region(void) | ||
| 67 | { | ||
| 68 | unsigned int lowmem, ebda_addr; | ||
| 69 | |||
| 70 | /* To determine the position of the EBDA and the */ | ||
| 71 | /* end of conventional memory, we need to look at */ | ||
| 72 | /* the BIOS data area. In a paravirtual environment */ | ||
| 73 | /* that area is absent. We'll just have to assume */ | ||
| 74 | /* that the paravirt case can handle memory setup */ | ||
| 75 | /* correctly, without our help. */ | ||
| 76 | if (paravirt_enabled()) | ||
| 77 | return; | ||
| 78 | |||
| 79 | /* end of low (conventional) memory */ | ||
| 80 | lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); | ||
| 81 | lowmem <<= 10; | ||
| 82 | |||
| 83 | /* start of EBDA area */ | ||
| 84 | ebda_addr = get_bios_ebda(); | ||
| 85 | |||
| 86 | /* Fixup: bios puts an EBDA in the top 64K segment */ | ||
| 87 | /* of conventional memory, but does not adjust lowmem. */ | ||
| 88 | if ((lowmem - ebda_addr) <= 0x10000) | ||
| 89 | lowmem = ebda_addr; | ||
| 90 | |||
| 91 | /* Fixup: bios does not report an EBDA at all. */ | ||
| 92 | /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ | ||
| 93 | if ((ebda_addr == 0) && (lowmem >= 0x9f000)) | ||
| 94 | lowmem = 0x9f000; | ||
| 95 | |||
| 96 | /* Paranoia: should never happen, but... */ | ||
| 97 | if ((lowmem == 0) || (lowmem >= 0x100000)) | ||
| 98 | lowmem = 0x9f000; | ||
| 99 | |||
| 100 | /* reserve all memory between lowmem and the 1MB mark */ | ||
| 101 | reserve_early(lowmem, 0x100000, "BIOS reserved"); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void __init reserve_setup_data(void) | ||
| 105 | { | ||
| 106 | struct setup_data *data; | ||
| 107 | unsigned long pa_data; | ||
| 108 | char buf[32]; | ||
| 109 | |||
| 110 | if (boot_params.hdr.version < 0x0209) | ||
| 111 | return; | ||
| 112 | pa_data = boot_params.hdr.setup_data; | ||
| 113 | while (pa_data) { | ||
| 114 | data = early_ioremap(pa_data, sizeof(*data)); | ||
| 115 | sprintf(buf, "setup data %x", data->type); | ||
| 116 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); | ||
| 117 | pa_data = data->next; | ||
| 118 | early_iounmap(data, sizeof(*data)); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void __init x86_64_start_kernel(char * real_mode_data) | 54 | void __init x86_64_start_kernel(char * real_mode_data) |
| 123 | { | 55 | { |
| 124 | int i; | 56 | int i; |
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index f7357cc0162c..b98b338aae1a 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
| @@ -194,6 +194,7 @@ default_entry: | |||
| 194 | xorl %ebx,%ebx /* %ebx is kept at zero */ | 194 | xorl %ebx,%ebx /* %ebx is kept at zero */ |
| 195 | 195 | ||
| 196 | movl $pa(pg0), %edi | 196 | movl $pa(pg0), %edi |
| 197 | movl %edi, pa(init_pg_tables_start) | ||
| 197 | movl $pa(swapper_pg_pmd), %edx | 198 | movl $pa(swapper_pg_pmd), %edx |
| 198 | movl $PTE_ATTR, %eax | 199 | movl $PTE_ATTR, %eax |
| 199 | 10: | 200 | 10: |
| @@ -219,6 +220,8 @@ default_entry: | |||
| 219 | jb 10b | 220 | jb 10b |
| 220 | 1: | 221 | 1: |
| 221 | movl %edi,pa(init_pg_tables_end) | 222 | movl %edi,pa(init_pg_tables_end) |
| 223 | shrl $12, %eax | ||
| 224 | movl %eax, pa(max_pfn_mapped) | ||
| 222 | 225 | ||
| 223 | /* Do early initialization of the fixmap area */ | 226 | /* Do early initialization of the fixmap area */ |
| 224 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax | 227 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax |
| @@ -228,6 +231,7 @@ default_entry: | |||
| 228 | page_pde_offset = (__PAGE_OFFSET >> 20); | 231 | page_pde_offset = (__PAGE_OFFSET >> 20); |
| 229 | 232 | ||
| 230 | movl $pa(pg0), %edi | 233 | movl $pa(pg0), %edi |
| 234 | movl %edi, pa(init_pg_tables_start) | ||
| 231 | movl $pa(swapper_pg_dir), %edx | 235 | movl $pa(swapper_pg_dir), %edx |
| 232 | movl $PTE_ATTR, %eax | 236 | movl $PTE_ATTR, %eax |
| 233 | 10: | 237 | 10: |
| @@ -249,6 +253,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20); | |||
| 249 | cmpl %ebp,%eax | 253 | cmpl %ebp,%eax |
| 250 | jb 10b | 254 | jb 10b |
| 251 | movl %edi,pa(init_pg_tables_end) | 255 | movl %edi,pa(init_pg_tables_end) |
| 256 | shrl $12, %eax | ||
| 257 | movl %eax, pa(max_pfn_mapped) | ||
| 252 | 258 | ||
| 253 | /* Do early initialization of the fixmap area */ | 259 | /* Do early initialization of the fixmap area */ |
| 254 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax | 260 | movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax |
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index dac47d61d2be..fedb3b113ace 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
| @@ -72,15 +72,21 @@ int sis_apic_bug = -1; | |||
| 72 | int nr_ioapic_registers[MAX_IO_APICS]; | 72 | int nr_ioapic_registers[MAX_IO_APICS]; |
| 73 | 73 | ||
| 74 | /* I/O APIC entries */ | 74 | /* I/O APIC entries */ |
| 75 | struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; | 75 | struct mp_config_ioapic mp_ioapics[MAX_IO_APICS]; |
| 76 | int nr_ioapics; | 76 | int nr_ioapics; |
| 77 | 77 | ||
| 78 | /* MP IRQ source entries */ | 78 | /* MP IRQ source entries */ |
| 79 | struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; | 79 | struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; |
| 80 | 80 | ||
| 81 | /* # of MP IRQ source entries */ | 81 | /* # of MP IRQ source entries */ |
| 82 | int mp_irq_entries; | 82 | int mp_irq_entries; |
| 83 | 83 | ||
| 84 | #if defined (CONFIG_MCA) || defined (CONFIG_EISA) | ||
| 85 | int mp_bus_id_to_type[MAX_MP_BUSSES]; | ||
| 86 | #endif | ||
| 87 | |||
| 88 | DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | ||
| 89 | |||
| 84 | static int disable_timer_pin_1 __initdata; | 90 | static int disable_timer_pin_1 __initdata; |
| 85 | 91 | ||
| 86 | /* | 92 | /* |
| @@ -110,7 +116,7 @@ struct io_apic { | |||
| 110 | static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) | 116 | static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) |
| 111 | { | 117 | { |
| 112 | return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) | 118 | return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) |
| 113 | + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); | 119 | + (mp_ioapics[idx].mp_apicaddr & ~PAGE_MASK); |
| 114 | } | 120 | } |
| 115 | 121 | ||
| 116 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) | 122 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) |
| @@ -802,10 +808,10 @@ static int find_irq_entry(int apic, int pin, int type) | |||
| 802 | int i; | 808 | int i; |
| 803 | 809 | ||
| 804 | for (i = 0; i < mp_irq_entries; i++) | 810 | for (i = 0; i < mp_irq_entries; i++) |
| 805 | if (mp_irqs[i].mpc_irqtype == type && | 811 | if (mp_irqs[i].mp_irqtype == type && |
| 806 | (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || | 812 | (mp_irqs[i].mp_dstapic == mp_ioapics[apic].mp_apicid || |
| 807 | mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && | 813 | mp_irqs[i].mp_dstapic == MP_APIC_ALL) && |
| 808 | mp_irqs[i].mpc_dstirq == pin) | 814 | mp_irqs[i].mp_dstirq == pin) |
| 809 | return i; | 815 | return i; |
| 810 | 816 | ||
| 811 | return -1; | 817 | return -1; |
| @@ -819,13 +825,13 @@ static int __init find_isa_irq_pin(int irq, int type) | |||
| 819 | int i; | 825 | int i; |
| 820 | 826 | ||
| 821 | for (i = 0; i < mp_irq_entries; i++) { | 827 | for (i = 0; i < mp_irq_entries; i++) { |
| 822 | int lbus = mp_irqs[i].mpc_srcbus; | 828 | int lbus = mp_irqs[i].mp_srcbus; |
| 823 | 829 | ||
| 824 | if (test_bit(lbus, mp_bus_not_pci) && | 830 | if (test_bit(lbus, mp_bus_not_pci) && |
| 825 | (mp_irqs[i].mpc_irqtype == type) && | 831 | (mp_irqs[i].mp_irqtype == type) && |
| 826 | (mp_irqs[i].mpc_srcbusirq == irq)) | 832 | (mp_irqs[i].mp_srcbusirq == irq)) |
| 827 | 833 | ||
| 828 | return mp_irqs[i].mpc_dstirq; | 834 | return mp_irqs[i].mp_dstirq; |
| 829 | } | 835 | } |
| 830 | return -1; | 836 | return -1; |
| 831 | } | 837 | } |
| @@ -835,17 +841,17 @@ static int __init find_isa_irq_apic(int irq, int type) | |||
| 835 | int i; | 841 | int i; |
| 836 | 842 | ||
| 837 | for (i = 0; i < mp_irq_entries; i++) { | 843 | for (i = 0; i < mp_irq_entries; i++) { |
| 838 | int lbus = mp_irqs[i].mpc_srcbus; | 844 | int lbus = mp_irqs[i].mp_srcbus; |
| 839 | 845 | ||
| 840 | if (test_bit(lbus, mp_bus_not_pci) && | 846 | if (test_bit(lbus, mp_bus_not_pci) && |
| 841 | (mp_irqs[i].mpc_irqtype == type) && | 847 | (mp_irqs[i].mp_irqtype == type) && |
| 842 | (mp_irqs[i].mpc_srcbusirq == irq)) | 848 | (mp_irqs[i].mp_srcbusirq == irq)) |
| 843 | break; | 849 | break; |
| 844 | } | 850 | } |
| 845 | if (i < mp_irq_entries) { | 851 | if (i < mp_irq_entries) { |
| 846 | int apic; | 852 | int apic; |
| 847 | for (apic = 0; apic < nr_ioapics; apic++) { | 853 | for (apic = 0; apic < nr_ioapics; apic++) { |
| 848 | if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) | 854 | if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic) |
| 849 | return apic; | 855 | return apic; |
| 850 | } | 856 | } |
| 851 | } | 857 | } |
| @@ -865,28 +871,28 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) | |||
| 865 | 871 | ||
| 866 | apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " | 872 | apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " |
| 867 | "slot:%d, pin:%d.\n", bus, slot, pin); | 873 | "slot:%d, pin:%d.\n", bus, slot, pin); |
| 868 | if (mp_bus_id_to_pci_bus[bus] == -1) { | 874 | if (test_bit(bus, mp_bus_not_pci)) { |
| 869 | printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); | 875 | printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); |
| 870 | return -1; | 876 | return -1; |
| 871 | } | 877 | } |
| 872 | for (i = 0; i < mp_irq_entries; i++) { | 878 | for (i = 0; i < mp_irq_entries; i++) { |
| 873 | int lbus = mp_irqs[i].mpc_srcbus; | 879 | int lbus = mp_irqs[i].mp_srcbus; |
| 874 | 880 | ||
| 875 | for (apic = 0; apic < nr_ioapics; apic++) | 881 | for (apic = 0; apic < nr_ioapics; apic++) |
| 876 | if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || | 882 | if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic || |
| 877 | mp_irqs[i].mpc_dstapic == MP_APIC_ALL) | 883 | mp_irqs[i].mp_dstapic == MP_APIC_ALL) |
| 878 | break; | 884 | break; |
| 879 | 885 | ||
| 880 | if (!test_bit(lbus, mp_bus_not_pci) && | 886 | if (!test_bit(lbus, mp_bus_not_pci) && |
| 881 | !mp_irqs[i].mpc_irqtype && | 887 | !mp_irqs[i].mp_irqtype && |
| 882 | (bus == lbus) && | 888 | (bus == lbus) && |
| 883 | (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { | 889 | (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) { |
| 884 | int irq = pin_2_irq(i, apic, mp_irqs[i].mpc_dstirq); | 890 | int irq = pin_2_irq(i, apic, mp_irqs[i].mp_dstirq); |
| 885 | 891 | ||
| 886 | if (!(apic || IO_APIC_IRQ(irq))) | 892 | if (!(apic || IO_APIC_IRQ(irq))) |
| 887 | continue; | 893 | continue; |
| 888 | 894 | ||
| 889 | if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) | 895 | if (pin == (mp_irqs[i].mp_srcbusirq & 3)) |
| 890 | return irq; | 896 | return irq; |
| 891 | /* | 897 | /* |
| 892 | * Use the first all-but-pin matching entry as a | 898 | * Use the first all-but-pin matching entry as a |
| @@ -953,7 +959,7 @@ static int EISA_ELCR(unsigned int irq) | |||
| 953 | * EISA conforming in the MP table, that means its trigger type must | 959 | * EISA conforming in the MP table, that means its trigger type must |
| 954 | * be read in from the ELCR */ | 960 | * be read in from the ELCR */ |
| 955 | 961 | ||
| 956 | #define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq)) | 962 | #define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mp_srcbusirq)) |
| 957 | #define default_EISA_polarity(idx) default_ISA_polarity(idx) | 963 | #define default_EISA_polarity(idx) default_ISA_polarity(idx) |
| 958 | 964 | ||
| 959 | /* PCI interrupts are always polarity one level triggered, | 965 | /* PCI interrupts are always polarity one level triggered, |
| @@ -970,13 +976,13 @@ static int EISA_ELCR(unsigned int irq) | |||
| 970 | 976 | ||
| 971 | static int MPBIOS_polarity(int idx) | 977 | static int MPBIOS_polarity(int idx) |
| 972 | { | 978 | { |
| 973 | int bus = mp_irqs[idx].mpc_srcbus; | 979 | int bus = mp_irqs[idx].mp_srcbus; |
| 974 | int polarity; | 980 | int polarity; |
| 975 | 981 | ||
| 976 | /* | 982 | /* |
| 977 | * Determine IRQ line polarity (high active or low active): | 983 | * Determine IRQ line polarity (high active or low active): |
| 978 | */ | 984 | */ |
| 979 | switch (mp_irqs[idx].mpc_irqflag & 3) { | 985 | switch (mp_irqs[idx].mp_irqflag & 3) { |
| 980 | case 0: /* conforms, ie. bus-type dependent polarity */ | 986 | case 0: /* conforms, ie. bus-type dependent polarity */ |
| 981 | { | 987 | { |
| 982 | polarity = test_bit(bus, mp_bus_not_pci)? | 988 | polarity = test_bit(bus, mp_bus_not_pci)? |
| @@ -1012,13 +1018,13 @@ static int MPBIOS_polarity(int idx) | |||
| 1012 | 1018 | ||
| 1013 | static int MPBIOS_trigger(int idx) | 1019 | static int MPBIOS_trigger(int idx) |
| 1014 | { | 1020 | { |
| 1015 | int bus = mp_irqs[idx].mpc_srcbus; | 1021 | int bus = mp_irqs[idx].mp_srcbus; |
| 1016 | int trigger; | 1022 | int trigger; |
| 1017 | 1023 | ||
| 1018 | /* | 1024 | /* |
| 1019 | * Determine IRQ trigger mode (edge or level sensitive): | 1025 | * Determine IRQ trigger mode (edge or level sensitive): |
| 1020 | */ | 1026 | */ |
| 1021 | switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) { | 1027 | switch ((mp_irqs[idx].mp_irqflag>>2) & 3) { |
| 1022 | case 0: /* conforms, ie. bus-type dependent */ | 1028 | case 0: /* conforms, ie. bus-type dependent */ |
| 1023 | { | 1029 | { |
| 1024 | trigger = test_bit(bus, mp_bus_not_pci)? | 1030 | trigger = test_bit(bus, mp_bus_not_pci)? |
| @@ -1095,16 +1101,16 @@ static inline int irq_trigger(int idx) | |||
| 1095 | static int pin_2_irq(int idx, int apic, int pin) | 1101 | static int pin_2_irq(int idx, int apic, int pin) |
| 1096 | { | 1102 | { |
| 1097 | int irq, i; | 1103 | int irq, i; |
| 1098 | int bus = mp_irqs[idx].mpc_srcbus; | 1104 | int bus = mp_irqs[idx].mp_srcbus; |
| 1099 | 1105 | ||
| 1100 | /* | 1106 | /* |
| 1101 | * Debugging check, we are in big trouble if this message pops up! | 1107 | * Debugging check, we are in big trouble if this message pops up! |
| 1102 | */ | 1108 | */ |
| 1103 | if (mp_irqs[idx].mpc_dstirq != pin) | 1109 | if (mp_irqs[idx].mp_dstirq != pin) |
| 1104 | printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); | 1110 | printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); |
| 1105 | 1111 | ||
| 1106 | if (test_bit(bus, mp_bus_not_pci)) | 1112 | if (test_bit(bus, mp_bus_not_pci)) |
| 1107 | irq = mp_irqs[idx].mpc_srcbusirq; | 1113 | irq = mp_irqs[idx].mp_srcbusirq; |
| 1108 | else { | 1114 | else { |
| 1109 | /* | 1115 | /* |
| 1110 | * PCI IRQs are mapped in order | 1116 | * PCI IRQs are mapped in order |
| @@ -1248,12 +1254,12 @@ static void __init setup_IO_APIC_irqs(void) | |||
| 1248 | if (first_notcon) { | 1254 | if (first_notcon) { |
| 1249 | apic_printk(APIC_VERBOSE, KERN_DEBUG | 1255 | apic_printk(APIC_VERBOSE, KERN_DEBUG |
| 1250 | " IO-APIC (apicid-pin) %d-%d", | 1256 | " IO-APIC (apicid-pin) %d-%d", |
| 1251 | mp_ioapics[apic].mpc_apicid, | 1257 | mp_ioapics[apic].mp_apicid, |
| 1252 | pin); | 1258 | pin); |
| 1253 | first_notcon = 0; | 1259 | first_notcon = 0; |
| 1254 | } else | 1260 | } else |
| 1255 | apic_printk(APIC_VERBOSE, ", %d-%d", | 1261 | apic_printk(APIC_VERBOSE, ", %d-%d", |
| 1256 | mp_ioapics[apic].mpc_apicid, pin); | 1262 | mp_ioapics[apic].mp_apicid, pin); |
| 1257 | continue; | 1263 | continue; |
| 1258 | } | 1264 | } |
| 1259 | 1265 | ||
| @@ -1348,7 +1354,7 @@ void __init print_IO_APIC(void) | |||
| 1348 | printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); | 1354 | printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); |
| 1349 | for (i = 0; i < nr_ioapics; i++) | 1355 | for (i = 0; i < nr_ioapics; i++) |
| 1350 | printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", | 1356 | printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", |
| 1351 | mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); | 1357 | mp_ioapics[i].mp_apicid, nr_ioapic_registers[i]); |
| 1352 | 1358 | ||
| 1353 | /* | 1359 | /* |
| 1354 | * We are a bit conservative about what we expect. We have to | 1360 | * We are a bit conservative about what we expect. We have to |
| @@ -1367,7 +1373,7 @@ void __init print_IO_APIC(void) | |||
| 1367 | reg_03.raw = io_apic_read(apic, 3); | 1373 | reg_03.raw = io_apic_read(apic, 3); |
| 1368 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1374 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| 1369 | 1375 | ||
| 1370 | printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); | 1376 | printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid); |
| 1371 | printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); | 1377 | printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); |
| 1372 | printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); | 1378 | printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); |
| 1373 | printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); | 1379 | printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); |
| @@ -1708,7 +1714,6 @@ void disable_IO_APIC(void) | |||
| 1708 | * by Matt Domsch <Matt_Domsch@dell.com> Tue Dec 21 12:25:05 CST 1999 | 1714 | * by Matt Domsch <Matt_Domsch@dell.com> Tue Dec 21 12:25:05 CST 1999 |
| 1709 | */ | 1715 | */ |
| 1710 | 1716 | ||
| 1711 | #ifndef CONFIG_X86_NUMAQ | ||
| 1712 | static void __init setup_ioapic_ids_from_mpc(void) | 1717 | static void __init setup_ioapic_ids_from_mpc(void) |
| 1713 | { | 1718 | { |
| 1714 | union IO_APIC_reg_00 reg_00; | 1719 | union IO_APIC_reg_00 reg_00; |
| @@ -1718,6 +1723,11 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1718 | unsigned char old_id; | 1723 | unsigned char old_id; |
| 1719 | unsigned long flags; | 1724 | unsigned long flags; |
| 1720 | 1725 | ||
| 1726 | #ifdef CONFIG_X86_NUMAQ | ||
| 1727 | if (found_numaq) | ||
| 1728 | return; | ||
| 1729 | #endif | ||
| 1730 | |||
| 1721 | /* | 1731 | /* |
| 1722 | * Don't check I/O APIC IDs for xAPIC systems. They have | 1732 | * Don't check I/O APIC IDs for xAPIC systems. They have |
| 1723 | * no meaning without the serial APIC bus. | 1733 | * no meaning without the serial APIC bus. |
| @@ -1741,14 +1751,14 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1741 | reg_00.raw = io_apic_read(apic, 0); | 1751 | reg_00.raw = io_apic_read(apic, 0); |
| 1742 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1752 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| 1743 | 1753 | ||
| 1744 | old_id = mp_ioapics[apic].mpc_apicid; | 1754 | old_id = mp_ioapics[apic].mp_apicid; |
| 1745 | 1755 | ||
| 1746 | if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) { | 1756 | if (mp_ioapics[apic].mp_apicid >= get_physical_broadcast()) { |
| 1747 | printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", | 1757 | printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", |
| 1748 | apic, mp_ioapics[apic].mpc_apicid); | 1758 | apic, mp_ioapics[apic].mp_apicid); |
| 1749 | printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", | 1759 | printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", |
| 1750 | reg_00.bits.ID); | 1760 | reg_00.bits.ID); |
| 1751 | mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; | 1761 | mp_ioapics[apic].mp_apicid = reg_00.bits.ID; |
| 1752 | } | 1762 | } |
| 1753 | 1763 | ||
| 1754 | /* | 1764 | /* |
| @@ -1757,9 +1767,9 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1757 | * 'stuck on smp_invalidate_needed IPI wait' messages. | 1767 | * 'stuck on smp_invalidate_needed IPI wait' messages. |
| 1758 | */ | 1768 | */ |
| 1759 | if (check_apicid_used(phys_id_present_map, | 1769 | if (check_apicid_used(phys_id_present_map, |
| 1760 | mp_ioapics[apic].mpc_apicid)) { | 1770 | mp_ioapics[apic].mp_apicid)) { |
| 1761 | printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", | 1771 | printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", |
| 1762 | apic, mp_ioapics[apic].mpc_apicid); | 1772 | apic, mp_ioapics[apic].mp_apicid); |
| 1763 | for (i = 0; i < get_physical_broadcast(); i++) | 1773 | for (i = 0; i < get_physical_broadcast(); i++) |
| 1764 | if (!physid_isset(i, phys_id_present_map)) | 1774 | if (!physid_isset(i, phys_id_present_map)) |
| 1765 | break; | 1775 | break; |
| @@ -1768,13 +1778,13 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1768 | printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", | 1778 | printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", |
| 1769 | i); | 1779 | i); |
| 1770 | physid_set(i, phys_id_present_map); | 1780 | physid_set(i, phys_id_present_map); |
| 1771 | mp_ioapics[apic].mpc_apicid = i; | 1781 | mp_ioapics[apic].mp_apicid = i; |
| 1772 | } else { | 1782 | } else { |
| 1773 | physid_mask_t tmp; | 1783 | physid_mask_t tmp; |
| 1774 | tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); | 1784 | tmp = apicid_to_cpu_present(mp_ioapics[apic].mp_apicid); |
| 1775 | apic_printk(APIC_VERBOSE, "Setting %d in the " | 1785 | apic_printk(APIC_VERBOSE, "Setting %d in the " |
| 1776 | "phys_id_present_map\n", | 1786 | "phys_id_present_map\n", |
| 1777 | mp_ioapics[apic].mpc_apicid); | 1787 | mp_ioapics[apic].mp_apicid); |
| 1778 | physids_or(phys_id_present_map, phys_id_present_map, tmp); | 1788 | physids_or(phys_id_present_map, phys_id_present_map, tmp); |
| 1779 | } | 1789 | } |
| 1780 | 1790 | ||
| @@ -1783,11 +1793,11 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1783 | * We need to adjust the IRQ routing table | 1793 | * We need to adjust the IRQ routing table |
| 1784 | * if the ID changed. | 1794 | * if the ID changed. |
| 1785 | */ | 1795 | */ |
| 1786 | if (old_id != mp_ioapics[apic].mpc_apicid) | 1796 | if (old_id != mp_ioapics[apic].mp_apicid) |
| 1787 | for (i = 0; i < mp_irq_entries; i++) | 1797 | for (i = 0; i < mp_irq_entries; i++) |
| 1788 | if (mp_irqs[i].mpc_dstapic == old_id) | 1798 | if (mp_irqs[i].mp_dstapic == old_id) |
| 1789 | mp_irqs[i].mpc_dstapic | 1799 | mp_irqs[i].mp_dstapic |
| 1790 | = mp_ioapics[apic].mpc_apicid; | 1800 | = mp_ioapics[apic].mp_apicid; |
| 1791 | 1801 | ||
| 1792 | /* | 1802 | /* |
| 1793 | * Read the right value from the MPC table and | 1803 | * Read the right value from the MPC table and |
| @@ -1795,9 +1805,9 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1795 | */ | 1805 | */ |
| 1796 | apic_printk(APIC_VERBOSE, KERN_INFO | 1806 | apic_printk(APIC_VERBOSE, KERN_INFO |
| 1797 | "...changing IO-APIC physical APIC ID to %d ...", | 1807 | "...changing IO-APIC physical APIC ID to %d ...", |
| 1798 | mp_ioapics[apic].mpc_apicid); | 1808 | mp_ioapics[apic].mp_apicid); |
| 1799 | 1809 | ||
| 1800 | reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; | 1810 | reg_00.bits.ID = mp_ioapics[apic].mp_apicid; |
| 1801 | spin_lock_irqsave(&ioapic_lock, flags); | 1811 | spin_lock_irqsave(&ioapic_lock, flags); |
| 1802 | io_apic_write(apic, 0, reg_00.raw); | 1812 | io_apic_write(apic, 0, reg_00.raw); |
| 1803 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1813 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| @@ -1808,15 +1818,12 @@ static void __init setup_ioapic_ids_from_mpc(void) | |||
| 1808 | spin_lock_irqsave(&ioapic_lock, flags); | 1818 | spin_lock_irqsave(&ioapic_lock, flags); |
| 1809 | reg_00.raw = io_apic_read(apic, 0); | 1819 | reg_00.raw = io_apic_read(apic, 0); |
| 1810 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1820 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| 1811 | if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) | 1821 | if (reg_00.bits.ID != mp_ioapics[apic].mp_apicid) |
| 1812 | printk("could not set ID!\n"); | 1822 | printk("could not set ID!\n"); |
| 1813 | else | 1823 | else |
| 1814 | apic_printk(APIC_VERBOSE, " ok.\n"); | 1824 | apic_printk(APIC_VERBOSE, " ok.\n"); |
| 1815 | } | 1825 | } |
| 1816 | } | 1826 | } |
| 1817 | #else | ||
| 1818 | static void __init setup_ioapic_ids_from_mpc(void) { } | ||
| 1819 | #endif | ||
| 1820 | 1827 | ||
| 1821 | int no_timer_check __initdata; | 1828 | int no_timer_check __initdata; |
| 1822 | 1829 | ||
| @@ -2352,8 +2359,8 @@ static int ioapic_resume(struct sys_device *dev) | |||
| 2352 | 2359 | ||
| 2353 | spin_lock_irqsave(&ioapic_lock, flags); | 2360 | spin_lock_irqsave(&ioapic_lock, flags); |
| 2354 | reg_00.raw = io_apic_read(dev->id, 0); | 2361 | reg_00.raw = io_apic_read(dev->id, 0); |
| 2355 | if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { | 2362 | if (reg_00.bits.ID != mp_ioapics[dev->id].mp_apicid) { |
| 2356 | reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; | 2363 | reg_00.bits.ID = mp_ioapics[dev->id].mp_apicid; |
| 2357 | io_apic_write(dev->id, 0, reg_00.raw); | 2364 | io_apic_write(dev->id, 0, reg_00.raw); |
| 2358 | } | 2365 | } |
| 2359 | spin_unlock_irqrestore(&ioapic_lock, flags); | 2366 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| @@ -2785,7 +2792,7 @@ int io_apic_set_pci_routing(int ioapic, int pin, int irq, int edge_level, int ac | |||
| 2785 | 2792 | ||
| 2786 | apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " | 2793 | apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " |
| 2787 | "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, | 2794 | "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, |
| 2788 | mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, | 2795 | mp_ioapics[ioapic].mp_apicid, pin, entry.vector, irq, |
| 2789 | edge_level, active_high_low); | 2796 | edge_level, active_high_low); |
| 2790 | 2797 | ||
| 2791 | ioapic_register_intr(irq, entry.vector, edge_level); | 2798 | ioapic_register_intr(irq, entry.vector, edge_level); |
| @@ -2806,8 +2813,8 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) | |||
| 2806 | return -1; | 2813 | return -1; |
| 2807 | 2814 | ||
| 2808 | for (i = 0; i < mp_irq_entries; i++) | 2815 | for (i = 0; i < mp_irq_entries; i++) |
| 2809 | if (mp_irqs[i].mpc_irqtype == mp_INT && | 2816 | if (mp_irqs[i].mp_irqtype == mp_INT && |
| 2810 | mp_irqs[i].mpc_srcbusirq == bus_irq) | 2817 | mp_irqs[i].mp_srcbusirq == bus_irq) |
| 2811 | break; | 2818 | break; |
| 2812 | if (i >= mp_irq_entries) | 2819 | if (i >= mp_irq_entries) |
| 2813 | return -1; | 2820 | return -1; |
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index 78a3866ab367..2eba4f4c14ba 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c | |||
| @@ -108,15 +108,17 @@ DEFINE_SPINLOCK(vector_lock); | |||
| 108 | int nr_ioapic_registers[MAX_IO_APICS]; | 108 | int nr_ioapic_registers[MAX_IO_APICS]; |
| 109 | 109 | ||
| 110 | /* I/O APIC entries */ | 110 | /* I/O APIC entries */ |
| 111 | struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; | 111 | struct mp_config_ioapic mp_ioapics[MAX_IO_APICS]; |
| 112 | int nr_ioapics; | 112 | int nr_ioapics; |
| 113 | 113 | ||
| 114 | /* MP IRQ source entries */ | 114 | /* MP IRQ source entries */ |
| 115 | struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; | 115 | struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; |
| 116 | 116 | ||
| 117 | /* # of MP IRQ source entries */ | 117 | /* # of MP IRQ source entries */ |
| 118 | int mp_irq_entries; | 118 | int mp_irq_entries; |
| 119 | 119 | ||
| 120 | DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | ||
| 121 | |||
| 120 | /* | 122 | /* |
| 121 | * Rough estimation of how many shared IRQs there are, can | 123 | * Rough estimation of how many shared IRQs there are, can |
| 122 | * be changed anytime. | 124 | * be changed anytime. |
| @@ -144,7 +146,7 @@ struct io_apic { | |||
| 144 | static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) | 146 | static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) |
| 145 | { | 147 | { |
| 146 | return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) | 148 | return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) |
| 147 | + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); | 149 | + (mp_ioapics[idx].mp_apicaddr & ~PAGE_MASK); |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) | 152 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) |
| @@ -464,10 +466,10 @@ static int find_irq_entry(int apic, int pin, int type) | |||
| 464 | int i; | 466 | int i; |
| 465 | 467 | ||
| 466 | for (i = 0; i < mp_irq_entries; i++) | 468 | for (i = 0; i < mp_irq_entries; i++) |
| 467 | if (mp_irqs[i].mpc_irqtype == type && | 469 | if (mp_irqs[i].mp_irqtype == type && |
| 468 | (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || | 470 | (mp_irqs[i].mp_dstapic == mp_ioapics[apic].mp_apicid || |
| 469 | mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && | 471 | mp_irqs[i].mp_dstapic == MP_APIC_ALL) && |
| 470 | mp_irqs[i].mpc_dstirq == pin) | 472 | mp_irqs[i].mp_dstirq == pin) |
| 471 | return i; | 473 | return i; |
| 472 | 474 | ||
| 473 | return -1; | 475 | return -1; |
| @@ -481,13 +483,13 @@ static int __init find_isa_irq_pin(int irq, int type) | |||
| 481 | int i; | 483 | int i; |
| 482 | 484 | ||
| 483 | for (i = 0; i < mp_irq_entries; i++) { | 485 | for (i = 0; i < mp_irq_entries; i++) { |
| 484 | int lbus = mp_irqs[i].mpc_srcbus; | 486 | int lbus = mp_irqs[i].mp_srcbus; |
| 485 | 487 | ||
| 486 | if (test_bit(lbus, mp_bus_not_pci) && | 488 | if (test_bit(lbus, mp_bus_not_pci) && |
| 487 | (mp_irqs[i].mpc_irqtype == type) && | 489 | (mp_irqs[i].mp_irqtype == type) && |
| 488 | (mp_irqs[i].mpc_srcbusirq == irq)) | 490 | (mp_irqs[i].mp_srcbusirq == irq)) |
| 489 | 491 | ||
| 490 | return mp_irqs[i].mpc_dstirq; | 492 | return mp_irqs[i].mp_dstirq; |
| 491 | } | 493 | } |
| 492 | return -1; | 494 | return -1; |
| 493 | } | 495 | } |
| @@ -497,17 +499,17 @@ static int __init find_isa_irq_apic(int irq, int type) | |||
| 497 | int i; | 499 | int i; |
| 498 | 500 | ||
| 499 | for (i = 0; i < mp_irq_entries; i++) { | 501 | for (i = 0; i < mp_irq_entries; i++) { |
| 500 | int lbus = mp_irqs[i].mpc_srcbus; | 502 | int lbus = mp_irqs[i].mp_srcbus; |
| 501 | 503 | ||
| 502 | if (test_bit(lbus, mp_bus_not_pci) && | 504 | if (test_bit(lbus, mp_bus_not_pci) && |
| 503 | (mp_irqs[i].mpc_irqtype == type) && | 505 | (mp_irqs[i].mp_irqtype == type) && |
| 504 | (mp_irqs[i].mpc_srcbusirq == irq)) | 506 | (mp_irqs[i].mp_srcbusirq == irq)) |
| 505 | break; | 507 | break; |
| 506 | } | 508 | } |
| 507 | if (i < mp_irq_entries) { | 509 | if (i < mp_irq_entries) { |
| 508 | int apic; | 510 | int apic; |
| 509 | for(apic = 0; apic < nr_ioapics; apic++) { | 511 | for(apic = 0; apic < nr_ioapics; apic++) { |
| 510 | if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) | 512 | if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic) |
| 511 | return apic; | 513 | return apic; |
| 512 | } | 514 | } |
| 513 | } | 515 | } |
| @@ -527,28 +529,28 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) | |||
| 527 | 529 | ||
| 528 | apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", | 530 | apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", |
| 529 | bus, slot, pin); | 531 | bus, slot, pin); |
| 530 | if (mp_bus_id_to_pci_bus[bus] == -1) { | 532 | if (test_bit(bus, mp_bus_not_pci)) { |
| 531 | apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); | 533 | apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); |
| 532 | return -1; | 534 | return -1; |
| 533 | } | 535 | } |
| 534 | for (i = 0; i < mp_irq_entries; i++) { | 536 | for (i = 0; i < mp_irq_entries; i++) { |
| 535 | int lbus = mp_irqs[i].mpc_srcbus; | 537 | int lbus = mp_irqs[i].mp_srcbus; |
| 536 | 538 | ||
| 537 | for (apic = 0; apic < nr_ioapics; apic++) | 539 | for (apic = 0; apic < nr_ioapics; apic++) |
| 538 | if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || | 540 | if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic || |
| 539 | mp_irqs[i].mpc_dstapic == MP_APIC_ALL) | 541 | mp_irqs[i].mp_dstapic == MP_APIC_ALL) |
| 540 | break; | 542 | break; |
| 541 | 543 | ||
| 542 | if (!test_bit(lbus, mp_bus_not_pci) && | 544 | if (!test_bit(lbus, mp_bus_not_pci) && |
| 543 | !mp_irqs[i].mpc_irqtype && | 545 | !mp_irqs[i].mp_irqtype && |
| 544 | (bus == lbus) && | 546 | (bus == lbus) && |
| 545 | (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { | 547 | (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) { |
| 546 | int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); | 548 | int irq = pin_2_irq(i,apic,mp_irqs[i].mp_dstirq); |
| 547 | 549 | ||
| 548 | if (!(apic || IO_APIC_IRQ(irq))) | 550 | if (!(apic || IO_APIC_IRQ(irq))) |
| 549 | continue; | 551 | continue; |
| 550 | 552 | ||
| 551 | if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) | 553 | if (pin == (mp_irqs[i].mp_srcbusirq & 3)) |
| 552 | return irq; | 554 | return irq; |
| 553 | /* | 555 | /* |
| 554 | * Use the first all-but-pin matching entry as a | 556 | * Use the first all-but-pin matching entry as a |
| @@ -576,13 +578,13 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) | |||
| 576 | 578 | ||
| 577 | static int MPBIOS_polarity(int idx) | 579 | static int MPBIOS_polarity(int idx) |
| 578 | { | 580 | { |
| 579 | int bus = mp_irqs[idx].mpc_srcbus; | 581 | int bus = mp_irqs[idx].mp_srcbus; |
| 580 | int polarity; | 582 | int polarity; |
| 581 | 583 | ||
| 582 | /* | 584 | /* |
| 583 | * Determine IRQ line polarity (high active or low active): | 585 | * Determine IRQ line polarity (high active or low active): |
| 584 | */ | 586 | */ |
| 585 | switch (mp_irqs[idx].mpc_irqflag & 3) | 587 | switch (mp_irqs[idx].mp_irqflag & 3) |
| 586 | { | 588 | { |
| 587 | case 0: /* conforms, ie. bus-type dependent polarity */ | 589 | case 0: /* conforms, ie. bus-type dependent polarity */ |
| 588 | if (test_bit(bus, mp_bus_not_pci)) | 590 | if (test_bit(bus, mp_bus_not_pci)) |
| @@ -618,13 +620,13 @@ static int MPBIOS_polarity(int idx) | |||
| 618 | 620 | ||
| 619 | static int MPBIOS_trigger(int idx) | 621 | static int MPBIOS_trigger(int idx) |
| 620 | { | 622 | { |
| 621 | int bus = mp_irqs[idx].mpc_srcbus; | 623 | int bus = mp_irqs[idx].mp_srcbus; |
| 622 | int trigger; | 624 | int trigger; |
| 623 | 625 | ||
| 624 | /* | 626 | /* |
| 625 | * Determine IRQ trigger mode (edge or level sensitive): | 627 | * Determine IRQ trigger mode (edge or level sensitive): |
| 626 | */ | 628 | */ |
| 627 | switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) | 629 | switch ((mp_irqs[idx].mp_irqflag>>2) & 3) |
| 628 | { | 630 | { |
| 629 | case 0: /* conforms, ie. bus-type dependent */ | 631 | case 0: /* conforms, ie. bus-type dependent */ |
| 630 | if (test_bit(bus, mp_bus_not_pci)) | 632 | if (test_bit(bus, mp_bus_not_pci)) |
| @@ -671,16 +673,16 @@ static inline int irq_trigger(int idx) | |||
| 671 | static int pin_2_irq(int idx, int apic, int pin) | 673 | static int pin_2_irq(int idx, int apic, int pin) |
| 672 | { | 674 | { |
| 673 | int irq, i; | 675 | int irq, i; |
| 674 | int bus = mp_irqs[idx].mpc_srcbus; | 676 | int bus = mp_irqs[idx].mp_srcbus; |
| 675 | 677 | ||
| 676 | /* | 678 | /* |
| 677 | * Debugging check, we are in big trouble if this message pops up! | 679 | * Debugging check, we are in big trouble if this message pops up! |
| 678 | */ | 680 | */ |
| 679 | if (mp_irqs[idx].mpc_dstirq != pin) | 681 | if (mp_irqs[idx].mp_dstirq != pin) |
| 680 | printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); | 682 | printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); |
| 681 | 683 | ||
| 682 | if (test_bit(bus, mp_bus_not_pci)) { | 684 | if (test_bit(bus, mp_bus_not_pci)) { |
| 683 | irq = mp_irqs[idx].mpc_srcbusirq; | 685 | irq = mp_irqs[idx].mp_srcbusirq; |
| 684 | } else { | 686 | } else { |
| 685 | /* | 687 | /* |
| 686 | * PCI IRQs are mapped in order | 688 | * PCI IRQs are mapped in order |
| @@ -857,7 +859,7 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, | |||
| 857 | apic_printk(APIC_VERBOSE,KERN_DEBUG | 859 | apic_printk(APIC_VERBOSE,KERN_DEBUG |
| 858 | "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> " | 860 | "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> " |
| 859 | "IRQ %d Mode:%i Active:%i)\n", | 861 | "IRQ %d Mode:%i Active:%i)\n", |
| 860 | apic, mp_ioapics[apic].mpc_apicid, pin, cfg->vector, | 862 | apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector, |
| 861 | irq, trigger, polarity); | 863 | irq, trigger, polarity); |
| 862 | 864 | ||
| 863 | /* | 865 | /* |
| @@ -898,10 +900,10 @@ static void __init setup_IO_APIC_irqs(void) | |||
| 898 | idx = find_irq_entry(apic,pin,mp_INT); | 900 | idx = find_irq_entry(apic,pin,mp_INT); |
| 899 | if (idx == -1) { | 901 | if (idx == -1) { |
| 900 | if (first_notcon) { | 902 | if (first_notcon) { |
| 901 | apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); | 903 | apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mp_apicid, pin); |
| 902 | first_notcon = 0; | 904 | first_notcon = 0; |
| 903 | } else | 905 | } else |
| 904 | apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin); | 906 | apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mp_apicid, pin); |
| 905 | continue; | 907 | continue; |
| 906 | } | 908 | } |
| 907 | if (!first_notcon) { | 909 | if (!first_notcon) { |
| @@ -969,7 +971,7 @@ void __apicdebuginit print_IO_APIC(void) | |||
| 969 | printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); | 971 | printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); |
| 970 | for (i = 0; i < nr_ioapics; i++) | 972 | for (i = 0; i < nr_ioapics; i++) |
| 971 | printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", | 973 | printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", |
| 972 | mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); | 974 | mp_ioapics[i].mp_apicid, nr_ioapic_registers[i]); |
| 973 | 975 | ||
| 974 | /* | 976 | /* |
| 975 | * We are a bit conservative about what we expect. We have to | 977 | * We are a bit conservative about what we expect. We have to |
| @@ -987,7 +989,7 @@ void __apicdebuginit print_IO_APIC(void) | |||
| 987 | spin_unlock_irqrestore(&ioapic_lock, flags); | 989 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| 988 | 990 | ||
| 989 | printk("\n"); | 991 | printk("\n"); |
| 990 | printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); | 992 | printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid); |
| 991 | printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); | 993 | printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); |
| 992 | printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); | 994 | printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); |
| 993 | 995 | ||
| @@ -1873,8 +1875,8 @@ static int ioapic_resume(struct sys_device *dev) | |||
| 1873 | 1875 | ||
| 1874 | spin_lock_irqsave(&ioapic_lock, flags); | 1876 | spin_lock_irqsave(&ioapic_lock, flags); |
| 1875 | reg_00.raw = io_apic_read(dev->id, 0); | 1877 | reg_00.raw = io_apic_read(dev->id, 0); |
| 1876 | if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { | 1878 | if (reg_00.bits.ID != mp_ioapics[dev->id].mp_apicid) { |
| 1877 | reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; | 1879 | reg_00.bits.ID = mp_ioapics[dev->id].mp_apicid; |
| 1878 | io_apic_write(dev->id, 0, reg_00.raw); | 1880 | io_apic_write(dev->id, 0, reg_00.raw); |
| 1879 | } | 1881 | } |
| 1880 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1882 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| @@ -2274,8 +2276,8 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) | |||
| 2274 | return -1; | 2276 | return -1; |
| 2275 | 2277 | ||
| 2276 | for (i = 0; i < mp_irq_entries; i++) | 2278 | for (i = 0; i < mp_irq_entries; i++) |
| 2277 | if (mp_irqs[i].mpc_irqtype == mp_INT && | 2279 | if (mp_irqs[i].mp_irqtype == mp_INT && |
| 2278 | mp_irqs[i].mpc_srcbusirq == bus_irq) | 2280 | mp_irqs[i].mp_srcbusirq == bus_irq) |
| 2279 | break; | 2281 | break; |
| 2280 | if (i >= mp_irq_entries) | 2282 | if (i >= mp_irq_entries) |
| 2281 | return -1; | 2283 | return -1; |
| @@ -2368,7 +2370,7 @@ void __init ioapic_init_mappings(void) | |||
| 2368 | ioapic_res = ioapic_setup_resources(); | 2370 | ioapic_res = ioapic_setup_resources(); |
| 2369 | for (i = 0; i < nr_ioapics; i++) { | 2371 | for (i = 0; i < nr_ioapics; i++) { |
| 2370 | if (smp_found_config) { | 2372 | if (smp_found_config) { |
| 2371 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; | 2373 | ioapic_phys = mp_ioapics[i].mp_apicaddr; |
| 2372 | } else { | 2374 | } else { |
| 2373 | ioapic_phys = (unsigned long) | 2375 | ioapic_phys = (unsigned long) |
| 2374 | alloc_bootmem_pages(PAGE_SIZE); | 2376 | alloc_bootmem_pages(PAGE_SIZE); |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 404683b94e79..8b6b1e05c306 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | #include <asm/proto.h> | 25 | #include <asm/proto.h> |
| 26 | #include <asm/acpi.h> | 26 | #include <asm/acpi.h> |
| 27 | #include <asm/bios_ebda.h> | 27 | #include <asm/bios_ebda.h> |
| 28 | #include <asm/e820.h> | ||
| 29 | #include <asm/trampoline.h> | ||
| 28 | 30 | ||
| 29 | #include <mach_apic.h> | 31 | #include <mach_apic.h> |
| 30 | #ifdef CONFIG_X86_32 | 32 | #ifdef CONFIG_X86_32 |
| @@ -32,28 +34,6 @@ | |||
| 32 | #include <mach_mpparse.h> | 34 | #include <mach_mpparse.h> |
| 33 | #endif | 35 | #endif |
| 34 | 36 | ||
| 35 | /* Have we found an MP table */ | ||
| 36 | int smp_found_config; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Various Linux-internal data structures created from the | ||
| 40 | * MP-table. | ||
| 41 | */ | ||
| 42 | #if defined (CONFIG_MCA) || defined (CONFIG_EISA) | ||
| 43 | int mp_bus_id_to_type[MAX_MP_BUSSES]; | ||
| 44 | #endif | ||
| 45 | |||
| 46 | DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | ||
| 47 | int mp_bus_id_to_pci_bus[MAX_MP_BUSSES] = {[0 ... MAX_MP_BUSSES - 1] = -1 }; | ||
| 48 | |||
| 49 | static int mp_current_pci_id; | ||
| 50 | |||
| 51 | int pic_mode; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Intel MP BIOS table parsing routines: | ||
| 55 | */ | ||
| 56 | |||
| 57 | /* | 37 | /* |
| 58 | * Checksum an MP configuration block. | 38 | * Checksum an MP configuration block. |
| 59 | */ | 39 | */ |
| @@ -69,15 +49,73 @@ static int __init mpf_checksum(unsigned char *mp, int len) | |||
| 69 | } | 49 | } |
| 70 | 50 | ||
| 71 | #ifdef CONFIG_X86_NUMAQ | 51 | #ifdef CONFIG_X86_NUMAQ |
| 52 | int found_numaq; | ||
| 72 | /* | 53 | /* |
| 73 | * Have to match translation table entries to main table entries by counter | 54 | * Have to match translation table entries to main table entries by counter |
| 74 | * hence the mpc_record variable .... can't see a less disgusting way of | 55 | * hence the mpc_record variable .... can't see a less disgusting way of |
| 75 | * doing this .... | 56 | * doing this .... |
| 76 | */ | 57 | */ |
| 58 | struct mpc_config_translation { | ||
| 59 | unsigned char mpc_type; | ||
| 60 | unsigned char trans_len; | ||
| 61 | unsigned char trans_type; | ||
| 62 | unsigned char trans_quad; | ||
| 63 | unsigned char trans_global; | ||
| 64 | unsigned char trans_local; | ||
| 65 | unsigned short trans_reserved; | ||
| 66 | }; | ||
| 67 | |||
| 77 | 68 | ||
| 78 | static int mpc_record; | 69 | static int mpc_record; |
| 79 | static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] | 70 | static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] |
| 80 | __cpuinitdata; | 71 | __cpuinitdata; |
| 72 | |||
| 73 | static inline int generate_logical_apicid(int quad, int phys_apicid) | ||
| 74 | { | ||
| 75 | return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); | ||
| 76 | } | ||
| 77 | |||
| 78 | |||
| 79 | static inline int mpc_apic_id(struct mpc_config_processor *m, | ||
| 80 | struct mpc_config_translation *translation_record) | ||
| 81 | { | ||
| 82 | int quad = translation_record->trans_quad; | ||
| 83 | int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid); | ||
| 84 | |||
| 85 | printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", | ||
| 86 | m->mpc_apicid, | ||
| 87 | (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, | ||
| 88 | (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, | ||
| 89 | m->mpc_apicver, quad, logical_apicid); | ||
| 90 | return logical_apicid; | ||
| 91 | } | ||
| 92 | |||
| 93 | int mp_bus_id_to_node[MAX_MP_BUSSES]; | ||
| 94 | |||
| 95 | int mp_bus_id_to_local[MAX_MP_BUSSES]; | ||
| 96 | |||
| 97 | static void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, | ||
| 98 | struct mpc_config_translation *translation) | ||
| 99 | { | ||
| 100 | int quad = translation->trans_quad; | ||
| 101 | int local = translation->trans_local; | ||
| 102 | |||
| 103 | mp_bus_id_to_node[m->mpc_busid] = quad; | ||
| 104 | mp_bus_id_to_local[m->mpc_busid] = local; | ||
| 105 | printk(KERN_INFO "Bus #%d is %s (node %d)\n", | ||
| 106 | m->mpc_busid, name, quad); | ||
| 107 | } | ||
| 108 | |||
| 109 | int quad_local_to_mp_bus_id [NR_CPUS/4][4]; | ||
| 110 | static void mpc_oem_pci_bus(struct mpc_config_bus *m, | ||
| 111 | struct mpc_config_translation *translation) | ||
| 112 | { | ||
| 113 | int quad = translation->trans_quad; | ||
| 114 | int local = translation->trans_local; | ||
| 115 | |||
| 116 | quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; | ||
| 117 | } | ||
| 118 | |||
| 81 | #endif | 119 | #endif |
| 82 | 120 | ||
| 83 | static void __cpuinit MP_processor_info(struct mpc_config_processor *m) | 121 | static void __cpuinit MP_processor_info(struct mpc_config_processor *m) |
| @@ -90,7 +128,10 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m) | |||
| 90 | return; | 128 | return; |
| 91 | } | 129 | } |
| 92 | #ifdef CONFIG_X86_NUMAQ | 130 | #ifdef CONFIG_X86_NUMAQ |
| 93 | apicid = mpc_apic_id(m, translation_table[mpc_record]); | 131 | if (found_numaq) |
| 132 | apicid = mpc_apic_id(m, translation_table[mpc_record]); | ||
| 133 | else | ||
| 134 | apicid = m->mpc_apicid; | ||
| 94 | #else | 135 | #else |
| 95 | apicid = m->mpc_apicid; | 136 | apicid = m->mpc_apicid; |
| 96 | #endif | 137 | #endif |
| @@ -103,17 +144,18 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m) | |||
| 103 | generic_processor_info(apicid, m->mpc_apicver); | 144 | generic_processor_info(apicid, m->mpc_apicver); |
| 104 | } | 145 | } |
| 105 | 146 | ||
| 147 | #ifdef CONFIG_X86_IO_APIC | ||
| 106 | static void __init MP_bus_info(struct mpc_config_bus *m) | 148 | static void __init MP_bus_info(struct mpc_config_bus *m) |
| 107 | { | 149 | { |
| 108 | char str[7]; | 150 | char str[7]; |
| 109 | |||
| 110 | memcpy(str, m->mpc_bustype, 6); | 151 | memcpy(str, m->mpc_bustype, 6); |
| 111 | str[6] = 0; | 152 | str[6] = 0; |
| 112 | 153 | ||
| 113 | #ifdef CONFIG_X86_NUMAQ | 154 | #ifdef CONFIG_X86_NUMAQ |
| 114 | mpc_oem_bus_info(m, str, translation_table[mpc_record]); | 155 | if (found_numaq) |
| 156 | mpc_oem_bus_info(m, str, translation_table[mpc_record]); | ||
| 115 | #else | 157 | #else |
| 116 | Dprintk("Bus #%d is %s\n", m->mpc_busid, str); | 158 | printk(KERN_INFO "Bus #%d is %s\n", m->mpc_busid, str); |
| 117 | #endif | 159 | #endif |
| 118 | 160 | ||
| 119 | #if MAX_MP_BUSSES < 256 | 161 | #if MAX_MP_BUSSES < 256 |
| @@ -132,11 +174,10 @@ static void __init MP_bus_info(struct mpc_config_bus *m) | |||
| 132 | #endif | 174 | #endif |
| 133 | } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) { | 175 | } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) { |
| 134 | #ifdef CONFIG_X86_NUMAQ | 176 | #ifdef CONFIG_X86_NUMAQ |
| 135 | mpc_oem_pci_bus(m, translation_table[mpc_record]); | 177 | if (found_numaq) |
| 178 | mpc_oem_pci_bus(m, translation_table[mpc_record]); | ||
| 136 | #endif | 179 | #endif |
| 137 | clear_bit(m->mpc_busid, mp_bus_not_pci); | 180 | clear_bit(m->mpc_busid, mp_bus_not_pci); |
| 138 | mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; | ||
| 139 | mp_current_pci_id++; | ||
| 140 | #if defined(CONFIG_EISA) || defined (CONFIG_MCA) | 181 | #if defined(CONFIG_EISA) || defined (CONFIG_MCA) |
| 141 | mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; | 182 | mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; |
| 142 | } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) { | 183 | } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) { |
| @@ -147,6 +188,7 @@ static void __init MP_bus_info(struct mpc_config_bus *m) | |||
| 147 | } else | 188 | } else |
| 148 | printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str); | 189 | printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str); |
| 149 | } | 190 | } |
| 191 | #endif | ||
| 150 | 192 | ||
| 151 | #ifdef CONFIG_X86_IO_APIC | 193 | #ifdef CONFIG_X86_IO_APIC |
| 152 | 194 | ||
| @@ -176,18 +218,89 @@ static void __init MP_ioapic_info(struct mpc_config_ioapic *m) | |||
| 176 | if (bad_ioapic(m->mpc_apicaddr)) | 218 | if (bad_ioapic(m->mpc_apicaddr)) |
| 177 | return; | 219 | return; |
| 178 | 220 | ||
| 179 | mp_ioapics[nr_ioapics] = *m; | 221 | mp_ioapics[nr_ioapics].mp_apicaddr = m->mpc_apicaddr; |
| 222 | mp_ioapics[nr_ioapics].mp_apicid = m->mpc_apicid; | ||
| 223 | mp_ioapics[nr_ioapics].mp_type = m->mpc_type; | ||
| 224 | mp_ioapics[nr_ioapics].mp_apicver = m->mpc_apicver; | ||
| 225 | mp_ioapics[nr_ioapics].mp_flags = m->mpc_flags; | ||
| 180 | nr_ioapics++; | 226 | nr_ioapics++; |
| 181 | } | 227 | } |
| 182 | 228 | ||
| 183 | static void __init MP_intsrc_info(struct mpc_config_intsrc *m) | 229 | static void print_MP_intsrc_info(struct mpc_config_intsrc *m) |
| 184 | { | 230 | { |
| 185 | mp_irqs[mp_irq_entries] = *m; | 231 | printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x," |
| 186 | Dprintk("Int: type %d, pol %d, trig %d, bus %d," | ||
| 187 | " IRQ %02x, APIC ID %x, APIC INT %02x\n", | 232 | " IRQ %02x, APIC ID %x, APIC INT %02x\n", |
| 188 | m->mpc_irqtype, m->mpc_irqflag & 3, | 233 | m->mpc_irqtype, m->mpc_irqflag & 3, |
| 189 | (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, | 234 | (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, |
| 190 | m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); | 235 | m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); |
| 236 | } | ||
| 237 | |||
| 238 | static void __init print_mp_irq_info(struct mp_config_intsrc *mp_irq) | ||
| 239 | { | ||
| 240 | printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x," | ||
| 241 | " IRQ %02x, APIC ID %x, APIC INT %02x\n", | ||
| 242 | mp_irq->mp_irqtype, mp_irq->mp_irqflag & 3, | ||
| 243 | (mp_irq->mp_irqflag >> 2) & 3, mp_irq->mp_srcbus, | ||
| 244 | mp_irq->mp_srcbusirq, mp_irq->mp_dstapic, mp_irq->mp_dstirq); | ||
| 245 | } | ||
| 246 | |||
| 247 | static void __init assign_to_mp_irq(struct mpc_config_intsrc *m, | ||
| 248 | struct mp_config_intsrc *mp_irq) | ||
| 249 | { | ||
| 250 | mp_irq->mp_dstapic = m->mpc_dstapic; | ||
| 251 | mp_irq->mp_type = m->mpc_type; | ||
| 252 | mp_irq->mp_irqtype = m->mpc_irqtype; | ||
| 253 | mp_irq->mp_irqflag = m->mpc_irqflag; | ||
| 254 | mp_irq->mp_srcbus = m->mpc_srcbus; | ||
| 255 | mp_irq->mp_srcbusirq = m->mpc_srcbusirq; | ||
| 256 | mp_irq->mp_dstirq = m->mpc_dstirq; | ||
| 257 | } | ||
| 258 | |||
| 259 | static void __init assign_to_mpc_intsrc(struct mp_config_intsrc *mp_irq, | ||
| 260 | struct mpc_config_intsrc *m) | ||
| 261 | { | ||
| 262 | m->mpc_dstapic = mp_irq->mp_dstapic; | ||
| 263 | m->mpc_type = mp_irq->mp_type; | ||
| 264 | m->mpc_irqtype = mp_irq->mp_irqtype; | ||
| 265 | m->mpc_irqflag = mp_irq->mp_irqflag; | ||
| 266 | m->mpc_srcbus = mp_irq->mp_srcbus; | ||
| 267 | m->mpc_srcbusirq = mp_irq->mp_srcbusirq; | ||
| 268 | m->mpc_dstirq = mp_irq->mp_dstirq; | ||
| 269 | } | ||
| 270 | |||
| 271 | static int __init mp_irq_mpc_intsrc_cmp(struct mp_config_intsrc *mp_irq, | ||
| 272 | struct mpc_config_intsrc *m) | ||
| 273 | { | ||
| 274 | if (mp_irq->mp_dstapic != m->mpc_dstapic) | ||
| 275 | return 1; | ||
| 276 | if (mp_irq->mp_type != m->mpc_type) | ||
| 277 | return 2; | ||
| 278 | if (mp_irq->mp_irqtype != m->mpc_irqtype) | ||
| 279 | return 3; | ||
| 280 | if (mp_irq->mp_irqflag != m->mpc_irqflag) | ||
| 281 | return 4; | ||
| 282 | if (mp_irq->mp_srcbus != m->mpc_srcbus) | ||
| 283 | return 5; | ||
| 284 | if (mp_irq->mp_srcbusirq != m->mpc_srcbusirq) | ||
| 285 | return 6; | ||
| 286 | if (mp_irq->mp_dstirq != m->mpc_dstirq) | ||
| 287 | return 7; | ||
| 288 | |||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | static void __init MP_intsrc_info(struct mpc_config_intsrc *m) | ||
| 293 | { | ||
| 294 | int i; | ||
| 295 | |||
| 296 | print_MP_intsrc_info(m); | ||
| 297 | |||
| 298 | for (i = 0; i < mp_irq_entries; i++) { | ||
| 299 | if (!mp_irq_mpc_intsrc_cmp(&mp_irqs[i], m)) | ||
| 300 | return; | ||
| 301 | } | ||
| 302 | |||
| 303 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
| 191 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | 304 | if (++mp_irq_entries == MAX_IRQ_SOURCES) |
| 192 | panic("Max # of irq sources exceeded!!\n"); | 305 | panic("Max # of irq sources exceeded!!\n"); |
| 193 | } | 306 | } |
| @@ -196,7 +309,7 @@ static void __init MP_intsrc_info(struct mpc_config_intsrc *m) | |||
| 196 | 309 | ||
| 197 | static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m) | 310 | static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m) |
| 198 | { | 311 | { |
| 199 | Dprintk("Lint: type %d, pol %d, trig %d, bus %d," | 312 | printk(KERN_INFO "Lint: type %d, pol %d, trig %d, bus %02x," |
| 200 | " IRQ %02x, APIC ID %x, APIC LINT %02x\n", | 313 | " IRQ %02x, APIC ID %x, APIC LINT %02x\n", |
| 201 | m->mpc_irqtype, m->mpc_irqflag & 3, | 314 | m->mpc_irqtype, m->mpc_irqflag & 3, |
| 202 | (m->mpc_irqflag >> 2) & 3, m->mpc_srcbusid, | 315 | (m->mpc_irqflag >> 2) & 3, m->mpc_srcbusid, |
| @@ -266,11 +379,14 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, | |||
| 266 | } | 379 | } |
| 267 | } | 380 | } |
| 268 | 381 | ||
| 269 | static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, | 382 | void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, |
| 270 | char *productid) | 383 | char *productid) |
| 271 | { | 384 | { |
| 272 | if (strncmp(oem, "IBM NUMA", 8)) | 385 | if (strncmp(oem, "IBM NUMA", 8)) |
| 273 | printk("Warning! May not be a NUMA-Q system!\n"); | 386 | printk("Warning! Not a NUMA-Q system!\n"); |
| 387 | else | ||
| 388 | found_numaq = 1; | ||
| 389 | |||
| 274 | if (mpc->mpc_oemptr) | 390 | if (mpc->mpc_oemptr) |
| 275 | smp_read_mpc_oem((struct mp_config_oemtable *)mpc->mpc_oemptr, | 391 | smp_read_mpc_oem((struct mp_config_oemtable *)mpc->mpc_oemptr, |
| 276 | mpc->mpc_oemsize); | 392 | mpc->mpc_oemsize); |
| @@ -281,12 +397,9 @@ static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, | |||
| 281 | * Read/parse the MPC | 397 | * Read/parse the MPC |
| 282 | */ | 398 | */ |
| 283 | 399 | ||
| 284 | static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | 400 | static int __init smp_check_mpc(struct mp_config_table *mpc, char *oem, |
| 401 | char *str) | ||
| 285 | { | 402 | { |
| 286 | char str[16]; | ||
| 287 | char oem[10]; | ||
| 288 | int count = sizeof(*mpc); | ||
| 289 | unsigned char *mpt = ((unsigned char *)mpc) + count; | ||
| 290 | 403 | ||
| 291 | if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) { | 404 | if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) { |
| 292 | printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n", | 405 | printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n", |
| @@ -309,19 +422,42 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | |||
| 309 | } | 422 | } |
| 310 | memcpy(oem, mpc->mpc_oem, 8); | 423 | memcpy(oem, mpc->mpc_oem, 8); |
| 311 | oem[8] = 0; | 424 | oem[8] = 0; |
| 312 | printk(KERN_INFO "MPTABLE: OEM ID: %s ", oem); | 425 | printk(KERN_INFO "MPTABLE: OEM ID: %s\n", oem); |
| 313 | 426 | ||
| 314 | memcpy(str, mpc->mpc_productid, 12); | 427 | memcpy(str, mpc->mpc_productid, 12); |
| 315 | str[12] = 0; | 428 | str[12] = 0; |
| 316 | printk("Product ID: %s ", str); | ||
| 317 | 429 | ||
| 318 | #ifdef CONFIG_X86_32 | 430 | printk(KERN_INFO "MPTABLE: Product ID: %s\n", str); |
| 319 | mps_oem_check(mpc, oem, str); | ||
| 320 | #endif | ||
| 321 | printk(KERN_INFO "MPTABLE: Product ID: %s ", str); | ||
| 322 | 431 | ||
| 323 | printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic); | 432 | printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic); |
| 324 | 433 | ||
| 434 | return 1; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | ||
| 438 | { | ||
| 439 | char str[16]; | ||
| 440 | char oem[10]; | ||
| 441 | |||
| 442 | int count = sizeof(*mpc); | ||
| 443 | unsigned char *mpt = ((unsigned char *)mpc) + count; | ||
| 444 | |||
| 445 | if (!smp_check_mpc(mpc, oem, str)) | ||
| 446 | return 0; | ||
| 447 | |||
| 448 | #ifdef CONFIG_X86_32 | ||
| 449 | /* | ||
| 450 | * need to make sure summit and es7000's mps_oem_check is safe to be | ||
| 451 | * called early via genericarch 's mps_oem_check | ||
| 452 | */ | ||
| 453 | if (early) { | ||
| 454 | #ifdef CONFIG_X86_NUMAQ | ||
| 455 | numaq_mps_oem_check(mpc, oem, str); | ||
| 456 | #endif | ||
| 457 | } else | ||
| 458 | mps_oem_check(mpc, oem, str); | ||
| 459 | #endif | ||
| 460 | |||
| 325 | /* save the local APIC address, it might be non-default */ | 461 | /* save the local APIC address, it might be non-default */ |
| 326 | if (!acpi_lapic) | 462 | if (!acpi_lapic) |
| 327 | mp_lapic_addr = mpc->mpc_lapic; | 463 | mp_lapic_addr = mpc->mpc_lapic; |
| @@ -352,7 +488,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | |||
| 352 | { | 488 | { |
| 353 | struct mpc_config_bus *m = | 489 | struct mpc_config_bus *m = |
| 354 | (struct mpc_config_bus *)mpt; | 490 | (struct mpc_config_bus *)mpt; |
| 491 | #ifdef CONFIG_X86_IO_APIC | ||
| 355 | MP_bus_info(m); | 492 | MP_bus_info(m); |
| 493 | #endif | ||
| 356 | mpt += sizeof(*m); | 494 | mpt += sizeof(*m); |
| 357 | count += sizeof(*m); | 495 | count += sizeof(*m); |
| 358 | break; | 496 | break; |
| @@ -402,6 +540,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | |||
| 402 | ++mpc_record; | 540 | ++mpc_record; |
| 403 | #endif | 541 | #endif |
| 404 | } | 542 | } |
| 543 | |||
| 544 | #ifdef CONFIG_X86_GENERICARCH | ||
| 545 | generic_bigsmp_probe(); | ||
| 546 | #endif | ||
| 547 | |||
| 405 | setup_apic_routing(); | 548 | setup_apic_routing(); |
| 406 | if (!num_processors) | 549 | if (!num_processors) |
| 407 | printk(KERN_ERR "MPTABLE: no processors registered!\n"); | 550 | printk(KERN_ERR "MPTABLE: no processors registered!\n"); |
| @@ -427,7 +570,7 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type) | |||
| 427 | intsrc.mpc_type = MP_INTSRC; | 570 | intsrc.mpc_type = MP_INTSRC; |
| 428 | intsrc.mpc_irqflag = 0; /* conforming */ | 571 | intsrc.mpc_irqflag = 0; /* conforming */ |
| 429 | intsrc.mpc_srcbus = 0; | 572 | intsrc.mpc_srcbus = 0; |
| 430 | intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid; | 573 | intsrc.mpc_dstapic = mp_ioapics[0].mp_apicid; |
| 431 | 574 | ||
| 432 | intsrc.mpc_irqtype = mp_INT; | 575 | intsrc.mpc_irqtype = mp_INT; |
| 433 | 576 | ||
| @@ -488,40 +631,11 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type) | |||
| 488 | MP_intsrc_info(&intsrc); | 631 | MP_intsrc_info(&intsrc); |
| 489 | } | 632 | } |
| 490 | 633 | ||
| 491 | #endif | ||
| 492 | 634 | ||
| 493 | static inline void __init construct_default_ISA_mptable(int mpc_default_type) | 635 | static void construct_ioapic_table(int mpc_default_type) |
| 494 | { | 636 | { |
| 495 | struct mpc_config_processor processor; | ||
| 496 | struct mpc_config_bus bus; | ||
| 497 | #ifdef CONFIG_X86_IO_APIC | ||
| 498 | struct mpc_config_ioapic ioapic; | 637 | struct mpc_config_ioapic ioapic; |
| 499 | #endif | 638 | struct mpc_config_bus bus; |
| 500 | struct mpc_config_lintsrc lintsrc; | ||
| 501 | int linttypes[2] = { mp_ExtINT, mp_NMI }; | ||
| 502 | int i; | ||
| 503 | |||
| 504 | /* | ||
| 505 | * local APIC has default address | ||
| 506 | */ | ||
| 507 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; | ||
| 508 | |||
| 509 | /* | ||
| 510 | * 2 CPUs, numbered 0 & 1. | ||
| 511 | */ | ||
| 512 | processor.mpc_type = MP_PROCESSOR; | ||
| 513 | /* Either an integrated APIC or a discrete 82489DX. */ | ||
| 514 | processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; | ||
| 515 | processor.mpc_cpuflag = CPU_ENABLED; | ||
| 516 | processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | | ||
| 517 | (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask; | ||
| 518 | processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; | ||
| 519 | processor.mpc_reserved[0] = 0; | ||
| 520 | processor.mpc_reserved[1] = 0; | ||
| 521 | for (i = 0; i < 2; i++) { | ||
| 522 | processor.mpc_apicid = i; | ||
| 523 | MP_processor_info(&processor); | ||
| 524 | } | ||
| 525 | 639 | ||
| 526 | bus.mpc_type = MP_BUS; | 640 | bus.mpc_type = MP_BUS; |
| 527 | bus.mpc_busid = 0; | 641 | bus.mpc_busid = 0; |
| @@ -550,7 +664,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) | |||
| 550 | MP_bus_info(&bus); | 664 | MP_bus_info(&bus); |
| 551 | } | 665 | } |
| 552 | 666 | ||
| 553 | #ifdef CONFIG_X86_IO_APIC | ||
| 554 | ioapic.mpc_type = MP_IOAPIC; | 667 | ioapic.mpc_type = MP_IOAPIC; |
| 555 | ioapic.mpc_apicid = 2; | 668 | ioapic.mpc_apicid = 2; |
| 556 | ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; | 669 | ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; |
| @@ -562,7 +675,42 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) | |||
| 562 | * We set up most of the low 16 IO-APIC pins according to MPS rules. | 675 | * We set up most of the low 16 IO-APIC pins according to MPS rules. |
| 563 | */ | 676 | */ |
| 564 | construct_default_ioirq_mptable(mpc_default_type); | 677 | construct_default_ioirq_mptable(mpc_default_type); |
| 678 | } | ||
| 679 | #else | ||
| 680 | static inline void construct_ioapic_table(int mpc_default_type) { } | ||
| 565 | #endif | 681 | #endif |
| 682 | |||
| 683 | static inline void __init construct_default_ISA_mptable(int mpc_default_type) | ||
| 684 | { | ||
| 685 | struct mpc_config_processor processor; | ||
| 686 | struct mpc_config_lintsrc lintsrc; | ||
| 687 | int linttypes[2] = { mp_ExtINT, mp_NMI }; | ||
| 688 | int i; | ||
| 689 | |||
| 690 | /* | ||
| 691 | * local APIC has default address | ||
| 692 | */ | ||
| 693 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; | ||
| 694 | |||
| 695 | /* | ||
| 696 | * 2 CPUs, numbered 0 & 1. | ||
| 697 | */ | ||
| 698 | processor.mpc_type = MP_PROCESSOR; | ||
| 699 | /* Either an integrated APIC or a discrete 82489DX. */ | ||
| 700 | processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; | ||
| 701 | processor.mpc_cpuflag = CPU_ENABLED; | ||
| 702 | processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | | ||
| 703 | (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask; | ||
| 704 | processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; | ||
| 705 | processor.mpc_reserved[0] = 0; | ||
| 706 | processor.mpc_reserved[1] = 0; | ||
| 707 | for (i = 0; i < 2; i++) { | ||
| 708 | processor.mpc_apicid = i; | ||
| 709 | MP_processor_info(&processor); | ||
| 710 | } | ||
| 711 | |||
| 712 | construct_ioapic_table(mpc_default_type); | ||
| 713 | |||
| 566 | lintsrc.mpc_type = MP_LINTSRC; | 714 | lintsrc.mpc_type = MP_LINTSRC; |
| 567 | lintsrc.mpc_irqflag = 0; /* conforming */ | 715 | lintsrc.mpc_irqflag = 0; /* conforming */ |
| 568 | lintsrc.mpc_srcbusid = 0; | 716 | lintsrc.mpc_srcbusid = 0; |
| @@ -600,7 +748,7 @@ static void __init __get_smp_config(unsigned early) | |||
| 600 | 748 | ||
| 601 | printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", | 749 | printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", |
| 602 | mpf->mpf_specification); | 750 | mpf->mpf_specification); |
| 603 | #ifdef CONFIG_X86_32 | 751 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32) |
| 604 | if (mpf->mpf_feature2 & (1 << 7)) { | 752 | if (mpf->mpf_feature2 & (1 << 7)) { |
| 605 | printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); | 753 | printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); |
| 606 | pic_mode = 1; | 754 | pic_mode = 1; |
| @@ -632,7 +780,9 @@ static void __init __get_smp_config(unsigned early) | |||
| 632 | * override the defaults. | 780 | * override the defaults. |
| 633 | */ | 781 | */ |
| 634 | if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr), early)) { | 782 | if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr), early)) { |
| 783 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 635 | smp_found_config = 0; | 784 | smp_found_config = 0; |
| 785 | #endif | ||
| 636 | printk(KERN_ERR | 786 | printk(KERN_ERR |
| 637 | "BIOS bug, MP table errors detected!...\n"); | 787 | "BIOS bug, MP table errors detected!...\n"); |
| 638 | printk(KERN_ERR "... disabling SMP support. " | 788 | printk(KERN_ERR "... disabling SMP support. " |
| @@ -689,7 +839,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length, | |||
| 689 | unsigned int *bp = phys_to_virt(base); | 839 | unsigned int *bp = phys_to_virt(base); |
| 690 | struct intel_mp_floating *mpf; | 840 | struct intel_mp_floating *mpf; |
| 691 | 841 | ||
| 692 | Dprintk("Scan SMP from %p for %ld bytes.\n", bp, length); | 842 | printk(KERN_DEBUG "Scan SMP from %p for %ld bytes.\n", bp, length); |
| 693 | BUILD_BUG_ON(sizeof(*mpf) != 16); | 843 | BUILD_BUG_ON(sizeof(*mpf) != 16); |
| 694 | 844 | ||
| 695 | while (length > 0) { | 845 | while (length > 0) { |
| @@ -699,15 +849,21 @@ static int __init smp_scan_config(unsigned long base, unsigned long length, | |||
| 699 | !mpf_checksum((unsigned char *)bp, 16) && | 849 | !mpf_checksum((unsigned char *)bp, 16) && |
| 700 | ((mpf->mpf_specification == 1) | 850 | ((mpf->mpf_specification == 1) |
| 701 | || (mpf->mpf_specification == 4))) { | 851 | || (mpf->mpf_specification == 4))) { |
| 702 | 852 | #ifdef CONFIG_X86_LOCAL_APIC | |
| 703 | smp_found_config = 1; | 853 | smp_found_config = 1; |
| 854 | #endif | ||
| 704 | mpf_found = mpf; | 855 | mpf_found = mpf; |
| 705 | #ifdef CONFIG_X86_32 | 856 | |
| 706 | printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n", | 857 | printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n", |
| 707 | mpf, virt_to_phys(mpf)); | 858 | mpf, virt_to_phys(mpf)); |
| 708 | reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE, | 859 | |
| 860 | if (!reserve) | ||
| 861 | return 1; | ||
| 862 | reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE, | ||
| 709 | BOOTMEM_DEFAULT); | 863 | BOOTMEM_DEFAULT); |
| 710 | if (mpf->mpf_physptr) { | 864 | if (mpf->mpf_physptr) { |
| 865 | unsigned long size = PAGE_SIZE; | ||
| 866 | #ifdef CONFIG_X86_32 | ||
| 711 | /* | 867 | /* |
| 712 | * We cannot access to MPC table to compute | 868 | * We cannot access to MPC table to compute |
| 713 | * table size yet, as only few megabytes from | 869 | * table size yet, as only few megabytes from |
| @@ -717,24 +873,15 @@ static int __init smp_scan_config(unsigned long base, unsigned long length, | |||
| 717 | * PAGE_SIZE from mpg->mpf_physptr yields BUG() | 873 | * PAGE_SIZE from mpg->mpf_physptr yields BUG() |
| 718 | * in reserve_bootmem. | 874 | * in reserve_bootmem. |
| 719 | */ | 875 | */ |
| 720 | unsigned long size = PAGE_SIZE; | ||
| 721 | unsigned long end = max_low_pfn * PAGE_SIZE; | 876 | unsigned long end = max_low_pfn * PAGE_SIZE; |
| 722 | if (mpf->mpf_physptr + size > end) | 877 | if (mpf->mpf_physptr + size > end) |
| 723 | size = end - mpf->mpf_physptr; | 878 | size = end - mpf->mpf_physptr; |
| 724 | reserve_bootmem(mpf->mpf_physptr, size, | 879 | #endif |
| 880 | reserve_bootmem_generic(mpf->mpf_physptr, size, | ||
| 725 | BOOTMEM_DEFAULT); | 881 | BOOTMEM_DEFAULT); |
| 726 | } | 882 | } |
| 727 | 883 | ||
| 728 | #else | 884 | return 1; |
| 729 | if (!reserve) | ||
| 730 | return 1; | ||
| 731 | |||
| 732 | reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE); | ||
| 733 | if (mpf->mpf_physptr) | ||
| 734 | reserve_bootmem_generic(mpf->mpf_physptr, | ||
| 735 | PAGE_SIZE); | ||
| 736 | #endif | ||
| 737 | return 1; | ||
| 738 | } | 885 | } |
| 739 | bp += 4; | 886 | bp += 4; |
| 740 | length -= 16; | 887 | length -= 16; |
| @@ -790,298 +937,294 @@ void __init find_smp_config(void) | |||
| 790 | __find_smp_config(1); | 937 | __find_smp_config(1); |
| 791 | } | 938 | } |
| 792 | 939 | ||
| 793 | /* -------------------------------------------------------------------------- | 940 | #ifdef CONFIG_X86_IO_APIC |
| 794 | ACPI-based MP Configuration | 941 | static u8 __initdata irq_used[MAX_IRQ_SOURCES]; |
| 795 | -------------------------------------------------------------------------- */ | ||
| 796 | 942 | ||
| 797 | /* | 943 | static int __init get_MP_intsrc_index(struct mpc_config_intsrc *m) |
| 798 | * Keep this outside and initialized to 0, for !CONFIG_ACPI builds: | 944 | { |
| 799 | */ | 945 | int i; |
| 800 | int es7000_plat; | ||
| 801 | 946 | ||
| 802 | #ifdef CONFIG_ACPI | 947 | if (m->mpc_irqtype != mp_INT) |
| 948 | return 0; | ||
| 803 | 949 | ||
| 804 | #ifdef CONFIG_X86_IO_APIC | 950 | if (m->mpc_irqflag != 0x0f) |
| 951 | return 0; | ||
| 805 | 952 | ||
| 806 | #define MP_ISA_BUS 0 | 953 | /* not legacy */ |
| 807 | 954 | ||
| 808 | extern struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS]; | 955 | for (i = 0; i < mp_irq_entries; i++) { |
| 956 | if (mp_irqs[i].mp_irqtype != mp_INT) | ||
| 957 | continue; | ||
| 809 | 958 | ||
| 810 | static int mp_find_ioapic(int gsi) | 959 | if (mp_irqs[i].mp_irqflag != 0x0f) |
| 811 | { | 960 | continue; |
| 812 | int i = 0; | ||
| 813 | 961 | ||
| 814 | /* Find the IOAPIC that manages this GSI. */ | 962 | if (mp_irqs[i].mp_srcbus != m->mpc_srcbus) |
| 815 | for (i = 0; i < nr_ioapics; i++) { | 963 | continue; |
| 816 | if ((gsi >= mp_ioapic_routing[i].gsi_base) | 964 | if (mp_irqs[i].mp_srcbusirq != m->mpc_srcbusirq) |
| 817 | && (gsi <= mp_ioapic_routing[i].gsi_end)) | 965 | continue; |
| 818 | return i; | 966 | if (irq_used[i]) { |
| 967 | /* already claimed */ | ||
| 968 | return -2; | ||
| 969 | } | ||
| 970 | irq_used[i] = 1; | ||
| 971 | return i; | ||
| 819 | } | 972 | } |
| 820 | 973 | ||
| 821 | printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); | 974 | /* not found */ |
| 822 | return -1; | 975 | return -1; |
| 823 | } | 976 | } |
| 824 | 977 | ||
| 825 | static u8 __init uniq_ioapic_id(u8 id) | 978 | #define SPARE_SLOT_NUM 20 |
| 826 | { | 979 | |
| 827 | #ifdef CONFIG_X86_32 | 980 | static struct mpc_config_intsrc __initdata *m_spare[SPARE_SLOT_NUM]; |
| 828 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && | ||
| 829 | !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) | ||
| 830 | return io_apic_get_unique_id(nr_ioapics, id); | ||
| 831 | else | ||
| 832 | return id; | ||
| 833 | #else | ||
| 834 | int i; | ||
| 835 | DECLARE_BITMAP(used, 256); | ||
| 836 | bitmap_zero(used, 256); | ||
| 837 | for (i = 0; i < nr_ioapics; i++) { | ||
| 838 | struct mpc_config_ioapic *ia = &mp_ioapics[i]; | ||
| 839 | __set_bit(ia->mpc_apicid, used); | ||
| 840 | } | ||
| 841 | if (!test_bit(id, used)) | ||
| 842 | return id; | ||
| 843 | return find_first_zero_bit(used, 256); | ||
| 844 | #endif | 981 | #endif |
| 845 | } | ||
| 846 | 982 | ||
| 847 | void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | 983 | static int __init replace_intsrc_all(struct mp_config_table *mpc, |
| 984 | unsigned long mpc_new_phys, | ||
| 985 | unsigned long mpc_new_length) | ||
| 848 | { | 986 | { |
| 849 | int idx = 0; | 987 | #ifdef CONFIG_X86_IO_APIC |
| 850 | 988 | int i; | |
| 851 | if (bad_ioapic(address)) | 989 | int nr_m_spare = 0; |
| 852 | return; | 990 | #endif |
| 853 | 991 | ||
| 854 | idx = nr_ioapics; | 992 | int count = sizeof(*mpc); |
| 993 | unsigned char *mpt = ((unsigned char *)mpc) + count; | ||
| 855 | 994 | ||
| 856 | mp_ioapics[idx].mpc_type = MP_IOAPIC; | 995 | printk(KERN_INFO "mpc_length %x\n", mpc->mpc_length); |
| 857 | mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE; | 996 | while (count < mpc->mpc_length) { |
| 858 | mp_ioapics[idx].mpc_apicaddr = address; | 997 | switch (*mpt) { |
| 998 | case MP_PROCESSOR: | ||
| 999 | { | ||
| 1000 | struct mpc_config_processor *m = | ||
| 1001 | (struct mpc_config_processor *)mpt; | ||
| 1002 | mpt += sizeof(*m); | ||
| 1003 | count += sizeof(*m); | ||
| 1004 | break; | ||
| 1005 | } | ||
| 1006 | case MP_BUS: | ||
| 1007 | { | ||
| 1008 | struct mpc_config_bus *m = | ||
| 1009 | (struct mpc_config_bus *)mpt; | ||
| 1010 | mpt += sizeof(*m); | ||
| 1011 | count += sizeof(*m); | ||
| 1012 | break; | ||
| 1013 | } | ||
| 1014 | case MP_IOAPIC: | ||
| 1015 | { | ||
| 1016 | mpt += sizeof(struct mpc_config_ioapic); | ||
| 1017 | count += sizeof(struct mpc_config_ioapic); | ||
| 1018 | break; | ||
| 1019 | } | ||
| 1020 | case MP_INTSRC: | ||
| 1021 | { | ||
| 1022 | #ifdef CONFIG_X86_IO_APIC | ||
| 1023 | struct mpc_config_intsrc *m = | ||
| 1024 | (struct mpc_config_intsrc *)mpt; | ||
| 859 | 1025 | ||
| 860 | set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); | 1026 | printk(KERN_INFO "OLD "); |
| 861 | mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id); | 1027 | print_MP_intsrc_info(m); |
| 862 | #ifdef CONFIG_X86_32 | 1028 | i = get_MP_intsrc_index(m); |
| 863 | mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); | 1029 | if (i > 0) { |
| 864 | #else | 1030 | assign_to_mpc_intsrc(&mp_irqs[i], m); |
| 865 | mp_ioapics[idx].mpc_apicver = 0; | 1031 | printk(KERN_INFO "NEW "); |
| 1032 | print_mp_irq_info(&mp_irqs[i]); | ||
| 1033 | } else if (!i) { | ||
| 1034 | /* legacy, do nothing */ | ||
| 1035 | } else if (nr_m_spare < SPARE_SLOT_NUM) { | ||
| 1036 | /* | ||
| 1037 | * not found (-1), or duplicated (-2) | ||
| 1038 | * are invalid entries, | ||
| 1039 | * we need to use the slot later | ||
| 1040 | */ | ||
| 1041 | m_spare[nr_m_spare] = m; | ||
| 1042 | nr_m_spare++; | ||
| 1043 | } | ||
| 866 | #endif | 1044 | #endif |
| 867 | /* | 1045 | mpt += sizeof(struct mpc_config_intsrc); |
| 868 | * Build basic GSI lookup table to facilitate gsi->io_apic lookups | 1046 | count += sizeof(struct mpc_config_intsrc); |
| 869 | * and to prevent reprogramming of IOAPIC pins (PCI GSIs). | 1047 | break; |
| 870 | */ | 1048 | } |
| 871 | mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid; | 1049 | case MP_LINTSRC: |
| 872 | mp_ioapic_routing[idx].gsi_base = gsi_base; | 1050 | { |
| 873 | mp_ioapic_routing[idx].gsi_end = gsi_base + | 1051 | struct mpc_config_lintsrc *m = |
| 874 | io_apic_get_redir_entries(idx); | 1052 | (struct mpc_config_lintsrc *)mpt; |
| 875 | 1053 | mpt += sizeof(*m); | |
| 876 | printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " | 1054 | count += sizeof(*m); |
| 877 | "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, | 1055 | break; |
| 878 | mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, | 1056 | } |
| 879 | mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end); | 1057 | default: |
| 880 | 1058 | /* wrong mptable */ | |
| 881 | nr_ioapics++; | 1059 | printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n"); |
| 882 | } | 1060 | printk(KERN_ERR "type %x\n", *mpt); |
| 1061 | print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_ADDRESS, 16, | ||
| 1062 | 1, mpc, mpc->mpc_length, 1); | ||
| 1063 | goto out; | ||
| 1064 | } | ||
| 1065 | } | ||
| 883 | 1066 | ||
| 884 | void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) | 1067 | #ifdef CONFIG_X86_IO_APIC |
| 885 | { | 1068 | for (i = 0; i < mp_irq_entries; i++) { |
| 886 | struct mpc_config_intsrc intsrc; | 1069 | if (irq_used[i]) |
| 887 | int ioapic = -1; | 1070 | continue; |
| 888 | int pin = -1; | ||
| 889 | 1071 | ||
| 890 | /* | 1072 | if (mp_irqs[i].mp_irqtype != mp_INT) |
| 891 | * Convert 'gsi' to 'ioapic.pin'. | 1073 | continue; |
| 892 | */ | ||
| 893 | ioapic = mp_find_ioapic(gsi); | ||
| 894 | if (ioapic < 0) | ||
| 895 | return; | ||
| 896 | pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | ||
| 897 | 1074 | ||
| 898 | /* | 1075 | if (mp_irqs[i].mp_irqflag != 0x0f) |
| 899 | * TBD: This check is for faulty timer entries, where the override | 1076 | continue; |
| 900 | * erroneously sets the trigger to level, resulting in a HUGE | ||
| 901 | * increase of timer interrupts! | ||
| 902 | */ | ||
| 903 | if ((bus_irq == 0) && (trigger == 3)) | ||
| 904 | trigger = 1; | ||
| 905 | 1077 | ||
| 906 | intsrc.mpc_type = MP_INTSRC; | 1078 | if (nr_m_spare > 0) { |
| 907 | intsrc.mpc_irqtype = mp_INT; | 1079 | printk(KERN_INFO "*NEW* found "); |
| 908 | intsrc.mpc_irqflag = (trigger << 2) | polarity; | 1080 | nr_m_spare--; |
| 909 | intsrc.mpc_srcbus = MP_ISA_BUS; | 1081 | assign_to_mpc_intsrc(&mp_irqs[i], m_spare[nr_m_spare]); |
| 910 | intsrc.mpc_srcbusirq = bus_irq; /* IRQ */ | 1082 | m_spare[nr_m_spare] = NULL; |
| 911 | intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */ | 1083 | } else { |
| 912 | intsrc.mpc_dstirq = pin; /* INTIN# */ | 1084 | struct mpc_config_intsrc *m = |
| 1085 | (struct mpc_config_intsrc *)mpt; | ||
| 1086 | count += sizeof(struct mpc_config_intsrc); | ||
| 1087 | if (!mpc_new_phys) { | ||
| 1088 | printk(KERN_INFO "No spare slots, try to append...take your risk, new mpc_length %x\n", count); | ||
| 1089 | } else { | ||
| 1090 | if (count <= mpc_new_length) | ||
| 1091 | printk(KERN_INFO "No spare slots, try to append..., new mpc_length %x\n", count); | ||
| 1092 | else { | ||
| 1093 | printk(KERN_ERR "mpc_new_length %lx is too small\n", mpc_new_length); | ||
| 1094 | goto out; | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | assign_to_mpc_intsrc(&mp_irqs[i], m); | ||
| 1098 | mpc->mpc_length = count; | ||
| 1099 | mpt += sizeof(struct mpc_config_intsrc); | ||
| 1100 | } | ||
| 1101 | print_mp_irq_info(&mp_irqs[i]); | ||
| 1102 | } | ||
| 1103 | #endif | ||
| 1104 | out: | ||
| 1105 | /* update checksum */ | ||
| 1106 | mpc->mpc_checksum = 0; | ||
| 1107 | mpc->mpc_checksum -= mpf_checksum((unsigned char *)mpc, | ||
| 1108 | mpc->mpc_length); | ||
| 913 | 1109 | ||
| 914 | MP_intsrc_info(&intsrc); | 1110 | return 0; |
| 915 | } | 1111 | } |
| 916 | 1112 | ||
| 917 | void __init mp_config_acpi_legacy_irqs(void) | 1113 | static int __initdata enable_update_mptable; |
| 918 | { | ||
| 919 | struct mpc_config_intsrc intsrc; | ||
| 920 | int i = 0; | ||
| 921 | int ioapic = -1; | ||
| 922 | 1114 | ||
| 923 | #if defined (CONFIG_MCA) || defined (CONFIG_EISA) | 1115 | static int __init update_mptable_setup(char *str) |
| 924 | /* | 1116 | { |
| 925 | * Fabricate the legacy ISA bus (bus #31). | 1117 | enable_update_mptable = 1; |
| 926 | */ | 1118 | return 0; |
| 927 | mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; | 1119 | } |
| 928 | #endif | 1120 | early_param("update_mptable", update_mptable_setup); |
| 929 | set_bit(MP_ISA_BUS, mp_bus_not_pci); | ||
| 930 | Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); | ||
| 931 | 1121 | ||
| 932 | /* | 1122 | static unsigned long __initdata mpc_new_phys; |
| 933 | * Older generations of ES7000 have no legacy identity mappings | 1123 | static unsigned long mpc_new_length __initdata = 4096; |
| 934 | */ | ||
| 935 | if (es7000_plat == 1) | ||
| 936 | return; | ||
| 937 | 1124 | ||
| 938 | /* | 1125 | /* alloc_mptable or alloc_mptable=4k */ |
| 939 | * Locate the IOAPIC that manages the ISA IRQs (0-15). | 1126 | static int __initdata alloc_mptable; |
| 940 | */ | 1127 | static int __init parse_alloc_mptable_opt(char *p) |
| 941 | ioapic = mp_find_ioapic(0); | 1128 | { |
| 942 | if (ioapic < 0) | 1129 | enable_update_mptable = 1; |
| 943 | return; | 1130 | alloc_mptable = 1; |
| 1131 | if (!p) | ||
| 1132 | return 0; | ||
| 1133 | mpc_new_length = memparse(p, &p); | ||
| 1134 | return 0; | ||
| 1135 | } | ||
| 1136 | early_param("alloc_mptable", parse_alloc_mptable_opt); | ||
| 944 | 1137 | ||
| 945 | intsrc.mpc_type = MP_INTSRC; | 1138 | void __init early_reserve_e820_mpc_new(void) |
| 946 | intsrc.mpc_irqflag = 0; /* Conforming */ | 1139 | { |
| 947 | intsrc.mpc_srcbus = MP_ISA_BUS; | 1140 | if (enable_update_mptable && alloc_mptable) { |
| 948 | #ifdef CONFIG_X86_IO_APIC | 1141 | u64 startt = 0; |
| 949 | intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; | 1142 | #ifdef CONFIG_X86_TRAMPOLINE |
| 1143 | startt = TRAMPOLINE_BASE; | ||
| 950 | #endif | 1144 | #endif |
| 951 | /* | 1145 | mpc_new_phys = early_reserve_e820(startt, mpc_new_length, 4); |
| 952 | * Use the default configuration for the IRQs 0-15. Unless | ||
| 953 | * overridden by (MADT) interrupt source override entries. | ||
| 954 | */ | ||
| 955 | for (i = 0; i < 16; i++) { | ||
| 956 | int idx; | ||
| 957 | |||
| 958 | for (idx = 0; idx < mp_irq_entries; idx++) { | ||
| 959 | struct mpc_config_intsrc *irq = mp_irqs + idx; | ||
| 960 | |||
| 961 | /* Do we already have a mapping for this ISA IRQ? */ | ||
| 962 | if (irq->mpc_srcbus == MP_ISA_BUS | ||
| 963 | && irq->mpc_srcbusirq == i) | ||
| 964 | break; | ||
| 965 | |||
| 966 | /* Do we already have a mapping for this IOAPIC pin */ | ||
| 967 | if ((irq->mpc_dstapic == intsrc.mpc_dstapic) && | ||
| 968 | (irq->mpc_dstirq == i)) | ||
| 969 | break; | ||
| 970 | } | ||
| 971 | |||
| 972 | if (idx != mp_irq_entries) { | ||
| 973 | printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); | ||
| 974 | continue; /* IRQ already used */ | ||
| 975 | } | ||
| 976 | |||
| 977 | intsrc.mpc_irqtype = mp_INT; | ||
| 978 | intsrc.mpc_srcbusirq = i; /* Identity mapped */ | ||
| 979 | intsrc.mpc_dstirq = i; | ||
| 980 | |||
| 981 | MP_intsrc_info(&intsrc); | ||
| 982 | } | 1146 | } |
| 983 | } | 1147 | } |
| 984 | 1148 | ||
| 985 | int mp_register_gsi(u32 gsi, int triggering, int polarity) | 1149 | static int __init update_mp_table(void) |
| 986 | { | 1150 | { |
| 987 | int ioapic; | 1151 | char str[16]; |
| 988 | int ioapic_pin; | 1152 | char oem[10]; |
| 989 | #ifdef CONFIG_X86_32 | 1153 | struct intel_mp_floating *mpf; |
| 990 | #define MAX_GSI_NUM 4096 | 1154 | struct mp_config_table *mpc; |
| 991 | #define IRQ_COMPRESSION_START 64 | 1155 | struct mp_config_table *mpc_new; |
| 1156 | |||
| 1157 | if (!enable_update_mptable) | ||
| 1158 | return 0; | ||
| 1159 | |||
| 1160 | mpf = mpf_found; | ||
| 1161 | if (!mpf) | ||
| 1162 | return 0; | ||
| 992 | 1163 | ||
| 993 | static int pci_irq = IRQ_COMPRESSION_START; | ||
| 994 | /* | 1164 | /* |
| 995 | * Mapping between Global System Interrupts, which | 1165 | * Now see if we need to go further. |
| 996 | * represent all possible interrupts, and IRQs | ||
| 997 | * assigned to actual devices. | ||
| 998 | */ | 1166 | */ |
| 999 | static int gsi_to_irq[MAX_GSI_NUM]; | 1167 | if (mpf->mpf_feature1 != 0) |
| 1000 | #else | 1168 | return 0; |
| 1001 | |||
| 1002 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) | ||
| 1003 | return gsi; | ||
| 1004 | #endif | ||
| 1005 | 1169 | ||
| 1006 | /* Don't set up the ACPI SCI because it's already set up */ | 1170 | if (!mpf->mpf_physptr) |
| 1007 | if (acpi_gbl_FADT.sci_interrupt == gsi) | 1171 | return 0; |
| 1008 | return gsi; | ||
| 1009 | 1172 | ||
| 1010 | ioapic = mp_find_ioapic(gsi); | 1173 | mpc = phys_to_virt(mpf->mpf_physptr); |
| 1011 | if (ioapic < 0) { | ||
| 1012 | printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); | ||
| 1013 | return gsi; | ||
| 1014 | } | ||
| 1015 | 1174 | ||
| 1016 | ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; | 1175 | if (!smp_check_mpc(mpc, oem, str)) |
| 1176 | return 0; | ||
| 1017 | 1177 | ||
| 1018 | #ifdef CONFIG_X86_32 | 1178 | printk(KERN_INFO "mpf: %lx\n", virt_to_phys(mpf)); |
| 1019 | if (ioapic_renumber_irq) | 1179 | printk(KERN_INFO "mpf_physptr: %x\n", mpf->mpf_physptr); |
| 1020 | gsi = ioapic_renumber_irq(ioapic, gsi); | ||
| 1021 | #endif | ||
| 1022 | 1180 | ||
| 1023 | /* | 1181 | if (mpc_new_phys && mpc->mpc_length > mpc_new_length) { |
| 1024 | * Avoid pin reprogramming. PRTs typically include entries | 1182 | mpc_new_phys = 0; |
| 1025 | * with redundant pin->gsi mappings (but unique PCI devices); | 1183 | printk(KERN_INFO "mpc_new_length is %ld, please use alloc_mptable=8k\n", |
| 1026 | * we only program the IOAPIC on the first. | 1184 | mpc_new_length); |
| 1027 | */ | ||
| 1028 | if (ioapic_pin > MP_MAX_IOAPIC_PIN) { | ||
| 1029 | printk(KERN_ERR "Invalid reference to IOAPIC pin " | ||
| 1030 | "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, | ||
| 1031 | ioapic_pin); | ||
| 1032 | return gsi; | ||
| 1033 | } | 1185 | } |
| 1034 | if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) { | 1186 | |
| 1035 | Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n", | 1187 | if (!mpc_new_phys) { |
| 1036 | mp_ioapic_routing[ioapic].apic_id, ioapic_pin); | 1188 | unsigned char old, new; |
| 1037 | #ifdef CONFIG_X86_32 | 1189 | /* check if we can change the postion */ |
| 1038 | return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]); | 1190 | mpc->mpc_checksum = 0; |
| 1039 | #else | 1191 | old = mpf_checksum((unsigned char *)mpc, mpc->mpc_length); |
| 1040 | return gsi; | 1192 | mpc->mpc_checksum = 0xff; |
| 1041 | #endif | 1193 | new = mpf_checksum((unsigned char *)mpc, mpc->mpc_length); |
| 1194 | if (old == new) { | ||
| 1195 | printk(KERN_INFO "mpc is readonly, please try alloc_mptable instead\n"); | ||
| 1196 | return 0; | ||
| 1197 | } | ||
| 1198 | printk(KERN_INFO "use in-positon replacing\n"); | ||
| 1199 | } else { | ||
| 1200 | mpf->mpf_physptr = mpc_new_phys; | ||
| 1201 | mpc_new = phys_to_virt(mpc_new_phys); | ||
| 1202 | memcpy(mpc_new, mpc, mpc->mpc_length); | ||
| 1203 | mpc = mpc_new; | ||
| 1204 | /* check if we can modify that */ | ||
| 1205 | if (mpc_new_phys - mpf->mpf_physptr) { | ||
| 1206 | struct intel_mp_floating *mpf_new; | ||
| 1207 | /* steal 16 bytes from [0, 1k) */ | ||
| 1208 | printk(KERN_INFO "mpf new: %x\n", 0x400 - 16); | ||
| 1209 | mpf_new = phys_to_virt(0x400 - 16); | ||
| 1210 | memcpy(mpf_new, mpf, 16); | ||
| 1211 | mpf = mpf_new; | ||
| 1212 | mpf->mpf_physptr = mpc_new_phys; | ||
| 1213 | } | ||
| 1214 | mpf->mpf_checksum = 0; | ||
| 1215 | mpf->mpf_checksum -= mpf_checksum((unsigned char *)mpf, 16); | ||
| 1216 | printk(KERN_INFO "mpf_physptr new: %x\n", mpf->mpf_physptr); | ||
| 1042 | } | 1217 | } |
| 1043 | 1218 | ||
| 1044 | set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed); | ||
| 1045 | #ifdef CONFIG_X86_32 | ||
| 1046 | /* | 1219 | /* |
| 1047 | * For GSI >= 64, use IRQ compression | 1220 | * only replace the one with mp_INT and |
| 1221 | * MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, | ||
| 1222 | * already in mp_irqs , stored by ... and mp_config_acpi_gsi, | ||
| 1223 | * may need pci=routeirq for all coverage | ||
| 1048 | */ | 1224 | */ |
| 1049 | if ((gsi >= IRQ_COMPRESSION_START) | 1225 | replace_intsrc_all(mpc, mpc_new_phys, mpc_new_length); |
| 1050 | && (triggering == ACPI_LEVEL_SENSITIVE)) { | 1226 | |
| 1051 | /* | 1227 | return 0; |
| 1052 | * For PCI devices assign IRQs in order, avoiding gaps | ||
| 1053 | * due to unused I/O APIC pins. | ||
| 1054 | */ | ||
| 1055 | int irq = gsi; | ||
| 1056 | if (gsi < MAX_GSI_NUM) { | ||
| 1057 | /* | ||
| 1058 | * Retain the VIA chipset work-around (gsi > 15), but | ||
| 1059 | * avoid a problem where the 8254 timer (IRQ0) is setup | ||
| 1060 | * via an override (so it's not on pin 0 of the ioapic), | ||
| 1061 | * and at the same time, the pin 0 interrupt is a PCI | ||
| 1062 | * type. The gsi > 15 test could cause these two pins | ||
| 1063 | * to be shared as IRQ0, and they are not shareable. | ||
| 1064 | * So test for this condition, and if necessary, avoid | ||
| 1065 | * the pin collision. | ||
| 1066 | */ | ||
| 1067 | gsi = pci_irq++; | ||
| 1068 | /* | ||
| 1069 | * Don't assign IRQ used by ACPI SCI | ||
| 1070 | */ | ||
| 1071 | if (gsi == acpi_gbl_FADT.sci_interrupt) | ||
| 1072 | gsi = pci_irq++; | ||
| 1073 | gsi_to_irq[irq] = gsi; | ||
| 1074 | } else { | ||
| 1075 | printk(KERN_ERR "GSI %u is too high\n", gsi); | ||
| 1076 | return gsi; | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | #endif | ||
| 1080 | io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, | ||
| 1081 | triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, | ||
| 1082 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | ||
| 1083 | return gsi; | ||
| 1084 | } | 1228 | } |
| 1085 | 1229 | ||
| 1086 | #endif /* CONFIG_X86_IO_APIC */ | 1230 | late_initcall(update_mp_table); |
| 1087 | #endif /* CONFIG_ACPI */ | ||
diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c index e65281b1634b..f0f1de1c4a1d 100644 --- a/arch/x86/kernel/numaq_32.c +++ b/arch/x86/kernel/numaq_32.c | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | #include <asm/numaq.h> | 31 | #include <asm/numaq.h> |
| 32 | #include <asm/topology.h> | 32 | #include <asm/topology.h> |
| 33 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
| 34 | #include <asm/mpspec.h> | ||
| 35 | #include <asm/e820.h> | ||
| 34 | 36 | ||
| 35 | #define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) | 37 | #define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) |
| 36 | 38 | ||
| @@ -58,6 +60,8 @@ static void __init smp_dump_qct(void) | |||
| 58 | node_end_pfn[node] = MB_TO_PAGES( | 60 | node_end_pfn[node] = MB_TO_PAGES( |
| 59 | eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); | 61 | eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); |
| 60 | 62 | ||
| 63 | e820_register_active_regions(node, node_start_pfn[node], | ||
| 64 | node_end_pfn[node]); | ||
| 61 | memory_present(node, | 65 | memory_present(node, |
| 62 | node_start_pfn[node], node_end_pfn[node]); | 66 | node_start_pfn[node], node_end_pfn[node]); |
| 63 | node_remap_size[node] = node_memmap_size_bytes(node, | 67 | node_remap_size[node] = node_memmap_size_bytes(node, |
| @@ -67,13 +71,24 @@ static void __init smp_dump_qct(void) | |||
| 67 | } | 71 | } |
| 68 | } | 72 | } |
| 69 | 73 | ||
| 70 | /* | 74 | static __init void early_check_numaq(void) |
| 71 | * Unlike Summit, we don't really care to let the NUMA-Q | 75 | { |
| 72 | * fall back to flat mode. Don't compile for NUMA-Q | 76 | /* |
| 73 | * unless you really need it! | 77 | * Find possible boot-time SMP configuration: |
| 74 | */ | 78 | */ |
| 79 | early_find_smp_config(); | ||
| 80 | /* | ||
| 81 | * get boot-time SMP configuration: | ||
| 82 | */ | ||
| 83 | if (smp_found_config) | ||
| 84 | early_get_smp_config(); | ||
| 85 | } | ||
| 86 | |||
| 75 | int __init get_memcfg_numaq(void) | 87 | int __init get_memcfg_numaq(void) |
| 76 | { | 88 | { |
| 89 | early_check_numaq(); | ||
| 90 | if (!found_numaq) | ||
| 91 | return 0; | ||
| 77 | smp_dump_qct(); | 92 | smp_dump_qct(); |
| 78 | return 1; | 93 | return 1; |
| 79 | } | 94 | } |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 6f80b852a196..5b0de38cde48 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
| @@ -17,6 +17,7 @@ unsigned int num_processors; | |||
| 17 | unsigned disabled_cpus __cpuinitdata; | 17 | unsigned disabled_cpus __cpuinitdata; |
| 18 | /* Processor that is doing the boot up */ | 18 | /* Processor that is doing the boot up */ |
| 19 | unsigned int boot_cpu_physical_apicid = -1U; | 19 | unsigned int boot_cpu_physical_apicid = -1U; |
| 20 | unsigned int max_physical_apicid; | ||
| 20 | EXPORT_SYMBOL(boot_cpu_physical_apicid); | 21 | EXPORT_SYMBOL(boot_cpu_physical_apicid); |
| 21 | 22 | ||
| 22 | DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID; | 23 | DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID; |
| @@ -137,3 +138,28 @@ void __init setup_per_cpu_areas(void) | |||
| 137 | } | 138 | } |
| 138 | 139 | ||
| 139 | #endif | 140 | #endif |
| 141 | |||
| 142 | void __init parse_setup_data(void) | ||
| 143 | { | ||
| 144 | struct setup_data *data; | ||
| 145 | u64 pa_data; | ||
| 146 | |||
| 147 | if (boot_params.hdr.version < 0x0209) | ||
| 148 | return; | ||
| 149 | pa_data = boot_params.hdr.setup_data; | ||
| 150 | while (pa_data) { | ||
| 151 | data = early_ioremap(pa_data, PAGE_SIZE); | ||
| 152 | switch (data->type) { | ||
| 153 | case SETUP_E820_EXT: | ||
| 154 | parse_e820_ext(data, pa_data); | ||
| 155 | break; | ||
| 156 | default: | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | #ifndef CONFIG_DEBUG_BOOT_PARAMS | ||
| 160 | free_early(pa_data, pa_data+sizeof(*data)+data->len); | ||
| 161 | #endif | ||
| 162 | pa_data = data->next; | ||
| 163 | early_iounmap(data, PAGE_SIZE); | ||
| 164 | } | ||
| 165 | } | ||
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 5a2f8e063887..7e06ecd83174 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | #include <asm/setup.h> | 59 | #include <asm/setup.h> |
| 60 | #include <asm/arch_hooks.h> | 60 | #include <asm/arch_hooks.h> |
| 61 | #include <asm/sections.h> | 61 | #include <asm/sections.h> |
| 62 | #include <asm/dmi.h> | ||
| 62 | #include <asm/io_apic.h> | 63 | #include <asm/io_apic.h> |
| 63 | #include <asm/ist.h> | 64 | #include <asm/ist.h> |
| 64 | #include <asm/io.h> | 65 | #include <asm/io.h> |
| @@ -67,10 +68,13 @@ | |||
| 67 | #include <asm/bios_ebda.h> | 68 | #include <asm/bios_ebda.h> |
| 68 | #include <asm/cacheflush.h> | 69 | #include <asm/cacheflush.h> |
| 69 | #include <asm/processor.h> | 70 | #include <asm/processor.h> |
| 71 | #include <asm/efi.h> | ||
| 72 | #include <asm/bugs.h> | ||
| 70 | 73 | ||
| 71 | /* This value is set up by the early boot code to point to the value | 74 | /* This value is set up by the early boot code to point to the value |
| 72 | immediately after the boot time page tables. It contains a *physical* | 75 | immediately after the boot time page tables. It contains a *physical* |
| 73 | address, and must not be in the .bss segment! */ | 76 | address, and must not be in the .bss segment! */ |
| 77 | unsigned long init_pg_tables_start __initdata = ~0UL; | ||
| 74 | unsigned long init_pg_tables_end __initdata = ~0UL; | 78 | unsigned long init_pg_tables_end __initdata = ~0UL; |
| 75 | 79 | ||
| 76 | /* | 80 | /* |
| @@ -182,6 +186,12 @@ int bootloader_type; | |||
| 182 | static unsigned int highmem_pages = -1; | 186 | static unsigned int highmem_pages = -1; |
| 183 | 187 | ||
| 184 | /* | 188 | /* |
| 189 | * Early DMI memory | ||
| 190 | */ | ||
| 191 | int dmi_alloc_index; | ||
| 192 | char dmi_alloc_data[DMI_MAX_DATA]; | ||
| 193 | |||
| 194 | /* | ||
| 185 | * Setup options | 195 | * Setup options |
| 186 | */ | 196 | */ |
| 187 | struct screen_info screen_info; | 197 | struct screen_info screen_info; |
| @@ -237,42 +247,6 @@ static inline void copy_edd(void) | |||
| 237 | } | 247 | } |
| 238 | #endif | 248 | #endif |
| 239 | 249 | ||
| 240 | int __initdata user_defined_memmap; | ||
| 241 | |||
| 242 | /* | ||
| 243 | * "mem=nopentium" disables the 4MB page tables. | ||
| 244 | * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM | ||
| 245 | * to <mem>, overriding the bios size. | ||
| 246 | * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from | ||
| 247 | * <start> to <start>+<mem>, overriding the bios size. | ||
| 248 | * | ||
| 249 | * HPA tells me bootloaders need to parse mem=, so no new | ||
| 250 | * option should be mem= [also see Documentation/i386/boot.txt] | ||
| 251 | */ | ||
| 252 | static int __init parse_mem(char *arg) | ||
| 253 | { | ||
| 254 | if (!arg) | ||
| 255 | return -EINVAL; | ||
| 256 | |||
| 257 | if (strcmp(arg, "nopentium") == 0) { | ||
| 258 | setup_clear_cpu_cap(X86_FEATURE_PSE); | ||
| 259 | } else { | ||
| 260 | /* If the user specifies memory size, we | ||
| 261 | * limit the BIOS-provided memory map to | ||
| 262 | * that size. exactmap can be used to specify | ||
| 263 | * the exact map. mem=number can be used to | ||
| 264 | * trim the existing memory map. | ||
| 265 | */ | ||
| 266 | unsigned long long mem_size; | ||
| 267 | |||
| 268 | mem_size = memparse(arg, &arg); | ||
| 269 | limit_regions(mem_size); | ||
| 270 | user_defined_memmap = 1; | ||
| 271 | } | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | early_param("mem", parse_mem); | ||
| 275 | |||
| 276 | #ifdef CONFIG_PROC_VMCORE | 250 | #ifdef CONFIG_PROC_VMCORE |
| 277 | /* elfcorehdr= specifies the location of elf core header | 251 | /* elfcorehdr= specifies the location of elf core header |
| 278 | * stored by the crashed kernel. | 252 | * stored by the crashed kernel. |
| @@ -395,56 +369,6 @@ unsigned long __init find_max_low_pfn(void) | |||
| 395 | return max_low_pfn; | 369 | return max_low_pfn; |
| 396 | } | 370 | } |
| 397 | 371 | ||
| 398 | #define BIOS_LOWMEM_KILOBYTES 0x413 | ||
| 399 | |||
| 400 | /* | ||
| 401 | * The BIOS places the EBDA/XBDA at the top of conventional | ||
| 402 | * memory, and usually decreases the reported amount of | ||
| 403 | * conventional memory (int 0x12) too. This also contains a | ||
| 404 | * workaround for Dell systems that neglect to reserve EBDA. | ||
| 405 | * The same workaround also avoids a problem with the AMD768MPX | ||
| 406 | * chipset: reserve a page before VGA to prevent PCI prefetch | ||
| 407 | * into it (errata #56). Usually the page is reserved anyways, | ||
| 408 | * unless you have no PS/2 mouse plugged in. | ||
| 409 | */ | ||
| 410 | static void __init reserve_ebda_region(void) | ||
| 411 | { | ||
| 412 | unsigned int lowmem, ebda_addr; | ||
| 413 | |||
| 414 | /* To determine the position of the EBDA and the */ | ||
| 415 | /* end of conventional memory, we need to look at */ | ||
| 416 | /* the BIOS data area. In a paravirtual environment */ | ||
| 417 | /* that area is absent. We'll just have to assume */ | ||
| 418 | /* that the paravirt case can handle memory setup */ | ||
| 419 | /* correctly, without our help. */ | ||
| 420 | if (paravirt_enabled()) | ||
| 421 | return; | ||
| 422 | |||
| 423 | /* end of low (conventional) memory */ | ||
| 424 | lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); | ||
| 425 | lowmem <<= 10; | ||
| 426 | |||
| 427 | /* start of EBDA area */ | ||
| 428 | ebda_addr = get_bios_ebda(); | ||
| 429 | |||
| 430 | /* Fixup: bios puts an EBDA in the top 64K segment */ | ||
| 431 | /* of conventional memory, but does not adjust lowmem. */ | ||
| 432 | if ((lowmem - ebda_addr) <= 0x10000) | ||
| 433 | lowmem = ebda_addr; | ||
| 434 | |||
| 435 | /* Fixup: bios does not report an EBDA at all. */ | ||
| 436 | /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ | ||
| 437 | if ((ebda_addr == 0) && (lowmem >= 0x9f000)) | ||
| 438 | lowmem = 0x9f000; | ||
| 439 | |||
| 440 | /* Paranoia: should never happen, but... */ | ||
| 441 | if ((lowmem == 0) || (lowmem >= 0x100000)) | ||
| 442 | lowmem = 0x9f000; | ||
| 443 | |||
| 444 | /* reserve all memory between lowmem and the 1MB mark */ | ||
| 445 | reserve_bootmem(lowmem, 0x100000 - lowmem, BOOTMEM_DEFAULT); | ||
| 446 | } | ||
| 447 | |||
| 448 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 372 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
| 449 | static void __init setup_bootmem_allocator(void); | 373 | static void __init setup_bootmem_allocator(void); |
| 450 | static unsigned long __init setup_memory(void) | 374 | static unsigned long __init setup_memory(void) |
| @@ -462,11 +386,13 @@ static unsigned long __init setup_memory(void) | |||
| 462 | if (max_pfn > max_low_pfn) { | 386 | if (max_pfn > max_low_pfn) { |
| 463 | highstart_pfn = max_low_pfn; | 387 | highstart_pfn = max_low_pfn; |
| 464 | } | 388 | } |
| 389 | memory_present(0, 0, highend_pfn); | ||
| 465 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", | 390 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", |
| 466 | pages_to_mb(highend_pfn - highstart_pfn)); | 391 | pages_to_mb(highend_pfn - highstart_pfn)); |
| 467 | num_physpages = highend_pfn; | 392 | num_physpages = highend_pfn; |
| 468 | high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; | 393 | high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; |
| 469 | #else | 394 | #else |
| 395 | memory_present(0, 0, max_low_pfn); | ||
| 470 | num_physpages = max_low_pfn; | 396 | num_physpages = max_low_pfn; |
| 471 | high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; | 397 | high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; |
| 472 | #endif | 398 | #endif |
| @@ -488,11 +414,12 @@ static void __init zone_sizes_init(void) | |||
| 488 | max_zone_pfns[ZONE_DMA] = | 414 | max_zone_pfns[ZONE_DMA] = |
| 489 | virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; | 415 | virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; |
| 490 | max_zone_pfns[ZONE_NORMAL] = max_low_pfn; | 416 | max_zone_pfns[ZONE_NORMAL] = max_low_pfn; |
| 417 | remove_all_active_ranges(); | ||
| 491 | #ifdef CONFIG_HIGHMEM | 418 | #ifdef CONFIG_HIGHMEM |
| 492 | max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; | 419 | max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; |
| 493 | add_active_range(0, 0, highend_pfn); | 420 | e820_register_active_regions(0, 0, highend_pfn); |
| 494 | #else | 421 | #else |
| 495 | add_active_range(0, 0, max_low_pfn); | 422 | e820_register_active_regions(0, 0, max_low_pfn); |
| 496 | #endif | 423 | #endif |
| 497 | 424 | ||
| 498 | free_area_init_nodes(max_zone_pfns); | 425 | free_area_init_nodes(max_zone_pfns); |
| @@ -526,25 +453,28 @@ static void __init reserve_crashkernel(void) | |||
| 526 | ret = parse_crashkernel(boot_command_line, total_mem, | 453 | ret = parse_crashkernel(boot_command_line, total_mem, |
| 527 | &crash_size, &crash_base); | 454 | &crash_size, &crash_base); |
| 528 | if (ret == 0 && crash_size > 0) { | 455 | if (ret == 0 && crash_size > 0) { |
| 529 | if (crash_base > 0) { | 456 | if (crash_base <= 0) { |
| 530 | printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " | ||
| 531 | "for crashkernel (System RAM: %ldMB)\n", | ||
| 532 | (unsigned long)(crash_size >> 20), | ||
| 533 | (unsigned long)(crash_base >> 20), | ||
| 534 | (unsigned long)(total_mem >> 20)); | ||
| 535 | |||
| 536 | if (reserve_bootmem(crash_base, crash_size, | ||
| 537 | BOOTMEM_EXCLUSIVE) < 0) { | ||
| 538 | printk(KERN_INFO "crashkernel reservation " | ||
| 539 | "failed - memory is in use\n"); | ||
| 540 | return; | ||
| 541 | } | ||
| 542 | |||
| 543 | crashk_res.start = crash_base; | ||
| 544 | crashk_res.end = crash_base + crash_size - 1; | ||
| 545 | } else | ||
| 546 | printk(KERN_INFO "crashkernel reservation failed - " | 457 | printk(KERN_INFO "crashkernel reservation failed - " |
| 547 | "you have to specify a base address\n"); | 458 | "you have to specify a base address\n"); |
| 459 | return; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (reserve_bootmem_generic(crash_base, crash_size, | ||
| 463 | BOOTMEM_EXCLUSIVE) < 0) { | ||
| 464 | printk(KERN_INFO "crashkernel reservation failed - " | ||
| 465 | "memory is in use\n"); | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | |||
| 469 | printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " | ||
| 470 | "for crashkernel (System RAM: %ldMB)\n", | ||
| 471 | (unsigned long)(crash_size >> 20), | ||
| 472 | (unsigned long)(crash_base >> 20), | ||
| 473 | (unsigned long)(total_mem >> 20)); | ||
| 474 | |||
| 475 | crashk_res.start = crash_base; | ||
| 476 | crashk_res.end = crash_base + crash_size - 1; | ||
| 477 | insert_resource(&iomem_resource, &crashk_res); | ||
| 548 | } | 478 | } |
| 549 | } | 479 | } |
| 550 | #else | 480 | #else |
| @@ -558,44 +488,57 @@ static bool do_relocate_initrd = false; | |||
| 558 | 488 | ||
| 559 | static void __init reserve_initrd(void) | 489 | static void __init reserve_initrd(void) |
| 560 | { | 490 | { |
| 561 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | 491 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; |
| 562 | unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; | 492 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; |
| 563 | unsigned long ramdisk_end = ramdisk_image + ramdisk_size; | 493 | u64 ramdisk_end = ramdisk_image + ramdisk_size; |
| 564 | unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; | 494 | u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT; |
| 565 | unsigned long ramdisk_here; | 495 | u64 ramdisk_here; |
| 566 | |||
| 567 | initrd_start = 0; | ||
| 568 | 496 | ||
| 569 | if (!boot_params.hdr.type_of_loader || | 497 | if (!boot_params.hdr.type_of_loader || |
| 570 | !ramdisk_image || !ramdisk_size) | 498 | !ramdisk_image || !ramdisk_size) |
| 571 | return; /* No initrd provided by bootloader */ | 499 | return; /* No initrd provided by bootloader */ |
| 572 | 500 | ||
| 573 | if (ramdisk_end < ramdisk_image) { | 501 | initrd_start = 0; |
| 574 | printk(KERN_ERR "initrd wraps around end of memory, " | 502 | |
| 575 | "disabling initrd\n"); | ||
| 576 | return; | ||
| 577 | } | ||
| 578 | if (ramdisk_size >= end_of_lowmem/2) { | 503 | if (ramdisk_size >= end_of_lowmem/2) { |
| 504 | free_early(ramdisk_image, ramdisk_end); | ||
| 579 | printk(KERN_ERR "initrd too large to handle, " | 505 | printk(KERN_ERR "initrd too large to handle, " |
| 580 | "disabling initrd\n"); | 506 | "disabling initrd\n"); |
| 581 | return; | 507 | return; |
| 582 | } | 508 | } |
| 509 | |||
| 510 | printk(KERN_INFO "old RAMDISK: %08llx - %08llx\n", ramdisk_image, | ||
| 511 | ramdisk_end); | ||
| 512 | |||
| 513 | |||
| 583 | if (ramdisk_end <= end_of_lowmem) { | 514 | if (ramdisk_end <= end_of_lowmem) { |
| 584 | /* All in lowmem, easy case */ | 515 | /* All in lowmem, easy case */ |
| 585 | reserve_bootmem(ramdisk_image, ramdisk_size, BOOTMEM_DEFAULT); | 516 | /* |
| 517 | * don't need to reserve again, already reserved early | ||
| 518 | * in i386_start_kernel | ||
| 519 | */ | ||
| 586 | initrd_start = ramdisk_image + PAGE_OFFSET; | 520 | initrd_start = ramdisk_image + PAGE_OFFSET; |
| 587 | initrd_end = initrd_start+ramdisk_size; | 521 | initrd_end = initrd_start+ramdisk_size; |
| 588 | return; | 522 | return; |
| 589 | } | 523 | } |
| 590 | 524 | ||
| 591 | /* We need to move the initrd down into lowmem */ | 525 | /* We need to move the initrd down into lowmem */ |
| 592 | ramdisk_here = (end_of_lowmem - ramdisk_size) & PAGE_MASK; | 526 | ramdisk_here = find_e820_area(min_low_pfn<<PAGE_SHIFT, |
| 527 | end_of_lowmem, ramdisk_size, | ||
| 528 | PAGE_SIZE); | ||
| 529 | |||
| 530 | if (ramdisk_here == -1ULL) | ||
| 531 | panic("Cannot find place for new RAMDISK of size %lld\n", | ||
| 532 | ramdisk_size); | ||
| 593 | 533 | ||
| 594 | /* Note: this includes all the lowmem currently occupied by | 534 | /* Note: this includes all the lowmem currently occupied by |
| 595 | the initrd, we rely on that fact to keep the data intact. */ | 535 | the initrd, we rely on that fact to keep the data intact. */ |
| 596 | reserve_bootmem(ramdisk_here, ramdisk_size, BOOTMEM_DEFAULT); | 536 | reserve_early(ramdisk_here, ramdisk_here + ramdisk_size, |
| 537 | "NEW RAMDISK"); | ||
| 597 | initrd_start = ramdisk_here + PAGE_OFFSET; | 538 | initrd_start = ramdisk_here + PAGE_OFFSET; |
| 598 | initrd_end = initrd_start + ramdisk_size; | 539 | initrd_end = initrd_start + ramdisk_size; |
| 540 | printk(KERN_INFO "Allocated new RAMDISK: %08llx - %08llx\n", | ||
| 541 | ramdisk_here, ramdisk_here + ramdisk_size); | ||
| 599 | 542 | ||
| 600 | do_relocate_initrd = true; | 543 | do_relocate_initrd = true; |
| 601 | } | 544 | } |
| @@ -604,10 +547,10 @@ static void __init reserve_initrd(void) | |||
| 604 | 547 | ||
| 605 | static void __init relocate_initrd(void) | 548 | static void __init relocate_initrd(void) |
| 606 | { | 549 | { |
| 607 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | 550 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; |
| 608 | unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; | 551 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; |
| 609 | unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; | 552 | u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT; |
| 610 | unsigned long ramdisk_here; | 553 | u64 ramdisk_here; |
| 611 | unsigned long slop, clen, mapaddr; | 554 | unsigned long slop, clen, mapaddr; |
| 612 | char *p, *q; | 555 | char *p, *q; |
| 613 | 556 | ||
| @@ -624,6 +567,10 @@ static void __init relocate_initrd(void) | |||
| 624 | p = (char *)__va(ramdisk_image); | 567 | p = (char *)__va(ramdisk_image); |
| 625 | memcpy(q, p, clen); | 568 | memcpy(q, p, clen); |
| 626 | q += clen; | 569 | q += clen; |
| 570 | /* need to free these low pages...*/ | ||
| 571 | printk(KERN_INFO "Freeing old partial RAMDISK %08llx-%08llx\n", | ||
| 572 | ramdisk_image, ramdisk_image + clen - 1); | ||
| 573 | free_bootmem(ramdisk_image, clen); | ||
| 627 | ramdisk_image += clen; | 574 | ramdisk_image += clen; |
| 628 | ramdisk_size -= clen; | 575 | ramdisk_size -= clen; |
| 629 | } | 576 | } |
| @@ -642,66 +589,47 @@ static void __init relocate_initrd(void) | |||
| 642 | ramdisk_image += clen; | 589 | ramdisk_image += clen; |
| 643 | ramdisk_size -= clen; | 590 | ramdisk_size -= clen; |
| 644 | } | 591 | } |
| 592 | /* high pages is not converted by early_res_to_bootmem */ | ||
| 593 | ramdisk_image = boot_params.hdr.ramdisk_image; | ||
| 594 | ramdisk_size = boot_params.hdr.ramdisk_size; | ||
| 595 | printk(KERN_INFO "Copied RAMDISK from %016llx - %016llx to %08llx - %08llx\n", | ||
| 596 | ramdisk_image, ramdisk_image + ramdisk_size - 1, | ||
| 597 | ramdisk_here, ramdisk_here + ramdisk_size - 1); | ||
| 598 | |||
| 599 | /* need to free that, otherwise init highmem will reserve it again */ | ||
| 600 | free_early(ramdisk_image, ramdisk_image+ramdisk_size); | ||
| 645 | } | 601 | } |
| 646 | 602 | ||
| 647 | #endif /* CONFIG_BLK_DEV_INITRD */ | 603 | #endif /* CONFIG_BLK_DEV_INITRD */ |
| 648 | 604 | ||
| 649 | void __init setup_bootmem_allocator(void) | 605 | void __init setup_bootmem_allocator(void) |
| 650 | { | 606 | { |
| 651 | unsigned long bootmap_size; | 607 | int i; |
| 608 | unsigned long bootmap_size, bootmap; | ||
| 652 | /* | 609 | /* |
| 653 | * Initialize the boot-time allocator (with low memory only): | 610 | * Initialize the boot-time allocator (with low memory only): |
| 654 | */ | 611 | */ |
| 655 | bootmap_size = init_bootmem(min_low_pfn, max_low_pfn); | 612 | bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT; |
| 656 | 613 | bootmap = find_e820_area(min_low_pfn<<PAGE_SHIFT, | |
| 657 | register_bootmem_low_pages(max_low_pfn); | 614 | max_pfn_mapped<<PAGE_SHIFT, bootmap_size, |
| 658 | 615 | PAGE_SIZE); | |
| 659 | /* | 616 | if (bootmap == -1L) |
| 660 | * Reserve the bootmem bitmap itself as well. We do this in two | 617 | panic("Cannot find bootmem map of size %ld\n", bootmap_size); |
| 661 | * steps (first step was init_bootmem()) because this catches | 618 | reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP"); |
| 662 | * the (very unlikely) case of us accidentally initializing the | ||
| 663 | * bootmem allocator with an invalid RAM area. | ||
| 664 | */ | ||
| 665 | reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) + | ||
| 666 | bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text), | ||
| 667 | BOOTMEM_DEFAULT); | ||
| 668 | |||
| 669 | /* | ||
| 670 | * reserve physical page 0 - it's a special BIOS page on many boxes, | ||
| 671 | * enabling clean reboots, SMP operation, laptop functions. | ||
| 672 | */ | ||
| 673 | reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT); | ||
| 674 | |||
| 675 | /* reserve EBDA region */ | ||
| 676 | reserve_ebda_region(); | ||
| 677 | |||
| 678 | #ifdef CONFIG_SMP | ||
| 679 | /* | ||
| 680 | * But first pinch a few for the stack/trampoline stuff | ||
| 681 | * FIXME: Don't need the extra page at 4K, but need to fix | ||
| 682 | * trampoline before removing it. (see the GDT stuff) | ||
| 683 | */ | ||
| 684 | reserve_bootmem(PAGE_SIZE, PAGE_SIZE, BOOTMEM_DEFAULT); | ||
| 685 | #endif | ||
| 686 | #ifdef CONFIG_ACPI_SLEEP | ||
| 687 | /* | ||
| 688 | * Reserve low memory region for sleep support. | ||
| 689 | */ | ||
| 690 | acpi_reserve_bootmem(); | ||
| 691 | #endif | ||
| 692 | #ifdef CONFIG_X86_FIND_SMP_CONFIG | ||
| 693 | /* | ||
| 694 | * Find and reserve possible boot-time SMP configuration: | ||
| 695 | */ | ||
| 696 | find_smp_config(); | ||
| 697 | #endif | ||
| 698 | #ifdef CONFIG_BLK_DEV_INITRD | 619 | #ifdef CONFIG_BLK_DEV_INITRD |
| 699 | reserve_initrd(); | 620 | reserve_initrd(); |
| 700 | #endif | 621 | #endif |
| 701 | numa_kva_reserve(); | 622 | bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, max_low_pfn); |
| 702 | reserve_crashkernel(); | 623 | printk(KERN_INFO " mapped low ram: 0 - %08lx\n", |
| 624 | max_pfn_mapped<<PAGE_SHIFT); | ||
| 625 | printk(KERN_INFO " low ram: %08lx - %08lx\n", | ||
| 626 | min_low_pfn<<PAGE_SHIFT, max_low_pfn<<PAGE_SHIFT); | ||
| 627 | printk(KERN_INFO " bootmap %08lx - %08lx\n", | ||
| 628 | bootmap, bootmap + bootmap_size); | ||
| 629 | for_each_online_node(i) | ||
| 630 | free_bootmem_with_active_regions(i, max_low_pfn); | ||
| 631 | early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT); | ||
| 703 | 632 | ||
| 704 | reserve_ibft_region(); | ||
| 705 | } | 633 | } |
| 706 | 634 | ||
| 707 | /* | 635 | /* |
| @@ -731,12 +659,6 @@ static void set_mca_bus(int x) | |||
| 731 | static void set_mca_bus(int x) { } | 659 | static void set_mca_bus(int x) { } |
| 732 | #endif | 660 | #endif |
| 733 | 661 | ||
| 734 | /* Overridden in paravirt.c if CONFIG_PARAVIRT */ | ||
| 735 | char * __init __attribute__((weak)) memory_setup(void) | ||
| 736 | { | ||
| 737 | return machine_specific_memory_setup(); | ||
| 738 | } | ||
| 739 | |||
| 740 | #ifdef CONFIG_NUMA | 662 | #ifdef CONFIG_NUMA |
| 741 | /* | 663 | /* |
| 742 | * In the golden day, when everything among i386 and x86_64 will be | 664 | * In the golden day, when everything among i386 and x86_64 will be |
| @@ -749,6 +671,8 @@ int x86_cpu_to_node_map_init[NR_CPUS] = { | |||
| 749 | DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE; | 671 | DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE; |
| 750 | #endif | 672 | #endif |
| 751 | 673 | ||
| 674 | static void probe_roms(void); | ||
| 675 | |||
| 752 | /* | 676 | /* |
| 753 | * Determine if we were loaded by an EFI loader. If so, then we have also been | 677 | * Determine if we were loaded by an EFI loader. If so, then we have also been |
| 754 | * passed the efi memmap, systab, etc., so we should use these data structures | 678 | * passed the efi memmap, systab, etc., so we should use these data structures |
| @@ -758,17 +682,21 @@ DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE; | |||
| 758 | */ | 682 | */ |
| 759 | void __init setup_arch(char **cmdline_p) | 683 | void __init setup_arch(char **cmdline_p) |
| 760 | { | 684 | { |
| 685 | int i; | ||
| 761 | unsigned long max_low_pfn; | 686 | unsigned long max_low_pfn; |
| 762 | 687 | ||
| 763 | memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); | 688 | memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); |
| 764 | pre_setup_arch_hook(); | 689 | pre_setup_arch_hook(); |
| 765 | early_cpu_init(); | 690 | early_cpu_init(); |
| 766 | early_ioremap_init(); | 691 | early_ioremap_init(); |
| 692 | reserve_setup_data(); | ||
| 767 | 693 | ||
| 768 | #ifdef CONFIG_EFI | 694 | #ifdef CONFIG_EFI |
| 769 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, | 695 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, |
| 770 | "EL32", 4)) | 696 | "EL32", 4)) { |
| 771 | efi_enabled = 1; | 697 | efi_enabled = 1; |
| 698 | efi_reserve_early(); | ||
| 699 | } | ||
| 772 | #endif | 700 | #endif |
| 773 | 701 | ||
| 774 | ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev); | 702 | ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev); |
| @@ -792,8 +720,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 792 | #endif | 720 | #endif |
| 793 | ARCH_SETUP | 721 | ARCH_SETUP |
| 794 | 722 | ||
| 795 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | 723 | setup_memory_map(); |
| 796 | print_memory_map(memory_setup()); | ||
| 797 | 724 | ||
| 798 | copy_edd(); | 725 | copy_edd(); |
| 799 | 726 | ||
| @@ -811,12 +738,18 @@ void __init setup_arch(char **cmdline_p) | |||
| 811 | bss_resource.start = virt_to_phys(&__bss_start); | 738 | bss_resource.start = virt_to_phys(&__bss_start); |
| 812 | bss_resource.end = virt_to_phys(&__bss_stop)-1; | 739 | bss_resource.end = virt_to_phys(&__bss_stop)-1; |
| 813 | 740 | ||
| 741 | parse_setup_data(); | ||
| 742 | |||
| 814 | parse_early_param(); | 743 | parse_early_param(); |
| 815 | 744 | ||
| 816 | if (user_defined_memmap) { | 745 | finish_e820_parsing(); |
| 817 | printk(KERN_INFO "user-defined physical RAM map:\n"); | 746 | |
| 818 | print_memory_map("user"); | 747 | probe_roms(); |
| 819 | } | 748 | |
| 749 | /* after parse_early_param, so could debug it */ | ||
| 750 | insert_resource(&iomem_resource, &code_resource); | ||
| 751 | insert_resource(&iomem_resource, &data_resource); | ||
| 752 | insert_resource(&iomem_resource, &bss_resource); | ||
| 820 | 753 | ||
| 821 | strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); | 754 | strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); |
| 822 | *cmdline_p = command_line; | 755 | *cmdline_p = command_line; |
| @@ -824,14 +757,67 @@ void __init setup_arch(char **cmdline_p) | |||
| 824 | if (efi_enabled) | 757 | if (efi_enabled) |
| 825 | efi_init(); | 758 | efi_init(); |
| 826 | 759 | ||
| 760 | if (ppro_with_ram_bug()) { | ||
| 761 | e820_update_range(0x70000000ULL, 0x40000ULL, E820_RAM, | ||
| 762 | E820_RESERVED); | ||
| 763 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | ||
| 764 | printk(KERN_INFO "fixed physical RAM map:\n"); | ||
| 765 | e820_print_map("bad_ppro"); | ||
| 766 | } | ||
| 767 | |||
| 768 | e820_register_active_regions(0, 0, -1UL); | ||
| 769 | /* | ||
| 770 | * partially used pages are not usable - thus | ||
| 771 | * we are rounding upwards: | ||
| 772 | */ | ||
| 773 | max_pfn = e820_end_of_ram(); | ||
| 774 | |||
| 775 | /* preallocate 4k for mptable mpc */ | ||
| 776 | early_reserve_e820_mpc_new(); | ||
| 827 | /* update e820 for memory not covered by WB MTRRs */ | 777 | /* update e820 for memory not covered by WB MTRRs */ |
| 828 | propagate_e820_map(); | ||
| 829 | mtrr_bp_init(); | 778 | mtrr_bp_init(); |
| 830 | if (mtrr_trim_uncached_memory(max_pfn)) | 779 | if (mtrr_trim_uncached_memory(max_pfn)) { |
| 831 | propagate_e820_map(); | 780 | remove_all_active_ranges(); |
| 781 | e820_register_active_regions(0, 0, -1UL); | ||
| 782 | max_pfn = e820_end_of_ram(); | ||
| 783 | } | ||
| 784 | |||
| 785 | dmi_scan_machine(); | ||
| 786 | |||
| 787 | io_delay_init(); | ||
| 788 | |||
| 789 | #ifdef CONFIG_ACPI | ||
| 790 | /* | ||
| 791 | * Parse the ACPI tables for possible boot-time SMP configuration. | ||
| 792 | */ | ||
| 793 | acpi_boot_table_init(); | ||
| 794 | #endif | ||
| 795 | |||
| 796 | #ifdef CONFIG_ACPI_NUMA | ||
| 797 | /* | ||
| 798 | * Parse SRAT to discover nodes. | ||
| 799 | */ | ||
| 800 | acpi_numa_init(); | ||
| 801 | #endif | ||
| 832 | 802 | ||
| 833 | max_low_pfn = setup_memory(); | 803 | max_low_pfn = setup_memory(); |
| 834 | 804 | ||
| 805 | #ifdef CONFIG_ACPI_SLEEP | ||
| 806 | /* | ||
| 807 | * Reserve low memory region for sleep support. | ||
| 808 | */ | ||
| 809 | acpi_reserve_bootmem(); | ||
| 810 | #endif | ||
| 811 | #ifdef CONFIG_X86_FIND_SMP_CONFIG | ||
| 812 | /* | ||
| 813 | * Find and reserve possible boot-time SMP configuration: | ||
| 814 | */ | ||
| 815 | find_smp_config(); | ||
| 816 | #endif | ||
| 817 | reserve_crashkernel(); | ||
| 818 | |||
| 819 | reserve_ibft_region(); | ||
| 820 | |||
| 835 | #ifdef CONFIG_KVM_CLOCK | 821 | #ifdef CONFIG_KVM_CLOCK |
| 836 | kvmclock_init(); | 822 | kvmclock_init(); |
| 837 | #endif | 823 | #endif |
| @@ -855,9 +841,6 @@ void __init setup_arch(char **cmdline_p) | |||
| 855 | * not to exceed the 8Mb limit. | 841 | * not to exceed the 8Mb limit. |
| 856 | */ | 842 | */ |
| 857 | 843 | ||
| 858 | #ifdef CONFIG_SMP | ||
| 859 | smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ | ||
| 860 | #endif | ||
| 861 | paging_init(); | 844 | paging_init(); |
| 862 | 845 | ||
| 863 | /* | 846 | /* |
| @@ -869,10 +852,6 @@ void __init setup_arch(char **cmdline_p) | |||
| 869 | init_ohci1394_dma_on_all_controllers(); | 852 | init_ohci1394_dma_on_all_controllers(); |
| 870 | #endif | 853 | #endif |
| 871 | 854 | ||
| 872 | remapped_pgdat_init(); | ||
| 873 | sparse_init(); | ||
| 874 | zone_sizes_init(); | ||
| 875 | |||
| 876 | /* | 855 | /* |
| 877 | * NOTE: at this point the bootmem allocator is fully available. | 856 | * NOTE: at this point the bootmem allocator is fully available. |
| 878 | */ | 857 | */ |
| @@ -881,11 +860,11 @@ void __init setup_arch(char **cmdline_p) | |||
| 881 | relocate_initrd(); | 860 | relocate_initrd(); |
| 882 | #endif | 861 | #endif |
| 883 | 862 | ||
| 884 | paravirt_post_allocator_init(); | 863 | remapped_pgdat_init(); |
| 885 | 864 | sparse_init(); | |
| 886 | dmi_scan_machine(); | 865 | zone_sizes_init(); |
| 887 | 866 | ||
| 888 | io_delay_init(); | 867 | paravirt_post_allocator_init(); |
| 889 | 868 | ||
| 890 | #ifdef CONFIG_X86_SMP | 869 | #ifdef CONFIG_X86_SMP |
| 891 | /* | 870 | /* |
| @@ -903,32 +882,31 @@ void __init setup_arch(char **cmdline_p) | |||
| 903 | generic_apic_probe(); | 882 | generic_apic_probe(); |
| 904 | #endif | 883 | #endif |
| 905 | 884 | ||
| 906 | #ifdef CONFIG_ACPI | ||
| 907 | /* | ||
| 908 | * Parse the ACPI tables for possible boot-time SMP configuration. | ||
| 909 | */ | ||
| 910 | acpi_boot_table_init(); | ||
| 911 | #endif | ||
| 912 | |||
| 913 | early_quirks(); | 885 | early_quirks(); |
| 914 | 886 | ||
| 915 | #ifdef CONFIG_ACPI | 887 | #ifdef CONFIG_ACPI |
| 916 | acpi_boot_init(); | 888 | acpi_boot_init(); |
| 917 | 889 | #endif | |
| 890 | #if defined(CONFIG_X86_MPPARSE) || defined(CONFIG_X86_VISWS) | ||
| 891 | if (smp_found_config) | ||
| 892 | get_smp_config(); | ||
| 893 | #endif | ||
| 918 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_PC) | 894 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_PC) |
| 919 | if (def_to_bigsmp) | 895 | if (def_to_bigsmp) |
| 920 | printk(KERN_WARNING "More than 8 CPUs detected and " | 896 | printk(KERN_WARNING "More than 8 CPUs detected and " |
| 921 | "CONFIG_X86_PC cannot handle it.\nUse " | 897 | "CONFIG_X86_PC cannot handle it.\nUse " |
| 922 | "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n"); | 898 | "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n"); |
| 923 | #endif | 899 | #endif |
| 924 | #endif | ||
| 925 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 926 | if (smp_found_config) | ||
| 927 | get_smp_config(); | ||
| 928 | #endif | ||
| 929 | 900 | ||
| 930 | e820_register_memory(); | 901 | e820_reserve_resources(); |
| 931 | e820_mark_nosave_regions(); | 902 | e820_mark_nosave_regions(max_low_pfn); |
| 903 | |||
| 904 | request_resource(&iomem_resource, &video_ram_resource); | ||
| 905 | /* request I/O space for devices used on all i[345]86 PCs */ | ||
| 906 | for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) | ||
| 907 | request_resource(&ioport_resource, &standard_io_resources[i]); | ||
| 908 | |||
| 909 | e820_setup_gap(); | ||
| 932 | 910 | ||
| 933 | #ifdef CONFIG_VT | 911 | #ifdef CONFIG_VT |
| 934 | #if defined(CONFIG_VGA_CONSOLE) | 912 | #if defined(CONFIG_VGA_CONSOLE) |
| @@ -940,25 +918,147 @@ void __init setup_arch(char **cmdline_p) | |||
| 940 | #endif | 918 | #endif |
| 941 | } | 919 | } |
| 942 | 920 | ||
| 943 | /* | 921 | static struct resource system_rom_resource = { |
| 944 | * Request address space for all standard resources | 922 | .name = "System ROM", |
| 945 | * | 923 | .start = 0xf0000, |
| 946 | * This is called just before pcibios_init(), which is also a | 924 | .end = 0xfffff, |
| 947 | * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). | 925 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM |
| 948 | */ | 926 | }; |
| 949 | static int __init request_standard_resources(void) | 927 | |
| 928 | static struct resource extension_rom_resource = { | ||
| 929 | .name = "Extension ROM", | ||
| 930 | .start = 0xe0000, | ||
| 931 | .end = 0xeffff, | ||
| 932 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 933 | }; | ||
| 934 | |||
| 935 | static struct resource adapter_rom_resources[] = { { | ||
| 936 | .name = "Adapter ROM", | ||
| 937 | .start = 0xc8000, | ||
| 938 | .end = 0, | ||
| 939 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 940 | }, { | ||
| 941 | .name = "Adapter ROM", | ||
| 942 | .start = 0, | ||
| 943 | .end = 0, | ||
| 944 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 945 | }, { | ||
| 946 | .name = "Adapter ROM", | ||
| 947 | .start = 0, | ||
| 948 | .end = 0, | ||
| 949 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 950 | }, { | ||
| 951 | .name = "Adapter ROM", | ||
| 952 | .start = 0, | ||
| 953 | .end = 0, | ||
| 954 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 955 | }, { | ||
| 956 | .name = "Adapter ROM", | ||
| 957 | .start = 0, | ||
| 958 | .end = 0, | ||
| 959 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 960 | }, { | ||
| 961 | .name = "Adapter ROM", | ||
| 962 | .start = 0, | ||
| 963 | .end = 0, | ||
| 964 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 965 | } }; | ||
| 966 | |||
| 967 | static struct resource video_rom_resource = { | ||
| 968 | .name = "Video ROM", | ||
| 969 | .start = 0xc0000, | ||
| 970 | .end = 0xc7fff, | ||
| 971 | .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM | ||
| 972 | }; | ||
| 973 | |||
| 974 | #define ROMSIGNATURE 0xaa55 | ||
| 975 | |||
| 976 | static int __init romsignature(const unsigned char *rom) | ||
| 950 | { | 977 | { |
| 978 | const unsigned short * const ptr = (const unsigned short *)rom; | ||
| 979 | unsigned short sig; | ||
| 980 | |||
| 981 | return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; | ||
| 982 | } | ||
| 983 | |||
| 984 | static int __init romchecksum(const unsigned char *rom, unsigned long length) | ||
| 985 | { | ||
| 986 | unsigned char sum, c; | ||
| 987 | |||
| 988 | for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) | ||
| 989 | sum += c; | ||
| 990 | return !length && !sum; | ||
| 991 | } | ||
| 992 | |||
| 993 | static void __init probe_roms(void) | ||
| 994 | { | ||
| 995 | const unsigned char *rom; | ||
| 996 | unsigned long start, length, upper; | ||
| 997 | unsigned char c; | ||
| 951 | int i; | 998 | int i; |
| 952 | 999 | ||
| 953 | printk(KERN_INFO "Setting up standard PCI resources\n"); | 1000 | /* video rom */ |
| 954 | init_iomem_resources(&code_resource, &data_resource, &bss_resource); | 1001 | upper = adapter_rom_resources[0].start; |
| 1002 | for (start = video_rom_resource.start; start < upper; start += 2048) { | ||
| 1003 | rom = isa_bus_to_virt(start); | ||
| 1004 | if (!romsignature(rom)) | ||
| 1005 | continue; | ||
| 955 | 1006 | ||
| 956 | request_resource(&iomem_resource, &video_ram_resource); | 1007 | video_rom_resource.start = start; |
| 957 | 1008 | ||
| 958 | /* request I/O space for devices used on all i[345]86 PCs */ | 1009 | if (probe_kernel_address(rom + 2, c) != 0) |
| 959 | for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) | 1010 | continue; |
| 960 | request_resource(&ioport_resource, &standard_io_resources[i]); | 1011 | |
| 961 | return 0; | 1012 | /* 0 < length <= 0x7f * 512, historically */ |
| 1013 | length = c * 512; | ||
| 1014 | |||
| 1015 | /* if checksum okay, trust length byte */ | ||
| 1016 | if (length && romchecksum(rom, length)) | ||
| 1017 | video_rom_resource.end = start + length - 1; | ||
| 1018 | |||
| 1019 | request_resource(&iomem_resource, &video_rom_resource); | ||
| 1020 | break; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | start = (video_rom_resource.end + 1 + 2047) & ~2047UL; | ||
| 1024 | if (start < upper) | ||
| 1025 | start = upper; | ||
| 1026 | |||
| 1027 | /* system rom */ | ||
| 1028 | request_resource(&iomem_resource, &system_rom_resource); | ||
| 1029 | upper = system_rom_resource.start; | ||
| 1030 | |||
| 1031 | /* check for extension rom (ignore length byte!) */ | ||
| 1032 | rom = isa_bus_to_virt(extension_rom_resource.start); | ||
| 1033 | if (romsignature(rom)) { | ||
| 1034 | length = extension_rom_resource.end - extension_rom_resource.start + 1; | ||
| 1035 | if (romchecksum(rom, length)) { | ||
| 1036 | request_resource(&iomem_resource, &extension_rom_resource); | ||
| 1037 | upper = extension_rom_resource.start; | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | /* check for adapter roms on 2k boundaries */ | ||
| 1042 | for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { | ||
| 1043 | rom = isa_bus_to_virt(start); | ||
| 1044 | if (!romsignature(rom)) | ||
| 1045 | continue; | ||
| 1046 | |||
| 1047 | if (probe_kernel_address(rom + 2, c) != 0) | ||
| 1048 | continue; | ||
| 1049 | |||
| 1050 | /* 0 < length <= 0x7f * 512, historically */ | ||
| 1051 | length = c * 512; | ||
| 1052 | |||
| 1053 | /* but accept any length that fits if checksum okay */ | ||
| 1054 | if (!length || start + length > upper || !romchecksum(rom, length)) | ||
| 1055 | continue; | ||
| 1056 | |||
| 1057 | adapter_rom_resources[i].start = start; | ||
| 1058 | adapter_rom_resources[i].end = start + length - 1; | ||
| 1059 | request_resource(&iomem_resource, &adapter_rom_resources[i]); | ||
| 1060 | |||
| 1061 | start = adapter_rom_resources[i++].end & ~2047UL; | ||
| 1062 | } | ||
| 962 | } | 1063 | } |
| 963 | 1064 | ||
| 964 | subsys_initcall(request_standard_resources); | ||
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 545440e471b2..9a87113ba996 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include <asm/desc.h> | 56 | #include <asm/desc.h> |
| 57 | #include <video/edid.h> | 57 | #include <video/edid.h> |
| 58 | #include <asm/e820.h> | 58 | #include <asm/e820.h> |
| 59 | #include <asm/mpspec.h> | ||
| 59 | #include <asm/dma.h> | 60 | #include <asm/dma.h> |
| 60 | #include <asm/gart.h> | 61 | #include <asm/gart.h> |
| 61 | #include <asm/mpspec.h> | 62 | #include <asm/mpspec.h> |
| @@ -245,7 +246,7 @@ static void __init reserve_crashkernel(void) | |||
| 245 | return; | 246 | return; |
| 246 | } | 247 | } |
| 247 | 248 | ||
| 248 | if (reserve_bootmem(crash_base, crash_size, | 249 | if (reserve_bootmem_generic(crash_base, crash_size, |
| 249 | BOOTMEM_EXCLUSIVE) < 0) { | 250 | BOOTMEM_EXCLUSIVE) < 0) { |
| 250 | printk(KERN_INFO "crashkernel reservation failed - " | 251 | printk(KERN_INFO "crashkernel reservation failed - " |
| 251 | "memory is in use\n"); | 252 | "memory is in use\n"); |
| @@ -267,34 +268,6 @@ static inline void __init reserve_crashkernel(void) | |||
| 267 | {} | 268 | {} |
| 268 | #endif | 269 | #endif |
| 269 | 270 | ||
| 270 | /* Overridden in paravirt.c if CONFIG_PARAVIRT */ | ||
| 271 | void __attribute__((weak)) __init memory_setup(void) | ||
| 272 | { | ||
| 273 | machine_specific_memory_setup(); | ||
| 274 | } | ||
| 275 | |||
| 276 | static void __init parse_setup_data(void) | ||
| 277 | { | ||
| 278 | struct setup_data *data; | ||
| 279 | unsigned long pa_data; | ||
| 280 | |||
| 281 | if (boot_params.hdr.version < 0x0209) | ||
| 282 | return; | ||
| 283 | pa_data = boot_params.hdr.setup_data; | ||
| 284 | while (pa_data) { | ||
| 285 | data = early_ioremap(pa_data, PAGE_SIZE); | ||
| 286 | switch (data->type) { | ||
| 287 | default: | ||
| 288 | break; | ||
| 289 | } | ||
| 290 | #ifndef CONFIG_DEBUG_BOOT_PARAMS | ||
| 291 | free_early(pa_data, pa_data+sizeof(*data)+data->len); | ||
| 292 | #endif | ||
| 293 | pa_data = data->next; | ||
| 294 | early_iounmap(data, PAGE_SIZE); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | /* | 271 | /* |
| 299 | * setup_arch - architecture-specific boot-time initializations | 272 | * setup_arch - architecture-specific boot-time initializations |
| 300 | * | 273 | * |
| @@ -319,13 +292,15 @@ void __init setup_arch(char **cmdline_p) | |||
| 319 | #endif | 292 | #endif |
| 320 | #ifdef CONFIG_EFI | 293 | #ifdef CONFIG_EFI |
| 321 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, | 294 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, |
| 322 | "EL64", 4)) | 295 | "EL64", 4)) { |
| 323 | efi_enabled = 1; | 296 | efi_enabled = 1; |
| 297 | efi_reserve_early(); | ||
| 298 | } | ||
| 324 | #endif | 299 | #endif |
| 325 | 300 | ||
| 326 | ARCH_SETUP | 301 | ARCH_SETUP |
| 327 | 302 | ||
| 328 | memory_setup(); | 303 | setup_memory_map(); |
| 329 | copy_edd(); | 304 | copy_edd(); |
| 330 | 305 | ||
| 331 | if (!boot_params.hdr.root_flags) | 306 | if (!boot_params.hdr.root_flags) |
| @@ -372,9 +347,13 @@ void __init setup_arch(char **cmdline_p) | |||
| 372 | * we are rounding upwards: | 347 | * we are rounding upwards: |
| 373 | */ | 348 | */ |
| 374 | end_pfn = e820_end_of_ram(); | 349 | end_pfn = e820_end_of_ram(); |
| 350 | |||
| 351 | /* pre allocte 4k for mptable mpc */ | ||
| 352 | early_reserve_e820_mpc_new(); | ||
| 375 | /* update e820 for memory not covered by WB MTRRs */ | 353 | /* update e820 for memory not covered by WB MTRRs */ |
| 376 | mtrr_bp_init(); | 354 | mtrr_bp_init(); |
| 377 | if (mtrr_trim_uncached_memory(end_pfn)) { | 355 | if (mtrr_trim_uncached_memory(end_pfn)) { |
| 356 | remove_all_active_ranges(); | ||
| 378 | e820_register_active_regions(0, 0, -1UL); | 357 | e820_register_active_regions(0, 0, -1UL); |
| 379 | end_pfn = e820_end_of_ram(); | 358 | end_pfn = e820_end_of_ram(); |
| 380 | } | 359 | } |
| @@ -383,7 +362,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 383 | 362 | ||
| 384 | check_efer(); | 363 | check_efer(); |
| 385 | 364 | ||
| 386 | max_pfn_mapped = init_memory_mapping(0, (max_pfn_mapped << PAGE_SHIFT)); | 365 | max_pfn_mapped = init_memory_mapping(0, (end_pfn << PAGE_SHIFT)); |
| 387 | if (efi_enabled) | 366 | if (efi_enabled) |
| 388 | efi_init(); | 367 | efi_init(); |
| 389 | 368 | ||
| @@ -444,13 +423,12 @@ void __init setup_arch(char **cmdline_p) | |||
| 444 | acpi_reserve_bootmem(); | 423 | acpi_reserve_bootmem(); |
| 445 | #endif | 424 | #endif |
| 446 | 425 | ||
| 447 | if (efi_enabled) | 426 | #ifdef CONFIG_X86_MPPARSE |
| 448 | efi_reserve_bootmem(); | ||
| 449 | |||
| 450 | /* | 427 | /* |
| 451 | * Find and reserve possible boot-time SMP configuration: | 428 | * Find and reserve possible boot-time SMP configuration: |
| 452 | */ | 429 | */ |
| 453 | find_smp_config(); | 430 | find_smp_config(); |
| 431 | #endif | ||
| 454 | #ifdef CONFIG_BLK_DEV_INITRD | 432 | #ifdef CONFIG_BLK_DEV_INITRD |
| 455 | if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { | 433 | if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { |
| 456 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | 434 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; |
| @@ -493,11 +471,13 @@ void __init setup_arch(char **cmdline_p) | |||
| 493 | 471 | ||
| 494 | init_cpu_to_node(); | 472 | init_cpu_to_node(); |
| 495 | 473 | ||
| 474 | #ifdef CONFIG_X86_MPPARSE | ||
| 496 | /* | 475 | /* |
| 497 | * get boot-time SMP configuration: | 476 | * get boot-time SMP configuration: |
| 498 | */ | 477 | */ |
| 499 | if (smp_found_config) | 478 | if (smp_found_config) |
| 500 | get_smp_config(); | 479 | get_smp_config(); |
| 480 | #endif | ||
| 501 | init_apic_mappings(); | 481 | init_apic_mappings(); |
| 502 | ioapic_init_mappings(); | 482 | ioapic_init_mappings(); |
| 503 | 483 | ||
| @@ -507,7 +487,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 507 | * We trust e820 completely. No explicit ROM probing in memory. | 487 | * We trust e820 completely. No explicit ROM probing in memory. |
| 508 | */ | 488 | */ |
| 509 | e820_reserve_resources(); | 489 | e820_reserve_resources(); |
| 510 | e820_mark_nosave_regions(); | 490 | e820_mark_nosave_regions(end_pfn); |
| 511 | 491 | ||
| 512 | /* request I/O space for devices used on all i[345]86 PCs */ | 492 | /* request I/O space for devices used on all i[345]86 PCs */ |
| 513 | for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) | 493 | for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index f2b666756299..6be701f3027f 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
| @@ -554,23 +554,6 @@ cpumask_t cpu_coregroup_map(int cpu) | |||
| 554 | return c->llc_shared_map; | 554 | return c->llc_shared_map; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | #ifdef CONFIG_X86_32 | ||
| 558 | /* | ||
| 559 | * We are called very early to get the low memory for the | ||
| 560 | * SMP bootup trampoline page. | ||
| 561 | */ | ||
| 562 | void __init smp_alloc_memory(void) | ||
| 563 | { | ||
| 564 | trampoline_base = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 565 | /* | ||
| 566 | * Has to be in very low memory so we can execute | ||
| 567 | * real-mode AP code. | ||
| 568 | */ | ||
| 569 | if (__pa(trampoline_base) >= 0x9F000) | ||
| 570 | BUG(); | ||
| 571 | } | ||
| 572 | #endif | ||
| 573 | |||
| 574 | static void impress_friends(void) | 557 | static void impress_friends(void) |
| 575 | { | 558 | { |
| 576 | int cpu; | 559 | int cpu; |
diff --git a/arch/x86/kernel/srat_32.c b/arch/x86/kernel/srat_32.c index 70e4a374b4e8..5978023b799b 100644 --- a/arch/x86/kernel/srat_32.c +++ b/arch/x86/kernel/srat_32.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/srat.h> | 31 | #include <asm/srat.h> |
| 32 | #include <asm/topology.h> | 32 | #include <asm/topology.h> |
| 33 | #include <asm/smp.h> | 33 | #include <asm/smp.h> |
| 34 | #include <asm/e820.h> | ||
| 34 | 35 | ||
| 35 | /* | 36 | /* |
| 36 | * proximity macros and definitions | 37 | * proximity macros and definitions |
| @@ -41,7 +42,7 @@ | |||
| 41 | #define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit))) | 42 | #define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit))) |
| 42 | /* bitmap length; _PXM is at most 255 */ | 43 | /* bitmap length; _PXM is at most 255 */ |
| 43 | #define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) | 44 | #define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) |
| 44 | static u8 pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */ | 45 | static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */ |
| 45 | 46 | ||
| 46 | #define MAX_CHUNKS_PER_NODE 3 | 47 | #define MAX_CHUNKS_PER_NODE 3 |
| 47 | #define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES) | 48 | #define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES) |
| @@ -52,16 +53,37 @@ struct node_memory_chunk_s { | |||
| 52 | u8 nid; // which cnode contains this chunk? | 53 | u8 nid; // which cnode contains this chunk? |
| 53 | u8 bank; // which mem bank on this node | 54 | u8 bank; // which mem bank on this node |
| 54 | }; | 55 | }; |
| 55 | static struct node_memory_chunk_s node_memory_chunk[MAXCHUNKS]; | 56 | static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS]; |
| 56 | 57 | ||
| 57 | static int num_memory_chunks; /* total number of memory chunks */ | 58 | static int __initdata num_memory_chunks; /* total number of memory chunks */ |
| 58 | static u8 __initdata apicid_to_pxm[MAX_APICID]; | 59 | static u8 __initdata apicid_to_pxm[MAX_APICID]; |
| 59 | 60 | ||
| 61 | int numa_off __initdata; | ||
| 62 | int acpi_numa __initdata; | ||
| 63 | |||
| 64 | static __init void bad_srat(void) | ||
| 65 | { | ||
| 66 | printk(KERN_ERR "SRAT: SRAT not used.\n"); | ||
| 67 | acpi_numa = -1; | ||
| 68 | num_memory_chunks = 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static __init inline int srat_disabled(void) | ||
| 72 | { | ||
| 73 | return numa_off || acpi_numa < 0; | ||
| 74 | } | ||
| 75 | |||
| 60 | /* Identify CPU proximity domains */ | 76 | /* Identify CPU proximity domains */ |
| 61 | static void __init parse_cpu_affinity_structure(char *p) | 77 | void __init |
| 78 | acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity) | ||
| 62 | { | 79 | { |
| 63 | struct acpi_srat_cpu_affinity *cpu_affinity = | 80 | if (srat_disabled()) |
| 64 | (struct acpi_srat_cpu_affinity *) p; | 81 | return; |
| 82 | if (cpu_affinity->header.length != | ||
| 83 | sizeof(struct acpi_srat_cpu_affinity)) { | ||
| 84 | bad_srat(); | ||
| 85 | return; | ||
| 86 | } | ||
| 65 | 87 | ||
| 66 | if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) | 88 | if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) |
| 67 | return; /* empty entry */ | 89 | return; /* empty entry */ |
| @@ -79,14 +101,21 @@ static void __init parse_cpu_affinity_structure(char *p) | |||
| 79 | * Identify memory proximity domains and hot-remove capabilities. | 101 | * Identify memory proximity domains and hot-remove capabilities. |
| 80 | * Fill node memory chunk list structure. | 102 | * Fill node memory chunk list structure. |
| 81 | */ | 103 | */ |
| 82 | static void __init parse_memory_affinity_structure (char *sratp) | 104 | void __init |
| 105 | acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity) | ||
| 83 | { | 106 | { |
| 84 | unsigned long long paddr, size; | 107 | unsigned long long paddr, size; |
| 85 | unsigned long start_pfn, end_pfn; | 108 | unsigned long start_pfn, end_pfn; |
| 86 | u8 pxm; | 109 | u8 pxm; |
| 87 | struct node_memory_chunk_s *p, *q, *pend; | 110 | struct node_memory_chunk_s *p, *q, *pend; |
| 88 | struct acpi_srat_mem_affinity *memory_affinity = | 111 | |
| 89 | (struct acpi_srat_mem_affinity *) sratp; | 112 | if (srat_disabled()) |
| 113 | return; | ||
| 114 | if (memory_affinity->header.length != | ||
| 115 | sizeof(struct acpi_srat_mem_affinity)) { | ||
| 116 | bad_srat(); | ||
| 117 | return; | ||
| 118 | } | ||
| 90 | 119 | ||
| 91 | if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) | 120 | if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) |
| 92 | return; /* empty entry */ | 121 | return; /* empty entry */ |
| @@ -134,6 +163,14 @@ static void __init parse_memory_affinity_structure (char *sratp) | |||
| 134 | "enabled and removable" : "enabled" ) ); | 163 | "enabled and removable" : "enabled" ) ); |
| 135 | } | 164 | } |
| 136 | 165 | ||
| 166 | /* Callback for SLIT parsing */ | ||
| 167 | void __init acpi_numa_slit_init(struct acpi_table_slit *slit) | ||
| 168 | { | ||
| 169 | } | ||
| 170 | |||
| 171 | void acpi_numa_arch_fixup(void) | ||
| 172 | { | ||
| 173 | } | ||
| 137 | /* | 174 | /* |
| 138 | * The SRAT table always lists ascending addresses, so can always | 175 | * The SRAT table always lists ascending addresses, so can always |
| 139 | * assume that the first "start" address that you see is the real | 176 | * assume that the first "start" address that you see is the real |
| @@ -166,39 +203,13 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c | |||
| 166 | node_end_pfn[nid] = memory_chunk->end_pfn; | 203 | node_end_pfn[nid] = memory_chunk->end_pfn; |
| 167 | } | 204 | } |
| 168 | 205 | ||
| 169 | /* Parse the ACPI Static Resource Affinity Table */ | 206 | int __init get_memcfg_from_srat(void) |
| 170 | static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) | ||
| 171 | { | 207 | { |
| 172 | u8 *start, *end, *p; | ||
| 173 | int i, j, nid; | 208 | int i, j, nid; |
| 174 | 209 | ||
| 175 | start = (u8 *)(&(sratp->reserved) + 1); /* skip header */ | ||
| 176 | p = start; | ||
| 177 | end = (u8 *)sratp + sratp->header.length; | ||
| 178 | |||
| 179 | memset(pxm_bitmap, 0, sizeof(pxm_bitmap)); /* init proximity domain bitmap */ | ||
| 180 | memset(node_memory_chunk, 0, sizeof(node_memory_chunk)); | ||
| 181 | 210 | ||
| 182 | num_memory_chunks = 0; | 211 | if (srat_disabled()) |
| 183 | while (p < end) { | 212 | goto out_fail; |
| 184 | switch (*p) { | ||
| 185 | case ACPI_SRAT_TYPE_CPU_AFFINITY: | ||
| 186 | parse_cpu_affinity_structure(p); | ||
| 187 | break; | ||
| 188 | case ACPI_SRAT_TYPE_MEMORY_AFFINITY: | ||
| 189 | parse_memory_affinity_structure(p); | ||
| 190 | break; | ||
| 191 | default: | ||
| 192 | printk("ACPI 2.0 SRAT: unknown entry skipped: type=0x%02X, len=%d\n", p[0], p[1]); | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | p += p[1]; | ||
| 196 | if (p[1] == 0) { | ||
| 197 | printk("acpi20_parse_srat: Entry length value is zero;" | ||
| 198 | " can't parse any further!\n"); | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | 213 | ||
| 203 | if (num_memory_chunks == 0) { | 214 | if (num_memory_chunks == 0) { |
| 204 | printk("could not finy any ACPI SRAT memory areas.\n"); | 215 | printk("could not finy any ACPI SRAT memory areas.\n"); |
| @@ -244,115 +255,19 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) | |||
| 244 | printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n", | 255 | printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n", |
| 245 | j, chunk->nid, chunk->start_pfn, chunk->end_pfn); | 256 | j, chunk->nid, chunk->start_pfn, chunk->end_pfn); |
| 246 | node_read_chunk(chunk->nid, chunk); | 257 | node_read_chunk(chunk->nid, chunk); |
| 247 | add_active_range(chunk->nid, chunk->start_pfn, chunk->end_pfn); | 258 | e820_register_active_regions(chunk->nid, chunk->start_pfn, |
| 259 | min(chunk->end_pfn, max_pfn)); | ||
| 248 | } | 260 | } |
| 249 | 261 | ||
| 250 | for_each_online_node(nid) { | 262 | for_each_online_node(nid) { |
| 251 | unsigned long start = node_start_pfn[nid]; | 263 | unsigned long start = node_start_pfn[nid]; |
| 252 | unsigned long end = node_end_pfn[nid]; | 264 | unsigned long end = min(node_end_pfn[nid], max_pfn); |
| 253 | 265 | ||
| 254 | memory_present(nid, start, end); | 266 | memory_present(nid, start, end); |
| 255 | node_remap_size[nid] = node_memmap_size_bytes(nid, start, end); | 267 | node_remap_size[nid] = node_memmap_size_bytes(nid, start, end); |
| 256 | } | 268 | } |
| 257 | return 1; | 269 | return 1; |
| 258 | out_fail: | 270 | out_fail: |
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | struct acpi_static_rsdt { | ||
| 263 | struct acpi_table_rsdt table; | ||
| 264 | u32 padding[7]; /* Allow for 7 more table entries */ | ||
| 265 | }; | ||
| 266 | |||
| 267 | int __init get_memcfg_from_srat(void) | ||
| 268 | { | ||
| 269 | struct acpi_table_header *header = NULL; | ||
| 270 | struct acpi_table_rsdp *rsdp = NULL; | ||
| 271 | struct acpi_table_rsdt *rsdt = NULL; | ||
| 272 | acpi_native_uint rsdp_address = 0; | ||
| 273 | struct acpi_static_rsdt saved_rsdt; | ||
| 274 | int tables = 0; | ||
| 275 | int i = 0; | ||
| 276 | |||
| 277 | rsdp_address = acpi_os_get_root_pointer(); | ||
| 278 | if (!rsdp_address) { | ||
| 279 | printk("%s: System description tables not found\n", | ||
| 280 | __func__); | ||
| 281 | goto out_err; | ||
| 282 | } | ||
| 283 | |||
| 284 | printk("%s: assigning address to rsdp\n", __func__); | ||
| 285 | rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address; | ||
| 286 | if (!rsdp) { | ||
| 287 | printk("%s: Didn't find ACPI root!\n", __func__); | ||
| 288 | goto out_err; | ||
| 289 | } | ||
| 290 | |||
| 291 | printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, | ||
| 292 | rsdp->oem_id); | ||
| 293 | |||
| 294 | if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) { | ||
| 295 | printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __func__); | ||
| 296 | goto out_err; | ||
| 297 | } | ||
| 298 | |||
| 299 | rsdt = (struct acpi_table_rsdt *) | ||
| 300 | early_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt)); | ||
| 301 | |||
| 302 | if (!rsdt) { | ||
| 303 | printk(KERN_WARNING | ||
| 304 | "%s: ACPI: Invalid root system description tables (RSDT)\n", | ||
| 305 | __func__); | ||
| 306 | goto out_err; | ||
| 307 | } | ||
| 308 | |||
| 309 | header = &rsdt->header; | ||
| 310 | |||
| 311 | if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) { | ||
| 312 | printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); | ||
| 313 | goto out_err; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* | ||
| 317 | * The number of tables is computed by taking the | ||
| 318 | * size of all entries (header size minus total | ||
| 319 | * size of RSDT) divided by the size of each entry | ||
| 320 | * (4-byte table pointers). | ||
| 321 | */ | ||
| 322 | tables = (header->length - sizeof(struct acpi_table_header)) / 4; | ||
| 323 | |||
| 324 | if (!tables) | ||
| 325 | goto out_err; | ||
| 326 | |||
| 327 | memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); | ||
| 328 | |||
| 329 | if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) { | ||
| 330 | printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", | ||
| 331 | saved_rsdt.table.header.length); | ||
| 332 | goto out_err; | ||
| 333 | } | ||
| 334 | |||
| 335 | printk("Begin SRAT table scan....\n"); | ||
| 336 | |||
| 337 | for (i = 0; i < tables; i++) { | ||
| 338 | /* Map in header, then map in full table length. */ | ||
| 339 | header = (struct acpi_table_header *) | ||
| 340 | early_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header)); | ||
| 341 | if (!header) | ||
| 342 | break; | ||
| 343 | header = (struct acpi_table_header *) | ||
| 344 | early_ioremap(saved_rsdt.table.table_offset_entry[i], header->length); | ||
| 345 | if (!header) | ||
| 346 | break; | ||
| 347 | |||
| 348 | if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4)) | ||
| 349 | continue; | ||
| 350 | |||
| 351 | /* we've found the srat table. don't need to look at any more tables */ | ||
| 352 | return acpi20_parse_srat((struct acpi_table_srat *)header); | ||
| 353 | } | ||
| 354 | out_err: | ||
| 355 | remove_all_active_ranges(); | ||
| 356 | printk("failed to get NUMA memory information from SRAT table\n"); | 271 | printk("failed to get NUMA memory information from SRAT table\n"); |
| 357 | return 0; | 272 | return 0; |
| 358 | } | 273 | } |
diff --git a/arch/x86/kernel/summit_32.c b/arch/x86/kernel/summit_32.c index ae751094eba9..d67ce5f044ba 100644 --- a/arch/x86/kernel/summit_32.c +++ b/arch/x86/kernel/summit_32.c | |||
| @@ -36,7 +36,9 @@ static struct rio_table_hdr *rio_table_hdr __initdata; | |||
| 36 | static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata; | 36 | static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata; |
| 37 | static struct rio_detail *rio_devs[MAX_NUMNODES*4] __initdata; | 37 | static struct rio_detail *rio_devs[MAX_NUMNODES*4] __initdata; |
| 38 | 38 | ||
| 39 | #ifndef CONFIG_X86_NUMAQ | ||
| 39 | static int mp_bus_id_to_node[MAX_MP_BUSSES] __initdata; | 40 | static int mp_bus_id_to_node[MAX_MP_BUSSES] __initdata; |
| 41 | #endif | ||
| 40 | 42 | ||
| 41 | static int __init setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus) | 43 | static int __init setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus) |
| 42 | { | 44 | { |
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index abbf199adebb..1106fac6024d 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | #include <asm/trampoline.h> | 3 | #include <asm/trampoline.h> |
| 4 | 4 | ||
| 5 | /* ready for x86_64, no harm for x86, since it will overwrite after alloc */ | 5 | /* ready for x86_64 and x86 */ |
| 6 | unsigned char *trampoline_base = __va(TRAMPOLINE_BASE); | 6 | unsigned char *trampoline_base = __va(TRAMPOLINE_BASE); |
| 7 | 7 | ||
| 8 | /* | 8 | /* |
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 5c7e2fd52075..e72cf0793fbe 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
| @@ -835,7 +835,7 @@ static __init char *lguest_memory_setup(void) | |||
| 835 | 835 | ||
| 836 | /* The Linux bootloader header contains an "e820" memory map: the | 836 | /* The Linux bootloader header contains an "e820" memory map: the |
| 837 | * Launcher populated the first entry with our memory limit. */ | 837 | * Launcher populated the first entry with our memory limit. */ |
| 838 | add_memory_region(boot_params.e820_map[0].addr, | 838 | e820_add_region(boot_params.e820_map[0].addr, |
| 839 | boot_params.e820_map[0].size, | 839 | boot_params.e820_map[0].size, |
| 840 | boot_params.e820_map[0].type); | 840 | boot_params.e820_map[0].type); |
| 841 | 841 | ||
| @@ -1012,6 +1012,7 @@ __init void lguest_init(void) | |||
| 1012 | * clobbered. The Launcher places our initial pagetables somewhere at | 1012 | * clobbered. The Launcher places our initial pagetables somewhere at |
| 1013 | * the top of our physical memory, so we don't need extra space: set | 1013 | * the top of our physical memory, so we don't need extra space: set |
| 1014 | * init_pg_tables_end to the end of the kernel. */ | 1014 | * init_pg_tables_end to the end of the kernel. */ |
| 1015 | init_pg_tables_start = __pa(pg0); | ||
| 1015 | init_pg_tables_end = __pa(pg0); | 1016 | init_pg_tables_end = __pa(pg0); |
| 1016 | 1017 | ||
| 1017 | /* Load the %fs segment register (the per-cpu segment register) with | 1018 | /* Load the %fs segment register (the per-cpu segment register) with |
| @@ -1065,9 +1066,9 @@ __init void lguest_init(void) | |||
| 1065 | pm_power_off = lguest_power_off; | 1066 | pm_power_off = lguest_power_off; |
| 1066 | machine_ops.restart = lguest_restart; | 1067 | machine_ops.restart = lguest_restart; |
| 1067 | 1068 | ||
| 1068 | /* Now we're set up, call start_kernel() in init/main.c and we proceed | 1069 | /* Now we're set up, call i386_start_kernel() in head32.c and we proceed |
| 1069 | * to boot as normal. It never returns. */ | 1070 | * to boot as normal. It never returns. */ |
| 1070 | start_kernel(); | 1071 | i386_start_kernel(); |
| 1071 | } | 1072 | } |
| 1072 | /* | 1073 | /* |
| 1073 | * This marks the end of stage II of our journey, The Guest. | 1074 | * This marks the end of stage II of our journey, The Guest. |
diff --git a/arch/x86/mach-default/setup.c b/arch/x86/mach-default/setup.c index 0c28a071824c..2f5e277686b8 100644 --- a/arch/x86/mach-default/setup.c +++ b/arch/x86/mach-default/setup.c | |||
| @@ -142,45 +142,3 @@ static int __init print_ipi_mode(void) | |||
| 142 | 142 | ||
| 143 | late_initcall(print_ipi_mode); | 143 | late_initcall(print_ipi_mode); |
| 144 | 144 | ||
| 145 | /** | ||
| 146 | * machine_specific_memory_setup - Hook for machine specific memory setup. | ||
| 147 | * | ||
| 148 | * Description: | ||
| 149 | * This is included late in kernel/setup.c so that it can make | ||
| 150 | * use of all of the static functions. | ||
| 151 | **/ | ||
| 152 | |||
| 153 | char * __init machine_specific_memory_setup(void) | ||
| 154 | { | ||
| 155 | char *who; | ||
| 156 | |||
| 157 | |||
| 158 | who = "BIOS-e820"; | ||
| 159 | |||
| 160 | /* | ||
| 161 | * Try to copy the BIOS-supplied E820-map. | ||
| 162 | * | ||
| 163 | * Otherwise fake a memory map; one section from 0k->640k, | ||
| 164 | * the next section from 1mb->appropriate_mem_k | ||
| 165 | */ | ||
| 166 | sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries); | ||
| 167 | if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) | ||
| 168 | < 0) { | ||
| 169 | unsigned long mem_size; | ||
| 170 | |||
| 171 | /* compare results from other methods and take the greater */ | ||
| 172 | if (boot_params.alt_mem_k | ||
| 173 | < boot_params.screen_info.ext_mem_k) { | ||
| 174 | mem_size = boot_params.screen_info.ext_mem_k; | ||
| 175 | who = "BIOS-88"; | ||
| 176 | } else { | ||
| 177 | mem_size = boot_params.alt_mem_k; | ||
| 178 | who = "BIOS-e801"; | ||
| 179 | } | ||
| 180 | |||
| 181 | e820.nr_map = 0; | ||
| 182 | add_memory_region(0, LOWMEMSIZE(), E820_RAM); | ||
| 183 | add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); | ||
| 184 | } | ||
| 185 | return who; | ||
| 186 | } | ||
diff --git a/arch/x86/mach-es7000/Makefile b/arch/x86/mach-es7000/Makefile index 69dd4da218dc..3ef8b43b62fc 100644 --- a/arch/x86/mach-es7000/Makefile +++ b/arch/x86/mach-es7000/Makefile | |||
| @@ -3,4 +3,3 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_X86_ES7000) := es7000plat.o | 5 | obj-$(CONFIG_X86_ES7000) := es7000plat.o |
| 6 | obj-$(CONFIG_X86_GENERICARCH) := es7000plat.o | ||
diff --git a/arch/x86/mach-es7000/es7000plat.c b/arch/x86/mach-es7000/es7000plat.c index f5d6f7d8b86e..4354ce804889 100644 --- a/arch/x86/mach-es7000/es7000plat.c +++ b/arch/x86/mach-es7000/es7000plat.c | |||
| @@ -52,6 +52,8 @@ static struct mip_reg *host_reg; | |||
| 52 | static int mip_port; | 52 | static int mip_port; |
| 53 | static unsigned long mip_addr, host_addr; | 53 | static unsigned long mip_addr, host_addr; |
| 54 | 54 | ||
| 55 | int es7000_plat; | ||
| 56 | |||
| 55 | /* | 57 | /* |
| 56 | * GSI override for ES7000 platforms. | 58 | * GSI override for ES7000 platforms. |
| 57 | */ | 59 | */ |
| @@ -175,53 +177,6 @@ find_unisys_acpi_oem_table(unsigned long *oem_addr) | |||
| 175 | } | 177 | } |
| 176 | #endif | 178 | #endif |
| 177 | 179 | ||
| 178 | /* | ||
| 179 | * This file also gets compiled if CONFIG_X86_GENERICARCH is set. Generic | ||
| 180 | * arch already has got following function definitions (asm-generic/es7000.c) | ||
| 181 | * hence no need to define these for that case. | ||
| 182 | */ | ||
| 183 | #ifndef CONFIG_X86_GENERICARCH | ||
| 184 | void es7000_sw_apic(void); | ||
| 185 | void __init enable_apic_mode(void) | ||
| 186 | { | ||
| 187 | es7000_sw_apic(); | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | __init int mps_oem_check(struct mp_config_table *mpc, char *oem, | ||
| 192 | char *productid) | ||
| 193 | { | ||
| 194 | if (mpc->mpc_oemptr) { | ||
| 195 | struct mp_config_oemtable *oem_table = | ||
| 196 | (struct mp_config_oemtable *)mpc->mpc_oemptr; | ||
| 197 | if (!strncmp(oem, "UNISYS", 6)) | ||
| 198 | return parse_unisys_oem((char *)oem_table); | ||
| 199 | } | ||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | #ifdef CONFIG_ACPI | ||
| 203 | /* Hook from generic ACPI tables.c */ | ||
| 204 | int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) | ||
| 205 | { | ||
| 206 | unsigned long oem_addr; | ||
| 207 | if (!find_unisys_acpi_oem_table(&oem_addr)) { | ||
| 208 | if (es7000_check_dsdt()) | ||
| 209 | return parse_unisys_oem((char *)oem_addr); | ||
| 210 | else { | ||
| 211 | setup_unisys(); | ||
| 212 | return 1; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | #else | ||
| 218 | int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) | ||
| 219 | { | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | #endif | ||
| 223 | #endif /* COFIG_X86_GENERICARCH */ | ||
| 224 | |||
| 225 | static void | 180 | static void |
| 226 | es7000_spin(int n) | 181 | es7000_spin(int n) |
| 227 | { | 182 | { |
diff --git a/arch/x86/mach-generic/Makefile b/arch/x86/mach-generic/Makefile index 19d6d407737b..0dbd7803a1d5 100644 --- a/arch/x86/mach-generic/Makefile +++ b/arch/x86/mach-generic/Makefile | |||
| @@ -2,7 +2,11 @@ | |||
| 2 | # Makefile for the generic architecture | 2 | # Makefile for the generic architecture |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | EXTRA_CFLAGS := -Iarch/x86/kernel | 5 | EXTRA_CFLAGS := -Iarch/x86/kernel |
| 6 | 6 | ||
| 7 | obj-y := probe.o summit.o bigsmp.o es7000.o default.o | 7 | obj-y := probe.o default.o |
| 8 | obj-y += ../../x86/mach-es7000/ | 8 | obj-$(CONFIG_X86_NUMAQ) += numaq.o |
| 9 | obj-$(CONFIG_X86_SUMMIT) += summit.o | ||
| 10 | obj-$(CONFIG_X86_BIGSMP) += bigsmp.o | ||
| 11 | obj-$(CONFIG_X86_ES7000) += es7000.o | ||
| 12 | obj-$(CONFIG_X86_ES7000) += ../../x86/mach-es7000/ | ||
diff --git a/arch/x86/mach-generic/bigsmp.c b/arch/x86/mach-generic/bigsmp.c index 95fc463056d0..59d771714559 100644 --- a/arch/x86/mach-generic/bigsmp.c +++ b/arch/x86/mach-generic/bigsmp.c | |||
| @@ -23,10 +23,8 @@ static int dmi_bigsmp; /* can be set by dmi scanners */ | |||
| 23 | 23 | ||
| 24 | static int hp_ht_bigsmp(const struct dmi_system_id *d) | 24 | static int hp_ht_bigsmp(const struct dmi_system_id *d) |
| 25 | { | 25 | { |
| 26 | #ifdef CONFIG_X86_GENERICARCH | ||
| 27 | printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); | 26 | printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); |
| 28 | dmi_bigsmp = 1; | 27 | dmi_bigsmp = 1; |
| 29 | #endif | ||
| 30 | return 0; | 28 | return 0; |
| 31 | } | 29 | } |
| 32 | 30 | ||
| @@ -48,7 +46,7 @@ static const struct dmi_system_id bigsmp_dmi_table[] = { | |||
| 48 | static int probe_bigsmp(void) | 46 | static int probe_bigsmp(void) |
| 49 | { | 47 | { |
| 50 | if (def_to_bigsmp) | 48 | if (def_to_bigsmp) |
| 51 | dmi_bigsmp = 1; | 49 | dmi_bigsmp = 1; |
| 52 | else | 50 | else |
| 53 | dmi_check_system(bigsmp_dmi_table); | 51 | dmi_check_system(bigsmp_dmi_table); |
| 54 | return dmi_bigsmp; | 52 | return dmi_bigsmp; |
diff --git a/arch/x86/mach-generic/numaq.c b/arch/x86/mach-generic/numaq.c new file mode 100644 index 000000000000..8091e68764c4 --- /dev/null +++ b/arch/x86/mach-generic/numaq.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * APIC driver for the IBM NUMAQ chipset. | ||
| 3 | */ | ||
| 4 | #define APIC_DEFINITION 1 | ||
| 5 | #include <linux/threads.h> | ||
| 6 | #include <linux/cpumask.h> | ||
| 7 | #include <linux/smp.h> | ||
| 8 | #include <asm/mpspec.h> | ||
| 9 | #include <asm/genapic.h> | ||
| 10 | #include <asm/fixmap.h> | ||
| 11 | #include <asm/apicdef.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/string.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <asm/mach-numaq/mach_apic.h> | ||
| 16 | #include <asm/mach-numaq/mach_apicdef.h> | ||
| 17 | #include <asm/mach-numaq/mach_ipi.h> | ||
| 18 | #include <asm/mach-numaq/mach_mpparse.h> | ||
| 19 | #include <asm/mach-numaq/mach_wakecpu.h> | ||
| 20 | #include <asm/numaq.h> | ||
| 21 | |||
| 22 | static int mps_oem_check(struct mp_config_table *mpc, char *oem, | ||
| 23 | char *productid) | ||
| 24 | { | ||
| 25 | numaq_mps_oem_check(mpc, oem, productid); | ||
| 26 | return found_numaq; | ||
| 27 | } | ||
| 28 | |||
| 29 | static int probe_numaq(void) | ||
| 30 | { | ||
| 31 | /* already know from get_memcfg_numaq() */ | ||
| 32 | return found_numaq; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* Hook from generic ACPI tables.c */ | ||
| 36 | static int acpi_madt_oem_check(char *oem_id, char *oem_table_id) | ||
| 37 | { | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | struct genapic apic_numaq = APIC_INIT("NUMAQ", probe_numaq); | ||
diff --git a/arch/x86/mach-generic/probe.c b/arch/x86/mach-generic/probe.c index c5ae751b994a..5a7e4619e1c4 100644 --- a/arch/x86/mach-generic/probe.c +++ b/arch/x86/mach-generic/probe.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <asm/apicdef.h> | 16 | #include <asm/apicdef.h> |
| 17 | #include <asm/genapic.h> | 17 | #include <asm/genapic.h> |
| 18 | 18 | ||
| 19 | extern struct genapic apic_numaq; | ||
| 19 | extern struct genapic apic_summit; | 20 | extern struct genapic apic_summit; |
| 20 | extern struct genapic apic_bigsmp; | 21 | extern struct genapic apic_bigsmp; |
| 21 | extern struct genapic apic_es7000; | 22 | extern struct genapic apic_es7000; |
| @@ -24,9 +25,18 @@ extern struct genapic apic_default; | |||
| 24 | struct genapic *genapic = &apic_default; | 25 | struct genapic *genapic = &apic_default; |
| 25 | 26 | ||
| 26 | static struct genapic *apic_probe[] __initdata = { | 27 | static struct genapic *apic_probe[] __initdata = { |
| 28 | #ifdef CONFIG_X86_NUMAQ | ||
| 29 | &apic_numaq, | ||
| 30 | #endif | ||
| 31 | #ifdef CONFIG_X86_SUMMIT | ||
| 27 | &apic_summit, | 32 | &apic_summit, |
| 33 | #endif | ||
| 34 | #ifdef CONFIG_X86_BIGSMP | ||
| 28 | &apic_bigsmp, | 35 | &apic_bigsmp, |
| 36 | #endif | ||
| 37 | #ifdef CONFIG_X86_ES7000 | ||
| 29 | &apic_es7000, | 38 | &apic_es7000, |
| 39 | #endif | ||
| 30 | &apic_default, /* must be last */ | 40 | &apic_default, /* must be last */ |
| 31 | NULL, | 41 | NULL, |
| 32 | }; | 42 | }; |
| @@ -54,6 +64,7 @@ early_param("apic", parse_apic); | |||
| 54 | 64 | ||
| 55 | void __init generic_bigsmp_probe(void) | 65 | void __init generic_bigsmp_probe(void) |
| 56 | { | 66 | { |
| 67 | #ifdef CONFIG_X86_BIGSMP | ||
| 57 | /* | 68 | /* |
| 58 | * This routine is used to switch to bigsmp mode when | 69 | * This routine is used to switch to bigsmp mode when |
| 59 | * - There is no apic= option specified by the user | 70 | * - There is no apic= option specified by the user |
| @@ -67,6 +78,7 @@ void __init generic_bigsmp_probe(void) | |||
| 67 | printk(KERN_INFO "Overriding APIC driver with %s\n", | 78 | printk(KERN_INFO "Overriding APIC driver with %s\n", |
| 68 | genapic->name); | 79 | genapic->name); |
| 69 | } | 80 | } |
| 81 | #endif | ||
| 70 | } | 82 | } |
| 71 | 83 | ||
| 72 | void __init generic_apic_probe(void) | 84 | void __init generic_apic_probe(void) |
| @@ -88,7 +100,8 @@ void __init generic_apic_probe(void) | |||
| 88 | 100 | ||
| 89 | /* These functions can switch the APIC even after the initial ->probe() */ | 101 | /* These functions can switch the APIC even after the initial ->probe() */ |
| 90 | 102 | ||
| 91 | int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) | 103 | int __init mps_oem_check(struct mp_config_table *mpc, char *oem, |
| 104 | char *productid) | ||
| 92 | { | 105 | { |
| 93 | int i; | 106 | int i; |
| 94 | for (i = 0; apic_probe[i]; ++i) { | 107 | for (i = 0; apic_probe[i]; ++i) { |
diff --git a/arch/x86/mach-visws/mpparse.c b/arch/x86/mach-visws/mpparse.c index 57484e91ab90..a2fb78c0d154 100644 --- a/arch/x86/mach-visws/mpparse.c +++ b/arch/x86/mach-visws/mpparse.c | |||
| @@ -8,11 +8,6 @@ | |||
| 8 | #include "cobalt.h" | 8 | #include "cobalt.h" |
| 9 | #include "mach_apic.h" | 9 | #include "mach_apic.h" |
| 10 | 10 | ||
| 11 | /* Have we found an MP table */ | ||
| 12 | int smp_found_config; | ||
| 13 | |||
| 14 | int pic_mode; | ||
| 15 | |||
| 16 | extern unsigned int __cpuinitdata maxcpus; | 11 | extern unsigned int __cpuinitdata maxcpus; |
| 17 | 12 | ||
| 18 | /* | 13 | /* |
| @@ -76,7 +71,9 @@ void __init find_smp_config(void) | |||
| 76 | if (ncpus > maxcpus) | 71 | if (ncpus > maxcpus) |
| 77 | ncpus = maxcpus; | 72 | ncpus = maxcpus; |
| 78 | 73 | ||
| 74 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 79 | smp_found_config = 1; | 75 | smp_found_config = 1; |
| 76 | #endif | ||
| 80 | while (ncpus--) | 77 | while (ncpus--) |
| 81 | MP_processor_info(mp++); | 78 | MP_processor_info(mp++); |
| 82 | 79 | ||
diff --git a/arch/x86/mach-visws/setup.c b/arch/x86/mach-visws/setup.c index de4c9dbd086f..d67868ec9b7f 100644 --- a/arch/x86/mach-visws/setup.c +++ b/arch/x86/mach-visws/setup.c | |||
| @@ -175,9 +175,9 @@ char * __init machine_specific_memory_setup(void) | |||
| 175 | sgivwfb_mem_size &= ~((1 << 20) - 1); | 175 | sgivwfb_mem_size &= ~((1 << 20) - 1); |
| 176 | sgivwfb_mem_phys = mem_size - gfx_mem_size; | 176 | sgivwfb_mem_phys = mem_size - gfx_mem_size; |
| 177 | 177 | ||
| 178 | add_memory_region(0, LOWMEMSIZE(), E820_RAM); | 178 | e820_add_region(0, LOWMEMSIZE(), E820_RAM); |
| 179 | add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM); | 179 | e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM); |
| 180 | add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED); | 180 | e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED); |
| 181 | 181 | ||
| 182 | return "PROM"; | 182 | return "PROM"; |
| 183 | } | 183 | } |
diff --git a/arch/x86/mach-voyager/setup.c b/arch/x86/mach-voyager/setup.c index 5ae5466b9eb9..6bbdd633864c 100644 --- a/arch/x86/mach-voyager/setup.c +++ b/arch/x86/mach-voyager/setup.c | |||
| @@ -62,6 +62,7 @@ void __init time_init_hook(void) | |||
| 62 | char *__init machine_specific_memory_setup(void) | 62 | char *__init machine_specific_memory_setup(void) |
| 63 | { | 63 | { |
| 64 | char *who; | 64 | char *who; |
| 65 | int new_nr; | ||
| 65 | 66 | ||
| 66 | who = "NOT VOYAGER"; | 67 | who = "NOT VOYAGER"; |
| 67 | 68 | ||
| @@ -73,7 +74,7 @@ char *__init machine_specific_memory_setup(void) | |||
| 73 | 74 | ||
| 74 | e820.nr_map = 0; | 75 | e820.nr_map = 0; |
| 75 | for (i = 0; voyager_memory_detect(i, &addr, &length); i++) { | 76 | for (i = 0; voyager_memory_detect(i, &addr, &length); i++) { |
| 76 | add_memory_region(addr, length, E820_RAM); | 77 | e820_add_region(addr, length, E820_RAM); |
| 77 | } | 78 | } |
| 78 | return who; | 79 | return who; |
| 79 | } else if (voyager_level == 4) { | 80 | } else if (voyager_level == 4) { |
| @@ -91,43 +92,17 @@ char *__init machine_specific_memory_setup(void) | |||
| 91 | tom = (boot_params.screen_info.ext_mem_k) << 10; | 92 | tom = (boot_params.screen_info.ext_mem_k) << 10; |
| 92 | } | 93 | } |
| 93 | who = "Voyager-TOM"; | 94 | who = "Voyager-TOM"; |
| 94 | add_memory_region(0, 0x9f000, E820_RAM); | 95 | e820_add_region(0, 0x9f000, E820_RAM); |
| 95 | /* map from 1M to top of memory */ | 96 | /* map from 1M to top of memory */ |
| 96 | add_memory_region(1 * 1024 * 1024, tom - 1 * 1024 * 1024, | 97 | e820_add_region(1 * 1024 * 1024, tom - 1 * 1024 * 1024, |
| 97 | E820_RAM); | 98 | E820_RAM); |
| 98 | /* FIXME: Should check the ASICs to see if I need to | 99 | /* FIXME: Should check the ASICs to see if I need to |
| 99 | * take out the 8M window. Just do it at the moment | 100 | * take out the 8M window. Just do it at the moment |
| 100 | * */ | 101 | * */ |
| 101 | add_memory_region(8 * 1024 * 1024, 8 * 1024 * 1024, | 102 | e820_add_region(8 * 1024 * 1024, 8 * 1024 * 1024, |
| 102 | E820_RESERVED); | 103 | E820_RESERVED); |
| 103 | return who; | 104 | return who; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | who = "BIOS-e820"; | 107 | return default_machine_specific_memory_setup(); |
| 107 | |||
| 108 | /* | ||
| 109 | * Try to copy the BIOS-supplied E820-map. | ||
| 110 | * | ||
| 111 | * Otherwise fake a memory map; one section from 0k->640k, | ||
| 112 | * the next section from 1mb->appropriate_mem_k | ||
| 113 | */ | ||
| 114 | sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries); | ||
| 115 | if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) | ||
| 116 | < 0) { | ||
| 117 | unsigned long mem_size; | ||
| 118 | |||
| 119 | /* compare results from other methods and take the greater */ | ||
| 120 | if (boot_params.alt_mem_k < boot_params.screen_info.ext_mem_k) { | ||
| 121 | mem_size = boot_params.screen_info.ext_mem_k; | ||
| 122 | who = "BIOS-88"; | ||
| 123 | } else { | ||
| 124 | mem_size = boot_params.alt_mem_k; | ||
| 125 | who = "BIOS-e801"; | ||
| 126 | } | ||
| 127 | |||
| 128 | e820.nr_map = 0; | ||
| 129 | add_memory_region(0, LOWMEMSIZE(), E820_RAM); | ||
| 130 | add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); | ||
| 131 | } | ||
| 132 | return who; | ||
| 133 | } | 108 | } |
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c index 8acbf0cdf1a5..8dedd01e909f 100644 --- a/arch/x86/mach-voyager/voyager_smp.c +++ b/arch/x86/mach-voyager/voyager_smp.c | |||
| @@ -59,11 +59,6 @@ __u32 voyager_quad_processors = 0; | |||
| 59 | * activity count. Finally exported by i386_ksyms.c */ | 59 | * activity count. Finally exported by i386_ksyms.c */ |
| 60 | static int voyager_extended_cpus = 1; | 60 | static int voyager_extended_cpus = 1; |
| 61 | 61 | ||
| 62 | /* Have we found an SMP box - used by time.c to do the profiling | ||
| 63 | interrupt for timeslicing; do not set to 1 until the per CPU timer | ||
| 64 | interrupt is active */ | ||
| 65 | int smp_found_config = 0; | ||
| 66 | |||
| 67 | /* Used for the invalidate map that's also checked in the spinlock */ | 62 | /* Used for the invalidate map that's also checked in the spinlock */ |
| 68 | static volatile unsigned long smp_invalidate_needed; | 63 | static volatile unsigned long smp_invalidate_needed; |
| 69 | 64 | ||
| @@ -1137,15 +1132,6 @@ void flush_tlb_all(void) | |||
| 1137 | on_each_cpu(do_flush_tlb_all, 0, 1, 1); | 1132 | on_each_cpu(do_flush_tlb_all, 0, 1, 1); |
| 1138 | } | 1133 | } |
| 1139 | 1134 | ||
| 1140 | /* used to set up the trampoline for other CPUs when the memory manager | ||
| 1141 | * is sorted out */ | ||
| 1142 | void __init smp_alloc_memory(void) | ||
| 1143 | { | ||
| 1144 | trampoline_base = alloc_bootmem_low_pages(PAGE_SIZE); | ||
| 1145 | if (__pa(trampoline_base) >= 0x93000) | ||
| 1146 | BUG(); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | /* send a reschedule CPI to one CPU by physical CPU number*/ | 1135 | /* send a reschedule CPI to one CPU by physical CPU number*/ |
| 1150 | static void voyager_smp_send_reschedule(int cpu) | 1136 | static void voyager_smp_send_reschedule(int cpu) |
| 1151 | { | 1137 | { |
diff --git a/arch/x86/mm/discontig_32.c b/arch/x86/mm/discontig_32.c index 8b4eac0ca07d..a2f73ba42b8b 100644 --- a/arch/x86/mm/discontig_32.c +++ b/arch/x86/mm/discontig_32.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <asm/setup.h> | 38 | #include <asm/setup.h> |
| 39 | #include <asm/mmzone.h> | 39 | #include <asm/mmzone.h> |
| 40 | #include <asm/bios_ebda.h> | 40 | #include <asm/bios_ebda.h> |
| 41 | #include <asm/proto.h> | ||
| 41 | 42 | ||
| 42 | struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; | 43 | struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; |
| 43 | EXPORT_SYMBOL(node_data); | 44 | EXPORT_SYMBOL(node_data); |
| @@ -59,14 +60,14 @@ unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly; | |||
| 59 | /* | 60 | /* |
| 60 | * 4) physnode_map - the mapping between a pfn and owning node | 61 | * 4) physnode_map - the mapping between a pfn and owning node |
| 61 | * physnode_map keeps track of the physical memory layout of a generic | 62 | * physnode_map keeps track of the physical memory layout of a generic |
| 62 | * numa node on a 256Mb break (each element of the array will | 63 | * numa node on a 64Mb break (each element of the array will |
| 63 | * represent 256Mb of memory and will be marked by the node id. so, | 64 | * represent 64Mb of memory and will be marked by the node id. so, |
| 64 | * if the first gig is on node 0, and the second gig is on node 1 | 65 | * if the first gig is on node 0, and the second gig is on node 1 |
| 65 | * physnode_map will contain: | 66 | * physnode_map will contain: |
| 66 | * | 67 | * |
| 67 | * physnode_map[0-3] = 0; | 68 | * physnode_map[0-15] = 0; |
| 68 | * physnode_map[4-7] = 1; | 69 | * physnode_map[16-31] = 1; |
| 69 | * physnode_map[8- ] = -1; | 70 | * physnode_map[32- ] = -1; |
| 70 | */ | 71 | */ |
| 71 | s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1}; | 72 | s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1}; |
| 72 | EXPORT_SYMBOL(physnode_map); | 73 | EXPORT_SYMBOL(physnode_map); |
| @@ -81,9 +82,9 @@ void memory_present(int nid, unsigned long start, unsigned long end) | |||
| 81 | printk(KERN_DEBUG " "); | 82 | printk(KERN_DEBUG " "); |
| 82 | for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) { | 83 | for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) { |
| 83 | physnode_map[pfn / PAGES_PER_ELEMENT] = nid; | 84 | physnode_map[pfn / PAGES_PER_ELEMENT] = nid; |
| 84 | printk("%ld ", pfn); | 85 | printk(KERN_CONT "%ld ", pfn); |
| 85 | } | 86 | } |
| 86 | printk("\n"); | 87 | printk(KERN_CONT "\n"); |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, | 90 | unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, |
| @@ -99,7 +100,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, | |||
| 99 | #endif | 100 | #endif |
| 100 | 101 | ||
| 101 | extern unsigned long find_max_low_pfn(void); | 102 | extern unsigned long find_max_low_pfn(void); |
| 102 | extern void add_one_highpage_init(struct page *, int, int); | ||
| 103 | extern unsigned long highend_pfn, highstart_pfn; | 103 | extern unsigned long highend_pfn, highstart_pfn; |
| 104 | 104 | ||
| 105 | #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) | 105 | #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) |
| @@ -119,11 +119,11 @@ int __init get_memcfg_numa_flat(void) | |||
| 119 | { | 119 | { |
| 120 | printk("NUMA - single node, flat memory mode\n"); | 120 | printk("NUMA - single node, flat memory mode\n"); |
| 121 | 121 | ||
| 122 | /* Run the memory configuration and find the top of memory. */ | ||
| 123 | propagate_e820_map(); | ||
| 124 | node_start_pfn[0] = 0; | 122 | node_start_pfn[0] = 0; |
| 125 | node_end_pfn[0] = max_pfn; | 123 | node_end_pfn[0] = max_pfn; |
| 124 | e820_register_active_regions(0, 0, max_pfn); | ||
| 126 | memory_present(0, 0, max_pfn); | 125 | memory_present(0, 0, max_pfn); |
| 126 | node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn); | ||
| 127 | 127 | ||
| 128 | /* Indicate there is one node available. */ | 128 | /* Indicate there is one node available. */ |
| 129 | nodes_clear(node_online_map); | 129 | nodes_clear(node_online_map); |
| @@ -159,9 +159,17 @@ static void __init allocate_pgdat(int nid) | |||
| 159 | if (nid && node_has_online_mem(nid) && node_remap_start_vaddr[nid]) | 159 | if (nid && node_has_online_mem(nid) && node_remap_start_vaddr[nid]) |
| 160 | NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid]; | 160 | NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid]; |
| 161 | else { | 161 | else { |
| 162 | NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(min_low_pfn)); | 162 | unsigned long pgdat_phys; |
| 163 | min_low_pfn += PFN_UP(sizeof(pg_data_t)); | 163 | pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT, |
| 164 | (nid ? max_low_pfn:max_pfn_mapped)<<PAGE_SHIFT, | ||
| 165 | sizeof(pg_data_t), | ||
| 166 | PAGE_SIZE); | ||
| 167 | NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT)); | ||
| 168 | reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), | ||
| 169 | "NODE_DATA"); | ||
| 164 | } | 170 | } |
| 171 | printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n", | ||
| 172 | nid, (unsigned long)NODE_DATA(nid)); | ||
| 165 | } | 173 | } |
| 166 | 174 | ||
| 167 | /* | 175 | /* |
| @@ -199,8 +207,12 @@ void __init remap_numa_kva(void) | |||
| 199 | int node; | 207 | int node; |
| 200 | 208 | ||
| 201 | for_each_online_node(node) { | 209 | for_each_online_node(node) { |
| 210 | printk(KERN_DEBUG "remap_numa_kva: node %d\n", node); | ||
| 202 | for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) { | 211 | for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) { |
| 203 | vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT); | 212 | vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT); |
| 213 | printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n", | ||
| 214 | (unsigned long)vaddr, | ||
| 215 | node_remap_start_pfn[node] + pfn); | ||
| 204 | set_pmd_pfn((ulong) vaddr, | 216 | set_pmd_pfn((ulong) vaddr, |
| 205 | node_remap_start_pfn[node] + pfn, | 217 | node_remap_start_pfn[node] + pfn, |
| 206 | PAGE_KERNEL_LARGE); | 218 | PAGE_KERNEL_LARGE); |
| @@ -212,17 +224,21 @@ static unsigned long calculate_numa_remap_pages(void) | |||
| 212 | { | 224 | { |
| 213 | int nid; | 225 | int nid; |
| 214 | unsigned long size, reserve_pages = 0; | 226 | unsigned long size, reserve_pages = 0; |
| 215 | unsigned long pfn; | ||
| 216 | 227 | ||
| 217 | for_each_online_node(nid) { | 228 | for_each_online_node(nid) { |
| 218 | unsigned old_end_pfn = node_end_pfn[nid]; | 229 | u64 node_kva_target; |
| 230 | u64 node_kva_final; | ||
| 219 | 231 | ||
| 220 | /* | 232 | /* |
| 221 | * The acpi/srat node info can show hot-add memroy zones | 233 | * The acpi/srat node info can show hot-add memroy zones |
| 222 | * where memory could be added but not currently present. | 234 | * where memory could be added but not currently present. |
| 223 | */ | 235 | */ |
| 236 | printk("node %d pfn: [%lx - %lx]\n", | ||
| 237 | nid, node_start_pfn[nid], node_end_pfn[nid]); | ||
| 224 | if (node_start_pfn[nid] > max_pfn) | 238 | if (node_start_pfn[nid] > max_pfn) |
| 225 | continue; | 239 | continue; |
| 240 | if (!node_end_pfn[nid]) | ||
| 241 | continue; | ||
| 226 | if (node_end_pfn[nid] > max_pfn) | 242 | if (node_end_pfn[nid] > max_pfn) |
| 227 | node_end_pfn[nid] = max_pfn; | 243 | node_end_pfn[nid] = max_pfn; |
| 228 | 244 | ||
| @@ -234,39 +250,45 @@ static unsigned long calculate_numa_remap_pages(void) | |||
| 234 | /* now the roundup is correct, convert to PAGE_SIZE pages */ | 250 | /* now the roundup is correct, convert to PAGE_SIZE pages */ |
| 235 | size = size * PTRS_PER_PTE; | 251 | size = size * PTRS_PER_PTE; |
| 236 | 252 | ||
| 237 | /* | 253 | node_kva_target = round_down(node_end_pfn[nid] - size, |
| 238 | * Validate the region we are allocating only contains valid | 254 | PTRS_PER_PTE); |
| 239 | * pages. | 255 | node_kva_target <<= PAGE_SHIFT; |
| 240 | */ | 256 | do { |
| 241 | for (pfn = node_end_pfn[nid] - size; | 257 | node_kva_final = find_e820_area(node_kva_target, |
| 242 | pfn < node_end_pfn[nid]; pfn++) | 258 | ((u64)node_end_pfn[nid])<<PAGE_SHIFT, |
| 243 | if (!page_is_ram(pfn)) | 259 | ((u64)size)<<PAGE_SHIFT, |
| 244 | break; | 260 | LARGE_PAGE_BYTES); |
| 261 | node_kva_target -= LARGE_PAGE_BYTES; | ||
| 262 | } while (node_kva_final == -1ULL && | ||
| 263 | (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid])); | ||
| 264 | |||
| 265 | if (node_kva_final == -1ULL) | ||
| 266 | panic("Can not get kva ram\n"); | ||
| 245 | 267 | ||
| 246 | if (pfn != node_end_pfn[nid]) | ||
| 247 | size = 0; | ||
| 248 | |||
| 249 | printk("Reserving %ld pages of KVA for lmem_map of node %d\n", | ||
| 250 | size, nid); | ||
| 251 | node_remap_size[nid] = size; | 268 | node_remap_size[nid] = size; |
| 252 | node_remap_offset[nid] = reserve_pages; | 269 | node_remap_offset[nid] = reserve_pages; |
| 253 | reserve_pages += size; | 270 | reserve_pages += size; |
| 254 | printk("Shrinking node %d from %ld pages to %ld pages\n", | 271 | printk("Reserving %ld pages of KVA for lmem_map of node %d at %llx\n", |
| 255 | nid, node_end_pfn[nid], node_end_pfn[nid] - size); | 272 | size, nid, node_kva_final>>PAGE_SHIFT); |
| 256 | 273 | ||
| 257 | if (node_end_pfn[nid] & (PTRS_PER_PTE-1)) { | 274 | /* |
| 258 | /* | 275 | * prevent kva address below max_low_pfn want it on system |
| 259 | * Align node_end_pfn[] and node_remap_start_pfn[] to | 276 | * with less memory later. |
| 260 | * pmd boundary. remap_numa_kva will barf otherwise. | 277 | * layout will be: KVA address , KVA RAM |
| 261 | */ | 278 | * |
| 262 | printk("Shrinking node %d further by %ld pages for proper alignment\n", | 279 | * we are supposed to only record the one less then max_low_pfn |
| 263 | nid, node_end_pfn[nid] & (PTRS_PER_PTE-1)); | 280 | * but we could have some hole in high memory, and it will only |
| 264 | size += node_end_pfn[nid] & (PTRS_PER_PTE-1); | 281 | * check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide |
| 265 | } | 282 | * to use it as free. |
| 283 | * So reserve_early here, hope we don't run out of that array | ||
| 284 | */ | ||
| 285 | reserve_early(node_kva_final, | ||
| 286 | node_kva_final+(((u64)size)<<PAGE_SHIFT), | ||
| 287 | "KVA RAM"); | ||
| 266 | 288 | ||
| 267 | node_end_pfn[nid] -= size; | 289 | node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT; |
| 268 | node_remap_start_pfn[nid] = node_end_pfn[nid]; | 290 | remove_active_range(nid, node_remap_start_pfn[nid], |
| 269 | shrink_active_range(nid, old_end_pfn, node_end_pfn[nid]); | 291 | node_remap_start_pfn[nid] + size); |
| 270 | } | 292 | } |
| 271 | printk("Reserving total of %ld pages for numa KVA remap\n", | 293 | printk("Reserving total of %ld pages for numa KVA remap\n", |
| 272 | reserve_pages); | 294 | reserve_pages); |
| @@ -284,8 +306,7 @@ static void init_remap_allocator(int nid) | |||
| 284 | 306 | ||
| 285 | printk ("node %d will remap to vaddr %08lx - %08lx\n", nid, | 307 | printk ("node %d will remap to vaddr %08lx - %08lx\n", nid, |
| 286 | (ulong) node_remap_start_vaddr[nid], | 308 | (ulong) node_remap_start_vaddr[nid], |
| 287 | (ulong) pfn_to_kaddr(highstart_pfn | 309 | (ulong) node_remap_end_vaddr[nid]); |
| 288 | + node_remap_offset[nid] + node_remap_size[nid])); | ||
| 289 | } | 310 | } |
| 290 | 311 | ||
| 291 | extern void setup_bootmem_allocator(void); | 312 | extern void setup_bootmem_allocator(void); |
| @@ -293,7 +314,7 @@ unsigned long __init setup_memory(void) | |||
| 293 | { | 314 | { |
| 294 | int nid; | 315 | int nid; |
| 295 | unsigned long system_start_pfn, system_max_low_pfn; | 316 | unsigned long system_start_pfn, system_max_low_pfn; |
| 296 | unsigned long wasted_pages; | 317 | long kva_target_pfn; |
| 297 | 318 | ||
| 298 | /* | 319 | /* |
| 299 | * When mapping a NUMA machine we allocate the node_mem_map arrays | 320 | * When mapping a NUMA machine we allocate the node_mem_map arrays |
| @@ -302,34 +323,38 @@ unsigned long __init setup_memory(void) | |||
| 302 | * this space and use it to adjust the boundary between ZONE_NORMAL | 323 | * this space and use it to adjust the boundary between ZONE_NORMAL |
| 303 | * and ZONE_HIGHMEM. | 324 | * and ZONE_HIGHMEM. |
| 304 | */ | 325 | */ |
| 326 | |||
| 327 | /* call find_max_low_pfn at first, it could update max_pfn */ | ||
| 328 | system_max_low_pfn = max_low_pfn = find_max_low_pfn(); | ||
| 329 | |||
| 330 | remove_all_active_ranges(); | ||
| 305 | get_memcfg_numa(); | 331 | get_memcfg_numa(); |
| 306 | 332 | ||
| 307 | kva_pages = calculate_numa_remap_pages(); | 333 | kva_pages = round_up(calculate_numa_remap_pages(), PTRS_PER_PTE); |
| 308 | 334 | ||
| 309 | /* partially used pages are not usable - thus round upwards */ | 335 | /* partially used pages are not usable - thus round upwards */ |
| 310 | system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end); | 336 | system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end); |
| 311 | 337 | ||
| 312 | kva_start_pfn = find_max_low_pfn() - kva_pages; | 338 | kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE); |
| 313 | 339 | do { | |
| 314 | #ifdef CONFIG_BLK_DEV_INITRD | 340 | kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT, |
| 315 | /* Numa kva area is below the initrd */ | 341 | max_low_pfn<<PAGE_SHIFT, |
| 316 | if (initrd_start) | 342 | kva_pages<<PAGE_SHIFT, |
| 317 | kva_start_pfn = PFN_DOWN(initrd_start - PAGE_OFFSET) | 343 | PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT; |
| 318 | - kva_pages; | 344 | kva_target_pfn -= PTRS_PER_PTE; |
| 319 | #endif | 345 | } while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn); |
| 320 | 346 | ||
| 321 | /* | 347 | if (kva_start_pfn == -1UL) |
| 322 | * We waste pages past at the end of the KVA for no good reason other | 348 | panic("Can not get kva space\n"); |
| 323 | * than how it is located. This is bad. | ||
| 324 | */ | ||
| 325 | wasted_pages = kva_start_pfn & (PTRS_PER_PTE-1); | ||
| 326 | kva_start_pfn -= wasted_pages; | ||
| 327 | kva_pages += wasted_pages; | ||
| 328 | 349 | ||
| 329 | system_max_low_pfn = max_low_pfn = find_max_low_pfn(); | ||
| 330 | printk("kva_start_pfn ~ %ld find_max_low_pfn() ~ %ld\n", | 350 | printk("kva_start_pfn ~ %ld find_max_low_pfn() ~ %ld\n", |
| 331 | kva_start_pfn, max_low_pfn); | 351 | kva_start_pfn, max_low_pfn); |
| 332 | printk("max_pfn = %ld\n", max_pfn); | 352 | printk("max_pfn = %ld\n", max_pfn); |
| 353 | |||
| 354 | /* avoid clash with initrd */ | ||
| 355 | reserve_early(kva_start_pfn<<PAGE_SHIFT, | ||
| 356 | (kva_start_pfn + kva_pages)<<PAGE_SHIFT, | ||
| 357 | "KVA PG"); | ||
| 333 | #ifdef CONFIG_HIGHMEM | 358 | #ifdef CONFIG_HIGHMEM |
| 334 | highstart_pfn = highend_pfn = max_pfn; | 359 | highstart_pfn = highend_pfn = max_pfn; |
| 335 | if (max_pfn > system_max_low_pfn) | 360 | if (max_pfn > system_max_low_pfn) |
| @@ -365,16 +390,8 @@ unsigned long __init setup_memory(void) | |||
| 365 | return max_low_pfn; | 390 | return max_low_pfn; |
| 366 | } | 391 | } |
| 367 | 392 | ||
| 368 | void __init numa_kva_reserve(void) | ||
| 369 | { | ||
| 370 | if (kva_pages) | ||
| 371 | reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages), | ||
| 372 | BOOTMEM_DEFAULT); | ||
| 373 | } | ||
| 374 | |||
| 375 | void __init zone_sizes_init(void) | 393 | void __init zone_sizes_init(void) |
| 376 | { | 394 | { |
| 377 | int nid; | ||
| 378 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | 395 | unsigned long max_zone_pfns[MAX_NR_ZONES]; |
| 379 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); | 396 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); |
| 380 | max_zone_pfns[ZONE_DMA] = | 397 | max_zone_pfns[ZONE_DMA] = |
| @@ -384,27 +401,18 @@ void __init zone_sizes_init(void) | |||
| 384 | max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; | 401 | max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; |
| 385 | #endif | 402 | #endif |
| 386 | 403 | ||
| 387 | /* If SRAT has not registered memory, register it now */ | ||
| 388 | if (find_max_pfn_with_active_regions() == 0) { | ||
| 389 | for_each_online_node(nid) { | ||
| 390 | if (node_has_online_mem(nid)) | ||
| 391 | add_active_range(nid, node_start_pfn[nid], | ||
| 392 | node_end_pfn[nid]); | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | free_area_init_nodes(max_zone_pfns); | 404 | free_area_init_nodes(max_zone_pfns); |
| 397 | return; | 405 | return; |
| 398 | } | 406 | } |
| 399 | 407 | ||
| 400 | void __init set_highmem_pages_init(int bad_ppro) | 408 | void __init set_highmem_pages_init(void) |
| 401 | { | 409 | { |
| 402 | #ifdef CONFIG_HIGHMEM | 410 | #ifdef CONFIG_HIGHMEM |
| 403 | struct zone *zone; | 411 | struct zone *zone; |
| 404 | struct page *page; | 412 | int nid; |
| 405 | 413 | ||
| 406 | for_each_zone(zone) { | 414 | for_each_zone(zone) { |
| 407 | unsigned long node_pfn, zone_start_pfn, zone_end_pfn; | 415 | unsigned long zone_start_pfn, zone_end_pfn; |
| 408 | 416 | ||
| 409 | if (!is_highmem(zone)) | 417 | if (!is_highmem(zone)) |
| 410 | continue; | 418 | continue; |
| @@ -412,16 +420,12 @@ void __init set_highmem_pages_init(int bad_ppro) | |||
| 412 | zone_start_pfn = zone->zone_start_pfn; | 420 | zone_start_pfn = zone->zone_start_pfn; |
| 413 | zone_end_pfn = zone_start_pfn + zone->spanned_pages; | 421 | zone_end_pfn = zone_start_pfn + zone->spanned_pages; |
| 414 | 422 | ||
| 423 | nid = zone_to_nid(zone); | ||
| 415 | printk("Initializing %s for node %d (%08lx:%08lx)\n", | 424 | printk("Initializing %s for node %d (%08lx:%08lx)\n", |
| 416 | zone->name, zone_to_nid(zone), | 425 | zone->name, nid, zone_start_pfn, zone_end_pfn); |
| 417 | zone_start_pfn, zone_end_pfn); | 426 | |
| 418 | 427 | add_highpages_with_active_regions(nid, zone_start_pfn, | |
| 419 | for (node_pfn = zone_start_pfn; node_pfn < zone_end_pfn; node_pfn++) { | 428 | zone_end_pfn); |
| 420 | if (!pfn_valid(node_pfn)) | ||
| 421 | continue; | ||
| 422 | page = pfn_to_page(node_pfn); | ||
| 423 | add_one_highpage_init(page, node_pfn, bad_ppro); | ||
| 424 | } | ||
| 425 | } | 429 | } |
| 426 | totalram_pages += totalhigh_pages; | 430 | totalram_pages += totalhigh_pages; |
| 427 | #endif | 431 | #endif |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index d71be0eb0130..65d55056b6e7 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
| @@ -225,13 +225,6 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
| 225 | update_page_count(PG_LEVEL_4K, pages_4k); | 225 | update_page_count(PG_LEVEL_4K, pages_4k); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | static inline int page_kills_ppro(unsigned long pagenr) | ||
| 229 | { | ||
| 230 | if (pagenr >= 0x70000 && pagenr <= 0x7003F) | ||
| 231 | return 1; | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | 228 | /* |
| 236 | * devmem_is_allowed() checks to see if /dev/mem access to a certain address | 229 | * devmem_is_allowed() checks to see if /dev/mem access to a certain address |
| 237 | * is valid. The argument is a physical page number. | 230 | * is valid. The argument is a physical page number. |
| @@ -292,29 +285,60 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base) | |||
| 292 | pkmap_page_table = pte; | 285 | pkmap_page_table = pte; |
| 293 | } | 286 | } |
| 294 | 287 | ||
| 295 | void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro) | 288 | static void __init add_one_highpage_init(struct page *page, int pfn) |
| 296 | { | 289 | { |
| 297 | if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { | 290 | ClearPageReserved(page); |
| 298 | ClearPageReserved(page); | 291 | init_page_count(page); |
| 299 | init_page_count(page); | 292 | __free_page(page); |
| 300 | __free_page(page); | 293 | totalhigh_pages++; |
| 301 | totalhigh_pages++; | ||
| 302 | } else | ||
| 303 | SetPageReserved(page); | ||
| 304 | } | 294 | } |
| 305 | 295 | ||
| 306 | #ifndef CONFIG_NUMA | 296 | struct add_highpages_data { |
| 307 | static void __init set_highmem_pages_init(int bad_ppro) | 297 | unsigned long start_pfn; |
| 298 | unsigned long end_pfn; | ||
| 299 | }; | ||
| 300 | |||
| 301 | static void __init add_highpages_work_fn(unsigned long start_pfn, | ||
| 302 | unsigned long end_pfn, void *datax) | ||
| 308 | { | 303 | { |
| 309 | int pfn; | 304 | int node_pfn; |
| 305 | struct page *page; | ||
| 306 | unsigned long final_start_pfn, final_end_pfn; | ||
| 307 | struct add_highpages_data *data; | ||
| 310 | 308 | ||
| 311 | for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) { | 309 | data = (struct add_highpages_data *)datax; |
| 312 | /* | 310 | |
| 313 | * Holes under sparsemem might not have no mem_map[]: | 311 | final_start_pfn = max(start_pfn, data->start_pfn); |
| 314 | */ | 312 | final_end_pfn = min(end_pfn, data->end_pfn); |
| 315 | if (pfn_valid(pfn)) | 313 | if (final_start_pfn >= final_end_pfn) |
| 316 | add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro); | 314 | return; |
| 315 | |||
| 316 | for (node_pfn = final_start_pfn; node_pfn < final_end_pfn; | ||
| 317 | node_pfn++) { | ||
| 318 | if (!pfn_valid(node_pfn)) | ||
| 319 | continue; | ||
| 320 | page = pfn_to_page(node_pfn); | ||
| 321 | add_one_highpage_init(page, node_pfn); | ||
| 317 | } | 322 | } |
| 323 | |||
| 324 | } | ||
| 325 | |||
| 326 | void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn, | ||
| 327 | unsigned long end_pfn) | ||
| 328 | { | ||
| 329 | struct add_highpages_data data; | ||
| 330 | |||
| 331 | data.start_pfn = start_pfn; | ||
| 332 | data.end_pfn = end_pfn; | ||
| 333 | |||
| 334 | work_with_active_regions(nid, add_highpages_work_fn, &data); | ||
| 335 | } | ||
| 336 | |||
| 337 | #ifndef CONFIG_NUMA | ||
| 338 | static void __init set_highmem_pages_init(void) | ||
| 339 | { | ||
| 340 | add_highpages_with_active_regions(0, highstart_pfn, highend_pfn); | ||
| 341 | |||
| 318 | totalram_pages += totalhigh_pages; | 342 | totalram_pages += totalhigh_pages; |
| 319 | } | 343 | } |
| 320 | #endif /* !CONFIG_NUMA */ | 344 | #endif /* !CONFIG_NUMA */ |
| @@ -322,7 +346,7 @@ static void __init set_highmem_pages_init(int bad_ppro) | |||
| 322 | #else | 346 | #else |
| 323 | # define kmap_init() do { } while (0) | 347 | # define kmap_init() do { } while (0) |
| 324 | # define permanent_kmaps_init(pgd_base) do { } while (0) | 348 | # define permanent_kmaps_init(pgd_base) do { } while (0) |
| 325 | # define set_highmem_pages_init(bad_ppro) do { } while (0) | 349 | # define set_highmem_pages_init() do { } while (0) |
| 326 | #endif /* CONFIG_HIGHMEM */ | 350 | #endif /* CONFIG_HIGHMEM */ |
| 327 | 351 | ||
| 328 | pteval_t __PAGE_KERNEL = _PAGE_KERNEL; | 352 | pteval_t __PAGE_KERNEL = _PAGE_KERNEL; |
| @@ -569,13 +593,11 @@ static struct kcore_list kcore_mem, kcore_vmalloc; | |||
| 569 | void __init mem_init(void) | 593 | void __init mem_init(void) |
| 570 | { | 594 | { |
| 571 | int codesize, reservedpages, datasize, initsize; | 595 | int codesize, reservedpages, datasize, initsize; |
| 572 | int tmp, bad_ppro; | 596 | int tmp; |
| 573 | 597 | ||
| 574 | #ifdef CONFIG_FLATMEM | 598 | #ifdef CONFIG_FLATMEM |
| 575 | BUG_ON(!mem_map); | 599 | BUG_ON(!mem_map); |
| 576 | #endif | 600 | #endif |
| 577 | bad_ppro = ppro_with_ram_bug(); | ||
| 578 | |||
| 579 | /* this will put all low memory onto the freelists */ | 601 | /* this will put all low memory onto the freelists */ |
| 580 | totalram_pages += free_all_bootmem(); | 602 | totalram_pages += free_all_bootmem(); |
| 581 | 603 | ||
| @@ -587,7 +609,7 @@ void __init mem_init(void) | |||
| 587 | if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) | 609 | if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) |
| 588 | reservedpages++; | 610 | reservedpages++; |
| 589 | 611 | ||
| 590 | set_highmem_pages_init(bad_ppro); | 612 | set_highmem_pages_init(); |
| 591 | 613 | ||
| 592 | codesize = (unsigned long) &_etext - (unsigned long) &_text; | 614 | codesize = (unsigned long) &_etext - (unsigned long) &_text; |
| 593 | datasize = (unsigned long) &_edata - (unsigned long) &_etext; | 615 | datasize = (unsigned long) &_edata - (unsigned long) &_etext; |
| @@ -776,3 +798,9 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
| 776 | free_init_pages("initrd memory", start, end); | 798 | free_init_pages("initrd memory", start, end); |
| 777 | } | 799 | } |
| 778 | #endif | 800 | #endif |
| 801 | |||
| 802 | int __init reserve_bootmem_generic(unsigned long phys, unsigned long len, | ||
| 803 | int flags) | ||
| 804 | { | ||
| 805 | return reserve_bootmem(phys, len, flags); | ||
| 806 | } | ||
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 48623ae628fb..18c6a006e406 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
| @@ -48,6 +48,18 @@ | |||
| 48 | #include <asm/numa.h> | 48 | #include <asm/numa.h> |
| 49 | #include <asm/cacheflush.h> | 49 | #include <asm/cacheflush.h> |
| 50 | 50 | ||
| 51 | /* | ||
| 52 | * PFN of last memory page. | ||
| 53 | */ | ||
| 54 | unsigned long end_pfn; | ||
| 55 | |||
| 56 | /* | ||
| 57 | * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. | ||
| 58 | * The direct mapping extends to max_pfn_mapped, so that we can directly access | ||
| 59 | * apertures, ACPI and other tables without having to play with fixmaps. | ||
| 60 | */ | ||
| 61 | unsigned long max_pfn_mapped; | ||
| 62 | |||
| 51 | static unsigned long dma_reserve __initdata; | 63 | static unsigned long dma_reserve __initdata; |
| 52 | 64 | ||
| 53 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 65 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
| @@ -808,12 +820,14 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
| 808 | } | 820 | } |
| 809 | #endif | 821 | #endif |
| 810 | 822 | ||
| 811 | void __init reserve_bootmem_generic(unsigned long phys, unsigned len) | 823 | int __init reserve_bootmem_generic(unsigned long phys, unsigned long len, |
| 824 | int flags) | ||
| 812 | { | 825 | { |
| 813 | #ifdef CONFIG_NUMA | 826 | #ifdef CONFIG_NUMA |
| 814 | int nid, next_nid; | 827 | int nid, next_nid; |
| 815 | #endif | 828 | #endif |
| 816 | unsigned long pfn = phys >> PAGE_SHIFT; | 829 | unsigned long pfn = phys >> PAGE_SHIFT; |
| 830 | int ret; | ||
| 817 | 831 | ||
| 818 | if (pfn >= end_pfn) { | 832 | if (pfn >= end_pfn) { |
| 819 | /* | 833 | /* |
| @@ -821,11 +835,11 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) | |||
| 821 | * firmware tables: | 835 | * firmware tables: |
| 822 | */ | 836 | */ |
| 823 | if (pfn < max_pfn_mapped) | 837 | if (pfn < max_pfn_mapped) |
| 824 | return; | 838 | return -EFAULT; |
| 825 | 839 | ||
| 826 | printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", | 840 | printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", |
| 827 | phys, len); | 841 | phys, len); |
| 828 | return; | 842 | return -EFAULT; |
| 829 | } | 843 | } |
| 830 | 844 | ||
| 831 | /* Should check here against the e820 map to avoid double free */ | 845 | /* Should check here against the e820 map to avoid double free */ |
| @@ -833,9 +847,13 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) | |||
| 833 | nid = phys_to_nid(phys); | 847 | nid = phys_to_nid(phys); |
| 834 | next_nid = phys_to_nid(phys + len - 1); | 848 | next_nid = phys_to_nid(phys + len - 1); |
| 835 | if (nid == next_nid) | 849 | if (nid == next_nid) |
| 836 | reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT); | 850 | ret = reserve_bootmem_node(NODE_DATA(nid), phys, len, flags); |
| 837 | else | 851 | else |
| 838 | reserve_bootmem(phys, len, BOOTMEM_DEFAULT); | 852 | ret = reserve_bootmem(phys, len, flags); |
| 853 | |||
| 854 | if (ret != 0) | ||
| 855 | return ret; | ||
| 856 | |||
| 839 | #else | 857 | #else |
| 840 | reserve_bootmem(phys, len, BOOTMEM_DEFAULT); | 858 | reserve_bootmem(phys, len, BOOTMEM_DEFAULT); |
| 841 | #endif | 859 | #endif |
| @@ -844,6 +862,8 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) | |||
| 844 | dma_reserve += len / PAGE_SIZE; | 862 | dma_reserve += len / PAGE_SIZE; |
| 845 | set_dma_reserve(dma_reserve); | 863 | set_dma_reserve(dma_reserve); |
| 846 | } | 864 | } |
| 865 | |||
| 866 | return 0; | ||
| 847 | } | 867 | } |
| 848 | 868 | ||
| 849 | int kern_addr_valid(unsigned long addr) | 869 | int kern_addr_valid(unsigned long addr) |
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c index 0ea66b532c35..317573ec9256 100644 --- a/arch/x86/mm/k8topology_64.c +++ b/arch/x86/mm/k8topology_64.c | |||
| @@ -57,18 +57,22 @@ static __init void early_get_boot_cpu_id(void) | |||
| 57 | /* | 57 | /* |
| 58 | * Find possible boot-time SMP configuration: | 58 | * Find possible boot-time SMP configuration: |
| 59 | */ | 59 | */ |
| 60 | #ifdef CONFIG_X86_MPPARSE | ||
| 60 | early_find_smp_config(); | 61 | early_find_smp_config(); |
| 62 | #endif | ||
| 61 | #ifdef CONFIG_ACPI | 63 | #ifdef CONFIG_ACPI |
| 62 | /* | 64 | /* |
| 63 | * Read APIC information from ACPI tables. | 65 | * Read APIC information from ACPI tables. |
| 64 | */ | 66 | */ |
| 65 | early_acpi_boot_init(); | 67 | early_acpi_boot_init(); |
| 66 | #endif | 68 | #endif |
| 69 | #ifdef CONFIG_X86_MPPARSE | ||
| 67 | /* | 70 | /* |
| 68 | * get boot-time SMP configuration: | 71 | * get boot-time SMP configuration: |
| 69 | */ | 72 | */ |
| 70 | if (smp_found_config) | 73 | if (smp_found_config) |
| 71 | early_get_smp_config(); | 74 | early_get_smp_config(); |
| 75 | #endif | ||
| 72 | early_init_lapic_mapping(); | 76 | early_init_lapic_mapping(); |
| 73 | } | 77 | } |
| 74 | 78 | ||
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index c5066d519e5d..afb07ffb931d 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c | |||
| @@ -233,7 +233,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, | |||
| 233 | else | 233 | else |
| 234 | bootmap_start = round_up(start, PAGE_SIZE); | 234 | bootmap_start = round_up(start, PAGE_SIZE); |
| 235 | /* | 235 | /* |
| 236 | * SMP_CAHCE_BYTES could be enough, but init_bootmem_node like | 236 | * SMP_CACHE_BYTES could be enough, but init_bootmem_node like |
| 237 | * to use that to align to PAGE_SIZE | 237 | * to use that to align to PAGE_SIZE |
| 238 | */ | 238 | */ |
| 239 | bootmap = early_node_mem(nodeid, bootmap_start, end, | 239 | bootmap = early_node_mem(nodeid, bootmap_start, end, |
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32 index f647e7e56da4..a34fbf557926 100644 --- a/arch/x86/pci/Makefile_32 +++ b/arch/x86/pci/Makefile_32 | |||
| @@ -13,10 +13,11 @@ pci-y := fixup.o | |||
| 13 | pci-$(CONFIG_ACPI) += acpi.o | 13 | pci-$(CONFIG_ACPI) += acpi.o |
| 14 | pci-y += legacy.o irq.o | 14 | pci-y += legacy.o irq.o |
| 15 | 15 | ||
| 16 | # Careful: VISWS and NUMAQ overrule the pci-y above. The colons are | 16 | # Careful: VISWS overrule the pci-y above. The colons are |
| 17 | # therefor correct. This needs a proper fix by distangling the code. | 17 | # therefor correct. This needs a proper fix by distangling the code. |
| 18 | pci-$(CONFIG_X86_VISWS) := visws.o fixup.o | 18 | pci-$(CONFIG_X86_VISWS) := visws.o fixup.o |
| 19 | pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o | 19 | |
| 20 | pci-$(CONFIG_X86_NUMAQ) += numa.o | ||
| 20 | 21 | ||
| 21 | # Necessary for NUMAQ as well | 22 | # Necessary for NUMAQ as well |
| 22 | pci-$(CONFIG_NUMA) += mp_bus_to_node.o | 23 | pci-$(CONFIG_NUMA) += mp_bus_to_node.o |
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 15f505d3a78e..d02c598451ec 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
| @@ -388,7 +388,7 @@ static int __init early_fill_mp_bus_info(void) | |||
| 388 | /* need to take out [0, TOM) for RAM*/ | 388 | /* need to take out [0, TOM) for RAM*/ |
| 389 | address = MSR_K8_TOP_MEM1; | 389 | address = MSR_K8_TOP_MEM1; |
| 390 | rdmsrl(address, val); | 390 | rdmsrl(address, val); |
| 391 | end = (val & 0xffffff8000000ULL); | 391 | end = (val & 0xffffff800000ULL); |
| 392 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); | 392 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); |
| 393 | if (end < (1ULL<<32)) | 393 | if (end < (1ULL<<32)) |
| 394 | update_range(range, 0, end - 1); | 394 | update_range(range, 0, end - 1); |
| @@ -482,7 +482,7 @@ static int __init early_fill_mp_bus_info(void) | |||
| 482 | /* TOP_MEM2 */ | 482 | /* TOP_MEM2 */ |
| 483 | address = MSR_K8_TOP_MEM2; | 483 | address = MSR_K8_TOP_MEM2; |
| 484 | rdmsrl(address, val); | 484 | rdmsrl(address, val); |
| 485 | end = (val & 0xffffff8000000ULL); | 485 | end = (val & 0xffffff800000ULL); |
| 486 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); | 486 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); |
| 487 | update_range(range, 1ULL<<32, end - 1); | 487 | update_range(range, 1ULL<<32, end - 1); |
| 488 | } | 488 | } |
diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numa.c index d9afbae5092b..99f1ecd485b5 100644 --- a/arch/x86/pci/numa.c +++ b/arch/x86/pci/numa.c | |||
| @@ -6,45 +6,21 @@ | |||
| 6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| 7 | #include <linux/nodemask.h> | 7 | #include <linux/nodemask.h> |
| 8 | #include <mach_apic.h> | 8 | #include <mach_apic.h> |
| 9 | #include <asm/mpspec.h> | ||
| 9 | #include "pci.h" | 10 | #include "pci.h" |
| 10 | 11 | ||
| 11 | #define XQUAD_PORTIO_BASE 0xfe400000 | 12 | #define XQUAD_PORTIO_BASE 0xfe400000 |
| 12 | #define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ | 13 | #define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ |
| 13 | 14 | ||
| 14 | int mp_bus_id_to_node[MAX_MP_BUSSES]; | ||
| 15 | #define BUS2QUAD(global) (mp_bus_id_to_node[global]) | 15 | #define BUS2QUAD(global) (mp_bus_id_to_node[global]) |
| 16 | 16 | ||
| 17 | int mp_bus_id_to_local[MAX_MP_BUSSES]; | ||
| 18 | #define BUS2LOCAL(global) (mp_bus_id_to_local[global]) | 17 | #define BUS2LOCAL(global) (mp_bus_id_to_local[global]) |
| 19 | 18 | ||
| 20 | void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, | ||
| 21 | struct mpc_config_translation *translation) | ||
| 22 | { | ||
| 23 | int quad = translation->trans_quad; | ||
| 24 | int local = translation->trans_local; | ||
| 25 | |||
| 26 | mp_bus_id_to_node[m->mpc_busid] = quad; | ||
| 27 | mp_bus_id_to_local[m->mpc_busid] = local; | ||
| 28 | printk(KERN_INFO "Bus #%d is %s (node %d)\n", | ||
| 29 | m->mpc_busid, name, quad); | ||
| 30 | } | ||
| 31 | |||
| 32 | int quad_local_to_mp_bus_id [NR_CPUS/4][4]; | ||
| 33 | #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) | 19 | #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) |
| 34 | void mpc_oem_pci_bus(struct mpc_config_bus *m, | ||
| 35 | struct mpc_config_translation *translation) | ||
| 36 | { | ||
| 37 | int quad = translation->trans_quad; | ||
| 38 | int local = translation->trans_local; | ||
| 39 | |||
| 40 | quad_local_to_mp_bus_id[quad][local] = m->mpc_busid; | ||
| 41 | } | ||
| 42 | 20 | ||
| 43 | /* Where the IO area was mapped on multiquad, always 0 otherwise */ | 21 | /* Where the IO area was mapped on multiquad, always 0 otherwise */ |
| 44 | void *xquad_portio; | 22 | void *xquad_portio; |
| 45 | #ifdef CONFIG_X86_NUMAQ | ||
| 46 | EXPORT_SYMBOL(xquad_portio); | 23 | EXPORT_SYMBOL(xquad_portio); |
| 47 | #endif | ||
| 48 | 24 | ||
| 49 | #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) | 25 | #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) |
| 50 | 26 | ||
| @@ -179,6 +155,9 @@ static int __init pci_numa_init(void) | |||
| 179 | { | 155 | { |
| 180 | int quad; | 156 | int quad; |
| 181 | 157 | ||
| 158 | if (!found_numaq) | ||
| 159 | return 0; | ||
| 160 | |||
| 182 | raw_pci_ops = &pci_direct_conf1_mq; | 161 | raw_pci_ops = &pci_direct_conf1_mq; |
| 183 | 162 | ||
| 184 | if (pcibios_scanned++) | 163 | if (pcibios_scanned++) |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bd74229081c3..fe60aa9fed0a 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -1273,6 +1273,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1273 | 1273 | ||
| 1274 | pgd = (pgd_t *)xen_start_info->pt_base; | 1274 | pgd = (pgd_t *)xen_start_info->pt_base; |
| 1275 | 1275 | ||
| 1276 | init_pg_tables_start = __pa(pgd); | ||
| 1276 | init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; | 1277 | init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; |
| 1277 | 1278 | ||
| 1278 | init_mm.pgd = pgd; /* use the Xen pagetables to start */ | 1279 | init_mm.pgd = pgd; /* use the Xen pagetables to start */ |
| @@ -1316,5 +1317,5 @@ asmlinkage void __init xen_start_kernel(void) | |||
| 1316 | } | 1317 | } |
| 1317 | 1318 | ||
| 1318 | /* Start the world */ | 1319 | /* Start the world */ |
| 1319 | start_kernel(); | 1320 | i386_start_kernel(); |
| 1320 | } | 1321 | } |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 488447878a9d..a29575803204 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
| @@ -40,8 +40,8 @@ char * __init xen_memory_setup(void) | |||
| 40 | max_pfn = min(MAX_DOMAIN_PAGES, max_pfn); | 40 | max_pfn = min(MAX_DOMAIN_PAGES, max_pfn); |
| 41 | 41 | ||
| 42 | e820.nr_map = 0; | 42 | e820.nr_map = 0; |
| 43 | add_memory_region(0, LOWMEMSIZE(), E820_RAM); | 43 | e820_add_region(0, LOWMEMSIZE(), E820_RAM); |
| 44 | add_memory_region(HIGH_MEMORY, PFN_PHYS(max_pfn)-HIGH_MEMORY, E820_RAM); | 44 | e820_add_region(HIGH_MEMORY, PFN_PHYS(max_pfn)-HIGH_MEMORY, E820_RAM); |
| 45 | 45 | ||
| 46 | return "Xen"; | 46 | return "Xen"; |
| 47 | } | 47 | } |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index c52fca833268..860f15f36ce9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | menuconfig ACPI | 5 | menuconfig ACPI |
| 6 | bool "ACPI (Advanced Configuration and Power Interface) Support" | 6 | bool "ACPI (Advanced Configuration and Power Interface) Support" |
| 7 | depends on !X86_NUMAQ | ||
| 8 | depends on !X86_VISWS | 7 | depends on !X86_VISWS |
| 9 | depends on !IA64_HP_SIM | 8 | depends on !IA64_HP_SIM |
| 10 | depends on IA64 || X86 | 9 | depends on IA64 || X86 |
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index c5e3ed7e903b..455575be3560 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
| @@ -8,6 +8,11 @@ | |||
| 8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
| 9 | #include <asm/dmi.h> | 9 | #include <asm/dmi.h> |
| 10 | 10 | ||
| 11 | /* | ||
| 12 | * DMI stands for "Desktop Management Interface". It is part | ||
| 13 | * of and an antecedent to, SMBIOS, which stands for System | ||
| 14 | * Management BIOS. See further: http://www.dmtf.org/standards | ||
| 15 | */ | ||
| 11 | static char dmi_empty_string[] = " "; | 16 | static char dmi_empty_string[] = " "; |
| 12 | 17 | ||
| 13 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) | 18 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
diff --git a/include/asm-x86/acpi.h b/include/asm-x86/acpi.h index 14411c9de46f..635d764dc13e 100644 --- a/include/asm-x86/acpi.h +++ b/include/asm-x86/acpi.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <asm/numa.h> | 28 | #include <asm/numa.h> |
| 29 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
| 30 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
| 31 | #include <asm/mpspec.h> | ||
| 31 | 32 | ||
| 32 | #define COMPILER_DEPENDENT_INT64 long long | 33 | #define COMPILER_DEPENDENT_INT64 long long |
| 33 | #define COMPILER_DEPENDENT_UINT64 unsigned long long | 34 | #define COMPILER_DEPENDENT_UINT64 unsigned long long |
| @@ -160,9 +161,7 @@ struct bootnode; | |||
| 160 | #ifdef CONFIG_ACPI_NUMA | 161 | #ifdef CONFIG_ACPI_NUMA |
| 161 | extern int acpi_numa; | 162 | extern int acpi_numa; |
| 162 | extern int acpi_scan_nodes(unsigned long start, unsigned long end); | 163 | extern int acpi_scan_nodes(unsigned long start, unsigned long end); |
| 163 | #ifdef CONFIG_X86_64 | 164 | #define NR_NODE_MEMBLKS (MAX_NUMNODES*2) |
| 164 | # define NR_NODE_MEMBLKS (MAX_NUMNODES*2) | ||
| 165 | #endif | ||
| 166 | extern void acpi_fake_nodes(const struct bootnode *fake_nodes, | 165 | extern void acpi_fake_nodes(const struct bootnode *fake_nodes, |
| 167 | int num_nodes); | 166 | int num_nodes); |
| 168 | #else | 167 | #else |
diff --git a/include/asm-x86/bios_ebda.h b/include/asm-x86/bios_ebda.h index b4a46b7be794..0033e50c13b2 100644 --- a/include/asm-x86/bios_ebda.h +++ b/include/asm-x86/bios_ebda.h | |||
| @@ -14,4 +14,6 @@ static inline unsigned int get_bios_ebda(void) | |||
| 14 | return address; /* 0 means none */ | 14 | return address; /* 0 means none */ |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | void reserve_ebda_region(void); | ||
| 18 | |||
| 17 | #endif /* _MACH_BIOS_EBDA_H */ | 19 | #endif /* _MACH_BIOS_EBDA_H */ |
diff --git a/include/asm-x86/bootparam.h b/include/asm-x86/bootparam.h index 3e36ba8f288b..55ae9d0c4255 100644 --- a/include/asm-x86/bootparam.h +++ b/include/asm-x86/bootparam.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | /* setup data types */ | 12 | /* setup data types */ |
| 13 | #define SETUP_NONE 0 | 13 | #define SETUP_NONE 0 |
| 14 | #define SETUP_E820_EXT 1 | ||
| 14 | 15 | ||
| 15 | /* extensible setup data list node */ | 16 | /* extensible setup data list node */ |
| 16 | struct setup_data { | 17 | struct setup_data { |
| @@ -107,4 +108,7 @@ struct boot_params { | |||
| 107 | __u8 _pad9[276]; /* 0xeec */ | 108 | __u8 _pad9[276]; /* 0xeec */ |
| 108 | } __attribute__((packed)); | 109 | } __attribute__((packed)); |
| 109 | 110 | ||
| 111 | void reserve_setup_data(void); | ||
| 112 | void parse_setup_data(void); | ||
| 113 | |||
| 110 | #endif /* _ASM_BOOTPARAM_H */ | 114 | #endif /* _ASM_BOOTPARAM_H */ |
diff --git a/include/asm-x86/dmi.h b/include/asm-x86/dmi.h index 4edf7514a750..58a86571fe0f 100644 --- a/include/asm-x86/dmi.h +++ b/include/asm-x86/dmi.h | |||
| @@ -3,12 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #include <asm/io.h> | 4 | #include <asm/io.h> |
| 5 | 5 | ||
| 6 | #ifdef CONFIG_X86_32 | ||
| 7 | |||
| 8 | #define dmi_alloc alloc_bootmem | ||
| 9 | |||
| 10 | #else /* CONFIG_X86_32 */ | ||
| 11 | |||
| 12 | #define DMI_MAX_DATA 2048 | 6 | #define DMI_MAX_DATA 2048 |
| 13 | 7 | ||
| 14 | extern int dmi_alloc_index; | 8 | extern int dmi_alloc_index; |
| @@ -25,8 +19,6 @@ static inline void *dmi_alloc(unsigned len) | |||
| 25 | return dmi_alloc_data + idx; | 19 | return dmi_alloc_data + idx; |
| 26 | } | 20 | } |
| 27 | 21 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | /* Use early IO mappings for DMI because it's initialized early */ | 22 | /* Use early IO mappings for DMI because it's initialized early */ |
| 31 | #define dmi_ioremap early_ioremap | 23 | #define dmi_ioremap early_ioremap |
| 32 | #define dmi_iounmap early_iounmap | 24 | #define dmi_iounmap early_iounmap |
diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h index 5103d0b2c46c..0e92b6a2ea00 100644 --- a/include/asm-x86/e820.h +++ b/include/asm-x86/e820.h | |||
| @@ -2,6 +2,41 @@ | |||
| 2 | #define __ASM_E820_H | 2 | #define __ASM_E820_H |
| 3 | #define E820MAP 0x2d0 /* our map */ | 3 | #define E820MAP 0x2d0 /* our map */ |
| 4 | #define E820MAX 128 /* number of entries in E820MAP */ | 4 | #define E820MAX 128 /* number of entries in E820MAP */ |
| 5 | |||
| 6 | /* | ||
| 7 | * Legacy E820 BIOS limits us to 128 (E820MAX) nodes due to the | ||
| 8 | * constrained space in the zeropage. If we have more nodes than | ||
| 9 | * that, and if we've booted off EFI firmware, then the EFI tables | ||
| 10 | * passed us from the EFI firmware can list more nodes. Size our | ||
| 11 | * internal memory map tables to have room for these additional | ||
| 12 | * nodes, based on up to three entries per node for which the | ||
| 13 | * kernel was built: MAX_NUMNODES == (1 << CONFIG_NODES_SHIFT), | ||
| 14 | * plus E820MAX, allowing space for the possible duplicate E820 | ||
| 15 | * entries that might need room in the same arrays, prior to the | ||
| 16 | * call to sanitize_e820_map() to remove duplicates. The allowance | ||
| 17 | * of three memory map entries per node is "enough" entries for | ||
| 18 | * the initial hardware platform motivating this mechanism to make | ||
| 19 | * use of additional EFI map entries. Future platforms may want | ||
| 20 | * to allow more than three entries per node or otherwise refine | ||
| 21 | * this size. | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Odd: 'make headers_check' complains about numa.h if I try | ||
| 26 | * to collapse the next two #ifdef lines to a single line: | ||
| 27 | * #if defined(__KERNEL__) && defined(CONFIG_EFI) | ||
| 28 | */ | ||
| 29 | #ifdef __KERNEL__ | ||
| 30 | #ifdef CONFIG_EFI | ||
| 31 | #include <linux/numa.h> | ||
| 32 | #define E820_X_MAX (E820MAX + 3 * MAX_NUMNODES) | ||
| 33 | #else /* ! CONFIG_EFI */ | ||
| 34 | #define E820_X_MAX E820MAX | ||
| 35 | #endif | ||
| 36 | #else /* ! __KERNEL__ */ | ||
| 37 | #define E820_X_MAX E820MAX | ||
| 38 | #endif | ||
| 39 | |||
| 5 | #define E820NR 0x1e8 /* # entries in E820MAP */ | 40 | #define E820NR 0x1e8 /* # entries in E820MAP */ |
| 6 | 41 | ||
| 7 | #define E820_RAM 1 | 42 | #define E820_RAM 1 |
| @@ -18,8 +53,59 @@ struct e820entry { | |||
| 18 | 53 | ||
| 19 | struct e820map { | 54 | struct e820map { |
| 20 | __u32 nr_map; | 55 | __u32 nr_map; |
| 21 | struct e820entry map[E820MAX]; | 56 | struct e820entry map[E820_X_MAX]; |
| 22 | }; | 57 | }; |
| 58 | |||
| 59 | extern struct e820map e820; | ||
| 60 | |||
| 61 | extern int e820_any_mapped(u64 start, u64 end, unsigned type); | ||
| 62 | extern int e820_all_mapped(u64 start, u64 end, unsigned type); | ||
| 63 | extern void e820_add_region(u64 start, u64 size, int type); | ||
| 64 | extern void e820_print_map(char *who); | ||
| 65 | extern int | ||
| 66 | sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, int *pnr_map); | ||
| 67 | extern int copy_e820_map(struct e820entry *biosmap, int nr_map); | ||
| 68 | extern u64 e820_update_range(u64 start, u64 size, unsigned old_type, | ||
| 69 | unsigned new_type); | ||
| 70 | extern void update_e820(void); | ||
| 71 | extern void e820_setup_gap(void); | ||
| 72 | struct setup_data; | ||
| 73 | extern void parse_e820_ext(struct setup_data *data, unsigned long pa_data); | ||
| 74 | |||
| 75 | #if defined(CONFIG_X86_64) || \ | ||
| 76 | (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION)) | ||
| 77 | extern void e820_mark_nosave_regions(unsigned long limit_pfn); | ||
| 78 | #else | ||
| 79 | static inline void e820_mark_nosave_regions(unsigned long limit_pfn) | ||
| 80 | { | ||
| 81 | } | ||
| 82 | #endif | ||
| 83 | |||
| 84 | extern unsigned long end_user_pfn; | ||
| 85 | |||
| 86 | extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align); | ||
| 87 | extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align); | ||
| 88 | extern void reserve_early(u64 start, u64 end, char *name); | ||
| 89 | extern void free_early(u64 start, u64 end); | ||
| 90 | extern void early_res_to_bootmem(u64 start, u64 end); | ||
| 91 | extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); | ||
| 92 | |||
| 93 | extern unsigned long e820_end_of_ram(void); | ||
| 94 | extern int e820_find_active_region(const struct e820entry *ei, | ||
| 95 | unsigned long start_pfn, | ||
| 96 | unsigned long last_pfn, | ||
| 97 | unsigned long *ei_startpfn, | ||
| 98 | unsigned long *ei_endpfn); | ||
| 99 | extern void e820_register_active_regions(int nid, unsigned long start_pfn, | ||
| 100 | unsigned long end_pfn); | ||
| 101 | extern u64 e820_hole_size(u64 start, u64 end); | ||
| 102 | extern void finish_e820_parsing(void); | ||
| 103 | extern void e820_reserve_resources(void); | ||
| 104 | extern void setup_memory_map(void); | ||
| 105 | extern char *default_machine_specific_memory_setup(void); | ||
| 106 | extern char *machine_specific_memory_setup(void); | ||
| 107 | extern char *memory_setup(void); | ||
| 108 | |||
| 23 | #endif /* __ASSEMBLY__ */ | 109 | #endif /* __ASSEMBLY__ */ |
| 24 | 110 | ||
| 25 | #define ISA_START_ADDRESS 0xa0000 | 111 | #define ISA_START_ADDRESS 0xa0000 |
| @@ -30,11 +116,9 @@ struct e820map { | |||
| 30 | #define BIOS_END 0x00100000 | 116 | #define BIOS_END 0x00100000 |
| 31 | 117 | ||
| 32 | #ifdef __KERNEL__ | 118 | #ifdef __KERNEL__ |
| 33 | #ifdef CONFIG_X86_32 | 119 | #include <linux/ioport.h> |
| 34 | # include "e820_32.h" | 120 | |
| 35 | #else | 121 | #define HIGH_MEMORY (1024*1024) |
| 36 | # include "e820_64.h" | ||
| 37 | #endif | ||
| 38 | #endif /* __KERNEL__ */ | 122 | #endif /* __KERNEL__ */ |
| 39 | 123 | ||
| 40 | #endif /* __ASM_E820_H */ | 124 | #endif /* __ASM_E820_H */ |
diff --git a/include/asm-x86/e820_32.h b/include/asm-x86/e820_32.h deleted file mode 100644 index a9f7c6ec32bf..000000000000 --- a/include/asm-x86/e820_32.h +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * structures and definitions for the int 15, ax=e820 memory map | ||
| 3 | * scheme. | ||
| 4 | * | ||
| 5 | * In a nutshell, arch/i386/boot/setup.S populates a scratch table | ||
| 6 | * in the empty_zero_block that contains a list of usable address/size | ||
| 7 | * duples. In arch/i386/kernel/setup.c, this information is | ||
| 8 | * transferred into the e820map, and in arch/i386/mm/init.c, that | ||
| 9 | * new information is used to mark pages reserved or not. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | #ifndef __E820_HEADER | ||
| 13 | #define __E820_HEADER | ||
| 14 | |||
| 15 | #include <linux/ioport.h> | ||
| 16 | |||
| 17 | #define HIGH_MEMORY (1024*1024) | ||
| 18 | |||
| 19 | #ifndef __ASSEMBLY__ | ||
| 20 | |||
| 21 | extern struct e820map e820; | ||
| 22 | extern void update_e820(void); | ||
| 23 | |||
| 24 | extern int e820_all_mapped(unsigned long start, unsigned long end, | ||
| 25 | unsigned type); | ||
| 26 | extern int e820_any_mapped(u64 start, u64 end, unsigned type); | ||
| 27 | extern void propagate_e820_map(void); | ||
| 28 | extern void register_bootmem_low_pages(unsigned long max_low_pfn); | ||
| 29 | extern void add_memory_region(unsigned long long start, | ||
| 30 | unsigned long long size, int type); | ||
| 31 | extern void update_memory_range(u64 start, u64 size, unsigned old_type, | ||
| 32 | unsigned new_type); | ||
| 33 | extern void e820_register_memory(void); | ||
| 34 | extern void limit_regions(unsigned long long size); | ||
| 35 | extern void print_memory_map(char *who); | ||
| 36 | extern void init_iomem_resources(struct resource *code_resource, | ||
| 37 | struct resource *data_resource, | ||
| 38 | struct resource *bss_resource); | ||
| 39 | |||
| 40 | #if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION) | ||
| 41 | extern void e820_mark_nosave_regions(void); | ||
| 42 | #else | ||
| 43 | static inline void e820_mark_nosave_regions(void) | ||
| 44 | { | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | |||
| 49 | #endif/*!__ASSEMBLY__*/ | ||
| 50 | #endif/*__E820_HEADER*/ | ||
diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h deleted file mode 100644 index 71c4d685d30d..000000000000 --- a/include/asm-x86/e820_64.h +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * structures and definitions for the int 15, ax=e820 memory map | ||
| 3 | * scheme. | ||
| 4 | * | ||
| 5 | * In a nutshell, setup.S populates a scratch table in the | ||
| 6 | * empty_zero_block that contains a list of usable address/size | ||
| 7 | * duples. setup.c, this information is transferred into the e820map, | ||
| 8 | * and in init.c/numa.c, that new information is used to mark pages | ||
| 9 | * reserved or not. | ||
| 10 | */ | ||
| 11 | #ifndef __E820_HEADER | ||
| 12 | #define __E820_HEADER | ||
| 13 | |||
| 14 | #include <linux/ioport.h> | ||
| 15 | |||
| 16 | #ifndef __ASSEMBLY__ | ||
| 17 | extern unsigned long find_e820_area(unsigned long start, unsigned long end, | ||
| 18 | unsigned long size, unsigned long align); | ||
| 19 | extern unsigned long find_e820_area_size(unsigned long start, | ||
| 20 | unsigned long *sizep, | ||
| 21 | unsigned long align); | ||
| 22 | extern void add_memory_region(unsigned long start, unsigned long size, | ||
| 23 | int type); | ||
| 24 | extern void update_memory_range(u64 start, u64 size, unsigned old_type, | ||
| 25 | unsigned new_type); | ||
| 26 | extern void setup_memory_region(void); | ||
| 27 | extern void contig_e820_setup(void); | ||
| 28 | extern unsigned long e820_end_of_ram(void); | ||
| 29 | extern void e820_reserve_resources(void); | ||
| 30 | extern void e820_mark_nosave_regions(void); | ||
| 31 | extern int e820_any_mapped(unsigned long start, unsigned long end, | ||
| 32 | unsigned type); | ||
| 33 | extern int e820_all_mapped(unsigned long start, unsigned long end, | ||
| 34 | unsigned type); | ||
| 35 | extern int e820_any_non_reserved(unsigned long start, unsigned long end); | ||
| 36 | extern int is_memory_any_valid(unsigned long start, unsigned long end); | ||
| 37 | extern int e820_all_non_reserved(unsigned long start, unsigned long end); | ||
| 38 | extern int is_memory_all_valid(unsigned long start, unsigned long end); | ||
| 39 | extern unsigned long e820_hole_size(unsigned long start, unsigned long end); | ||
| 40 | |||
| 41 | extern void e820_setup_gap(void); | ||
| 42 | extern void e820_register_active_regions(int nid, unsigned long start_pfn, | ||
| 43 | unsigned long end_pfn); | ||
| 44 | |||
| 45 | extern void finish_e820_parsing(void); | ||
| 46 | |||
| 47 | extern struct e820map e820; | ||
| 48 | extern void update_e820(void); | ||
| 49 | |||
| 50 | extern void reserve_early(unsigned long start, unsigned long end, char *name); | ||
| 51 | extern void free_early(unsigned long start, unsigned long end); | ||
| 52 | extern void early_res_to_bootmem(unsigned long start, unsigned long end); | ||
| 53 | |||
| 54 | #endif/*!__ASSEMBLY__*/ | ||
| 55 | |||
| 56 | #endif/*__E820_HEADER*/ | ||
diff --git a/include/asm-x86/efi.h b/include/asm-x86/efi.h index d53004b855cc..7ed2bd7a7f51 100644 --- a/include/asm-x86/efi.h +++ b/include/asm-x86/efi.h | |||
| @@ -90,7 +90,7 @@ extern void *efi_ioremap(unsigned long addr, unsigned long size); | |||
| 90 | 90 | ||
| 91 | #endif /* CONFIG_X86_32 */ | 91 | #endif /* CONFIG_X86_32 */ |
| 92 | 92 | ||
| 93 | extern void efi_reserve_bootmem(void); | 93 | extern void efi_reserve_early(void); |
| 94 | extern void efi_call_phys_prelog(void); | 94 | extern void efi_call_phys_prelog(void); |
| 95 | extern void efi_call_phys_epilog(void); | 95 | extern void efi_call_phys_epilog(void); |
| 96 | 96 | ||
diff --git a/include/asm-x86/highmem.h b/include/asm-x86/highmem.h index e153f3b44774..4514b16cc723 100644 --- a/include/asm-x86/highmem.h +++ b/include/asm-x86/highmem.h | |||
| @@ -74,6 +74,9 @@ struct page *kmap_atomic_to_page(void *ptr); | |||
| 74 | 74 | ||
| 75 | #define flush_cache_kmaps() do { } while (0) | 75 | #define flush_cache_kmaps() do { } while (0) |
| 76 | 76 | ||
| 77 | extern void add_highpages_with_active_regions(int nid, unsigned long start_pfn, | ||
| 78 | unsigned long end_pfn); | ||
| 79 | |||
| 77 | #endif /* __KERNEL__ */ | 80 | #endif /* __KERNEL__ */ |
| 78 | 81 | ||
| 79 | #endif /* _ASM_HIGHMEM_H */ | 82 | #endif /* _ASM_HIGHMEM_H */ |
diff --git a/include/asm-x86/io_apic.h b/include/asm-x86/io_apic.h index dc0f55f2b034..8b1f5684842e 100644 --- a/include/asm-x86/io_apic.h +++ b/include/asm-x86/io_apic.h | |||
| @@ -121,21 +121,32 @@ extern int nr_ioapic_registers[MAX_IO_APICS]; | |||
| 121 | 121 | ||
| 122 | #define MP_MAX_IOAPIC_PIN 127 | 122 | #define MP_MAX_IOAPIC_PIN 127 |
| 123 | 123 | ||
| 124 | struct mp_ioapic_routing { | 124 | struct mp_config_ioapic { |
| 125 | int apic_id; | 125 | unsigned long mp_apicaddr; |
| 126 | int gsi_base; | 126 | unsigned int mp_apicid; |
| 127 | int gsi_end; | 127 | unsigned char mp_type; |
| 128 | DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); | 128 | unsigned char mp_apicver; |
| 129 | unsigned char mp_flags; | ||
| 130 | }; | ||
| 131 | |||
| 132 | struct mp_config_intsrc { | ||
| 133 | unsigned int mp_dstapic; | ||
| 134 | unsigned char mp_type; | ||
| 135 | unsigned char mp_irqtype; | ||
| 136 | unsigned short mp_irqflag; | ||
| 137 | unsigned char mp_srcbus; | ||
| 138 | unsigned char mp_srcbusirq; | ||
| 139 | unsigned char mp_dstirq; | ||
| 129 | }; | 140 | }; |
| 130 | 141 | ||
| 131 | /* I/O APIC entries */ | 142 | /* I/O APIC entries */ |
| 132 | extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; | 143 | extern struct mp_config_ioapic mp_ioapics[MAX_IO_APICS]; |
| 133 | 144 | ||
| 134 | /* # of MP IRQ source entries */ | 145 | /* # of MP IRQ source entries */ |
| 135 | extern int mp_irq_entries; | 146 | extern int mp_irq_entries; |
| 136 | 147 | ||
| 137 | /* MP IRQ source entries */ | 148 | /* MP IRQ source entries */ |
| 138 | extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; | 149 | extern struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; |
| 139 | 150 | ||
| 140 | /* non-0 if default (table-less) MP configuration */ | 151 | /* non-0 if default (table-less) MP configuration */ |
| 141 | extern int mpc_default_type; | 152 | extern int mpc_default_type; |
diff --git a/include/asm-x86/ipi.h b/include/asm-x86/ipi.h index ecc80f341f37..196d63c28aa4 100644 --- a/include/asm-x86/ipi.h +++ b/include/asm-x86/ipi.h | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | #include <asm/hw_irq.h> | 21 | #include <asm/hw_irq.h> |
| 22 | #include <asm/apic.h> | 22 | #include <asm/apic.h> |
| 23 | #include <asm/smp.h> | ||
| 23 | 24 | ||
| 24 | /* | 25 | /* |
| 25 | * the following functions deal with sending IPIs between CPUs. | 26 | * the following functions deal with sending IPIs between CPUs. |
diff --git a/include/asm-x86/mach-bigsmp/mach_mpspec.h b/include/asm-x86/mach-bigsmp/mach_mpspec.h deleted file mode 100644 index 6b5dadcf1d0e..000000000000 --- a/include/asm-x86/mach-bigsmp/mach_mpspec.h +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_MPSPEC_H | ||
| 2 | #define __ASM_MACH_MPSPEC_H | ||
| 3 | |||
| 4 | #define MAX_IRQ_SOURCES 256 | ||
| 5 | |||
| 6 | #define MAX_MP_BUSSES 32 | ||
| 7 | |||
| 8 | #endif /* __ASM_MACH_MPSPEC_H */ | ||
diff --git a/include/asm-x86/mach-es7000/mach_mpspec.h b/include/asm-x86/mach-es7000/mach_mpspec.h deleted file mode 100644 index b1f5039d4506..000000000000 --- a/include/asm-x86/mach-es7000/mach_mpspec.h +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_MPSPEC_H | ||
| 2 | #define __ASM_MACH_MPSPEC_H | ||
| 3 | |||
| 4 | #define MAX_IRQ_SOURCES 256 | ||
| 5 | |||
| 6 | #define MAX_MP_BUSSES 256 | ||
| 7 | |||
| 8 | #endif /* __ASM_MACH_MPSPEC_H */ | ||
diff --git a/include/asm-x86/mach-generic/mach_mpparse.h b/include/asm-x86/mach-generic/mach_mpparse.h index 0d0b5ba2e9d1..586cadbf3787 100644 --- a/include/asm-x86/mach-generic/mach_mpparse.h +++ b/include/asm-x86/mach-generic/mach_mpparse.h | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | #ifndef _MACH_MPPARSE_H | 1 | #ifndef _MACH_MPPARSE_H |
| 2 | #define _MACH_MPPARSE_H 1 | 2 | #define _MACH_MPPARSE_H 1 |
| 3 | 3 | ||
| 4 | int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid); | 4 | |
| 5 | int acpi_madt_oem_check(char *oem_id, char *oem_table_id); | 5 | extern int mps_oem_check(struct mp_config_table *mpc, char *oem, |
| 6 | char *productid); | ||
| 7 | |||
| 8 | extern int acpi_madt_oem_check(char *oem_id, char *oem_table_id); | ||
| 6 | 9 | ||
| 7 | #endif | 10 | #endif |
diff --git a/include/asm-x86/mach-numaq/mach_apic.h b/include/asm-x86/mach-numaq/mach_apic.h index 75a56e5afbe7..d802465e026a 100644 --- a/include/asm-x86/mach-numaq/mach_apic.h +++ b/include/asm-x86/mach-numaq/mach_apic.h | |||
| @@ -20,8 +20,14 @@ static inline cpumask_t target_cpus(void) | |||
| 20 | #define INT_DELIVERY_MODE dest_LowestPrio | 20 | #define INT_DELIVERY_MODE dest_LowestPrio |
| 21 | #define INT_DEST_MODE 0 /* physical delivery on LOCAL quad */ | 21 | #define INT_DEST_MODE 0 /* physical delivery on LOCAL quad */ |
| 22 | 22 | ||
| 23 | #define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap) | 23 | static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) |
| 24 | #define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map) | 24 | { |
| 25 | return physid_isset(apicid, bitmap); | ||
| 26 | } | ||
| 27 | static inline unsigned long check_apicid_present(int bit) | ||
| 28 | { | ||
| 29 | return physid_isset(bit, phys_cpu_present_map); | ||
| 30 | } | ||
| 25 | #define apicid_cluster(apicid) (apicid & 0xF0) | 31 | #define apicid_cluster(apicid) (apicid & 0xF0) |
| 26 | 32 | ||
| 27 | static inline int apic_id_registered(void) | 33 | static inline int apic_id_registered(void) |
| @@ -77,11 +83,6 @@ static inline int cpu_present_to_apicid(int mps_cpu) | |||
| 77 | return BAD_APICID; | 83 | return BAD_APICID; |
| 78 | } | 84 | } |
| 79 | 85 | ||
| 80 | static inline int generate_logical_apicid(int quad, int phys_apicid) | ||
| 81 | { | ||
| 82 | return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline int apicid_to_node(int logical_apicid) | 86 | static inline int apicid_to_node(int logical_apicid) |
| 86 | { | 87 | { |
| 87 | return logical_apicid >> 4; | 88 | return logical_apicid >> 4; |
| @@ -95,30 +96,6 @@ static inline physid_mask_t apicid_to_cpu_present(int logical_apicid) | |||
| 95 | return physid_mask_of_physid(cpu + 4*node); | 96 | return physid_mask_of_physid(cpu + 4*node); |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | struct mpc_config_translation { | ||
| 99 | unsigned char mpc_type; | ||
| 100 | unsigned char trans_len; | ||
| 101 | unsigned char trans_type; | ||
| 102 | unsigned char trans_quad; | ||
| 103 | unsigned char trans_global; | ||
| 104 | unsigned char trans_local; | ||
| 105 | unsigned short trans_reserved; | ||
| 106 | }; | ||
| 107 | |||
| 108 | static inline int mpc_apic_id(struct mpc_config_processor *m, | ||
| 109 | struct mpc_config_translation *translation_record) | ||
| 110 | { | ||
| 111 | int quad = translation_record->trans_quad; | ||
| 112 | int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid); | ||
| 113 | |||
| 114 | printk("Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", | ||
| 115 | m->mpc_apicid, | ||
| 116 | (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, | ||
| 117 | (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, | ||
| 118 | m->mpc_apicver, quad, logical_apicid); | ||
| 119 | return logical_apicid; | ||
| 120 | } | ||
| 121 | |||
| 122 | extern void *xquad_portio; | 99 | extern void *xquad_portio; |
| 123 | 100 | ||
| 124 | static inline void setup_portio_remap(void) | 101 | static inline void setup_portio_remap(void) |
diff --git a/include/asm-x86/mach-numaq/mach_mpparse.h b/include/asm-x86/mach-numaq/mach_mpparse.h index 459b12401187..626aef6b155f 100644 --- a/include/asm-x86/mach-numaq/mach_mpparse.h +++ b/include/asm-x86/mach-numaq/mach_mpparse.h | |||
| @@ -1,14 +1,7 @@ | |||
| 1 | #ifndef __ASM_MACH_MPPARSE_H | 1 | #ifndef __ASM_MACH_MPPARSE_H |
| 2 | #define __ASM_MACH_MPPARSE_H | 2 | #define __ASM_MACH_MPPARSE_H |
| 3 | 3 | ||
| 4 | extern void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, | 4 | extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, |
| 5 | struct mpc_config_translation *translation); | 5 | char *productid); |
| 6 | extern void mpc_oem_pci_bus(struct mpc_config_bus *m, | ||
| 7 | struct mpc_config_translation *translation); | ||
| 8 | |||
| 9 | /* Hook from generic ACPI tables.c */ | ||
| 10 | static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) | ||
| 11 | { | ||
| 12 | } | ||
| 13 | 6 | ||
| 14 | #endif /* __ASM_MACH_MPPARSE_H */ | 7 | #endif /* __ASM_MACH_MPPARSE_H */ |
diff --git a/include/asm-x86/mach-numaq/mach_mpspec.h b/include/asm-x86/mach-numaq/mach_mpspec.h deleted file mode 100644 index dffb09856f8f..000000000000 --- a/include/asm-x86/mach-numaq/mach_mpspec.h +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_MPSPEC_H | ||
| 2 | #define __ASM_MACH_MPSPEC_H | ||
| 3 | |||
| 4 | #define MAX_IRQ_SOURCES 512 | ||
| 5 | |||
| 6 | #define MAX_MP_BUSSES 32 | ||
| 7 | |||
| 8 | #endif /* __ASM_MACH_MPSPEC_H */ | ||
diff --git a/include/asm-x86/mach-summit/mach_mpspec.h b/include/asm-x86/mach-summit/mach_mpspec.h deleted file mode 100644 index bd765523511a..000000000000 --- a/include/asm-x86/mach-summit/mach_mpspec.h +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | #ifndef __ASM_MACH_MPSPEC_H | ||
| 2 | #define __ASM_MACH_MPSPEC_H | ||
| 3 | |||
| 4 | #define MAX_IRQ_SOURCES 256 | ||
| 5 | |||
| 6 | /* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */ | ||
| 7 | #define MAX_MP_BUSSES 260 | ||
| 8 | |||
| 9 | #endif /* __ASM_MACH_MPSPEC_H */ | ||
diff --git a/include/asm-x86/mmzone_32.h b/include/asm-x86/mmzone_32.h index cb2cad0b65a7..b2298a227567 100644 --- a/include/asm-x86/mmzone_32.h +++ b/include/asm-x86/mmzone_32.h | |||
| @@ -12,11 +12,9 @@ | |||
| 12 | extern struct pglist_data *node_data[]; | 12 | extern struct pglist_data *node_data[]; |
| 13 | #define NODE_DATA(nid) (node_data[nid]) | 13 | #define NODE_DATA(nid) (node_data[nid]) |
| 14 | 14 | ||
| 15 | #ifdef CONFIG_X86_NUMAQ | 15 | #include <asm/numaq.h> |
| 16 | #include <asm/numaq.h> | 16 | /* summit or generic arch */ |
| 17 | #elif defined(CONFIG_ACPI_SRAT)/* summit or generic arch */ | 17 | #include <asm/srat.h> |
| 18 | #include <asm/srat.h> | ||
| 19 | #endif | ||
| 20 | 18 | ||
| 21 | extern int get_memcfg_numa_flat(void); | 19 | extern int get_memcfg_numa_flat(void); |
| 22 | /* | 20 | /* |
| @@ -26,28 +24,20 @@ extern int get_memcfg_numa_flat(void); | |||
| 26 | */ | 24 | */ |
| 27 | static inline void get_memcfg_numa(void) | 25 | static inline void get_memcfg_numa(void) |
| 28 | { | 26 | { |
| 29 | #ifdef CONFIG_X86_NUMAQ | 27 | |
| 30 | if (get_memcfg_numaq()) | 28 | if (get_memcfg_numaq()) |
| 31 | return; | 29 | return; |
| 32 | #elif defined(CONFIG_ACPI_SRAT) | ||
| 33 | if (get_memcfg_from_srat()) | 30 | if (get_memcfg_from_srat()) |
| 34 | return; | 31 | return; |
| 35 | #endif | ||
| 36 | |||
| 37 | get_memcfg_numa_flat(); | 32 | get_memcfg_numa_flat(); |
| 38 | } | 33 | } |
| 39 | 34 | ||
| 40 | extern int early_pfn_to_nid(unsigned long pfn); | 35 | extern int early_pfn_to_nid(unsigned long pfn); |
| 41 | extern void numa_kva_reserve(void); | ||
| 42 | 36 | ||
| 43 | #else /* !CONFIG_NUMA */ | 37 | #else /* !CONFIG_NUMA */ |
| 44 | 38 | ||
| 45 | #define get_memcfg_numa get_memcfg_numa_flat | 39 | #define get_memcfg_numa get_memcfg_numa_flat |
| 46 | #define get_zholes_size(n) (0) | ||
| 47 | 40 | ||
| 48 | static inline void numa_kva_reserve(void) | ||
| 49 | { | ||
| 50 | } | ||
| 51 | #endif /* CONFIG_NUMA */ | 41 | #endif /* CONFIG_NUMA */ |
| 52 | 42 | ||
| 53 | #ifdef CONFIG_DISCONTIGMEM | 43 | #ifdef CONFIG_DISCONTIGMEM |
| @@ -55,14 +45,14 @@ static inline void numa_kva_reserve(void) | |||
| 55 | /* | 45 | /* |
| 56 | * generic node memory support, the following assumptions apply: | 46 | * generic node memory support, the following assumptions apply: |
| 57 | * | 47 | * |
| 58 | * 1) memory comes in 256Mb contigious chunks which are either present or not | 48 | * 1) memory comes in 64Mb contigious chunks which are either present or not |
| 59 | * 2) we will not have more than 64Gb in total | 49 | * 2) we will not have more than 64Gb in total |
| 60 | * | 50 | * |
| 61 | * for now assume that 64Gb is max amount of RAM for whole system | 51 | * for now assume that 64Gb is max amount of RAM for whole system |
| 62 | * 64Gb / 4096bytes/page = 16777216 pages | 52 | * 64Gb / 4096bytes/page = 16777216 pages |
| 63 | */ | 53 | */ |
| 64 | #define MAX_NR_PAGES 16777216 | 54 | #define MAX_NR_PAGES 16777216 |
| 65 | #define MAX_ELEMENTS 256 | 55 | #define MAX_ELEMENTS 1024 |
| 66 | #define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS) | 56 | #define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS) |
| 67 | 57 | ||
| 68 | extern s8 physnode_map[]; | 58 | extern s8 physnode_map[]; |
| @@ -87,9 +77,6 @@ static inline int pfn_to_nid(unsigned long pfn) | |||
| 87 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \ | 77 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \ |
| 88 | }) | 78 | }) |
| 89 | 79 | ||
| 90 | #ifdef CONFIG_X86_NUMAQ /* we have contiguous memory on NUMA-Q */ | ||
| 91 | #define pfn_valid(pfn) ((pfn) < num_physpages) | ||
| 92 | #else | ||
| 93 | static inline int pfn_valid(int pfn) | 80 | static inline int pfn_valid(int pfn) |
| 94 | { | 81 | { |
| 95 | int nid = pfn_to_nid(pfn); | 82 | int nid = pfn_to_nid(pfn); |
| @@ -98,7 +85,6 @@ static inline int pfn_valid(int pfn) | |||
| 98 | return (pfn < node_end_pfn(nid)); | 85 | return (pfn < node_end_pfn(nid)); |
| 99 | return 0; | 86 | return 0; |
| 100 | } | 87 | } |
| 101 | #endif /* CONFIG_X86_NUMAQ */ | ||
| 102 | 88 | ||
| 103 | #endif /* CONFIG_DISCONTIGMEM */ | 89 | #endif /* CONFIG_DISCONTIGMEM */ |
| 104 | 90 | ||
diff --git a/include/asm-x86/mpspec.h b/include/asm-x86/mpspec.h index 57a991b9c053..6ec1a5453b3e 100644 --- a/include/asm-x86/mpspec.h +++ b/include/asm-x86/mpspec.h | |||
| @@ -13,6 +13,12 @@ extern int apic_version[MAX_APICS]; | |||
| 13 | extern u8 apicid_2_node[]; | 13 | extern u8 apicid_2_node[]; |
| 14 | extern int pic_mode; | 14 | extern int pic_mode; |
| 15 | 15 | ||
| 16 | #ifdef CONFIG_X86_NUMAQ | ||
| 17 | extern int mp_bus_id_to_node[MAX_MP_BUSSES]; | ||
| 18 | extern int mp_bus_id_to_local[MAX_MP_BUSSES]; | ||
| 19 | extern int quad_local_to_mp_bus_id [NR_CPUS/4][4]; | ||
| 20 | #endif | ||
| 21 | |||
| 16 | #define MAX_APICID 256 | 22 | #define MAX_APICID 256 |
| 17 | 23 | ||
| 18 | #else | 24 | #else |
| @@ -21,26 +27,30 @@ extern int pic_mode; | |||
| 21 | /* Each PCI slot may be a combo card with its own bus. 4 IRQ pins per slot. */ | 27 | /* Each PCI slot may be a combo card with its own bus. 4 IRQ pins per slot. */ |
| 22 | #define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4) | 28 | #define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4) |
| 23 | 29 | ||
| 30 | #endif | ||
| 31 | |||
| 24 | extern void early_find_smp_config(void); | 32 | extern void early_find_smp_config(void); |
| 25 | extern void early_get_smp_config(void); | 33 | extern void early_get_smp_config(void); |
| 26 | 34 | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #if defined(CONFIG_MCA) || defined(CONFIG_EISA) | 35 | #if defined(CONFIG_MCA) || defined(CONFIG_EISA) |
| 30 | extern int mp_bus_id_to_type[MAX_MP_BUSSES]; | 36 | extern int mp_bus_id_to_type[MAX_MP_BUSSES]; |
| 31 | #endif | 37 | #endif |
| 32 | 38 | ||
| 33 | extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | 39 | extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); |
| 34 | 40 | ||
| 35 | extern int mp_bus_id_to_pci_bus[MAX_MP_BUSSES]; | ||
| 36 | |||
| 37 | extern unsigned int boot_cpu_physical_apicid; | 41 | extern unsigned int boot_cpu_physical_apicid; |
| 42 | extern unsigned int max_physical_apicid; | ||
| 38 | extern int smp_found_config; | 43 | extern int smp_found_config; |
| 39 | extern int mpc_default_type; | 44 | extern int mpc_default_type; |
| 40 | extern unsigned long mp_lapic_addr; | 45 | extern unsigned long mp_lapic_addr; |
| 41 | 46 | ||
| 42 | extern void find_smp_config(void); | 47 | extern void find_smp_config(void); |
| 43 | extern void get_smp_config(void); | 48 | extern void get_smp_config(void); |
| 49 | #ifdef CONFIG_X86_MPPARSE | ||
| 50 | extern void early_reserve_e820_mpc_new(void); | ||
| 51 | #else | ||
| 52 | static inline void early_reserve_e820_mpc_new(void) { } | ||
| 53 | #endif | ||
| 44 | 54 | ||
| 45 | void __cpuinit generic_processor_info(int apicid, int version); | 55 | void __cpuinit generic_processor_info(int apicid, int version); |
| 46 | #ifdef CONFIG_ACPI | 56 | #ifdef CONFIG_ACPI |
| @@ -49,6 +59,17 @@ extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, | |||
| 49 | u32 gsi); | 59 | u32 gsi); |
| 50 | extern void mp_config_acpi_legacy_irqs(void); | 60 | extern void mp_config_acpi_legacy_irqs(void); |
| 51 | extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low); | 61 | extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low); |
| 62 | #ifdef CONFIG_X86_IO_APIC | ||
| 63 | extern int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, | ||
| 64 | u32 gsi, int triggering, int polarity); | ||
| 65 | #else | ||
| 66 | static inline int | ||
| 67 | mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, | ||
| 68 | u32 gsi, int triggering, int polarity) | ||
| 69 | { | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | #endif | ||
| 52 | #endif /* CONFIG_ACPI */ | 73 | #endif /* CONFIG_ACPI */ |
| 53 | 74 | ||
| 54 | #define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS) | 75 | #define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS) |
diff --git a/include/asm-x86/numa_32.h b/include/asm-x86/numa_32.h index 03d0f7a9bf02..a02674f64869 100644 --- a/include/asm-x86/numa_32.h +++ b/include/asm-x86/numa_32.h | |||
| @@ -5,7 +5,7 @@ extern int pxm_to_nid(int pxm); | |||
| 5 | 5 | ||
| 6 | #ifdef CONFIG_NUMA | 6 | #ifdef CONFIG_NUMA |
| 7 | extern void __init remap_numa_kva(void); | 7 | extern void __init remap_numa_kva(void); |
| 8 | extern void set_highmem_pages_init(int); | 8 | extern void set_highmem_pages_init(void); |
| 9 | #else | 9 | #else |
| 10 | static inline void remap_numa_kva(void) | 10 | static inline void remap_numa_kva(void) |
| 11 | { | 11 | { |
diff --git a/include/asm-x86/numaq.h b/include/asm-x86/numaq.h index 94b86c31239a..ef068d2465d6 100644 --- a/include/asm-x86/numaq.h +++ b/include/asm-x86/numaq.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | #ifdef CONFIG_X86_NUMAQ | 29 | #ifdef CONFIG_X86_NUMAQ |
| 30 | 30 | ||
| 31 | extern int found_numaq; | ||
| 31 | extern int get_memcfg_numaq(void); | 32 | extern int get_memcfg_numaq(void); |
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| @@ -156,9 +157,10 @@ struct sys_cfg_data { | |||
| 156 | struct eachquadmem eq[MAX_NUMNODES]; /* indexed by quad id */ | 157 | struct eachquadmem eq[MAX_NUMNODES]; /* indexed by quad id */ |
| 157 | }; | 158 | }; |
| 158 | 159 | ||
| 159 | static inline unsigned long *get_zholes_size(int nid) | 160 | #else |
| 161 | static inline int get_memcfg_numaq(void) | ||
| 160 | { | 162 | { |
| 161 | return NULL; | 163 | return 0; |
| 162 | } | 164 | } |
| 163 | #endif /* CONFIG_X86_NUMAQ */ | 165 | #endif /* CONFIG_X86_NUMAQ */ |
| 164 | #endif /* NUMAQ_H */ | 166 | #endif /* NUMAQ_H */ |
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h index 6c8b41b03f6d..3dd458c385c0 100644 --- a/include/asm-x86/proto.h +++ b/include/asm-x86/proto.h | |||
| @@ -14,8 +14,6 @@ extern void ia32_syscall(void); | |||
| 14 | extern void ia32_cstar_target(void); | 14 | extern void ia32_cstar_target(void); |
| 15 | extern void ia32_sysenter_target(void); | 15 | extern void ia32_sysenter_target(void); |
| 16 | 16 | ||
| 17 | extern void reserve_bootmem_generic(unsigned long phys, unsigned len); | ||
| 18 | |||
| 19 | extern void syscall32_cpu_init(void); | 17 | extern void syscall32_cpu_init(void); |
| 20 | 18 | ||
| 21 | extern void check_efer(void); | 19 | extern void check_efer(void); |
diff --git a/include/asm-x86/setup.h b/include/asm-x86/setup.h index fa6763af8d26..e14b6e73d266 100644 --- a/include/asm-x86/setup.h +++ b/include/asm-x86/setup.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | /* Interrupt control for vSMPowered x86_64 systems */ | 8 | /* Interrupt control for vSMPowered x86_64 systems */ |
| 9 | void vsmp_init(void); | 9 | void vsmp_init(void); |
| 10 | 10 | ||
| 11 | char *machine_specific_memory_setup(void); | ||
| 12 | #ifndef CONFIG_PARAVIRT | 11 | #ifndef CONFIG_PARAVIRT |
| 13 | #define paravirt_post_allocator_init() do {} while (0) | 12 | #define paravirt_post_allocator_init() do {} while (0) |
| 14 | #endif | 13 | #endif |
| @@ -43,27 +42,19 @@ char *machine_specific_memory_setup(void); | |||
| 43 | */ | 42 | */ |
| 44 | extern struct boot_params boot_params; | 43 | extern struct boot_params boot_params; |
| 45 | 44 | ||
| 46 | #ifdef __i386__ | ||
| 47 | /* | 45 | /* |
| 48 | * Do NOT EVER look at the BIOS memory size location. | 46 | * Do NOT EVER look at the BIOS memory size location. |
| 49 | * It does not work on many machines. | 47 | * It does not work on many machines. |
| 50 | */ | 48 | */ |
| 51 | #define LOWMEMSIZE() (0x9f000) | 49 | #define LOWMEMSIZE() (0x9f000) |
| 52 | 50 | ||
| 53 | struct e820entry; | 51 | #ifdef __i386__ |
| 54 | |||
| 55 | char * __init machine_specific_memory_setup(void); | ||
| 56 | char *memory_setup(void); | ||
| 57 | 52 | ||
| 58 | int __init copy_e820_map(struct e820entry *biosmap, int nr_map); | 53 | void __init i386_start_kernel(void); |
| 59 | int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map); | ||
| 60 | void __init add_memory_region(unsigned long long start, | ||
| 61 | unsigned long long size, int type); | ||
| 62 | 54 | ||
| 55 | extern unsigned long init_pg_tables_start; | ||
| 63 | extern unsigned long init_pg_tables_end; | 56 | extern unsigned long init_pg_tables_end; |
| 64 | 57 | ||
| 65 | |||
| 66 | |||
| 67 | #endif /* __i386__ */ | 58 | #endif /* __i386__ */ |
| 68 | #endif /* _SETUP */ | 59 | #endif /* _SETUP */ |
| 69 | #endif /* __ASSEMBLY__ */ | 60 | #endif /* __ASSEMBLY__ */ |
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h index 1ebaa5cd3112..514e52b95cef 100644 --- a/include/asm-x86/smp.h +++ b/include/asm-x86/smp.h | |||
| @@ -201,7 +201,6 @@ extern void cpu_exit_clear(void); | |||
| 201 | extern void cpu_uninit(void); | 201 | extern void cpu_uninit(void); |
| 202 | #endif | 202 | #endif |
| 203 | 203 | ||
| 204 | extern void smp_alloc_memory(void); | ||
| 205 | extern void lock_ipi_call_lock(void); | 204 | extern void lock_ipi_call_lock(void); |
| 206 | extern void unlock_ipi_call_lock(void); | 205 | extern void unlock_ipi_call_lock(void); |
| 207 | #endif /* __ASSEMBLY__ */ | 206 | #endif /* __ASSEMBLY__ */ |
diff --git a/include/asm-x86/srat.h b/include/asm-x86/srat.h index f4bba131d068..456fe0b5a921 100644 --- a/include/asm-x86/srat.h +++ b/include/asm-x86/srat.h | |||
| @@ -27,11 +27,13 @@ | |||
| 27 | #ifndef _ASM_SRAT_H_ | 27 | #ifndef _ASM_SRAT_H_ |
| 28 | #define _ASM_SRAT_H_ | 28 | #define _ASM_SRAT_H_ |
| 29 | 29 | ||
| 30 | #ifndef CONFIG_ACPI_SRAT | 30 | #ifdef CONFIG_ACPI_SRAT |
| 31 | #error CONFIG_ACPI_SRAT not defined, and srat.h header has been included | ||
| 32 | #endif | ||
| 33 | |||
| 34 | extern int get_memcfg_from_srat(void); | 31 | extern int get_memcfg_from_srat(void); |
| 35 | extern unsigned long *get_zholes_size(int); | 32 | #else |
| 33 | static inline int get_memcfg_from_srat(void) | ||
| 34 | { | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | #endif | ||
| 36 | 38 | ||
| 37 | #endif /* _ASM_SRAT_H_ */ | 39 | #endif /* _ASM_SRAT_H_ */ |
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h index 7e4c133795a1..bacfceedf1d2 100644 --- a/include/asm-x86/system.h +++ b/include/asm-x86/system.h | |||
| @@ -303,7 +303,6 @@ static inline void clflush(volatile void *__p) | |||
| 303 | void disable_hlt(void); | 303 | void disable_hlt(void); |
| 304 | void enable_hlt(void); | 304 | void enable_hlt(void); |
| 305 | 305 | ||
| 306 | extern int es7000_plat; | ||
| 307 | void cpu_idle_wait(void); | 306 | void cpu_idle_wait(void); |
| 308 | 307 | ||
| 309 | extern unsigned long arch_align_stack(unsigned long sp); | 308 | extern unsigned long arch_align_stack(unsigned long sp); |
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 686895bacd9d..a1d9b79078ea 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h | |||
| @@ -84,6 +84,8 @@ extern int reserve_bootmem(unsigned long addr, unsigned long size, int flags); | |||
| 84 | __alloc_bootmem_low(x, PAGE_SIZE, 0) | 84 | __alloc_bootmem_low(x, PAGE_SIZE, 0) |
| 85 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ | 85 | #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ |
| 86 | 86 | ||
| 87 | extern int reserve_bootmem_generic(unsigned long addr, unsigned long size, | ||
| 88 | int flags); | ||
| 87 | extern unsigned long free_all_bootmem(void); | 89 | extern unsigned long free_all_bootmem(void); |
| 88 | extern unsigned long free_all_bootmem_node(pg_data_t *pgdat); | 90 | extern unsigned long free_all_bootmem_node(pg_data_t *pgdat); |
| 89 | extern void *__alloc_bootmem_node(pg_data_t *pgdat, | 91 | extern void *__alloc_bootmem_node(pg_data_t *pgdat, |
diff --git a/include/linux/efi.h b/include/linux/efi.h index a5f359a7ad0e..807373d467f7 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
| @@ -287,7 +287,6 @@ efi_guid_unparse(efi_guid_t *guid, char *out) | |||
| 287 | extern void efi_init (void); | 287 | extern void efi_init (void); |
| 288 | extern void *efi_get_pal_addr (void); | 288 | extern void *efi_get_pal_addr (void); |
| 289 | extern void efi_map_pal_code (void); | 289 | extern void efi_map_pal_code (void); |
| 290 | extern void efi_map_memmap(void); | ||
| 291 | extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); | 290 | extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); |
| 292 | extern void efi_gettimeofday (struct timespec *ts); | 291 | extern void efi_gettimeofday (struct timespec *ts); |
| 293 | extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ | 292 | extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ |
| @@ -295,14 +294,11 @@ extern u64 efi_get_iobase (void); | |||
| 295 | extern u32 efi_mem_type (unsigned long phys_addr); | 294 | extern u32 efi_mem_type (unsigned long phys_addr); |
| 296 | extern u64 efi_mem_attributes (unsigned long phys_addr); | 295 | extern u64 efi_mem_attributes (unsigned long phys_addr); |
| 297 | extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); | 296 | extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); |
| 298 | extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, | ||
| 299 | u64 attr); | ||
| 300 | extern int __init efi_uart_console_only (void); | 297 | extern int __init efi_uart_console_only (void); |
| 301 | extern void efi_initialize_iomem_resources(struct resource *code_resource, | 298 | extern void efi_initialize_iomem_resources(struct resource *code_resource, |
| 302 | struct resource *data_resource, struct resource *bss_resource); | 299 | struct resource *data_resource, struct resource *bss_resource); |
| 303 | extern unsigned long efi_get_time(void); | 300 | extern unsigned long efi_get_time(void); |
| 304 | extern int efi_set_rtc_mmss(unsigned long nowtime); | 301 | extern int efi_set_rtc_mmss(unsigned long nowtime); |
| 305 | extern int is_available_memory(efi_memory_desc_t * md); | ||
| 306 | extern struct efi_memory_map memmap; | 302 | extern struct efi_memory_map memmap; |
| 307 | 303 | ||
| 308 | /** | 304 | /** |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 586a943cab01..e4de460907c1 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
| @@ -998,8 +998,8 @@ extern void free_area_init_node(int nid, pg_data_t *pgdat, | |||
| 998 | extern void free_area_init_nodes(unsigned long *max_zone_pfn); | 998 | extern void free_area_init_nodes(unsigned long *max_zone_pfn); |
| 999 | extern void add_active_range(unsigned int nid, unsigned long start_pfn, | 999 | extern void add_active_range(unsigned int nid, unsigned long start_pfn, |
| 1000 | unsigned long end_pfn); | 1000 | unsigned long end_pfn); |
| 1001 | extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn, | 1001 | extern void remove_active_range(unsigned int nid, unsigned long start_pfn, |
| 1002 | unsigned long new_end_pfn); | 1002 | unsigned long end_pfn); |
| 1003 | extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn, | 1003 | extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn, |
| 1004 | unsigned long end_pfn); | 1004 | unsigned long end_pfn); |
| 1005 | extern void remove_all_active_ranges(void); | 1005 | extern void remove_all_active_ranges(void); |
| @@ -1011,6 +1011,8 @@ extern unsigned long find_min_pfn_with_active_regions(void); | |||
| 1011 | extern unsigned long find_max_pfn_with_active_regions(void); | 1011 | extern unsigned long find_max_pfn_with_active_regions(void); |
| 1012 | extern void free_bootmem_with_active_regions(int nid, | 1012 | extern void free_bootmem_with_active_regions(int nid, |
| 1013 | unsigned long max_low_pfn); | 1013 | unsigned long max_low_pfn); |
| 1014 | typedef void (*work_fn_t)(unsigned long, unsigned long, void *); | ||
| 1015 | extern void work_with_active_regions(int nid, work_fn_t work_fn, void *data); | ||
| 1014 | extern void sparse_memory_present_with_active_regions(int nid); | 1016 | extern void sparse_memory_present_with_active_regions(int nid); |
| 1015 | #ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID | 1017 | #ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID |
| 1016 | extern int early_pfn_to_nid(unsigned long pfn); | 1018 | extern int early_pfn_to_nid(unsigned long pfn); |
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h index e875905f7b12..e8c06122be36 100644 --- a/include/linux/pageblock-flags.h +++ b/include/linux/pageblock-flags.h | |||
| @@ -25,13 +25,11 @@ | |||
| 25 | 25 | ||
| 26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
| 27 | 27 | ||
| 28 | /* Macro to aid the definition of ranges of bits */ | ||
| 29 | #define PB_range(name, required_bits) \ | ||
| 30 | name, name ## _end = (name + required_bits) - 1 | ||
| 31 | |||
| 32 | /* Bit indices that affect a whole block of pages */ | 28 | /* Bit indices that affect a whole block of pages */ |
| 33 | enum pageblock_bits { | 29 | enum pageblock_bits { |
| 34 | PB_range(PB_migrate, 3), /* 3 bits required for migrate types */ | 30 | PB_migrate, |
| 31 | PB_migrate_end = PB_migrate + 3 - 1, | ||
| 32 | /* 3 bits required for migrate types */ | ||
| 35 | NR_PAGEBLOCK_BITS | 33 | NR_PAGEBLOCK_BITS |
| 36 | }; | 34 | }; |
| 37 | 35 | ||
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f32fae3121f0..41c6e3aa059f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -2929,6 +2929,14 @@ void __init free_bootmem_with_active_regions(int nid, | |||
| 2929 | } | 2929 | } |
| 2930 | } | 2930 | } |
| 2931 | 2931 | ||
| 2932 | void __init work_with_active_regions(int nid, work_fn_t work_fn, void *data) | ||
| 2933 | { | ||
| 2934 | int i; | ||
| 2935 | |||
| 2936 | for_each_active_range_index_in_nid(i, nid) | ||
| 2937 | work_fn(early_node_map[i].start_pfn, early_node_map[i].end_pfn, | ||
| 2938 | data); | ||
| 2939 | } | ||
| 2932 | /** | 2940 | /** |
| 2933 | * sparse_memory_present_with_active_regions - Call memory_present for each active range | 2941 | * sparse_memory_present_with_active_regions - Call memory_present for each active range |
| 2934 | * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used. | 2942 | * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used. |
| @@ -3461,6 +3469,11 @@ void __paginginit free_area_init_node(int nid, struct pglist_data *pgdat, | |||
| 3461 | calculate_node_totalpages(pgdat, zones_size, zholes_size); | 3469 | calculate_node_totalpages(pgdat, zones_size, zholes_size); |
| 3462 | 3470 | ||
| 3463 | alloc_node_mem_map(pgdat); | 3471 | alloc_node_mem_map(pgdat); |
| 3472 | #ifdef CONFIG_FLAT_NODE_MEM_MAP | ||
| 3473 | printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n", | ||
| 3474 | nid, (unsigned long)pgdat, | ||
| 3475 | (unsigned long)pgdat->node_mem_map); | ||
| 3476 | #endif | ||
| 3464 | 3477 | ||
| 3465 | free_area_init_core(pgdat, zones_size, zholes_size); | 3478 | free_area_init_core(pgdat, zones_size, zholes_size); |
| 3466 | } | 3479 | } |
| @@ -3547,27 +3560,68 @@ void __init add_active_range(unsigned int nid, unsigned long start_pfn, | |||
| 3547 | } | 3560 | } |
| 3548 | 3561 | ||
| 3549 | /** | 3562 | /** |
| 3550 | * shrink_active_range - Shrink an existing registered range of PFNs | 3563 | * remove_active_range - Shrink an existing registered range of PFNs |
| 3551 | * @nid: The node id the range is on that should be shrunk | 3564 | * @nid: The node id the range is on that should be shrunk |
| 3552 | * @old_end_pfn: The old end PFN of the range | 3565 | * @start_pfn: The new PFN of the range |
| 3553 | * @new_end_pfn: The new PFN of the range | 3566 | * @end_pfn: The new PFN of the range |
| 3554 | * | 3567 | * |
| 3555 | * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node. | 3568 | * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node. |
| 3556 | * The map is kept at the end physical page range that has already been | 3569 | * The map is kept near the end physical page range that has already been |
| 3557 | * registered with add_active_range(). This function allows an arch to shrink | 3570 | * registered. This function allows an arch to shrink an existing registered |
| 3558 | * an existing registered range. | 3571 | * range. |
| 3559 | */ | 3572 | */ |
| 3560 | void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn, | 3573 | void __init remove_active_range(unsigned int nid, unsigned long start_pfn, |
| 3561 | unsigned long new_end_pfn) | 3574 | unsigned long end_pfn) |
| 3562 | { | 3575 | { |
| 3563 | int i; | 3576 | int i, j; |
| 3577 | int removed = 0; | ||
| 3578 | |||
| 3579 | printk(KERN_DEBUG "remove_active_range (%d, %lu, %lu)\n", | ||
| 3580 | nid, start_pfn, end_pfn); | ||
| 3564 | 3581 | ||
| 3565 | /* Find the old active region end and shrink */ | 3582 | /* Find the old active region end and shrink */ |
| 3566 | for_each_active_range_index_in_nid(i, nid) | 3583 | for_each_active_range_index_in_nid(i, nid) { |
| 3567 | if (early_node_map[i].end_pfn == old_end_pfn) { | 3584 | if (early_node_map[i].start_pfn >= start_pfn && |
| 3568 | early_node_map[i].end_pfn = new_end_pfn; | 3585 | early_node_map[i].end_pfn <= end_pfn) { |
| 3569 | break; | 3586 | /* clear it */ |
| 3587 | early_node_map[i].start_pfn = 0; | ||
| 3588 | early_node_map[i].end_pfn = 0; | ||
| 3589 | removed = 1; | ||
| 3590 | continue; | ||
| 3570 | } | 3591 | } |
| 3592 | if (early_node_map[i].start_pfn < start_pfn && | ||
| 3593 | early_node_map[i].end_pfn > start_pfn) { | ||
| 3594 | unsigned long temp_end_pfn = early_node_map[i].end_pfn; | ||
| 3595 | early_node_map[i].end_pfn = start_pfn; | ||
| 3596 | if (temp_end_pfn > end_pfn) | ||
| 3597 | add_active_range(nid, end_pfn, temp_end_pfn); | ||
| 3598 | continue; | ||
| 3599 | } | ||
| 3600 | if (early_node_map[i].start_pfn >= start_pfn && | ||
| 3601 | early_node_map[i].end_pfn > end_pfn && | ||
| 3602 | early_node_map[i].start_pfn < end_pfn) { | ||
| 3603 | early_node_map[i].start_pfn = end_pfn; | ||
| 3604 | continue; | ||
| 3605 | } | ||
| 3606 | } | ||
| 3607 | |||
| 3608 | if (!removed) | ||
| 3609 | return; | ||
| 3610 | |||
| 3611 | /* remove the blank ones */ | ||
| 3612 | for (i = nr_nodemap_entries - 1; i > 0; i--) { | ||
| 3613 | if (early_node_map[i].nid != nid) | ||
| 3614 | continue; | ||
| 3615 | if (early_node_map[i].end_pfn) | ||
| 3616 | continue; | ||
| 3617 | /* we found it, get rid of it */ | ||
| 3618 | for (j = i; j < nr_nodemap_entries - 1; j++) | ||
| 3619 | memcpy(&early_node_map[j], &early_node_map[j+1], | ||
| 3620 | sizeof(early_node_map[j])); | ||
| 3621 | j = nr_nodemap_entries - 1; | ||
| 3622 | memset(&early_node_map[j], 0, sizeof(early_node_map[j])); | ||
| 3623 | nr_nodemap_entries--; | ||
| 3624 | } | ||
| 3571 | } | 3625 | } |
| 3572 | 3626 | ||
| 3573 | /** | 3627 | /** |
