162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * irq.h: in kernel interrupt controller related definitions
462306a36Sopenharmony_ci * Copyright (c) 2007, Intel Corporation.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Authors:
762306a36Sopenharmony_ci *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef __IRQ_H
1162306a36Sopenharmony_ci#define __IRQ_H
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/mm_types.h>
1462306a36Sopenharmony_ci#include <linux/hrtimer.h>
1562306a36Sopenharmony_ci#include <linux/kvm_host.h>
1662306a36Sopenharmony_ci#include <linux/spinlock.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <kvm/iodev.h>
1962306a36Sopenharmony_ci#include "lapic.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define PIC_NUM_PINS 16
2262306a36Sopenharmony_ci#define SELECT_PIC(irq) \
2362306a36Sopenharmony_ci	((irq) < 8 ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct kvm;
2662306a36Sopenharmony_cistruct kvm_vcpu;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct kvm_kpic_state {
2962306a36Sopenharmony_ci	u8 last_irr;	/* edge detection */
3062306a36Sopenharmony_ci	u8 irr;		/* interrupt request register */
3162306a36Sopenharmony_ci	u8 imr;		/* interrupt mask register */
3262306a36Sopenharmony_ci	u8 isr;		/* interrupt service register */
3362306a36Sopenharmony_ci	u8 priority_add;	/* highest irq priority */
3462306a36Sopenharmony_ci	u8 irq_base;
3562306a36Sopenharmony_ci	u8 read_reg_select;
3662306a36Sopenharmony_ci	u8 poll;
3762306a36Sopenharmony_ci	u8 special_mask;
3862306a36Sopenharmony_ci	u8 init_state;
3962306a36Sopenharmony_ci	u8 auto_eoi;
4062306a36Sopenharmony_ci	u8 rotate_on_auto_eoi;
4162306a36Sopenharmony_ci	u8 special_fully_nested_mode;
4262306a36Sopenharmony_ci	u8 init4;		/* true if 4 byte init */
4362306a36Sopenharmony_ci	u8 elcr;		/* PIIX edge/trigger selection */
4462306a36Sopenharmony_ci	u8 elcr_mask;
4562306a36Sopenharmony_ci	u8 isr_ack;	/* interrupt ack detection */
4662306a36Sopenharmony_ci	struct kvm_pic *pics_state;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct kvm_pic {
5062306a36Sopenharmony_ci	spinlock_t lock;
5162306a36Sopenharmony_ci	bool wakeup_needed;
5262306a36Sopenharmony_ci	unsigned pending_acks;
5362306a36Sopenharmony_ci	struct kvm *kvm;
5462306a36Sopenharmony_ci	struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
5562306a36Sopenharmony_ci	int output;		/* intr from master PIC */
5662306a36Sopenharmony_ci	struct kvm_io_device dev_master;
5762306a36Sopenharmony_ci	struct kvm_io_device dev_slave;
5862306a36Sopenharmony_ci	struct kvm_io_device dev_elcr;
5962306a36Sopenharmony_ci	unsigned long irq_states[PIC_NUM_PINS];
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciint kvm_pic_init(struct kvm *kvm);
6362306a36Sopenharmony_civoid kvm_pic_destroy(struct kvm *kvm);
6462306a36Sopenharmony_ciint kvm_pic_read_irq(struct kvm *kvm);
6562306a36Sopenharmony_civoid kvm_pic_update_irq(struct kvm_pic *s);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic inline int irqchip_split(struct kvm *kvm)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int mode = kvm->arch.irqchip_mode;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Matches smp_wmb() when setting irqchip_mode */
7262306a36Sopenharmony_ci	smp_rmb();
7362306a36Sopenharmony_ci	return mode == KVM_IRQCHIP_SPLIT;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic inline int irqchip_kernel(struct kvm *kvm)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	int mode = kvm->arch.irqchip_mode;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Matches smp_wmb() when setting irqchip_mode */
8162306a36Sopenharmony_ci	smp_rmb();
8262306a36Sopenharmony_ci	return mode == KVM_IRQCHIP_KERNEL;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic inline int pic_in_kernel(struct kvm *kvm)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return irqchip_kernel(kvm);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline int irqchip_in_kernel(struct kvm *kvm)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int mode = kvm->arch.irqchip_mode;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Matches smp_wmb() when setting irqchip_mode */
9562306a36Sopenharmony_ci	smp_rmb();
9662306a36Sopenharmony_ci	return mode != KVM_IRQCHIP_NONE;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
10062306a36Sopenharmony_civoid kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
10162306a36Sopenharmony_civoid kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
10262306a36Sopenharmony_civoid __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
10362306a36Sopenharmony_civoid __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu);
10462306a36Sopenharmony_civoid __kvm_migrate_timers(struct kvm_vcpu *vcpu);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciint apic_has_pending_timer(struct kvm_vcpu *vcpu);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint kvm_setup_default_irq_routing(struct kvm *kvm);
10962306a36Sopenharmony_ciint kvm_setup_empty_irq_routing(struct kvm *kvm);
11062306a36Sopenharmony_ciint kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
11162306a36Sopenharmony_ci			     struct kvm_lapic_irq *irq,
11262306a36Sopenharmony_ci			     struct dest_map *dest_map);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#endif
115