1 | /* |
2 | * s390 PCI BUS |
3 | * |
4 | * Copyright 2014 IBM Corp. |
5 | * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com> |
6 | * Hong Bo Li <lihbbj@cn.ibm.com> |
7 | * Yi Min Zhao <zyimin@cn.ibm.com> |
8 | * |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or (at |
10 | * your option) any later version. See the COPYING file in the top-level |
11 | * directory. |
12 | */ |
13 | |
14 | #include "qemu/osdep.h" |
15 | #include "qapi/error.h" |
16 | #include "qapi/visitor.h" |
17 | #include "cpu.h" |
18 | #include "s390-pci-bus.h" |
19 | #include "s390-pci-inst.h" |
20 | #include "hw/pci/pci_bus.h" |
21 | #include "hw/qdev-properties.h" |
22 | #include "hw/pci/pci_bridge.h" |
23 | #include "hw/pci/msi.h" |
24 | #include "qemu/error-report.h" |
25 | #include "qemu/module.h" |
26 | |
27 | #ifndef DEBUG_S390PCI_BUS |
28 | #define DEBUG_S390PCI_BUS 0 |
29 | #endif |
30 | |
31 | #define DPRINTF(fmt, ...) \ |
32 | do { \ |
33 | if (DEBUG_S390PCI_BUS) { \ |
34 | fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); \ |
35 | } \ |
36 | } while (0) |
37 | |
38 | S390pciState *s390_get_phb(void) |
39 | { |
40 | static S390pciState *phb; |
41 | |
42 | if (!phb) { |
43 | phb = S390_PCI_HOST_BRIDGE( |
44 | object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); |
45 | assert(phb != NULL); |
46 | } |
47 | |
48 | return phb; |
49 | } |
50 | |
51 | int pci_chsc_sei_nt2_get_event(void *res) |
52 | { |
53 | ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res; |
54 | PciCcdfAvail *accdf; |
55 | PciCcdfErr *eccdf; |
56 | int rc = 1; |
57 | SeiContainer *sei_cont; |
58 | S390pciState *s = s390_get_phb(); |
59 | |
60 | sei_cont = QTAILQ_FIRST(&s->pending_sei); |
61 | if (sei_cont) { |
62 | QTAILQ_REMOVE(&s->pending_sei, sei_cont, link); |
63 | nt2_res->nt = 2; |
64 | nt2_res->cc = sei_cont->cc; |
65 | nt2_res->length = cpu_to_be16(sizeof(ChscSeiNt2Res)); |
66 | switch (sei_cont->cc) { |
67 | case 1: /* error event */ |
68 | eccdf = (PciCcdfErr *)nt2_res->ccdf; |
69 | eccdf->fid = cpu_to_be32(sei_cont->fid); |
70 | eccdf->fh = cpu_to_be32(sei_cont->fh); |
71 | eccdf->e = cpu_to_be32(sei_cont->e); |
72 | eccdf->faddr = cpu_to_be64(sei_cont->faddr); |
73 | eccdf->pec = cpu_to_be16(sei_cont->pec); |
74 | break; |
75 | case 2: /* availability event */ |
76 | accdf = (PciCcdfAvail *)nt2_res->ccdf; |
77 | accdf->fid = cpu_to_be32(sei_cont->fid); |
78 | accdf->fh = cpu_to_be32(sei_cont->fh); |
79 | accdf->pec = cpu_to_be16(sei_cont->pec); |
80 | break; |
81 | default: |
82 | abort(); |
83 | } |
84 | g_free(sei_cont); |
85 | rc = 0; |
86 | } |
87 | |
88 | return rc; |
89 | } |
90 | |
91 | int pci_chsc_sei_nt2_have_event(void) |
92 | { |
93 | S390pciState *s = s390_get_phb(); |
94 | |
95 | return !QTAILQ_EMPTY(&s->pending_sei); |
96 | } |
97 | |
98 | S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, |
99 | S390PCIBusDevice *pbdev) |
100 | { |
101 | S390PCIBusDevice *ret = pbdev ? QTAILQ_NEXT(pbdev, link) : |
102 | QTAILQ_FIRST(&s->zpci_devs); |
103 | |
104 | while (ret && ret->state == ZPCI_FS_RESERVED) { |
105 | ret = QTAILQ_NEXT(ret, link); |
106 | } |
107 | |
108 | return ret; |
109 | } |
110 | |
111 | S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid) |
112 | { |
113 | S390PCIBusDevice *pbdev; |
114 | |
115 | QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) { |
116 | if (pbdev->fid == fid) { |
117 | return pbdev; |
118 | } |
119 | } |
120 | |
121 | return NULL; |
122 | } |
123 | |
124 | void s390_pci_sclp_configure(SCCB *sccb) |
125 | { |
126 | IoaCfgSccb *psccb = (IoaCfgSccb *)sccb; |
127 | S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(), |
128 | be32_to_cpu(psccb->aid)); |
129 | uint16_t rc; |
130 | |
131 | if (!pbdev) { |
132 | DPRINTF("sclp config no dev found\n" ); |
133 | rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; |
134 | goto out; |
135 | } |
136 | |
137 | switch (pbdev->state) { |
138 | case ZPCI_FS_RESERVED: |
139 | rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE; |
140 | break; |
141 | case ZPCI_FS_STANDBY: |
142 | pbdev->state = ZPCI_FS_DISABLED; |
143 | rc = SCLP_RC_NORMAL_COMPLETION; |
144 | break; |
145 | default: |
146 | rc = SCLP_RC_NO_ACTION_REQUIRED; |
147 | } |
148 | out: |
149 | psccb->header.response_code = cpu_to_be16(rc); |
150 | } |
151 | |
152 | static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev) |
153 | { |
154 | HotplugHandler *hotplug_ctrl; |
155 | |
156 | /* Unplug the PCI device */ |
157 | if (pbdev->pdev) { |
158 | DeviceState *pdev = DEVICE(pbdev->pdev); |
159 | |
160 | hotplug_ctrl = qdev_get_hotplug_handler(pdev); |
161 | hotplug_handler_unplug(hotplug_ctrl, pdev, &error_abort); |
162 | object_unparent(OBJECT(pdev)); |
163 | } |
164 | |
165 | /* Unplug the zPCI device */ |
166 | hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(pbdev)); |
167 | hotplug_handler_unplug(hotplug_ctrl, DEVICE(pbdev), &error_abort); |
168 | object_unparent(OBJECT(pbdev)); |
169 | } |
170 | |
171 | void s390_pci_sclp_deconfigure(SCCB *sccb) |
172 | { |
173 | IoaCfgSccb *psccb = (IoaCfgSccb *)sccb; |
174 | S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(), |
175 | be32_to_cpu(psccb->aid)); |
176 | uint16_t rc; |
177 | |
178 | if (!pbdev) { |
179 | DPRINTF("sclp deconfig no dev found\n" ); |
180 | rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; |
181 | goto out; |
182 | } |
183 | |
184 | switch (pbdev->state) { |
185 | case ZPCI_FS_RESERVED: |
186 | rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE; |
187 | break; |
188 | case ZPCI_FS_STANDBY: |
189 | rc = SCLP_RC_NO_ACTION_REQUIRED; |
190 | break; |
191 | default: |
192 | if (pbdev->summary_ind) { |
193 | pci_dereg_irqs(pbdev); |
194 | } |
195 | if (pbdev->iommu->enabled) { |
196 | pci_dereg_ioat(pbdev->iommu); |
197 | } |
198 | pbdev->state = ZPCI_FS_STANDBY; |
199 | rc = SCLP_RC_NORMAL_COMPLETION; |
200 | |
201 | if (pbdev->unplug_requested) { |
202 | s390_pci_perform_unplug(pbdev); |
203 | } |
204 | } |
205 | out: |
206 | psccb->header.response_code = cpu_to_be16(rc); |
207 | } |
208 | |
209 | static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid) |
210 | { |
211 | S390PCIBusDevice *pbdev; |
212 | |
213 | QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) { |
214 | if (pbdev->uid == uid) { |
215 | return pbdev; |
216 | } |
217 | } |
218 | |
219 | return NULL; |
220 | } |
221 | |
222 | S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, |
223 | const char *target) |
224 | { |
225 | S390PCIBusDevice *pbdev; |
226 | |
227 | if (!target) { |
228 | return NULL; |
229 | } |
230 | |
231 | QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) { |
232 | if (!strcmp(pbdev->target, target)) { |
233 | return pbdev; |
234 | } |
235 | } |
236 | |
237 | return NULL; |
238 | } |
239 | |
240 | static S390PCIBusDevice *s390_pci_find_dev_by_pci(S390pciState *s, |
241 | PCIDevice *pci_dev) |
242 | { |
243 | S390PCIBusDevice *pbdev; |
244 | |
245 | if (!pci_dev) { |
246 | return NULL; |
247 | } |
248 | |
249 | QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) { |
250 | if (pbdev->pdev == pci_dev) { |
251 | return pbdev; |
252 | } |
253 | } |
254 | |
255 | return NULL; |
256 | } |
257 | |
258 | S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx) |
259 | { |
260 | return g_hash_table_lookup(s->zpci_table, &idx); |
261 | } |
262 | |
263 | S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh) |
264 | { |
265 | uint32_t idx = FH_MASK_INDEX & fh; |
266 | S390PCIBusDevice *pbdev = s390_pci_find_dev_by_idx(s, idx); |
267 | |
268 | if (pbdev && pbdev->fh == fh) { |
269 | return pbdev; |
270 | } |
271 | |
272 | return NULL; |
273 | } |
274 | |
275 | static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh, |
276 | uint32_t fid, uint64_t faddr, uint32_t e) |
277 | { |
278 | SeiContainer *sei_cont; |
279 | S390pciState *s = s390_get_phb(); |
280 | |
281 | sei_cont = g_new0(SeiContainer, 1); |
282 | sei_cont->fh = fh; |
283 | sei_cont->fid = fid; |
284 | sei_cont->cc = cc; |
285 | sei_cont->pec = pec; |
286 | sei_cont->faddr = faddr; |
287 | sei_cont->e = e; |
288 | |
289 | QTAILQ_INSERT_TAIL(&s->pending_sei, sei_cont, link); |
290 | css_generate_css_crws(0); |
291 | } |
292 | |
293 | static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh, |
294 | uint32_t fid) |
295 | { |
296 | s390_pci_generate_event(2, pec, fh, fid, 0, 0); |
297 | } |
298 | |
299 | void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, |
300 | uint64_t faddr, uint32_t e) |
301 | { |
302 | s390_pci_generate_event(1, pec, fh, fid, faddr, e); |
303 | } |
304 | |
305 | static void s390_pci_set_irq(void *opaque, int irq, int level) |
306 | { |
307 | /* nothing to do */ |
308 | } |
309 | |
310 | static int s390_pci_map_irq(PCIDevice *pci_dev, int irq_num) |
311 | { |
312 | /* nothing to do */ |
313 | return 0; |
314 | } |
315 | |
316 | static uint64_t s390_pci_get_table_origin(uint64_t iota) |
317 | { |
318 | return iota & ~ZPCI_IOTA_RTTO_FLAG; |
319 | } |
320 | |
321 | static unsigned int calc_rtx(dma_addr_t ptr) |
322 | { |
323 | return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK; |
324 | } |
325 | |
326 | static unsigned int calc_sx(dma_addr_t ptr) |
327 | { |
328 | return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK; |
329 | } |
330 | |
331 | static unsigned int calc_px(dma_addr_t ptr) |
332 | { |
333 | return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK; |
334 | } |
335 | |
336 | static uint64_t get_rt_sto(uint64_t entry) |
337 | { |
338 | return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) |
339 | ? (entry & ZPCI_RTE_ADDR_MASK) |
340 | : 0; |
341 | } |
342 | |
343 | static uint64_t get_st_pto(uint64_t entry) |
344 | { |
345 | return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) |
346 | ? (entry & ZPCI_STE_ADDR_MASK) |
347 | : 0; |
348 | } |
349 | |
350 | static bool rt_entry_isvalid(uint64_t entry) |
351 | { |
352 | return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID; |
353 | } |
354 | |
355 | static bool pt_entry_isvalid(uint64_t entry) |
356 | { |
357 | return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID; |
358 | } |
359 | |
360 | static bool entry_isprotected(uint64_t entry) |
361 | { |
362 | return (entry & ZPCI_TABLE_PROT_MASK) == ZPCI_TABLE_PROTECTED; |
363 | } |
364 | |
365 | /* ett is expected table type, -1 page table, 0 segment table, 1 region table */ |
366 | static uint64_t get_table_index(uint64_t iova, int8_t ett) |
367 | { |
368 | switch (ett) { |
369 | case ZPCI_ETT_PT: |
370 | return calc_px(iova); |
371 | case ZPCI_ETT_ST: |
372 | return calc_sx(iova); |
373 | case ZPCI_ETT_RT: |
374 | return calc_rtx(iova); |
375 | } |
376 | |
377 | return -1; |
378 | } |
379 | |
380 | static bool entry_isvalid(uint64_t entry, int8_t ett) |
381 | { |
382 | switch (ett) { |
383 | case ZPCI_ETT_PT: |
384 | return pt_entry_isvalid(entry); |
385 | case ZPCI_ETT_ST: |
386 | case ZPCI_ETT_RT: |
387 | return rt_entry_isvalid(entry); |
388 | } |
389 | |
390 | return false; |
391 | } |
392 | |
393 | /* Return true if address translation is done */ |
394 | static bool translate_iscomplete(uint64_t entry, int8_t ett) |
395 | { |
396 | switch (ett) { |
397 | case 0: |
398 | return (entry & ZPCI_TABLE_FC) ? true : false; |
399 | case 1: |
400 | return false; |
401 | } |
402 | |
403 | return true; |
404 | } |
405 | |
406 | static uint64_t get_frame_size(int8_t ett) |
407 | { |
408 | switch (ett) { |
409 | case ZPCI_ETT_PT: |
410 | return 1ULL << 12; |
411 | case ZPCI_ETT_ST: |
412 | return 1ULL << 20; |
413 | case ZPCI_ETT_RT: |
414 | return 1ULL << 31; |
415 | } |
416 | |
417 | return 0; |
418 | } |
419 | |
420 | static uint64_t get_next_table_origin(uint64_t entry, int8_t ett) |
421 | { |
422 | switch (ett) { |
423 | case ZPCI_ETT_PT: |
424 | return entry & ZPCI_PTE_ADDR_MASK; |
425 | case ZPCI_ETT_ST: |
426 | return get_st_pto(entry); |
427 | case ZPCI_ETT_RT: |
428 | return get_rt_sto(entry); |
429 | } |
430 | |
431 | return 0; |
432 | } |
433 | |
434 | /** |
435 | * table_translate: do translation within one table and return the following |
436 | * table origin |
437 | * |
438 | * @entry: the entry being translated, the result is stored in this. |
439 | * @to: the address of table origin. |
440 | * @ett: expected table type, 1 region table, 0 segment table and -1 page table. |
441 | * @error: error code |
442 | */ |
443 | static uint64_t table_translate(S390IOTLBEntry *entry, uint64_t to, int8_t ett, |
444 | uint16_t *error) |
445 | { |
446 | uint64_t tx, te, nto = 0; |
447 | uint16_t err = 0; |
448 | |
449 | tx = get_table_index(entry->iova, ett); |
450 | te = address_space_ldq(&address_space_memory, to + tx * sizeof(uint64_t), |
451 | MEMTXATTRS_UNSPECIFIED, NULL); |
452 | |
453 | if (!te) { |
454 | err = ERR_EVENT_INVALTE; |
455 | goto out; |
456 | } |
457 | |
458 | if (!entry_isvalid(te, ett)) { |
459 | entry->perm &= IOMMU_NONE; |
460 | goto out; |
461 | } |
462 | |
463 | if (ett == ZPCI_ETT_RT && ((te & ZPCI_TABLE_LEN_RTX) != ZPCI_TABLE_LEN_RTX |
464 | || te & ZPCI_TABLE_OFFSET_MASK)) { |
465 | err = ERR_EVENT_INVALTL; |
466 | goto out; |
467 | } |
468 | |
469 | nto = get_next_table_origin(te, ett); |
470 | if (!nto) { |
471 | err = ERR_EVENT_TT; |
472 | goto out; |
473 | } |
474 | |
475 | if (entry_isprotected(te)) { |
476 | entry->perm &= IOMMU_RO; |
477 | } else { |
478 | entry->perm &= IOMMU_RW; |
479 | } |
480 | |
481 | if (translate_iscomplete(te, ett)) { |
482 | switch (ett) { |
483 | case ZPCI_ETT_PT: |
484 | entry->translated_addr = te & ZPCI_PTE_ADDR_MASK; |
485 | break; |
486 | case ZPCI_ETT_ST: |
487 | entry->translated_addr = (te & ZPCI_SFAA_MASK) | |
488 | (entry->iova & ~ZPCI_SFAA_MASK); |
489 | break; |
490 | } |
491 | nto = 0; |
492 | } |
493 | out: |
494 | if (err) { |
495 | entry->perm = IOMMU_NONE; |
496 | *error = err; |
497 | } |
498 | entry->len = get_frame_size(ett); |
499 | return nto; |
500 | } |
501 | |
502 | uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, |
503 | S390IOTLBEntry *entry) |
504 | { |
505 | uint64_t to = s390_pci_get_table_origin(g_iota); |
506 | int8_t ett = 1; |
507 | uint16_t error = 0; |
508 | |
509 | entry->iova = addr & PAGE_MASK; |
510 | entry->translated_addr = 0; |
511 | entry->perm = IOMMU_RW; |
512 | |
513 | if (entry_isprotected(g_iota)) { |
514 | entry->perm &= IOMMU_RO; |
515 | } |
516 | |
517 | while (to) { |
518 | to = table_translate(entry, to, ett--, &error); |
519 | } |
520 | |
521 | return error; |
522 | } |
523 | |
524 | static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, |
525 | IOMMUAccessFlags flag, int iommu_idx) |
526 | { |
527 | S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); |
528 | S390IOTLBEntry *entry; |
529 | uint64_t iova = addr & PAGE_MASK; |
530 | uint16_t error = 0; |
531 | IOMMUTLBEntry ret = { |
532 | .target_as = &address_space_memory, |
533 | .iova = 0, |
534 | .translated_addr = 0, |
535 | .addr_mask = ~(hwaddr)0, |
536 | .perm = IOMMU_NONE, |
537 | }; |
538 | |
539 | switch (iommu->pbdev->state) { |
540 | case ZPCI_FS_ENABLED: |
541 | case ZPCI_FS_BLOCKED: |
542 | if (!iommu->enabled) { |
543 | return ret; |
544 | } |
545 | break; |
546 | default: |
547 | return ret; |
548 | } |
549 | |
550 | DPRINTF("iommu trans addr 0x%" PRIx64 "\n" , addr); |
551 | |
552 | if (addr < iommu->pba || addr > iommu->pal) { |
553 | error = ERR_EVENT_OORANGE; |
554 | goto err; |
555 | } |
556 | |
557 | entry = g_hash_table_lookup(iommu->iotlb, &iova); |
558 | if (entry) { |
559 | ret.iova = entry->iova; |
560 | ret.translated_addr = entry->translated_addr; |
561 | ret.addr_mask = entry->len - 1; |
562 | ret.perm = entry->perm; |
563 | } else { |
564 | ret.iova = iova; |
565 | ret.addr_mask = ~PAGE_MASK; |
566 | ret.perm = IOMMU_NONE; |
567 | } |
568 | |
569 | if (flag != IOMMU_NONE && !(flag & ret.perm)) { |
570 | error = ERR_EVENT_TPROTE; |
571 | } |
572 | err: |
573 | if (error) { |
574 | iommu->pbdev->state = ZPCI_FS_ERROR; |
575 | s390_pci_generate_error_event(error, iommu->pbdev->fh, |
576 | iommu->pbdev->fid, addr, 0); |
577 | } |
578 | return ret; |
579 | } |
580 | |
581 | static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, |
582 | IOMMUNotifier *notifier) |
583 | { |
584 | /* It's impossible to plug a pci device on s390x that already has iommu |
585 | * mappings which need to be replayed, that is due to the "one iommu per |
586 | * zpci device" construct. But when we support migration of vfio-pci |
587 | * devices in future, we need to revisit this. |
588 | */ |
589 | return; |
590 | } |
591 | |
592 | static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, |
593 | int devfn) |
594 | { |
595 | uint64_t key = (uintptr_t)bus; |
596 | S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key); |
597 | S390PCIIOMMU *iommu; |
598 | |
599 | if (!table) { |
600 | table = g_new0(S390PCIIOMMUTable, 1); |
601 | table->key = key; |
602 | g_hash_table_insert(s->iommu_table, &table->key, table); |
603 | } |
604 | |
605 | iommu = table->iommu[PCI_SLOT(devfn)]; |
606 | if (!iommu) { |
607 | iommu = S390_PCI_IOMMU(object_new(TYPE_S390_PCI_IOMMU)); |
608 | |
609 | char *mr_name = g_strdup_printf("iommu-root-%02x:%02x.%01x" , |
610 | pci_bus_num(bus), |
611 | PCI_SLOT(devfn), |
612 | PCI_FUNC(devfn)); |
613 | char *as_name = g_strdup_printf("iommu-pci-%02x:%02x.%01x" , |
614 | pci_bus_num(bus), |
615 | PCI_SLOT(devfn), |
616 | PCI_FUNC(devfn)); |
617 | memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX); |
618 | address_space_init(&iommu->as, &iommu->mr, as_name); |
619 | iommu->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, |
620 | NULL, g_free); |
621 | table->iommu[PCI_SLOT(devfn)] = iommu; |
622 | |
623 | g_free(mr_name); |
624 | g_free(as_name); |
625 | } |
626 | |
627 | return iommu; |
628 | } |
629 | |
630 | static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) |
631 | { |
632 | S390pciState *s = opaque; |
633 | S390PCIIOMMU *iommu = s390_pci_get_iommu(s, bus, devfn); |
634 | |
635 | return &iommu->as; |
636 | } |
637 | |
638 | static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) |
639 | { |
640 | uint8_t ind_old, ind_new; |
641 | hwaddr len = 1; |
642 | uint8_t *ind_addr; |
643 | |
644 | ind_addr = cpu_physical_memory_map(ind_loc, &len, 1); |
645 | if (!ind_addr) { |
646 | s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0); |
647 | return -1; |
648 | } |
649 | do { |
650 | ind_old = *ind_addr; |
651 | ind_new = ind_old | to_be_set; |
652 | } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); |
653 | cpu_physical_memory_unmap(ind_addr, len, 1, len); |
654 | |
655 | return ind_old; |
656 | } |
657 | |
658 | static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, |
659 | unsigned int size) |
660 | { |
661 | S390PCIBusDevice *pbdev = opaque; |
662 | uint32_t vec = data & ZPCI_MSI_VEC_MASK; |
663 | uint64_t ind_bit; |
664 | uint32_t sum_bit; |
665 | |
666 | assert(pbdev); |
667 | DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n" , data, |
668 | pbdev->idx, vec); |
669 | |
670 | if (pbdev->state != ZPCI_FS_ENABLED) { |
671 | return; |
672 | } |
673 | |
674 | ind_bit = pbdev->routes.adapter.ind_offset; |
675 | sum_bit = pbdev->routes.adapter.summary_offset; |
676 | |
677 | set_ind_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8, |
678 | 0x80 >> ((ind_bit + vec) % 8)); |
679 | if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8, |
680 | 0x80 >> (sum_bit % 8))) { |
681 | css_adapter_interrupt(CSS_IO_ADAPTER_PCI, pbdev->isc); |
682 | } |
683 | } |
684 | |
685 | static uint64_t s390_msi_ctrl_read(void *opaque, hwaddr addr, unsigned size) |
686 | { |
687 | return 0xffffffff; |
688 | } |
689 | |
690 | static const MemoryRegionOps s390_msi_ctrl_ops = { |
691 | .write = s390_msi_ctrl_write, |
692 | .read = s390_msi_ctrl_read, |
693 | .endianness = DEVICE_LITTLE_ENDIAN, |
694 | }; |
695 | |
696 | void s390_pci_iommu_enable(S390PCIIOMMU *iommu) |
697 | { |
698 | char *name = g_strdup_printf("iommu-s390-%04x" , iommu->pbdev->uid); |
699 | memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr), |
700 | TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), |
701 | name, iommu->pal - iommu->pba + 1); |
702 | iommu->enabled = true; |
703 | memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr)); |
704 | g_free(name); |
705 | } |
706 | |
707 | void s390_pci_iommu_disable(S390PCIIOMMU *iommu) |
708 | { |
709 | iommu->enabled = false; |
710 | g_hash_table_remove_all(iommu->iotlb); |
711 | memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr)); |
712 | object_unparent(OBJECT(&iommu->iommu_mr)); |
713 | } |
714 | |
715 | static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) |
716 | { |
717 | uint64_t key = (uintptr_t)bus; |
718 | S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key); |
719 | S390PCIIOMMU *iommu = table ? table->iommu[PCI_SLOT(devfn)] : NULL; |
720 | |
721 | if (!table || !iommu) { |
722 | return; |
723 | } |
724 | |
725 | table->iommu[PCI_SLOT(devfn)] = NULL; |
726 | g_hash_table_destroy(iommu->iotlb); |
727 | address_space_destroy(&iommu->as); |
728 | object_unparent(OBJECT(&iommu->mr)); |
729 | object_unparent(OBJECT(iommu)); |
730 | object_unref(OBJECT(iommu)); |
731 | } |
732 | |
733 | static void s390_pcihost_realize(DeviceState *dev, Error **errp) |
734 | { |
735 | PCIBus *b; |
736 | BusState *bus; |
737 | PCIHostState *phb = PCI_HOST_BRIDGE(dev); |
738 | S390pciState *s = S390_PCI_HOST_BRIDGE(dev); |
739 | Error *local_err = NULL; |
740 | |
741 | DPRINTF("host_init\n" ); |
742 | |
743 | b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq, |
744 | NULL, get_system_memory(), get_system_io(), 0, |
745 | 64, TYPE_PCI_BUS); |
746 | pci_setup_iommu(b, s390_pci_dma_iommu, s); |
747 | |
748 | bus = BUS(b); |
749 | qbus_set_hotplug_handler(bus, OBJECT(dev), &local_err); |
750 | if (local_err) { |
751 | error_propagate(errp, local_err); |
752 | return; |
753 | } |
754 | phb->bus = b; |
755 | |
756 | s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL)); |
757 | qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev), &local_err); |
758 | if (local_err) { |
759 | error_propagate(errp, local_err); |
760 | return; |
761 | } |
762 | |
763 | s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal, |
764 | NULL, g_free); |
765 | s->zpci_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL); |
766 | s->bus_no = 0; |
767 | QTAILQ_INIT(&s->pending_sei); |
768 | QTAILQ_INIT(&s->zpci_devs); |
769 | |
770 | css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, |
771 | S390_ADAPTER_SUPPRESSIBLE, &local_err); |
772 | error_propagate(errp, local_err); |
773 | } |
774 | |
775 | static int s390_pci_msix_init(S390PCIBusDevice *pbdev) |
776 | { |
777 | char *name; |
778 | uint8_t pos; |
779 | uint16_t ctrl; |
780 | uint32_t table, pba; |
781 | |
782 | pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX); |
783 | if (!pos) { |
784 | return -1; |
785 | } |
786 | |
787 | ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS, |
788 | pci_config_size(pbdev->pdev), sizeof(ctrl)); |
789 | table = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_TABLE, |
790 | pci_config_size(pbdev->pdev), sizeof(table)); |
791 | pba = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_PBA, |
792 | pci_config_size(pbdev->pdev), sizeof(pba)); |
793 | |
794 | pbdev->msix.table_bar = table & PCI_MSIX_FLAGS_BIRMASK; |
795 | pbdev->msix.table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK; |
796 | pbdev->msix.pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK; |
797 | pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; |
798 | pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; |
799 | |
800 | name = g_strdup_printf("msix-s390-%04x" , pbdev->uid); |
801 | memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev), |
802 | &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE); |
803 | memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR, |
804 | &pbdev->msix_notify_mr); |
805 | g_free(name); |
806 | |
807 | return 0; |
808 | } |
809 | |
810 | static void s390_pci_msix_free(S390PCIBusDevice *pbdev) |
811 | { |
812 | memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr); |
813 | object_unparent(OBJECT(&pbdev->msix_notify_mr)); |
814 | } |
815 | |
816 | static S390PCIBusDevice *s390_pci_device_new(S390pciState *s, |
817 | const char *target, Error **errp) |
818 | { |
819 | Error *local_err = NULL; |
820 | DeviceState *dev; |
821 | |
822 | dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE); |
823 | if (!dev) { |
824 | error_setg(errp, "zPCI device could not be created" ); |
825 | return NULL; |
826 | } |
827 | |
828 | object_property_set_str(OBJECT(dev), target, "target" , &local_err); |
829 | if (local_err) { |
830 | object_unparent(OBJECT(dev)); |
831 | error_propagate_prepend(errp, local_err, |
832 | "zPCI device could not be created: " ); |
833 | return NULL; |
834 | } |
835 | object_property_set_bool(OBJECT(dev), true, "realized" , &local_err); |
836 | if (local_err) { |
837 | object_unparent(OBJECT(dev)); |
838 | error_propagate_prepend(errp, local_err, |
839 | "zPCI device could not be created: " ); |
840 | return NULL; |
841 | } |
842 | |
843 | return S390_PCI_DEVICE(dev); |
844 | } |
845 | |
846 | static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev) |
847 | { |
848 | uint32_t idx; |
849 | |
850 | idx = s->next_idx; |
851 | while (s390_pci_find_dev_by_idx(s, idx)) { |
852 | idx = (idx + 1) & FH_MASK_INDEX; |
853 | if (idx == s->next_idx) { |
854 | return false; |
855 | } |
856 | } |
857 | |
858 | pbdev->idx = idx; |
859 | return true; |
860 | } |
861 | |
862 | static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, |
863 | Error **errp) |
864 | { |
865 | S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); |
866 | |
867 | if (!s390_has_feat(S390_FEAT_ZPCI)) { |
868 | warn_report("Plugging a PCI/zPCI device without the 'zpci' CPU " |
869 | "feature enabled; the guest will not be able to see/use " |
870 | "this device" ); |
871 | } |
872 | |
873 | if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { |
874 | PCIDevice *pdev = PCI_DEVICE(dev); |
875 | |
876 | if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { |
877 | error_setg(errp, "multifunction not supported in s390" ); |
878 | return; |
879 | } |
880 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { |
881 | S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); |
882 | |
883 | if (!s390_pci_alloc_idx(s, pbdev)) { |
884 | error_setg(errp, "no slot for plugging zpci device" ); |
885 | return; |
886 | } |
887 | } |
888 | } |
889 | |
890 | static void s390_pci_update_subordinate(PCIDevice *dev, uint32_t nr) |
891 | { |
892 | uint32_t old_nr; |
893 | |
894 | pci_default_write_config(dev, PCI_SUBORDINATE_BUS, nr, 1); |
895 | while (!pci_bus_is_root(pci_get_bus(dev))) { |
896 | dev = pci_get_bus(dev)->parent_dev; |
897 | |
898 | old_nr = pci_default_read_config(dev, PCI_SUBORDINATE_BUS, 1); |
899 | if (old_nr < nr) { |
900 | pci_default_write_config(dev, PCI_SUBORDINATE_BUS, nr, 1); |
901 | } |
902 | } |
903 | } |
904 | |
905 | static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, |
906 | Error **errp) |
907 | { |
908 | S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); |
909 | PCIDevice *pdev = NULL; |
910 | S390PCIBusDevice *pbdev = NULL; |
911 | |
912 | if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { |
913 | PCIBridge *pb = PCI_BRIDGE(dev); |
914 | |
915 | pdev = PCI_DEVICE(dev); |
916 | pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq); |
917 | pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s); |
918 | |
919 | qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s), errp); |
920 | |
921 | if (dev->hotplugged) { |
922 | pci_default_write_config(pdev, PCI_PRIMARY_BUS, |
923 | pci_dev_bus_num(pdev), 1); |
924 | s->bus_no += 1; |
925 | pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1); |
926 | |
927 | s390_pci_update_subordinate(pdev, s->bus_no); |
928 | } |
929 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { |
930 | pdev = PCI_DEVICE(dev); |
931 | |
932 | if (!dev->id) { |
933 | /* In the case the PCI device does not define an id */ |
934 | /* we generate one based on the PCI address */ |
935 | dev->id = g_strdup_printf("auto_%02x:%02x.%01x" , |
936 | pci_dev_bus_num(pdev), |
937 | PCI_SLOT(pdev->devfn), |
938 | PCI_FUNC(pdev->devfn)); |
939 | } |
940 | |
941 | pbdev = s390_pci_find_dev_by_target(s, dev->id); |
942 | if (!pbdev) { |
943 | pbdev = s390_pci_device_new(s, dev->id, errp); |
944 | if (!pbdev) { |
945 | return; |
946 | } |
947 | } |
948 | |
949 | if (object_dynamic_cast(OBJECT(dev), "vfio-pci" )) { |
950 | pbdev->fh |= FH_SHM_VFIO; |
951 | } else { |
952 | pbdev->fh |= FH_SHM_EMUL; |
953 | } |
954 | |
955 | pbdev->pdev = pdev; |
956 | pbdev->iommu = s390_pci_get_iommu(s, pci_get_bus(pdev), pdev->devfn); |
957 | pbdev->iommu->pbdev = pbdev; |
958 | pbdev->state = ZPCI_FS_DISABLED; |
959 | |
960 | if (s390_pci_msix_init(pbdev)) { |
961 | error_setg(errp, "MSI-X support is mandatory " |
962 | "in the S390 architecture" ); |
963 | return; |
964 | } |
965 | |
966 | if (dev->hotplugged) { |
967 | s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED , |
968 | pbdev->fh, pbdev->fid); |
969 | } |
970 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { |
971 | pbdev = S390_PCI_DEVICE(dev); |
972 | |
973 | /* the allocated idx is actually getting used */ |
974 | s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX; |
975 | pbdev->fh = pbdev->idx; |
976 | QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link); |
977 | g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev); |
978 | } else { |
979 | g_assert_not_reached(); |
980 | } |
981 | } |
982 | |
983 | static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, |
984 | Error **errp) |
985 | { |
986 | S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); |
987 | S390PCIBusDevice *pbdev = NULL; |
988 | |
989 | if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { |
990 | PCIDevice *pci_dev = PCI_DEVICE(dev); |
991 | PCIBus *bus; |
992 | int32_t devfn; |
993 | |
994 | pbdev = s390_pci_find_dev_by_pci(s, PCI_DEVICE(dev)); |
995 | g_assert(pbdev); |
996 | |
997 | s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, |
998 | pbdev->fh, pbdev->fid); |
999 | bus = pci_get_bus(pci_dev); |
1000 | devfn = pci_dev->devfn; |
1001 | object_property_set_bool(OBJECT(dev), false, "realized" , NULL); |
1002 | |
1003 | s390_pci_msix_free(pbdev); |
1004 | s390_pci_iommu_free(s, bus, devfn); |
1005 | pbdev->pdev = NULL; |
1006 | pbdev->state = ZPCI_FS_RESERVED; |
1007 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { |
1008 | pbdev = S390_PCI_DEVICE(dev); |
1009 | pbdev->fid = 0; |
1010 | QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); |
1011 | g_hash_table_remove(s->zpci_table, &pbdev->idx); |
1012 | object_property_set_bool(OBJECT(dev), false, "realized" , NULL); |
1013 | } |
1014 | } |
1015 | |
1016 | static void s390_pcihost_unplug_request(HotplugHandler *hotplug_dev, |
1017 | DeviceState *dev, |
1018 | Error **errp) |
1019 | { |
1020 | S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); |
1021 | S390PCIBusDevice *pbdev; |
1022 | |
1023 | if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { |
1024 | error_setg(errp, "PCI bridge hot unplug currently not supported" ); |
1025 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { |
1026 | /* |
1027 | * Redirect the unplug request to the zPCI device and remember that |
1028 | * we've checked the PCI device already (to prevent endless recursion). |
1029 | */ |
1030 | pbdev = s390_pci_find_dev_by_pci(s, PCI_DEVICE(dev)); |
1031 | g_assert(pbdev); |
1032 | pbdev->pci_unplug_request_processed = true; |
1033 | qdev_unplug(DEVICE(pbdev), errp); |
1034 | } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { |
1035 | pbdev = S390_PCI_DEVICE(dev); |
1036 | |
1037 | /* |
1038 | * If unplug was initially requested for the zPCI device, we |
1039 | * first have to redirect to the PCI device, which will in return |
1040 | * redirect back to us after performing its checks (if the request |
1041 | * is not blocked, e.g. because it's a PCI bridge). |
1042 | */ |
1043 | if (pbdev->pdev && !pbdev->pci_unplug_request_processed) { |
1044 | qdev_unplug(DEVICE(pbdev->pdev), errp); |
1045 | return; |
1046 | } |
1047 | pbdev->pci_unplug_request_processed = false; |
1048 | |
1049 | switch (pbdev->state) { |
1050 | case ZPCI_FS_STANDBY: |
1051 | case ZPCI_FS_RESERVED: |
1052 | s390_pci_perform_unplug(pbdev); |
1053 | break; |
1054 | default: |
1055 | /* |
1056 | * Allow to send multiple requests, e.g. if the guest crashed |
1057 | * before releasing the device, we would not be able to send |
1058 | * another request to the same VM (e.g. fresh OS). |
1059 | */ |
1060 | pbdev->unplug_requested = true; |
1061 | s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST, |
1062 | pbdev->fh, pbdev->fid); |
1063 | } |
1064 | } else { |
1065 | g_assert_not_reached(); |
1066 | } |
1067 | } |
1068 | |
1069 | static void s390_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev, |
1070 | void *opaque) |
1071 | { |
1072 | S390pciState *s = opaque; |
1073 | PCIBus *sec_bus = NULL; |
1074 | |
1075 | if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) != |
1076 | PCI_HEADER_TYPE_BRIDGE)) { |
1077 | return; |
1078 | } |
1079 | |
1080 | (s->bus_no)++; |
1081 | pci_default_write_config(pdev, PCI_PRIMARY_BUS, pci_dev_bus_num(pdev), 1); |
1082 | pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1); |
1083 | pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1); |
1084 | |
1085 | sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); |
1086 | if (!sec_bus) { |
1087 | return; |
1088 | } |
1089 | |
1090 | /* Assign numbers to all child bridges. The last is the highest number. */ |
1091 | pci_for_each_device(sec_bus, pci_bus_num(sec_bus), |
1092 | s390_pci_enumerate_bridge, s); |
1093 | pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1); |
1094 | } |
1095 | |
1096 | static void s390_pcihost_reset(DeviceState *dev) |
1097 | { |
1098 | S390pciState *s = S390_PCI_HOST_BRIDGE(dev); |
1099 | PCIBus *bus = s->parent_obj.bus; |
1100 | S390PCIBusDevice *pbdev, *next; |
1101 | |
1102 | /* Process all pending unplug requests */ |
1103 | QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) { |
1104 | if (pbdev->unplug_requested) { |
1105 | if (pbdev->summary_ind) { |
1106 | pci_dereg_irqs(pbdev); |
1107 | } |
1108 | if (pbdev->iommu->enabled) { |
1109 | pci_dereg_ioat(pbdev->iommu); |
1110 | } |
1111 | pbdev->state = ZPCI_FS_STANDBY; |
1112 | s390_pci_perform_unplug(pbdev); |
1113 | } |
1114 | } |
1115 | |
1116 | /* |
1117 | * When resetting a PCI bridge, the assigned numbers are set to 0. So |
1118 | * on every system reset, we also have to reassign numbers. |
1119 | */ |
1120 | s->bus_no = 0; |
1121 | pci_for_each_device(bus, pci_bus_num(bus), s390_pci_enumerate_bridge, s); |
1122 | } |
1123 | |
1124 | static void s390_pcihost_class_init(ObjectClass *klass, void *data) |
1125 | { |
1126 | DeviceClass *dc = DEVICE_CLASS(klass); |
1127 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); |
1128 | |
1129 | dc->reset = s390_pcihost_reset; |
1130 | dc->realize = s390_pcihost_realize; |
1131 | hc->pre_plug = s390_pcihost_pre_plug; |
1132 | hc->plug = s390_pcihost_plug; |
1133 | hc->unplug_request = s390_pcihost_unplug_request; |
1134 | hc->unplug = s390_pcihost_unplug; |
1135 | msi_nonbroken = true; |
1136 | } |
1137 | |
1138 | static const TypeInfo s390_pcihost_info = { |
1139 | .name = TYPE_S390_PCI_HOST_BRIDGE, |
1140 | .parent = TYPE_PCI_HOST_BRIDGE, |
1141 | .instance_size = sizeof(S390pciState), |
1142 | .class_init = s390_pcihost_class_init, |
1143 | .interfaces = (InterfaceInfo[]) { |
1144 | { TYPE_HOTPLUG_HANDLER }, |
1145 | { } |
1146 | } |
1147 | }; |
1148 | |
1149 | static const TypeInfo s390_pcibus_info = { |
1150 | .name = TYPE_S390_PCI_BUS, |
1151 | .parent = TYPE_BUS, |
1152 | .instance_size = sizeof(S390PCIBus), |
1153 | }; |
1154 | |
1155 | static uint16_t s390_pci_generate_uid(S390pciState *s) |
1156 | { |
1157 | uint16_t uid = 0; |
1158 | |
1159 | do { |
1160 | uid++; |
1161 | if (!s390_pci_find_dev_by_uid(s, uid)) { |
1162 | return uid; |
1163 | } |
1164 | } while (uid < ZPCI_MAX_UID); |
1165 | |
1166 | return UID_UNDEFINED; |
1167 | } |
1168 | |
1169 | static uint32_t s390_pci_generate_fid(S390pciState *s, Error **errp) |
1170 | { |
1171 | uint32_t fid = 0; |
1172 | |
1173 | do { |
1174 | if (!s390_pci_find_dev_by_fid(s, fid)) { |
1175 | return fid; |
1176 | } |
1177 | } while (fid++ != ZPCI_MAX_FID); |
1178 | |
1179 | error_setg(errp, "no free fid could be found" ); |
1180 | return 0; |
1181 | } |
1182 | |
1183 | static void s390_pci_device_realize(DeviceState *dev, Error **errp) |
1184 | { |
1185 | S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev); |
1186 | S390pciState *s = s390_get_phb(); |
1187 | |
1188 | if (!zpci->target) { |
1189 | error_setg(errp, "target must be defined" ); |
1190 | return; |
1191 | } |
1192 | |
1193 | if (s390_pci_find_dev_by_target(s, zpci->target)) { |
1194 | error_setg(errp, "target %s already has an associated zpci device" , |
1195 | zpci->target); |
1196 | return; |
1197 | } |
1198 | |
1199 | if (zpci->uid == UID_UNDEFINED) { |
1200 | zpci->uid = s390_pci_generate_uid(s); |
1201 | if (!zpci->uid) { |
1202 | error_setg(errp, "no free uid could be found" ); |
1203 | return; |
1204 | } |
1205 | } else if (s390_pci_find_dev_by_uid(s, zpci->uid)) { |
1206 | error_setg(errp, "uid %u already in use" , zpci->uid); |
1207 | return; |
1208 | } |
1209 | |
1210 | if (!zpci->fid_defined) { |
1211 | Error *local_error = NULL; |
1212 | |
1213 | zpci->fid = s390_pci_generate_fid(s, &local_error); |
1214 | if (local_error) { |
1215 | error_propagate(errp, local_error); |
1216 | return; |
1217 | } |
1218 | } else if (s390_pci_find_dev_by_fid(s, zpci->fid)) { |
1219 | error_setg(errp, "fid %u already in use" , zpci->fid); |
1220 | return; |
1221 | } |
1222 | |
1223 | zpci->state = ZPCI_FS_RESERVED; |
1224 | zpci->fmb.format = ZPCI_FMB_FORMAT; |
1225 | } |
1226 | |
1227 | static void s390_pci_device_reset(DeviceState *dev) |
1228 | { |
1229 | S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); |
1230 | |
1231 | switch (pbdev->state) { |
1232 | case ZPCI_FS_RESERVED: |
1233 | return; |
1234 | case ZPCI_FS_STANDBY: |
1235 | break; |
1236 | default: |
1237 | pbdev->fh &= ~FH_MASK_ENABLE; |
1238 | pbdev->state = ZPCI_FS_DISABLED; |
1239 | break; |
1240 | } |
1241 | |
1242 | if (pbdev->summary_ind) { |
1243 | pci_dereg_irqs(pbdev); |
1244 | } |
1245 | if (pbdev->iommu->enabled) { |
1246 | pci_dereg_ioat(pbdev->iommu); |
1247 | } |
1248 | |
1249 | fmb_timer_free(pbdev); |
1250 | } |
1251 | |
1252 | static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name, |
1253 | void *opaque, Error **errp) |
1254 | { |
1255 | Property *prop = opaque; |
1256 | uint32_t *ptr = qdev_get_prop_ptr(DEVICE(obj), prop); |
1257 | |
1258 | visit_type_uint32(v, name, ptr, errp); |
1259 | } |
1260 | |
1261 | static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name, |
1262 | void *opaque, Error **errp) |
1263 | { |
1264 | DeviceState *dev = DEVICE(obj); |
1265 | S390PCIBusDevice *zpci = S390_PCI_DEVICE(obj); |
1266 | Property *prop = opaque; |
1267 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
1268 | |
1269 | if (dev->realized) { |
1270 | qdev_prop_set_after_realize(dev, name, errp); |
1271 | return; |
1272 | } |
1273 | |
1274 | visit_type_uint32(v, name, ptr, errp); |
1275 | zpci->fid_defined = true; |
1276 | } |
1277 | |
1278 | static const PropertyInfo s390_pci_fid_propinfo = { |
1279 | .name = "zpci_fid" , |
1280 | .get = s390_pci_get_fid, |
1281 | .set = s390_pci_set_fid, |
1282 | }; |
1283 | |
1284 | #define DEFINE_PROP_S390_PCI_FID(_n, _s, _f) \ |
1285 | DEFINE_PROP(_n, _s, _f, s390_pci_fid_propinfo, uint32_t) |
1286 | |
1287 | static Property s390_pci_device_properties[] = { |
1288 | DEFINE_PROP_UINT16("uid" , S390PCIBusDevice, uid, UID_UNDEFINED), |
1289 | DEFINE_PROP_S390_PCI_FID("fid" , S390PCIBusDevice, fid), |
1290 | DEFINE_PROP_STRING("target" , S390PCIBusDevice, target), |
1291 | DEFINE_PROP_END_OF_LIST(), |
1292 | }; |
1293 | |
1294 | static const VMStateDescription s390_pci_device_vmstate = { |
1295 | .name = TYPE_S390_PCI_DEVICE, |
1296 | /* |
1297 | * TODO: add state handling here, so migration works at least with |
1298 | * emulated pci devices on s390x |
1299 | */ |
1300 | .unmigratable = 1, |
1301 | }; |
1302 | |
1303 | static void s390_pci_device_class_init(ObjectClass *klass, void *data) |
1304 | { |
1305 | DeviceClass *dc = DEVICE_CLASS(klass); |
1306 | |
1307 | dc->desc = "zpci device" ; |
1308 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
1309 | dc->reset = s390_pci_device_reset; |
1310 | dc->bus_type = TYPE_S390_PCI_BUS; |
1311 | dc->realize = s390_pci_device_realize; |
1312 | dc->props = s390_pci_device_properties; |
1313 | dc->vmsd = &s390_pci_device_vmstate; |
1314 | } |
1315 | |
1316 | static const TypeInfo s390_pci_device_info = { |
1317 | .name = TYPE_S390_PCI_DEVICE, |
1318 | .parent = TYPE_DEVICE, |
1319 | .instance_size = sizeof(S390PCIBusDevice), |
1320 | .class_init = s390_pci_device_class_init, |
1321 | }; |
1322 | |
1323 | static TypeInfo s390_pci_iommu_info = { |
1324 | .name = TYPE_S390_PCI_IOMMU, |
1325 | .parent = TYPE_OBJECT, |
1326 | .instance_size = sizeof(S390PCIIOMMU), |
1327 | }; |
1328 | |
1329 | static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data) |
1330 | { |
1331 | IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); |
1332 | |
1333 | imrc->translate = s390_translate_iommu; |
1334 | imrc->replay = s390_pci_iommu_replay; |
1335 | } |
1336 | |
1337 | static const TypeInfo s390_iommu_memory_region_info = { |
1338 | .parent = TYPE_IOMMU_MEMORY_REGION, |
1339 | .name = TYPE_S390_IOMMU_MEMORY_REGION, |
1340 | .class_init = s390_iommu_memory_region_class_init, |
1341 | }; |
1342 | |
1343 | static void s390_pci_register_types(void) |
1344 | { |
1345 | type_register_static(&s390_pcihost_info); |
1346 | type_register_static(&s390_pcibus_info); |
1347 | type_register_static(&s390_pci_device_info); |
1348 | type_register_static(&s390_pci_iommu_info); |
1349 | type_register_static(&s390_iommu_memory_region_info); |
1350 | } |
1351 | |
1352 | type_init(s390_pci_register_types) |
1353 | |