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" 12cf716b31SLaurent Vivier 13cf716b31SLaurent Vivier #include "hw/pci/pci_regs.h" 14cf716b31SLaurent Vivier 15cf716b31SLaurent Vivier #include "qemu-common.h" 16cf716b31SLaurent Vivier #include "qemu/host-utils.h" 17cf716b31SLaurent Vivier 18cf716b31SLaurent Vivier 19cf716b31SLaurent Vivier /* From include/hw/pci-host/spapr.h */ 20cf716b31SLaurent Vivier 21cd1b354eSDavid Gibson typedef struct QPCIWindow { 22cd1b354eSDavid Gibson uint64_t pci_base; /* window address in PCI space */ 23cd1b354eSDavid Gibson uint64_t size; /* window size */ 24cd1b354eSDavid Gibson } QPCIWindow; 25cf716b31SLaurent Vivier 26cf716b31SLaurent Vivier typedef struct QPCIBusSPAPR { 27cf716b31SLaurent Vivier QPCIBus bus; 28cf716b31SLaurent Vivier QGuestAllocator *alloc; 29cf716b31SLaurent Vivier 30cd1b354eSDavid Gibson uint64_t buid; 31cd1b354eSDavid Gibson 32cd1b354eSDavid Gibson uint64_t pio_cpu_base; 33cd1b354eSDavid Gibson QPCIWindow pio; 34cd1b354eSDavid Gibson 358360544aSDavid Gibson uint64_t mmio32_cpu_base; 368360544aSDavid Gibson QPCIWindow mmio32; 37cf716b31SLaurent Vivier } QPCIBusSPAPR; 38cf716b31SLaurent Vivier 39cf716b31SLaurent Vivier /* 40cf716b31SLaurent Vivier * PCI devices are always little-endian 41cf716b31SLaurent Vivier * SPAPR by default is big-endian 42cf716b31SLaurent Vivier * so PCI accessors need to swap data endianness 43cf716b31SLaurent Vivier */ 44cf716b31SLaurent Vivier 45a795fc08SDavid Gibson static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) 46cf716b31SLaurent Vivier { 47cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 48a795fc08SDavid Gibson return readb(s->pio_cpu_base + addr); 49cf716b31SLaurent Vivier } 50cf716b31SLaurent Vivier 51a795fc08SDavid Gibson static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 52cf716b31SLaurent Vivier { 53cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 54a795fc08SDavid Gibson writeb(s->pio_cpu_base + addr, val); 55cf716b31SLaurent Vivier } 56cf716b31SLaurent Vivier 57a795fc08SDavid Gibson static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) 58cf716b31SLaurent Vivier { 59cd1b354eSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 60a795fc08SDavid Gibson return bswap16(readw(s->pio_cpu_base + addr)); 61cf716b31SLaurent Vivier } 62cf716b31SLaurent Vivier 63a795fc08SDavid Gibson static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 64a795fc08SDavid Gibson { 65a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 66a795fc08SDavid Gibson writew(s->pio_cpu_base + addr, bswap16(val)); 67a795fc08SDavid Gibson } 68a795fc08SDavid Gibson 69a795fc08SDavid Gibson static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) 70a795fc08SDavid Gibson { 71a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 72a795fc08SDavid Gibson return bswap32(readl(s->pio_cpu_base + addr)); 73a795fc08SDavid Gibson } 74a795fc08SDavid Gibson 75a795fc08SDavid Gibson static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 76a795fc08SDavid Gibson { 77a795fc08SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 78a795fc08SDavid Gibson writel(s->pio_cpu_base + addr, bswap32(val)); 79a795fc08SDavid Gibson } 80a795fc08SDavid Gibson 81f775f45aSDavid Gibson static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr) 82f775f45aSDavid Gibson { 83f775f45aSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 84f775f45aSDavid Gibson return bswap64(readq(s->pio_cpu_base + addr)); 85f775f45aSDavid Gibson } 86f775f45aSDavid Gibson 87f775f45aSDavid Gibson static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) 88f775f45aSDavid Gibson { 89f775f45aSDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 90f775f45aSDavid Gibson writeq(s->pio_cpu_base + addr, bswap64(val)); 91f775f45aSDavid Gibson } 92f775f45aSDavid Gibson 939a84f889SDavid Gibson static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, 949a84f889SDavid Gibson void *buf, size_t len) 959a84f889SDavid Gibson { 969a84f889SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 979a84f889SDavid Gibson memread(s->mmio32_cpu_base + addr, buf, len); 989a84f889SDavid Gibson } 999a84f889SDavid Gibson 1009a84f889SDavid Gibson static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, 1019a84f889SDavid Gibson const void *buf, size_t len) 1029a84f889SDavid Gibson { 1039a84f889SDavid Gibson QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 1049a84f889SDavid Gibson memwrite(s->mmio32_cpu_base + addr, buf, len); 1059a84f889SDavid Gibson } 1069a84f889SDavid Gibson 107cf716b31SLaurent Vivier static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 108cf716b31SLaurent Vivier { 109cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 110cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 111cd1b354eSDavid Gibson return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1); 112cf716b31SLaurent Vivier } 113cf716b31SLaurent Vivier 114cf716b31SLaurent Vivier static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 115cf716b31SLaurent Vivier { 116cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 117cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 118cd1b354eSDavid Gibson return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2); 119cf716b31SLaurent Vivier } 120cf716b31SLaurent Vivier 121cf716b31SLaurent Vivier static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 122cf716b31SLaurent Vivier { 123cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 124cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 125cd1b354eSDavid Gibson return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4); 126cf716b31SLaurent Vivier } 127cf716b31SLaurent Vivier 128cf716b31SLaurent Vivier static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, 129cf716b31SLaurent Vivier uint8_t value) 130cf716b31SLaurent Vivier { 131cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 132cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 133cd1b354eSDavid Gibson qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value); 134cf716b31SLaurent Vivier } 135cf716b31SLaurent Vivier 136cf716b31SLaurent Vivier static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, 137cf716b31SLaurent Vivier uint16_t value) 138cf716b31SLaurent Vivier { 139cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 140cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 141cd1b354eSDavid Gibson qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value); 142cf716b31SLaurent Vivier } 143cf716b31SLaurent Vivier 144cf716b31SLaurent Vivier static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, 145cf716b31SLaurent Vivier uint32_t value) 146cf716b31SLaurent Vivier { 147cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 148cf716b31SLaurent Vivier uint32_t config_addr = (devfn << 8) | offset; 149cd1b354eSDavid Gibson qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value); 150cf716b31SLaurent Vivier } 151cf716b31SLaurent Vivier 152357d1e3bSDavid Gibson #define SPAPR_PCI_BASE (1ULL << 45) 153357d1e3bSDavid Gibson 1548360544aSDavid Gibson #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ 155cd1b354eSDavid Gibson #define SPAPR_PCI_IO_WIN_SIZE 0x10000 156cd1b354eSDavid Gibson 157*e5d1730dSEric Blake QPCIBus *qpci_init_spapr(QTestState *qts, QGuestAllocator *alloc) 158cf716b31SLaurent Vivier { 159*e5d1730dSEric Blake QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1); 160cf716b31SLaurent Vivier 161*e5d1730dSEric Blake assert(qts); 162cf716b31SLaurent Vivier 163cf716b31SLaurent Vivier ret->alloc = alloc; 164cf716b31SLaurent Vivier 165a795fc08SDavid Gibson ret->bus.pio_readb = qpci_spapr_pio_readb; 166a795fc08SDavid Gibson ret->bus.pio_readw = qpci_spapr_pio_readw; 167a795fc08SDavid Gibson ret->bus.pio_readl = qpci_spapr_pio_readl; 168f775f45aSDavid Gibson ret->bus.pio_readq = qpci_spapr_pio_readq; 169cf716b31SLaurent Vivier 170a795fc08SDavid Gibson ret->bus.pio_writeb = qpci_spapr_pio_writeb; 171a795fc08SDavid Gibson ret->bus.pio_writew = qpci_spapr_pio_writew; 172a795fc08SDavid Gibson ret->bus.pio_writel = qpci_spapr_pio_writel; 173f775f45aSDavid Gibson ret->bus.pio_writeq = qpci_spapr_pio_writeq; 174a795fc08SDavid Gibson 1759a84f889SDavid Gibson ret->bus.memread = qpci_spapr_memread; 1769a84f889SDavid Gibson ret->bus.memwrite = qpci_spapr_memwrite; 1779a84f889SDavid Gibson 178cf716b31SLaurent Vivier ret->bus.config_readb = qpci_spapr_config_readb; 179cf716b31SLaurent Vivier ret->bus.config_readw = qpci_spapr_config_readw; 180cf716b31SLaurent Vivier ret->bus.config_readl = qpci_spapr_config_readl; 181cf716b31SLaurent Vivier 182cf716b31SLaurent Vivier ret->bus.config_writeb = qpci_spapr_config_writeb; 183cf716b31SLaurent Vivier ret->bus.config_writew = qpci_spapr_config_writew; 184cf716b31SLaurent Vivier ret->bus.config_writel = qpci_spapr_config_writel; 185cf716b31SLaurent Vivier 186cd1b354eSDavid Gibson /* FIXME: We assume the default location of the PHB for now. 187cd1b354eSDavid Gibson * Ideally we'd parse the device tree deposited in the guest to 188cd1b354eSDavid Gibson * get the window locations */ 189cd1b354eSDavid Gibson ret->buid = 0x800000020000000ULL; 190cd1b354eSDavid Gibson 191357d1e3bSDavid Gibson ret->pio_cpu_base = SPAPR_PCI_BASE; 192cd1b354eSDavid Gibson ret->pio.pci_base = 0; 193cd1b354eSDavid Gibson ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; 194cd1b354eSDavid Gibson 1958360544aSDavid Gibson /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ 196b8454169SLaurent Vivier ret->mmio32_cpu_base = SPAPR_PCI_BASE; 197b8454169SLaurent Vivier ret->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE; 1988360544aSDavid Gibson ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; 199cd1b354eSDavid Gibson 200*e5d1730dSEric Blake ret->bus.qts = qts; 201b8cc4d02SDavid Gibson ret->bus.pio_alloc_ptr = 0xc000; 202b8cc4d02SDavid Gibson ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base; 203b8cc4d02SDavid Gibson ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size; 204cf716b31SLaurent Vivier 205cf716b31SLaurent Vivier return &ret->bus; 206cf716b31SLaurent Vivier } 207cf716b31SLaurent Vivier 208cf716b31SLaurent Vivier void qpci_free_spapr(QPCIBus *bus) 209cf716b31SLaurent Vivier { 210cf716b31SLaurent Vivier QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 211cf716b31SLaurent Vivier 212cf716b31SLaurent Vivier g_free(s); 213cf716b31SLaurent Vivier } 214