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
check_is_mio_supported(void)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
s390x_pcilgi(const void * ioaddr,size_t len)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
s390x_pcistgi(void * ioaddr,uint64_t val,size_t len)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
s390x_pci_mmio_read_8(const void * ioaddr)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
s390x_pci_mmio_read_16(const void * ioaddr)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
s390x_pci_mmio_read_32(const void * ioaddr)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
s390x_pci_mmio_read_64(const void * ioaddr)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
s390x_pci_mmio_write_8(void * ioaddr,uint8_t val)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
s390x_pci_mmio_write_16(void * ioaddr,uint16_t val)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
s390x_pci_mmio_write_32(void * ioaddr,uint32_t val)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
s390x_pci_mmio_write_64(void * ioaddr,uint64_t val)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