diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-07 18:59:39 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-07 18:59:39 -0500 |
| commit | 322aafa6645a48c3b7837ca7385f126ab78127fd (patch) | |
| tree | 50f6665aedcf051cecd571183df81ba7f248014b | |
| parent | dd04265b028c00c365a78f9ff78a05e217f98656 (diff) | |
| parent | c7bbf52aa4fa332b84c4f2bb33e69561ee6870b4 (diff) | |
Merge branch 'x86-mrst-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-mrst-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (30 commits)
x86, mrst: Fix whitespace breakage in apb_timer.c
x86, mrst: Fix APB timer per cpu clockevent
x86, mrst: Remove X86_MRST dependency on PCI_IOAPIC
x86, olpc: Use pci subarch init for OLPC
x86, pci: Add arch_init to x86_init abstraction
x86, mrst: Add Kconfig dependencies for Moorestown
x86, pci: Exclude Moorestown PCI code if CONFIG_X86_MRST=n
x86, numaq: Make CONFIG_X86_NUMAQ depend on CONFIG_PCI
x86, pci: Add sanity check for PCI fixed bar probing
x86, legacy_irq: Remove duplicate vector assigment
x86, legacy_irq: Remove left over nr_legacy_irqs
x86, mrst: Platform clock setup code
x86, apbt: Moorestown APB system timer driver
x86, mrst: Add vrtc platform data setup code
x86, mrst: Add platform timer info parsing code
x86, mrst: Fill in PCI functions in x86_init layer
x86, mrst: Add dummy legacy pic to platform setup
x86/PCI: Moorestown PCI support
x86, ioapic: Add dummy ioapic functions
x86, ioapic: Early enable ioapic for timer irq
...
Fixed up semantic conflict of new clocksources due to commit
17622339af25 ("clocksource: add argument to resume callback").
42 files changed, 1662 insertions, 162 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d80930d58dae..3bc48b0bd3a9 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -2834,6 +2834,12 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 2834 | default x2apic cluster mode on platforms | 2834 | default x2apic cluster mode on platforms |
| 2835 | supporting x2apic. | 2835 | supporting x2apic. |
| 2836 | 2836 | ||
| 2837 | x86_mrst_timer= [X86-32,APBT] | ||
| 2838 | Choose timer option for x86 Moorestown MID platform. | ||
| 2839 | Two valid options are apbt timer only and lapic timer | ||
| 2840 | plus one apbt timer for broadcast timer. | ||
| 2841 | x86_mrst_timer=apbt_only | lapic_and_apbt | ||
| 2842 | |||
| 2837 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. | 2843 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. |
| 2838 | xd_geo= See header of drivers/block/xd.c. | 2844 | xd_geo= See header of drivers/block/xd.c. |
| 2839 | 2845 | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f15f37bfbd62..e98440371525 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -393,8 +393,12 @@ config X86_ELAN | |||
| 393 | 393 | ||
| 394 | config X86_MRST | 394 | config X86_MRST |
| 395 | bool "Moorestown MID platform" | 395 | bool "Moorestown MID platform" |
| 396 | depends on PCI | ||
| 397 | depends on PCI_GOANY | ||
| 396 | depends on X86_32 | 398 | depends on X86_32 |
| 397 | depends on X86_EXTENDED_PLATFORM | 399 | depends on X86_EXTENDED_PLATFORM |
| 400 | depends on X86_IO_APIC | ||
| 401 | select APB_TIMER | ||
| 398 | ---help--- | 402 | ---help--- |
| 399 | Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin | 403 | Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin |
| 400 | Internet Device(MID) platform. Moorestown consists of two chips: | 404 | Internet Device(MID) platform. Moorestown consists of two chips: |
| @@ -429,6 +433,7 @@ config X86_32_NON_STANDARD | |||
| 429 | config X86_NUMAQ | 433 | config X86_NUMAQ |
| 430 | bool "NUMAQ (IBM/Sequent)" | 434 | bool "NUMAQ (IBM/Sequent)" |
| 431 | depends on X86_32_NON_STANDARD | 435 | depends on X86_32_NON_STANDARD |
| 436 | depends on PCI | ||
| 432 | select NUMA | 437 | select NUMA |
| 433 | select X86_MPPARSE | 438 | select X86_MPPARSE |
| 434 | ---help--- | 439 | ---help--- |
| @@ -629,6 +634,16 @@ config HPET_EMULATE_RTC | |||
| 629 | def_bool y | 634 | def_bool y |
| 630 | depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y) | 635 | depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y) |
| 631 | 636 | ||
| 637 | config APB_TIMER | ||
| 638 | def_bool y if MRST | ||
| 639 | prompt "Langwell APB Timer Support" if X86_MRST | ||
| 640 | help | ||
| 641 | APB timer is the replacement for 8254, HPET on X86 MID platforms. | ||
| 642 | The APBT provides a stable time base on SMP | ||
| 643 | systems, unlike the TSC, but it is more expensive to access, | ||
| 644 | as it is off-chip. APB timers are always running regardless of CPU | ||
| 645 | C states, they are used as per CPU clockevent device when possible. | ||
| 646 | |||
| 632 | # Mark as embedded because too many people got it wrong. | 647 | # Mark as embedded because too many people got it wrong. |
| 633 | # The code disables itself when not needed. | 648 | # The code disables itself when not needed. |
| 634 | config DMI | 649 | config DMI |
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h new file mode 100644 index 000000000000..c74a2eebe570 --- /dev/null +++ b/arch/x86/include/asm/apb_timer.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* | ||
| 2 | * apb_timer.h: Driver for Langwell APB timer based on Synopsis DesignWare | ||
| 3 | * | ||
| 4 | * (C) Copyright 2009 Intel Corporation | ||
| 5 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; version 2 | ||
| 10 | * of the License. | ||
| 11 | * | ||
| 12 | * Note: | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef ASM_X86_APBT_H | ||
| 16 | #define ASM_X86_APBT_H | ||
| 17 | #include <linux/sfi.h> | ||
| 18 | |||
| 19 | #ifdef CONFIG_APB_TIMER | ||
| 20 | |||
| 21 | /* Langwell DW APB timer registers */ | ||
| 22 | #define APBTMR_N_LOAD_COUNT 0x00 | ||
| 23 | #define APBTMR_N_CURRENT_VALUE 0x04 | ||
| 24 | #define APBTMR_N_CONTROL 0x08 | ||
| 25 | #define APBTMR_N_EOI 0x0c | ||
| 26 | #define APBTMR_N_INT_STATUS 0x10 | ||
| 27 | |||
| 28 | #define APBTMRS_INT_STATUS 0xa0 | ||
| 29 | #define APBTMRS_EOI 0xa4 | ||
| 30 | #define APBTMRS_RAW_INT_STATUS 0xa8 | ||
| 31 | #define APBTMRS_COMP_VERSION 0xac | ||
| 32 | #define APBTMRS_REG_SIZE 0x14 | ||
| 33 | |||
| 34 | /* register bits */ | ||
| 35 | #define APBTMR_CONTROL_ENABLE (1<<0) | ||
| 36 | #define APBTMR_CONTROL_MODE_PERIODIC (1<<1) /*1: periodic 0:free running */ | ||
| 37 | #define APBTMR_CONTROL_INT (1<<2) | ||
| 38 | |||
| 39 | /* default memory mapped register base */ | ||
| 40 | #define LNW_SCU_ADDR 0xFF100000 | ||
| 41 | #define LNW_EXT_TIMER_OFFSET 0x1B800 | ||
| 42 | #define APBT_DEFAULT_BASE (LNW_SCU_ADDR+LNW_EXT_TIMER_OFFSET) | ||
| 43 | #define LNW_EXT_TIMER_PGOFFSET 0x800 | ||
| 44 | |||
| 45 | /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ | ||
| 46 | #define APBT_MAX_FREQ 50 | ||
| 47 | #define APBT_MIN_FREQ 1 | ||
| 48 | #define APBT_MMAP_SIZE 1024 | ||
| 49 | |||
| 50 | #define APBT_DEV_USED 1 | ||
| 51 | |||
| 52 | extern void apbt_time_init(void); | ||
| 53 | extern struct clock_event_device *global_clock_event; | ||
| 54 | extern unsigned long apbt_quick_calibrate(void); | ||
| 55 | extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu); | ||
| 56 | extern void apbt_setup_secondary_clock(void); | ||
| 57 | extern unsigned int boot_cpu_id; | ||
| 58 | extern int disable_apbt_percpu; | ||
| 59 | |||
| 60 | extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); | ||
| 61 | extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr); | ||
| 62 | extern int sfi_mtimer_num; | ||
| 63 | |||
| 64 | #else /* CONFIG_APB_TIMER */ | ||
| 65 | |||
| 66 | static inline unsigned long apbt_quick_calibrate(void) {return 0; } | ||
| 67 | static inline void apbt_time_init(void) {return 0; } | ||
| 68 | |||
| 69 | #endif | ||
| 70 | #endif /* ASM_X86_APBT_H */ | ||
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index eeac829a0f44..a929c9ede33d 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h | |||
| @@ -53,13 +53,6 @@ extern void threshold_interrupt(void); | |||
| 53 | extern void call_function_interrupt(void); | 53 | extern void call_function_interrupt(void); |
| 54 | extern void call_function_single_interrupt(void); | 54 | extern void call_function_single_interrupt(void); |
| 55 | 55 | ||
| 56 | /* PIC specific functions */ | ||
| 57 | extern void disable_8259A_irq(unsigned int irq); | ||
| 58 | extern void enable_8259A_irq(unsigned int irq); | ||
| 59 | extern int i8259A_irq_pending(unsigned int irq); | ||
| 60 | extern void make_8259A_irq(unsigned int irq); | ||
| 61 | extern void init_8259A(int aeoi); | ||
| 62 | |||
| 63 | /* IOAPIC */ | 56 | /* IOAPIC */ |
| 64 | #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs)) | 57 | #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs)) |
| 65 | extern unsigned long io_apic_irqs; | 58 | extern unsigned long io_apic_irqs; |
diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index 7ec65b18085d..1655147646aa 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h | |||
| @@ -26,11 +26,6 @@ extern unsigned int cached_irq_mask; | |||
| 26 | 26 | ||
| 27 | extern raw_spinlock_t i8259A_lock; | 27 | extern raw_spinlock_t i8259A_lock; |
| 28 | 28 | ||
| 29 | extern void init_8259A(int auto_eoi); | ||
| 30 | extern void enable_8259A_irq(unsigned int irq); | ||
| 31 | extern void disable_8259A_irq(unsigned int irq); | ||
| 32 | extern unsigned int startup_8259A_irq(unsigned int irq); | ||
| 33 | |||
| 34 | /* the PIC may need a careful delay on some platforms, hence specific calls */ | 29 | /* the PIC may need a careful delay on some platforms, hence specific calls */ |
| 35 | static inline unsigned char inb_pic(unsigned int port) | 30 | static inline unsigned char inb_pic(unsigned int port) |
| 36 | { | 31 | { |
| @@ -57,7 +52,17 @@ static inline void outb_pic(unsigned char value, unsigned int port) | |||
| 57 | 52 | ||
| 58 | extern struct irq_chip i8259A_chip; | 53 | extern struct irq_chip i8259A_chip; |
| 59 | 54 | ||
| 60 | extern void mask_8259A(void); | 55 | struct legacy_pic { |
| 61 | extern void unmask_8259A(void); | 56 | int nr_legacy_irqs; |
| 57 | struct irq_chip *chip; | ||
| 58 | void (*mask_all)(void); | ||
| 59 | void (*restore_mask)(void); | ||
| 60 | void (*init)(int auto_eoi); | ||
| 61 | int (*irq_pending)(unsigned int irq); | ||
| 62 | void (*make_irq)(unsigned int irq); | ||
| 63 | }; | ||
| 64 | |||
| 65 | extern struct legacy_pic *legacy_pic; | ||
| 66 | extern struct legacy_pic null_legacy_pic; | ||
| 62 | 67 | ||
| 63 | #endif /* _ASM_X86_I8259_H */ | 68 | #endif /* _ASM_X86_I8259_H */ |
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 5f61f6e0ffdd..35832a03a515 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h | |||
| @@ -143,8 +143,6 @@ extern int noioapicreroute; | |||
| 143 | /* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */ | 143 | /* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */ |
| 144 | extern int timer_through_8259; | 144 | extern int timer_through_8259; |
| 145 | 145 | ||
| 146 | extern void io_apic_disable_legacy(void); | ||
| 147 | |||
| 148 | /* | 146 | /* |
| 149 | * If we use the IO-APIC for IRQ routing, disable automatic | 147 | * If we use the IO-APIC for IRQ routing, disable automatic |
| 150 | * assignment of PCI IRQ's. | 148 | * assignment of PCI IRQ's. |
| @@ -189,6 +187,7 @@ extern struct mp_ioapic_gsi mp_gsi_routing[]; | |||
| 189 | int mp_find_ioapic(int gsi); | 187 | int mp_find_ioapic(int gsi); |
| 190 | int mp_find_ioapic_pin(int ioapic, int gsi); | 188 | int mp_find_ioapic_pin(int ioapic, int gsi); |
| 191 | void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); | 189 | void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); |
| 190 | extern void __init pre_init_apic_IRQ0(void); | ||
| 192 | 191 | ||
| 193 | #else /* !CONFIG_X86_IO_APIC */ | 192 | #else /* !CONFIG_X86_IO_APIC */ |
| 194 | 193 | ||
| @@ -198,7 +197,11 @@ static const int timer_through_8259 = 0; | |||
| 198 | static inline void ioapic_init_mappings(void) { } | 197 | static inline void ioapic_init_mappings(void) { } |
| 199 | static inline void ioapic_insert_resources(void) { } | 198 | static inline void ioapic_insert_resources(void) { } |
| 200 | static inline void probe_nr_irqs_gsi(void) { } | 199 | static inline void probe_nr_irqs_gsi(void) { } |
| 200 | static inline int mp_find_ioapic(int gsi) { return 0; } | ||
| 201 | 201 | ||
| 202 | struct io_apic_irq_attr; | ||
| 203 | static inline int io_apic_set_pci_routing(struct device *dev, int irq, | ||
| 204 | struct io_apic_irq_attr *irq_attr) { return 0; } | ||
| 202 | #endif | 205 | #endif |
| 203 | 206 | ||
| 204 | #endif /* _ASM_X86_IO_APIC_H */ | 207 | #endif /* _ASM_X86_IO_APIC_H */ |
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 262292729fc4..5458380b6ef8 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h | |||
| @@ -48,6 +48,5 @@ extern DECLARE_BITMAP(used_vectors, NR_VECTORS); | |||
| 48 | extern int vector_used_by_percpu_irq(unsigned int vector); | 48 | extern int vector_used_by_percpu_irq(unsigned int vector); |
| 49 | 49 | ||
| 50 | extern void init_ISA_irqs(void); | 50 | extern void init_ISA_irqs(void); |
| 51 | extern int nr_legacy_irqs; | ||
| 52 | 51 | ||
| 53 | #endif /* _ASM_X86_IRQ_H */ | 52 | #endif /* _ASM_X86_IRQ_H */ |
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h new file mode 100644 index 000000000000..451d30e7f62d --- /dev/null +++ b/arch/x86/include/asm/mrst.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * mrst.h: Intel Moorestown platform specific setup code | ||
| 3 | * | ||
| 4 | * (C) Copyright 2009 Intel Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; version 2 | ||
| 9 | * of the License. | ||
| 10 | */ | ||
| 11 | #ifndef _ASM_X86_MRST_H | ||
| 12 | #define _ASM_X86_MRST_H | ||
| 13 | extern int pci_mrst_init(void); | ||
| 14 | int __init sfi_parse_mrtc(struct sfi_table_header *table); | ||
| 15 | |||
| 16 | #define SFI_MTMR_MAX_NUM 8 | ||
| 17 | #define SFI_MRTC_MAX 8 | ||
| 18 | |||
| 19 | #endif /* _ASM_X86_MRST_H */ | ||
diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h index 13370b95ea94..37c516545ec8 100644 --- a/arch/x86/include/asm/numaq.h +++ b/arch/x86/include/asm/numaq.h | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | extern int found_numaq; | 31 | extern int found_numaq; |
| 32 | extern int get_memcfg_numaq(void); | 32 | extern int get_memcfg_numaq(void); |
| 33 | extern int pci_numaq_init(void); | ||
| 33 | 34 | ||
| 34 | extern void *xquad_portio; | 35 | extern void *xquad_portio; |
| 35 | 36 | ||
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h index 3a57385d9fa7..101229b0d8ed 100644 --- a/arch/x86/include/asm/olpc.h +++ b/arch/x86/include/asm/olpc.h | |||
| @@ -13,7 +13,6 @@ struct olpc_platform_t { | |||
| 13 | 13 | ||
| 14 | #define OLPC_F_PRESENT 0x01 | 14 | #define OLPC_F_PRESENT 0x01 |
| 15 | #define OLPC_F_DCON 0x02 | 15 | #define OLPC_F_DCON 0x02 |
| 16 | #define OLPC_F_VSA 0x04 | ||
| 17 | 16 | ||
| 18 | #ifdef CONFIG_OLPC | 17 | #ifdef CONFIG_OLPC |
| 19 | 18 | ||
| @@ -51,18 +50,6 @@ static inline int olpc_has_dcon(void) | |||
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | /* | 52 | /* |
| 54 | * The VSA is software from AMD that typical Geode bioses will include. | ||
| 55 | * It is used to emulate the PCI bus, VGA, etc. OLPC's Open Firmware does | ||
| 56 | * not include the VSA; instead, PCI is emulated by the kernel. | ||
| 57 | * | ||
| 58 | * The VSA is described further in arch/x86/pci/olpc.c. | ||
| 59 | */ | ||
| 60 | static inline int olpc_has_vsa(void) | ||
| 61 | { | ||
| 62 | return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * The "Mass Production" version of OLPC's XO is identified as being model | 53 | * The "Mass Production" version of OLPC's XO is identified as being model |
| 67 | * C2. During the prototype phase, the following models (in chronological | 54 | * C2. During the prototype phase, the following models (in chronological |
| 68 | * order) were created: A1, B1, B2, B3, B4, C1. The A1 through B2 models | 55 | * order) were created: A1, B1, B2, B3, B4, C1. The A1 through B2 models |
| @@ -87,13 +74,10 @@ static inline int olpc_has_dcon(void) | |||
| 87 | return 0; | 74 | return 0; |
| 88 | } | 75 | } |
| 89 | 76 | ||
| 90 | static inline int olpc_has_vsa(void) | ||
| 91 | { | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | #endif | 77 | #endif |
| 96 | 78 | ||
| 79 | extern int pci_olpc_init(void); | ||
| 80 | |||
| 97 | /* EC related functions */ | 81 | /* EC related functions */ |
| 98 | 82 | ||
| 99 | extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, | 83 | extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, |
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index b4a00dd4eed5..3e002ca5a287 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
| @@ -45,8 +45,15 @@ static inline int pci_proc_domain(struct pci_bus *bus) | |||
| 45 | 45 | ||
| 46 | #ifdef CONFIG_PCI | 46 | #ifdef CONFIG_PCI |
| 47 | extern unsigned int pcibios_assign_all_busses(void); | 47 | extern unsigned int pcibios_assign_all_busses(void); |
| 48 | extern int pci_legacy_init(void); | ||
| 49 | # ifdef CONFIG_ACPI | ||
| 50 | # define x86_default_pci_init pci_acpi_init | ||
| 51 | # else | ||
| 52 | # define x86_default_pci_init pci_legacy_init | ||
| 53 | # endif | ||
| 48 | #else | 54 | #else |
| 49 | #define pcibios_assign_all_busses() 0 | 55 | # define pcibios_assign_all_busses() 0 |
| 56 | # define x86_default_pci_init NULL | ||
| 50 | #endif | 57 | #endif |
| 51 | 58 | ||
| 52 | extern unsigned long pci_mem_start; | 59 | extern unsigned long pci_mem_start; |
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 05b58ccb2e82..1a0422348d6d 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h | |||
| @@ -83,7 +83,6 @@ struct irq_routing_table { | |||
| 83 | 83 | ||
| 84 | extern unsigned int pcibios_irq_mask; | 84 | extern unsigned int pcibios_irq_mask; |
| 85 | 85 | ||
| 86 | extern int pcibios_scanned; | ||
| 87 | extern spinlock_t pci_config_lock; | 86 | extern spinlock_t pci_config_lock; |
| 88 | 87 | ||
| 89 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); | 88 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); |
| @@ -106,16 +105,15 @@ extern bool port_cf9_safe; | |||
| 106 | extern int pci_direct_probe(void); | 105 | extern int pci_direct_probe(void); |
| 107 | extern void pci_direct_init(int type); | 106 | extern void pci_direct_init(int type); |
| 108 | extern void pci_pcbios_init(void); | 107 | extern void pci_pcbios_init(void); |
| 109 | extern int pci_olpc_init(void); | ||
| 110 | extern void __init dmi_check_pciprobe(void); | 108 | extern void __init dmi_check_pciprobe(void); |
| 111 | extern void __init dmi_check_skip_isa_align(void); | 109 | extern void __init dmi_check_skip_isa_align(void); |
| 112 | 110 | ||
| 113 | /* some common used subsys_initcalls */ | 111 | /* some common used subsys_initcalls */ |
| 114 | extern int __init pci_acpi_init(void); | 112 | extern int __init pci_acpi_init(void); |
| 115 | extern int __init pcibios_irq_init(void); | 113 | extern void __init pcibios_irq_init(void); |
| 116 | extern int __init pci_visws_init(void); | ||
| 117 | extern int __init pci_numaq_init(void); | ||
| 118 | extern int __init pcibios_init(void); | 114 | extern int __init pcibios_init(void); |
| 115 | extern int pci_legacy_init(void); | ||
| 116 | extern void pcibios_fixup_irqs(void); | ||
| 119 | 117 | ||
| 120 | /* pci-mmconfig.c */ | 118 | /* pci-mmconfig.c */ |
| 121 | 119 | ||
| @@ -183,3 +181,17 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val) | |||
| 183 | { | 181 | { |
| 184 | asm volatile("movl %%eax,(%1)" : : "a" (val), "r" (pos) : "memory"); | 182 | asm volatile("movl %%eax,(%1)" : : "a" (val), "r" (pos) : "memory"); |
| 185 | } | 183 | } |
| 184 | |||
| 185 | #ifdef CONFIG_PCI | ||
| 186 | # ifdef CONFIG_ACPI | ||
| 187 | # define x86_default_pci_init pci_acpi_init | ||
| 188 | # else | ||
| 189 | # define x86_default_pci_init pci_legacy_init | ||
| 190 | # endif | ||
| 191 | # define x86_default_pci_init_irq pcibios_irq_init | ||
| 192 | # define x86_default_pci_fixup_irqs pcibios_fixup_irqs | ||
| 193 | #else | ||
| 194 | # define x86_default_pci_init NULL | ||
| 195 | # define x86_default_pci_init_irq NULL | ||
| 196 | # define x86_default_pci_fixup_irqs NULL | ||
| 197 | #endif | ||
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 18e496c98ff0..86b1506f4179 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h | |||
| @@ -37,10 +37,8 @@ void setup_bios_corruption_check(void); | |||
| 37 | 37 | ||
| 38 | #ifdef CONFIG_X86_VISWS | 38 | #ifdef CONFIG_X86_VISWS |
| 39 | extern void visws_early_detect(void); | 39 | extern void visws_early_detect(void); |
| 40 | extern int is_visws_box(void); | ||
| 41 | #else | 40 | #else |
| 42 | static inline void visws_early_detect(void) { } | 41 | static inline void visws_early_detect(void) { } |
| 43 | static inline int is_visws_box(void) { return 0; } | ||
| 44 | #endif | 42 | #endif |
| 45 | 43 | ||
| 46 | extern unsigned long saved_video_mode; | 44 | extern unsigned long saved_video_mode; |
diff --git a/arch/x86/include/asm/visws/cobalt.h b/arch/x86/include/asm/visws/cobalt.h index 166adf61e770..2edb37637ead 100644 --- a/arch/x86/include/asm/visws/cobalt.h +++ b/arch/x86/include/asm/visws/cobalt.h | |||
| @@ -122,4 +122,6 @@ extern char visws_board_type; | |||
| 122 | 122 | ||
| 123 | extern char visws_board_rev; | 123 | extern char visws_board_rev; |
| 124 | 124 | ||
| 125 | extern int pci_visws_init(void); | ||
| 126 | |||
| 125 | #endif /* _ASM_X86_VISWS_COBALT_H */ | 127 | #endif /* _ASM_X86_VISWS_COBALT_H */ |
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 60cc35269083..519b54327d75 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h | |||
| @@ -99,6 +99,20 @@ struct x86_init_iommu { | |||
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | /** | 101 | /** |
| 102 | * struct x86_init_pci - platform specific pci init functions | ||
| 103 | * @arch_init: platform specific pci arch init call | ||
| 104 | * @init: platform specific pci subsystem init | ||
| 105 | * @init_irq: platform specific pci irq init | ||
| 106 | * @fixup_irqs: platform specific pci irq fixup | ||
| 107 | */ | ||
| 108 | struct x86_init_pci { | ||
| 109 | int (*arch_init)(void); | ||
| 110 | int (*init)(void); | ||
| 111 | void (*init_irq)(void); | ||
| 112 | void (*fixup_irqs)(void); | ||
| 113 | }; | ||
| 114 | |||
| 115 | /** | ||
| 102 | * struct x86_init_ops - functions for platform specific setup | 116 | * struct x86_init_ops - functions for platform specific setup |
| 103 | * | 117 | * |
| 104 | */ | 118 | */ |
| @@ -110,6 +124,7 @@ struct x86_init_ops { | |||
| 110 | struct x86_init_paging paging; | 124 | struct x86_init_paging paging; |
| 111 | struct x86_init_timers timers; | 125 | struct x86_init_timers timers; |
| 112 | struct x86_init_iommu iommu; | 126 | struct x86_init_iommu iommu; |
| 127 | struct x86_init_pci pci; | ||
| 113 | }; | 128 | }; |
| 114 | 129 | ||
| 115 | /** | 130 | /** |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index d87f09bc5a52..4c58352209e0 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -87,6 +87,7 @@ obj-$(CONFIG_VM86) += vm86_32.o | |||
| 87 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 87 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 88 | 88 | ||
| 89 | obj-$(CONFIG_HPET_TIMER) += hpet.o | 89 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
| 90 | obj-$(CONFIG_APB_TIMER) += apb_timer.o | ||
| 90 | 91 | ||
| 91 | obj-$(CONFIG_K8_NB) += k8.o | 92 | obj-$(CONFIG_K8_NB) += k8.o |
| 92 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o | 93 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 738fcb60e708..a54d714545ff 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/ioport.h> | 35 | #include <linux/ioport.h> |
| 36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
| 37 | 37 | ||
| 38 | #include <asm/pci_x86.h> | ||
| 38 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
| 39 | #include <asm/io_apic.h> | 40 | #include <asm/io_apic.h> |
| 40 | #include <asm/apic.h> | 41 | #include <asm/apic.h> |
| @@ -1624,6 +1625,9 @@ int __init acpi_boot_init(void) | |||
| 1624 | 1625 | ||
| 1625 | acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); | 1626 | acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); |
| 1626 | 1627 | ||
| 1628 | if (!acpi_noirq) | ||
| 1629 | x86_init.pci.init = pci_acpi_init; | ||
| 1630 | |||
| 1627 | return 0; | 1631 | return 0; |
| 1628 | } | 1632 | } |
| 1629 | 1633 | ||
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c new file mode 100644 index 000000000000..4b7099526d2c --- /dev/null +++ b/arch/x86/kernel/apb_timer.c | |||
| @@ -0,0 +1,784 @@ | |||
| 1 | /* | ||
| 2 | * apb_timer.c: Driver for Langwell APB timers | ||
| 3 | * | ||
| 4 | * (C) Copyright 2009 Intel Corporation | ||
| 5 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; version 2 | ||
| 10 | * of the License. | ||
| 11 | * | ||
| 12 | * Note: | ||
| 13 | * Langwell is the south complex of Intel Moorestown MID platform. There are | ||
| 14 | * eight external timers in total that can be used by the operating system. | ||
| 15 | * The timer information, such as frequency and addresses, is provided to the | ||
| 16 | * OS via SFI tables. | ||
| 17 | * Timer interrupts are routed via FW/HW emulated IOAPIC independently via | ||
| 18 | * individual redirection table entries (RTE). | ||
| 19 | * Unlike HPET, there is no master counter, therefore one of the timers are | ||
| 20 | * used as clocksource. The overall allocation looks like: | ||
| 21 | * - timer 0 - NR_CPUs for per cpu timer | ||
| 22 | * - one timer for clocksource | ||
| 23 | * - one timer for watchdog driver. | ||
| 24 | * It is also worth notice that APB timer does not support true one-shot mode, | ||
| 25 | * free-running mode will be used here to emulate one-shot mode. | ||
| 26 | * APB timer can also be used as broadcast timer along with per cpu local APIC | ||
| 27 | * timer, but by default APB timer has higher rating than local APIC timers. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/clocksource.h> | ||
| 31 | #include <linux/clockchips.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <linux/errno.h> | ||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/sysdev.h> | ||
| 36 | #include <linux/pm.h> | ||
| 37 | #include <linux/pci.h> | ||
| 38 | #include <linux/sfi.h> | ||
| 39 | #include <linux/interrupt.h> | ||
| 40 | #include <linux/cpu.h> | ||
| 41 | #include <linux/irq.h> | ||
| 42 | |||
| 43 | #include <asm/fixmap.h> | ||
| 44 | #include <asm/apb_timer.h> | ||
| 45 | |||
| 46 | #define APBT_MASK CLOCKSOURCE_MASK(32) | ||
| 47 | #define APBT_SHIFT 22 | ||
| 48 | #define APBT_CLOCKEVENT_RATING 150 | ||
| 49 | #define APBT_CLOCKSOURCE_RATING 250 | ||
| 50 | #define APBT_MIN_DELTA_USEC 200 | ||
| 51 | |||
| 52 | #define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) | ||
| 53 | #define APBT_CLOCKEVENT0_NUM (0) | ||
| 54 | #define APBT_CLOCKEVENT1_NUM (1) | ||
| 55 | #define APBT_CLOCKSOURCE_NUM (2) | ||
| 56 | |||
| 57 | static unsigned long apbt_address; | ||
| 58 | static int apb_timer_block_enabled; | ||
| 59 | static void __iomem *apbt_virt_address; | ||
| 60 | static int phy_cs_timer_id; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Common DW APB timer info | ||
| 64 | */ | ||
| 65 | static uint64_t apbt_freq; | ||
| 66 | |||
| 67 | static void apbt_set_mode(enum clock_event_mode mode, | ||
| 68 | struct clock_event_device *evt); | ||
| 69 | static int apbt_next_event(unsigned long delta, | ||
| 70 | struct clock_event_device *evt); | ||
| 71 | static cycle_t apbt_read_clocksource(struct clocksource *cs); | ||
| 72 | static void apbt_restart_clocksource(struct clocksource *cs); | ||
| 73 | |||
| 74 | struct apbt_dev { | ||
| 75 | struct clock_event_device evt; | ||
| 76 | unsigned int num; | ||
| 77 | int cpu; | ||
| 78 | unsigned int irq; | ||
| 79 | unsigned int tick; | ||
| 80 | unsigned int count; | ||
| 81 | unsigned int flags; | ||
| 82 | char name[10]; | ||
| 83 | }; | ||
| 84 | |||
| 85 | int disable_apbt_percpu __cpuinitdata; | ||
| 86 | |||
| 87 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); | ||
| 88 | |||
| 89 | #ifdef CONFIG_SMP | ||
| 90 | static unsigned int apbt_num_timers_used; | ||
| 91 | static struct apbt_dev *apbt_devs; | ||
| 92 | #endif | ||
| 93 | |||
| 94 | static inline unsigned long apbt_readl_reg(unsigned long a) | ||
| 95 | { | ||
| 96 | return readl(apbt_virt_address + a); | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline void apbt_writel_reg(unsigned long d, unsigned long a) | ||
| 100 | { | ||
| 101 | writel(d, apbt_virt_address + a); | ||
| 102 | } | ||
| 103 | |||
| 104 | static inline unsigned long apbt_readl(int n, unsigned long a) | ||
| 105 | { | ||
| 106 | return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline void apbt_writel(int n, unsigned long d, unsigned long a) | ||
| 110 | { | ||
| 111 | writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
| 112 | } | ||
| 113 | |||
| 114 | static inline void apbt_set_mapping(void) | ||
| 115 | { | ||
| 116 | struct sfi_timer_table_entry *mtmr; | ||
| 117 | |||
| 118 | if (apbt_virt_address) { | ||
| 119 | pr_debug("APBT base already mapped\n"); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM); | ||
| 123 | if (mtmr == NULL) { | ||
| 124 | printk(KERN_ERR "Failed to get MTMR %d from SFI\n", | ||
| 125 | APBT_CLOCKEVENT0_NUM); | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | apbt_address = (unsigned long)mtmr->phys_addr; | ||
| 129 | if (!apbt_address) { | ||
| 130 | printk(KERN_WARNING "No timer base from SFI, use default\n"); | ||
| 131 | apbt_address = APBT_DEFAULT_BASE; | ||
| 132 | } | ||
| 133 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); | ||
| 134 | if (apbt_virt_address) { | ||
| 135 | pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ | ||
| 136 | (void *)apbt_address, (void *)apbt_virt_address); | ||
| 137 | } else { | ||
| 138 | pr_debug("Failed mapping APBT phy address at %p\n",\ | ||
| 139 | (void *)apbt_address); | ||
| 140 | goto panic_noapbt; | ||
| 141 | } | ||
| 142 | apbt_freq = mtmr->freq_hz / USEC_PER_SEC; | ||
| 143 | sfi_free_mtmr(mtmr); | ||
| 144 | |||
| 145 | /* Now figure out the physical timer id for clocksource device */ | ||
| 146 | mtmr = sfi_get_mtmr(APBT_CLOCKSOURCE_NUM); | ||
| 147 | if (mtmr == NULL) | ||
| 148 | goto panic_noapbt; | ||
| 149 | |||
| 150 | /* Now figure out the physical timer id */ | ||
| 151 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) | ||
| 152 | / APBTMRS_REG_SIZE; | ||
| 153 | pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); | ||
| 154 | return; | ||
| 155 | |||
| 156 | panic_noapbt: | ||
| 157 | panic("Failed to setup APB system timer\n"); | ||
| 158 | |||
| 159 | } | ||
| 160 | |||
| 161 | static inline void apbt_clear_mapping(void) | ||
| 162 | { | ||
| 163 | iounmap(apbt_virt_address); | ||
| 164 | apbt_virt_address = NULL; | ||
| 165 | } | ||
| 166 | |||
| 167 | /* | ||
| 168 | * APBT timer interrupt enable / disable | ||
| 169 | */ | ||
| 170 | static inline int is_apbt_capable(void) | ||
| 171 | { | ||
| 172 | return apbt_virt_address ? 1 : 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static struct clocksource clocksource_apbt = { | ||
| 176 | .name = "apbt", | ||
| 177 | .rating = APBT_CLOCKSOURCE_RATING, | ||
| 178 | .read = apbt_read_clocksource, | ||
| 179 | .mask = APBT_MASK, | ||
| 180 | .shift = APBT_SHIFT, | ||
| 181 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 182 | .resume = apbt_restart_clocksource, | ||
| 183 | }; | ||
| 184 | |||
| 185 | /* boot APB clock event device */ | ||
| 186 | static struct clock_event_device apbt_clockevent = { | ||
| 187 | .name = "apbt0", | ||
| 188 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 189 | .set_mode = apbt_set_mode, | ||
| 190 | .set_next_event = apbt_next_event, | ||
| 191 | .shift = APBT_SHIFT, | ||
| 192 | .irq = 0, | ||
| 193 | .rating = APBT_CLOCKEVENT_RATING, | ||
| 194 | }; | ||
| 195 | |||
| 196 | /* | ||
| 197 | * if user does not want to use per CPU apb timer, just give it a lower rating | ||
| 198 | * than local apic timer and skip the late per cpu timer init. | ||
| 199 | */ | ||
| 200 | static inline int __init setup_x86_mrst_timer(char *arg) | ||
| 201 | { | ||
| 202 | if (!arg) | ||
| 203 | return -EINVAL; | ||
| 204 | |||
| 205 | if (strcmp("apbt_only", arg) == 0) | ||
| 206 | disable_apbt_percpu = 0; | ||
| 207 | else if (strcmp("lapic_and_apbt", arg) == 0) | ||
| 208 | disable_apbt_percpu = 1; | ||
| 209 | else { | ||
| 210 | pr_warning("X86 MRST timer option %s not recognised" | ||
| 211 | " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | ||
| 212 | arg); | ||
| 213 | return -EINVAL; | ||
| 214 | } | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); | ||
| 218 | |||
| 219 | /* | ||
| 220 | * start count down from 0xffff_ffff. this is done by toggling the enable bit | ||
| 221 | * then load initial load count to ~0. | ||
| 222 | */ | ||
| 223 | static void apbt_start_counter(int n) | ||
| 224 | { | ||
| 225 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 226 | |||
| 227 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 228 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 229 | apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); | ||
| 230 | /* enable, mask interrupt */ | ||
| 231 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 232 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
| 233 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 234 | /* read it once to get cached counter value initialized */ | ||
| 235 | apbt_read_clocksource(&clocksource_apbt); | ||
| 236 | } | ||
| 237 | |||
| 238 | static irqreturn_t apbt_interrupt_handler(int irq, void *data) | ||
| 239 | { | ||
| 240 | struct apbt_dev *dev = (struct apbt_dev *)data; | ||
| 241 | struct clock_event_device *aevt = &dev->evt; | ||
| 242 | |||
| 243 | if (!aevt->event_handler) { | ||
| 244 | printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", | ||
| 245 | dev->num); | ||
| 246 | return IRQ_NONE; | ||
| 247 | } | ||
| 248 | aevt->event_handler(aevt); | ||
| 249 | return IRQ_HANDLED; | ||
| 250 | } | ||
| 251 | |||
| 252 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
| 253 | { | ||
| 254 | apbt_start_counter(phy_cs_timer_id); | ||
| 255 | } | ||
| 256 | |||
| 257 | /* Setup IRQ routing via IOAPIC */ | ||
| 258 | #ifdef CONFIG_SMP | ||
| 259 | static void apbt_setup_irq(struct apbt_dev *adev) | ||
| 260 | { | ||
| 261 | struct irq_chip *chip; | ||
| 262 | struct irq_desc *desc; | ||
| 263 | |||
| 264 | /* timer0 irq has been setup early */ | ||
| 265 | if (adev->irq == 0) | ||
| 266 | return; | ||
| 267 | desc = irq_to_desc(adev->irq); | ||
| 268 | chip = get_irq_chip(adev->irq); | ||
| 269 | disable_irq(adev->irq); | ||
| 270 | desc->status |= IRQ_MOVE_PCNTXT; | ||
| 271 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); | ||
| 272 | /* APB timer irqs are set up as mp_irqs, timer is edge triggerred */ | ||
| 273 | set_irq_chip_and_handler_name(adev->irq, chip, handle_edge_irq, "edge"); | ||
| 274 | enable_irq(adev->irq); | ||
| 275 | if (system_state == SYSTEM_BOOTING) | ||
| 276 | if (request_irq(adev->irq, apbt_interrupt_handler, | ||
| 277 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
| 278 | adev->name, adev)) { | ||
| 279 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
| 280 | adev->num); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | #endif | ||
| 284 | |||
| 285 | static void apbt_enable_int(int n) | ||
| 286 | { | ||
| 287 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 288 | /* clear pending intr */ | ||
| 289 | apbt_readl(n, APBTMR_N_EOI); | ||
| 290 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 291 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 292 | } | ||
| 293 | |||
| 294 | static void apbt_disable_int(int n) | ||
| 295 | { | ||
| 296 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 297 | |||
| 298 | ctrl |= APBTMR_CONTROL_INT; | ||
| 299 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 300 | } | ||
| 301 | |||
| 302 | |||
| 303 | static int __init apbt_clockevent_register(void) | ||
| 304 | { | ||
| 305 | struct sfi_timer_table_entry *mtmr; | ||
| 306 | struct apbt_dev *adev = &__get_cpu_var(cpu_apbt_dev); | ||
| 307 | |||
| 308 | mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM); | ||
| 309 | if (mtmr == NULL) { | ||
| 310 | printk(KERN_ERR "Failed to get MTMR %d from SFI\n", | ||
| 311 | APBT_CLOCKEVENT0_NUM); | ||
| 312 | return -ENODEV; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* | ||
| 316 | * We need to calculate the scaled math multiplication factor for | ||
| 317 | * nanosecond to apbt tick conversion. | ||
| 318 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
| 319 | */ | ||
| 320 | apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz | ||
| 321 | , NSEC_PER_SEC, APBT_SHIFT); | ||
| 322 | |||
| 323 | /* Calculate the min / max delta */ | ||
| 324 | apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
| 325 | &apbt_clockevent); | ||
| 326 | apbt_clockevent.min_delta_ns = clockevent_delta2ns( | ||
| 327 | APBT_MIN_DELTA_USEC*apbt_freq, | ||
| 328 | &apbt_clockevent); | ||
| 329 | /* | ||
| 330 | * Start apbt with the boot cpu mask and make it | ||
| 331 | * global if not used for per cpu timer. | ||
| 332 | */ | ||
| 333 | apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); | ||
| 334 | adev->num = smp_processor_id(); | ||
| 335 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); | ||
| 336 | |||
| 337 | if (disable_apbt_percpu) { | ||
| 338 | apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100; | ||
| 339 | global_clock_event = &adev->evt; | ||
| 340 | printk(KERN_DEBUG "%s clockevent registered as global\n", | ||
| 341 | global_clock_event->name); | ||
| 342 | } | ||
| 343 | |||
| 344 | if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, | ||
| 345 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
| 346 | apbt_clockevent.name, adev)) { | ||
| 347 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
| 348 | apbt_clockevent.irq); | ||
| 349 | } | ||
| 350 | |||
| 351 | clockevents_register_device(&adev->evt); | ||
| 352 | /* Start APBT 0 interrupts */ | ||
| 353 | apbt_enable_int(APBT_CLOCKEVENT0_NUM); | ||
| 354 | |||
| 355 | sfi_free_mtmr(mtmr); | ||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | #ifdef CONFIG_SMP | ||
| 360 | /* Should be called with per cpu */ | ||
| 361 | void apbt_setup_secondary_clock(void) | ||
| 362 | { | ||
| 363 | struct apbt_dev *adev; | ||
| 364 | struct clock_event_device *aevt; | ||
| 365 | int cpu; | ||
| 366 | |||
| 367 | /* Don't register boot CPU clockevent */ | ||
| 368 | cpu = smp_processor_id(); | ||
| 369 | if (cpu == boot_cpu_id) | ||
| 370 | return; | ||
| 371 | /* | ||
| 372 | * We need to calculate the scaled math multiplication factor for | ||
| 373 | * nanosecond to apbt tick conversion. | ||
| 374 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
| 375 | */ | ||
| 376 | printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); | ||
| 377 | adev = &per_cpu(cpu_apbt_dev, cpu); | ||
| 378 | aevt = &adev->evt; | ||
| 379 | |||
| 380 | memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); | ||
| 381 | aevt->cpumask = cpumask_of(cpu); | ||
| 382 | aevt->name = adev->name; | ||
| 383 | aevt->mode = CLOCK_EVT_MODE_UNUSED; | ||
| 384 | |||
| 385 | printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", | ||
| 386 | cpu, aevt->name, *(u32 *)aevt->cpumask); | ||
| 387 | |||
| 388 | apbt_setup_irq(adev); | ||
| 389 | |||
| 390 | clockevents_register_device(aevt); | ||
| 391 | |||
| 392 | apbt_enable_int(cpu); | ||
| 393 | |||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | /* | ||
| 398 | * this notify handler process CPU hotplug events. in case of S0i3, nonboot | ||
| 399 | * cpus are disabled/enabled frequently, for performance reasons, we keep the | ||
| 400 | * per cpu timer irq registered so that we do need to do free_irq/request_irq. | ||
| 401 | * | ||
| 402 | * TODO: it might be more reliable to directly disable percpu clockevent device | ||
| 403 | * without the notifier chain. currently, cpu 0 may get interrupts from other | ||
| 404 | * cpu timers during the offline process due to the ordering of notification. | ||
| 405 | * the extra interrupt is harmless. | ||
| 406 | */ | ||
| 407 | static int apbt_cpuhp_notify(struct notifier_block *n, | ||
| 408 | unsigned long action, void *hcpu) | ||
| 409 | { | ||
| 410 | unsigned long cpu = (unsigned long)hcpu; | ||
| 411 | struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu); | ||
| 412 | |||
| 413 | switch (action & 0xf) { | ||
| 414 | case CPU_DEAD: | ||
| 415 | apbt_disable_int(cpu); | ||
| 416 | if (system_state == SYSTEM_RUNNING) | ||
| 417 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | ||
| 418 | else if (adev) { | ||
| 419 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | ||
| 420 | free_irq(adev->irq, adev); | ||
| 421 | } | ||
| 422 | break; | ||
| 423 | default: | ||
| 424 | pr_debug(KERN_INFO "APBT notified %lu, no action\n", action); | ||
| 425 | } | ||
| 426 | return NOTIFY_OK; | ||
| 427 | } | ||
| 428 | |||
| 429 | static __init int apbt_late_init(void) | ||
| 430 | { | ||
| 431 | if (disable_apbt_percpu) | ||
| 432 | return 0; | ||
| 433 | /* This notifier should be called after workqueue is ready */ | ||
| 434 | hotcpu_notifier(apbt_cpuhp_notify, -20); | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | fs_initcall(apbt_late_init); | ||
| 438 | #else | ||
| 439 | |||
| 440 | void apbt_setup_secondary_clock(void) {} | ||
| 441 | |||
| 442 | #endif /* CONFIG_SMP */ | ||
| 443 | |||
| 444 | static void apbt_set_mode(enum clock_event_mode mode, | ||
| 445 | struct clock_event_device *evt) | ||
| 446 | { | ||
| 447 | unsigned long ctrl; | ||
| 448 | uint64_t delta; | ||
| 449 | int timer_num; | ||
| 450 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
| 451 | |||
| 452 | timer_num = adev->num; | ||
| 453 | pr_debug("%s CPU %d timer %d mode=%d\n", | ||
| 454 | __func__, first_cpu(*evt->cpumask), timer_num, mode); | ||
| 455 | |||
| 456 | switch (mode) { | ||
| 457 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 458 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; | ||
| 459 | delta >>= apbt_clockevent.shift; | ||
| 460 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 461 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
| 462 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 463 | /* | ||
| 464 | * DW APB p. 46, have to disable timer before load counter, | ||
| 465 | * may cause sync problem. | ||
| 466 | */ | ||
| 467 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 468 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 469 | udelay(1); | ||
| 470 | pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); | ||
| 471 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
| 472 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 473 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 474 | break; | ||
| 475 | /* APB timer does not have one-shot mode, use free running mode */ | ||
| 476 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 477 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 478 | /* | ||
| 479 | * set free running mode, this mode will let timer reload max | ||
| 480 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
| 481 | * the next event, therefore emulate the one-shot mode. | ||
| 482 | */ | ||
| 483 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 484 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 485 | |||
| 486 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 487 | /* write again to set free running mode */ | ||
| 488 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 489 | |||
| 490 | /* | ||
| 491 | * DW APB p. 46, load counter with all 1s before starting free | ||
| 492 | * running mode. | ||
| 493 | */ | ||
| 494 | apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); | ||
| 495 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 496 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 497 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 498 | break; | ||
| 499 | |||
| 500 | case CLOCK_EVT_MODE_UNUSED: | ||
| 501 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 502 | apbt_disable_int(timer_num); | ||
| 503 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 504 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 505 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 506 | break; | ||
| 507 | |||
| 508 | case CLOCK_EVT_MODE_RESUME: | ||
| 509 | apbt_enable_int(timer_num); | ||
| 510 | break; | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | static int apbt_next_event(unsigned long delta, | ||
| 515 | struct clock_event_device *evt) | ||
| 516 | { | ||
| 517 | unsigned long ctrl; | ||
| 518 | int timer_num; | ||
| 519 | |||
| 520 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
| 521 | |||
| 522 | timer_num = adev->num; | ||
| 523 | /* Disable timer */ | ||
| 524 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 525 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 526 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 527 | /* write new count */ | ||
| 528 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
| 529 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 530 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | /* | ||
| 535 | * APB timer clock is not in sync with pclk on Langwell, which translates to | ||
| 536 | * unreliable read value caused by sampling error. the error does not add up | ||
| 537 | * overtime and only happens when sampling a 0 as a 1 by mistake. so the time | ||
| 538 | * would go backwards. the following code is trying to prevent time traveling | ||
| 539 | * backwards. little bit paranoid. | ||
| 540 | */ | ||
| 541 | static cycle_t apbt_read_clocksource(struct clocksource *cs) | ||
| 542 | { | ||
| 543 | unsigned long t0, t1, t2; | ||
| 544 | static unsigned long last_read; | ||
| 545 | |||
| 546 | bad_count: | ||
| 547 | t1 = apbt_readl(phy_cs_timer_id, | ||
| 548 | APBTMR_N_CURRENT_VALUE); | ||
| 549 | t2 = apbt_readl(phy_cs_timer_id, | ||
| 550 | APBTMR_N_CURRENT_VALUE); | ||
| 551 | if (unlikely(t1 < t2)) { | ||
| 552 | pr_debug("APBT: read current count error %lx:%lx:%lx\n", | ||
| 553 | t1, t2, t2 - t1); | ||
| 554 | goto bad_count; | ||
| 555 | } | ||
| 556 | /* | ||
| 557 | * check against cached last read, makes sure time does not go back. | ||
| 558 | * it could be a normal rollover but we will do tripple check anyway | ||
| 559 | */ | ||
| 560 | if (unlikely(t2 > last_read)) { | ||
| 561 | /* check if we have a normal rollover */ | ||
| 562 | unsigned long raw_intr_status = | ||
| 563 | apbt_readl_reg(APBTMRS_RAW_INT_STATUS); | ||
| 564 | /* | ||
| 565 | * cs timer interrupt is masked but raw intr bit is set if | ||
| 566 | * rollover occurs. then we read EOI reg to clear it. | ||
| 567 | */ | ||
| 568 | if (raw_intr_status & (1 << phy_cs_timer_id)) { | ||
| 569 | apbt_readl(phy_cs_timer_id, APBTMR_N_EOI); | ||
| 570 | goto out; | ||
| 571 | } | ||
| 572 | pr_debug("APB CS going back %lx:%lx:%lx ", | ||
| 573 | t2, last_read, t2 - last_read); | ||
| 574 | bad_count_x3: | ||
| 575 | pr_debug(KERN_INFO "tripple check enforced\n"); | ||
| 576 | t0 = apbt_readl(phy_cs_timer_id, | ||
| 577 | APBTMR_N_CURRENT_VALUE); | ||
| 578 | udelay(1); | ||
| 579 | t1 = apbt_readl(phy_cs_timer_id, | ||
| 580 | APBTMR_N_CURRENT_VALUE); | ||
| 581 | udelay(1); | ||
| 582 | t2 = apbt_readl(phy_cs_timer_id, | ||
| 583 | APBTMR_N_CURRENT_VALUE); | ||
| 584 | if ((t2 > t1) || (t1 > t0)) { | ||
| 585 | printk(KERN_ERR "Error: APB CS tripple check failed\n"); | ||
| 586 | goto bad_count_x3; | ||
| 587 | } | ||
| 588 | } | ||
| 589 | out: | ||
| 590 | last_read = t2; | ||
| 591 | return (cycle_t)~t2; | ||
| 592 | } | ||
| 593 | |||
| 594 | static int apbt_clocksource_register(void) | ||
| 595 | { | ||
| 596 | u64 start, now; | ||
| 597 | cycle_t t1; | ||
| 598 | |||
| 599 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ | ||
| 600 | apbt_start_counter(phy_cs_timer_id); | ||
| 601 | |||
| 602 | /* Verify whether apbt counter works */ | ||
| 603 | t1 = apbt_read_clocksource(&clocksource_apbt); | ||
| 604 | rdtscll(start); | ||
| 605 | |||
| 606 | /* | ||
| 607 | * We don't know the TSC frequency yet, but waiting for | ||
| 608 | * 200000 TSC cycles is safe: | ||
| 609 | * 4 GHz == 50us | ||
| 610 | * 1 GHz == 200us | ||
| 611 | */ | ||
| 612 | do { | ||
| 613 | rep_nop(); | ||
| 614 | rdtscll(now); | ||
| 615 | } while ((now - start) < 200000UL); | ||
| 616 | |||
| 617 | /* APBT is the only always on clocksource, it has to work! */ | ||
| 618 | if (t1 == apbt_read_clocksource(&clocksource_apbt)) | ||
| 619 | panic("APBT counter not counting. APBT disabled\n"); | ||
| 620 | |||
| 621 | /* | ||
| 622 | * initialize and register APBT clocksource | ||
| 623 | * convert that to ns/clock cycle | ||
| 624 | * mult = (ns/c) * 2^APBT_SHIFT | ||
| 625 | */ | ||
| 626 | clocksource_apbt.mult = div_sc(MSEC_PER_SEC, | ||
| 627 | (unsigned long) apbt_freq, APBT_SHIFT); | ||
| 628 | clocksource_register(&clocksource_apbt); | ||
| 629 | |||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | |||
| 633 | /* | ||
| 634 | * Early setup the APBT timer, only use timer 0 for booting then switch to | ||
| 635 | * per CPU timer if possible. | ||
| 636 | * returns 1 if per cpu apbt is setup | ||
| 637 | * returns 0 if no per cpu apbt is chosen | ||
| 638 | * panic if set up failed, this is the only platform timer on Moorestown. | ||
| 639 | */ | ||
| 640 | void __init apbt_time_init(void) | ||
| 641 | { | ||
| 642 | #ifdef CONFIG_SMP | ||
| 643 | int i; | ||
| 644 | struct sfi_timer_table_entry *p_mtmr; | ||
| 645 | unsigned int percpu_timer; | ||
| 646 | struct apbt_dev *adev; | ||
| 647 | #endif | ||
| 648 | |||
| 649 | if (apb_timer_block_enabled) | ||
| 650 | return; | ||
| 651 | apbt_set_mapping(); | ||
| 652 | if (apbt_virt_address) { | ||
| 653 | pr_debug("Found APBT version 0x%lx\n",\ | ||
| 654 | apbt_readl_reg(APBTMRS_COMP_VERSION)); | ||
| 655 | } else | ||
| 656 | goto out_noapbt; | ||
| 657 | /* | ||
| 658 | * Read the frequency and check for a sane value, for ESL model | ||
| 659 | * we extend the possible clock range to allow time scaling. | ||
| 660 | */ | ||
| 661 | |||
| 662 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { | ||
| 663 | pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); | ||
| 664 | goto out_noapbt; | ||
| 665 | } | ||
| 666 | if (apbt_clocksource_register()) { | ||
| 667 | pr_debug("APBT has failed to register clocksource\n"); | ||
| 668 | goto out_noapbt; | ||
| 669 | } | ||
| 670 | if (!apbt_clockevent_register()) | ||
| 671 | apb_timer_block_enabled = 1; | ||
| 672 | else { | ||
| 673 | pr_debug("APBT has failed to register clockevent\n"); | ||
| 674 | goto out_noapbt; | ||
| 675 | } | ||
| 676 | #ifdef CONFIG_SMP | ||
| 677 | /* kernel cmdline disable apb timer, so we will use lapic timers */ | ||
| 678 | if (disable_apbt_percpu) { | ||
| 679 | printk(KERN_INFO "apbt: disabled per cpu timer\n"); | ||
| 680 | return; | ||
| 681 | } | ||
| 682 | pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus()); | ||
| 683 | if (num_possible_cpus() <= sfi_mtimer_num) { | ||
| 684 | percpu_timer = 1; | ||
| 685 | apbt_num_timers_used = num_possible_cpus(); | ||
| 686 | } else { | ||
| 687 | percpu_timer = 0; | ||
| 688 | apbt_num_timers_used = 1; | ||
| 689 | adev = &per_cpu(cpu_apbt_dev, 0); | ||
| 690 | adev->flags &= ~APBT_DEV_USED; | ||
| 691 | } | ||
| 692 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); | ||
| 693 | |||
| 694 | /* here we set up per CPU timer data structure */ | ||
| 695 | apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, | ||
| 696 | GFP_KERNEL); | ||
| 697 | if (!apbt_devs) { | ||
| 698 | printk(KERN_ERR "Failed to allocate APB timer devices\n"); | ||
| 699 | return; | ||
| 700 | } | ||
| 701 | for (i = 0; i < apbt_num_timers_used; i++) { | ||
| 702 | adev = &per_cpu(cpu_apbt_dev, i); | ||
| 703 | adev->num = i; | ||
| 704 | adev->cpu = i; | ||
| 705 | p_mtmr = sfi_get_mtmr(i); | ||
| 706 | if (p_mtmr) { | ||
| 707 | adev->tick = p_mtmr->freq_hz; | ||
| 708 | adev->irq = p_mtmr->irq; | ||
| 709 | } else | ||
| 710 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); | ||
| 711 | adev->count = 0; | ||
| 712 | sprintf(adev->name, "apbt%d", i); | ||
| 713 | } | ||
| 714 | #endif | ||
| 715 | |||
| 716 | return; | ||
| 717 | |||
| 718 | out_noapbt: | ||
| 719 | apbt_clear_mapping(); | ||
| 720 | apb_timer_block_enabled = 0; | ||
| 721 | panic("failed to enable APB timer\n"); | ||
| 722 | } | ||
| 723 | |||
| 724 | static inline void apbt_disable(int n) | ||
| 725 | { | ||
| 726 | if (is_apbt_capable()) { | ||
| 727 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 728 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 729 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | /* called before apb_timer_enable, use early map */ | ||
| 734 | unsigned long apbt_quick_calibrate() | ||
| 735 | { | ||
| 736 | int i, scale; | ||
| 737 | u64 old, new; | ||
| 738 | cycle_t t1, t2; | ||
| 739 | unsigned long khz = 0; | ||
| 740 | u32 loop, shift; | ||
| 741 | |||
| 742 | apbt_set_mapping(); | ||
| 743 | apbt_start_counter(phy_cs_timer_id); | ||
| 744 | |||
| 745 | /* check if the timer can count down, otherwise return */ | ||
| 746 | old = apbt_read_clocksource(&clocksource_apbt); | ||
| 747 | i = 10000; | ||
| 748 | while (--i) { | ||
| 749 | if (old != apbt_read_clocksource(&clocksource_apbt)) | ||
| 750 | break; | ||
| 751 | } | ||
| 752 | if (!i) | ||
| 753 | goto failed; | ||
| 754 | |||
| 755 | /* count 16 ms */ | ||
| 756 | loop = (apbt_freq * 1000) << 4; | ||
| 757 | |||
| 758 | /* restart the timer to ensure it won't get to 0 in the calibration */ | ||
| 759 | apbt_start_counter(phy_cs_timer_id); | ||
| 760 | |||
| 761 | old = apbt_read_clocksource(&clocksource_apbt); | ||
| 762 | old += loop; | ||
| 763 | |||
| 764 | t1 = __native_read_tsc(); | ||
| 765 | |||
| 766 | do { | ||
| 767 | new = apbt_read_clocksource(&clocksource_apbt); | ||
| 768 | } while (new < old); | ||
| 769 | |||
| 770 | t2 = __native_read_tsc(); | ||
| 771 | |||
| 772 | shift = 5; | ||
| 773 | if (unlikely(loop >> shift == 0)) { | ||
| 774 | printk(KERN_INFO | ||
| 775 | "APBT TSC calibration failed, not enough resolution\n"); | ||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | scale = (int)div_u64((t2 - t1), loop >> shift); | ||
| 779 | khz = (scale * apbt_freq * 1000) >> shift; | ||
| 780 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); | ||
| 781 | return khz; | ||
| 782 | failed: | ||
| 783 | return 0; | ||
| 784 | } | ||
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 6e29b2a77aa8..00187f1fcfb7 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
| @@ -1390,7 +1390,7 @@ void __init enable_IR_x2apic(void) | |||
| 1390 | } | 1390 | } |
| 1391 | 1391 | ||
| 1392 | local_irq_save(flags); | 1392 | local_irq_save(flags); |
| 1393 | mask_8259A(); | 1393 | legacy_pic->mask_all(); |
| 1394 | mask_IO_APIC_setup(ioapic_entries); | 1394 | mask_IO_APIC_setup(ioapic_entries); |
| 1395 | 1395 | ||
| 1396 | if (dmar_table_init_ret) | 1396 | if (dmar_table_init_ret) |
| @@ -1422,7 +1422,7 @@ void __init enable_IR_x2apic(void) | |||
| 1422 | nox2apic: | 1422 | nox2apic: |
| 1423 | if (!ret) /* IR enabling failed */ | 1423 | if (!ret) /* IR enabling failed */ |
| 1424 | restore_IO_APIC_setup(ioapic_entries); | 1424 | restore_IO_APIC_setup(ioapic_entries); |
| 1425 | unmask_8259A(); | 1425 | legacy_pic->restore_mask(); |
| 1426 | local_irq_restore(flags); | 1426 | local_irq_restore(flags); |
| 1427 | 1427 | ||
| 1428 | out: | 1428 | out: |
| @@ -2018,7 +2018,7 @@ static int lapic_resume(struct sys_device *dev) | |||
| 2018 | } | 2018 | } |
| 2019 | 2019 | ||
| 2020 | mask_IO_APIC_setup(ioapic_entries); | 2020 | mask_IO_APIC_setup(ioapic_entries); |
| 2021 | mask_8259A(); | 2021 | legacy_pic->mask_all(); |
| 2022 | } | 2022 | } |
| 2023 | 2023 | ||
| 2024 | if (x2apic_mode) | 2024 | if (x2apic_mode) |
| @@ -2062,7 +2062,7 @@ static int lapic_resume(struct sys_device *dev) | |||
| 2062 | 2062 | ||
| 2063 | if (intr_remapping_enabled) { | 2063 | if (intr_remapping_enabled) { |
| 2064 | reenable_intr_remapping(x2apic_mode); | 2064 | reenable_intr_remapping(x2apic_mode); |
| 2065 | unmask_8259A(); | 2065 | legacy_pic->restore_mask(); |
| 2066 | restore_IO_APIC_setup(ioapic_entries); | 2066 | restore_IO_APIC_setup(ioapic_entries); |
| 2067 | free_ioapic_entries(ioapic_entries); | 2067 | free_ioapic_entries(ioapic_entries); |
| 2068 | } | 2068 | } |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 14862f11cc4a..e4e0ddcb1546 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
| @@ -143,12 +143,6 @@ static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY]; | |||
| 143 | static struct irq_cfg irq_cfgx[NR_IRQS]; | 143 | static struct irq_cfg irq_cfgx[NR_IRQS]; |
| 144 | #endif | 144 | #endif |
| 145 | 145 | ||
| 146 | void __init io_apic_disable_legacy(void) | ||
| 147 | { | ||
| 148 | nr_legacy_irqs = 0; | ||
| 149 | nr_irqs_gsi = 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | int __init arch_early_irq_init(void) | 146 | int __init arch_early_irq_init(void) |
| 153 | { | 147 | { |
| 154 | struct irq_cfg *cfg; | 148 | struct irq_cfg *cfg; |
| @@ -157,6 +151,11 @@ int __init arch_early_irq_init(void) | |||
| 157 | int node; | 151 | int node; |
| 158 | int i; | 152 | int i; |
| 159 | 153 | ||
| 154 | if (!legacy_pic->nr_legacy_irqs) { | ||
| 155 | nr_irqs_gsi = 0; | ||
| 156 | io_apic_irqs = ~0UL; | ||
| 157 | } | ||
| 158 | |||
| 160 | cfg = irq_cfgx; | 159 | cfg = irq_cfgx; |
| 161 | count = ARRAY_SIZE(irq_cfgx); | 160 | count = ARRAY_SIZE(irq_cfgx); |
| 162 | node= cpu_to_node(boot_cpu_id); | 161 | node= cpu_to_node(boot_cpu_id); |
| @@ -170,7 +169,7 @@ int __init arch_early_irq_init(void) | |||
| 170 | * For legacy IRQ's, start with assigning irq0 to irq15 to | 169 | * For legacy IRQ's, start with assigning irq0 to irq15 to |
| 171 | * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0. | 170 | * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0. |
| 172 | */ | 171 | */ |
| 173 | if (i < nr_legacy_irqs) { | 172 | if (i < legacy_pic->nr_legacy_irqs) { |
| 174 | cfg[i].vector = IRQ0_VECTOR + i; | 173 | cfg[i].vector = IRQ0_VECTOR + i; |
| 175 | cpumask_set_cpu(0, cfg[i].domain); | 174 | cpumask_set_cpu(0, cfg[i].domain); |
| 176 | } | 175 | } |
| @@ -852,7 +851,7 @@ static int __init find_isa_irq_apic(int irq, int type) | |||
| 852 | */ | 851 | */ |
| 853 | static int EISA_ELCR(unsigned int irq) | 852 | static int EISA_ELCR(unsigned int irq) |
| 854 | { | 853 | { |
| 855 | if (irq < nr_legacy_irqs) { | 854 | if (irq < legacy_pic->nr_legacy_irqs) { |
| 856 | unsigned int port = 0x4d0 + (irq >> 3); | 855 | unsigned int port = 0x4d0 + (irq >> 3); |
| 857 | return (inb(port) >> (irq & 7)) & 1; | 856 | return (inb(port) >> (irq & 7)) & 1; |
| 858 | } | 857 | } |
| @@ -1439,7 +1438,7 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq | |||
| 1439 | * controllers like 8259. Now that IO-APIC can handle this irq, update | 1438 | * controllers like 8259. Now that IO-APIC can handle this irq, update |
| 1440 | * the cfg->domain. | 1439 | * the cfg->domain. |
| 1441 | */ | 1440 | */ |
| 1442 | if (irq < nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain)) | 1441 | if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain)) |
| 1443 | apic->vector_allocation_domain(0, cfg->domain); | 1442 | apic->vector_allocation_domain(0, cfg->domain); |
| 1444 | 1443 | ||
| 1445 | if (assign_irq_vector(irq, cfg, apic->target_cpus())) | 1444 | if (assign_irq_vector(irq, cfg, apic->target_cpus())) |
| @@ -1463,8 +1462,8 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq | |||
| 1463 | } | 1462 | } |
| 1464 | 1463 | ||
| 1465 | ioapic_register_intr(irq, desc, trigger); | 1464 | ioapic_register_intr(irq, desc, trigger); |
| 1466 | if (irq < nr_legacy_irqs) | 1465 | if (irq < legacy_pic->nr_legacy_irqs) |
| 1467 | disable_8259A_irq(irq); | 1466 | legacy_pic->chip->mask(irq); |
| 1468 | 1467 | ||
| 1469 | ioapic_write_entry(apic_id, pin, entry); | 1468 | ioapic_write_entry(apic_id, pin, entry); |
| 1470 | } | 1469 | } |
| @@ -1873,7 +1872,7 @@ __apicdebuginit(void) print_PIC(void) | |||
| 1873 | unsigned int v; | 1872 | unsigned int v; |
| 1874 | unsigned long flags; | 1873 | unsigned long flags; |
| 1875 | 1874 | ||
| 1876 | if (!nr_legacy_irqs) | 1875 | if (!legacy_pic->nr_legacy_irqs) |
| 1877 | return; | 1876 | return; |
| 1878 | 1877 | ||
| 1879 | printk(KERN_DEBUG "\nprinting PIC contents\n"); | 1878 | printk(KERN_DEBUG "\nprinting PIC contents\n"); |
| @@ -1957,7 +1956,7 @@ void __init enable_IO_APIC(void) | |||
| 1957 | nr_ioapic_registers[apic] = reg_01.bits.entries+1; | 1956 | nr_ioapic_registers[apic] = reg_01.bits.entries+1; |
| 1958 | } | 1957 | } |
| 1959 | 1958 | ||
| 1960 | if (!nr_legacy_irqs) | 1959 | if (!legacy_pic->nr_legacy_irqs) |
| 1961 | return; | 1960 | return; |
| 1962 | 1961 | ||
| 1963 | for(apic = 0; apic < nr_ioapics; apic++) { | 1962 | for(apic = 0; apic < nr_ioapics; apic++) { |
| @@ -2014,7 +2013,7 @@ void disable_IO_APIC(void) | |||
| 2014 | */ | 2013 | */ |
| 2015 | clear_IO_APIC(); | 2014 | clear_IO_APIC(); |
| 2016 | 2015 | ||
| 2017 | if (!nr_legacy_irqs) | 2016 | if (!legacy_pic->nr_legacy_irqs) |
| 2018 | return; | 2017 | return; |
| 2019 | 2018 | ||
| 2020 | /* | 2019 | /* |
| @@ -2247,9 +2246,9 @@ static unsigned int startup_ioapic_irq(unsigned int irq) | |||
| 2247 | struct irq_cfg *cfg; | 2246 | struct irq_cfg *cfg; |
| 2248 | 2247 | ||
| 2249 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 2248 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
| 2250 | if (irq < nr_legacy_irqs) { | 2249 | if (irq < legacy_pic->nr_legacy_irqs) { |
| 2251 | disable_8259A_irq(irq); | 2250 | legacy_pic->chip->mask(irq); |
| 2252 | if (i8259A_irq_pending(irq)) | 2251 | if (legacy_pic->irq_pending(irq)) |
| 2253 | was_pending = 1; | 2252 | was_pending = 1; |
| 2254 | } | 2253 | } |
| 2255 | cfg = irq_cfg(irq); | 2254 | cfg = irq_cfg(irq); |
| @@ -2782,8 +2781,8 @@ static inline void init_IO_APIC_traps(void) | |||
| 2782 | * so default to an old-fashioned 8259 | 2781 | * so default to an old-fashioned 8259 |
| 2783 | * interrupt if we can.. | 2782 | * interrupt if we can.. |
| 2784 | */ | 2783 | */ |
| 2785 | if (irq < nr_legacy_irqs) | 2784 | if (irq < legacy_pic->nr_legacy_irqs) |
| 2786 | make_8259A_irq(irq); | 2785 | legacy_pic->make_irq(irq); |
| 2787 | else | 2786 | else |
| 2788 | /* Strange. Oh, well.. */ | 2787 | /* Strange. Oh, well.. */ |
| 2789 | desc->chip = &no_irq_chip; | 2788 | desc->chip = &no_irq_chip; |
| @@ -2940,7 +2939,7 @@ static inline void __init check_timer(void) | |||
| 2940 | /* | 2939 | /* |
| 2941 | * get/set the timer IRQ vector: | 2940 | * get/set the timer IRQ vector: |
| 2942 | */ | 2941 | */ |
| 2943 | disable_8259A_irq(0); | 2942 | legacy_pic->chip->mask(0); |
| 2944 | assign_irq_vector(0, cfg, apic->target_cpus()); | 2943 | assign_irq_vector(0, cfg, apic->target_cpus()); |
| 2945 | 2944 | ||
| 2946 | /* | 2945 | /* |
| @@ -2953,7 +2952,7 @@ static inline void __init check_timer(void) | |||
| 2953 | * automatically. | 2952 | * automatically. |
| 2954 | */ | 2953 | */ |
| 2955 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); | 2954 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); |
| 2956 | init_8259A(1); | 2955 | legacy_pic->init(1); |
| 2957 | #ifdef CONFIG_X86_32 | 2956 | #ifdef CONFIG_X86_32 |
| 2958 | { | 2957 | { |
| 2959 | unsigned int ver; | 2958 | unsigned int ver; |
| @@ -3012,7 +3011,7 @@ static inline void __init check_timer(void) | |||
| 3012 | if (timer_irq_works()) { | 3011 | if (timer_irq_works()) { |
| 3013 | if (nmi_watchdog == NMI_IO_APIC) { | 3012 | if (nmi_watchdog == NMI_IO_APIC) { |
| 3014 | setup_nmi(); | 3013 | setup_nmi(); |
| 3015 | enable_8259A_irq(0); | 3014 | legacy_pic->chip->unmask(0); |
| 3016 | } | 3015 | } |
| 3017 | if (disable_timer_pin_1 > 0) | 3016 | if (disable_timer_pin_1 > 0) |
| 3018 | clear_IO_APIC_pin(0, pin1); | 3017 | clear_IO_APIC_pin(0, pin1); |
| @@ -3035,14 +3034,14 @@ static inline void __init check_timer(void) | |||
| 3035 | */ | 3034 | */ |
| 3036 | replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); | 3035 | replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); |
| 3037 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); | 3036 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); |
| 3038 | enable_8259A_irq(0); | 3037 | legacy_pic->chip->unmask(0); |
| 3039 | if (timer_irq_works()) { | 3038 | if (timer_irq_works()) { |
| 3040 | apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); | 3039 | apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); |
| 3041 | timer_through_8259 = 1; | 3040 | timer_through_8259 = 1; |
| 3042 | if (nmi_watchdog == NMI_IO_APIC) { | 3041 | if (nmi_watchdog == NMI_IO_APIC) { |
| 3043 | disable_8259A_irq(0); | 3042 | legacy_pic->chip->mask(0); |
| 3044 | setup_nmi(); | 3043 | setup_nmi(); |
| 3045 | enable_8259A_irq(0); | 3044 | legacy_pic->chip->unmask(0); |
| 3046 | } | 3045 | } |
| 3047 | goto out; | 3046 | goto out; |
| 3048 | } | 3047 | } |
| @@ -3050,7 +3049,7 @@ static inline void __init check_timer(void) | |||
| 3050 | * Cleanup, just in case ... | 3049 | * Cleanup, just in case ... |
| 3051 | */ | 3050 | */ |
| 3052 | local_irq_disable(); | 3051 | local_irq_disable(); |
| 3053 | disable_8259A_irq(0); | 3052 | legacy_pic->chip->mask(0); |
| 3054 | clear_IO_APIC_pin(apic2, pin2); | 3053 | clear_IO_APIC_pin(apic2, pin2); |
| 3055 | apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n"); | 3054 | apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n"); |
| 3056 | } | 3055 | } |
| @@ -3069,22 +3068,22 @@ static inline void __init check_timer(void) | |||
| 3069 | 3068 | ||
| 3070 | lapic_register_intr(0, desc); | 3069 | lapic_register_intr(0, desc); |
| 3071 | apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ | 3070 | apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ |
| 3072 | enable_8259A_irq(0); | 3071 | legacy_pic->chip->unmask(0); |
| 3073 | 3072 | ||
| 3074 | if (timer_irq_works()) { | 3073 | if (timer_irq_works()) { |
| 3075 | apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); | 3074 | apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); |
| 3076 | goto out; | 3075 | goto out; |
| 3077 | } | 3076 | } |
| 3078 | local_irq_disable(); | 3077 | local_irq_disable(); |
| 3079 | disable_8259A_irq(0); | 3078 | legacy_pic->chip->mask(0); |
| 3080 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); | 3079 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); |
| 3081 | apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n"); | 3080 | apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n"); |
| 3082 | 3081 | ||
| 3083 | apic_printk(APIC_QUIET, KERN_INFO | 3082 | apic_printk(APIC_QUIET, KERN_INFO |
| 3084 | "...trying to set up timer as ExtINT IRQ...\n"); | 3083 | "...trying to set up timer as ExtINT IRQ...\n"); |
| 3085 | 3084 | ||
| 3086 | init_8259A(0); | 3085 | legacy_pic->init(0); |
| 3087 | make_8259A_irq(0); | 3086 | legacy_pic->make_irq(0); |
| 3088 | apic_write(APIC_LVT0, APIC_DM_EXTINT); | 3087 | apic_write(APIC_LVT0, APIC_DM_EXTINT); |
| 3089 | 3088 | ||
| 3090 | unlock_ExtINT_logic(); | 3089 | unlock_ExtINT_logic(); |
| @@ -3126,7 +3125,7 @@ void __init setup_IO_APIC(void) | |||
| 3126 | /* | 3125 | /* |
| 3127 | * calling enable_IO_APIC() is moved to setup_local_APIC for BP | 3126 | * calling enable_IO_APIC() is moved to setup_local_APIC for BP |
| 3128 | */ | 3127 | */ |
| 3129 | io_apic_irqs = nr_legacy_irqs ? ~PIC_IRQS : ~0UL; | 3128 | io_apic_irqs = legacy_pic->nr_legacy_irqs ? ~PIC_IRQS : ~0UL; |
| 3130 | 3129 | ||
| 3131 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); | 3130 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); |
| 3132 | /* | 3131 | /* |
| @@ -3137,7 +3136,7 @@ void __init setup_IO_APIC(void) | |||
| 3137 | sync_Arb_IDs(); | 3136 | sync_Arb_IDs(); |
| 3138 | setup_IO_APIC_irqs(); | 3137 | setup_IO_APIC_irqs(); |
| 3139 | init_IO_APIC_traps(); | 3138 | init_IO_APIC_traps(); |
| 3140 | if (nr_legacy_irqs) | 3139 | if (legacy_pic->nr_legacy_irqs) |
| 3141 | check_timer(); | 3140 | check_timer(); |
| 3142 | } | 3141 | } |
| 3143 | 3142 | ||
| @@ -3928,7 +3927,7 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq, | |||
| 3928 | /* | 3927 | /* |
| 3929 | * IRQs < 16 are already in the irq_2_pin[] map | 3928 | * IRQs < 16 are already in the irq_2_pin[] map |
| 3930 | */ | 3929 | */ |
| 3931 | if (irq >= nr_legacy_irqs) { | 3930 | if (irq >= legacy_pic->nr_legacy_irqs) { |
| 3932 | cfg = desc->chip_data; | 3931 | cfg = desc->chip_data; |
| 3933 | if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) { | 3932 | if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) { |
| 3934 | printk(KERN_INFO "can not add pin %d for irq %d\n", | 3933 | printk(KERN_INFO "can not add pin %d for irq %d\n", |
| @@ -4302,3 +4301,24 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | |||
| 4302 | 4301 | ||
| 4303 | nr_ioapics++; | 4302 | nr_ioapics++; |
| 4304 | } | 4303 | } |
| 4304 | |||
| 4305 | /* Enable IOAPIC early just for system timer */ | ||
| 4306 | void __init pre_init_apic_IRQ0(void) | ||
| 4307 | { | ||
| 4308 | struct irq_cfg *cfg; | ||
| 4309 | struct irq_desc *desc; | ||
| 4310 | |||
| 4311 | printk(KERN_INFO "Early APIC setup for system timer0\n"); | ||
| 4312 | #ifndef CONFIG_SMP | ||
| 4313 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); | ||
| 4314 | #endif | ||
| 4315 | desc = irq_to_desc_alloc_node(0, 0); | ||
| 4316 | |||
| 4317 | setup_local_APIC(); | ||
| 4318 | |||
| 4319 | cfg = irq_cfg(0); | ||
| 4320 | add_pin_to_irq_node(cfg, 0, 0, 0); | ||
| 4321 | set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge"); | ||
| 4322 | |||
| 4323 | setup_IO_APIC_irq(0, 0, 0, desc, 0, 0); | ||
| 4324 | } | ||
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index bd7c96b5e8d8..8aa65adbd25d 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c | |||
| @@ -177,7 +177,7 @@ int __init check_nmi_watchdog(void) | |||
| 177 | error: | 177 | error: |
| 178 | if (nmi_watchdog == NMI_IO_APIC) { | 178 | if (nmi_watchdog == NMI_IO_APIC) { |
| 179 | if (!timer_through_8259) | 179 | if (!timer_through_8259) |
| 180 | disable_8259A_irq(0); | 180 | legacy_pic->chip->mask(0); |
| 181 | on_each_cpu(__acpi_nmi_disable, NULL, 1); | 181 | on_each_cpu(__acpi_nmi_disable, NULL, 1); |
| 182 | } | 182 | } |
| 183 | 183 | ||
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 47dd856708e5..3e28401f161c 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c | |||
| @@ -277,6 +277,7 @@ static __init void early_check_numaq(void) | |||
| 277 | x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus; | 277 | x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus; |
| 278 | x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info; | 278 | x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info; |
| 279 | x86_init.timers.tsc_pre_init = numaq_tsc_init; | 279 | x86_init.timers.tsc_pre_init = numaq_tsc_init; |
| 280 | x86_init.pci.init = pci_numaq_init; | ||
| 280 | } | 281 | } |
| 281 | } | 282 | } |
| 282 | 283 | ||
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index 8c93a84bb627..fb725ee15f55 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c | |||
| @@ -34,6 +34,12 @@ | |||
| 34 | static int i8259A_auto_eoi; | 34 | static int i8259A_auto_eoi; |
| 35 | DEFINE_RAW_SPINLOCK(i8259A_lock); | 35 | DEFINE_RAW_SPINLOCK(i8259A_lock); |
| 36 | static void mask_and_ack_8259A(unsigned int); | 36 | static void mask_and_ack_8259A(unsigned int); |
| 37 | static void mask_8259A(void); | ||
| 38 | static void unmask_8259A(void); | ||
| 39 | static void disable_8259A_irq(unsigned int irq); | ||
| 40 | static void enable_8259A_irq(unsigned int irq); | ||
| 41 | static void init_8259A(int auto_eoi); | ||
| 42 | static int i8259A_irq_pending(unsigned int irq); | ||
| 37 | 43 | ||
| 38 | struct irq_chip i8259A_chip = { | 44 | struct irq_chip i8259A_chip = { |
| 39 | .name = "XT-PIC", | 45 | .name = "XT-PIC", |
| @@ -63,7 +69,7 @@ unsigned int cached_irq_mask = 0xffff; | |||
| 63 | */ | 69 | */ |
| 64 | unsigned long io_apic_irqs; | 70 | unsigned long io_apic_irqs; |
| 65 | 71 | ||
| 66 | void disable_8259A_irq(unsigned int irq) | 72 | static void disable_8259A_irq(unsigned int irq) |
| 67 | { | 73 | { |
| 68 | unsigned int mask = 1 << irq; | 74 | unsigned int mask = 1 << irq; |
| 69 | unsigned long flags; | 75 | unsigned long flags; |
| @@ -77,7 +83,7 @@ void disable_8259A_irq(unsigned int irq) | |||
| 77 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 83 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 78 | } | 84 | } |
| 79 | 85 | ||
| 80 | void enable_8259A_irq(unsigned int irq) | 86 | static void enable_8259A_irq(unsigned int irq) |
| 81 | { | 87 | { |
| 82 | unsigned int mask = ~(1 << irq); | 88 | unsigned int mask = ~(1 << irq); |
| 83 | unsigned long flags; | 89 | unsigned long flags; |
| @@ -91,7 +97,7 @@ void enable_8259A_irq(unsigned int irq) | |||
| 91 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 97 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 92 | } | 98 | } |
| 93 | 99 | ||
| 94 | int i8259A_irq_pending(unsigned int irq) | 100 | static int i8259A_irq_pending(unsigned int irq) |
| 95 | { | 101 | { |
| 96 | unsigned int mask = 1<<irq; | 102 | unsigned int mask = 1<<irq; |
| 97 | unsigned long flags; | 103 | unsigned long flags; |
| @@ -107,7 +113,7 @@ int i8259A_irq_pending(unsigned int irq) | |||
| 107 | return ret; | 113 | return ret; |
| 108 | } | 114 | } |
| 109 | 115 | ||
| 110 | void make_8259A_irq(unsigned int irq) | 116 | static void make_8259A_irq(unsigned int irq) |
| 111 | { | 117 | { |
| 112 | disable_irq_nosync(irq); | 118 | disable_irq_nosync(irq); |
| 113 | io_apic_irqs &= ~(1<<irq); | 119 | io_apic_irqs &= ~(1<<irq); |
| @@ -281,7 +287,7 @@ static int __init i8259A_init_sysfs(void) | |||
| 281 | 287 | ||
| 282 | device_initcall(i8259A_init_sysfs); | 288 | device_initcall(i8259A_init_sysfs); |
| 283 | 289 | ||
| 284 | void mask_8259A(void) | 290 | static void mask_8259A(void) |
| 285 | { | 291 | { |
| 286 | unsigned long flags; | 292 | unsigned long flags; |
| 287 | 293 | ||
| @@ -293,7 +299,7 @@ void mask_8259A(void) | |||
| 293 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 299 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 294 | } | 300 | } |
| 295 | 301 | ||
| 296 | void unmask_8259A(void) | 302 | static void unmask_8259A(void) |
| 297 | { | 303 | { |
| 298 | unsigned long flags; | 304 | unsigned long flags; |
| 299 | 305 | ||
| @@ -305,7 +311,7 @@ void unmask_8259A(void) | |||
| 305 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 311 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 306 | } | 312 | } |
| 307 | 313 | ||
| 308 | void init_8259A(int auto_eoi) | 314 | static void init_8259A(int auto_eoi) |
| 309 | { | 315 | { |
| 310 | unsigned long flags; | 316 | unsigned long flags; |
| 311 | 317 | ||
| @@ -358,3 +364,47 @@ void init_8259A(int auto_eoi) | |||
| 358 | 364 | ||
| 359 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 365 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 360 | } | 366 | } |
| 367 | |||
| 368 | /* | ||
| 369 | * make i8259 a driver so that we can select pic functions at run time. the goal | ||
| 370 | * is to make x86 binary compatible among pc compatible and non-pc compatible | ||
| 371 | * platforms, such as x86 MID. | ||
| 372 | */ | ||
| 373 | |||
| 374 | static void legacy_pic_noop(void) { }; | ||
| 375 | static void legacy_pic_uint_noop(unsigned int unused) { }; | ||
| 376 | static void legacy_pic_int_noop(int unused) { }; | ||
| 377 | |||
| 378 | static struct irq_chip dummy_pic_chip = { | ||
| 379 | .name = "dummy pic", | ||
| 380 | .mask = legacy_pic_uint_noop, | ||
| 381 | .unmask = legacy_pic_uint_noop, | ||
| 382 | .disable = legacy_pic_uint_noop, | ||
| 383 | .mask_ack = legacy_pic_uint_noop, | ||
| 384 | }; | ||
| 385 | static int legacy_pic_irq_pending_noop(unsigned int irq) | ||
| 386 | { | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | struct legacy_pic null_legacy_pic = { | ||
| 391 | .nr_legacy_irqs = 0, | ||
| 392 | .chip = &dummy_pic_chip, | ||
| 393 | .mask_all = legacy_pic_noop, | ||
| 394 | .restore_mask = legacy_pic_noop, | ||
| 395 | .init = legacy_pic_int_noop, | ||
| 396 | .irq_pending = legacy_pic_irq_pending_noop, | ||
| 397 | .make_irq = legacy_pic_uint_noop, | ||
| 398 | }; | ||
| 399 | |||
| 400 | struct legacy_pic default_legacy_pic = { | ||
| 401 | .nr_legacy_irqs = NR_IRQS_LEGACY, | ||
| 402 | .chip = &i8259A_chip, | ||
| 403 | .mask_all = mask_8259A, | ||
| 404 | .restore_mask = unmask_8259A, | ||
| 405 | .init = init_8259A, | ||
| 406 | .irq_pending = i8259A_irq_pending, | ||
| 407 | .make_irq = make_8259A_irq, | ||
| 408 | }; | ||
| 409 | |||
| 410 | struct legacy_pic *legacy_pic = &default_legacy_pic; | ||
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index fce55d532631..ef257fc2921b 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c | |||
| @@ -99,9 +99,6 @@ int vector_used_by_percpu_irq(unsigned int vector) | |||
| 99 | return 0; | 99 | return 0; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | /* Number of legacy interrupts */ | ||
| 103 | int nr_legacy_irqs __read_mostly = NR_IRQS_LEGACY; | ||
| 104 | |||
| 105 | void __init init_ISA_irqs(void) | 102 | void __init init_ISA_irqs(void) |
| 106 | { | 103 | { |
| 107 | int i; | 104 | int i; |
| @@ -109,12 +106,12 @@ void __init init_ISA_irqs(void) | |||
| 109 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | 106 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) |
| 110 | init_bsp_APIC(); | 107 | init_bsp_APIC(); |
| 111 | #endif | 108 | #endif |
| 112 | init_8259A(0); | 109 | legacy_pic->init(0); |
| 113 | 110 | ||
| 114 | /* | 111 | /* |
| 115 | * 16 old-style INTA-cycle interrupts: | 112 | * 16 old-style INTA-cycle interrupts: |
| 116 | */ | 113 | */ |
| 117 | for (i = 0; i < NR_IRQS_LEGACY; i++) { | 114 | for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) { |
| 118 | struct irq_desc *desc = irq_to_desc(i); | 115 | struct irq_desc *desc = irq_to_desc(i); |
| 119 | 116 | ||
| 120 | desc->status = IRQ_DISABLED; | 117 | desc->status = IRQ_DISABLED; |
| @@ -138,7 +135,7 @@ void __init init_IRQ(void) | |||
| 138 | * then this vector space can be freed and re-used dynamically as the | 135 | * then this vector space can be freed and re-used dynamically as the |
| 139 | * irq's migrate etc. | 136 | * irq's migrate etc. |
| 140 | */ | 137 | */ |
| 141 | for (i = 0; i < nr_legacy_irqs; i++) | 138 | for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) |
| 142 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; | 139 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; |
| 143 | 140 | ||
| 144 | x86_init.irqs.intr_init(); | 141 | x86_init.irqs.intr_init(); |
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 3b7078abc871..0aad8670858e 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c | |||
| @@ -10,8 +10,211 @@ | |||
| 10 | * of the License. | 10 | * of the License. |
| 11 | */ | 11 | */ |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/sfi.h> | ||
| 15 | #include <linux/irq.h> | ||
| 16 | #include <linux/module.h> | ||
| 13 | 17 | ||
| 14 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
| 19 | #include <asm/mpspec_def.h> | ||
| 20 | #include <asm/hw_irq.h> | ||
| 21 | #include <asm/apic.h> | ||
| 22 | #include <asm/io_apic.h> | ||
| 23 | #include <asm/mrst.h> | ||
| 24 | #include <asm/io.h> | ||
| 25 | #include <asm/i8259.h> | ||
| 26 | #include <asm/apb_timer.h> | ||
| 27 | |||
| 28 | static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | ||
| 29 | static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | ||
| 30 | int sfi_mtimer_num; | ||
| 31 | |||
| 32 | struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; | ||
| 33 | EXPORT_SYMBOL_GPL(sfi_mrtc_array); | ||
| 34 | int sfi_mrtc_num; | ||
| 35 | |||
| 36 | static inline void assign_to_mp_irq(struct mpc_intsrc *m, | ||
| 37 | struct mpc_intsrc *mp_irq) | ||
| 38 | { | ||
| 39 | memcpy(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline int mp_irq_cmp(struct mpc_intsrc *mp_irq, | ||
| 43 | struct mpc_intsrc *m) | ||
| 44 | { | ||
| 45 | return memcmp(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void save_mp_irq(struct mpc_intsrc *m) | ||
| 49 | { | ||
| 50 | int i; | ||
| 51 | |||
| 52 | for (i = 0; i < mp_irq_entries; i++) { | ||
| 53 | if (!mp_irq_cmp(&mp_irqs[i], m)) | ||
| 54 | return; | ||
| 55 | } | ||
| 56 | |||
| 57 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
| 58 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | ||
| 59 | panic("Max # of irq sources exceeded!!\n"); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* parse all the mtimer info to a static mtimer array */ | ||
| 63 | static int __init sfi_parse_mtmr(struct sfi_table_header *table) | ||
| 64 | { | ||
| 65 | struct sfi_table_simple *sb; | ||
| 66 | struct sfi_timer_table_entry *pentry; | ||
| 67 | struct mpc_intsrc mp_irq; | ||
| 68 | int totallen; | ||
| 69 | |||
| 70 | sb = (struct sfi_table_simple *)table; | ||
| 71 | if (!sfi_mtimer_num) { | ||
| 72 | sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, | ||
| 73 | struct sfi_timer_table_entry); | ||
| 74 | pentry = (struct sfi_timer_table_entry *) sb->pentry; | ||
| 75 | totallen = sfi_mtimer_num * sizeof(*pentry); | ||
| 76 | memcpy(sfi_mtimer_array, pentry, totallen); | ||
| 77 | } | ||
| 78 | |||
| 79 | printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num); | ||
| 80 | pentry = sfi_mtimer_array; | ||
| 81 | for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | ||
| 82 | printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz," | ||
| 83 | " irq = %d\n", totallen, (u32)pentry->phys_addr, | ||
| 84 | pentry->freq_hz, pentry->irq); | ||
| 85 | if (!pentry->irq) | ||
| 86 | continue; | ||
| 87 | mp_irq.type = MP_IOAPIC; | ||
| 88 | mp_irq.irqtype = mp_INT; | ||
| 89 | /* triggering mode edge bit 2-3, active high polarity bit 0-1 */ | ||
| 90 | mp_irq.irqflag = 5; | ||
| 91 | mp_irq.srcbus = 0; | ||
| 92 | mp_irq.srcbusirq = pentry->irq; /* IRQ */ | ||
| 93 | mp_irq.dstapic = MP_APIC_ALL; | ||
| 94 | mp_irq.dstirq = pentry->irq; | ||
| 95 | save_mp_irq(&mp_irq); | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | struct sfi_timer_table_entry *sfi_get_mtmr(int hint) | ||
| 102 | { | ||
| 103 | int i; | ||
| 104 | if (hint < sfi_mtimer_num) { | ||
| 105 | if (!sfi_mtimer_usage[hint]) { | ||
| 106 | pr_debug("hint taken for timer %d irq %d\n",\ | ||
| 107 | hint, sfi_mtimer_array[hint].irq); | ||
| 108 | sfi_mtimer_usage[hint] = 1; | ||
| 109 | return &sfi_mtimer_array[hint]; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | /* take the first timer available */ | ||
| 113 | for (i = 0; i < sfi_mtimer_num;) { | ||
| 114 | if (!sfi_mtimer_usage[i]) { | ||
| 115 | sfi_mtimer_usage[i] = 1; | ||
| 116 | return &sfi_mtimer_array[i]; | ||
| 117 | } | ||
| 118 | i++; | ||
| 119 | } | ||
| 120 | return NULL; | ||
| 121 | } | ||
| 122 | |||
| 123 | void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) | ||
| 124 | { | ||
| 125 | int i; | ||
| 126 | for (i = 0; i < sfi_mtimer_num;) { | ||
| 127 | if (mtmr->irq == sfi_mtimer_array[i].irq) { | ||
| 128 | sfi_mtimer_usage[i] = 0; | ||
| 129 | return; | ||
| 130 | } | ||
| 131 | i++; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | /* parse all the mrtc info to a global mrtc array */ | ||
| 136 | int __init sfi_parse_mrtc(struct sfi_table_header *table) | ||
| 137 | { | ||
| 138 | struct sfi_table_simple *sb; | ||
| 139 | struct sfi_rtc_table_entry *pentry; | ||
| 140 | struct mpc_intsrc mp_irq; | ||
| 141 | |||
| 142 | int totallen; | ||
| 143 | |||
| 144 | sb = (struct sfi_table_simple *)table; | ||
| 145 | if (!sfi_mrtc_num) { | ||
| 146 | sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, | ||
| 147 | struct sfi_rtc_table_entry); | ||
| 148 | pentry = (struct sfi_rtc_table_entry *)sb->pentry; | ||
| 149 | totallen = sfi_mrtc_num * sizeof(*pentry); | ||
| 150 | memcpy(sfi_mrtc_array, pentry, totallen); | ||
| 151 | } | ||
| 152 | |||
| 153 | printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num); | ||
| 154 | pentry = sfi_mrtc_array; | ||
| 155 | for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { | ||
| 156 | printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n", | ||
| 157 | totallen, (u32)pentry->phys_addr, pentry->irq); | ||
| 158 | mp_irq.type = MP_IOAPIC; | ||
| 159 | mp_irq.irqtype = mp_INT; | ||
| 160 | mp_irq.irqflag = 0; | ||
| 161 | mp_irq.srcbus = 0; | ||
| 162 | mp_irq.srcbusirq = pentry->irq; /* IRQ */ | ||
| 163 | mp_irq.dstapic = MP_APIC_ALL; | ||
| 164 | mp_irq.dstirq = pentry->irq; | ||
| 165 | save_mp_irq(&mp_irq); | ||
| 166 | } | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | /* | ||
| 171 | * the secondary clock in Moorestown can be APBT or LAPIC clock, default to | ||
| 172 | * APBT but cmdline option can also override it. | ||
| 173 | */ | ||
| 174 | static void __cpuinit mrst_setup_secondary_clock(void) | ||
| 175 | { | ||
| 176 | /* restore default lapic clock if disabled by cmdline */ | ||
| 177 | if (disable_apbt_percpu) | ||
| 178 | return setup_secondary_APIC_clock(); | ||
| 179 | apbt_setup_secondary_clock(); | ||
| 180 | } | ||
| 181 | |||
| 182 | static unsigned long __init mrst_calibrate_tsc(void) | ||
| 183 | { | ||
| 184 | unsigned long flags, fast_calibrate; | ||
| 185 | |||
| 186 | local_irq_save(flags); | ||
| 187 | fast_calibrate = apbt_quick_calibrate(); | ||
| 188 | local_irq_restore(flags); | ||
| 189 | |||
| 190 | if (fast_calibrate) | ||
| 191 | return fast_calibrate; | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | void __init mrst_time_init(void) | ||
| 197 | { | ||
| 198 | sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | ||
| 199 | pre_init_apic_IRQ0(); | ||
| 200 | apbt_time_init(); | ||
| 201 | } | ||
| 202 | |||
| 203 | void __init mrst_rtc_init(void) | ||
| 204 | { | ||
| 205 | sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * if we use per cpu apb timer, the bootclock already setup. if we use lapic | ||
| 210 | * timer and one apbt timer for broadcast, we need to set up lapic boot clock. | ||
| 211 | */ | ||
| 212 | static void __init mrst_setup_boot_clock(void) | ||
| 213 | { | ||
| 214 | pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu); | ||
| 215 | if (disable_apbt_percpu) | ||
| 216 | setup_boot_APIC_clock(); | ||
| 217 | }; | ||
| 15 | 218 | ||
| 16 | /* | 219 | /* |
| 17 | * Moorestown specific x86_init function overrides and early setup | 220 | * Moorestown specific x86_init function overrides and early setup |
| @@ -21,4 +224,17 @@ void __init x86_mrst_early_setup(void) | |||
| 21 | { | 224 | { |
| 22 | x86_init.resources.probe_roms = x86_init_noop; | 225 | x86_init.resources.probe_roms = x86_init_noop; |
| 23 | x86_init.resources.reserve_resources = x86_init_noop; | 226 | x86_init.resources.reserve_resources = x86_init_noop; |
| 227 | |||
| 228 | x86_init.timers.timer_init = mrst_time_init; | ||
| 229 | x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock; | ||
| 230 | |||
| 231 | x86_init.irqs.pre_vector_init = x86_init_noop; | ||
| 232 | |||
| 233 | x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; | ||
| 234 | |||
| 235 | x86_platform.calibrate_tsc = mrst_calibrate_tsc; | ||
| 236 | x86_init.pci.init = pci_mrst_init; | ||
| 237 | x86_init.pci.fixup_irqs = x86_init_noop; | ||
| 238 | |||
| 239 | legacy_pic = &null_legacy_pic; | ||
| 24 | } | 240 | } |
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c index 9d1d263f786f..8297160c41b3 100644 --- a/arch/x86/kernel/olpc.c +++ b/arch/x86/kernel/olpc.c | |||
| @@ -17,7 +17,9 @@ | |||
| 17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
| 18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
| 19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
| 20 | |||
| 20 | #include <asm/geode.h> | 21 | #include <asm/geode.h> |
| 22 | #include <asm/setup.h> | ||
| 21 | #include <asm/olpc.h> | 23 | #include <asm/olpc.h> |
| 22 | 24 | ||
| 23 | #ifdef CONFIG_OPEN_FIRMWARE | 25 | #ifdef CONFIG_OPEN_FIRMWARE |
| @@ -243,9 +245,11 @@ static int __init olpc_init(void) | |||
| 243 | olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, | 245 | olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, |
| 244 | (unsigned char *) &olpc_platform_info.ecver, 1); | 246 | (unsigned char *) &olpc_platform_info.ecver, 1); |
| 245 | 247 | ||
| 246 | /* check to see if the VSA exists */ | 248 | #ifdef CONFIG_PCI_OLPC |
| 247 | if (cs5535_has_vsa2()) | 249 | /* If the VSA exists let it emulate PCI, if not emulate in kernel */ |
| 248 | olpc_platform_info.flags |= OLPC_F_VSA; | 250 | if (!cs5535_has_vsa2()) |
| 251 | x86_init.pci.arch_init = pci_olpc_init; | ||
| 252 | #endif | ||
| 249 | 253 | ||
| 250 | printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", | 254 | printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", |
| 251 | ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", | 255 | ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a435c76d714e..a02e80c3c54b 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include <linux/err.h> | 48 | #include <linux/err.h> |
| 49 | #include <linux/nmi.h> | 49 | #include <linux/nmi.h> |
| 50 | #include <linux/tboot.h> | 50 | #include <linux/tboot.h> |
| 51 | #include <linux/stackprotector.h> | ||
| 51 | 52 | ||
| 52 | #include <asm/acpi.h> | 53 | #include <asm/acpi.h> |
| 53 | #include <asm/desc.h> | 54 | #include <asm/desc.h> |
| @@ -67,6 +68,7 @@ | |||
| 67 | #include <linux/mc146818rtc.h> | 68 | #include <linux/mc146818rtc.h> |
| 68 | 69 | ||
| 69 | #include <asm/smpboot_hooks.h> | 70 | #include <asm/smpboot_hooks.h> |
| 71 | #include <asm/i8259.h> | ||
| 70 | 72 | ||
| 71 | #ifdef CONFIG_X86_32 | 73 | #ifdef CONFIG_X86_32 |
| 72 | u8 apicid_2_node[MAX_APICID]; | 74 | u8 apicid_2_node[MAX_APICID]; |
| @@ -291,9 +293,9 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
| 291 | check_tsc_sync_target(); | 293 | check_tsc_sync_target(); |
| 292 | 294 | ||
| 293 | if (nmi_watchdog == NMI_IO_APIC) { | 295 | if (nmi_watchdog == NMI_IO_APIC) { |
| 294 | disable_8259A_irq(0); | 296 | legacy_pic->chip->mask(0); |
| 295 | enable_NMI_through_LVT0(); | 297 | enable_NMI_through_LVT0(); |
| 296 | enable_8259A_irq(0); | 298 | legacy_pic->chip->unmask(0); |
| 297 | } | 299 | } |
| 298 | 300 | ||
| 299 | #ifdef CONFIG_X86_32 | 301 | #ifdef CONFIG_X86_32 |
| @@ -329,6 +331,9 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
| 329 | /* enable local interrupts */ | 331 | /* enable local interrupts */ |
| 330 | local_irq_enable(); | 332 | local_irq_enable(); |
| 331 | 333 | ||
| 334 | /* to prevent fake stack check failure in clock setup */ | ||
| 335 | boot_init_stack_canary(); | ||
| 336 | |||
| 332 | x86_cpuinit.setup_percpu_clockev(); | 337 | x86_cpuinit.setup_percpu_clockev(); |
| 333 | 338 | ||
| 334 | wmb(); | 339 | wmb(); |
diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c index ab38ce0984fa..e680ea52db9b 100644 --- a/arch/x86/kernel/visws_quirks.c +++ b/arch/x86/kernel/visws_quirks.c | |||
| @@ -49,11 +49,6 @@ extern int no_broadcast; | |||
| 49 | char visws_board_type = -1; | 49 | char visws_board_type = -1; |
| 50 | char visws_board_rev = -1; | 50 | char visws_board_rev = -1; |
| 51 | 51 | ||
| 52 | int is_visws_box(void) | ||
| 53 | { | ||
| 54 | return visws_board_type >= 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void __init visws_time_init(void) | 52 | static void __init visws_time_init(void) |
| 58 | { | 53 | { |
| 59 | printk(KERN_INFO "Starting Cobalt Timer system clock\n"); | 54 | printk(KERN_INFO "Starting Cobalt Timer system clock\n"); |
| @@ -242,6 +237,8 @@ void __init visws_early_detect(void) | |||
| 242 | x86_init.irqs.pre_vector_init = visws_pre_intr_init; | 237 | x86_init.irqs.pre_vector_init = visws_pre_intr_init; |
| 243 | x86_init.irqs.trap_init = visws_trap_init; | 238 | x86_init.irqs.trap_init = visws_trap_init; |
| 244 | x86_init.timers.timer_init = visws_time_init; | 239 | x86_init.timers.timer_init = visws_time_init; |
| 240 | x86_init.pci.init = pci_visws_init; | ||
| 241 | x86_init.pci.init_irq = x86_init_noop; | ||
| 245 | 242 | ||
| 246 | /* | 243 | /* |
| 247 | * Install reboot quirks: | 244 | * Install reboot quirks: |
| @@ -508,7 +505,7 @@ static struct irq_chip cobalt_irq_type = { | |||
| 508 | */ | 505 | */ |
| 509 | static unsigned int startup_piix4_master_irq(unsigned int irq) | 506 | static unsigned int startup_piix4_master_irq(unsigned int irq) |
| 510 | { | 507 | { |
| 511 | init_8259A(0); | 508 | legacy_pic->init(0); |
| 512 | 509 | ||
| 513 | return startup_cobalt_irq(irq); | 510 | return startup_cobalt_irq(irq); |
| 514 | } | 511 | } |
| @@ -532,9 +529,6 @@ static struct irq_chip piix4_master_irq_type = { | |||
| 532 | 529 | ||
| 533 | static struct irq_chip piix4_virtual_irq_type = { | 530 | static struct irq_chip piix4_virtual_irq_type = { |
| 534 | .name = "PIIX4-virtual", | 531 | .name = "PIIX4-virtual", |
| 535 | .shutdown = disable_8259A_irq, | ||
| 536 | .enable = enable_8259A_irq, | ||
| 537 | .disable = disable_8259A_irq, | ||
| 538 | }; | 532 | }; |
| 539 | 533 | ||
| 540 | 534 | ||
| @@ -609,7 +603,7 @@ static irqreturn_t piix4_master_intr(int irq, void *dev_id) | |||
| 609 | handle_IRQ_event(realirq, desc->action); | 603 | handle_IRQ_event(realirq, desc->action); |
| 610 | 604 | ||
| 611 | if (!(desc->status & IRQ_DISABLED)) | 605 | if (!(desc->status & IRQ_DISABLED)) |
| 612 | enable_8259A_irq(realirq); | 606 | legacy_pic->chip->unmask(realirq); |
| 613 | 607 | ||
| 614 | return IRQ_HANDLED; | 608 | return IRQ_HANDLED; |
| 615 | 609 | ||
| @@ -628,6 +622,12 @@ static struct irqaction cascade_action = { | |||
| 628 | .name = "cascade", | 622 | .name = "cascade", |
| 629 | }; | 623 | }; |
| 630 | 624 | ||
| 625 | static inline void set_piix4_virtual_irq_type(void) | ||
| 626 | { | ||
| 627 | piix4_virtual_irq_type.shutdown = i8259A_chip.mask; | ||
| 628 | piix4_virtual_irq_type.enable = i8259A_chip.unmask; | ||
| 629 | piix4_virtual_irq_type.disable = i8259A_chip.mask; | ||
| 630 | } | ||
| 631 | 631 | ||
| 632 | void init_VISWS_APIC_irqs(void) | 632 | void init_VISWS_APIC_irqs(void) |
| 633 | { | 633 | { |
| @@ -653,6 +653,7 @@ void init_VISWS_APIC_irqs(void) | |||
| 653 | desc->chip = &piix4_master_irq_type; | 653 | desc->chip = &piix4_master_irq_type; |
| 654 | } | 654 | } |
| 655 | else if (i < CO_IRQ_APIC0) { | 655 | else if (i < CO_IRQ_APIC0) { |
| 656 | set_piix4_virtual_irq_type(); | ||
| 656 | desc->chip = &piix4_virtual_irq_type; | 657 | desc->chip = &piix4_virtual_irq_type; |
| 657 | } | 658 | } |
| 658 | else if (IS_CO_APIC(i)) { | 659 | else if (IS_CO_APIC(i)) { |
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index ee5746c94628..61a1e8c7e19f 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
| @@ -4,9 +4,11 @@ | |||
| 4 | * For licencing details see kernel-base/COPYING | 4 | * For licencing details see kernel-base/COPYING |
| 5 | */ | 5 | */ |
| 6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| 7 | #include <linux/ioport.h> | ||
| 7 | 8 | ||
| 8 | #include <asm/bios_ebda.h> | 9 | #include <asm/bios_ebda.h> |
| 9 | #include <asm/paravirt.h> | 10 | #include <asm/paravirt.h> |
| 11 | #include <asm/pci_x86.h> | ||
| 10 | #include <asm/mpspec.h> | 12 | #include <asm/mpspec.h> |
| 11 | #include <asm/setup.h> | 13 | #include <asm/setup.h> |
| 12 | #include <asm/apic.h> | 14 | #include <asm/apic.h> |
| @@ -70,6 +72,12 @@ struct x86_init_ops x86_init __initdata = { | |||
| 70 | .iommu = { | 72 | .iommu = { |
| 71 | .iommu_init = iommu_init_noop, | 73 | .iommu_init = iommu_init_noop, |
| 72 | }, | 74 | }, |
| 75 | |||
| 76 | .pci = { | ||
| 77 | .init = x86_default_pci_init, | ||
| 78 | .init_irq = x86_default_pci_init_irq, | ||
| 79 | .fixup_irqs = x86_default_pci_fixup_irqs, | ||
| 80 | }, | ||
| 73 | }; | 81 | }; |
| 74 | 82 | ||
| 75 | struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = { | 83 | struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = { |
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index 0b7d3e9593e1..b110d97fb925 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile | |||
| @@ -13,6 +13,8 @@ obj-$(CONFIG_X86_VISWS) += visws.o | |||
| 13 | 13 | ||
| 14 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o | 14 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o |
| 15 | 15 | ||
| 16 | obj-$(CONFIG_X86_MRST) += mrst.o | ||
| 17 | |||
| 16 | obj-y += common.o early.o | 18 | obj-y += common.o early.o |
| 17 | obj-y += amd_bus.o bus_numa.o | 19 | obj-y += amd_bus.o bus_numa.o |
| 18 | 20 | ||
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 5f11ff6f5389..6e22454bfaa6 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
| @@ -298,17 +298,14 @@ int __init pci_acpi_init(void) | |||
| 298 | { | 298 | { |
| 299 | struct pci_dev *dev = NULL; | 299 | struct pci_dev *dev = NULL; |
| 300 | 300 | ||
| 301 | if (pcibios_scanned) | ||
| 302 | return 0; | ||
| 303 | |||
| 304 | if (acpi_noirq) | 301 | if (acpi_noirq) |
| 305 | return 0; | 302 | return -ENODEV; |
| 306 | 303 | ||
| 307 | printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); | 304 | printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); |
| 308 | acpi_irq_penalty_init(); | 305 | acpi_irq_penalty_init(); |
| 309 | pcibios_scanned++; | ||
| 310 | pcibios_enable_irq = acpi_pci_irq_enable; | 306 | pcibios_enable_irq = acpi_pci_irq_enable; |
| 311 | pcibios_disable_irq = acpi_pci_irq_disable; | 307 | pcibios_disable_irq = acpi_pci_irq_disable; |
| 308 | x86_init.pci.init_irq = x86_init_noop; | ||
| 312 | 309 | ||
| 313 | if (pci_routeirq) { | 310 | if (pci_routeirq) { |
| 314 | /* | 311 | /* |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 3736176acaab..294e10cb11e1 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
| @@ -72,12 +72,6 @@ struct pci_ops pci_root_ops = { | |||
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | /* | 74 | /* |
| 75 | * legacy, numa, and acpi all want to call pcibios_scan_root | ||
| 76 | * from their initcalls. This flag prevents that. | ||
| 77 | */ | ||
| 78 | int pcibios_scanned; | ||
| 79 | |||
| 80 | /* | ||
| 81 | * This interrupt-safe spinlock protects all accesses to PCI | 75 | * This interrupt-safe spinlock protects all accesses to PCI |
| 82 | * configuration space. | 76 | * configuration space. |
| 83 | */ | 77 | */ |
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c index 25a1f8efed4a..adb62aaa7ecd 100644 --- a/arch/x86/pci/init.c +++ b/arch/x86/pci/init.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #include <linux/pci.h> | 1 | #include <linux/pci.h> |
| 2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
| 3 | #include <asm/pci_x86.h> | 3 | #include <asm/pci_x86.h> |
| 4 | #include <asm/x86_init.h> | ||
| 4 | 5 | ||
| 5 | /* arch_initcall has too random ordering, so call the initializers | 6 | /* arch_initcall has too random ordering, so call the initializers |
| 6 | in the right sequence from here. */ | 7 | in the right sequence from here. */ |
| @@ -15,10 +16,9 @@ static __init int pci_arch_init(void) | |||
| 15 | if (!(pci_probe & PCI_PROBE_NOEARLY)) | 16 | if (!(pci_probe & PCI_PROBE_NOEARLY)) |
| 16 | pci_mmcfg_early_init(); | 17 | pci_mmcfg_early_init(); |
| 17 | 18 | ||
| 18 | #ifdef CONFIG_PCI_OLPC | 19 | if (x86_init.pci.arch_init && !x86_init.pci.arch_init()) |
| 19 | if (!pci_olpc_init()) | 20 | return 0; |
| 20 | return 0; /* skip additional checks if it's an XO */ | 21 | |
| 21 | #endif | ||
| 22 | #ifdef CONFIG_PCI_BIOS | 22 | #ifdef CONFIG_PCI_BIOS |
| 23 | pci_pcbios_init(); | 23 | pci_pcbios_init(); |
| 24 | #endif | 24 | #endif |
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index b02f6d8ac922..8b107521d24e 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c | |||
| @@ -53,7 +53,7 @@ struct irq_router_handler { | |||
| 53 | int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); | 53 | int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; | 56 | int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq; |
| 57 | void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; | 57 | void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| @@ -1018,7 +1018,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
| 1018 | return 1; | 1018 | return 1; |
| 1019 | } | 1019 | } |
| 1020 | 1020 | ||
| 1021 | static void __init pcibios_fixup_irqs(void) | 1021 | void __init pcibios_fixup_irqs(void) |
| 1022 | { | 1022 | { |
| 1023 | struct pci_dev *dev = NULL; | 1023 | struct pci_dev *dev = NULL; |
| 1024 | u8 pin; | 1024 | u8 pin; |
| @@ -1112,12 +1112,12 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = { | |||
| 1112 | { } | 1112 | { } |
| 1113 | }; | 1113 | }; |
| 1114 | 1114 | ||
| 1115 | int __init pcibios_irq_init(void) | 1115 | void __init pcibios_irq_init(void) |
| 1116 | { | 1116 | { |
| 1117 | DBG(KERN_DEBUG "PCI: IRQ init\n"); | 1117 | DBG(KERN_DEBUG "PCI: IRQ init\n"); |
| 1118 | 1118 | ||
| 1119 | if (pcibios_enable_irq || raw_pci_ops == NULL) | 1119 | if (raw_pci_ops == NULL) |
| 1120 | return 0; | 1120 | return; |
| 1121 | 1121 | ||
| 1122 | dmi_check_system(pciirq_dmi_table); | 1122 | dmi_check_system(pciirq_dmi_table); |
| 1123 | 1123 | ||
| @@ -1144,9 +1144,7 @@ int __init pcibios_irq_init(void) | |||
| 1144 | pirq_table = NULL; | 1144 | pirq_table = NULL; |
| 1145 | } | 1145 | } |
| 1146 | 1146 | ||
| 1147 | pcibios_enable_irq = pirq_enable_irq; | 1147 | x86_init.pci.fixup_irqs(); |
| 1148 | |||
| 1149 | pcibios_fixup_irqs(); | ||
| 1150 | 1148 | ||
| 1151 | if (io_apic_assign_pci_irqs && pci_routeirq) { | 1149 | if (io_apic_assign_pci_irqs && pci_routeirq) { |
| 1152 | struct pci_dev *dev = NULL; | 1150 | struct pci_dev *dev = NULL; |
| @@ -1159,8 +1157,6 @@ int __init pcibios_irq_init(void) | |||
| 1159 | for_each_pci_dev(dev) | 1157 | for_each_pci_dev(dev) |
| 1160 | pirq_enable_irq(dev); | 1158 | pirq_enable_irq(dev); |
| 1161 | } | 1159 | } |
| 1162 | |||
| 1163 | return 0; | ||
| 1164 | } | 1160 | } |
| 1165 | 1161 | ||
| 1166 | static void pirq_penalize_isa_irq(int irq, int active) | 1162 | static void pirq_penalize_isa_irq(int irq, int active) |
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 4061bb0f267d..0db5eaf54560 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c | |||
| @@ -35,16 +35,13 @@ static void __devinit pcibios_fixup_peer_bridges(void) | |||
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | static int __init pci_legacy_init(void) | 38 | int __init pci_legacy_init(void) |
| 39 | { | 39 | { |
| 40 | if (!raw_pci_ops) { | 40 | if (!raw_pci_ops) { |
| 41 | printk("PCI: System does not support PCI\n"); | 41 | printk("PCI: System does not support PCI\n"); |
| 42 | return 0; | 42 | return 0; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | if (pcibios_scanned++) | ||
| 46 | return 0; | ||
| 47 | |||
| 48 | printk("PCI: Probing PCI hardware\n"); | 45 | printk("PCI: Probing PCI hardware\n"); |
| 49 | pci_root_bus = pcibios_scan_root(0); | 46 | pci_root_bus = pcibios_scan_root(0); |
| 50 | if (pci_root_bus) | 47 | if (pci_root_bus) |
| @@ -55,18 +52,15 @@ static int __init pci_legacy_init(void) | |||
| 55 | 52 | ||
| 56 | int __init pci_subsys_init(void) | 53 | int __init pci_subsys_init(void) |
| 57 | { | 54 | { |
| 58 | #ifdef CONFIG_X86_NUMAQ | 55 | /* |
| 59 | pci_numaq_init(); | 56 | * The init function returns an non zero value when |
| 60 | #endif | 57 | * pci_legacy_init should be invoked. |
| 61 | #ifdef CONFIG_ACPI | 58 | */ |
| 62 | pci_acpi_init(); | 59 | if (x86_init.pci.init()) |
| 63 | #endif | 60 | pci_legacy_init(); |
| 64 | #ifdef CONFIG_X86_VISWS | 61 | |
| 65 | pci_visws_init(); | ||
| 66 | #endif | ||
| 67 | pci_legacy_init(); | ||
| 68 | pcibios_fixup_peer_bridges(); | 62 | pcibios_fixup_peer_bridges(); |
| 69 | pcibios_irq_init(); | 63 | x86_init.pci.init_irq(); |
| 70 | pcibios_init(); | 64 | pcibios_init(); |
| 71 | 65 | ||
| 72 | return 0; | 66 | return 0; |
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c new file mode 100644 index 000000000000..8bf2fcb88d04 --- /dev/null +++ b/arch/x86/pci/mrst.c | |||
| @@ -0,0 +1,262 @@ | |||
| 1 | /* | ||
| 2 | * Moorestown PCI support | ||
| 3 | * Copyright (c) 2008 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * Moorestown has an interesting PCI implementation: | ||
| 7 | * - configuration space is memory mapped (as defined by MCFG) | ||
| 8 | * - Lincroft devices also have a real, type 1 configuration space | ||
| 9 | * - Early Lincroft silicon has a type 1 access bug that will cause | ||
| 10 | * a hang if non-existent devices are accessed | ||
| 11 | * - some devices have the "fixed BAR" capability, which means | ||
| 12 | * they can't be relocated or modified; check for that during | ||
| 13 | * BAR sizing | ||
| 14 | * | ||
| 15 | * So, we use the MCFG space for all reads and writes, but also send | ||
| 16 | * Lincroft writes to type 1 space. But only read/write if the device | ||
| 17 | * actually exists, otherwise return all 1s for reads and bit bucket | ||
| 18 | * the writes. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/pci.h> | ||
| 23 | #include <linux/ioport.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/dmi.h> | ||
| 26 | |||
| 27 | #include <asm/acpi.h> | ||
| 28 | #include <asm/segment.h> | ||
| 29 | #include <asm/io.h> | ||
| 30 | #include <asm/smp.h> | ||
| 31 | #include <asm/pci_x86.h> | ||
| 32 | #include <asm/hw_irq.h> | ||
| 33 | #include <asm/io_apic.h> | ||
| 34 | |||
| 35 | #define PCIE_CAP_OFFSET 0x100 | ||
| 36 | |||
| 37 | /* Fixed BAR fields */ | ||
| 38 | #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ | ||
| 39 | #define PCI_FIXED_BAR_0_SIZE 0x04 | ||
| 40 | #define PCI_FIXED_BAR_1_SIZE 0x08 | ||
| 41 | #define PCI_FIXED_BAR_2_SIZE 0x0c | ||
| 42 | #define PCI_FIXED_BAR_3_SIZE 0x10 | ||
| 43 | #define PCI_FIXED_BAR_4_SIZE 0x14 | ||
| 44 | #define PCI_FIXED_BAR_5_SIZE 0x1c | ||
| 45 | |||
| 46 | /** | ||
| 47 | * fixed_bar_cap - return the offset of the fixed BAR cap if found | ||
| 48 | * @bus: PCI bus | ||
| 49 | * @devfn: device in question | ||
| 50 | * | ||
| 51 | * Look for the fixed BAR cap on @bus and @devfn, returning its offset | ||
| 52 | * if found or 0 otherwise. | ||
| 53 | */ | ||
| 54 | static int fixed_bar_cap(struct pci_bus *bus, unsigned int devfn) | ||
| 55 | { | ||
| 56 | int pos; | ||
| 57 | u32 pcie_cap = 0, cap_data; | ||
| 58 | |||
| 59 | pos = PCIE_CAP_OFFSET; | ||
| 60 | |||
| 61 | if (!raw_pci_ext_ops) | ||
| 62 | return 0; | ||
| 63 | |||
| 64 | while (pos) { | ||
| 65 | if (raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
| 66 | devfn, pos, 4, &pcie_cap)) | ||
| 67 | return 0; | ||
| 68 | |||
| 69 | if (pcie_cap == 0xffffffff) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (PCI_EXT_CAP_ID(pcie_cap) == PCI_EXT_CAP_ID_VNDR) { | ||
| 73 | raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
| 74 | devfn, pos + 4, 4, &cap_data); | ||
| 75 | if ((cap_data & 0xffff) == PCIE_VNDR_CAP_ID_FIXED_BAR) | ||
| 76 | return pos; | ||
| 77 | } | ||
| 78 | |||
| 79 | pos = pcie_cap >> 20; | ||
| 80 | } | ||
| 81 | |||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn, | ||
| 86 | int reg, int len, u32 val, int offset) | ||
| 87 | { | ||
| 88 | u32 size; | ||
| 89 | unsigned int domain, busnum; | ||
| 90 | int bar = (reg - PCI_BASE_ADDRESS_0) >> 2; | ||
| 91 | |||
| 92 | domain = pci_domain_nr(bus); | ||
| 93 | busnum = bus->number; | ||
| 94 | |||
| 95 | if (val == ~0 && len == 4) { | ||
| 96 | unsigned long decode; | ||
| 97 | |||
| 98 | raw_pci_ext_ops->read(domain, busnum, devfn, | ||
| 99 | offset + 8 + (bar * 4), 4, &size); | ||
| 100 | |||
| 101 | /* Turn the size into a decode pattern for the sizing code */ | ||
| 102 | if (size) { | ||
| 103 | decode = size - 1; | ||
| 104 | decode |= decode >> 1; | ||
| 105 | decode |= decode >> 2; | ||
| 106 | decode |= decode >> 4; | ||
| 107 | decode |= decode >> 8; | ||
| 108 | decode |= decode >> 16; | ||
| 109 | decode++; | ||
| 110 | decode = ~(decode - 1); | ||
| 111 | } else { | ||
| 112 | decode = ~0; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 116 | * If val is all ones, the core code is trying to size the reg, | ||
| 117 | * so update the mmconfig space with the real size. | ||
| 118 | * | ||
| 119 | * Note: this assumes the fixed size we got is a power of two. | ||
| 120 | */ | ||
| 121 | return raw_pci_ext_ops->write(domain, busnum, devfn, reg, 4, | ||
| 122 | decode); | ||
| 123 | } | ||
| 124 | |||
| 125 | /* This is some other kind of BAR write, so just do it. */ | ||
| 126 | return raw_pci_ext_ops->write(domain, busnum, devfn, reg, len, val); | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * type1_access_ok - check whether to use type 1 | ||
| 131 | * @bus: bus number | ||
| 132 | * @devfn: device & function in question | ||
| 133 | * | ||
| 134 | * If the bus is on a Lincroft chip and it exists, or is not on a Lincroft at | ||
| 135 | * all, the we can go ahead with any reads & writes. If it's on a Lincroft, | ||
| 136 | * but doesn't exist, avoid the access altogether to keep the chip from | ||
| 137 | * hanging. | ||
| 138 | */ | ||
| 139 | static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) | ||
| 140 | { | ||
| 141 | /* This is a workaround for A0 LNC bug where PCI status register does | ||
| 142 | * not have new CAP bit set. can not be written by SW either. | ||
| 143 | * | ||
| 144 | * PCI header type in real LNC indicates a single function device, this | ||
| 145 | * will prevent probing other devices under the same function in PCI | ||
| 146 | * shim. Therefore, use the header type in shim instead. | ||
| 147 | */ | ||
| 148 | if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE) | ||
| 149 | return 0; | ||
| 150 | if (bus == 0 && (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(0, 0))) | ||
| 151 | return 1; | ||
| 152 | return 0; /* langwell on others */ | ||
| 153 | } | ||
| 154 | |||
| 155 | static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | ||
| 156 | int size, u32 *value) | ||
| 157 | { | ||
| 158 | if (type1_access_ok(bus->number, devfn, where)) | ||
| 159 | return pci_direct_conf1.read(pci_domain_nr(bus), bus->number, | ||
| 160 | devfn, where, size, value); | ||
| 161 | return raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
| 162 | devfn, where, size, value); | ||
| 163 | } | ||
| 164 | |||
| 165 | static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | ||
| 166 | int size, u32 value) | ||
| 167 | { | ||
| 168 | int offset; | ||
| 169 | |||
| 170 | /* On MRST, there is no PCI ROM BAR, this will cause a subsequent read | ||
| 171 | * to ROM BAR return 0 then being ignored. | ||
| 172 | */ | ||
| 173 | if (where == PCI_ROM_ADDRESS) | ||
| 174 | return 0; | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Devices with fixed BARs need special handling: | ||
| 178 | * - BAR sizing code will save, write ~0, read size, restore | ||
| 179 | * - so writes to fixed BARs need special handling | ||
| 180 | * - other writes to fixed BAR devices should go through mmconfig | ||
| 181 | */ | ||
| 182 | offset = fixed_bar_cap(bus, devfn); | ||
| 183 | if (offset && | ||
| 184 | (where >= PCI_BASE_ADDRESS_0 && where <= PCI_BASE_ADDRESS_5)) { | ||
| 185 | return pci_device_update_fixed(bus, devfn, where, size, value, | ||
| 186 | offset); | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * On Moorestown update both real & mmconfig space | ||
| 191 | * Note: early Lincroft silicon can't handle type 1 accesses to | ||
| 192 | * non-existent devices, so just eat the write in that case. | ||
| 193 | */ | ||
| 194 | if (type1_access_ok(bus->number, devfn, where)) | ||
| 195 | return pci_direct_conf1.write(pci_domain_nr(bus), bus->number, | ||
| 196 | devfn, where, size, value); | ||
| 197 | return raw_pci_ext_ops->write(pci_domain_nr(bus), bus->number, devfn, | ||
| 198 | where, size, value); | ||
| 199 | } | ||
| 200 | |||
| 201 | static int mrst_pci_irq_enable(struct pci_dev *dev) | ||
| 202 | { | ||
| 203 | u8 pin; | ||
| 204 | struct io_apic_irq_attr irq_attr; | ||
| 205 | |||
| 206 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | ||
| 207 | |||
| 208 | /* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to | ||
| 209 | * IOAPIC RTE entries, so we just enable RTE for the device. | ||
| 210 | */ | ||
| 211 | irq_attr.ioapic = mp_find_ioapic(dev->irq); | ||
| 212 | irq_attr.ioapic_pin = dev->irq; | ||
| 213 | irq_attr.trigger = 1; /* level */ | ||
| 214 | irq_attr.polarity = 1; /* active low */ | ||
| 215 | io_apic_set_pci_routing(&dev->dev, dev->irq, &irq_attr); | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | struct pci_ops pci_mrst_ops = { | ||
| 221 | .read = pci_read, | ||
| 222 | .write = pci_write, | ||
| 223 | }; | ||
| 224 | |||
| 225 | /** | ||
| 226 | * pci_mrst_init - installs pci_mrst_ops | ||
| 227 | * | ||
| 228 | * Moorestown has an interesting PCI implementation (see above). | ||
| 229 | * Called when the early platform detection installs it. | ||
| 230 | */ | ||
| 231 | int __init pci_mrst_init(void) | ||
| 232 | { | ||
| 233 | printk(KERN_INFO "Moorestown platform detected, using MRST PCI ops\n"); | ||
| 234 | pci_mmcfg_late_init(); | ||
| 235 | pcibios_enable_irq = mrst_pci_irq_enable; | ||
| 236 | pci_root_ops = pci_mrst_ops; | ||
| 237 | /* Continue with standard init */ | ||
| 238 | return 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * Langwell devices reside at fixed offsets, don't try to move them. | ||
| 243 | */ | ||
| 244 | static void __devinit pci_fixed_bar_fixup(struct pci_dev *dev) | ||
| 245 | { | ||
| 246 | unsigned long offset; | ||
| 247 | u32 size; | ||
| 248 | int i; | ||
| 249 | |||
| 250 | /* Fixup the BAR sizes for fixed BAR devices and make them unmoveable */ | ||
| 251 | offset = fixed_bar_cap(dev->bus, dev->devfn); | ||
| 252 | if (!offset || PCI_DEVFN(2, 0) == dev->devfn || | ||
| 253 | PCI_DEVFN(2, 2) == dev->devfn) | ||
| 254 | return; | ||
| 255 | |||
| 256 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | ||
| 257 | pci_read_config_dword(dev, offset + 8 + (i * 4), &size); | ||
| 258 | dev->resource[i].end = dev->resource[i].start + size - 1; | ||
| 259 | dev->resource[i].flags |= IORESOURCE_PCI_FIXED; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixed_bar_fixup); | ||
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c index 8884a1c1ada6..8223738ad806 100644 --- a/arch/x86/pci/numaq_32.c +++ b/arch/x86/pci/numaq_32.c | |||
| @@ -148,14 +148,8 @@ int __init pci_numaq_init(void) | |||
| 148 | { | 148 | { |
| 149 | int quad; | 149 | int quad; |
| 150 | 150 | ||
| 151 | if (!found_numaq) | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | raw_pci_ops = &pci_direct_conf1_mq; | 151 | raw_pci_ops = &pci_direct_conf1_mq; |
| 155 | 152 | ||
| 156 | if (pcibios_scanned++) | ||
| 157 | return 0; | ||
| 158 | |||
| 159 | pci_root_bus = pcibios_scan_root(0); | 153 | pci_root_bus = pcibios_scan_root(0); |
| 160 | if (pci_root_bus) | 154 | if (pci_root_bus) |
| 161 | pci_bus_add_devices(pci_root_bus); | 155 | pci_bus_add_devices(pci_root_bus); |
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c index b889d824f7c6..b34815408f58 100644 --- a/arch/x86/pci/olpc.c +++ b/arch/x86/pci/olpc.c | |||
| @@ -304,9 +304,6 @@ static struct pci_raw_ops pci_olpc_conf = { | |||
| 304 | 304 | ||
| 305 | int __init pci_olpc_init(void) | 305 | int __init pci_olpc_init(void) |
| 306 | { | 306 | { |
| 307 | if (!machine_is_olpc() || olpc_has_vsa()) | ||
| 308 | return -ENODEV; | ||
| 309 | |||
| 310 | printk(KERN_INFO "PCI: Using configuration type OLPC\n"); | 307 | printk(KERN_INFO "PCI: Using configuration type OLPC\n"); |
| 311 | raw_pci_ops = &pci_olpc_conf; | 308 | raw_pci_ops = &pci_olpc_conf; |
| 312 | is_lx = is_geode_lx(); | 309 | is_lx = is_geode_lx(); |
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c index bcead7a46871..03008f72eb04 100644 --- a/arch/x86/pci/visws.c +++ b/arch/x86/pci/visws.c | |||
| @@ -69,9 +69,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) | |||
| 69 | 69 | ||
| 70 | int __init pci_visws_init(void) | 70 | int __init pci_visws_init(void) |
| 71 | { | 71 | { |
| 72 | if (!is_visws_box()) | ||
| 73 | return -1; | ||
| 74 | |||
| 75 | pcibios_enable_irq = &pci_visws_enable_irq; | 72 | pcibios_enable_irq = &pci_visws_enable_irq; |
| 76 | pcibios_disable_irq = &pci_visws_disable_irq; | 73 | pcibios_disable_irq = &pci_visws_disable_irq; |
| 77 | 74 | ||
| @@ -90,5 +87,6 @@ int __init pci_visws_init(void) | |||
| 90 | pci_scan_bus_with_sysdata(pci_bus1); | 87 | pci_scan_bus_with_sysdata(pci_bus1); |
| 91 | pci_fixup_irqs(pci_common_swizzle, visws_map_irq); | 88 | pci_fixup_irqs(pci_common_swizzle, visws_map_irq); |
| 92 | pcibios_resource_survey(); | 89 | pcibios_resource_survey(); |
| 93 | return 0; | 90 | /* Request bus scan */ |
| 91 | return 1; | ||
| 94 | } | 92 | } |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5b548aee9cbc..77b493b3d97b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -303,6 +303,49 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) | |||
| 303 | } | 303 | } |
| 304 | EXPORT_SYMBOL_GPL(pci_find_ext_capability); | 304 | EXPORT_SYMBOL_GPL(pci_find_ext_capability); |
| 305 | 305 | ||
| 306 | /** | ||
| 307 | * pci_bus_find_ext_capability - find an extended capability | ||
| 308 | * @bus: the PCI bus to query | ||
| 309 | * @devfn: PCI device to query | ||
| 310 | * @cap: capability code | ||
| 311 | * | ||
| 312 | * Like pci_find_ext_capability() but works for pci devices that do not have a | ||
| 313 | * pci_dev structure set up yet. | ||
| 314 | * | ||
| 315 | * Returns the address of the requested capability structure within the | ||
| 316 | * device's PCI configuration space or 0 in case the device does not | ||
| 317 | * support it. | ||
| 318 | */ | ||
| 319 | int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn, | ||
| 320 | int cap) | ||
| 321 | { | ||
| 322 | u32 header; | ||
| 323 | int ttl; | ||
| 324 | int pos = PCI_CFG_SPACE_SIZE; | ||
| 325 | |||
| 326 | /* minimum 8 bytes per capability */ | ||
| 327 | ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; | ||
| 328 | |||
| 329 | if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) | ||
| 330 | return 0; | ||
| 331 | if (header == 0xffffffff || header == 0) | ||
| 332 | return 0; | ||
| 333 | |||
| 334 | while (ttl-- > 0) { | ||
| 335 | if (PCI_EXT_CAP_ID(header) == cap) | ||
| 336 | return pos; | ||
| 337 | |||
| 338 | pos = PCI_EXT_CAP_NEXT(header); | ||
| 339 | if (pos < PCI_CFG_SPACE_SIZE) | ||
| 340 | break; | ||
| 341 | |||
| 342 | if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 306 | static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) | 349 | static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) |
| 307 | { | 350 | { |
| 308 | int rc, ttl = PCI_FIND_CAP_TTL; | 351 | int rc, ttl = PCI_FIND_CAP_TTL; |
diff --git a/include/linux/pci.h b/include/linux/pci.h index ec95ebe629f1..cd5809a5963e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -678,6 +678,8 @@ enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *dev); | |||
| 678 | int pci_find_capability(struct pci_dev *dev, int cap); | 678 | int pci_find_capability(struct pci_dev *dev, int cap); |
| 679 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); | 679 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); |
| 680 | int pci_find_ext_capability(struct pci_dev *dev, int cap); | 680 | int pci_find_ext_capability(struct pci_dev *dev, int cap); |
| 681 | int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn, | ||
| 682 | int cap); | ||
| 681 | int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); | 683 | int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); |
| 682 | int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); | 684 | int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); |
| 683 | struct pci_bus *pci_find_next_bus(const struct pci_bus *from); | 685 | struct pci_bus *pci_find_next_bus(const struct pci_bus *from); |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 9f2ad0aa3c39..c8f302991b66 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
| @@ -507,6 +507,7 @@ | |||
| 507 | #define PCI_EXT_CAP_ID_VC 2 | 507 | #define PCI_EXT_CAP_ID_VC 2 |
| 508 | #define PCI_EXT_CAP_ID_DSN 3 | 508 | #define PCI_EXT_CAP_ID_DSN 3 |
| 509 | #define PCI_EXT_CAP_ID_PWR 4 | 509 | #define PCI_EXT_CAP_ID_PWR 4 |
| 510 | #define PCI_EXT_CAP_ID_VNDR 11 | ||
| 510 | #define PCI_EXT_CAP_ID_ACS 13 | 511 | #define PCI_EXT_CAP_ID_ACS 13 |
| 511 | #define PCI_EXT_CAP_ID_ARI 14 | 512 | #define PCI_EXT_CAP_ID_ARI 14 |
| 512 | #define PCI_EXT_CAP_ID_ATS 15 | 513 | #define PCI_EXT_CAP_ID_ATS 15 |
