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