summaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/lapic.h
blob: f60974a878aa8d48979ae404bdd83b517c54fab6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 * From coreboot file of same name
 *
 * Copyright (C) 2014 Google, Inc
 *
 * SPDX-License-Identifier:	GPL-2.0
 */

#ifndef _ARCH_ASM_LAPIC_H
#define _ARCH_ASM_LAPIC_H

#include <asm/io.h>
#include <asm/msr.h>
#include <asm/msr-index.h>
#include <asm/processor.h>

#define LAPIC_DEFAULT_BASE		0xfee00000

#define LAPIC_ID			0x020
#define LAPIC_LVR			0x030

#define LAPIC_TASKPRI			0x080
#define LAPIC_TPRI_MASK			0xff

#define LAPIC_RRR			0x0c0

#define LAPIC_SPIV			0x0f0
#define LAPIC_SPIV_ENABLE		0x100

#define LAPIC_ICR			0x300
#define LAPIC_DEST_SELF			0x40000
#define LAPIC_DEST_ALLINC		0x80000
#define LAPIC_DEST_ALLBUT		0xc0000
#define LAPIC_ICR_RR_MASK		0x30000
#define LAPIC_ICR_RR_INVALID		0x00000
#define LAPIC_ICR_RR_INPROG		0x10000
#define LAPIC_ICR_RR_VALID		0x20000
#define LAPIC_INT_LEVELTRIG		0x08000
#define LAPIC_INT_ASSERT		0x04000
#define LAPIC_ICR_BUSY			0x01000
#define LAPIC_DEST_LOGICAL		0x00800
#define LAPIC_DM_FIXED			0x00000
#define LAPIC_DM_LOWEST			0x00100
#define LAPIC_DM_SMI			0x00200
#define LAPIC_DM_REMRD			0x00300
#define LAPIC_DM_NMI			0x00400
#define LAPIC_DM_INIT			0x00500
#define LAPIC_DM_STARTUP		0x00600
#define LAPIC_DM_EXTINT			0x00700
#define LAPIC_VECTOR_MASK		0x000ff

#define LAPIC_ICR2			0x310
#define GET_LAPIC_DEST_FIELD(x)		(((x) >> 24) & 0xff)
#define SET_LAPIC_DEST_FIELD(x)		((x) << 24)

#define LAPIC_LVT0			0x350
#define LAPIC_LVT1			0x360
#define LAPIC_LVT_MASKED		(1 << 16)
#define LAPIC_LVT_LEVEL_TRIGGER		(1 << 15)
#define LAPIC_LVT_REMOTE_IRR		(1 << 14)
#define LAPIC_INPUT_POLARITY		(1 << 13)
#define LAPIC_SEND_PENDING		(1 << 12)
#define LAPIC_LVT_RESERVED_1		(1 << 11)
#define LAPIC_DELIVERY_MODE_MASK	(7 << 8)
#define LAPIC_DELIVERY_MODE_FIXED	(0 << 8)
#define LAPIC_DELIVERY_MODE_NMI		(4 << 8)
#define LAPIC_DELIVERY_MODE_EXTINT	(7 << 8)

static inline __attribute__((always_inline))
		unsigned long lapic_read(unsigned long reg)
{
	return readl(LAPIC_DEFAULT_BASE + reg);
}

static inline __attribute__((always_inline))
		void lapic_write(unsigned long reg, unsigned long val)
{
	writel(val, LAPIC_DEFAULT_BASE + reg);
}

static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void)
{
	do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
}

static inline void enable_lapic(void)
{
	msr_t msr;

	msr = msr_read(MSR_IA32_APICBASE);
	msr.hi &= 0xffffff00;
	msr.lo |= MSR_IA32_APICBASE_ENABLE;
	msr.lo &= ~MSR_IA32_APICBASE_BASE;
	msr.lo |= LAPIC_DEFAULT_BASE;
	msr_write(MSR_IA32_APICBASE, msr);
}

static inline void disable_lapic(void)
{
	msr_t msr;

	msr = msr_read(MSR_IA32_APICBASE);
	msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
	msr_write(MSR_IA32_APICBASE, msr);
}

static inline __attribute__((always_inline)) unsigned long lapicid(void)
{
	return lapic_read(LAPIC_ID) >> 24;
}

static inline __attribute__((always_inline)) void stop_this_cpu(void)
{
	/* Called by an AP when it is ready to halt and wait for a new task */
	for (;;)
		cpu_hlt();
}

#define xchg(ptr, v)	((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
						    sizeof(*(ptr))))

struct __xchg_dummy	{ unsigned long a[100]; };
#define __xg(x)		((struct __xchg_dummy *)(x))

/*
 * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
 *
 * Note 2: xchg has side effect, so that attribute volatile is necessary,
 *         but generally the primitive is invalid, *ptr is output argument.
 */
static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
				   int size)
{
	switch (size) {
	case 1:
		__asm__ __volatile__("xchgb %b0,%1"
			: "=q" (x)
			: "m" (*__xg(ptr)), "0" (x)
			: "memory");
		break;
	case 2:
		__asm__ __volatile__("xchgw %w0,%1"
			: "=r" (x)
			: "m" (*__xg(ptr)), "0" (x)
			: "memory");
		break;
	case 4:
		__asm__ __volatile__("xchgl %0,%1"
			: "=r" (x)
			: "m" (*__xg(ptr)), "0" (x)
			: "memory");
		break;
	}

	return x;
}

static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
{
	(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
}

#define lapic_read_around(x)		lapic_read(x)
#define lapic_write_around(x, y)	lapic_write_atomic((x), (y))

static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
{
	int timeout;
	unsigned long status;
	int result;

	lapic_wait_icr_idle();
	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
	lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));

	timeout = 0;
	do {
		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);

	result = -1;
	if (status == LAPIC_ICR_RR_VALID) {
		*pvalue = lapic_read(LAPIC_RRR);
		result = 0;
	}

	return result;
}

void lapic_setup(void);

#endif
OpenPOWER on IntegriCloud