1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4  */
5 
6 #include <linux/highmem.h>
7 #include <linux/mm.h>
8 #include <linux/bitops.h>
9 #include "ls3a_ipi.h"
10 #include "ls7a_irq.h"
11 #include "ls3a_ext_irq.h"
12 
ls7a_ioapic_lock(struct ls7a_kvm_ioapic *s, unsigned long *flags)13 void ls7a_ioapic_lock(struct ls7a_kvm_ioapic *s, unsigned long *flags)
14 {
15 	unsigned long tmp;
16 	spin_lock_irqsave(&s->lock, tmp);
17 	*flags = tmp;
18 }
19 
ls7a_ioapic_unlock(struct ls7a_kvm_ioapic *s, unsigned long *flags)20 void ls7a_ioapic_unlock(struct ls7a_kvm_ioapic *s, unsigned long *flags)
21 {
22 	unsigned long tmp;
23 	tmp = *flags;
24 	spin_unlock_irqrestore(&s->lock, tmp);
25 }
26 
kvm_ls7a_ioapic_raise(struct kvm *kvm, unsigned long mask)27 static void kvm_ls7a_ioapic_raise(struct kvm *kvm, unsigned long mask)
28 {
29 	unsigned long irqnum, val;
30 	struct ls7a_kvm_ioapic *s = ls7a_ioapic_irqchip(kvm);
31 	struct kvm_ls7a_ioapic_state *state;
32 	struct kvm_loongarch_interrupt irq;
33 	int i;
34 
35 	state = &s->ls7a_ioapic;
36 	irq.cpu = -1;
37 	val = mask & state->intirr & (~state->int_mask);
38 	val &= ~state->intisr;
39 	for_each_set_bit(i, &val, 64) {
40 		state->intisr |= 0x1ULL << i;
41 		irqnum = state->htmsi_vector[i];
42 		kvm_debug("msi_irq_handler,%ld,up\n", irqnum);
43 		msi_irq_handler(kvm, irqnum, 1);
44 	}
45 
46 	kvm->stat.ls7a_ioapic_update++;
47 }
48 
kvm_ls7a_ioapic_lower(struct kvm *kvm, unsigned long mask)49 static void kvm_ls7a_ioapic_lower(struct kvm *kvm, unsigned long mask)
50 {
51 	unsigned long irqnum, val;
52 	struct ls7a_kvm_ioapic *s = ls7a_ioapic_irqchip(kvm);
53 	struct kvm_ls7a_ioapic_state *state;
54 	struct kvm_loongarch_interrupt irq;
55 	int i;
56 
57 	state = &s->ls7a_ioapic;
58 	irq.cpu = -1;
59 	val = mask & state->intisr;
60 	for_each_set_bit(i, &val, 64) {
61 		state->intisr &= ~(0x1ULL << i);
62 		irqnum = state->htmsi_vector[i];
63 		kvm_debug("msi_irq_handler,%ld,down\n", irqnum);
64 		msi_irq_handler(kvm, irqnum, 0);
65 	}
66 
67 	kvm->stat.ls7a_ioapic_update++;
68 }
69 
kvm_ls7a_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq_source_id, int level, bool line_status)70 int kvm_ls7a_set_msi(struct kvm_kernel_irq_routing_entry *e,
71 		struct kvm *kvm, int irq_source_id, int level, bool line_status)
72 {
73 	if (!level)
74 		return -1;
75 
76 	kvm_debug("msi data is 0x%x\n", e->msi.data);
77 	msi_irq_handler(kvm, e->msi.data, 1);
78 	return 0;
79 }
80 
kvm_ls7a_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)81 int kvm_ls7a_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
82 {
83 	struct kvm_kernel_irq_routing_entry route;
84 
85 	if (msi->flags != 0)
86 		return -EINVAL;
87 
88 	kvm->stat.ls7a_msi_irq++;
89 	route.msi.address_lo = msi->address_lo;
90 	route.msi.address_hi = msi->address_hi;
91 	route.msi.data = msi->data;
92 
93 	kvm_debug("msi data is 0x%x\n", route.msi.data);
94 	return kvm_ls7a_set_msi(&route, kvm,
95 				KVM_USERSPACE_IRQ_SOURCE_ID, 1, false);
96 
97 }
98 
kvm_ls7a_ioapic_set_irq(struct kvm *kvm, int irq, int level)99 int kvm_ls7a_ioapic_set_irq(struct kvm *kvm, int irq, int level)
100 {
101 	struct ls7a_kvm_ioapic *s;
102 	struct kvm_ls7a_ioapic_state *state;
103 	uint64_t mask = 1ULL << irq;
104 	s = ls7a_ioapic_irqchip(kvm);
105 	state = &s->ls7a_ioapic;
106 	BUG_ON(irq < 0 || irq >= LS7A_IOAPIC_NUM_PINS);
107 
108 	if (state->intedge & mask) {
109 		/* edge triggered */
110 		if (level) {
111 			if ((state->last_intirr & mask) == 0) {
112 				state->intirr |= mask;
113 				kvm_ls7a_ioapic_raise(kvm, mask);
114 			}
115 			state->last_intirr |= mask;
116 		} else
117 			state->last_intirr &= ~mask;
118 	} else {
119 		/* level triggered */
120 		if (!!level) {
121 			if ((state->intirr & mask) == 0) {
122 				state->intirr |= mask;
123 				kvm_ls7a_ioapic_raise(kvm, mask);
124 			}
125 		} else {
126 			if (state->intirr & mask) {
127 				state->intirr &= ~mask;
128 				kvm_ls7a_ioapic_lower(kvm, mask);
129 			}
130 		}
131 	}
132 	kvm->stat.ls7a_ioapic_set_irq++;
133 	return 0;
134 }
135 
ls7a_ioapic_reg_write(struct ls7a_kvm_ioapic *s, gpa_t addr, int len, const void *val)136 static int ls7a_ioapic_reg_write(struct ls7a_kvm_ioapic *s,
137 			  gpa_t addr, int len, const void *val)
138 {
139 	struct kvm *kvm;
140 	struct kvm_ls7a_ioapic_state *state;
141 	int64_t offset_tmp;
142 	uint64_t offset;
143 	uint64_t old, himask, lowmask;
144 	unsigned long data, flags;
145 
146 	offset = addr & 0xfff;
147 	kvm = s->kvm;
148 	state = &(s->ls7a_ioapic);
149 	lowmask = 0xFFFFFFFFUL;
150 	himask = lowmask << 32;
151 
152 	if (offset & (len - 1)) {
153 		printk("%s(%d):unaligned address access %llx size %d \n",
154 			__FUNCTION__, __LINE__, addr, len);
155 		return 0;
156 	}
157 
158 	if (8 == len) {
159 		data = *(uint64_t *)val;
160 		switch (offset) {
161 		case LS7A_INT_MASK_OFFSET:
162 			old = state->int_mask;
163 			state->int_mask = data;
164 			if (old & ~data)
165 				kvm_ls7a_ioapic_raise(kvm, old & ~data);
166 			if (~old & data)
167 				kvm_ls7a_ioapic_lower(kvm, ~old & data);
168 			break;
169 		case LS7A_INT_STATUS_OFFSET:
170 			state->intisr = data;
171 			break;
172 		case LS7A_INT_EDGE_OFFSET:
173 			state->intedge = data;
174 			break;
175 		case LS7A_INT_CLEAR_OFFSET:
176 			/*
177 			 * For emulated device, only clear edge triggered irq
178 			 * on writing INTCLR reg no effect on level triggered
179 			 * irq
180 			 * However for pass-through device with level-triggered
181 			 * intx, here need clear interrupt
182 			 */
183 			old  = data;
184 			data = data & state->intedge;
185 			state->intirr &= ~data;
186 			kvm_ls7a_ioapic_lower(kvm, data);
187 			state->intisr &= ~data;
188 
189 			data = old & ~state->intedge;
190 			ls7a_ioapic_unlock(kvm->arch.v_ioapic, &flags);
191 			for_each_set_bit(offset_tmp, &data, 64)
192 				kvm_notify_acked_irq(kvm, 0, offset_tmp);
193 			ls7a_ioapic_lock(kvm->arch.v_ioapic, &flags);
194 			break;
195 		case LS7A_INT_POL_OFFSET:
196 			state->int_polarity = data;
197 			break;
198 		case LS7A_HTMSI_EN_OFFSET:
199 			state->htmsi_en = data;
200 			break;
201 		case LS7A_AUTO_CTRL0_OFFSET:
202 		case LS7A_AUTO_CTRL1_OFFSET:
203 			break;
204 		default:
205 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
206 			break;
207 		}
208 	} else if (4 == len) {
209 		data = *(uint32_t *)val;
210 		switch (offset) {
211 		case LS7A_INT_MASK_OFFSET:
212 			old = state->int_mask & lowmask;
213 			state->int_mask = (state->int_mask & himask) | data;
214 			if (old & ~data)
215 				kvm_ls7a_ioapic_raise(kvm, old & ~data);
216 			if (~old & data)
217 				kvm_ls7a_ioapic_lower(kvm, ~old & data);
218 			break;
219 		case LS7A_INT_MASK_OFFSET + 4:
220 			data = data << 32;
221 			old = state->int_mask & himask;
222 			state->int_mask = (state->int_mask & lowmask) | data;
223 			if (old & ~data)
224 				kvm_ls7a_ioapic_raise(kvm, old & ~data);
225 			if (~old & data)
226 				kvm_ls7a_ioapic_lower(kvm, ~old & data);
227 			break;
228 		case LS7A_INT_STATUS_OFFSET:
229 			state->intisr = (state->intisr & himask) | data;
230 			break;
231 		case LS7A_INT_STATUS_OFFSET + 4:
232 			data = data << 32;
233 			state->intisr = (state->intisr & lowmask) | data;
234 			break;
235 		case LS7A_INT_EDGE_OFFSET:
236 			state->intedge = (state->intedge & himask) | data;
237 			break;
238 		case LS7A_INT_EDGE_OFFSET + 4:
239 			data = data << 32;
240 			state->intedge = (state->intedge & lowmask) | data;
241 			break;
242 		case LS7A_INT_CLEAR_OFFSET + 4:
243 			data = data << 32;
244 			fallthrough;
245 		case LS7A_INT_CLEAR_OFFSET:
246 			old  = data;
247 			data = data & state->intedge;
248 			state->intirr &= ~data;
249 			kvm_ls7a_ioapic_lower(kvm, data);
250 			state->intisr &= ~data;
251 
252 			data = old & ~state->intedge;
253 			ls7a_ioapic_unlock(kvm->arch.v_ioapic, &flags);
254 			for_each_set_bit(offset_tmp, &data, 64)
255 				kvm_notify_acked_irq(kvm, 0, offset_tmp);
256 			ls7a_ioapic_lock(kvm->arch.v_ioapic, &flags);
257 			break;
258 		case LS7A_INT_POL_OFFSET:
259 			state->int_polarity = (state->int_polarity & himask) | data;
260 			break;
261 		case LS7A_INT_POL_OFFSET+4:
262 			data = data << 32;
263 			state->int_polarity = (state->int_polarity & lowmask) | data;
264 			break;
265 		case LS7A_HTMSI_EN_OFFSET:
266 			state->htmsi_en = (state->htmsi_en & himask) | data;
267 			break;
268 		case LS7A_HTMSI_EN_OFFSET+4:
269 			data = data << 32;
270 			state->htmsi_en = (state->htmsi_en & lowmask) | data;
271 			break;
272 		case LS7A_AUTO_CTRL0_OFFSET:
273 		case LS7A_AUTO_CTRL0_OFFSET+4:
274 		case LS7A_AUTO_CTRL1_OFFSET:
275 		case LS7A_AUTO_CTRL1_OFFSET+4:
276 			break;
277 		default:
278 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
279 			break;
280 		}
281 	} else if (1 == len) {
282 		data = *(unsigned char *)val;
283 		if (offset >= LS7A_HTMSI_VEC_OFFSET) {
284 			offset_tmp = offset - LS7A_HTMSI_VEC_OFFSET;
285 			if (offset_tmp >= 0 && offset_tmp < 64) {
286 				state->htmsi_vector[offset_tmp] =
287 					(uint8_t)(data & 0xff);
288 			}
289 		} else if (offset >=  LS7A_ROUTE_ENTRY_OFFSET) {
290 			offset_tmp = offset - LS7A_ROUTE_ENTRY_OFFSET;
291 			if (offset_tmp >= 0 && offset_tmp < 64) {
292 				state->route_entry[offset_tmp] =
293 					(uint8_t)(data & 0xff);
294 			}
295 		} else {
296 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
297 		}
298 	} else {
299 		WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
300 	}
301 	kvm->stat.ioapic_reg_write++;
302 	return 0;
303 }
304 
to_ioapic(struct kvm_io_device *dev)305 static inline struct ls7a_kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
306 {
307 	return container_of(dev, struct ls7a_kvm_ioapic, dev_ls7a_ioapic);
308 }
309 
kvm_ls7a_ioapic_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, int len, const void *val)310 static int kvm_ls7a_ioapic_write(struct kvm_vcpu *vcpu,
311 				 struct kvm_io_device *this,
312 				 gpa_t addr, int len, const void *val)
313 {
314 	struct ls7a_kvm_ioapic *s = to_ioapic(this);
315 	unsigned long flags;
316 
317 	ls7a_ioapic_lock(s->kvm->arch.v_ioapic, &flags);
318 	ls7a_ioapic_reg_write(s, addr, len, val);
319 	ls7a_ioapic_unlock(s->kvm->arch.v_ioapic, &flags);
320 
321 	return 0;
322 }
323 
ls7a_ioapic_reg_read(struct ls7a_kvm_ioapic *s, gpa_t addr, int len, void *val)324 static int ls7a_ioapic_reg_read(struct ls7a_kvm_ioapic *s,
325 		       gpa_t addr, int len, void *val)
326 {
327 	uint64_t offset, offset_tmp;
328 	struct kvm *kvm;
329 	struct kvm_ls7a_ioapic_state *state;
330 	uint64_t result = 0, lowmask, himask;
331 
332 	state = &(s->ls7a_ioapic);
333 	kvm = s->kvm;
334 	offset = addr & 0xfff;
335 	lowmask = 0xFFFFFFFFUL;
336 	himask = lowmask << 32;
337 	if (offset & (len - 1)) {
338 		printk("%s(%d):unaligned address access %llx size %d \n",
339 			__FUNCTION__, __LINE__, addr, len);
340 		return 0;
341 	}
342 
343 	if (8 == len) {
344 		switch (offset) {
345 		case LS7A_INT_MASK_OFFSET:
346 			result = state->int_mask;
347 			break;
348 		case LS7A_INT_STATUS_OFFSET:
349 			result = state->intisr & (~state->int_mask);
350 			break;
351 		case LS7A_INT_EDGE_OFFSET:
352 			result = state->intedge;
353 			break;
354 		case LS7A_INT_POL_OFFSET:
355 			result = state->int_polarity;
356 			break;
357 		case LS7A_HTMSI_EN_OFFSET:
358 			result = state->htmsi_en;
359 			break;
360 		case LS7A_AUTO_CTRL0_OFFSET:
361 		case LS7A_AUTO_CTRL1_OFFSET:
362 			break;
363 		case LS7A_INT_ID_OFFSET:
364 			result = LS7A_INT_ID_VER;
365 			result = (result << 32) + LS7A_INT_ID_VAL;
366 			break;
367 		default:
368 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
369 			break;
370 		}
371 		if (val != NULL)
372 			*(uint64_t *)val = result;
373 	} else if (4 == len) {
374 		switch (offset) {
375 		case LS7A_INT_MASK_OFFSET:
376 			result = state->int_mask & lowmask;
377 			break;
378 		case LS7A_INT_MASK_OFFSET + 4:
379 			result = state->int_mask & himask;
380 			result = result >> 32;
381 			break;
382 		case LS7A_INT_STATUS_OFFSET:
383 			result = state->intisr & (~state->int_mask) & lowmask;
384 			break;
385 		case LS7A_INT_STATUS_OFFSET + 4:
386 			result = state->intisr & (~state->int_mask) & himask;
387 			result = result >> 32;
388 			break;
389 		case LS7A_INT_EDGE_OFFSET:
390 			result = state->intedge & lowmask;
391 			break;
392 		case LS7A_INT_EDGE_OFFSET + 4:
393 			result = state->intedge & himask;
394 			result = result >> 32;
395 			break;
396 		case LS7A_INT_POL_OFFSET:
397 			result = state->int_polarity & lowmask;
398 			break;
399 		case LS7A_INT_POL_OFFSET + 4:
400 			result = state->int_polarity & himask;
401 			result = result >> 32;
402 			break;
403 		case LS7A_HTMSI_EN_OFFSET:
404 			result = state->htmsi_en & lowmask;
405 			break;
406 		case LS7A_HTMSI_EN_OFFSET + 4:
407 			result = state->htmsi_en & himask;
408 			result = result >> 32;
409 			break;
410 		case LS7A_AUTO_CTRL0_OFFSET:
411 		case LS7A_AUTO_CTRL0_OFFSET + 4:
412 		case LS7A_AUTO_CTRL1_OFFSET:
413 		case LS7A_AUTO_CTRL1_OFFSET + 4:
414 			break;
415 		case LS7A_INT_ID_OFFSET:
416 			result = LS7A_INT_ID_VAL;
417 			break;
418 		case LS7A_INT_ID_OFFSET + 4:
419 			result = LS7A_INT_ID_VER;
420 			break;
421 		default:
422 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
423 			break;
424 		}
425 		if (val != NULL)
426 			*(uint32_t *)val = result;
427 	} else if (1 == len) {
428 		if (offset >= LS7A_HTMSI_VEC_OFFSET) {
429 			offset_tmp = offset - LS7A_HTMSI_VEC_OFFSET;
430 			if (offset_tmp >= 0 && offset_tmp < 64) {
431 				result = state->htmsi_vector[offset_tmp];
432 			}
433 		} else if (offset >=  LS7A_ROUTE_ENTRY_OFFSET) {
434 			offset_tmp = offset - LS7A_ROUTE_ENTRY_OFFSET;
435 			if (offset_tmp >= 0 && offset_tmp < 64) {
436 				result = state->route_entry[offset_tmp];
437 			}
438 		} else {
439 			WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
440 		}
441 		if (val != NULL)
442 			*(unsigned char *)val = result;
443 	} else {
444 		WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
445 	}
446 	kvm->stat.ioapic_reg_read++;
447 	return result;
448 }
449 
kvm_ls7a_ioapic_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, int len, void *val)450 static int kvm_ls7a_ioapic_read(struct kvm_vcpu *vcpu,
451 				struct kvm_io_device *this,
452 				gpa_t addr, int len, void *val)
453 {
454 	struct ls7a_kvm_ioapic *s = to_ioapic(this);
455 	unsigned long flags;
456 	uint64_t result = 0;
457 
458 	ls7a_ioapic_lock(s->kvm->arch.v_ioapic, &flags);
459 	result = ls7a_ioapic_reg_read(s, addr, len, val);
460 	ls7a_ioapic_unlock(s->kvm->arch.v_ioapic, &flags);
461 	return 0;
462 }
463 
464 static const struct kvm_io_device_ops kvm_ls7a_ioapic_ops = {
465 	.read     = kvm_ls7a_ioapic_read,
466 	.write    = kvm_ls7a_ioapic_write,
467 };
468 
kvm_ls7a_ioapic_alias_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, int len, void *val)469 static int kvm_ls7a_ioapic_alias_read(struct kvm_vcpu *vcpu,
470 		struct kvm_io_device *this, gpa_t addr, int len, void *val)
471 {
472 	struct ls7a_kvm_ioapic *s;
473 	unsigned long flags;
474 
475 	s = container_of(this, struct ls7a_kvm_ioapic, ls7a_ioapic_alias);
476 	ls7a_ioapic_lock(s->kvm->arch.v_ioapic, &flags);
477 	ls7a_ioapic_reg_read(s, addr, len, val);
478 	ls7a_ioapic_unlock(s->kvm->arch.v_ioapic, &flags);
479 	return 0;
480 }
481 
kvm_ls7a_ioapic_alias_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr, int len, const void *val)482 static int kvm_ls7a_ioapic_alias_write(struct kvm_vcpu *vcpu,
483 		struct kvm_io_device *this, gpa_t addr, int len, const void *val)
484 {
485 	struct ls7a_kvm_ioapic *s;
486 	unsigned long flags;
487 
488 	s = container_of(this, struct ls7a_kvm_ioapic, ls7a_ioapic_alias);
489 	ls7a_ioapic_lock(s->kvm->arch.v_ioapic, &flags);
490 	ls7a_ioapic_reg_write(s, addr, len, val);
491 	ls7a_ioapic_unlock(s->kvm->arch.v_ioapic, &flags);
492 
493 	return 0;
494 }
495 
496 static const struct kvm_io_device_ops kvm_ls7a_ioapic_ops_alias = {
497 	.read     = kvm_ls7a_ioapic_alias_read,
498 	.write    = kvm_ls7a_ioapic_alias_write,
499 };
500 
kvm_create_ls7a_ioapic(struct kvm *kvm)501 int kvm_create_ls7a_ioapic(struct kvm *kvm)
502 {
503 	struct ls7a_kvm_ioapic *s;
504 	int ret;
505 	unsigned long ls7a_ioapic_reg_base;
506 
507 	s = kzalloc(sizeof(struct ls7a_kvm_ioapic), GFP_KERNEL);
508 	if (!s)
509 		return -ENOMEM;
510 	spin_lock_init(&s->lock);
511 	s->kvm = kvm;
512 
513 	ls7a_ioapic_reg_base = LS7A_IOAPIC_GUEST_REG_BASE;
514 
515 	/*
516 	 * Initialize MMIO device
517 	 */
518 	kvm_iodevice_init(&s->dev_ls7a_ioapic, &kvm_ls7a_ioapic_ops);
519 	mutex_lock(&kvm->slots_lock);
520 	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ls7a_ioapic_reg_base,
521 						   0x1000, &s->dev_ls7a_ioapic);
522 	if (ret < 0) {
523 		kvm_err("Failed register ioapic, err:%d\n", ret);
524 		goto fail_unlock;
525 	}
526 
527 	ls7a_ioapic_reg_base = LS7A_IOAPIC_GUEST_REG_BASE_ALIAS;
528 	kvm_iodevice_init(&s->ls7a_ioapic_alias, &kvm_ls7a_ioapic_ops_alias);
529 	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ls7a_ioapic_reg_base,
530 						0x1000, &s->ls7a_ioapic_alias);
531 	if (ret < 0) {
532 		kvm_err("Failed register alias ioapic, err:%d\n", ret);
533 		kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
534 				&s->dev_ls7a_ioapic);
535 		goto fail_unlock;
536 	}
537 	mutex_unlock(&kvm->slots_lock);
538 
539 	kvm->arch.v_ioapic = s;
540 
541 	return 0;
542 
543 fail_unlock:
544 	mutex_unlock(&kvm->slots_lock);
545 	kfree(s);
546 
547 	return -EFAULT;
548 }
549 
550 
kvm_get_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state)551 int kvm_get_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state)
552 {
553 	struct ls7a_kvm_ioapic *ls7a_ioapic = ls7a_ioapic_irqchip(kvm);
554 	struct kvm_ls7a_ioapic_state *ioapic_state =
555 					    &(ls7a_ioapic->ls7a_ioapic);
556 	unsigned long flags;
557 
558 	ls7a_ioapic_lock(ls7a_ioapic, &flags);
559 	memcpy(state, ioapic_state, sizeof(struct kvm_ls7a_ioapic_state));
560 	ls7a_ioapic_unlock(ls7a_ioapic, &flags);
561 	kvm->stat.get_ls7a_ioapic++;
562 	return 0;
563 }
564 
kvm_set_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state)565 int kvm_set_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state)
566 {
567 	struct ls7a_kvm_ioapic *ls7a_ioapic = ls7a_ioapic_irqchip(kvm);
568 	struct kvm_ls7a_ioapic_state *ioapic_state =
569 					    &(ls7a_ioapic->ls7a_ioapic);
570 	unsigned long flags;
571 
572 	if (!ls7a_ioapic)
573 		return -EINVAL;
574 
575 	ls7a_ioapic_lock(ls7a_ioapic, &flags);
576 	memcpy(ioapic_state, state, sizeof(struct kvm_ls7a_ioapic_state));
577 	ls7a_ioapic_unlock(ls7a_ioapic, &flags);
578 	kvm->stat.set_ls7a_ioapic++;
579 	return 0;
580 }
581 
kvm_destroy_ls7a_ioapic(struct kvm *kvm)582 void kvm_destroy_ls7a_ioapic(struct kvm *kvm)
583 {
584 	struct ls7a_kvm_ioapic *vpic = kvm->arch.v_ioapic;
585 	if (!vpic)
586 		return;
587 	mutex_lock(&kvm->slots_lock);
588 	kvm_io_bus_unregister_dev(vpic->kvm, KVM_MMIO_BUS,
589 					&vpic->ls7a_ioapic_alias);
590 	kvm_io_bus_unregister_dev(vpic->kvm, KVM_MMIO_BUS,
591 					&vpic->dev_ls7a_ioapic);
592 	mutex_unlock(&kvm->slots_lock);
593 	kfree(vpic);
594 }
595 
kvm_dump_ls7a_ioapic_state(struct seq_file *m, struct ls7a_kvm_ioapic *ioapic)596 void kvm_dump_ls7a_ioapic_state(struct seq_file *m,
597 		struct ls7a_kvm_ioapic *ioapic)
598 {
599 	struct kvm_ls7a_ioapic_state *ioapic_state;
600 	unsigned long flags;
601 	int i = 0;
602 
603 	if (!ioapic)
604 		return;
605 
606 	seq_puts(m, "\nIOAPIC state:\n");
607 	ioapic_state = &(ioapic->ls7a_ioapic);
608 
609 	ls7a_ioapic_lock(ioapic, &flags);
610 	seq_puts(m, "irq masked: ");
611 	for (i = 0; i < 64; i++) {
612 		if (!test_bit(i, (void *)&ioapic_state->int_mask))
613 			seq_printf(m, "%d ", i);
614 	}
615 	seq_printf(m, "\nhtmsi_en:0x%016llx\n"
616 			"intedge:0x%016llx",
617 			ioapic_state->htmsi_en,
618 			ioapic_state->intedge);
619 
620 	seq_puts(m, "\nroute_entry: ");
621 	for (i = 0; i < 64; i++)
622 		seq_printf(m, "%d ", ioapic_state->route_entry[i]);
623 
624 	seq_puts(m, "\nhtmsi_vector: ");
625 	for (i = 0; i < 64; i++)
626 		seq_printf(m, "%d ", ioapic_state->htmsi_vector[i]);
627 
628 	seq_printf(m, "\nintirr:%016llx\n"
629 			"intisr:%016llx\n",
630 			ioapic_state->intirr,
631 			ioapic_state->intisr);
632 	ls7a_ioapic_unlock(ioapic, &flags);
633 }
634