xref: /qemu/util/s390x_pci_mmio.c (revision ec7e5a90fea996f04ea24e81b680a87bc975354a)
1 /*
2  * s390x PCI MMIO definitions
3  *
4  * Copyright 2025 IBM Corp.
5  * Author(s): Farhan Ali <alifm@linux.ibm.com>
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9 
10 #include "qemu/osdep.h"
11 #include <sys/syscall.h>
12 #include "qemu/s390x_pci_mmio.h"
13 #include "elf.h"
14 
15 union register_pair {
16     unsigned __int128 pair;
17     struct {
18         uint64_t even;
19         uint64_t odd;
20     };
21 };
22 
23 static bool is_mio_supported;
24 
25 static __attribute__((constructor)) void check_is_mio_supported(void)
26 {
27     is_mio_supported = !!(qemu_getauxval(AT_HWCAP) & HWCAP_S390_PCI_MIO);
28 }
29 
30 static uint64_t s390x_pcilgi(const void *ioaddr, size_t len)
31 {
32     union register_pair ioaddr_len = { .even = (uint64_t)ioaddr,
33                                        .odd = len };
34     uint64_t val;
35     int cc;
36 
37     asm volatile(
38         /* pcilgi */
39         ".insn   rre,0xb9d60000,%[val],%[ioaddr_len]\n"
40         "ipm     %[cc]\n"
41         "srl     %[cc],28\n"
42         : [cc] "=d"(cc), [val] "=d"(val),
43         [ioaddr_len] "+d"(ioaddr_len.pair) :: "cc");
44 
45     if (cc) {
46         val = -1ULL;
47     }
48 
49     return val;
50 }
51 
52 static void s390x_pcistgi(void *ioaddr, uint64_t val, size_t len)
53 {
54     union register_pair ioaddr_len = {.even = (uint64_t)ioaddr, .odd = len};
55 
56     asm volatile (
57         /* pcistgi */
58         ".insn   rre,0xb9d40000,%[val],%[ioaddr_len]\n"
59         : [ioaddr_len] "+d" (ioaddr_len.pair)
60         : [val] "d" (val)
61         : "cc", "memory");
62 }
63 
64 uint8_t s390x_pci_mmio_read_8(const void *ioaddr)
65 {
66     uint8_t val = 0;
67 
68     if (is_mio_supported) {
69         val = s390x_pcilgi(ioaddr, sizeof(val));
70     } else {
71         syscall(__NR_s390_pci_mmio_read, ioaddr, &val, sizeof(val));
72     }
73     return val;
74 }
75 
76 uint16_t s390x_pci_mmio_read_16(const void *ioaddr)
77 {
78     uint16_t val = 0;
79 
80     if (is_mio_supported) {
81         val = s390x_pcilgi(ioaddr, sizeof(val));
82     } else {
83         syscall(__NR_s390_pci_mmio_read, ioaddr, &val, sizeof(val));
84     }
85     return val;
86 }
87 
88 uint32_t s390x_pci_mmio_read_32(const void *ioaddr)
89 {
90     uint32_t val = 0;
91 
92     if (is_mio_supported) {
93         val = s390x_pcilgi(ioaddr, sizeof(val));
94     } else {
95         syscall(__NR_s390_pci_mmio_read, ioaddr, &val, sizeof(val));
96     }
97     return val;
98 }
99 
100 uint64_t s390x_pci_mmio_read_64(const void *ioaddr)
101 {
102     uint64_t val = 0;
103 
104     if (is_mio_supported) {
105         val = s390x_pcilgi(ioaddr, sizeof(val));
106     } else {
107         syscall(__NR_s390_pci_mmio_read, ioaddr, &val, sizeof(val));
108     }
109     return val;
110 }
111 
112 void s390x_pci_mmio_write_8(void *ioaddr, uint8_t val)
113 {
114     if (is_mio_supported) {
115         s390x_pcistgi(ioaddr, val, sizeof(val));
116     } else {
117         syscall(__NR_s390_pci_mmio_write, ioaddr, &val, sizeof(val));
118     }
119 }
120 
121 void s390x_pci_mmio_write_16(void *ioaddr, uint16_t val)
122 {
123     if (is_mio_supported) {
124         s390x_pcistgi(ioaddr, val, sizeof(val));
125     } else {
126         syscall(__NR_s390_pci_mmio_write, ioaddr, &val, sizeof(val));
127     }
128 }
129 
130 void s390x_pci_mmio_write_32(void *ioaddr, uint32_t val)
131 {
132     if (is_mio_supported) {
133         s390x_pcistgi(ioaddr, val, sizeof(val));
134     } else {
135         syscall(__NR_s390_pci_mmio_write, ioaddr, &val, sizeof(val));
136     }
137 }
138 
139 void s390x_pci_mmio_write_64(void *ioaddr, uint64_t val)
140 {
141     if (is_mio_supported) {
142         s390x_pcistgi(ioaddr, val, sizeof(val));
143     } else {
144         syscall(__NR_s390_pci_mmio_write, ioaddr, &val, sizeof(val));
145     }
146 }
147