1
2
3
4
5
6
7
8
9#include "qemu/osdep.h"
10#include "qemu/log.h"
11#include "qapi/error.h"
12#include "qemu-common.h"
13#include "hw/pci-host/pnv_phb3_regs.h"
14#include "hw/pci-host/pnv_phb3.h"
15#include "hw/ppc/pnv.h"
16#include "hw/pci/msi.h"
17#include "monitor/monitor.h"
18#include "hw/irq.h"
19#include "hw/qdev-properties.h"
20#include "sysemu/reset.h"
21
22static uint64_t phb3_msi_ive_addr(PnvPHB3 *phb, int srcno)
23{
24 uint64_t ivtbar = phb->regs[PHB_IVT_BAR >> 3];
25 uint64_t phbctl = phb->regs[PHB_CONTROL >> 3];
26
27 if (!(ivtbar & PHB_IVT_BAR_ENABLE)) {
28 qemu_log_mask(LOG_GUEST_ERROR, "Failed access to disable IVT BAR !");
29 return 0;
30 }
31
32 if (srcno >= (ivtbar & PHB_IVT_LENGTH_MASK)) {
33 qemu_log_mask(LOG_GUEST_ERROR, "MSI out of bounds (%d vs 0x%"PRIx64")",
34 srcno, (uint64_t) (ivtbar & PHB_IVT_LENGTH_MASK));
35 return 0;
36 }
37
38 ivtbar &= PHB_IVT_BASE_ADDRESS_MASK;
39
40 if (phbctl & PHB_CTRL_IVE_128_BYTES) {
41 return ivtbar + 128 * srcno;
42 } else {
43 return ivtbar + 16 * srcno;
44 }
45}
46
47static bool phb3_msi_read_ive(PnvPHB3 *phb, int srcno, uint64_t *out_ive)
48{
49 uint64_t ive_addr, ive;
50
51 ive_addr = phb3_msi_ive_addr(phb, srcno);
52 if (!ive_addr) {
53 return false;
54 }
55
56 if (dma_memory_read(&address_space_memory, ive_addr,
57 &ive, sizeof(ive), MEMTXATTRS_UNSPECIFIED)) {
58 qemu_log_mask(LOG_GUEST_ERROR, "Failed to read IVE at 0x%" PRIx64,
59 ive_addr);
60 return false;
61 }
62 *out_ive = be64_to_cpu(ive);
63
64 return true;
65}
66
67static void phb3_msi_set_p(Phb3MsiState *msi, int srcno, uint8_t gen)
68{
69 uint64_t ive_addr;
70 uint8_t p = 0x01 | (gen << 1);
71
72 ive_addr = phb3_msi_ive_addr(msi->phb, srcno);
73 if (!ive_addr) {
74 return;
75 }
76
77 if (dma_memory_write(&address_space_memory, ive_addr + 4,
78 &p, 1, MEMTXATTRS_UNSPECIFIED)) {
79 qemu_log_mask(LOG_GUEST_ERROR,
80 "Failed to write IVE (set P) at 0x%" PRIx64, ive_addr);
81 }
82}
83
84static void phb3_msi_set_q(Phb3MsiState *msi, int srcno)
85{
86 uint64_t ive_addr;
87 uint8_t q = 0x01;
88
89 ive_addr = phb3_msi_ive_addr(msi->phb, srcno);
90 if (!ive_addr) {
91 return;
92 }
93
94 if (dma_memory_write(&address_space_memory, ive_addr + 5,
95 &q, 1, MEMTXATTRS_UNSPECIFIED)) {
96 qemu_log_mask(LOG_GUEST_ERROR,
97 "Failed to write IVE (set Q) at 0x%" PRIx64, ive_addr);
98 }
99}
100
101static void phb3_msi_try_send(Phb3MsiState *msi, int srcno, bool force)
102{
103 ICSState *ics = ICS(msi);
104 uint64_t ive;
105 uint64_t server, prio, pq, gen;
106
107 if (!phb3_msi_read_ive(msi->phb, srcno, &ive)) {
108 return;
109 }
110
111 server = GETFIELD(IODA2_IVT_SERVER, ive);
112 prio = GETFIELD(IODA2_IVT_PRIORITY, ive);
113 if (!force) {
114 pq = GETFIELD(IODA2_IVT_Q, ive) | (GETFIELD(IODA2_IVT_P, ive) << 1);
115 } else {
116 pq = 0;
117 }
118 gen = GETFIELD(IODA2_IVT_GEN, ive);
119
120
121
122
123
124 server >>= 2;
125
126 switch (pq) {
127 case 0:
128 if (prio == 0xff) {
129
130 phb3_msi_set_q(msi, srcno);
131 } else {
132
133 phb3_msi_set_p(msi, srcno, gen);
134 icp_irq(ics, server, srcno + ics->offset, prio);
135 }
136 break;
137 case 2:
138
139 phb3_msi_set_q(msi, srcno);
140 break;
141 case 1:
142 case 3:
143 default:
144
145 break;
146 }
147}
148
149static void phb3_msi_set_irq(void *opaque, int srcno, int val)
150{
151 Phb3MsiState *msi = PHB3_MSI(opaque);
152
153 if (val) {
154 phb3_msi_try_send(msi, srcno, false);
155 }
156}
157
158
159void pnv_phb3_msi_send(Phb3MsiState *msi, uint64_t addr, uint16_t data,
160 int32_t dev_pe)
161{
162 ICSState *ics = ICS(msi);
163 uint64_t ive;
164 uint16_t pe;
165 uint32_t src = ((addr >> 4) & 0xffff) | (data & 0x1f);
166
167 if (src >= ics->nr_irqs) {
168 qemu_log_mask(LOG_GUEST_ERROR, "MSI %d out of bounds", src);
169 return;
170 }
171 if (dev_pe >= 0) {
172 if (!phb3_msi_read_ive(msi->phb, src, &ive)) {
173 return;
174 }
175 pe = GETFIELD(IODA2_IVT_PE, ive);
176 if (pe != dev_pe) {
177 qemu_log_mask(LOG_GUEST_ERROR,
178 "MSI %d send by PE#%d but assigned to PE#%d",
179 src, dev_pe, pe);
180 return;
181 }
182 }
183 qemu_irq_pulse(msi->qirqs[src]);
184}
185
186void pnv_phb3_msi_ffi(Phb3MsiState *msi, uint64_t val)
187{
188
189 pnv_phb3_msi_send(msi, val, 0, -1);
190
191
192 msi->phb->regs[PHB_FFI_LOCK >> 3] = 0;
193}
194
195static void phb3_msi_reject(ICSState *ics, uint32_t nr)
196{
197 Phb3MsiState *msi = PHB3_MSI(ics);
198 unsigned int srcno = nr - ics->offset;
199 unsigned int idx = srcno >> 6;
200 unsigned int bit = 1ull << (srcno & 0x3f);
201
202 assert(srcno < PHB3_MAX_MSI);
203
204 msi->rba[idx] |= bit;
205 msi->rba_sum |= (1u << idx);
206}
207
208static void phb3_msi_resend(ICSState *ics)
209{
210 Phb3MsiState *msi = PHB3_MSI(ics);
211 unsigned int i, j;
212
213 if (msi->rba_sum == 0) {
214 return;
215 }
216
217 for (i = 0; i < 32; i++) {
218 if ((msi->rba_sum & (1u << i)) == 0) {
219 continue;
220 }
221 msi->rba_sum &= ~(1u << i);
222 for (j = 0; j < 64; j++) {
223 if ((msi->rba[i] & (1ull << j)) == 0) {
224 continue;
225 }
226 msi->rba[i] &= ~(1ull << j);
227 phb3_msi_try_send(msi, i * 64 + j, true);
228 }
229 }
230}
231
232static void phb3_msi_reset(DeviceState *dev)
233{
234 Phb3MsiState *msi = PHB3_MSI(dev);
235 ICSStateClass *icsc = ICS_GET_CLASS(dev);
236
237 icsc->parent_reset(dev);
238
239 memset(msi->rba, 0, sizeof(msi->rba));
240 msi->rba_sum = 0;
241}
242
243static void phb3_msi_reset_handler(void *dev)
244{
245 phb3_msi_reset(dev);
246}
247
248void pnv_phb3_msi_update_config(Phb3MsiState *msi, uint32_t base,
249 uint32_t count)
250{
251 ICSState *ics = ICS(msi);
252
253 if (count > PHB3_MAX_MSI) {
254 count = PHB3_MAX_MSI;
255 }
256 ics->nr_irqs = count;
257 ics->offset = base;
258}
259
260static void phb3_msi_realize(DeviceState *dev, Error **errp)
261{
262 Phb3MsiState *msi = PHB3_MSI(dev);
263 ICSState *ics = ICS(msi);
264 ICSStateClass *icsc = ICS_GET_CLASS(ics);
265 Error *local_err = NULL;
266
267 assert(msi->phb);
268
269 icsc->parent_realize(dev, &local_err);
270 if (local_err) {
271 error_propagate(errp, local_err);
272 return;
273 }
274
275 msi->qirqs = qemu_allocate_irqs(phb3_msi_set_irq, msi, ics->nr_irqs);
276
277 qemu_register_reset(phb3_msi_reset_handler, dev);
278}
279
280static void phb3_msi_instance_init(Object *obj)
281{
282 Phb3MsiState *msi = PHB3_MSI(obj);
283 ICSState *ics = ICS(obj);
284
285 object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
286 (Object **)&msi->phb,
287 object_property_allow_set_link,
288 OBJ_PROP_LINK_STRONG);
289
290
291 ics->offset = 0;
292}
293
294static void phb3_msi_class_init(ObjectClass *klass, void *data)
295{
296 DeviceClass *dc = DEVICE_CLASS(klass);
297 ICSStateClass *isc = ICS_CLASS(klass);
298
299 device_class_set_parent_realize(dc, phb3_msi_realize,
300 &isc->parent_realize);
301 device_class_set_parent_reset(dc, phb3_msi_reset,
302 &isc->parent_reset);
303
304 isc->reject = phb3_msi_reject;
305 isc->resend = phb3_msi_resend;
306}
307
308static const TypeInfo phb3_msi_info = {
309 .name = TYPE_PHB3_MSI,
310 .parent = TYPE_ICS,
311 .instance_size = sizeof(Phb3MsiState),
312 .class_init = phb3_msi_class_init,
313 .class_size = sizeof(ICSStateClass),
314 .instance_init = phb3_msi_instance_init,
315};
316
317static void pnv_phb3_msi_register_types(void)
318{
319 type_register_static(&phb3_msi_info);
320}
321
322type_init(pnv_phb3_msi_register_types);
323
324void pnv_phb3_msi_pic_print_info(Phb3MsiState *msi, Monitor *mon)
325{
326 ICSState *ics = ICS(msi);
327 int i;
328
329 monitor_printf(mon, "ICS %4x..%4x %p\n",
330 ics->offset, ics->offset + ics->nr_irqs - 1, ics);
331
332 for (i = 0; i < ics->nr_irqs; i++) {
333 uint64_t ive;
334
335 if (!phb3_msi_read_ive(msi->phb, i, &ive)) {
336 return;
337 }
338
339 if (GETFIELD(IODA2_IVT_PRIORITY, ive) == 0xff) {
340 continue;
341 }
342
343 monitor_printf(mon, " %4x %c%c server=%04x prio=%02x gen=%d\n",
344 ics->offset + i,
345 GETFIELD(IODA2_IVT_P, ive) ? 'P' : '-',
346 GETFIELD(IODA2_IVT_Q, ive) ? 'Q' : '-',
347 (uint32_t) GETFIELD(IODA2_IVT_SERVER, ive) >> 2,
348 (uint32_t) GETFIELD(IODA2_IVT_PRIORITY, ive),
349 (uint32_t) GETFIELD(IODA2_IVT_GEN, ive));
350 }
351}
352