162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __KVM_IO_APIC_H
362306a36Sopenharmony_ci#define __KVM_IO_APIC_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/kvm_host.h>
662306a36Sopenharmony_ci#include <kvm/iodev.h>
762306a36Sopenharmony_ci#include "irq.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistruct kvm;
1062306a36Sopenharmony_cistruct kvm_vcpu;
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
1362306a36Sopenharmony_ci#define MAX_NR_RESERVED_IOAPIC_PINS KVM_MAX_IRQ_ROUTES
1462306a36Sopenharmony_ci#define IOAPIC_VERSION_ID 0x11	/* IOAPIC version */
1562306a36Sopenharmony_ci#define IOAPIC_EDGE_TRIG  0
1662306a36Sopenharmony_ci#define IOAPIC_LEVEL_TRIG 1
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000
1962306a36Sopenharmony_ci#define IOAPIC_MEM_LENGTH            0x100
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Direct registers. */
2262306a36Sopenharmony_ci#define IOAPIC_REG_SELECT  0x00
2362306a36Sopenharmony_ci#define IOAPIC_REG_WINDOW  0x10
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Indirect registers. */
2662306a36Sopenharmony_ci#define IOAPIC_REG_APIC_ID 0x00	/* x86 IOAPIC only */
2762306a36Sopenharmony_ci#define IOAPIC_REG_VERSION 0x01
2862306a36Sopenharmony_ci#define IOAPIC_REG_ARB_ID  0x02	/* x86 IOAPIC only */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*ioapic delivery mode*/
3162306a36Sopenharmony_ci#define	IOAPIC_FIXED			0x0
3262306a36Sopenharmony_ci#define	IOAPIC_LOWEST_PRIORITY		0x1
3362306a36Sopenharmony_ci#define	IOAPIC_PMI			0x2
3462306a36Sopenharmony_ci#define	IOAPIC_NMI			0x4
3562306a36Sopenharmony_ci#define	IOAPIC_INIT			0x5
3662306a36Sopenharmony_ci#define	IOAPIC_EXTINT			0x7
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define RTC_GSI 8
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct dest_map {
4162306a36Sopenharmony_ci	/* vcpu bitmap where IRQ has been sent */
4262306a36Sopenharmony_ci	DECLARE_BITMAP(map, KVM_MAX_VCPU_IDS);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Vector sent to a given vcpu, only valid when
4662306a36Sopenharmony_ci	 * the vcpu's bit in map is set
4762306a36Sopenharmony_ci	 */
4862306a36Sopenharmony_ci	u8 vectors[KVM_MAX_VCPU_IDS];
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct rtc_status {
5362306a36Sopenharmony_ci	int pending_eoi;
5462306a36Sopenharmony_ci	struct dest_map dest_map;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciunion kvm_ioapic_redirect_entry {
5862306a36Sopenharmony_ci	u64 bits;
5962306a36Sopenharmony_ci	struct {
6062306a36Sopenharmony_ci		u8 vector;
6162306a36Sopenharmony_ci		u8 delivery_mode:3;
6262306a36Sopenharmony_ci		u8 dest_mode:1;
6362306a36Sopenharmony_ci		u8 delivery_status:1;
6462306a36Sopenharmony_ci		u8 polarity:1;
6562306a36Sopenharmony_ci		u8 remote_irr:1;
6662306a36Sopenharmony_ci		u8 trig_mode:1;
6762306a36Sopenharmony_ci		u8 mask:1;
6862306a36Sopenharmony_ci		u8 reserve:7;
6962306a36Sopenharmony_ci		u8 reserved[4];
7062306a36Sopenharmony_ci		u8 dest_id;
7162306a36Sopenharmony_ci	} fields;
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct kvm_ioapic {
7562306a36Sopenharmony_ci	u64 base_address;
7662306a36Sopenharmony_ci	u32 ioregsel;
7762306a36Sopenharmony_ci	u32 id;
7862306a36Sopenharmony_ci	u32 irr;
7962306a36Sopenharmony_ci	u32 pad;
8062306a36Sopenharmony_ci	union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
8162306a36Sopenharmony_ci	unsigned long irq_states[IOAPIC_NUM_PINS];
8262306a36Sopenharmony_ci	struct kvm_io_device dev;
8362306a36Sopenharmony_ci	struct kvm *kvm;
8462306a36Sopenharmony_ci	spinlock_t lock;
8562306a36Sopenharmony_ci	struct rtc_status rtc_status;
8662306a36Sopenharmony_ci	struct delayed_work eoi_inject;
8762306a36Sopenharmony_ci	u32 irq_eoi[IOAPIC_NUM_PINS];
8862306a36Sopenharmony_ci	u32 irr_delivered;
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#ifdef DEBUG
9262306a36Sopenharmony_ci#define ASSERT(x)  							\
9362306a36Sopenharmony_cido {									\
9462306a36Sopenharmony_ci	if (!(x)) {							\
9562306a36Sopenharmony_ci		printk(KERN_EMERG "assertion failed %s: %d: %s\n",	\
9662306a36Sopenharmony_ci		       __FILE__, __LINE__, #x);				\
9762306a36Sopenharmony_ci		BUG();							\
9862306a36Sopenharmony_ci	}								\
9962306a36Sopenharmony_ci} while (0)
10062306a36Sopenharmony_ci#else
10162306a36Sopenharmony_ci#define ASSERT(x) do { } while (0)
10262306a36Sopenharmony_ci#endif
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic inline int ioapic_in_kernel(struct kvm *kvm)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return irqchip_kernel(kvm);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_civoid kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu);
11062306a36Sopenharmony_civoid kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector,
11162306a36Sopenharmony_ci			int trigger_mode);
11262306a36Sopenharmony_ciint kvm_ioapic_init(struct kvm *kvm);
11362306a36Sopenharmony_civoid kvm_ioapic_destroy(struct kvm *kvm);
11462306a36Sopenharmony_ciint kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
11562306a36Sopenharmony_ci		       int level, bool line_status);
11662306a36Sopenharmony_civoid kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id);
11762306a36Sopenharmony_civoid kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
11862306a36Sopenharmony_civoid kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
11962306a36Sopenharmony_civoid kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu,
12062306a36Sopenharmony_ci			   ulong *ioapic_handled_vectors);
12162306a36Sopenharmony_civoid kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
12262306a36Sopenharmony_ci			    ulong *ioapic_handled_vectors);
12362306a36Sopenharmony_ci#endif
124