1cf716b31SLaurent Vivier /* 2cf716b31SLaurent Vivier * libqos PCI bindings for SPAPR 3cf716b31SLaurent Vivier * 4cf716b31SLaurent Vivier * This work is licensed under the terms of the GNU GPL, version 2 or later. 5cf716b31SLaurent Vivier * See the COPYING file in the top-level directory. 6cf716b31SLaurent Vivier */ 7cf716b31SLaurent Vivier 8cf716b31SLaurent Vivier #include "qemu/osdep.h" 9cf716b31SLaurent Vivier #include "libqtest.h" 10cf716b31SLaurent Vivier #include "libqos/pci-spapr.h" 11cf716b31SLaurent Vivier #include "libqos/rtas.h" 12b8782d2aSEmanuele Giuseppe Esposito #include "libqos/qgraph.h" 13cf716b31SLaurent Vivier 14cf716b31SLaurent Vivier #include "hw/pci/pci_regs.h" 15cf716b31SLaurent Vivier 16cf716b31SLaurent Vivier #include "qemu-common.h" 17cf716b31SLaurent Vivier #include "qemu/host-utils.h" 18cf716b31SLaurent Vivier 19cf716b31SLaurent Vivier /* 20cf716b31SLaurent Vivier * PCI devices are always little-endian 21cf716b31SLaurent Vivier * SPAPR by default is big-endian 22cf716b31SLaurent Vivier * so PCI accessors need to swap data endianness 23cf716b31SLaurent Vivier */ 24cf716b31SLaurent Vivier 25a795fc08SDavid Gibson static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) 26cf716b31SLaurent Vivier { 27cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 28d786f782SThomas Huth return qtest_readb(bus->qts, s->pio_cpu_base + addr); 29cf716b31SLaurent Vivier } 30cf716b31SLaurent Vivier 31a795fc08SDavid Gibson static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 32cf716b31SLaurent Vivier { 33cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 34d786f782SThomas Huth qtest_writeb(bus->qts, s->pio_cpu_base + addr, val); 35cf716b31SLaurent Vivier } 36cf716b31SLaurent Vivier 37a795fc08SDavid Gibson static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) 38cf716b31SLaurent Vivier { 39cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 40d786f782SThomas Huth return bswap16(qtest_readw(bus->qts, s->pio_cpu_base + addr)); 41cf716b31SLaurent Vivier } 42cf716b31SLaurent Vivier 43a795fc08SDavid Gibson static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 44a795fc08SDavid Gibson { 45a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 46d786f782SThomas Huth qtest_writew(bus->qts, s->pio_cpu_base + addr, bswap16(val)); 47a795fc08SDavid Gibson } 48a795fc08SDavid Gibson 49a795fc08SDavid Gibson static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) 50a795fc08SDavid Gibson { 51a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 52d786f782SThomas Huth return bswap32(qtest_readl(bus->qts, s->pio_cpu_base + addr)); 53a795fc08SDavid Gibson } 54a795fc08SDavid Gibson 55a795fc08SDavid Gibson static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 56a795fc08SDavid Gibson { 57a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 58d786f782SThomas Huth qtest_writel(bus->qts, s->pio_cpu_base + addr, bswap32(val)); 59a795fc08SDavid Gibson } 60a795fc08SDavid Gibson 61f775f45aSDavid Gibson static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr) 62f775f45aSDavid Gibson { 63f775f45aSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 64d786f782SThomas Huth return bswap64(qtest_readq(bus->qts, s->pio_cpu_base + addr)); 65f775f45aSDavid Gibson } 66f775f45aSDavid Gibson 67f775f45aSDavid Gibson static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) 68f775f45aSDavid Gibson { 69f775f45aSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 70d786f782SThomas Huth qtest_writeq(bus->qts, s->pio_cpu_base + addr, bswap64(val)); 71f775f45aSDavid Gibson } 72f775f45aSDavid Gibson 739a84f889SDavid Gibson static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, 749a84f889SDavid Gibson void *buf, size_t len) 759a84f889SDavid Gibson { 769a84f889SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 77d786f782SThomas Huth qtest_memread(bus->qts, s->mmio32_cpu_base + addr, buf, len); 789a84f889SDavid Gibson } 799a84f889SDavid Gibson 809a84f889SDavid Gibson static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, 819a84f889SDavid Gibson const void *buf, size_t len) 829a84f889SDavid Gibson { 839a84f889SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 84d786f782SThomas Huth qtest_memwrite(bus->qts, s->mmio32_cpu_base + addr, buf, len); 859a84f889SDavid Gibson } 869a84f889SDavid Gibson 87cf716b31SLaurent Vivier static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 88cf716b31SLaurent Vivier { 89cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 90cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 919b67af76SEric Blake return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, 929b67af76SEric Blake config_addr, 1); 93cf716b31SLaurent Vivier } 94cf716b31SLaurent Vivier 95cf716b31SLaurent Vivier static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 96cf716b31SLaurent Vivier { 97cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 98cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 999b67af76SEric Blake return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, 1009b67af76SEric Blake config_addr, 2); 101cf716b31SLaurent Vivier } 102cf716b31SLaurent Vivier 103cf716b31SLaurent Vivier static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 104cf716b31SLaurent Vivier { 105cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 106cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 1079b67af76SEric Blake return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, 1089b67af76SEric Blake config_addr, 4); 109cf716b31SLaurent Vivier } 110cf716b31SLaurent Vivier 111cf716b31SLaurent Vivier static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, 112cf716b31SLaurent Vivier uint8_t value) 113cf716b31SLaurent Vivier { 114cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 115cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 1169b67af76SEric Blake qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, 1179b67af76SEric Blake config_addr, 1, value); 118cf716b31SLaurent Vivier } 119cf716b31SLaurent Vivier 120cf716b31SLaurent Vivier static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, 121cf716b31SLaurent Vivier uint16_t value) 122cf716b31SLaurent Vivier { 123cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 124cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 1259b67af76SEric Blake qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, 1269b67af76SEric Blake config_addr, 2, value); 127cf716b31SLaurent Vivier } 128cf716b31SLaurent Vivier 129cf716b31SLaurent Vivier static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, 130cf716b31SLaurent Vivier uint32_t value) 131cf716b31SLaurent Vivier { 132cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 133cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 1349b67af76SEric Blake qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, 1359b67af76SEric Blake config_addr, 4, value); 136cf716b31SLaurent Vivier } 137cf716b31SLaurent Vivier 138357d1e3bSDavid Gibson #define SPAPR_PCI_BASE (1ULL << 45) 139357d1e3bSDavid Gibson 1408360544aSDavid Gibson #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ 141cd1b354eSDavid Gibson #define SPAPR_PCI_IO_WIN_SIZE 0x10000 142cd1b354eSDavid Gibson 143b8782d2aSEmanuele Giuseppe Esposito static void *qpci_spapr_get_driver(void *obj, const char *interface) 144cf716b31SLaurent Vivier { 145b8782d2aSEmanuele Giuseppe Esposito QPCIBusSPAPR *qpci = obj; 146b8782d2aSEmanuele Giuseppe Esposito if (!g_strcmp0(interface, "pci-bus")) { 147b8782d2aSEmanuele Giuseppe Esposito return &qpci->bus; 148b8782d2aSEmanuele Giuseppe Esposito } 149b8782d2aSEmanuele Giuseppe Esposito fprintf(stderr, "%s not present in pci-bus-spapr", interface); 150b8782d2aSEmanuele Giuseppe Esposito g_assert_not_reached(); 151b8782d2aSEmanuele Giuseppe Esposito } 152cf716b31SLaurent Vivier 153b8782d2aSEmanuele Giuseppe Esposito void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts, 154b8782d2aSEmanuele Giuseppe Esposito QGuestAllocator *alloc) 155b8782d2aSEmanuele Giuseppe Esposito { 156e5d1730dSEric Blake assert(qts); 157cf716b31SLaurent Vivier 158*92bbafc7SEmanuele Giuseppe Esposito /* tests cannot use spapr, needs to be fixed first */ 159*92bbafc7SEmanuele Giuseppe Esposito qpci->bus.has_buggy_msi = TRUE; 160*92bbafc7SEmanuele Giuseppe Esposito 161b8782d2aSEmanuele Giuseppe Esposito qpci->alloc = alloc; 162cf716b31SLaurent Vivier 163b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_readb = qpci_spapr_pio_readb; 164b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_readw = qpci_spapr_pio_readw; 165b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_readl = qpci_spapr_pio_readl; 166b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_readq = qpci_spapr_pio_readq; 167cf716b31SLaurent Vivier 168b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_writeb = qpci_spapr_pio_writeb; 169b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_writew = qpci_spapr_pio_writew; 170b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_writel = qpci_spapr_pio_writel; 171b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_writeq = qpci_spapr_pio_writeq; 172a795fc08SDavid Gibson 173b8782d2aSEmanuele Giuseppe Esposito qpci->bus.memread = qpci_spapr_memread; 174b8782d2aSEmanuele Giuseppe Esposito qpci->bus.memwrite = qpci_spapr_memwrite; 1759a84f889SDavid Gibson 176b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_readb = qpci_spapr_config_readb; 177b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_readw = qpci_spapr_config_readw; 178b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_readl = qpci_spapr_config_readl; 179cf716b31SLaurent Vivier 180b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_writeb = qpci_spapr_config_writeb; 181b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_writew = qpci_spapr_config_writew; 182b8782d2aSEmanuele Giuseppe Esposito qpci->bus.config_writel = qpci_spapr_config_writel; 183cf716b31SLaurent Vivier 184cd1b354eSDavid Gibson /* FIXME: We assume the default location of the PHB for now. 185cd1b354eSDavid Gibson * Ideally we'd parse the device tree deposited in the guest to 186cd1b354eSDavid Gibson * get the window locations */ 187b8782d2aSEmanuele Giuseppe Esposito qpci->buid = 0x800000020000000ULL; 188cd1b354eSDavid Gibson 189b8782d2aSEmanuele Giuseppe Esposito qpci->pio_cpu_base = SPAPR_PCI_BASE; 190b8782d2aSEmanuele Giuseppe Esposito qpci->pio.pci_base = 0; 191b8782d2aSEmanuele Giuseppe Esposito qpci->pio.size = SPAPR_PCI_IO_WIN_SIZE; 192cd1b354eSDavid Gibson 1938360544aSDavid Gibson /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ 194b8782d2aSEmanuele Giuseppe Esposito qpci->mmio32_cpu_base = SPAPR_PCI_BASE; 195b8782d2aSEmanuele Giuseppe Esposito qpci->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE; 196b8782d2aSEmanuele Giuseppe Esposito qpci->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; 197cd1b354eSDavid Gibson 198b8782d2aSEmanuele Giuseppe Esposito qpci->bus.qts = qts; 199b8782d2aSEmanuele Giuseppe Esposito qpci->bus.pio_alloc_ptr = 0xc000; 200b8782d2aSEmanuele Giuseppe Esposito qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base; 201b8782d2aSEmanuele Giuseppe Esposito qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size; 202cf716b31SLaurent Vivier 203b8782d2aSEmanuele Giuseppe Esposito qpci->obj.get_driver = qpci_spapr_get_driver; 204b8782d2aSEmanuele Giuseppe Esposito } 205b8782d2aSEmanuele Giuseppe Esposito 206b8782d2aSEmanuele Giuseppe Esposito QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc) 207b8782d2aSEmanuele Giuseppe Esposito { 208b8782d2aSEmanuele Giuseppe Esposito QPCIBusSPAPR *qpci = g_new0(QPCIBusSPAPR, 1); 209b8782d2aSEmanuele Giuseppe Esposito qpci_init_spapr(qpci, qts, alloc); 210b8782d2aSEmanuele Giuseppe Esposito 211b8782d2aSEmanuele Giuseppe Esposito return &qpci->bus; 212cf716b31SLaurent Vivier } 213cf716b31SLaurent Vivier 214cf716b31SLaurent Vivier void qpci_free_spapr(QPCIBus *bus) 215cf716b31SLaurent Vivier { 216b8782d2aSEmanuele Giuseppe Esposito QPCIBusSPAPR *s; 217b8782d2aSEmanuele Giuseppe Esposito 218b8782d2aSEmanuele Giuseppe Esposito if (!bus) { 219b8782d2aSEmanuele Giuseppe Esposito return; 220b8782d2aSEmanuele Giuseppe Esposito } 221b8782d2aSEmanuele Giuseppe Esposito s = container_of(bus, QPCIBusSPAPR, bus); 222cf716b31SLaurent Vivier 223cf716b31SLaurent Vivier g_free(s); 224cf716b31SLaurent Vivier } 225b8782d2aSEmanuele Giuseppe Esposito 226b8782d2aSEmanuele Giuseppe Esposito static void qpci_spapr_register_nodes(void) 227b8782d2aSEmanuele Giuseppe Esposito { 228b8782d2aSEmanuele Giuseppe Esposito qos_node_create_driver("pci-bus-spapr", NULL); 229b8782d2aSEmanuele Giuseppe Esposito qos_node_produces("pci-bus-spapr", "pci-bus"); 230b8782d2aSEmanuele Giuseppe Esposito } 231b8782d2aSEmanuele Giuseppe Esposito 232b8782d2aSEmanuele Giuseppe Esposito libqos_init(qpci_spapr_register_nodes); 233