1 /* 2 * libqos PCI bindings for SPAPR 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "libqtest.h" 10 #include "libqos/pci-spapr.h" 11 #include "libqos/rtas.h" 12 13 #include "hw/pci/pci_regs.h" 14 15 #include "qemu-common.h" 16 #include "qemu/host-utils.h" 17 18 19 /* From include/hw/pci-host/spapr.h */ 20 21 #define SPAPR_PCI_BASE_BUID 0x800000020000000ULL 22 23 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL 24 25 #define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL 26 #define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL 27 #define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 28 #define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ 29 SPAPR_PCI_MEM_WIN_BUS_OFFSET) 30 #define SPAPR_PCI_IO_WIN_OFF 0x80000000 31 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 32 33 /* index is the phb index */ 34 35 #define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) 36 #define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ 37 (index) * SPAPR_PCI_WINDOW_SPACING) 38 #define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) 39 #define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) 40 41 typedef struct QPCIBusSPAPR { 42 QPCIBus bus; 43 QGuestAllocator *alloc; 44 45 uint64_t pci_hole_start; 46 uint64_t pci_hole_size; 47 uint64_t pci_hole_alloc; 48 49 uint32_t pci_iohole_start; 50 uint32_t pci_iohole_size; 51 uint32_t pci_iohole_alloc; 52 } QPCIBusSPAPR; 53 54 /* 55 * PCI devices are always little-endian 56 * SPAPR by default is big-endian 57 * so PCI accessors need to swap data endianness 58 */ 59 60 static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) 61 { 62 uint64_t port = (uintptr_t)addr; 63 uint8_t v; 64 if (port < SPAPR_PCI_IO_WIN_SIZE) { 65 v = readb(IOBASE(0) + port); 66 } else { 67 v = readb(MMIOBASE(0) + port); 68 } 69 return v; 70 } 71 72 static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) 73 { 74 uint64_t port = (uintptr_t)addr; 75 uint16_t v; 76 if (port < SPAPR_PCI_IO_WIN_SIZE) { 77 v = readw(IOBASE(0) + port); 78 } else { 79 v = readw(MMIOBASE(0) + port); 80 } 81 return bswap16(v); 82 } 83 84 static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) 85 { 86 uint64_t port = (uintptr_t)addr; 87 uint32_t v; 88 if (port < SPAPR_PCI_IO_WIN_SIZE) { 89 v = readl(IOBASE(0) + port); 90 } else { 91 v = readl(MMIOBASE(0) + port); 92 } 93 return bswap32(v); 94 } 95 96 static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) 97 { 98 uint64_t port = (uintptr_t)addr; 99 if (port < SPAPR_PCI_IO_WIN_SIZE) { 100 writeb(IOBASE(0) + port, value); 101 } else { 102 writeb(MMIOBASE(0) + port, value); 103 } 104 } 105 106 static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) 107 { 108 uint64_t port = (uintptr_t)addr; 109 value = bswap16(value); 110 if (port < SPAPR_PCI_IO_WIN_SIZE) { 111 writew(IOBASE(0) + port, value); 112 } else { 113 writew(MMIOBASE(0) + port, value); 114 } 115 } 116 117 static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) 118 { 119 uint64_t port = (uintptr_t)addr; 120 value = bswap32(value); 121 if (port < SPAPR_PCI_IO_WIN_SIZE) { 122 writel(IOBASE(0) + port, value); 123 } else { 124 writel(MMIOBASE(0) + port, value); 125 } 126 } 127 128 static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 129 { 130 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 131 uint32_t config_addr = (devfn << 8) | offset; 132 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), 133 config_addr, 1); 134 } 135 136 static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 137 { 138 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 139 uint32_t config_addr = (devfn << 8) | offset; 140 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), 141 config_addr, 2); 142 } 143 144 static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 145 { 146 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 147 uint32_t config_addr = (devfn << 8) | offset; 148 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), 149 config_addr, 4); 150 } 151 152 static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, 153 uint8_t value) 154 { 155 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 156 uint32_t config_addr = (devfn << 8) | offset; 157 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), 158 config_addr, 1, value); 159 } 160 161 static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, 162 uint16_t value) 163 { 164 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 165 uint32_t config_addr = (devfn << 8) | offset; 166 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), 167 config_addr, 2, value); 168 } 169 170 static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, 171 uint32_t value) 172 { 173 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 174 uint32_t config_addr = (devfn << 8) | offset; 175 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), 176 config_addr, 4, value); 177 } 178 179 static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, 180 uint64_t *sizeptr) 181 { 182 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 183 static const int bar_reg_map[] = { 184 PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, 185 PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, 186 }; 187 int bar_reg; 188 uint32_t addr; 189 uint64_t size; 190 uint32_t io_type; 191 192 g_assert(barno >= 0 && barno <= 5); 193 bar_reg = bar_reg_map[barno]; 194 195 qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); 196 addr = qpci_config_readl(dev, bar_reg); 197 198 io_type = addr & PCI_BASE_ADDRESS_SPACE; 199 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { 200 addr &= PCI_BASE_ADDRESS_IO_MASK; 201 } else { 202 addr &= PCI_BASE_ADDRESS_MEM_MASK; 203 } 204 205 size = (1ULL << ctzl(addr)); 206 if (size == 0) { 207 return NULL; 208 } 209 if (sizeptr) { 210 *sizeptr = size; 211 } 212 213 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { 214 uint16_t loc; 215 216 g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size 217 <= s->pci_iohole_size); 218 s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); 219 loc = s->pci_iohole_start + s->pci_iohole_alloc; 220 s->pci_iohole_alloc += size; 221 222 qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); 223 224 return (void *)(unsigned long)loc; 225 } else { 226 uint64_t loc; 227 228 g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size 229 <= s->pci_hole_size); 230 s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); 231 loc = s->pci_hole_start + s->pci_hole_alloc; 232 s->pci_hole_alloc += size; 233 234 qpci_config_writel(dev, bar_reg, loc); 235 236 return (void *)(unsigned long)loc; 237 } 238 } 239 240 static void qpci_spapr_iounmap(QPCIBus *bus, void *data) 241 { 242 /* FIXME */ 243 } 244 245 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) 246 { 247 QPCIBusSPAPR *ret; 248 249 ret = g_malloc(sizeof(*ret)); 250 251 ret->alloc = alloc; 252 253 ret->bus.io_readb = qpci_spapr_io_readb; 254 ret->bus.io_readw = qpci_spapr_io_readw; 255 ret->bus.io_readl = qpci_spapr_io_readl; 256 257 ret->bus.io_writeb = qpci_spapr_io_writeb; 258 ret->bus.io_writew = qpci_spapr_io_writew; 259 ret->bus.io_writel = qpci_spapr_io_writel; 260 261 ret->bus.config_readb = qpci_spapr_config_readb; 262 ret->bus.config_readw = qpci_spapr_config_readw; 263 ret->bus.config_readl = qpci_spapr_config_readl; 264 265 ret->bus.config_writeb = qpci_spapr_config_writeb; 266 ret->bus.config_writew = qpci_spapr_config_writew; 267 ret->bus.config_writel = qpci_spapr_config_writel; 268 269 ret->bus.iomap = qpci_spapr_iomap; 270 ret->bus.iounmap = qpci_spapr_iounmap; 271 272 ret->pci_hole_start = 0xC0000000; 273 ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; 274 ret->pci_hole_alloc = 0; 275 276 ret->pci_iohole_start = 0xc000; 277 ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; 278 ret->pci_iohole_alloc = 0; 279 280 return &ret->bus; 281 } 282 283 void qpci_free_spapr(QPCIBus *bus) 284 { 285 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); 286 287 g_free(s); 288 } 289