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