xref: /openbmc/qemu/hw/s390x/s390-pci-inst.c (revision b0cb0a66d6d535112aa513568ef21dcb1ad283ed)
1 /*
2  * s390 PCI instructions
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 "qemu-common.h"
16 #include "cpu.h"
17 #include "s390-pci-inst.h"
18 #include "s390-pci-bus.h"
19 #include "exec/memory-internal.h"
20 #include "qemu/error-report.h"
21 #include "sysemu/hw_accel.h"
22 
23 /* #define DEBUG_S390PCI_INST */
24 #ifdef DEBUG_S390PCI_INST
25 #define DPRINTF(fmt, ...) \
26     do { fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); } while (0)
27 #else
28 #define DPRINTF(fmt, ...) \
29     do { } while (0)
30 #endif
31 
32 static void s390_set_status_code(CPUS390XState *env,
33                                  uint8_t r, uint64_t status_code)
34 {
35     env->regs[r] &= ~0xff000000ULL;
36     env->regs[r] |= (status_code & 0xff) << 24;
37 }
38 
39 static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
40 {
41     S390PCIBusDevice *pbdev = NULL;
42     uint32_t res_code, initial_l2, g_l2;
43     int rc, i;
44     uint64_t resume_token;
45 
46     rc = 0;
47     if (lduw_p(&rrb->request.hdr.len) != 32) {
48         res_code = CLP_RC_LEN;
49         rc = -EINVAL;
50         goto out;
51     }
52 
53     if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
54         res_code = CLP_RC_FMT;
55         rc = -EINVAL;
56         goto out;
57     }
58 
59     if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
60         ldq_p(&rrb->request.reserved1) != 0) {
61         res_code = CLP_RC_RESNOT0;
62         rc = -EINVAL;
63         goto out;
64     }
65 
66     resume_token = ldq_p(&rrb->request.resume_token);
67 
68     if (resume_token) {
69         pbdev = s390_pci_find_dev_by_idx(resume_token);
70         if (!pbdev) {
71             res_code = CLP_RC_LISTPCI_BADRT;
72             rc = -EINVAL;
73             goto out;
74         }
75     } else {
76         pbdev = s390_pci_find_next_avail_dev(NULL);
77     }
78 
79     if (lduw_p(&rrb->response.hdr.len) < 48) {
80         res_code = CLP_RC_8K;
81         rc = -EINVAL;
82         goto out;
83     }
84 
85     initial_l2 = lduw_p(&rrb->response.hdr.len);
86     if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry)
87         != 0) {
88         res_code = CLP_RC_LEN;
89         rc = -EINVAL;
90         *cc = 3;
91         goto out;
92     }
93 
94     stl_p(&rrb->response.fmt, 0);
95     stq_p(&rrb->response.reserved1, 0);
96     stl_p(&rrb->response.mdd, FH_MASK_SHM);
97     stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
98     rrb->response.flags = UID_CHECKING_ENABLED;
99     rrb->response.entry_size = sizeof(ClpFhListEntry);
100 
101     i = 0;
102     g_l2 = LIST_PCI_HDR_LEN;
103     while (g_l2 < initial_l2 && pbdev) {
104         stw_p(&rrb->response.fh_list[i].device_id,
105             pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
106         stw_p(&rrb->response.fh_list[i].vendor_id,
107             pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
108         /* Ignore RESERVED devices. */
109         stl_p(&rrb->response.fh_list[i].config,
110             pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31);
111         stl_p(&rrb->response.fh_list[i].fid, pbdev->fid);
112         stl_p(&rrb->response.fh_list[i].fh, pbdev->fh);
113 
114         g_l2 += sizeof(ClpFhListEntry);
115         /* Add endian check for DPRINTF? */
116         DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n",
117                 g_l2,
118                 lduw_p(&rrb->response.fh_list[i].vendor_id),
119                 lduw_p(&rrb->response.fh_list[i].device_id),
120                 ldl_p(&rrb->response.fh_list[i].fid),
121                 ldl_p(&rrb->response.fh_list[i].fh));
122         pbdev = s390_pci_find_next_avail_dev(pbdev);
123         i++;
124     }
125 
126     if (!pbdev) {
127         resume_token = 0;
128     } else {
129         resume_token = pbdev->fh & FH_MASK_INDEX;
130     }
131     stq_p(&rrb->response.resume_token, resume_token);
132     stw_p(&rrb->response.hdr.len, g_l2);
133     stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
134 out:
135     if (rc) {
136         DPRINTF("list pci failed rc 0x%x\n", rc);
137         stw_p(&rrb->response.hdr.rsp, res_code);
138     }
139     return rc;
140 }
141 
142 int clp_service_call(S390CPU *cpu, uint8_t r2)
143 {
144     ClpReqHdr *reqh;
145     ClpRspHdr *resh;
146     S390PCIBusDevice *pbdev;
147     uint32_t req_len;
148     uint32_t res_len;
149     uint8_t buffer[4096 * 2];
150     uint8_t cc = 0;
151     CPUS390XState *env = &cpu->env;
152     int i;
153 
154     cpu_synchronize_state(CPU(cpu));
155 
156     if (env->psw.mask & PSW_MASK_PSTATE) {
157         program_interrupt(env, PGM_PRIVILEGED, 4);
158         return 0;
159     }
160 
161     if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) {
162         return 0;
163     }
164     reqh = (ClpReqHdr *)buffer;
165     req_len = lduw_p(&reqh->len);
166     if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
167         program_interrupt(env, PGM_OPERAND, 4);
168         return 0;
169     }
170 
171     if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
172                                req_len + sizeof(*resh))) {
173         return 0;
174     }
175     resh = (ClpRspHdr *)(buffer + req_len);
176     res_len = lduw_p(&resh->len);
177     if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
178         program_interrupt(env, PGM_OPERAND, 4);
179         return 0;
180     }
181     if ((req_len + res_len) > 8192) {
182         program_interrupt(env, PGM_OPERAND, 4);
183         return 0;
184     }
185 
186     if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
187                                req_len + res_len)) {
188         return 0;
189     }
190 
191     if (req_len != 32) {
192         stw_p(&resh->rsp, CLP_RC_LEN);
193         goto out;
194     }
195 
196     switch (lduw_p(&reqh->cmd)) {
197     case CLP_LIST_PCI: {
198         ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer;
199         list_pci(rrb, &cc);
200         break;
201     }
202     case CLP_SET_PCI_FN: {
203         ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
204         ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
205 
206         pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqsetpci->fh));
207         if (!pbdev) {
208                 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
209                 goto out;
210         }
211 
212         switch (reqsetpci->oc) {
213         case CLP_SET_ENABLE_PCI_FN:
214             switch (reqsetpci->ndas) {
215             case 0:
216                 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS);
217                 goto out;
218             case 1:
219                 break;
220             default:
221                 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES);
222                 goto out;
223             }
224 
225             if (pbdev->fh & FH_MASK_ENABLE) {
226                 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
227                 goto out;
228             }
229 
230             pbdev->fh |= FH_MASK_ENABLE;
231             pbdev->state = ZPCI_FS_ENABLED;
232             stl_p(&ressetpci->fh, pbdev->fh);
233             stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
234             break;
235         case CLP_SET_DISABLE_PCI_FN:
236             if (!(pbdev->fh & FH_MASK_ENABLE)) {
237                 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
238                 goto out;
239             }
240             device_reset(DEVICE(pbdev));
241             pbdev->fh &= ~FH_MASK_ENABLE;
242             pbdev->state = ZPCI_FS_DISABLED;
243             stl_p(&ressetpci->fh, pbdev->fh);
244             stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
245             break;
246         default:
247             DPRINTF("unknown set pci command\n");
248             stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
249             break;
250         }
251         break;
252     }
253     case CLP_QUERY_PCI_FN: {
254         ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
255         ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
256 
257         pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqquery->fh));
258         if (!pbdev) {
259             DPRINTF("query pci no pci dev\n");
260             stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
261             goto out;
262         }
263 
264         for (i = 0; i < PCI_BAR_COUNT; i++) {
265             uint32_t data = pci_get_long(pbdev->pdev->config +
266                 PCI_BASE_ADDRESS_0 + (i * 4));
267 
268             stl_p(&resquery->bar[i], data);
269             resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
270                                     ctz64(pbdev->pdev->io_regions[i].size) : 0;
271             DPRINTF("bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x\n", i,
272                     ldl_p(&resquery->bar[i]),
273                     pbdev->pdev->io_regions[i].size,
274                     resquery->bar_size[i]);
275         }
276 
277         stq_p(&resquery->sdma, ZPCI_SDMA_ADDR);
278         stq_p(&resquery->edma, ZPCI_EDMA_ADDR);
279         stl_p(&resquery->fid, pbdev->fid);
280         stw_p(&resquery->pchid, 0);
281         stw_p(&resquery->ug, 1);
282         stl_p(&resquery->uid, pbdev->uid);
283         stw_p(&resquery->hdr.rsp, CLP_RC_OK);
284         break;
285     }
286     case CLP_QUERY_PCI_FNGRP: {
287         ClpRspQueryPciGrp *resgrp = (ClpRspQueryPciGrp *)resh;
288         resgrp->fr = 1;
289         stq_p(&resgrp->dasm, 0);
290         stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
291         stw_p(&resgrp->mui, 0);
292         stw_p(&resgrp->i, 128);
293         resgrp->version = 0;
294 
295         stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
296         break;
297     }
298     default:
299         DPRINTF("unknown clp command\n");
300         stw_p(&resh->rsp, CLP_RC_CMD);
301         break;
302     }
303 
304 out:
305     if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer,
306                                 req_len + res_len)) {
307         return 0;
308     }
309     setcc(cpu, cc);
310     return 0;
311 }
312 
313 int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
314 {
315     CPUS390XState *env = &cpu->env;
316     S390PCIBusDevice *pbdev;
317     uint64_t offset;
318     uint64_t data;
319     MemoryRegion *mr;
320     MemTxResult result;
321     uint8_t len;
322     uint32_t fh;
323     uint8_t pcias;
324 
325     cpu_synchronize_state(CPU(cpu));
326 
327     if (env->psw.mask & PSW_MASK_PSTATE) {
328         program_interrupt(env, PGM_PRIVILEGED, 4);
329         return 0;
330     }
331 
332     if (r2 & 0x1) {
333         program_interrupt(env, PGM_SPECIFICATION, 4);
334         return 0;
335     }
336 
337     fh = env->regs[r2] >> 32;
338     pcias = (env->regs[r2] >> 16) & 0xf;
339     len = env->regs[r2] & 0xf;
340     offset = env->regs[r2 + 1];
341 
342     pbdev = s390_pci_find_dev_by_fh(fh);
343     if (!pbdev) {
344         DPRINTF("pcilg no pci dev\n");
345         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
346         return 0;
347     }
348 
349     switch (pbdev->state) {
350     case ZPCI_FS_RESERVED:
351     case ZPCI_FS_STANDBY:
352     case ZPCI_FS_DISABLED:
353     case ZPCI_FS_PERMANENT_ERROR:
354         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
355         return 0;
356     case ZPCI_FS_ERROR:
357         setcc(cpu, ZPCI_PCI_LS_ERR);
358         s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
359         return 0;
360     default:
361         break;
362     }
363 
364     if (pcias < 6) {
365         if ((8 - (offset & 0x7)) < len) {
366             program_interrupt(env, PGM_OPERAND, 4);
367             return 0;
368         }
369         mr = pbdev->pdev->io_regions[pcias].memory;
370         result = memory_region_dispatch_read(mr, offset, &data, len,
371                                              MEMTXATTRS_UNSPECIFIED);
372         if (result != MEMTX_OK) {
373             program_interrupt(env, PGM_OPERAND, 4);
374             return 0;
375         }
376     } else if (pcias == 15) {
377         if ((4 - (offset & 0x3)) < len) {
378             program_interrupt(env, PGM_OPERAND, 4);
379             return 0;
380         }
381         data =  pci_host_config_read_common(
382                    pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
383 
384         switch (len) {
385         case 1:
386             break;
387         case 2:
388             data = bswap16(data);
389             break;
390         case 4:
391             data = bswap32(data);
392             break;
393         case 8:
394             data = bswap64(data);
395             break;
396         default:
397             program_interrupt(env, PGM_OPERAND, 4);
398             return 0;
399         }
400     } else {
401         DPRINTF("invalid space\n");
402         setcc(cpu, ZPCI_PCI_LS_ERR);
403         s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
404         return 0;
405     }
406 
407     env->regs[r1] = data;
408     setcc(cpu, ZPCI_PCI_LS_OK);
409     return 0;
410 }
411 
412 static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset,
413                                        uint64_t *data, uint8_t len)
414 {
415     uint32_t val;
416     uint8_t *msg_data;
417 
418     if (offset % PCI_MSIX_ENTRY_SIZE != 8) {
419         return;
420     }
421 
422     if (len != 4) {
423         DPRINTF("access msix table msg data but len is %d\n", len);
424         return;
425     }
426 
427     msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE +
428                PCI_MSIX_ENTRY_VECTOR_CTRL;
429     val = pci_get_long(msg_data) |
430         ((pbdev->fh & FH_MASK_INDEX) << ZPCI_MSI_VEC_BITS);
431     pci_set_long(msg_data, val);
432     DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data);
433 }
434 
435 static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias)
436 {
437     if (pbdev->msix.available && pbdev->msix.table_bar == pcias &&
438         offset >= pbdev->msix.table_offset &&
439         offset <= pbdev->msix.table_offset +
440                   (pbdev->msix.entries - 1) * PCI_MSIX_ENTRY_SIZE) {
441         return 1;
442     } else {
443         return 0;
444     }
445 }
446 
447 int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
448 {
449     CPUS390XState *env = &cpu->env;
450     uint64_t offset, data;
451     S390PCIBusDevice *pbdev;
452     MemoryRegion *mr;
453     MemTxResult result;
454     uint8_t len;
455     uint32_t fh;
456     uint8_t pcias;
457 
458     cpu_synchronize_state(CPU(cpu));
459 
460     if (env->psw.mask & PSW_MASK_PSTATE) {
461         program_interrupt(env, PGM_PRIVILEGED, 4);
462         return 0;
463     }
464 
465     if (r2 & 0x1) {
466         program_interrupt(env, PGM_SPECIFICATION, 4);
467         return 0;
468     }
469 
470     fh = env->regs[r2] >> 32;
471     pcias = (env->regs[r2] >> 16) & 0xf;
472     len = env->regs[r2] & 0xf;
473     offset = env->regs[r2 + 1];
474 
475     pbdev = s390_pci_find_dev_by_fh(fh);
476     if (!pbdev) {
477         DPRINTF("pcistg no pci dev\n");
478         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
479         return 0;
480     }
481 
482     switch (pbdev->state) {
483     case ZPCI_FS_RESERVED:
484     case ZPCI_FS_STANDBY:
485     case ZPCI_FS_DISABLED:
486     case ZPCI_FS_PERMANENT_ERROR:
487         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
488         return 0;
489     case ZPCI_FS_ERROR:
490         setcc(cpu, ZPCI_PCI_LS_ERR);
491         s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
492         return 0;
493     default:
494         break;
495     }
496 
497     data = env->regs[r1];
498     if (pcias < 6) {
499         if ((8 - (offset & 0x7)) < len) {
500             program_interrupt(env, PGM_OPERAND, 4);
501             return 0;
502         }
503 
504         if (trap_msix(pbdev, offset, pcias)) {
505             offset = offset - pbdev->msix.table_offset;
506             mr = &pbdev->pdev->msix_table_mmio;
507             update_msix_table_msg_data(pbdev, offset, &data, len);
508         } else {
509             mr = pbdev->pdev->io_regions[pcias].memory;
510         }
511 
512         result = memory_region_dispatch_write(mr, offset, data, len,
513                                      MEMTXATTRS_UNSPECIFIED);
514         if (result != MEMTX_OK) {
515             program_interrupt(env, PGM_OPERAND, 4);
516             return 0;
517         }
518     } else if (pcias == 15) {
519         if ((4 - (offset & 0x3)) < len) {
520             program_interrupt(env, PGM_OPERAND, 4);
521             return 0;
522         }
523         switch (len) {
524         case 1:
525             break;
526         case 2:
527             data = bswap16(data);
528             break;
529         case 4:
530             data = bswap32(data);
531             break;
532         case 8:
533             data = bswap64(data);
534             break;
535         default:
536             program_interrupt(env, PGM_OPERAND, 4);
537             return 0;
538         }
539 
540         pci_host_config_write_common(pbdev->pdev, offset,
541                                      pci_config_size(pbdev->pdev),
542                                      data, len);
543     } else {
544         DPRINTF("pcistg invalid space\n");
545         setcc(cpu, ZPCI_PCI_LS_ERR);
546         s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
547         return 0;
548     }
549 
550     setcc(cpu, ZPCI_PCI_LS_OK);
551     return 0;
552 }
553 
554 int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
555 {
556     CPUS390XState *env = &cpu->env;
557     uint32_t fh;
558     S390PCIBusDevice *pbdev;
559     hwaddr start, end;
560     IOMMUTLBEntry entry;
561     MemoryRegion *mr;
562 
563     cpu_synchronize_state(CPU(cpu));
564 
565     if (env->psw.mask & PSW_MASK_PSTATE) {
566         program_interrupt(env, PGM_PRIVILEGED, 4);
567         goto out;
568     }
569 
570     if (r2 & 0x1) {
571         program_interrupt(env, PGM_SPECIFICATION, 4);
572         goto out;
573     }
574 
575     fh = env->regs[r1] >> 32;
576     start = env->regs[r2];
577     end = start + env->regs[r2 + 1];
578 
579     pbdev = s390_pci_find_dev_by_fh(fh);
580     if (!pbdev) {
581         DPRINTF("rpcit no pci dev\n");
582         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
583         goto out;
584     }
585 
586     switch (pbdev->state) {
587     case ZPCI_FS_RESERVED:
588     case ZPCI_FS_STANDBY:
589     case ZPCI_FS_DISABLED:
590     case ZPCI_FS_PERMANENT_ERROR:
591         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
592         return 0;
593     case ZPCI_FS_ERROR:
594         setcc(cpu, ZPCI_PCI_LS_ERR);
595         s390_set_status_code(env, r1, ZPCI_MOD_ST_ERROR_RECOVER);
596         return 0;
597     default:
598         break;
599     }
600 
601     if (!pbdev->g_iota) {
602         pbdev->state = ZPCI_FS_ERROR;
603         setcc(cpu, ZPCI_PCI_LS_ERR);
604         s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
605         s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
606                                       start, 0);
607         goto out;
608     }
609 
610     if (end < pbdev->pba || start > pbdev->pal) {
611         pbdev->state = ZPCI_FS_ERROR;
612         setcc(cpu, ZPCI_PCI_LS_ERR);
613         s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
614         s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
615                                       start, 0);
616         goto out;
617     }
618 
619     mr = &pbdev->iommu_mr;
620     while (start < end) {
621         entry = mr->iommu_ops->translate(mr, start, 0);
622 
623         if (!entry.translated_addr) {
624             pbdev->state = ZPCI_FS_ERROR;
625             setcc(cpu, ZPCI_PCI_LS_ERR);
626             s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
627             s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
628                                           start, ERR_EVENT_Q_BIT);
629             goto out;
630         }
631 
632         memory_region_notify_iommu(mr, entry);
633         start += entry.addr_mask + 1;
634     }
635 
636     setcc(cpu, ZPCI_PCI_LS_OK);
637 out:
638     return 0;
639 }
640 
641 int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
642                         uint8_t ar)
643 {
644     CPUS390XState *env = &cpu->env;
645     S390PCIBusDevice *pbdev;
646     MemoryRegion *mr;
647     MemTxResult result;
648     int i;
649     uint32_t fh;
650     uint8_t pcias;
651     uint8_t len;
652     uint8_t buffer[128];
653 
654     if (env->psw.mask & PSW_MASK_PSTATE) {
655         program_interrupt(env, PGM_PRIVILEGED, 6);
656         return 0;
657     }
658 
659     fh = env->regs[r1] >> 32;
660     pcias = (env->regs[r1] >> 16) & 0xf;
661     len = env->regs[r1] & 0xff;
662 
663     if (pcias > 5) {
664         DPRINTF("pcistb invalid space\n");
665         setcc(cpu, ZPCI_PCI_LS_ERR);
666         s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
667         return 0;
668     }
669 
670     switch (len) {
671     case 16:
672     case 32:
673     case 64:
674     case 128:
675         break;
676     default:
677         program_interrupt(env, PGM_SPECIFICATION, 6);
678         return 0;
679     }
680 
681     pbdev = s390_pci_find_dev_by_fh(fh);
682     if (!pbdev) {
683         DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
684         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
685         return 0;
686     }
687 
688     switch (pbdev->state) {
689     case ZPCI_FS_RESERVED:
690     case ZPCI_FS_STANDBY:
691     case ZPCI_FS_DISABLED:
692     case ZPCI_FS_PERMANENT_ERROR:
693         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
694         return 0;
695     case ZPCI_FS_ERROR:
696         setcc(cpu, ZPCI_PCI_LS_ERR);
697         s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
698         return 0;
699     default:
700         break;
701     }
702 
703     mr = pbdev->pdev->io_regions[pcias].memory;
704     if (!memory_region_access_valid(mr, env->regs[r3], len, true)) {
705         program_interrupt(env, PGM_OPERAND, 6);
706         return 0;
707     }
708 
709     if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) {
710         return 0;
711     }
712 
713     for (i = 0; i < len / 8; i++) {
714         result = memory_region_dispatch_write(mr, env->regs[r3] + i * 8,
715                                      ldq_p(buffer + i * 8), 8,
716                                      MEMTXATTRS_UNSPECIFIED);
717         if (result != MEMTX_OK) {
718             program_interrupt(env, PGM_OPERAND, 6);
719             return 0;
720         }
721     }
722 
723     setcc(cpu, ZPCI_PCI_LS_OK);
724     return 0;
725 }
726 
727 static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
728 {
729     int ret, len;
730 
731     ret = css_register_io_adapter(S390_PCIPT_ADAPTER,
732                                   FIB_DATA_ISC(ldl_p(&fib.data)), true, false,
733                                   &pbdev->routes.adapter.adapter_id);
734     assert(ret == 0);
735 
736     pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
737     len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
738     pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
739 
740     ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
741     if (ret) {
742         goto out;
743     }
744 
745     ret = map_indicator(&pbdev->routes.adapter, pbdev->indicator);
746     if (ret) {
747         goto out;
748     }
749 
750     pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
751     pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
752     pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
753     pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
754     pbdev->isc = FIB_DATA_ISC(ldl_p(&fib.data));
755     pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
756     pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
757 
758     DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
759     return 0;
760 out:
761     release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
762     release_indicator(&pbdev->routes.adapter, pbdev->indicator);
763     pbdev->summary_ind = NULL;
764     pbdev->indicator = NULL;
765     return ret;
766 }
767 
768 int pci_dereg_irqs(S390PCIBusDevice *pbdev)
769 {
770     release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
771     release_indicator(&pbdev->routes.adapter, pbdev->indicator);
772 
773     pbdev->summary_ind = NULL;
774     pbdev->indicator = NULL;
775     pbdev->routes.adapter.summary_addr = 0;
776     pbdev->routes.adapter.summary_offset = 0;
777     pbdev->routes.adapter.ind_addr = 0;
778     pbdev->routes.adapter.ind_offset = 0;
779     pbdev->isc = 0;
780     pbdev->noi = 0;
781     pbdev->sum = 0;
782 
783     DPRINTF("dereg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
784     return 0;
785 }
786 
787 static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
788 {
789     uint64_t pba = ldq_p(&fib.pba);
790     uint64_t pal = ldq_p(&fib.pal);
791     uint64_t g_iota = ldq_p(&fib.iota);
792     uint8_t dt = (g_iota >> 2) & 0x7;
793     uint8_t t = (g_iota >> 11) & 0x1;
794 
795     if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) {
796         program_interrupt(env, PGM_OPERAND, 6);
797         return -EINVAL;
798     }
799 
800     /* currently we only support designation type 1 with translation */
801     if (!(dt == ZPCI_IOTA_RTTO && t)) {
802         error_report("unsupported ioat dt %d t %d", dt, t);
803         program_interrupt(env, PGM_OPERAND, 6);
804         return -EINVAL;
805     }
806 
807     pbdev->pba = pba;
808     pbdev->pal = pal;
809     pbdev->g_iota = g_iota;
810 
811     s390_pci_iommu_enable(pbdev);
812 
813     return 0;
814 }
815 
816 void pci_dereg_ioat(S390PCIBusDevice *pbdev)
817 {
818     s390_pci_iommu_disable(pbdev);
819     pbdev->pba = 0;
820     pbdev->pal = 0;
821     pbdev->g_iota = 0;
822 }
823 
824 int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
825 {
826     CPUS390XState *env = &cpu->env;
827     uint8_t oc, dmaas;
828     uint32_t fh;
829     ZpciFib fib;
830     S390PCIBusDevice *pbdev;
831     uint64_t cc = ZPCI_PCI_LS_OK;
832 
833     if (env->psw.mask & PSW_MASK_PSTATE) {
834         program_interrupt(env, PGM_PRIVILEGED, 6);
835         return 0;
836     }
837 
838     oc = env->regs[r1] & 0xff;
839     dmaas = (env->regs[r1] >> 16) & 0xff;
840     fh = env->regs[r1] >> 32;
841 
842     if (fiba & 0x7) {
843         program_interrupt(env, PGM_SPECIFICATION, 6);
844         return 0;
845     }
846 
847     pbdev = s390_pci_find_dev_by_fh(fh);
848     if (!pbdev) {
849         DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
850         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
851         return 0;
852     }
853 
854     switch (pbdev->state) {
855     case ZPCI_FS_RESERVED:
856     case ZPCI_FS_STANDBY:
857     case ZPCI_FS_DISABLED:
858     case ZPCI_FS_PERMANENT_ERROR:
859         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
860         return 0;
861     default:
862         break;
863     }
864 
865     if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
866         return 0;
867     }
868 
869     if (fib.fmt != 0) {
870         program_interrupt(env, PGM_OPERAND, 6);
871         return 0;
872     }
873 
874     switch (oc) {
875     case ZPCI_MOD_FC_REG_INT:
876         if (pbdev->summary_ind) {
877             cc = ZPCI_PCI_LS_ERR;
878             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
879         } else if (reg_irqs(env, pbdev, fib)) {
880             cc = ZPCI_PCI_LS_ERR;
881             s390_set_status_code(env, r1, ZPCI_MOD_ST_RES_NOT_AVAIL);
882         }
883         break;
884     case ZPCI_MOD_FC_DEREG_INT:
885         if (!pbdev->summary_ind) {
886             cc = ZPCI_PCI_LS_ERR;
887             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
888         } else {
889             pci_dereg_irqs(pbdev);
890         }
891         break;
892     case ZPCI_MOD_FC_REG_IOAT:
893         if (dmaas != 0) {
894             cc = ZPCI_PCI_LS_ERR;
895             s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
896         } else if (pbdev->iommu_enabled) {
897             cc = ZPCI_PCI_LS_ERR;
898             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
899         } else if (reg_ioat(env, pbdev, fib)) {
900             cc = ZPCI_PCI_LS_ERR;
901             s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
902         }
903         break;
904     case ZPCI_MOD_FC_DEREG_IOAT:
905         if (dmaas != 0) {
906             cc = ZPCI_PCI_LS_ERR;
907             s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
908         } else if (!pbdev->iommu_enabled) {
909             cc = ZPCI_PCI_LS_ERR;
910             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
911         } else {
912             pci_dereg_ioat(pbdev);
913         }
914         break;
915     case ZPCI_MOD_FC_REREG_IOAT:
916         if (dmaas != 0) {
917             cc = ZPCI_PCI_LS_ERR;
918             s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
919         } else if (!pbdev->iommu_enabled) {
920             cc = ZPCI_PCI_LS_ERR;
921             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
922         } else {
923             pci_dereg_ioat(pbdev);
924             if (reg_ioat(env, pbdev, fib)) {
925                 cc = ZPCI_PCI_LS_ERR;
926                 s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
927             }
928         }
929         break;
930     case ZPCI_MOD_FC_RESET_ERROR:
931         switch (pbdev->state) {
932         case ZPCI_FS_BLOCKED:
933         case ZPCI_FS_ERROR:
934             pbdev->state = ZPCI_FS_ENABLED;
935             break;
936         default:
937             cc = ZPCI_PCI_LS_ERR;
938             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
939         }
940         break;
941     case ZPCI_MOD_FC_RESET_BLOCK:
942         switch (pbdev->state) {
943         case ZPCI_FS_ERROR:
944             pbdev->state = ZPCI_FS_BLOCKED;
945             break;
946         default:
947             cc = ZPCI_PCI_LS_ERR;
948             s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
949         }
950         break;
951     case ZPCI_MOD_FC_SET_MEASURE:
952         pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
953         break;
954     default:
955         program_interrupt(&cpu->env, PGM_OPERAND, 6);
956         cc = ZPCI_PCI_LS_ERR;
957     }
958 
959     setcc(cpu, cc);
960     return 0;
961 }
962 
963 int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
964 {
965     CPUS390XState *env = &cpu->env;
966     uint8_t dmaas;
967     uint32_t fh;
968     ZpciFib fib;
969     S390PCIBusDevice *pbdev;
970     uint32_t data;
971     uint64_t cc = ZPCI_PCI_LS_OK;
972 
973     if (env->psw.mask & PSW_MASK_PSTATE) {
974         program_interrupt(env, PGM_PRIVILEGED, 6);
975         return 0;
976     }
977 
978     fh = env->regs[r1] >> 32;
979     dmaas = (env->regs[r1] >> 16) & 0xff;
980 
981     if (dmaas) {
982         setcc(cpu, ZPCI_PCI_LS_ERR);
983         s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_INVAL_DMAAS);
984         return 0;
985     }
986 
987     if (fiba & 0x7) {
988         program_interrupt(env, PGM_SPECIFICATION, 6);
989         return 0;
990     }
991 
992     pbdev = s390_pci_find_dev_by_idx(fh & FH_MASK_INDEX);
993     if (!pbdev) {
994         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
995         return 0;
996     }
997 
998     memset(&fib, 0, sizeof(fib));
999 
1000     switch (pbdev->state) {
1001     case ZPCI_FS_RESERVED:
1002     case ZPCI_FS_STANDBY:
1003         setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
1004         return 0;
1005     case ZPCI_FS_DISABLED:
1006         if (fh & FH_MASK_ENABLE) {
1007             setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
1008             return 0;
1009         }
1010         goto out;
1011     /* BLOCKED bit is set to one coincident with the setting of ERROR bit.
1012      * FH Enabled bit is set to one in states of ENABLED, BLOCKED or ERROR. */
1013     case ZPCI_FS_ERROR:
1014         fib.fc |= 0x20;
1015     case ZPCI_FS_BLOCKED:
1016         fib.fc |= 0x40;
1017     case ZPCI_FS_ENABLED:
1018         fib.fc |= 0x80;
1019         if (pbdev->iommu_enabled) {
1020             fib.fc |= 0x10;
1021         }
1022         if (!(fh & FH_MASK_ENABLE)) {
1023             env->regs[r1] |= 1ULL << 63;
1024         }
1025         break;
1026     case ZPCI_FS_PERMANENT_ERROR:
1027         setcc(cpu, ZPCI_PCI_LS_ERR);
1028         s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_PERM_ERROR);
1029         return 0;
1030     }
1031 
1032     stq_p(&fib.pba, pbdev->pba);
1033     stq_p(&fib.pal, pbdev->pal);
1034     stq_p(&fib.iota, pbdev->g_iota);
1035     stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
1036     stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
1037     stq_p(&fib.fmb_addr, pbdev->fmb_addr);
1038 
1039     data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) |
1040            ((uint32_t)pbdev->routes.adapter.ind_offset << 8) |
1041            ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
1042     stl_p(&fib.data, data);
1043 
1044 out:
1045     if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
1046         return 0;
1047     }
1048 
1049     setcc(cpu, cc);
1050     return 0;
1051 }
1052