Blame view

virt/kvm/ioapic.c 10.9 KB
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
1
2
  /*
   *  Copyright (C) 2001  MandrakeSoft S.A.
221d059d1   Avi Kivity   KVM: Update Red H...
3
   *  Copyright 2010 Red Hat, Inc. and/or its affiliates.
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
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
   *
   *    MandrakeSoft S.A.
   *    43, rue d'Aboukir
   *    75002 Paris - France
   *    http://www.linux-mandrake.com/
   *    http://www.mandrakesoft.com/
   *
   *  This library is free software; you can redistribute it and/or
   *  modify it under the terms of the GNU Lesser General Public
   *  License as published by the Free Software Foundation; either
   *  version 2 of the License, or (at your option) any later version.
   *
   *  This library is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   *  Lesser General Public License for more details.
   *
   *  You should have received a copy of the GNU Lesser General Public
   *  License along with this library; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   *  Yunhong Jiang <yunhong.jiang@intel.com>
   *  Yaozu (Eddie) Dong <eddie.dong@intel.com>
   *  Based on Xen 3.1 code.
   */
edf884172   Avi Kivity   KVM: Move arch de...
29
  #include <linux/kvm_host.h>
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
30
31
32
33
34
35
  #include <linux/kvm.h>
  #include <linux/mm.h>
  #include <linux/highmem.h>
  #include <linux/smp.h>
  #include <linux/hrtimer.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
37
  #include <asm/processor.h>
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
38
39
  #include <asm/page.h>
  #include <asm/current.h>
1000ff8d8   Gleb Natapov   KVM: Add trace po...
40
  #include <trace/events/kvm.h>
82470196f   Zhang Xiantao   KVM: Move irqchip...
41
42
43
  
  #include "ioapic.h"
  #include "lapic.h"
f52447261   Marcelo Tosatti   KVM: irq ack noti...
44
  #include "irq.h"
82470196f   Zhang Xiantao   KVM: Move irqchip...
45

e25e3ed56   Laurent Vivier   KVM: Add some \n ...
46
47
48
  #if 0
  #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
  #else
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
49
  #define ioapic_debug(fmt, arg...)
e25e3ed56   Laurent Vivier   KVM: Add some \n ...
50
  #endif
ff4b9df87   Marcelo Tosatti   KVM: IOAPIC: only...
51
  static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
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
  
  static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
  					  unsigned long addr,
  					  unsigned long length)
  {
  	unsigned long result = 0;
  
  	switch (ioapic->ioregsel) {
  	case IOAPIC_REG_VERSION:
  		result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
  			  | (IOAPIC_VERSION_ID & 0xff));
  		break;
  
  	case IOAPIC_REG_APIC_ID:
  	case IOAPIC_REG_ARB_ID:
  		result = ((ioapic->id & 0xf) << 24);
  		break;
  
  	default:
  		{
  			u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
  			u64 redir_content;
  
  			ASSERT(redir_index < IOAPIC_NUM_PINS);
  
  			redir_content = ioapic->redirtbl[redir_index].bits;
  			result = (ioapic->ioregsel & 0x1) ?
  			    (redir_content >> 32) & 0xffffffff :
  			    redir_content & 0xffffffff;
  			break;
  		}
  	}
  
  	return result;
  }
4925663a0   Gleb Natapov   KVM: Report IRQ i...
87
  static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
88
  {
cf9e4e15e   Sheng Yang   KVM: Split IOAPIC...
89
  	union kvm_ioapic_redirect_entry *pent;
4925663a0   Gleb Natapov   KVM: Report IRQ i...
90
  	int injected = -1;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
91
92
93
94
  
  	pent = &ioapic->redirtbl[idx];
  
  	if (!pent->fields.mask) {
4925663a0   Gleb Natapov   KVM: Report IRQ i...
95
  		injected = ioapic_deliver(ioapic, idx);
ff4b9df87   Marcelo Tosatti   KVM: IOAPIC: only...
96
  		if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
97
98
  			pent->fields.remote_irr = 1;
  	}
4925663a0   Gleb Natapov   KVM: Report IRQ i...
99
100
  
  	return injected;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
101
  }
46a929bc1   Avi Kivity   KVM: avoid taking...
102
103
104
105
106
107
108
109
110
111
112
113
  static void update_handled_vectors(struct kvm_ioapic *ioapic)
  {
  	DECLARE_BITMAP(handled_vectors, 256);
  	int i;
  
  	memset(handled_vectors, 0, sizeof(handled_vectors));
  	for (i = 0; i < IOAPIC_NUM_PINS; ++i)
  		__set_bit(ioapic->redirtbl[i].fields.vector, handled_vectors);
  	memcpy(ioapic->handled_vectors, handled_vectors,
  	       sizeof(handled_vectors));
  	smp_wmb();
  }
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
114
115
116
  static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
  {
  	unsigned index;
75858a84a   Avi Kivity   KVM: Interrupt ma...
117
  	bool mask_before, mask_after;
70f93dae3   Gleb Natapov   KVM: Use temporar...
118
  	union kvm_ioapic_redirect_entry *e;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  
  	switch (ioapic->ioregsel) {
  	case IOAPIC_REG_VERSION:
  		/* Writes are ignored. */
  		break;
  
  	case IOAPIC_REG_APIC_ID:
  		ioapic->id = (val >> 24) & 0xf;
  		break;
  
  	case IOAPIC_REG_ARB_ID:
  		break;
  
  	default:
  		index = (ioapic->ioregsel - 0x10) >> 1;
e25e3ed56   Laurent Vivier   KVM: Add some \n ...
134
135
  		ioapic_debug("change redir index %x val %x
  ", index, val);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
136
137
  		if (index >= IOAPIC_NUM_PINS)
  			return;
70f93dae3   Gleb Natapov   KVM: Use temporar...
138
139
  		e = &ioapic->redirtbl[index];
  		mask_before = e->fields.mask;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
140
  		if (ioapic->ioregsel & 1) {
70f93dae3   Gleb Natapov   KVM: Use temporar...
141
142
  			e->bits &= 0xffffffff;
  			e->bits |= (u64) val << 32;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
143
  		} else {
70f93dae3   Gleb Natapov   KVM: Use temporar...
144
145
146
  			e->bits &= ~0xffffffffULL;
  			e->bits |= (u32) val;
  			e->fields.remote_irr = 0;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
147
  		}
46a929bc1   Avi Kivity   KVM: avoid taking...
148
  		update_handled_vectors(ioapic);
70f93dae3   Gleb Natapov   KVM: Use temporar...
149
  		mask_after = e->fields.mask;
75858a84a   Avi Kivity   KVM: Interrupt ma...
150
  		if (mask_before != mask_after)
4a994358b   Gleb Natapov   KVM: Convert mask...
151
  			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
70f93dae3   Gleb Natapov   KVM: Use temporar...
152
  		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
b4a2f5e72   Gleb Natapov   KVM: Avoid redeli...
153
  		    && ioapic->irr & (1 << index))
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
154
155
156
157
  			ioapic_service(ioapic, index);
  		break;
  	}
  }
a53c17d21   Gleb Natapov   KVM: ioapic/msi i...
158
159
  static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
  {
58c2dde17   Gleb Natapov   KVM: APIC: get ri...
160
161
  	union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
  	struct kvm_lapic_irq irqe;
a53c17d21   Gleb Natapov   KVM: ioapic/msi i...
162
163
164
165
  
  	ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
  		     "vector=%x trig_mode=%x
  ",
a38f84ca8   Liu Yuan   KVM: ioapic: Fix ...
166
  		     entry->fields.dest_id, entry->fields.dest_mode,
58c2dde17   Gleb Natapov   KVM: APIC: get ri...
167
168
169
170
171
172
173
174
175
176
  		     entry->fields.delivery_mode, entry->fields.vector,
  		     entry->fields.trig_mode);
  
  	irqe.dest_id = entry->fields.dest_id;
  	irqe.vector = entry->fields.vector;
  	irqe.dest_mode = entry->fields.dest_mode;
  	irqe.trig_mode = entry->fields.trig_mode;
  	irqe.delivery_mode = entry->fields.delivery_mode << 8;
  	irqe.level = 1;
  	irqe.shorthand = 0;
a53c17d21   Gleb Natapov   KVM: ioapic/msi i...
177
178
179
180
  
  #ifdef CONFIG_X86
  	/* Always delivery PIT interrupt to vcpu 0 */
  	if (irq == 0) {
58c2dde17   Gleb Natapov   KVM: APIC: get ri...
181
  		irqe.dest_mode = 0; /* Physical mode. */
c5af89b68   Gleb Natapov   KVM: Introduce kv...
182
183
  		/* need to read apic_id from apic regiest since
  		 * it can be rewritten */
d546cb406   Gleb Natapov   KVM: drop bsp_vcp...
184
  		irqe.dest_id = ioapic->kvm->bsp_vcpu_id;
a53c17d21   Gleb Natapov   KVM: ioapic/msi i...
185
186
  	}
  #endif
58c2dde17   Gleb Natapov   KVM: APIC: get ri...
187
  	return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
a53c17d21   Gleb Natapov   KVM: ioapic/msi i...
188
  }
4925663a0   Gleb Natapov   KVM: Report IRQ i...
189
  int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
190
  {
07dc7263b   Marcelo Tosatti   KVM: read apic->i...
191
  	u32 old_irr;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
192
  	u32 mask = 1 << irq;
cf9e4e15e   Sheng Yang   KVM: Split IOAPIC...
193
  	union kvm_ioapic_redirect_entry entry;
4925663a0   Gleb Natapov   KVM: Report IRQ i...
194
  	int ret = 1;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
195

46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
196
  	spin_lock(&ioapic->lock);
07dc7263b   Marcelo Tosatti   KVM: read apic->i...
197
  	old_irr = ioapic->irr;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
198
199
200
201
202
203
  	if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
  		entry = ioapic->redirtbl[irq];
  		level ^= entry.fields.polarity;
  		if (!level)
  			ioapic->irr &= ~mask;
  		else {
b4a2f5e72   Gleb Natapov   KVM: Avoid redeli...
204
  			int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
205
  			ioapic->irr |= mask;
b4a2f5e72   Gleb Natapov   KVM: Avoid redeli...
206
207
  			if ((edge && old_irr != ioapic->irr) ||
  			    (!edge && !entry.fields.remote_irr))
4925663a0   Gleb Natapov   KVM: Report IRQ i...
208
  				ret = ioapic_service(ioapic, irq);
65a822116   Gleb Natapov   KVM: Fix coalesce...
209
210
  			else
  				ret = 0; /* report coalesced interrupt */
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
211
  		}
1000ff8d8   Gleb Natapov   KVM: Add trace po...
212
  		trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
213
  	}
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
214
  	spin_unlock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
215

4925663a0   Gleb Natapov   KVM: Report IRQ i...
216
  	return ret;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
217
  }
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
218
219
  static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
  				     int trigger_mode)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
220
  {
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
221
222
223
224
  	int i;
  
  	for (i = 0; i < IOAPIC_NUM_PINS; i++) {
  		union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
225

eba0226bd   Gleb Natapov   KVM: Move IO APIC...
226
227
  		if (ent->fields.vector != vector)
  			continue;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
228

eba0226bd   Gleb Natapov   KVM: Move IO APIC...
229
230
231
232
233
234
235
236
  		/*
  		 * We are dropping lock while calling ack notifiers because ack
  		 * notifier callbacks for assigned devices call into IOAPIC
  		 * recursively. Since remote_irr is cleared only after call
  		 * to notifiers if the same vector will be delivered while lock
  		 * is dropped it will be put into irr and will be delivered
  		 * after ack notifier returns.
  		 */
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
237
  		spin_unlock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
238
  		kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
239
  		spin_lock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
240
241
242
  
  		if (trigger_mode != IOAPIC_LEVEL_TRIG)
  			continue;
f52447261   Marcelo Tosatti   KVM: irq ack noti...
243

f52447261   Marcelo Tosatti   KVM: irq ack noti...
244
245
  		ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
  		ent->fields.remote_irr = 0;
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
246
247
  		if (!ent->fields.mask && (ioapic->irr & (1 << i)))
  			ioapic_service(ioapic, i);
f52447261   Marcelo Tosatti   KVM: irq ack noti...
248
  	}
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
249
  }
f52447261   Marcelo Tosatti   KVM: irq ack noti...
250
  void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
4fa6b9c5d   Avi Kivity   KVM: ioapic: fix ...
251
252
  {
  	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
4fa6b9c5d   Avi Kivity   KVM: ioapic: fix ...
253

46a929bc1   Avi Kivity   KVM: avoid taking...
254
255
256
  	smp_rmb();
  	if (!test_bit(vector, ioapic->handled_vectors))
  		return;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
257
  	spin_lock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
258
  	__kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
259
  	spin_unlock(&ioapic->lock);
4fa6b9c5d   Avi Kivity   KVM: ioapic: fix ...
260
  }
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
261
262
263
264
  static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
  {
  	return container_of(dev, struct kvm_ioapic, dev);
  }
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
265
  static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
266
  {
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
267
268
269
  	return ((addr >= ioapic->base_address &&
  		 (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
  }
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
270
271
  static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
  			    void *val)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
272
  {
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
273
  	struct kvm_ioapic *ioapic = to_ioapic(this);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
274
  	u32 result;
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
275
276
  	if (!ioapic_in_range(ioapic, addr))
  		return -EOPNOTSUPP;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
277

e25e3ed56   Laurent Vivier   KVM: Add some \n ...
278
279
  	ioapic_debug("addr %lx
  ", (unsigned long)addr);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
280
281
282
  	ASSERT(!(addr & 0xf));	/* check alignment */
  
  	addr &= 0xff;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
283
  	spin_lock(&ioapic->lock);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
284
285
286
287
288
289
290
291
292
293
294
295
296
  	switch (addr) {
  	case IOAPIC_REG_SELECT:
  		result = ioapic->ioregsel;
  		break;
  
  	case IOAPIC_REG_WINDOW:
  		result = ioapic_read_indirect(ioapic, addr, len);
  		break;
  
  	default:
  		result = 0;
  		break;
  	}
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
297
  	spin_unlock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
298

1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
299
300
301
302
303
304
305
306
307
308
309
310
311
  	switch (len) {
  	case 8:
  		*(u64 *) val = result;
  		break;
  	case 1:
  	case 2:
  	case 4:
  		memcpy(val, (char *)&result, len);
  		break;
  	default:
  		printk(KERN_WARNING "ioapic: wrong length %d
  ", len);
  	}
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
312
  	return 0;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
313
  }
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
314
315
  static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
  			     const void *val)
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
316
  {
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
317
  	struct kvm_ioapic *ioapic = to_ioapic(this);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
318
  	u32 data;
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
319
320
  	if (!ioapic_in_range(ioapic, addr))
  		return -EOPNOTSUPP;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
321

e25e3ed56   Laurent Vivier   KVM: Add some \n ...
322
323
324
  	ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p
  ",
  		     (void*)addr, len, val);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
325
  	ASSERT(!(addr & 0xf));	/* check alignment */
60eead79a   Marcelo Tosatti   KVM: introduce ir...
326

d77fe6354   Julian Stecklina   KVM: Allow aligne...
327
328
329
  	switch (len) {
  	case 8:
  	case 4:
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
330
  		data = *(u32 *) val;
d77fe6354   Julian Stecklina   KVM: Allow aligne...
331
332
333
334
335
336
337
338
  		break;
  	case 2:
  		data = *(u16 *) val;
  		break;
  	case 1:
  		data = *(u8  *) val;
  		break;
  	default:
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
339
340
  		printk(KERN_WARNING "ioapic: Unsupported size %d
  ", len);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
341
  		return 0;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
342
343
344
  	}
  
  	addr &= 0xff;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
345
  	spin_lock(&ioapic->lock);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
346
347
  	switch (addr) {
  	case IOAPIC_REG_SELECT:
d77fe6354   Julian Stecklina   KVM: Allow aligne...
348
  		ioapic->ioregsel = data & 0xFF; /* 8-bit register */
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
349
350
351
352
353
  		break;
  
  	case IOAPIC_REG_WINDOW:
  		ioapic_write_indirect(ioapic, data);
  		break;
b1fd3d30b   Zhang Xiantao   KVM: Extend ioapi...
354
355
  #ifdef	CONFIG_IA64
  	case IOAPIC_REG_EOI:
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
356
  		__kvm_ioapic_update_eoi(ioapic, data, IOAPIC_LEVEL_TRIG);
b1fd3d30b   Zhang Xiantao   KVM: Extend ioapi...
357
358
  		break;
  #endif
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
359
360
361
362
  
  	default:
  		break;
  	}
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
363
  	spin_unlock(&ioapic->lock);
bda9020e2   Michael S. Tsirkin   KVM: remove in_ra...
364
  	return 0;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
365
  }
8c392696e   Eddie Dong   KVM: Split IOAPIC...
366
367
368
369
370
371
372
373
374
375
  void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
  {
  	int i;
  
  	for (i = 0; i < IOAPIC_NUM_PINS; i++)
  		ioapic->redirtbl[i].fields.mask = 1;
  	ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
  	ioapic->ioregsel = 0;
  	ioapic->irr = 0;
  	ioapic->id = 0;
46a929bc1   Avi Kivity   KVM: avoid taking...
376
  	update_handled_vectors(ioapic);
8c392696e   Eddie Dong   KVM: Split IOAPIC...
377
  }
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
378
379
380
  static const struct kvm_io_device_ops ioapic_mmio_ops = {
  	.read     = ioapic_mmio_read,
  	.write    = ioapic_mmio_write,
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
381
  };
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
382
383
384
  int kvm_ioapic_init(struct kvm *kvm)
  {
  	struct kvm_ioapic *ioapic;
090b7aff2   Gregory Haskins   KVM: make io_bus ...
385
  	int ret;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
386
387
388
389
  
  	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
  	if (!ioapic)
  		return -ENOMEM;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
390
  	spin_lock_init(&ioapic->lock);
d7deeeb02   Zhang Xiantao   KVM: Portability:...
391
  	kvm->arch.vioapic = ioapic;
8c392696e   Eddie Dong   KVM: Split IOAPIC...
392
  	kvm_ioapic_reset(ioapic);
d76685c4a   Gregory Haskins   KVM: cleanup io_d...
393
  	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
394
  	ioapic->kvm = kvm;
79fac95ec   Marcelo Tosatti   KVM: convert slot...
395
  	mutex_lock(&kvm->slots_lock);
743eeb0b0   Sasha Levin   KVM: Intelligent ...
396
397
  	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
  				      IOAPIC_MEM_LENGTH, &ioapic->dev);
79fac95ec   Marcelo Tosatti   KVM: convert slot...
398
  	mutex_unlock(&kvm->slots_lock);
1ae77badc   Wei Yongjun   KVM: kvm->arch.vi...
399
400
  	if (ret < 0) {
  		kvm->arch.vioapic = NULL;
090b7aff2   Gregory Haskins   KVM: make io_bus ...
401
  		kfree(ioapic);
1ae77badc   Wei Yongjun   KVM: kvm->arch.vi...
402
  	}
090b7aff2   Gregory Haskins   KVM: make io_bus ...
403
404
  
  	return ret;
1fd4f2a5e   Eddie Dong   KVM: In-kernel I/...
405
  }
75858a84a   Avi Kivity   KVM: Interrupt ma...
406

72bb2fcd2   Wei Yongjun   KVM: cleanup the ...
407
408
409
410
411
412
413
414
415
416
  void kvm_ioapic_destroy(struct kvm *kvm)
  {
  	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
  
  	if (ioapic) {
  		kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
  		kvm->arch.vioapic = NULL;
  		kfree(ioapic);
  	}
  }
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
417
418
419
420
421
  int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
  {
  	struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
  	if (!ioapic)
  		return -EINVAL;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
422
  	spin_lock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
423
  	memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
424
  	spin_unlock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
425
426
427
428
429
430
431
432
  	return 0;
  }
  
  int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
  {
  	struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
  	if (!ioapic)
  		return -EINVAL;
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
433
  	spin_lock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
434
  	memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
46a929bc1   Avi Kivity   KVM: avoid taking...
435
  	update_handled_vectors(ioapic);
46a47b1ed   Marcelo Tosatti   KVM: convert ioap...
436
  	spin_unlock(&ioapic->lock);
eba0226bd   Gleb Natapov   KVM: Move IO APIC...
437
438
  	return 0;
  }