1 /* 2 * libqos PCI bindings for generic PCI 3 * 4 * Copyright Red Hat Inc., 2022 5 * 6 * Authors: 7 * Eric Auger <eric.auger@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "../libqtest.h" 15 #include "generic-pcihost.h" 16 #include "qapi/qmp/qdict.h" 17 #include "hw/pci/pci_regs.h" 18 #include "qemu/host-utils.h" 19 20 #include "qemu/module.h" 21 22 /* QGenericPCIHost */ 23 24 QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device) 25 { 26 QGenericPCIHost *host = obj; 27 if (!g_strcmp0(device, "pci-bus-generic")) { 28 return &host->pci.obj; 29 } 30 fprintf(stderr, "%s not present in generic-pcihost\n", device); 31 g_assert_not_reached(); 32 } 33 34 void qos_create_generic_pcihost(QGenericPCIHost *host, 35 QTestState *qts, 36 QGuestAllocator *alloc) 37 { 38 host->obj.get_device = generic_pcihost_get_device; 39 qpci_init_generic(&host->pci, qts, alloc, false); 40 } 41 42 static uint8_t qpci_generic_pio_readb(QPCIBus *bus, uint32_t addr) 43 { 44 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 45 46 return qtest_readb(bus->qts, s->gpex_pio_base + addr); 47 } 48 49 static void qpci_generic_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 50 { 51 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 52 53 qtest_writeb(bus->qts, s->gpex_pio_base + addr, val); 54 } 55 56 static uint16_t qpci_generic_pio_readw(QPCIBus *bus, uint32_t addr) 57 { 58 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 59 60 return qtest_readw(bus->qts, s->gpex_pio_base + addr); 61 } 62 63 static void qpci_generic_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 64 { 65 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 66 67 qtest_writew(bus->qts, s->gpex_pio_base + addr, val); 68 } 69 70 static uint32_t qpci_generic_pio_readl(QPCIBus *bus, uint32_t addr) 71 { 72 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 73 74 return qtest_readl(bus->qts, s->gpex_pio_base + addr); 75 } 76 77 static void qpci_generic_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 78 { 79 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 80 81 qtest_writel(bus->qts, s->gpex_pio_base + addr, val); 82 } 83 84 static uint64_t qpci_generic_pio_readq(QPCIBus *bus, uint32_t addr) 85 { 86 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 87 88 return qtest_readq(bus->qts, s->gpex_pio_base + addr); 89 } 90 91 static void qpci_generic_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) 92 { 93 QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus); 94 95 qtest_writeq(bus->qts, s->gpex_pio_base + addr, val); 96 } 97 98 static void qpci_generic_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) 99 { 100 qtest_memread(bus->qts, addr, buf, len); 101 } 102 103 static void qpci_generic_memwrite(QPCIBus *bus, uint32_t addr, 104 const void *buf, size_t len) 105 { 106 qtest_memwrite(bus->qts, addr, buf, len); 107 } 108 109 static uint8_t qpci_generic_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 110 { 111 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 112 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 113 uint8_t val; 114 115 qtest_memread(bus->qts, addr, &val, 1); 116 return val; 117 } 118 119 static uint16_t qpci_generic_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 120 { 121 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 122 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 123 uint16_t val; 124 125 qtest_memread(bus->qts, addr, &val, 2); 126 return le16_to_cpu(val); 127 } 128 129 static uint32_t qpci_generic_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 130 { 131 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 132 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 133 uint32_t val; 134 135 qtest_memread(bus->qts, addr, &val, 4); 136 return le32_to_cpu(val); 137 } 138 139 static void 140 qpci_generic_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) 141 { 142 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 143 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 144 145 qtest_memwrite(bus->qts, addr, &value, 1); 146 } 147 148 static void 149 qpci_generic_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) 150 { 151 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 152 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 153 uint16_t val = cpu_to_le16(value); 154 155 qtest_memwrite(bus->qts, addr, &val, 2); 156 } 157 158 static void 159 qpci_generic_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) 160 { 161 QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus); 162 uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset); 163 uint32_t val = cpu_to_le32(value); 164 165 qtest_memwrite(bus->qts, addr, &val, 4); 166 } 167 168 static void *qpci_generic_get_driver(void *obj, const char *interface) 169 { 170 QGenericPCIBus *qpci = obj; 171 if (!g_strcmp0(interface, "pci-bus")) { 172 return &qpci->bus; 173 } 174 fprintf(stderr, "%s not present in pci-bus-generic\n", interface); 175 g_assert_not_reached(); 176 } 177 178 void qpci_init_generic(QGenericPCIBus *qpci, QTestState *qts, 179 QGuestAllocator *alloc, bool hotpluggable) 180 { 181 assert(qts); 182 183 qpci->gpex_pio_base = 0x3eff0000; 184 qpci->bus.not_hotpluggable = !hotpluggable; 185 qpci->bus.has_buggy_msi = false; 186 187 qpci->bus.pio_readb = qpci_generic_pio_readb; 188 qpci->bus.pio_readw = qpci_generic_pio_readw; 189 qpci->bus.pio_readl = qpci_generic_pio_readl; 190 qpci->bus.pio_readq = qpci_generic_pio_readq; 191 192 qpci->bus.pio_writeb = qpci_generic_pio_writeb; 193 qpci->bus.pio_writew = qpci_generic_pio_writew; 194 qpci->bus.pio_writel = qpci_generic_pio_writel; 195 qpci->bus.pio_writeq = qpci_generic_pio_writeq; 196 197 qpci->bus.memread = qpci_generic_memread; 198 qpci->bus.memwrite = qpci_generic_memwrite; 199 200 qpci->bus.config_readb = qpci_generic_config_readb; 201 qpci->bus.config_readw = qpci_generic_config_readw; 202 qpci->bus.config_readl = qpci_generic_config_readl; 203 204 qpci->bus.config_writeb = qpci_generic_config_writeb; 205 qpci->bus.config_writew = qpci_generic_config_writew; 206 qpci->bus.config_writel = qpci_generic_config_writel; 207 208 qpci->bus.qts = qts; 209 qpci->bus.pio_alloc_ptr = 0x0000; 210 qpci->bus.pio_limit = 0x10000; 211 qpci->bus.mmio_alloc_ptr = 0x10000000; 212 qpci->bus.mmio_limit = 0x2eff0000; 213 qpci->ecam_alloc_ptr = 0x4010000000; 214 215 qpci->obj.get_driver = qpci_generic_get_driver; 216 } 217 218 static void qpci_generic_register_nodes(void) 219 { 220 qos_node_create_driver("pci-bus-generic", NULL); 221 qos_node_produces("pci-bus-generic", "pci-bus"); 222 } 223 224 static void qpci_generic_pci_register_nodes(void) 225 { 226 qos_node_create_driver("generic-pcihost", NULL); 227 qos_node_contains("generic-pcihost", "pci-bus-generic", NULL); 228 } 229 230 libqos_init(qpci_generic_register_nodes); 231 libqos_init(qpci_generic_pci_register_nodes); 232