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; | |
42 | u8 asserted; /* Only for LSI */ | |
43 | u8 exists; | |
44 | }; | |
45 | ||
46 | /* Atomic ICP state, updated with a single compare & swap */ | |
47 | union kvmppc_icp_state { | |
48 | unsigned long raw; | |
49 | struct { | |
50 | u8 out_ee:1; | |
51 | u8 need_resend:1; | |
52 | u8 cppr; | |
53 | u8 mfrr; | |
54 | u8 pending_pri; | |
55 | u32 xisr; | |
56 | }; | |
57 | }; | |
58 | ||
59 | /* One bit per ICS */ | |
60 | #define ICP_RESEND_MAP_SIZE (KVMPPC_XICS_MAX_ICS_ID / BITS_PER_LONG + 1) | |
61 | ||
62 | struct kvmppc_icp { | |
63 | struct kvm_vcpu *vcpu; | |
64 | unsigned long server_num; | |
65 | union kvmppc_icp_state state; | |
66 | unsigned long resend_map[ICP_RESEND_MAP_SIZE]; | |
e7d26f28 BH |
67 | |
68 | /* Real mode might find something too hard, here's the action | |
69 | * it might request from virtual mode | |
70 | */ | |
71 | #define XICS_RM_KICK_VCPU 0x1 | |
72 | #define XICS_RM_CHECK_RESEND 0x2 | |
73 | #define XICS_RM_REJECT 0x4 | |
25a2150b | 74 | #define XICS_RM_NOTIFY_EOI 0x8 |
e7d26f28 BH |
75 | u32 rm_action; |
76 | struct kvm_vcpu *rm_kick_target; | |
77 | u32 rm_reject; | |
25a2150b | 78 | u32 rm_eoied_irq; |
e7d26f28 BH |
79 | |
80 | /* Debug stuff for real mode */ | |
81 | union kvmppc_icp_state rm_dbgstate; | |
82 | struct kvm_vcpu *rm_dbgtgt; | |
bc5ad3f3 BH |
83 | }; |
84 | ||
85 | struct kvmppc_ics { | |
86 | struct mutex lock; | |
87 | u16 icsid; | |
88 | struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS]; | |
89 | }; | |
90 | ||
91 | struct kvmppc_xics { | |
92 | struct kvm *kvm; | |
5975a2e0 | 93 | struct kvm_device *dev; |
bc5ad3f3 BH |
94 | struct dentry *dentry; |
95 | u32 max_icsid; | |
e7d26f28 BH |
96 | bool real_mode; |
97 | bool real_mode_dbg; | |
bc5ad3f3 BH |
98 | struct kvmppc_ics *ics[KVMPPC_XICS_MAX_ICS_ID + 1]; |
99 | }; | |
100 | ||
101 | static inline struct kvmppc_icp *kvmppc_xics_find_server(struct kvm *kvm, | |
102 | u32 nr) | |
103 | { | |
104 | struct kvm_vcpu *vcpu = NULL; | |
105 | int i; | |
106 | ||
107 | kvm_for_each_vcpu(i, vcpu, kvm) { | |
108 | if (vcpu->arch.icp && nr == vcpu->arch.icp->server_num) | |
109 | return vcpu->arch.icp; | |
110 | } | |
111 | return NULL; | |
112 | } | |
113 | ||
114 | static inline struct kvmppc_ics *kvmppc_xics_find_ics(struct kvmppc_xics *xics, | |
115 | u32 irq, u16 *source) | |
116 | { | |
117 | u32 icsid = irq >> KVMPPC_XICS_ICS_SHIFT; | |
118 | u16 src = irq & KVMPPC_XICS_SRC_MASK; | |
119 | struct kvmppc_ics *ics; | |
120 | ||
121 | if (source) | |
122 | *source = src; | |
123 | if (icsid > KVMPPC_XICS_MAX_ICS_ID) | |
124 | return NULL; | |
125 | ics = xics->ics[icsid]; | |
126 | if (!ics) | |
127 | return NULL; | |
128 | return ics; | |
129 | } | |
130 | ||
131 | ||
132 | #endif /* _KVM_PPC_BOOK3S_XICS_H */ |