aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-10 14:16:49 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-12 02:44:59 -0400
commit1b374e4d6f8b3eb2fcd034fcc24ea8ba1dfde7aa (patch)
treefaf5aa00e344e473957206bc82ffbb746e438d0b
parent2d7a66d02e11af9ab8e16c76d22767e622b4e3d7 (diff)
x64, x2apic/intr-remap: basic apic ops support
Introduce basic apic operations which handle the apic programming. This will be used later to introduce another specific operations for x2apic. For the perfomance critial accesses like IPI's, EOI etc, we use the native operations as they are already referenced by different indirections like genapic, irq_chip etc. 64bit Paravirt ops can also define their apic operations accordingly. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: akpm@linux-foundation.org Cc: arjan@linux.intel.com Cc: andi@firstfloor.org Cc: ebiederm@xmission.com Cc: jbarnes@virtuousgeek.org Cc: steiner@sgi.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/apic_32.c6
-rw-r--r--arch/x86/kernel/apic_64.c34
-rw-r--r--arch/x86/kernel/io_apic_64.c8
-rw-r--r--arch/x86/kernel/paravirt.c8
-rw-r--r--arch/x86/kernel/smpboot.c28
-rw-r--r--include/asm-x86/apic.h43
-rw-r--r--include/asm-x86/ipi.h16
-rw-r--r--include/asm-x86/paravirt.h2
-rw-r--r--include/asm-x86/smp.h2
9 files changed, 109 insertions, 38 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 3e58b676d23b..2a83c07bd887 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -145,6 +145,12 @@ static int modern_apic(void)
145 return lapic_get_version() >= 0x14; 145 return lapic_get_version() >= 0x14;
146} 146}
147 147
148void apic_icr_write(u32 low, u32 id)
149{
150 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(id));
151 apic_write_around(APIC_ICR, low);
152}
153
148void apic_wait_icr_idle(void) 154void apic_wait_icr_idle(void)
149{ 155{
150 while (apic_read(APIC_ICR) & APIC_ICR_BUSY) 156 while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 3963f590c3d4..9bb040689b31 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -119,13 +119,13 @@ static int modern_apic(void)
119 return lapic_get_version() >= 0x14; 119 return lapic_get_version() >= 0x14;
120} 120}
121 121
122void apic_wait_icr_idle(void) 122void xapic_wait_icr_idle(void)
123{ 123{
124 while (apic_read(APIC_ICR) & APIC_ICR_BUSY) 124 while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
125 cpu_relax(); 125 cpu_relax();
126} 126}
127 127
128u32 safe_apic_wait_icr_idle(void) 128u32 safe_xapic_wait_icr_idle(void)
129{ 129{
130 u32 send_status; 130 u32 send_status;
131 int timeout; 131 int timeout;
@@ -141,6 +141,36 @@ u32 safe_apic_wait_icr_idle(void)
141 return send_status; 141 return send_status;
142} 142}
143 143
144void xapic_icr_write(u32 low, u32 id)
145{
146 apic_write(APIC_ICR2, id << 24);
147 apic_write(APIC_ICR, low);
148}
149
150u64 xapic_icr_read(void)
151{
152 u32 icr1, icr2;
153
154 icr2 = apic_read(APIC_ICR2);
155 icr1 = apic_read(APIC_ICR);
156
157 return (icr1 | ((u64)icr2 << 32));
158}
159
160static struct apic_ops xapic_ops = {
161 .read = native_apic_mem_read,
162 .write = native_apic_mem_write,
163 .write_atomic = native_apic_mem_write_atomic,
164 .icr_read = xapic_icr_read,
165 .icr_write = xapic_icr_write,
166 .wait_icr_idle = xapic_wait_icr_idle,
167 .safe_wait_icr_idle = safe_xapic_wait_icr_idle,
168};
169
170struct apic_ops __read_mostly *apic_ops = &xapic_ops;
171
172EXPORT_SYMBOL_GPL(apic_ops);
173
144/** 174/**
145 * enable_NMI_through_LVT0 - enable NMI through local vector table 0 175 * enable_NMI_through_LVT0 - enable NMI through local vector table 0
146 */ 176 */
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index 84dd63c13d63..b62d42ef9283 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -1157,6 +1157,7 @@ static __apicdebuginit void print_APIC_bitfield (int base)
1157void __apicdebuginit print_local_APIC(void * dummy) 1157void __apicdebuginit print_local_APIC(void * dummy)
1158{ 1158{
1159 unsigned int v, ver, maxlvt; 1159 unsigned int v, ver, maxlvt;
1160 unsigned long icr;
1160 1161
1161 if (apic_verbosity == APIC_QUIET) 1162 if (apic_verbosity == APIC_QUIET)
1162 return; 1163 return;
@@ -1200,10 +1201,9 @@ void __apicdebuginit print_local_APIC(void * dummy)
1200 v = apic_read(APIC_ESR); 1201 v = apic_read(APIC_ESR);
1201 printk(KERN_DEBUG "... APIC ESR: %08x\n", v); 1202 printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
1202 1203
1203 v = apic_read(APIC_ICR); 1204 icr = apic_icr_read();
1204 printk(KERN_DEBUG "... APIC ICR: %08x\n", v); 1205 printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
1205 v = apic_read(APIC_ICR2); 1206 printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
1206 printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
1207 1207
1208 v = apic_read(APIC_LVTT); 1208 v = apic_read(APIC_LVTT);
1209 printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); 1209 printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index e0f571d58c19..b80105a0f474 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -360,9 +360,11 @@ struct pv_cpu_ops pv_cpu_ops = {
360 360
361struct pv_apic_ops pv_apic_ops = { 361struct pv_apic_ops pv_apic_ops = {
362#ifdef CONFIG_X86_LOCAL_APIC 362#ifdef CONFIG_X86_LOCAL_APIC
363 .apic_write = native_apic_write, 363#ifnded CONFIG_X86_64
364 .apic_write_atomic = native_apic_write_atomic, 364 .apic_write = native_apic_mem_write,
365 .apic_read = native_apic_read, 365 .apic_write_atomic = native_apic_mem_write_atomic,
366 .apic_read = native_apic_mem_read,
367#endif
366 .setup_boot_clock = setup_boot_APIC_clock, 368 .setup_boot_clock = setup_boot_APIC_clock,
367 .setup_secondary_clock = setup_secondary_APIC_clock, 369 .setup_secondary_clock = setup_secondary_APIC_clock,
368 .startup_ipi_hook = paravirt_nop, 370 .startup_ipi_hook = paravirt_nop,
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index f35c2d8016ac..c55263b3df02 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -123,7 +123,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
123 123
124static atomic_t init_deasserted; 124static atomic_t init_deasserted;
125 125
126static int boot_cpu_logical_apicid;
127 126
128/* representing cpus for which sibling maps can be computed */ 127/* representing cpus for which sibling maps can be computed */
129static cpumask_t cpu_sibling_setup_map; 128static cpumask_t cpu_sibling_setup_map;
@@ -165,6 +164,8 @@ static void unmap_cpu_to_node(int cpu)
165#endif 164#endif
166 165
167#ifdef CONFIG_X86_32 166#ifdef CONFIG_X86_32
167static int boot_cpu_logical_apicid;
168
168u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = 169u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
169 { [0 ... NR_CPUS-1] = BAD_APICID }; 170 { [0 ... NR_CPUS-1] = BAD_APICID };
170 171
@@ -546,8 +547,7 @@ static inline void __inquire_remote_apic(int apicid)
546 printk(KERN_CONT 547 printk(KERN_CONT
547 "a previous APIC delivery may have failed\n"); 548 "a previous APIC delivery may have failed\n");
548 549
549 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); 550 apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
550 apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
551 551
552 timeout = 0; 552 timeout = 0;
553 do { 553 do {
@@ -579,11 +579,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
579 int maxlvt; 579 int maxlvt;
580 580
581 /* Target chip */ 581 /* Target chip */
582 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
583
584 /* Boot on the stack */ 582 /* Boot on the stack */
585 /* Kick the second */ 583 /* Kick the second */
586 apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); 584 apic_icr_write(APIC_DM_NMI | APIC_DEST_LOGICAL, logical_apicid);
587 585
588 Dprintk("Waiting for send to finish...\n"); 586 Dprintk("Waiting for send to finish...\n");
589 send_status = safe_apic_wait_icr_idle(); 587 send_status = safe_apic_wait_icr_idle();
@@ -639,13 +637,11 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
639 /* 637 /*
640 * Turn INIT on target chip 638 * Turn INIT on target chip
641 */ 639 */
642 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
643
644 /* 640 /*
645 * Send IPI 641 * Send IPI
646 */ 642 */
647 apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT 643 apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
648 | APIC_DM_INIT); 644 phys_apicid);
649 645
650 Dprintk("Waiting for send to finish...\n"); 646 Dprintk("Waiting for send to finish...\n");
651 send_status = safe_apic_wait_icr_idle(); 647 send_status = safe_apic_wait_icr_idle();
@@ -655,10 +651,8 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
655 Dprintk("Deasserting INIT.\n"); 651 Dprintk("Deasserting INIT.\n");
656 652
657 /* Target chip */ 653 /* Target chip */
658 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
659
660 /* Send IPI */ 654 /* Send IPI */
661 apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); 655 apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
662 656
663 Dprintk("Waiting for send to finish...\n"); 657 Dprintk("Waiting for send to finish...\n");
664 send_status = safe_apic_wait_icr_idle(); 658 send_status = safe_apic_wait_icr_idle();
@@ -703,12 +697,10 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
703 */ 697 */
704 698
705 /* Target chip */ 699 /* Target chip */
706 apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
707
708 /* Boot on the stack */ 700 /* Boot on the stack */
709 /* Kick the second */ 701 /* Kick the second */
710 apic_write_around(APIC_ICR, APIC_DM_STARTUP 702 apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
711 | (start_eip >> 12)); 703 phys_apicid);
712 704
713 /* 705 /*
714 * Give the other CPU some time to accept the IPI. 706 * Give the other CPU some time to accept the IPI.
@@ -1147,7 +1139,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
1147 * Setup boot CPU information 1139 * Setup boot CPU information
1148 */ 1140 */
1149 smp_store_cpu_info(0); /* Final full version of the data */ 1141 smp_store_cpu_info(0); /* Final full version of the data */
1142#ifdef CONFIG_X86_32
1150 boot_cpu_logical_apicid = logical_smp_processor_id(); 1143 boot_cpu_logical_apicid = logical_smp_processor_id();
1144#endif
1151 current_thread_info()->cpu = 0; /* needed? */ 1145 current_thread_info()->cpu = 0; /* needed? */
1152 set_cpu_sibling_map(0); 1146 set_cpu_sibling_map(0);
1153 1147
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index 4e2c1e517f06..6fda195337c5 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -47,32 +47,59 @@ extern int disable_apic;
47#ifdef CONFIG_PARAVIRT 47#ifdef CONFIG_PARAVIRT
48#include <asm/paravirt.h> 48#include <asm/paravirt.h>
49#else 49#else
50#define apic_write native_apic_write 50#ifndef CONFIG_X86_64
51#define apic_write_atomic native_apic_write_atomic 51#define apic_write native_apic_mem_write
52#define apic_read native_apic_read 52#define apic_write_atomic native_apic_mem_write_atomic
53#define apic_read native_apic_mem_read
54#endif
53#define setup_boot_clock setup_boot_APIC_clock 55#define setup_boot_clock setup_boot_APIC_clock
54#define setup_secondary_clock setup_secondary_APIC_clock 56#define setup_secondary_clock setup_secondary_APIC_clock
55#endif 57#endif
56 58
57extern int is_vsmp_box(void); 59extern int is_vsmp_box(void);
58 60
59static inline void native_apic_write(unsigned long reg, u32 v) 61static inline void native_apic_mem_write(u32 reg, u32 v)
60{ 62{
61 *((volatile u32 *)(APIC_BASE + reg)) = v; 63 *((volatile u32 *)(APIC_BASE + reg)) = v;
62} 64}
63 65
64static inline void native_apic_write_atomic(unsigned long reg, u32 v) 66static inline void native_apic_mem_write_atomic(u32 reg, u32 v)
65{ 67{
66 (void)xchg((u32 *)(APIC_BASE + reg), v); 68 (void)xchg((u32 *)(APIC_BASE + reg), v);
67} 69}
68 70
69static inline u32 native_apic_read(unsigned long reg) 71static inline u32 native_apic_mem_read(u32 reg)
70{ 72{
71 return *((volatile u32 *)(APIC_BASE + reg)); 73 return *((volatile u32 *)(APIC_BASE + reg));
72} 74}
73 75
76#ifdef CONFIG_X86_32
74extern void apic_wait_icr_idle(void); 77extern void apic_wait_icr_idle(void);
75extern u32 safe_apic_wait_icr_idle(void); 78extern u32 safe_apic_wait_icr_idle(void);
79extern void apic_icr_write(u32 low, u32 id);
80#else
81
82struct apic_ops {
83 u32 (*read)(u32 reg);
84 void (*write)(u32 reg, u32 v);
85 void (*write_atomic)(u32 reg, u32 v);
86 u64 (*icr_read)(void);
87 void (*icr_write)(u32 low, u32 high);
88 void (*wait_icr_idle)(void);
89 u32 (*safe_wait_icr_idle)(void);
90};
91
92extern struct apic_ops *apic_ops;
93
94#define apic_read (apic_ops->read)
95#define apic_write (apic_ops->write)
96#define apic_write_atomic (apic_ops->write_atomic)
97#define apic_icr_read (apic_ops->icr_read)
98#define apic_icr_write (apic_ops->icr_write)
99#define apic_wait_icr_idle (apic_ops->wait_icr_idle)
100#define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle)
101#endif
102
76extern int get_physical_broadcast(void); 103extern int get_physical_broadcast(void);
77 104
78#ifdef CONFIG_X86_GOOD_APIC 105#ifdef CONFIG_X86_GOOD_APIC
@@ -95,7 +122,11 @@ static inline void ack_APIC_irq(void)
95 */ 122 */
96 123
97 /* Docs say use 0 for future compatibility */ 124 /* Docs say use 0 for future compatibility */
125#ifdef CONFIG_X86_32
98 apic_write_around(APIC_EOI, 0); 126 apic_write_around(APIC_EOI, 0);
127#else
128 native_apic_mem_write(APIC_EOI, 0);
129#endif
99} 130}
100 131
101extern int lapic_get_maxlvt(void); 132extern int lapic_get_maxlvt(void);
diff --git a/include/asm-x86/ipi.h b/include/asm-x86/ipi.h
index 196d63c28aa4..3d8d6a6c1f8e 100644
--- a/include/asm-x86/ipi.h
+++ b/include/asm-x86/ipi.h
@@ -49,6 +49,12 @@ static inline int __prepare_ICR2(unsigned int mask)
49 return SET_APIC_DEST_FIELD(mask); 49 return SET_APIC_DEST_FIELD(mask);
50} 50}
51 51
52static inline void __xapic_wait_icr_idle(void)
53{
54 while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY)
55 cpu_relax();
56}
57
52static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, 58static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
53 unsigned int dest) 59 unsigned int dest)
54{ 60{
@@ -64,7 +70,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
64 /* 70 /*
65 * Wait for idle. 71 * Wait for idle.
66 */ 72 */
67 apic_wait_icr_idle(); 73 __xapic_wait_icr_idle();
68 74
69 /* 75 /*
70 * No need to touch the target chip field 76 * No need to touch the target chip field
@@ -74,7 +80,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
74 /* 80 /*
75 * Send the IPI. The write to APIC_ICR fires this off. 81 * Send the IPI. The write to APIC_ICR fires this off.
76 */ 82 */
77 apic_write(APIC_ICR, cfg); 83 native_apic_mem_write(APIC_ICR, cfg);
78} 84}
79 85
80/* 86/*
@@ -92,13 +98,13 @@ static inline void __send_IPI_dest_field(unsigned int mask, int vector,
92 if (unlikely(vector == NMI_VECTOR)) 98 if (unlikely(vector == NMI_VECTOR))
93 safe_apic_wait_icr_idle(); 99 safe_apic_wait_icr_idle();
94 else 100 else
95 apic_wait_icr_idle(); 101 __xapic_wait_icr_idle();
96 102
97 /* 103 /*
98 * prepare target chip field 104 * prepare target chip field
99 */ 105 */
100 cfg = __prepare_ICR2(mask); 106 cfg = __prepare_ICR2(mask);
101 apic_write(APIC_ICR2, cfg); 107 native_apic_mem_write(APIC_ICR2, cfg);
102 108
103 /* 109 /*
104 * program the ICR 110 * program the ICR
@@ -108,7 +114,7 @@ static inline void __send_IPI_dest_field(unsigned int mask, int vector,
108 /* 114 /*
109 * Send the IPI. The write to APIC_ICR fires this off. 115 * Send the IPI. The write to APIC_ICR fires this off.
110 */ 116 */
111 apic_write(APIC_ICR, cfg); 117 native_apic_mem_write(APIC_ICR, cfg);
112} 118}
113 119
114static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) 120static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index ef5e8ec6a6ab..10adac02e6db 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -891,6 +891,7 @@ static inline void slow_down_io(void)
891/* 891/*
892 * Basic functions accessing APICs. 892 * Basic functions accessing APICs.
893 */ 893 */
894#ifndef CONFIG_X86_64
894static inline void apic_write(unsigned long reg, u32 v) 895static inline void apic_write(unsigned long reg, u32 v)
895{ 896{
896 PVOP_VCALL2(pv_apic_ops.apic_write, reg, v); 897 PVOP_VCALL2(pv_apic_ops.apic_write, reg, v);
@@ -905,6 +906,7 @@ static inline u32 apic_read(unsigned long reg)
905{ 906{
906 return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg); 907 return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg);
907} 908}
909#endif
908 910
909static inline void setup_boot_clock(void) 911static inline void setup_boot_clock(void)
910{ 912{
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 9848715fbd9e..d9d007d22785 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -158,13 +158,13 @@ extern int safe_smp_processor_id(void);
158 158
159#ifdef CONFIG_X86_LOCAL_APIC 159#ifdef CONFIG_X86_LOCAL_APIC
160 160
161#ifndef CONFIG_X86_64
161static inline int logical_smp_processor_id(void) 162static inline int logical_smp_processor_id(void)
162{ 163{
163 /* we don't want to mark this access volatile - bad code generation */ 164 /* we don't want to mark this access volatile - bad code generation */
164 return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR)); 165 return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR));
165} 166}
166 167
167#ifndef CONFIG_X86_64
168static inline unsigned int read_apic_id(void) 168static inline unsigned int read_apic_id(void)
169{ 169{
170 return *(u32 *)(APIC_BASE + APIC_ID); 170 return *(u32 *)(APIC_BASE + APIC_ID);