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