From e1030ca5abc97e1465bc03776ebccaff1e9f7083 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 1/6] sun4u: pass PCIDevice into pci_ebus_init() instead of PCIBus In order to wire up the ebus PCI address spaces differently then we need access to the underlying PCIDevice. Signed-off-by: Mark Cave-Ayland --- hw/sparc64/sun4u.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index bbdb40c330..bcac7fcc42 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -224,13 +224,11 @@ static void isa_irq_handler(void *opaque, int n, int level) /* EBUS (Eight bit bus) bridge */ static ISABus * -pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs) +pci_ebus_init(PCIDevice *pci_dev, qemu_irq *irqs) { qemu_irq *isa_irq; - PCIDevice *pci_dev; ISABus *isa_bus; - pci_dev = pci_create_simple(bus, devfn, "ebus"); isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0")); isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); isa_bus_irqs(isa_bus, isa_irq); @@ -429,6 +427,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, unsigned int i; uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; PCIBus *pci_bus, *pci_bus2, *pci_bus3; + PCIDevice *ebus; ISABus *isa_bus; SysBusDevice *s; qemu_irq *ivec_irqs, *pbm_irqs; @@ -452,7 +451,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_vga_init(pci_bus); // XXX Should be pci_bus3 - isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); + ebus = pci_create_simple(pci_bus, -1, "ebus"); + isa_bus = pci_ebus_init(ebus, pbm_irqs); i = 0; if (hwdef->console_serial_base) { From d6acc8a5cf561be3feed8dac236e8921f0b6a68d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 2/6] sun4u: switch to using qdev to instantiate fw_cfg interface Signed-off-by: Mark Cave-Ayland --- hw/sparc64/sun4u.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index bcac7fcc42..9507461810 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -512,7 +512,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, graphic_width, graphic_height, graphic_depth, (uint8_t *)&nd_table[0].macaddr); - fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT); + dev = qdev_create(NULL, TYPE_FW_CFG_IO); + qdev_prop_set_bit(dev, "dma_enabled", false); + object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, + OBJECT(dev), NULL); + qdev_init_nofail(dev); + memory_region_add_subregion(get_system_io(), BIOS_CFG_IOPORT, + &FW_CFG_IO(dev)->comb_iomem); + + fw_cfg = FW_CFG(dev); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); From 07c847413b8e3776f2f2c4375b2838d4ee0008ed Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 3/6] sun4u: expose fw_cfg and NVRAM on ebus PCI IO address space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow future changes to the sun4u PCI topology. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Acked-By: Artyom Tarasenko --- hw/sparc64/sun4u.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 9507461810..8d1e08923a 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -450,7 +450,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, &pci_bus3, &pbm_irqs); pci_vga_init(pci_bus); - // XXX Should be pci_bus3 + /* XXX Should be pci_bus3 */ ebus = pci_create_simple(pci_bus, -1, "ebus"); isa_bus = pci_ebus_init(ebus, pbm_irqs); @@ -492,7 +492,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* Map NVRAM into I/O (ebus) space */ nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59); s = SYS_BUS_DEVICE(nvram); - memory_region_add_subregion(get_system_io(), 0x2000, + memory_region_add_subregion(pci_address_space_io(ebus), 0x2000, sysbus_mmio_get_region(s, 0)); initrd_size = 0; @@ -514,10 +514,9 @@ static void sun4uv_init(MemoryRegion *address_space_mem, dev = qdev_create(NULL, TYPE_FW_CFG_IO); qdev_prop_set_bit(dev, "dma_enabled", false); - object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(dev), NULL); + object_property_add_child(OBJECT(ebus), TYPE_FW_CFG, OBJECT(dev), NULL); qdev_init_nofail(dev); - memory_region_add_subregion(get_system_io(), BIOS_CFG_IOPORT, + memory_region_add_subregion(pci_address_space_io(ebus), BIOS_CFG_IOPORT, &FW_CFG_IO(dev)->comb_iomem); fw_cfg = FW_CFG(dev); From 311f2b7a47105a5bc460d350e77667bcabb16832 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 4/6] apb: fix up PCI bus nomenclature Rather than referring to the PCI busses as bus2 and bus3, refer to them as busA and busB as per the documentation. Also replace the long bus names with the shorter pciA and pciB aliases (to make it easier to attach additional devices to either from the command line). Signed-off-by: Mark Cave-Ayland --- hw/pci-host/apb.c | 12 +++++------- hw/sparc64/sun4u.c | 8 ++++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 96e5d0b60d..c2a3af35b5 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -654,7 +654,7 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) PCIBus *pci_apb_init(hwaddr special_base, hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, + qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB, qemu_irq **pbm_irqs) { DeviceState *dev; @@ -705,18 +705,16 @@ PCIBus *pci_apb_init(hwaddr special_base, pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, "pbm-bridge"); br = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1", - pci_apb_map_irq); + pci_bridge_map_irq(br, "pciB", pci_apb_map_irq); qdev_init_nofail(&pci_dev->qdev); - *bus2 = pci_bridge_get_sec_bus(br); + *busB = pci_bridge_get_sec_bus(br); pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, "pbm-bridge"); br = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2", - pci_apb_map_irq); + pci_bridge_map_irq(br, "pciA", pci_apb_map_irq); qdev_init_nofail(&pci_dev->qdev); - *bus3 = pci_bridge_get_sec_bus(br); + *busA = pci_bridge_get_sec_bus(br); return phb->bus; } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 8d1e08923a..5e59269adc 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -426,7 +426,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, Nvram *nvram; unsigned int i; uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; - PCIBus *pci_bus, *pci_bus2, *pci_bus3; + PCIBus *pci_bus, *pci_busA, *pci_busB; PCIDevice *ebus; ISABus *isa_bus; SysBusDevice *s; @@ -446,11 +446,11 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX); - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, - &pci_bus3, &pbm_irqs); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA, + &pci_busB, &pbm_irqs); pci_vga_init(pci_bus); - /* XXX Should be pci_bus3 */ + /* XXX Should be pci_busA */ ebus = pci_create_simple(pci_bus, -1, "ebus"); isa_bus = pci_ebus_init(ebus, pbm_irqs); From b2f9005a2bb1d8da04dfa9183ee1e00f8f219bd4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 5/6] apb: fix endianness for APB and PCI config accesses Signed-off-by: Mark Cave-Ayland --- hw/pci-host/apb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index c2a3af35b5..d893f8d2ba 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -559,7 +559,7 @@ static uint64_t apb_config_readl (void *opaque, static const MemoryRegionOps apb_config_ops = { .read = apb_config_readl, .write = apb_config_writel, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, }; static void apb_pci_config_write(void *opaque, hwaddr addr, @@ -568,7 +568,6 @@ static void apb_pci_config_write(void *opaque, hwaddr addr, APBState *s = opaque; PCIHostState *phb = PCI_HOST_BRIDGE(s); - val = qemu_bswap_len(val, size); APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val); pci_data_write(phb->bus, addr, val, size); } @@ -581,7 +580,6 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr, PCIHostState *phb = PCI_HOST_BRIDGE(s); ret = pci_data_read(phb->bus, addr, size); - ret = qemu_bswap_len(ret, size); APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret); return ret; } @@ -743,7 +741,7 @@ static void pci_pbm_reset(DeviceState *d) static const MemoryRegionOps pci_config_ops = { .read = apb_pci_config_read, .write = apb_pci_config_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int pci_pbm_init_device(SysBusDevice *dev) From e5fd1eb05ec918e9877640d85ec45680cf106632 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 4 Sep 2017 18:41:01 +0100 Subject: [PATCH 6/6] apb: add busA qdev property to PBM PCI bridge As future sun4u PCI topologies place the ebus containing the in-built devices behind a PCI bridge, add a busA property to the PBM PCI bridge that is then used to allow IO accesses by default. This allows early fw_cfg/NVRAM/serial access to occur even before OpenBIOS has had a chance to configure the PCI bridges. Signed-off-by: Mark Cave-Ayland --- hw/pci-host/apb.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index d893f8d2ba..b709456b97 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -155,6 +155,18 @@ typedef struct APBState { unsigned int nr_resets; } APBState; +#define TYPE_PBM_PCI_BRIDGE "pbm-bridge" +#define PBM_PCI_BRIDGE(obj) \ + OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) + +typedef struct PBMPCIBridge { + /*< private >*/ + PCIBridge parent_obj; + + /* Is this busA with in-built devices (ebus)? */ + bool busA; +} PBMPCIBridge; + static inline void pbm_set_request(APBState *s, unsigned int irq_num) { APB_DPRINTF("%s: request irq %d\n", __func__, irq_num); @@ -632,8 +644,6 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level) static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) { - pci_bridge_initfn(dev, TYPE_PCI_BUS); - /* * command register: * According to PCI bridge spec, after reset @@ -643,11 +653,23 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) * the reset value should be zero unless the boot pin is tied high * (which is true) and thus it should be PCI_COMMAND_MEMORY. */ - pci_set_word(dev->config + PCI_COMMAND, - PCI_COMMAND_MEMORY); + uint16_t cmd = PCI_COMMAND_MEMORY; + PBMPCIBridge *br = PBM_PCI_BRIDGE(dev); + + pci_bridge_initfn(dev, TYPE_PCI_BUS); + + /* If initialising busA, ensure that we allow IO transactions so that + we get the early serial console until OpenBIOS configures the bridge */ + if (br->busA) { + cmd |= PCI_COMMAND_IO; + } + + pci_set_word(dev->config + PCI_COMMAND, cmd); pci_set_word(dev->config + PCI_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); + + pci_bridge_update_mappings(PCI_BRIDGE(br)); } PCIBus *pci_apb_init(hwaddr special_base, @@ -701,16 +723,17 @@ PCIBus *pci_apb_init(hwaddr special_base, /* APB secondary busses */ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, - "pbm-bridge"); + TYPE_PBM_PCI_BRIDGE); br = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(br, "pciB", pci_apb_map_irq); qdev_init_nofail(&pci_dev->qdev); *busB = pci_bridge_get_sec_bus(br); pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, - "pbm-bridge"); + TYPE_PBM_PCI_BRIDGE); br = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(br, "pciA", pci_apb_map_irq); + qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); qdev_init_nofail(&pci_dev->qdev); *busA = pci_bridge_get_sec_bus(br); @@ -832,6 +855,11 @@ static const TypeInfo pbm_host_info = { .class_init = pbm_host_class_init, }; +static Property pbm_pci_properties[] = { + DEFINE_PROP_BOOL("busA", PBMPCIBridge, busA, false), + DEFINE_PROP_END_OF_LIST(), +}; + static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -847,12 +875,14 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_bridge_reset; dc->vmsd = &vmstate_pci_device; + dc->props = pbm_pci_properties; } static const TypeInfo pbm_pci_bridge_info = { - .name = "pbm-bridge", + .name = TYPE_PBM_PCI_BRIDGE, .parent = TYPE_PCI_BRIDGE, .class_init = pbm_pci_bridge_class_init, + .instance_size = sizeof(PBMPCIBridge), }; static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data)