]>
Commit | Line | Data |
---|---|---|
bc5ad3f3 BH |
1 | /* |
2 | * Copyright 2012 Michael Ellerman, IBM Corporation. | |
3 | * Copyright 2012 Benjamin Herrenschmidt, IBM Corporation | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License, version 2, as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | #ifndef _KVM_PPC_BOOK3S_XICS_H | |
11 | #define _KVM_PPC_BOOK3S_XICS_H | |
12 | ||
5af50993 | 13 | #ifdef CONFIG_KVM_XICS |
bc5ad3f3 BH |
14 | /* |
15 | * We use a two-level tree to store interrupt source information. | |
16 | * There are up to 1024 ICS nodes, each of which can represent | |
17 | * 1024 sources. | |
18 | */ | |
19 | #define KVMPPC_XICS_MAX_ICS_ID 1023 | |
20 | #define KVMPPC_XICS_ICS_SHIFT 10 | |
21 | #define KVMPPC_XICS_IRQ_PER_ICS (1 << KVMPPC_XICS_ICS_SHIFT) | |
22 | #define KVMPPC_XICS_SRC_MASK (KVMPPC_XICS_IRQ_PER_ICS - 1) | |
23 | ||
24 | /* | |
25 | * Interrupt source numbers below this are reserved, for example | |
26 | * 0 is "no interrupt", and 2 is used for IPIs. | |
27 | */ | |
28 | #define KVMPPC_XICS_FIRST_IRQ 16 | |
29 | #define KVMPPC_XICS_NR_IRQS ((KVMPPC_XICS_MAX_ICS_ID + 1) * \ | |
30 | KVMPPC_XICS_IRQ_PER_ICS) | |
31 | ||
32 | /* Priority value to use for disabling an interrupt */ | |
33 | #define MASKED 0xff | |
34 | ||
17d48610 LZ |
35 | #define PQ_PRESENTED 1 |
36 | #define PQ_QUEUED 2 | |
37 | ||
bc5ad3f3 BH |
38 | /* State for one irq source */ |
39 | struct ics_irq_state { | |
40 | u32 number; | |
41 | u32 server; | |
17d48610 | 42 | u32 pq_state; |
bc5ad3f3 | 43 | u8 priority; |
d19bd862 | 44 | u8 saved_priority; |
bc5ad3f3 BH |
45 | u8 resend; |
46 | u8 masked_pending; | |
b1a4286b | 47 | u8 lsi; /* level-sensitive interrupt */ |
bc5ad3f3 | 48 | u8 exists; |
5d375199 PM |
49 | int intr_cpu; |
50 | u32 host_irq; | |
bc5ad3f3 BH |
51 | }; |
52 | ||
53 | /* Atomic ICP state, updated with a single compare & swap */ | |
54 | union kvmppc_icp_state { | |
55 | unsigned long raw; | |
56 | struct { | |
57 | u8 out_ee:1; | |
58 | u8 need_resend:1; | |
59 | u8 cppr; | |
60 | u8 mfrr; | |
61 | u8 pending_pri; | |
62 | u32 xisr; | |
63 | }; | |
64 | }; | |
65 | ||
66 | /* One bit per ICS */ | |
67 | #define ICP_RESEND_MAP_SIZE (KVMPPC_XICS_MAX_ICS_ID / BITS_PER_LONG + 1) | |
68 | ||
69 | struct kvmppc_icp { | |
70 | struct kvm_vcpu *vcpu; | |
71 | unsigned long server_num; | |
72 | union kvmppc_icp_state state; | |
73 | unsigned long resend_map[ICP_RESEND_MAP_SIZE]; | |
e7d26f28 BH |
74 | |
75 | /* Real mode might find something too hard, here's the action | |
76 | * it might request from virtual mode | |
77 | */ | |
78 | #define XICS_RM_KICK_VCPU 0x1 | |
79 | #define XICS_RM_CHECK_RESEND 0x2 | |
25a2150b | 80 | #define XICS_RM_NOTIFY_EOI 0x8 |
e7d26f28 BH |
81 | u32 rm_action; |
82 | struct kvm_vcpu *rm_kick_target; | |
5b88cda6 | 83 | struct kvmppc_icp *rm_resend_icp; |
e7d26f28 | 84 | u32 rm_reject; |
25a2150b | 85 | u32 rm_eoied_irq; |
e7d26f28 | 86 | |
878610fe SW |
87 | /* Counters for each reason we exited real mode */ |
88 | unsigned long n_rm_kick_vcpu; | |
89 | unsigned long n_rm_check_resend; | |
878610fe | 90 | unsigned long n_rm_notify_eoi; |
6e0365b7 SW |
91 | /* Counters for handling ICP processing in real mode */ |
92 | unsigned long n_check_resend; | |
93 | unsigned long n_reject; | |
878610fe | 94 | |
e7d26f28 BH |
95 | /* Debug stuff for real mode */ |
96 | union kvmppc_icp_state rm_dbgstate; | |
97 | struct kvm_vcpu *rm_dbgtgt; | |
bc5ad3f3 BH |
98 | }; |
99 | ||
100 | struct kvmppc_ics { | |
34cb7954 | 101 | arch_spinlock_t lock; |
bc5ad3f3 BH |
102 | u16 icsid; |
103 | struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS]; | |
104 | }; | |
105 | ||
106 | struct kvmppc_xics { | |
107 | struct kvm *kvm; | |
5975a2e0 | 108 | struct kvm_device *dev; |
bc5ad3f3 BH |
109 | struct dentry *dentry; |
110 | u32 max_icsid; | |
e7d26f28 BH |
111 | bool real_mode; |
112 | bool real_mode_dbg; | |
6e0365b7 SW |
113 | u32 err_noics; |
114 | u32 err_noicp; | |
bc5ad3f3 BH |
115 | struct kvmppc_ics *ics[KVMPPC_XICS_MAX_ICS_ID + 1]; |
116 | }; | |
117 | ||
118 | static inline struct kvmppc_icp *kvmppc_xics_find_server(struct kvm *kvm, | |
119 | u32 nr) | |
120 | { | |
121 | struct kvm_vcpu *vcpu = NULL; | |
122 | int i; | |
123 | ||
124 | kvm_for_each_vcpu(i, vcpu, kvm) { | |
125 | if (vcpu->arch.icp && nr == vcpu->arch.icp->server_num) | |
126 | return vcpu->arch.icp; | |
127 | } | |
128 | return NULL; | |
129 | } | |
130 | ||
131 | static inline struct kvmppc_ics *kvmppc_xics_find_ics(struct kvmppc_xics *xics, | |
132 | u32 irq, u16 *source) | |
133 | { | |
134 | u32 icsid = irq >> KVMPPC_XICS_ICS_SHIFT; | |
135 | u16 src = irq & KVMPPC_XICS_SRC_MASK; | |
136 | struct kvmppc_ics *ics; | |
137 | ||
138 | if (source) | |
139 | *source = src; | |
140 | if (icsid > KVMPPC_XICS_MAX_ICS_ID) | |
141 | return NULL; | |
142 | ics = xics->ics[icsid]; | |
143 | if (!ics) | |
144 | return NULL; | |
145 | return ics; | |
146 | } | |
147 | ||
5af50993 BH |
148 | extern unsigned long xics_rm_h_xirr(struct kvm_vcpu *vcpu); |
149 | extern int xics_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, | |
150 | unsigned long mfrr); | |
151 | extern int xics_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr); | |
152 | extern int xics_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr); | |
bc5ad3f3 | 153 | |
5af50993 | 154 | #endif /* CONFIG_KVM_XICS */ |
bc5ad3f3 | 155 | #endif /* _KVM_PPC_BOOK3S_XICS_H */ |