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