146fd3201SPhilippe Mathieu-Daudé /*
246fd3201SPhilippe Mathieu-Daudé * QEMU PREP PCI host
346fd3201SPhilippe Mathieu-Daudé *
446fd3201SPhilippe Mathieu-Daudé * Copyright (c) 2006 Fabrice Bellard
546fd3201SPhilippe Mathieu-Daudé * Copyright (c) 2011-2013 Andreas Färber
646fd3201SPhilippe Mathieu-Daudé *
746fd3201SPhilippe Mathieu-Daudé * Permission is hereby granted, free of charge, to any person obtaining a copy
846fd3201SPhilippe Mathieu-Daudé * of this software and associated documentation files (the "Software"), to deal
946fd3201SPhilippe Mathieu-Daudé * in the Software without restriction, including without limitation the rights
1046fd3201SPhilippe Mathieu-Daudé * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1146fd3201SPhilippe Mathieu-Daudé * copies of the Software, and to permit persons to whom the Software is
1246fd3201SPhilippe Mathieu-Daudé * furnished to do so, subject to the following conditions:
1346fd3201SPhilippe Mathieu-Daudé *
1446fd3201SPhilippe Mathieu-Daudé * The above copyright notice and this permission notice shall be included in
1546fd3201SPhilippe Mathieu-Daudé * all copies or substantial portions of the Software.
1646fd3201SPhilippe Mathieu-Daudé *
1746fd3201SPhilippe Mathieu-Daudé * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1846fd3201SPhilippe Mathieu-Daudé * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1946fd3201SPhilippe Mathieu-Daudé * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2046fd3201SPhilippe Mathieu-Daudé * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2146fd3201SPhilippe Mathieu-Daudé * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2246fd3201SPhilippe Mathieu-Daudé * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2346fd3201SPhilippe Mathieu-Daudé * THE SOFTWARE.
2446fd3201SPhilippe Mathieu-Daudé */
2546fd3201SPhilippe Mathieu-Daudé
2646fd3201SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
2746fd3201SPhilippe Mathieu-Daudé #include "qemu/datadir.h"
2846fd3201SPhilippe Mathieu-Daudé #include "qemu/units.h"
2946fd3201SPhilippe Mathieu-Daudé #include "qemu/log.h"
3046fd3201SPhilippe Mathieu-Daudé #include "qapi/error.h"
31edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
3246fd3201SPhilippe Mathieu-Daudé #include "hw/pci/pci_bus.h"
3346fd3201SPhilippe Mathieu-Daudé #include "hw/pci/pci_host.h"
3446fd3201SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
3546fd3201SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
3646fd3201SPhilippe Mathieu-Daudé #include "hw/intc/i8259.h"
3746fd3201SPhilippe Mathieu-Daudé #include "hw/irq.h"
3846fd3201SPhilippe Mathieu-Daudé #include "hw/loader.h"
3946fd3201SPhilippe Mathieu-Daudé #include "hw/or-irq.h"
4046fd3201SPhilippe Mathieu-Daudé #include "elf.h"
4146fd3201SPhilippe Mathieu-Daudé #include "qom/object.h"
4246fd3201SPhilippe Mathieu-Daudé
4346fd3201SPhilippe Mathieu-Daudé #define TYPE_RAVEN_PCI_DEVICE "raven"
4446fd3201SPhilippe Mathieu-Daudé #define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
4546fd3201SPhilippe Mathieu-Daudé
4646fd3201SPhilippe Mathieu-Daudé OBJECT_DECLARE_SIMPLE_TYPE(RavenPCIState, RAVEN_PCI_DEVICE)
4746fd3201SPhilippe Mathieu-Daudé
4846fd3201SPhilippe Mathieu-Daudé struct RavenPCIState {
4946fd3201SPhilippe Mathieu-Daudé PCIDevice dev;
5046fd3201SPhilippe Mathieu-Daudé
5146fd3201SPhilippe Mathieu-Daudé uint32_t elf_machine;
5246fd3201SPhilippe Mathieu-Daudé char *bios_name;
5346fd3201SPhilippe Mathieu-Daudé MemoryRegion bios;
5446fd3201SPhilippe Mathieu-Daudé };
5546fd3201SPhilippe Mathieu-Daudé
5646fd3201SPhilippe Mathieu-Daudé typedef struct PRePPCIState PREPPCIState;
5746fd3201SPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(PREPPCIState, RAVEN_PCI_HOST_BRIDGE,
5846fd3201SPhilippe Mathieu-Daudé TYPE_RAVEN_PCI_HOST_BRIDGE)
5946fd3201SPhilippe Mathieu-Daudé
6046fd3201SPhilippe Mathieu-Daudé struct PRePPCIState {
6146fd3201SPhilippe Mathieu-Daudé PCIHostState parent_obj;
6246fd3201SPhilippe Mathieu-Daudé
63e844f0c5SPhilippe Mathieu-Daudé OrIRQState *or_irq;
6446fd3201SPhilippe Mathieu-Daudé qemu_irq pci_irqs[PCI_NUM_PINS];
6546fd3201SPhilippe Mathieu-Daudé PCIBus pci_bus;
6646fd3201SPhilippe Mathieu-Daudé AddressSpace pci_io_as;
6746fd3201SPhilippe Mathieu-Daudé MemoryRegion pci_io;
6846fd3201SPhilippe Mathieu-Daudé MemoryRegion pci_io_non_contiguous;
6946fd3201SPhilippe Mathieu-Daudé MemoryRegion pci_memory;
7046fd3201SPhilippe Mathieu-Daudé MemoryRegion pci_intack;
7146fd3201SPhilippe Mathieu-Daudé MemoryRegion bm;
7246fd3201SPhilippe Mathieu-Daudé MemoryRegion bm_ram_alias;
7346fd3201SPhilippe Mathieu-Daudé MemoryRegion bm_pci_memory_alias;
7446fd3201SPhilippe Mathieu-Daudé AddressSpace bm_as;
7546fd3201SPhilippe Mathieu-Daudé RavenPCIState pci_dev;
7646fd3201SPhilippe Mathieu-Daudé
7746fd3201SPhilippe Mathieu-Daudé int contiguous_map;
7846fd3201SPhilippe Mathieu-Daudé bool is_legacy_prep;
7946fd3201SPhilippe Mathieu-Daudé };
8046fd3201SPhilippe Mathieu-Daudé
8146fd3201SPhilippe Mathieu-Daudé #define BIOS_SIZE (1 * MiB)
8246fd3201SPhilippe Mathieu-Daudé
8364e73920SPhilippe Mathieu-Daudé #define PCI_IO_BASE_ADDR 0x80000000 /* Physical address on main bus */
8464e73920SPhilippe Mathieu-Daudé
raven_pci_io_config(hwaddr addr)8546fd3201SPhilippe Mathieu-Daudé static inline uint32_t raven_pci_io_config(hwaddr addr)
8646fd3201SPhilippe Mathieu-Daudé {
8746fd3201SPhilippe Mathieu-Daudé int i;
8846fd3201SPhilippe Mathieu-Daudé
8946fd3201SPhilippe Mathieu-Daudé for (i = 0; i < 11; i++) {
9046fd3201SPhilippe Mathieu-Daudé if ((addr & (1 << (11 + i))) != 0) {
9146fd3201SPhilippe Mathieu-Daudé break;
9246fd3201SPhilippe Mathieu-Daudé }
9346fd3201SPhilippe Mathieu-Daudé }
9446fd3201SPhilippe Mathieu-Daudé return (addr & 0x7ff) | (i << 11);
9546fd3201SPhilippe Mathieu-Daudé }
9646fd3201SPhilippe Mathieu-Daudé
raven_pci_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned int size)9746fd3201SPhilippe Mathieu-Daudé static void raven_pci_io_write(void *opaque, hwaddr addr,
9846fd3201SPhilippe Mathieu-Daudé uint64_t val, unsigned int size)
9946fd3201SPhilippe Mathieu-Daudé {
10046fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
10146fd3201SPhilippe Mathieu-Daudé PCIHostState *phb = PCI_HOST_BRIDGE(s);
10246fd3201SPhilippe Mathieu-Daudé pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
10346fd3201SPhilippe Mathieu-Daudé }
10446fd3201SPhilippe Mathieu-Daudé
raven_pci_io_read(void * opaque,hwaddr addr,unsigned int size)10546fd3201SPhilippe Mathieu-Daudé static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
10646fd3201SPhilippe Mathieu-Daudé unsigned int size)
10746fd3201SPhilippe Mathieu-Daudé {
10846fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
10946fd3201SPhilippe Mathieu-Daudé PCIHostState *phb = PCI_HOST_BRIDGE(s);
11046fd3201SPhilippe Mathieu-Daudé return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
11146fd3201SPhilippe Mathieu-Daudé }
11246fd3201SPhilippe Mathieu-Daudé
11346fd3201SPhilippe Mathieu-Daudé static const MemoryRegionOps raven_pci_io_ops = {
11446fd3201SPhilippe Mathieu-Daudé .read = raven_pci_io_read,
11546fd3201SPhilippe Mathieu-Daudé .write = raven_pci_io_write,
11646fd3201SPhilippe Mathieu-Daudé .endianness = DEVICE_LITTLE_ENDIAN,
11746fd3201SPhilippe Mathieu-Daudé };
11846fd3201SPhilippe Mathieu-Daudé
raven_intack_read(void * opaque,hwaddr addr,unsigned int size)11946fd3201SPhilippe Mathieu-Daudé static uint64_t raven_intack_read(void *opaque, hwaddr addr,
12046fd3201SPhilippe Mathieu-Daudé unsigned int size)
12146fd3201SPhilippe Mathieu-Daudé {
12246fd3201SPhilippe Mathieu-Daudé return pic_read_irq(isa_pic);
12346fd3201SPhilippe Mathieu-Daudé }
12446fd3201SPhilippe Mathieu-Daudé
raven_intack_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)12546fd3201SPhilippe Mathieu-Daudé static void raven_intack_write(void *opaque, hwaddr addr,
12646fd3201SPhilippe Mathieu-Daudé uint64_t data, unsigned size)
12746fd3201SPhilippe Mathieu-Daudé {
12846fd3201SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__);
12946fd3201SPhilippe Mathieu-Daudé }
13046fd3201SPhilippe Mathieu-Daudé
13146fd3201SPhilippe Mathieu-Daudé static const MemoryRegionOps raven_intack_ops = {
13246fd3201SPhilippe Mathieu-Daudé .read = raven_intack_read,
13346fd3201SPhilippe Mathieu-Daudé .write = raven_intack_write,
13446fd3201SPhilippe Mathieu-Daudé .valid = {
13546fd3201SPhilippe Mathieu-Daudé .max_access_size = 1,
13646fd3201SPhilippe Mathieu-Daudé },
13746fd3201SPhilippe Mathieu-Daudé };
13846fd3201SPhilippe Mathieu-Daudé
raven_io_address(PREPPCIState * s,hwaddr addr)13946fd3201SPhilippe Mathieu-Daudé static inline hwaddr raven_io_address(PREPPCIState *s,
14046fd3201SPhilippe Mathieu-Daudé hwaddr addr)
14146fd3201SPhilippe Mathieu-Daudé {
14246fd3201SPhilippe Mathieu-Daudé if (s->contiguous_map == 0) {
14346fd3201SPhilippe Mathieu-Daudé /* 64 KB contiguous space for IOs */
14446fd3201SPhilippe Mathieu-Daudé addr &= 0xFFFF;
14546fd3201SPhilippe Mathieu-Daudé } else {
14646fd3201SPhilippe Mathieu-Daudé /* 8 MB non-contiguous space for IOs */
14746fd3201SPhilippe Mathieu-Daudé addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
14846fd3201SPhilippe Mathieu-Daudé }
14946fd3201SPhilippe Mathieu-Daudé
15046fd3201SPhilippe Mathieu-Daudé /* FIXME: handle endianness switch */
15146fd3201SPhilippe Mathieu-Daudé
15246fd3201SPhilippe Mathieu-Daudé return addr;
15346fd3201SPhilippe Mathieu-Daudé }
15446fd3201SPhilippe Mathieu-Daudé
raven_io_read(void * opaque,hwaddr addr,unsigned int size)15546fd3201SPhilippe Mathieu-Daudé static uint64_t raven_io_read(void *opaque, hwaddr addr,
15646fd3201SPhilippe Mathieu-Daudé unsigned int size)
15746fd3201SPhilippe Mathieu-Daudé {
15846fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
15946fd3201SPhilippe Mathieu-Daudé uint8_t buf[4];
16046fd3201SPhilippe Mathieu-Daudé
16146fd3201SPhilippe Mathieu-Daudé addr = raven_io_address(s, addr);
16264e73920SPhilippe Mathieu-Daudé address_space_read(&s->pci_io_as, addr + PCI_IO_BASE_ADDR,
16346fd3201SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED, buf, size);
16446fd3201SPhilippe Mathieu-Daudé
16546fd3201SPhilippe Mathieu-Daudé if (size == 1) {
16646fd3201SPhilippe Mathieu-Daudé return buf[0];
16746fd3201SPhilippe Mathieu-Daudé } else if (size == 2) {
16846fd3201SPhilippe Mathieu-Daudé return lduw_le_p(buf);
16946fd3201SPhilippe Mathieu-Daudé } else if (size == 4) {
17046fd3201SPhilippe Mathieu-Daudé return ldl_le_p(buf);
17146fd3201SPhilippe Mathieu-Daudé } else {
17246fd3201SPhilippe Mathieu-Daudé g_assert_not_reached();
17346fd3201SPhilippe Mathieu-Daudé }
17446fd3201SPhilippe Mathieu-Daudé }
17546fd3201SPhilippe Mathieu-Daudé
raven_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned int size)17646fd3201SPhilippe Mathieu-Daudé static void raven_io_write(void *opaque, hwaddr addr,
17746fd3201SPhilippe Mathieu-Daudé uint64_t val, unsigned int size)
17846fd3201SPhilippe Mathieu-Daudé {
17946fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
18046fd3201SPhilippe Mathieu-Daudé uint8_t buf[4];
18146fd3201SPhilippe Mathieu-Daudé
18246fd3201SPhilippe Mathieu-Daudé addr = raven_io_address(s, addr);
18346fd3201SPhilippe Mathieu-Daudé
18446fd3201SPhilippe Mathieu-Daudé if (size == 1) {
18546fd3201SPhilippe Mathieu-Daudé buf[0] = val;
18646fd3201SPhilippe Mathieu-Daudé } else if (size == 2) {
18746fd3201SPhilippe Mathieu-Daudé stw_le_p(buf, val);
18846fd3201SPhilippe Mathieu-Daudé } else if (size == 4) {
18946fd3201SPhilippe Mathieu-Daudé stl_le_p(buf, val);
19046fd3201SPhilippe Mathieu-Daudé } else {
19146fd3201SPhilippe Mathieu-Daudé g_assert_not_reached();
19246fd3201SPhilippe Mathieu-Daudé }
19346fd3201SPhilippe Mathieu-Daudé
19464e73920SPhilippe Mathieu-Daudé address_space_write(&s->pci_io_as, addr + PCI_IO_BASE_ADDR,
19546fd3201SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED, buf, size);
19646fd3201SPhilippe Mathieu-Daudé }
19746fd3201SPhilippe Mathieu-Daudé
19846fd3201SPhilippe Mathieu-Daudé static const MemoryRegionOps raven_io_ops = {
19946fd3201SPhilippe Mathieu-Daudé .read = raven_io_read,
20046fd3201SPhilippe Mathieu-Daudé .write = raven_io_write,
20146fd3201SPhilippe Mathieu-Daudé .endianness = DEVICE_LITTLE_ENDIAN,
20246fd3201SPhilippe Mathieu-Daudé .impl.max_access_size = 4,
203*f94d58f2SPeter Maydell .impl.unaligned = true,
20446fd3201SPhilippe Mathieu-Daudé .valid.unaligned = true,
20546fd3201SPhilippe Mathieu-Daudé };
20646fd3201SPhilippe Mathieu-Daudé
raven_map_irq(PCIDevice * pci_dev,int irq_num)20746fd3201SPhilippe Mathieu-Daudé static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
20846fd3201SPhilippe Mathieu-Daudé {
20946fd3201SPhilippe Mathieu-Daudé return (irq_num + (pci_dev->devfn >> 3)) & 1;
21046fd3201SPhilippe Mathieu-Daudé }
21146fd3201SPhilippe Mathieu-Daudé
raven_set_irq(void * opaque,int irq_num,int level)21246fd3201SPhilippe Mathieu-Daudé static void raven_set_irq(void *opaque, int irq_num, int level)
21346fd3201SPhilippe Mathieu-Daudé {
21446fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
21546fd3201SPhilippe Mathieu-Daudé
21646fd3201SPhilippe Mathieu-Daudé qemu_set_irq(s->pci_irqs[irq_num], level);
21746fd3201SPhilippe Mathieu-Daudé }
21846fd3201SPhilippe Mathieu-Daudé
raven_pcihost_set_iommu(PCIBus * bus,void * opaque,int devfn)21946fd3201SPhilippe Mathieu-Daudé static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
22046fd3201SPhilippe Mathieu-Daudé int devfn)
22146fd3201SPhilippe Mathieu-Daudé {
22246fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
22346fd3201SPhilippe Mathieu-Daudé
22446fd3201SPhilippe Mathieu-Daudé return &s->bm_as;
22546fd3201SPhilippe Mathieu-Daudé }
22646fd3201SPhilippe Mathieu-Daudé
227ba7d12ebSYi Liu static const PCIIOMMUOps raven_iommu_ops = {
228ba7d12ebSYi Liu .get_address_space = raven_pcihost_set_iommu,
229ba7d12ebSYi Liu };
230ba7d12ebSYi Liu
raven_change_gpio(void * opaque,int n,int level)23146fd3201SPhilippe Mathieu-Daudé static void raven_change_gpio(void *opaque, int n, int level)
23246fd3201SPhilippe Mathieu-Daudé {
23346fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = opaque;
23446fd3201SPhilippe Mathieu-Daudé
23546fd3201SPhilippe Mathieu-Daudé s->contiguous_map = level;
23646fd3201SPhilippe Mathieu-Daudé }
23746fd3201SPhilippe Mathieu-Daudé
raven_pcihost_realizefn(DeviceState * d,Error ** errp)23846fd3201SPhilippe Mathieu-Daudé static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
23946fd3201SPhilippe Mathieu-Daudé {
24046fd3201SPhilippe Mathieu-Daudé SysBusDevice *dev = SYS_BUS_DEVICE(d);
24146fd3201SPhilippe Mathieu-Daudé PCIHostState *h = PCI_HOST_BRIDGE(dev);
24246fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
24346fd3201SPhilippe Mathieu-Daudé MemoryRegion *address_space_mem = get_system_memory();
24446fd3201SPhilippe Mathieu-Daudé int i;
24546fd3201SPhilippe Mathieu-Daudé
24646fd3201SPhilippe Mathieu-Daudé if (s->is_legacy_prep) {
24746fd3201SPhilippe Mathieu-Daudé for (i = 0; i < PCI_NUM_PINS; i++) {
24846fd3201SPhilippe Mathieu-Daudé sysbus_init_irq(dev, &s->pci_irqs[i]);
24946fd3201SPhilippe Mathieu-Daudé }
25046fd3201SPhilippe Mathieu-Daudé } else {
25146fd3201SPhilippe Mathieu-Daudé /* According to PReP specification section 6.1.6 "System Interrupt
25246fd3201SPhilippe Mathieu-Daudé * Assignments", all PCI interrupts are routed via IRQ 15 */
25346fd3201SPhilippe Mathieu-Daudé s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ));
25446fd3201SPhilippe Mathieu-Daudé object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS,
25546fd3201SPhilippe Mathieu-Daudé &error_fatal);
25646fd3201SPhilippe Mathieu-Daudé qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal);
25746fd3201SPhilippe Mathieu-Daudé sysbus_init_irq(dev, &s->or_irq->out_irq);
25846fd3201SPhilippe Mathieu-Daudé
25946fd3201SPhilippe Mathieu-Daudé for (i = 0; i < PCI_NUM_PINS; i++) {
26046fd3201SPhilippe Mathieu-Daudé s->pci_irqs[i] = qdev_get_gpio_in(DEVICE(s->or_irq), i);
26146fd3201SPhilippe Mathieu-Daudé }
26246fd3201SPhilippe Mathieu-Daudé }
26346fd3201SPhilippe Mathieu-Daudé
26446fd3201SPhilippe Mathieu-Daudé qdev_init_gpio_in(d, raven_change_gpio, 1);
26546fd3201SPhilippe Mathieu-Daudé
266f021f4e9SBernhard Beschow pci_bus_irqs(&s->pci_bus, raven_set_irq, s, PCI_NUM_PINS);
267f021f4e9SBernhard Beschow pci_bus_map_irqs(&s->pci_bus, raven_map_irq);
26846fd3201SPhilippe Mathieu-Daudé
26946fd3201SPhilippe Mathieu-Daudé memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
27046fd3201SPhilippe Mathieu-Daudé "pci-conf-idx", 4);
27146fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
27246fd3201SPhilippe Mathieu-Daudé
27346fd3201SPhilippe Mathieu-Daudé memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
27446fd3201SPhilippe Mathieu-Daudé "pci-conf-data", 4);
27546fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
27646fd3201SPhilippe Mathieu-Daudé
27746fd3201SPhilippe Mathieu-Daudé memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
27846fd3201SPhilippe Mathieu-Daudé "pciio", 0x00400000);
27946fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
28046fd3201SPhilippe Mathieu-Daudé
28146fd3201SPhilippe Mathieu-Daudé memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
28246fd3201SPhilippe Mathieu-Daudé "pci-intack", 1);
28346fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
28446fd3201SPhilippe Mathieu-Daudé
28546fd3201SPhilippe Mathieu-Daudé /* TODO Remove once realize propagates to child devices. */
28646fd3201SPhilippe Mathieu-Daudé qdev_realize(DEVICE(&s->pci_dev), BUS(&s->pci_bus), errp);
28746fd3201SPhilippe Mathieu-Daudé }
28846fd3201SPhilippe Mathieu-Daudé
raven_pcihost_initfn(Object * obj)28946fd3201SPhilippe Mathieu-Daudé static void raven_pcihost_initfn(Object *obj)
29046fd3201SPhilippe Mathieu-Daudé {
29146fd3201SPhilippe Mathieu-Daudé PCIHostState *h = PCI_HOST_BRIDGE(obj);
29246fd3201SPhilippe Mathieu-Daudé PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
29346fd3201SPhilippe Mathieu-Daudé MemoryRegion *address_space_mem = get_system_memory();
29446fd3201SPhilippe Mathieu-Daudé DeviceState *pci_dev;
29546fd3201SPhilippe Mathieu-Daudé
29646fd3201SPhilippe Mathieu-Daudé memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
29746fd3201SPhilippe Mathieu-Daudé memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
29846fd3201SPhilippe Mathieu-Daudé "pci-io-non-contiguous", 0x00800000);
29946fd3201SPhilippe Mathieu-Daudé memory_region_init(&s->pci_memory, obj, "pci-memory", 0x3f000000);
30046fd3201SPhilippe Mathieu-Daudé address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
30146fd3201SPhilippe Mathieu-Daudé
3026dad5a68SAlexander Bulekov /*
3036dad5a68SAlexander Bulekov * Raven's raven_io_ops use the address-space API to access pci-conf-idx
3046dad5a68SAlexander Bulekov * (which is also owned by the raven device). As such, mark the
3056dad5a68SAlexander Bulekov * pci_io_non_contiguous as re-entrancy safe.
3066dad5a68SAlexander Bulekov */
3076dad5a68SAlexander Bulekov s->pci_io_non_contiguous.disable_reentrancy_guard = true;
3086dad5a68SAlexander Bulekov
30946fd3201SPhilippe Mathieu-Daudé /* CPU address space */
31064e73920SPhilippe Mathieu-Daudé memory_region_add_subregion(address_space_mem, PCI_IO_BASE_ADDR,
31164e73920SPhilippe Mathieu-Daudé &s->pci_io);
31264e73920SPhilippe Mathieu-Daudé memory_region_add_subregion_overlap(address_space_mem, PCI_IO_BASE_ADDR,
31346fd3201SPhilippe Mathieu-Daudé &s->pci_io_non_contiguous, 1);
31446fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
3158d4cdf01SPeter Maydell pci_root_bus_init(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
31646fd3201SPhilippe Mathieu-Daudé &s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
31746fd3201SPhilippe Mathieu-Daudé
31846fd3201SPhilippe Mathieu-Daudé /* Bus master address space */
31946fd3201SPhilippe Mathieu-Daudé memory_region_init(&s->bm, obj, "bm-raven", 4 * GiB);
32046fd3201SPhilippe Mathieu-Daudé memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
32146fd3201SPhilippe Mathieu-Daudé &s->pci_memory, 0,
32246fd3201SPhilippe Mathieu-Daudé memory_region_size(&s->pci_memory));
32346fd3201SPhilippe Mathieu-Daudé memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
32446fd3201SPhilippe Mathieu-Daudé get_system_memory(), 0, 0x80000000);
32546fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(&s->bm, 0 , &s->bm_pci_memory_alias);
32646fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
32746fd3201SPhilippe Mathieu-Daudé address_space_init(&s->bm_as, &s->bm, "raven-bm");
328ba7d12ebSYi Liu pci_setup_iommu(&s->pci_bus, &raven_iommu_ops, s);
32946fd3201SPhilippe Mathieu-Daudé
33046fd3201SPhilippe Mathieu-Daudé h->bus = &s->pci_bus;
33146fd3201SPhilippe Mathieu-Daudé
33246fd3201SPhilippe Mathieu-Daudé object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
33346fd3201SPhilippe Mathieu-Daudé pci_dev = DEVICE(&s->pci_dev);
33446fd3201SPhilippe Mathieu-Daudé object_property_set_int(OBJECT(&s->pci_dev), "addr", PCI_DEVFN(0, 0),
33546fd3201SPhilippe Mathieu-Daudé NULL);
33646fd3201SPhilippe Mathieu-Daudé qdev_prop_set_bit(pci_dev, "multifunction", false);
33746fd3201SPhilippe Mathieu-Daudé }
33846fd3201SPhilippe Mathieu-Daudé
raven_realize(PCIDevice * d,Error ** errp)33946fd3201SPhilippe Mathieu-Daudé static void raven_realize(PCIDevice *d, Error **errp)
34046fd3201SPhilippe Mathieu-Daudé {
34146fd3201SPhilippe Mathieu-Daudé RavenPCIState *s = RAVEN_PCI_DEVICE(d);
34246fd3201SPhilippe Mathieu-Daudé char *filename;
34346fd3201SPhilippe Mathieu-Daudé int bios_size = -1;
34446fd3201SPhilippe Mathieu-Daudé
3458a8c9c3aSPhilippe Mathieu-Daudé d->config[PCI_CACHE_LINE_SIZE] = 0x08;
3468a8c9c3aSPhilippe Mathieu-Daudé d->config[PCI_LATENCY_TIMER] = 0x10;
3478a8c9c3aSPhilippe Mathieu-Daudé d->config[PCI_CAPABILITY_LIST] = 0x00;
34846fd3201SPhilippe Mathieu-Daudé
349cb50fc68SPhilippe Mathieu-Daudé if (!memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios",
350cb50fc68SPhilippe Mathieu-Daudé BIOS_SIZE, errp)) {
351cb50fc68SPhilippe Mathieu-Daudé return;
352cb50fc68SPhilippe Mathieu-Daudé }
35346fd3201SPhilippe Mathieu-Daudé memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
35446fd3201SPhilippe Mathieu-Daudé &s->bios);
35546fd3201SPhilippe Mathieu-Daudé if (s->bios_name) {
35646fd3201SPhilippe Mathieu-Daudé filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
35746fd3201SPhilippe Mathieu-Daudé if (filename) {
35846fd3201SPhilippe Mathieu-Daudé if (s->elf_machine != EM_NONE) {
35946fd3201SPhilippe Mathieu-Daudé bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
36046fd3201SPhilippe Mathieu-Daudé NULL, NULL, NULL, 1, s->elf_machine,
36146fd3201SPhilippe Mathieu-Daudé 0, 0);
36246fd3201SPhilippe Mathieu-Daudé }
36346fd3201SPhilippe Mathieu-Daudé if (bios_size < 0) {
36446fd3201SPhilippe Mathieu-Daudé bios_size = get_image_size(filename);
36546fd3201SPhilippe Mathieu-Daudé if (bios_size > 0 && bios_size <= BIOS_SIZE) {
36646fd3201SPhilippe Mathieu-Daudé hwaddr bios_addr;
36746fd3201SPhilippe Mathieu-Daudé bios_size = (bios_size + 0xfff) & ~0xfff;
36846fd3201SPhilippe Mathieu-Daudé bios_addr = (uint32_t)(-BIOS_SIZE);
36946fd3201SPhilippe Mathieu-Daudé bios_size = load_image_targphys(filename, bios_addr,
37046fd3201SPhilippe Mathieu-Daudé bios_size);
37146fd3201SPhilippe Mathieu-Daudé }
37246fd3201SPhilippe Mathieu-Daudé }
37346fd3201SPhilippe Mathieu-Daudé }
37446fd3201SPhilippe Mathieu-Daudé g_free(filename);
37546fd3201SPhilippe Mathieu-Daudé if (bios_size < 0 || bios_size > BIOS_SIZE) {
37646fd3201SPhilippe Mathieu-Daudé memory_region_del_subregion(get_system_memory(), &s->bios);
37746fd3201SPhilippe Mathieu-Daudé error_setg(errp, "Could not load bios image '%s'", s->bios_name);
37846fd3201SPhilippe Mathieu-Daudé return;
37946fd3201SPhilippe Mathieu-Daudé }
38046fd3201SPhilippe Mathieu-Daudé }
38146fd3201SPhilippe Mathieu-Daudé
38246fd3201SPhilippe Mathieu-Daudé vmstate_register_ram_global(&s->bios);
38346fd3201SPhilippe Mathieu-Daudé }
38446fd3201SPhilippe Mathieu-Daudé
38546fd3201SPhilippe Mathieu-Daudé static const VMStateDescription vmstate_raven = {
38646fd3201SPhilippe Mathieu-Daudé .name = "raven",
38746fd3201SPhilippe Mathieu-Daudé .version_id = 0,
38846fd3201SPhilippe Mathieu-Daudé .minimum_version_id = 0,
389e2bd53a3SRichard Henderson .fields = (const VMStateField[]) {
39046fd3201SPhilippe Mathieu-Daudé VMSTATE_PCI_DEVICE(dev, RavenPCIState),
39146fd3201SPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST()
39246fd3201SPhilippe Mathieu-Daudé },
39346fd3201SPhilippe Mathieu-Daudé };
39446fd3201SPhilippe Mathieu-Daudé
raven_class_init(ObjectClass * klass,void * data)39546fd3201SPhilippe Mathieu-Daudé static void raven_class_init(ObjectClass *klass, void *data)
39646fd3201SPhilippe Mathieu-Daudé {
39746fd3201SPhilippe Mathieu-Daudé PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
39846fd3201SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass);
39946fd3201SPhilippe Mathieu-Daudé
40046fd3201SPhilippe Mathieu-Daudé k->realize = raven_realize;
40146fd3201SPhilippe Mathieu-Daudé k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
40246fd3201SPhilippe Mathieu-Daudé k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
40346fd3201SPhilippe Mathieu-Daudé k->revision = 0x00;
40446fd3201SPhilippe Mathieu-Daudé k->class_id = PCI_CLASS_BRIDGE_HOST;
40546fd3201SPhilippe Mathieu-Daudé dc->desc = "PReP Host Bridge - Motorola Raven";
40646fd3201SPhilippe Mathieu-Daudé dc->vmsd = &vmstate_raven;
40746fd3201SPhilippe Mathieu-Daudé /*
40846fd3201SPhilippe Mathieu-Daudé * Reason: PCI-facing part of the host bridge, not usable without
40946fd3201SPhilippe Mathieu-Daudé * the host-facing part, which can't be device_add'ed, yet.
41046fd3201SPhilippe Mathieu-Daudé */
41146fd3201SPhilippe Mathieu-Daudé dc->user_creatable = false;
41246fd3201SPhilippe Mathieu-Daudé }
41346fd3201SPhilippe Mathieu-Daudé
41446fd3201SPhilippe Mathieu-Daudé static const TypeInfo raven_info = {
41546fd3201SPhilippe Mathieu-Daudé .name = TYPE_RAVEN_PCI_DEVICE,
41646fd3201SPhilippe Mathieu-Daudé .parent = TYPE_PCI_DEVICE,
41746fd3201SPhilippe Mathieu-Daudé .instance_size = sizeof(RavenPCIState),
41846fd3201SPhilippe Mathieu-Daudé .class_init = raven_class_init,
41946fd3201SPhilippe Mathieu-Daudé .interfaces = (InterfaceInfo[]) {
42046fd3201SPhilippe Mathieu-Daudé { INTERFACE_CONVENTIONAL_PCI_DEVICE },
42146fd3201SPhilippe Mathieu-Daudé { },
42246fd3201SPhilippe Mathieu-Daudé },
42346fd3201SPhilippe Mathieu-Daudé };
42446fd3201SPhilippe Mathieu-Daudé
42546fd3201SPhilippe Mathieu-Daudé static Property raven_pcihost_properties[] = {
42646fd3201SPhilippe Mathieu-Daudé DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
42746fd3201SPhilippe Mathieu-Daudé EM_NONE),
42846fd3201SPhilippe Mathieu-Daudé DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
42946fd3201SPhilippe Mathieu-Daudé /* Temporary workaround until legacy prep machine is removed */
43046fd3201SPhilippe Mathieu-Daudé DEFINE_PROP_BOOL("is-legacy-prep", PREPPCIState, is_legacy_prep,
43146fd3201SPhilippe Mathieu-Daudé false),
43246fd3201SPhilippe Mathieu-Daudé DEFINE_PROP_END_OF_LIST()
43346fd3201SPhilippe Mathieu-Daudé };
43446fd3201SPhilippe Mathieu-Daudé
raven_pcihost_class_init(ObjectClass * klass,void * data)43546fd3201SPhilippe Mathieu-Daudé static void raven_pcihost_class_init(ObjectClass *klass, void *data)
43646fd3201SPhilippe Mathieu-Daudé {
43746fd3201SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass);
43846fd3201SPhilippe Mathieu-Daudé
43946fd3201SPhilippe Mathieu-Daudé set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
44046fd3201SPhilippe Mathieu-Daudé dc->realize = raven_pcihost_realizefn;
44146fd3201SPhilippe Mathieu-Daudé device_class_set_props(dc, raven_pcihost_properties);
44246fd3201SPhilippe Mathieu-Daudé dc->fw_name = "pci";
44346fd3201SPhilippe Mathieu-Daudé }
44446fd3201SPhilippe Mathieu-Daudé
44546fd3201SPhilippe Mathieu-Daudé static const TypeInfo raven_pcihost_info = {
44646fd3201SPhilippe Mathieu-Daudé .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
44746fd3201SPhilippe Mathieu-Daudé .parent = TYPE_PCI_HOST_BRIDGE,
44846fd3201SPhilippe Mathieu-Daudé .instance_size = sizeof(PREPPCIState),
44946fd3201SPhilippe Mathieu-Daudé .instance_init = raven_pcihost_initfn,
45046fd3201SPhilippe Mathieu-Daudé .class_init = raven_pcihost_class_init,
45146fd3201SPhilippe Mathieu-Daudé };
45246fd3201SPhilippe Mathieu-Daudé
raven_register_types(void)45346fd3201SPhilippe Mathieu-Daudé static void raven_register_types(void)
45446fd3201SPhilippe Mathieu-Daudé {
45546fd3201SPhilippe Mathieu-Daudé type_register_static(&raven_pcihost_info);
45646fd3201SPhilippe Mathieu-Daudé type_register_static(&raven_info);
45746fd3201SPhilippe Mathieu-Daudé }
45846fd3201SPhilippe Mathieu-Daudé
45946fd3201SPhilippe Mathieu-Daudé type_init(raven_register_types)
460