/* * s390x PCI MMIO definitions * * Copyright 2025 IBM Corp. * Author(s): Farhan Ali * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" #include #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)); } }