18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef __LS7A_KVM_IRQ_H
78c2ecf20Sopenharmony_ci#define __LS7A_KVM_IRQ_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/mm_types.h>
108c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
118c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
128c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
138c2ecf20Sopenharmony_ci#include <loongson.h>
148c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
158c2ecf20Sopenharmony_ci#include "kvmcpu.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <kvm/iodev.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define LS7A_APIC_NUM_PINS	64
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define LS7A_ROUTE_ENTRY_OFFSET	0x100
228c2ecf20Sopenharmony_ci#define LS7A_INT_ID_OFFSET	0x0
238c2ecf20Sopenharmony_ci#define LS7A_INT_ID_VAL		0x7000000UL
248c2ecf20Sopenharmony_ci#define LS7A_INT_ID_VER		0x1f0001UL
258c2ecf20Sopenharmony_ci#define LS7A_INT_MASK_OFFSET	0x20
268c2ecf20Sopenharmony_ci#define LS7A_INT_EDGE_OFFSET	0x60
278c2ecf20Sopenharmony_ci#define LS7A_INT_CLEAR_OFFSET	0x80
288c2ecf20Sopenharmony_ci#define LS7A_INT_STATUS_OFFSET	0x3a0
298c2ecf20Sopenharmony_ci#define LS7A_INT_POL_OFFSET	0x3e0
308c2ecf20Sopenharmony_ci#define LS7A_HTMSI_EN_OFFSET	0x40
318c2ecf20Sopenharmony_ci#define LS7A_HTMSI_VEC_OFFSET	0x200
328c2ecf20Sopenharmony_ci#define LS7A_AUTO_CTRL0_OFFSET	0xc0
338c2ecf20Sopenharmony_ci#define LS7A_AUTO_CTRL1_OFFSET	0xe0
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define LS7A_IOAPIC_GUEST_REG_BASE		0x10000000UL
368c2ecf20Sopenharmony_ci#define LS7A_IOAPIC_GUEST_REG_BASE_ALIAS	0xe0010000000UL
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define LS7A_IOAPIC_NUM_PINS			32
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_citypedef struct kvm_ls7a_ioapic_state {
418c2ecf20Sopenharmony_ci	u64 int_id;
428c2ecf20Sopenharmony_ci	/* 0x020 interrupt mask register */
438c2ecf20Sopenharmony_ci	u64 int_mask;
448c2ecf20Sopenharmony_ci	/* 0x040 1=msi */
458c2ecf20Sopenharmony_ci	u64 htmsi_en;
468c2ecf20Sopenharmony_ci	/* 0x060 edge=1 level  =0 */
478c2ecf20Sopenharmony_ci	u64 intedge;
488c2ecf20Sopenharmony_ci	/* 0x080 for clean edge int,set 1 clean,set 0 is noused */
498c2ecf20Sopenharmony_ci	u64 intclr;
508c2ecf20Sopenharmony_ci	/* 0x0c0 */
518c2ecf20Sopenharmony_ci	u64 auto_crtl0;
528c2ecf20Sopenharmony_ci	/* 0x0e0 */
538c2ecf20Sopenharmony_ci	u64 auto_crtl1;
548c2ecf20Sopenharmony_ci	/* 0x100 - 0x140 */
558c2ecf20Sopenharmony_ci	u8 route_entry[64];
568c2ecf20Sopenharmony_ci	/* 0x200 - 0x240 */
578c2ecf20Sopenharmony_ci	u8 htmsi_vector[64];
588c2ecf20Sopenharmony_ci	/* 0x300 */
598c2ecf20Sopenharmony_ci	u64 intisr_chip0;
608c2ecf20Sopenharmony_ci	/* 0x320 */
618c2ecf20Sopenharmony_ci	u64 intisr_chip1;
628c2ecf20Sopenharmony_ci	/* edge detection */
638c2ecf20Sopenharmony_ci	u64 last_intirr;
648c2ecf20Sopenharmony_ci	/* 0x380 interrupt request register */
658c2ecf20Sopenharmony_ci	u64 intirr;
668c2ecf20Sopenharmony_ci	/* 0x3a0 interrupt service register */
678c2ecf20Sopenharmony_ci	u64 intisr;
688c2ecf20Sopenharmony_ci	/* 0x3e0 interrupt level polarity selection register,
698c2ecf20Sopenharmony_ci	 * 0 for high level tirgger
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	u64 int_polarity;
728c2ecf20Sopenharmony_ci} LS7AApicState;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistruct ls7a_kvm_ioapic {
758c2ecf20Sopenharmony_ci	spinlock_t lock;
768c2ecf20Sopenharmony_ci	bool wakeup_needed;
778c2ecf20Sopenharmony_ci	unsigned pending_acks;
788c2ecf20Sopenharmony_ci	struct kvm *kvm;
798c2ecf20Sopenharmony_ci	struct kvm_ls7a_ioapic_state ls7a_ioapic;
808c2ecf20Sopenharmony_ci	struct kvm_io_device dev_ls7a_ioapic;
818c2ecf20Sopenharmony_ci	struct kvm_io_device ls7a_ioapic_alias;
828c2ecf20Sopenharmony_ci	void (*ack_notifier)(void *opaque, int irq);
838c2ecf20Sopenharmony_ci	unsigned long irq_states[LS7A_APIC_NUM_PINS];
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline struct ls7a_kvm_ioapic *ls7a_ioapic_irqchip(struct kvm *kvm)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	return kvm->arch.v_ioapic;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic inline int ls7a_ioapic_in_kernel(struct kvm *kvm)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	int ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = (ls7a_ioapic_irqchip(kvm) != NULL);
968c2ecf20Sopenharmony_ci	return ret;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint kvm_set_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state);
1008c2ecf20Sopenharmony_ciint kvm_get_ls7a_ioapic(struct kvm *kvm, struct ls7a_ioapic_state *state);
1018c2ecf20Sopenharmony_ciint kvm_create_ls7a_ioapic(struct kvm *kvm);
1028c2ecf20Sopenharmony_civoid kvm_destroy_ls7a_ioapic(struct kvm *kvm);
1038c2ecf20Sopenharmony_ciint kvm_ls7a_ioapic_set_irq(struct kvm *kvm, int irq, int level);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_civoid ls7a_ioapic_lock(struct ls7a_kvm_ioapic *s, unsigned long *flags);
1068c2ecf20Sopenharmony_civoid ls7a_ioapic_unlock(struct ls7a_kvm_ioapic *s, unsigned long *flags);
1078c2ecf20Sopenharmony_ciint kvm_ls7a_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
1088c2ecf20Sopenharmony_ciint kvm_ls7a_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
1098c2ecf20Sopenharmony_ci					int irq_source_id, int level, bool line_status);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_civoid kvm_dump_ls7a_ioapic_state(struct seq_file *m, struct ls7a_kvm_ioapic *ioapic);
1128c2ecf20Sopenharmony_ci#endif
113