ppc440_pcix.c (15230B)
1/* 2 * Emulation of the ibm,plb-pcix PCI controller 3 * This is found in some 440 SoCs e.g. the 460EX. 4 * 5 * Copyright (c) 2016-2018 BALATON Zoltan 6 * 7 * Derived from ppc4xx_pci.c and pci-host/ppce500.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22#include "qemu/osdep.h" 23#include "qemu/error-report.h" 24#include "qemu/log.h" 25#include "qemu/module.h" 26#include "hw/irq.h" 27#include "hw/ppc/ppc.h" 28#include "hw/ppc/ppc4xx.h" 29#include "hw/pci/pci.h" 30#include "hw/pci/pci_host.h" 31#include "trace.h" 32#include "qom/object.h" 33 34struct PLBOutMap { 35 uint64_t la; 36 uint64_t pcia; 37 uint32_t sa; 38 MemoryRegion mr; 39}; 40 41struct PLBInMap { 42 uint64_t sa; 43 uint64_t la; 44 MemoryRegion mr; 45}; 46 47#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host" 48OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST_BRIDGE) 49 50#define PPC440_PCIX_NR_POMS 3 51#define PPC440_PCIX_NR_PIMS 3 52 53struct PPC440PCIXState { 54 PCIHostState parent_obj; 55 56 PCIDevice *dev; 57 struct PLBOutMap pom[PPC440_PCIX_NR_POMS]; 58 struct PLBInMap pim[PPC440_PCIX_NR_PIMS]; 59 uint32_t sts; 60 qemu_irq irq; 61 AddressSpace bm_as; 62 MemoryRegion bm; 63 64 MemoryRegion container; 65 MemoryRegion iomem; 66 MemoryRegion busmem; 67}; 68 69#define PPC440_REG_BASE 0x80000 70#define PPC440_REG_SIZE 0xff 71 72#define PCIC0_CFGADDR 0x0 73#define PCIC0_CFGDATA 0x4 74 75#define PCIX0_POM0LAL 0x68 76#define PCIX0_POM0LAH 0x6c 77#define PCIX0_POM0SA 0x70 78#define PCIX0_POM0PCIAL 0x74 79#define PCIX0_POM0PCIAH 0x78 80#define PCIX0_POM1LAL 0x7c 81#define PCIX0_POM1LAH 0x80 82#define PCIX0_POM1SA 0x84 83#define PCIX0_POM1PCIAL 0x88 84#define PCIX0_POM1PCIAH 0x8c 85#define PCIX0_POM2SA 0x90 86 87#define PCIX0_PIM0SAL 0x98 88#define PCIX0_PIM0LAL 0x9c 89#define PCIX0_PIM0LAH 0xa0 90#define PCIX0_PIM1SA 0xa4 91#define PCIX0_PIM1LAL 0xa8 92#define PCIX0_PIM1LAH 0xac 93#define PCIX0_PIM2SAL 0xb0 94#define PCIX0_PIM2LAL 0xb4 95#define PCIX0_PIM2LAH 0xb8 96#define PCIX0_PIM0SAH 0xf8 97#define PCIX0_PIM2SAH 0xfc 98 99#define PCIX0_STS 0xe0 100 101#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE) 102 103static void ppc440_pcix_clear_region(MemoryRegion *parent, 104 MemoryRegion *mem) 105{ 106 if (memory_region_is_mapped(mem)) { 107 memory_region_del_subregion(parent, mem); 108 object_unparent(OBJECT(mem)); 109 } 110} 111 112/* DMA mapping */ 113static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx) 114{ 115 MemoryRegion *mem = &s->pim[idx].mr; 116 char *name; 117 uint64_t size; 118 119 /* Before we modify anything, unmap and destroy the region */ 120 ppc440_pcix_clear_region(&s->bm, mem); 121 122 if (!(s->pim[idx].sa & 1)) { 123 /* Not enabled, nothing to do */ 124 return; 125 } 126 127 name = g_strdup_printf("PCI Inbound Window %d", idx); 128 size = ~(s->pim[idx].sa & ~7ULL) + 1; 129 memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(), 130 s->pim[idx].la, size); 131 memory_region_add_subregion_overlap(&s->bm, 0, mem, -1); 132 g_free(name); 133 134 trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la); 135} 136 137/* BAR mapping */ 138static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx) 139{ 140 MemoryRegion *mem = &s->pom[idx].mr; 141 MemoryRegion *address_space_mem = get_system_memory(); 142 char *name; 143 uint32_t size; 144 145 /* Before we modify anything, unmap and destroy the region */ 146 ppc440_pcix_clear_region(address_space_mem, mem); 147 148 if (!(s->pom[idx].sa & 1)) { 149 /* Not enabled, nothing to do */ 150 return; 151 } 152 153 name = g_strdup_printf("PCI Outbound Window %d", idx); 154 size = ~(s->pom[idx].sa & 0xfffffffe) + 1; 155 if (!size) { 156 size = 0xffffffff; 157 } 158 memory_region_init_alias(mem, OBJECT(s), name, &s->busmem, 159 s->pom[idx].pcia, size); 160 memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem); 161 g_free(name); 162 163 trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia); 164} 165 166static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr, 167 uint64_t val, unsigned size) 168{ 169 struct PPC440PCIXState *s = opaque; 170 171 trace_ppc440_pcix_reg_write(addr, val, size); 172 switch (addr) { 173 case PCI_VENDOR_ID ... PCI_MAX_LAT: 174 stl_le_p(s->dev->config + addr, val); 175 break; 176 177 case PCIX0_POM0LAL: 178 s->pom[0].la &= 0xffffffff00000000ULL; 179 s->pom[0].la |= val; 180 ppc440_pcix_update_pom(s, 0); 181 break; 182 case PCIX0_POM0LAH: 183 s->pom[0].la &= 0xffffffffULL; 184 s->pom[0].la |= val << 32; 185 ppc440_pcix_update_pom(s, 0); 186 break; 187 case PCIX0_POM0SA: 188 s->pom[0].sa = val; 189 ppc440_pcix_update_pom(s, 0); 190 break; 191 case PCIX0_POM0PCIAL: 192 s->pom[0].pcia &= 0xffffffff00000000ULL; 193 s->pom[0].pcia |= val; 194 ppc440_pcix_update_pom(s, 0); 195 break; 196 case PCIX0_POM0PCIAH: 197 s->pom[0].pcia &= 0xffffffffULL; 198 s->pom[0].pcia |= val << 32; 199 ppc440_pcix_update_pom(s, 0); 200 break; 201 case PCIX0_POM1LAL: 202 s->pom[1].la &= 0xffffffff00000000ULL; 203 s->pom[1].la |= val; 204 ppc440_pcix_update_pom(s, 1); 205 break; 206 case PCIX0_POM1LAH: 207 s->pom[1].la &= 0xffffffffULL; 208 s->pom[1].la |= val << 32; 209 ppc440_pcix_update_pom(s, 1); 210 break; 211 case PCIX0_POM1SA: 212 s->pom[1].sa = val; 213 ppc440_pcix_update_pom(s, 1); 214 break; 215 case PCIX0_POM1PCIAL: 216 s->pom[1].pcia &= 0xffffffff00000000ULL; 217 s->pom[1].pcia |= val; 218 ppc440_pcix_update_pom(s, 1); 219 break; 220 case PCIX0_POM1PCIAH: 221 s->pom[1].pcia &= 0xffffffffULL; 222 s->pom[1].pcia |= val << 32; 223 ppc440_pcix_update_pom(s, 1); 224 break; 225 case PCIX0_POM2SA: 226 s->pom[2].sa = val; 227 break; 228 229 case PCIX0_PIM0SAL: 230 s->pim[0].sa &= 0xffffffff00000000ULL; 231 s->pim[0].sa |= val; 232 ppc440_pcix_update_pim(s, 0); 233 break; 234 case PCIX0_PIM0LAL: 235 s->pim[0].la &= 0xffffffff00000000ULL; 236 s->pim[0].la |= val; 237 ppc440_pcix_update_pim(s, 0); 238 break; 239 case PCIX0_PIM0LAH: 240 s->pim[0].la &= 0xffffffffULL; 241 s->pim[0].la |= val << 32; 242 ppc440_pcix_update_pim(s, 0); 243 break; 244 case PCIX0_PIM1SA: 245 s->pim[1].sa = val; 246 ppc440_pcix_update_pim(s, 1); 247 break; 248 case PCIX0_PIM1LAL: 249 s->pim[1].la &= 0xffffffff00000000ULL; 250 s->pim[1].la |= val; 251 ppc440_pcix_update_pim(s, 1); 252 break; 253 case PCIX0_PIM1LAH: 254 s->pim[1].la &= 0xffffffffULL; 255 s->pim[1].la |= val << 32; 256 ppc440_pcix_update_pim(s, 1); 257 break; 258 case PCIX0_PIM2SAL: 259 s->pim[2].sa &= 0xffffffff00000000ULL; 260 s->pim[2].sa |= val; 261 ppc440_pcix_update_pim(s, 2); 262 break; 263 case PCIX0_PIM2LAL: 264 s->pim[2].la &= 0xffffffff00000000ULL; 265 s->pim[2].la |= val; 266 ppc440_pcix_update_pim(s, 2); 267 break; 268 case PCIX0_PIM2LAH: 269 s->pim[2].la &= 0xffffffffULL; 270 s->pim[2].la |= val << 32; 271 ppc440_pcix_update_pim(s, 2); 272 break; 273 274 case PCIX0_STS: 275 s->sts = val; 276 break; 277 278 case PCIX0_PIM0SAH: 279 s->pim[0].sa &= 0xffffffffULL; 280 s->pim[0].sa |= val << 32; 281 ppc440_pcix_update_pim(s, 0); 282 break; 283 case PCIX0_PIM2SAH: 284 s->pim[2].sa &= 0xffffffffULL; 285 s->pim[2].sa |= val << 32; 286 ppc440_pcix_update_pim(s, 2); 287 break; 288 289 default: 290 qemu_log_mask(LOG_UNIMP, 291 "%s: unhandled PCI internal register 0x%"HWADDR_PRIx"\n", 292 __func__, addr); 293 break; 294 } 295} 296 297static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr, 298 unsigned size) 299{ 300 struct PPC440PCIXState *s = opaque; 301 uint32_t val; 302 303 switch (addr) { 304 case PCI_VENDOR_ID ... PCI_MAX_LAT: 305 val = ldl_le_p(s->dev->config + addr); 306 break; 307 308 case PCIX0_POM0LAL: 309 val = s->pom[0].la; 310 break; 311 case PCIX0_POM0LAH: 312 val = s->pom[0].la >> 32; 313 break; 314 case PCIX0_POM0SA: 315 val = s->pom[0].sa; 316 break; 317 case PCIX0_POM0PCIAL: 318 val = s->pom[0].pcia; 319 break; 320 case PCIX0_POM0PCIAH: 321 val = s->pom[0].pcia >> 32; 322 break; 323 case PCIX0_POM1LAL: 324 val = s->pom[1].la; 325 break; 326 case PCIX0_POM1LAH: 327 val = s->pom[1].la >> 32; 328 break; 329 case PCIX0_POM1SA: 330 val = s->pom[1].sa; 331 break; 332 case PCIX0_POM1PCIAL: 333 val = s->pom[1].pcia; 334 break; 335 case PCIX0_POM1PCIAH: 336 val = s->pom[1].pcia >> 32; 337 break; 338 case PCIX0_POM2SA: 339 val = s->pom[2].sa; 340 break; 341 342 case PCIX0_PIM0SAL: 343 val = s->pim[0].sa; 344 break; 345 case PCIX0_PIM0LAL: 346 val = s->pim[0].la; 347 break; 348 case PCIX0_PIM0LAH: 349 val = s->pim[0].la >> 32; 350 break; 351 case PCIX0_PIM1SA: 352 val = s->pim[1].sa; 353 break; 354 case PCIX0_PIM1LAL: 355 val = s->pim[1].la; 356 break; 357 case PCIX0_PIM1LAH: 358 val = s->pim[1].la >> 32; 359 break; 360 case PCIX0_PIM2SAL: 361 val = s->pim[2].sa; 362 break; 363 case PCIX0_PIM2LAL: 364 val = s->pim[2].la; 365 break; 366 case PCIX0_PIM2LAH: 367 val = s->pim[2].la >> 32; 368 break; 369 370 case PCIX0_STS: 371 val = s->sts; 372 break; 373 374 case PCIX0_PIM0SAH: 375 val = s->pim[0].sa >> 32; 376 break; 377 case PCIX0_PIM2SAH: 378 val = s->pim[2].sa >> 32; 379 break; 380 381 default: 382 qemu_log_mask(LOG_UNIMP, 383 "%s: invalid PCI internal register 0x%" HWADDR_PRIx "\n", 384 __func__, addr); 385 val = 0; 386 } 387 388 trace_ppc440_pcix_reg_read(addr, val); 389 return val; 390} 391 392static const MemoryRegionOps pci_reg_ops = { 393 .read = ppc440_pcix_reg_read4, 394 .write = ppc440_pcix_reg_write4, 395 .endianness = DEVICE_LITTLE_ENDIAN, 396}; 397 398static void ppc440_pcix_reset(DeviceState *dev) 399{ 400 struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev); 401 int i; 402 403 for (i = 0; i < PPC440_PCIX_NR_POMS; i++) { 404 ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr); 405 } 406 for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) { 407 ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr); 408 } 409 memset(s->pom, 0, sizeof(s->pom)); 410 memset(s->pim, 0, sizeof(s->pim)); 411 for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) { 412 s->pim[i].sa = 0xffffffff00000000ULL; 413 } 414 s->sts = 0; 415} 416 417/* 418 * All four IRQ[ABCD] pins from all slots are tied to a single board 419 * IRQ, so our mapping function here maps everything to IRQ 0. 420 * The code in pci_change_irq_level() tracks the number of times 421 * the mapped IRQ is asserted and deasserted, so if multiple devices 422 * assert an IRQ at the same time the behaviour is correct. 423 * 424 * This may need further refactoring for boards that use multiple IRQ lines. 425 */ 426static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num) 427{ 428 trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, 0); 429 return 0; 430} 431 432static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level) 433{ 434 qemu_irq *pci_irq = opaque; 435 436 trace_ppc440_pcix_set_irq(irq_num); 437 if (irq_num < 0) { 438 error_report("%s: PCI irq %d", __func__, irq_num); 439 return; 440 } 441 qemu_set_irq(*pci_irq, level); 442} 443 444static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) 445{ 446 PPC440PCIXState *s = opaque; 447 448 return &s->bm_as; 449} 450 451/* 452 * Some guests on sam460ex write all kinds of garbage here such as 453 * missing enable bit and low bits set and still expect this to work 454 * (apparently it does on real hardware because these boot there) so 455 * we have to override these ops here and fix it up 456 */ 457static void pci_host_config_write(void *opaque, hwaddr addr, 458 uint64_t val, unsigned len) 459{ 460 PCIHostState *s = opaque; 461 462 if (addr != 0 || len != 4) { 463 return; 464 } 465 s->config_reg = (val & 0xfffffffcULL) | (1UL << 31); 466} 467 468static uint64_t pci_host_config_read(void *opaque, hwaddr addr, 469 unsigned len) 470{ 471 PCIHostState *s = opaque; 472 uint32_t val = s->config_reg; 473 474 return val; 475} 476 477const MemoryRegionOps ppc440_pcix_host_conf_ops = { 478 .read = pci_host_config_read, 479 .write = pci_host_config_write, 480 .endianness = DEVICE_LITTLE_ENDIAN, 481}; 482 483static void ppc440_pcix_realize(DeviceState *dev, Error **errp) 484{ 485 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 486 PPC440PCIXState *s; 487 PCIHostState *h; 488 489 h = PCI_HOST_BRIDGE(dev); 490 s = PPC440_PCIX_HOST_BRIDGE(dev); 491 492 sysbus_init_irq(sbd, &s->irq); 493 memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX); 494 h->bus = pci_register_root_bus(dev, NULL, ppc440_pcix_set_irq, 495 ppc440_pcix_map_irq, &s->irq, &s->busmem, 496 get_system_io(), PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS); 497 498 s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge"); 499 500 memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX); 501 memory_region_add_subregion(&s->bm, 0x0, &s->busmem); 502 address_space_init(&s->bm_as, &s->bm, "pci-bm"); 503 pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); 504 505 memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); 506 memory_region_init_io(&h->conf_mem, OBJECT(s), &ppc440_pcix_host_conf_ops, 507 h, "pci-conf-idx", 4); 508 memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, 509 h, "pci-conf-data", 4); 510 memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s, 511 "pci.reg", PPC440_REG_SIZE); 512 memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); 513 memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); 514 memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem); 515 sysbus_init_mmio(sbd, &s->container); 516} 517 518static void ppc440_pcix_class_init(ObjectClass *klass, void *data) 519{ 520 DeviceClass *dc = DEVICE_CLASS(klass); 521 522 dc->realize = ppc440_pcix_realize; 523 dc->reset = ppc440_pcix_reset; 524} 525 526static const TypeInfo ppc440_pcix_info = { 527 .name = TYPE_PPC440_PCIX_HOST_BRIDGE, 528 .parent = TYPE_PCI_HOST_BRIDGE, 529 .instance_size = sizeof(PPC440PCIXState), 530 .class_init = ppc440_pcix_class_init, 531}; 532 533static void ppc440_pcix_register_types(void) 534{ 535 type_register_static(&ppc440_pcix_info); 536} 537 538type_init(ppc440_pcix_register_types)