This switches the sun4u model to being much closer to a real Ultra 5.
Since the existing code previously bypassed the PCI bridge interrupt
swizzling, reorganise the interrupt mapping functions so that
pci_pbm_map_irq() is used by the PCI bridges and pci_apb_map_irq() is
used by the PCI host bridge.
As part of this change we also combine the "onboard" NIC and the ebus into
a single multi-function device as done on a real Ultra 5.
Finally we mark the physically unavailable slots (plus slot 0 in busA) as
reserved to ensure that users can't plug devices into non-existent slots
which will break interrupt routing.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
hw/pci-host/apb.c | 35 +++++++++++++++++++++++++++--------
hw/sparc64/sun4u.c | 25 ++++++++++++++++++++-----
2 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index f9badad..5000432 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -601,16 +601,35 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
/* The APB host has an IRQ line for each IRQ line of each slot. */
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
{
- return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
+ /* Return the irq as swizzled by the PBM */
+ return irq_num;
}
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
{
+ PBMPCIBridge *br = PBM_PCI_BRIDGE(pci_bridge_get_device(
+ PCI_BUS(qdev_get_parent_bus(DEVICE(pci_dev)))));
+
int bus_offset;
- if (pci_dev->devfn & 1)
- bus_offset = 16;
- else
- bus_offset = 0;
+ if (br->busA) {
+ bus_offset = 0x0;
+
+ /* The on-board devices have fixed (legacy) OBIO intnos */
+ switch (PCI_SLOT(pci_dev->devfn)) {
+ case 1:
+ /* Onboard NIC */
+ return 0x21;
+ case 3:
+ /* Onboard IDE */
+ return 0x20;
+
+ default:
+ /* Normal intno, fall through */
+ break;
+ }
+ } else {
+ bus_offset = 0x10;
+ }
return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
}
@@ -692,7 +711,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
d = APB_DEVICE(dev);
phb = PCI_HOST_BRIDGE(dev);
phb->bus = pci_register_bus(DEVICE(phb), "pci",
- pci_apb_set_irq, pci_pbm_map_irq, d,
+ pci_apb_set_irq, pci_apb_map_irq, d,
&d->pci_mmio,
get_system_io(),
0, 32, TYPE_PCI_BUS);
@@ -726,14 +745,14 @@ PCIBus *pci_apb_init(hwaddr special_base,
pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
TYPE_PBM_PCI_BRIDGE);
br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "pciB", pci_apb_map_irq);
+ pci_bridge_map_irq(br, "pciB", pci_pbm_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,
TYPE_PBM_PCI_BRIDGE);
br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "pciA", pci_apb_map_irq);
+ pci_bridge_map_irq(br, "pciA", pci_pbm_map_irq);
qdev_prop_set_bit(DEVICE(pci_dev), "busA", true);
qdev_init_nofail(&pci_dev->qdev);
*busA = pci_bridge_get_sec_bus(br);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 3bb3bf2..b8b96be 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -27,6 +27,7 @@
#include "cpu.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
#include "hw/pci-host/apb.h"
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
@@ -42,6 +43,7 @@
#include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h"
#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "hw/loader.h"
#include "elf.h"
#include "qemu/cutils.h"
@@ -448,10 +450,17 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
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_busA,
&pci_busB, &pbm_irqs);
- pci_vga_init(pci_bus);
- /* XXX Should be pci_busA */
- ebus = pci_create_simple(pci_bus, -1, "ebus");
+ /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is
+ reserved (leaving no slots free after on-board devices) leaving slots
+ 0-3 are free on busB 4*/
+ pci_bus->slot_reserved_mask = 0xfffffffc;
+ pci_busA->slot_reserved_mask = 0xfffffff1;
+ pci_busB->slot_reserved_mask = 0xfffffff0;
+
+ ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, "ebus");
+ qdev_init_nofail(DEVICE(ebus));
+
isa_bus = pci_ebus_init(ebus, pbm_irqs);
i = 0;
@@ -464,14 +473,20 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
- pci_dev = pci_create(pci_bus, -1, "ne2k_pci");
+ pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA");
+
+ pci_dev = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 1), true,
+ "ne2k_pci");
dev = &pci_dev->qdev;
qdev_set_nic_properties(dev, &nd_table[0]);
qdev_init_nofail(dev);
ide_drive_get(hd, ARRAY_SIZE(hd));
- pci_cmd646_ide_init(pci_bus, hd, 1);
+ pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide");
+ qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1);
+ qdev_init_nofail(&pci_dev->qdev);
+ pci_ide_create_devs(pci_dev, hd);
isa_create_simple(isa_bus, "i8042");
--
1.7.10.4
On Tue, Jul 11, 2017 at 11:53 PM, Mark Cave-Ayland
<mark.cave-ayland@ilande.co.uk> wrote:
> This switches the sun4u model to being much closer to a real Ultra 5.
>
> Since the existing code previously bypassed the PCI bridge interrupt
> swizzling, reorganise the interrupt mapping functions so that
> pci_pbm_map_irq() is used by the PCI bridges and pci_apb_map_irq() is
> used by the PCI host bridge.
>
> As part of this change we also combine the "onboard" NIC and the ebus into
> a single multi-function device as done on a real Ultra 5.
While they are combined on a real Ultra 5, it has a different NIC.
Are the guest OSes smart enough to use NE2000 as an onboard device?
> Finally we mark the physically unavailable slots (plus slot 0 in busA) as
> reserved to ensure that users can't plug devices into non-existent slots
> which will break interrupt routing.
>
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
> hw/pci-host/apb.c | 35 +++++++++++++++++++++++++++--------
> hw/sparc64/sun4u.c | 25 ++++++++++++++++++++-----
> 2 files changed, 47 insertions(+), 13 deletions(-)
>
> diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
> index f9badad..5000432 100644
> --- a/hw/pci-host/apb.c
> +++ b/hw/pci-host/apb.c
> @@ -601,16 +601,35 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
> /* The APB host has an IRQ line for each IRQ line of each slot. */
> static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
> {
> - return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
> + /* Return the irq as swizzled by the PBM */
> + return irq_num;
> }
>
> static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
> {
> + PBMPCIBridge *br = PBM_PCI_BRIDGE(pci_bridge_get_device(
> + PCI_BUS(qdev_get_parent_bus(DEVICE(pci_dev)))));
> +
> int bus_offset;
> - if (pci_dev->devfn & 1)
> - bus_offset = 16;
> - else
> - bus_offset = 0;
> + if (br->busA) {
> + bus_offset = 0x0;
> +
> + /* The on-board devices have fixed (legacy) OBIO intnos */
> + switch (PCI_SLOT(pci_dev->devfn)) {
> + case 1:
> + /* Onboard NIC */
> + return 0x21;
> + case 3:
> + /* Onboard IDE */
> + return 0x20;
> +
> + default:
> + /* Normal intno, fall through */
> + break;
> + }
> + } else {
> + bus_offset = 0x10;
> + }
> return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
> }
>
> @@ -692,7 +711,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
> d = APB_DEVICE(dev);
> phb = PCI_HOST_BRIDGE(dev);
> phb->bus = pci_register_bus(DEVICE(phb), "pci",
> - pci_apb_set_irq, pci_pbm_map_irq, d,
> + pci_apb_set_irq, pci_apb_map_irq, d,
> &d->pci_mmio,
> get_system_io(),
> 0, 32, TYPE_PCI_BUS);
> @@ -726,14 +745,14 @@ PCIBus *pci_apb_init(hwaddr special_base,
> pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
> TYPE_PBM_PCI_BRIDGE);
> br = PCI_BRIDGE(pci_dev);
> - pci_bridge_map_irq(br, "pciB", pci_apb_map_irq);
> + pci_bridge_map_irq(br, "pciB", pci_pbm_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,
> TYPE_PBM_PCI_BRIDGE);
> br = PCI_BRIDGE(pci_dev);
> - pci_bridge_map_irq(br, "pciA", pci_apb_map_irq);
> + pci_bridge_map_irq(br, "pciA", pci_pbm_map_irq);
> qdev_prop_set_bit(DEVICE(pci_dev), "busA", true);
> qdev_init_nofail(&pci_dev->qdev);
> *busA = pci_bridge_get_sec_bus(br);
> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
> index 3bb3bf2..b8b96be 100644
> --- a/hw/sparc64/sun4u.c
> +++ b/hw/sparc64/sun4u.c
> @@ -27,6 +27,7 @@
> #include "cpu.h"
> #include "hw/hw.h"
> #include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> #include "hw/pci-host/apb.h"
> #include "hw/i386/pc.h"
> #include "hw/char/serial.h"
> @@ -42,6 +43,7 @@
> #include "hw/nvram/fw_cfg.h"
> #include "hw/sysbus.h"
> #include "hw/ide.h"
> +#include "hw/ide/pci.h"
> #include "hw/loader.h"
> #include "elf.h"
> #include "qemu/cutils.h"
> @@ -448,10 +450,17 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
> 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_busA,
> &pci_busB, &pbm_irqs);
> - pci_vga_init(pci_bus);
>
> - /* XXX Should be pci_busA */
> - ebus = pci_create_simple(pci_bus, -1, "ebus");
> + /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is
> + reserved (leaving no slots free after on-board devices) leaving slots
> + 0-3 are free on busB 4*/
> + pci_bus->slot_reserved_mask = 0xfffffffc;
> + pci_busA->slot_reserved_mask = 0xfffffff1;
> + pci_busB->slot_reserved_mask = 0xfffffff0;
> +
> + ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, "ebus");
> + qdev_init_nofail(DEVICE(ebus));
> +
> isa_bus = pci_ebus_init(ebus, pbm_irqs);
>
> i = 0;
> @@ -464,14 +473,20 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
> serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
> parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
>
> - pci_dev = pci_create(pci_bus, -1, "ne2k_pci");
> + pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA");
> +
> + pci_dev = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 1), true,
> + "ne2k_pci");
> dev = &pci_dev->qdev;
> qdev_set_nic_properties(dev, &nd_table[0]);
> qdev_init_nofail(dev);
>
> ide_drive_get(hd, ARRAY_SIZE(hd));
>
> - pci_cmd646_ide_init(pci_bus, hd, 1);
> + pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide");
> + qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1);
> + qdev_init_nofail(&pci_dev->qdev);
> + pci_ide_create_devs(pci_dev, hd);
>
> isa_create_simple(isa_bus, "i8042");
>
> --
> 1.7.10.4
>
--
Regards,
Artyom Tarasenko
SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu
On 12/07/17 10:59, Artyom Tarasenko wrote:
> On Tue, Jul 11, 2017 at 11:53 PM, Mark Cave-Ayland
> <mark.cave-ayland@ilande.co.uk> wrote:
>> This switches the sun4u model to being much closer to a real Ultra 5.
>>
>> Since the existing code previously bypassed the PCI bridge interrupt
>> swizzling, reorganise the interrupt mapping functions so that
>> pci_pbm_map_irq() is used by the PCI bridges and pci_apb_map_irq() is
>> used by the PCI host bridge.
>>
>> As part of this change we also combine the "onboard" NIC and the ebus into
>> a single multi-function device as done on a real Ultra 5.
>
> While they are combined on a real Ultra 5, it has a different NIC.
> Are the guest OSes smart enough to use NE2000 as an onboard device?
Yes, since the ne2000 is the default NIC unless you explicitly change it
on the command line - in which case I think it's fairly safe to assume
that you know what you're doing ;)
At some point I'll come up with a proper hme device as not all OSs
enable the ne2000 driver by default by SPARC, which should get
networking going for pretty much all SPARC64 OSs.
>> Finally we mark the physically unavailable slots (plus slot 0 in busA) as
>> reserved to ensure that users can't plug devices into non-existent slots
>> which will break interrupt routing.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>> hw/pci-host/apb.c | 35 +++++++++++++++++++++++++++--------
>> hw/sparc64/sun4u.c | 25 ++++++++++++++++++++-----
>> 2 files changed, 47 insertions(+), 13 deletions(-)
>>
>> diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
>> index f9badad..5000432 100644
>> --- a/hw/pci-host/apb.c
>> +++ b/hw/pci-host/apb.c
>> @@ -601,16 +601,35 @@ static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
>> /* The APB host has an IRQ line for each IRQ line of each slot. */
>> static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
>> {
>> - return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
>> + /* Return the irq as swizzled by the PBM */
>> + return irq_num;
>> }
>>
>> static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
>> {
>> + PBMPCIBridge *br = PBM_PCI_BRIDGE(pci_bridge_get_device(
>> + PCI_BUS(qdev_get_parent_bus(DEVICE(pci_dev)))));
>> +
>> int bus_offset;
>> - if (pci_dev->devfn & 1)
>> - bus_offset = 16;
>> - else
>> - bus_offset = 0;
>> + if (br->busA) {
>> + bus_offset = 0x0;
>> +
>> + /* The on-board devices have fixed (legacy) OBIO intnos */
>> + switch (PCI_SLOT(pci_dev->devfn)) {
>> + case 1:
>> + /* Onboard NIC */
>> + return 0x21;
>> + case 3:
>> + /* Onboard IDE */
>> + return 0x20;
>> +
>> + default:
>> + /* Normal intno, fall through */
>> + break;
>> + }
>> + } else {
>> + bus_offset = 0x10;
>> + }
>> return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
>> }
>>
>> @@ -692,7 +711,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
>> d = APB_DEVICE(dev);
>> phb = PCI_HOST_BRIDGE(dev);
>> phb->bus = pci_register_bus(DEVICE(phb), "pci",
>> - pci_apb_set_irq, pci_pbm_map_irq, d,
>> + pci_apb_set_irq, pci_apb_map_irq, d,
>> &d->pci_mmio,
>> get_system_io(),
>> 0, 32, TYPE_PCI_BUS);
>> @@ -726,14 +745,14 @@ PCIBus *pci_apb_init(hwaddr special_base,
>> pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
>> TYPE_PBM_PCI_BRIDGE);
>> br = PCI_BRIDGE(pci_dev);
>> - pci_bridge_map_irq(br, "pciB", pci_apb_map_irq);
>> + pci_bridge_map_irq(br, "pciB", pci_pbm_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,
>> TYPE_PBM_PCI_BRIDGE);
>> br = PCI_BRIDGE(pci_dev);
>> - pci_bridge_map_irq(br, "pciA", pci_apb_map_irq);
>> + pci_bridge_map_irq(br, "pciA", pci_pbm_map_irq);
>> qdev_prop_set_bit(DEVICE(pci_dev), "busA", true);
>> qdev_init_nofail(&pci_dev->qdev);
>> *busA = pci_bridge_get_sec_bus(br);
>> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
>> index 3bb3bf2..b8b96be 100644
>> --- a/hw/sparc64/sun4u.c
>> +++ b/hw/sparc64/sun4u.c
>> @@ -27,6 +27,7 @@
>> #include "cpu.h"
>> #include "hw/hw.h"
>> #include "hw/pci/pci.h"
>> +#include "hw/pci/pci_bus.h"
>> #include "hw/pci-host/apb.h"
>> #include "hw/i386/pc.h"
>> #include "hw/char/serial.h"
>> @@ -42,6 +43,7 @@
>> #include "hw/nvram/fw_cfg.h"
>> #include "hw/sysbus.h"
>> #include "hw/ide.h"
>> +#include "hw/ide/pci.h"
>> #include "hw/loader.h"
>> #include "elf.h"
>> #include "qemu/cutils.h"
>> @@ -448,10 +450,17 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
>> 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_busA,
>> &pci_busB, &pbm_irqs);
>> - pci_vga_init(pci_bus);
>>
>> - /* XXX Should be pci_busA */
>> - ebus = pci_create_simple(pci_bus, -1, "ebus");
>> + /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is
>> + reserved (leaving no slots free after on-board devices) leaving slots
>> + 0-3 are free on busB 4*/
>> + pci_bus->slot_reserved_mask = 0xfffffffc;
>> + pci_busA->slot_reserved_mask = 0xfffffff1;
>> + pci_busB->slot_reserved_mask = 0xfffffff0;
>> +
>> + ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, "ebus");
>> + qdev_init_nofail(DEVICE(ebus));
>> +
>> isa_bus = pci_ebus_init(ebus, pbm_irqs);
>>
>> i = 0;
>> @@ -464,14 +473,20 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
>> serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
>> parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
>>
>> - pci_dev = pci_create(pci_bus, -1, "ne2k_pci");
>> + pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA");
>> +
>> + pci_dev = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 1), true,
>> + "ne2k_pci");
>> dev = &pci_dev->qdev;
>> qdev_set_nic_properties(dev, &nd_table[0]);
>> qdev_init_nofail(dev);
>>
>> ide_drive_get(hd, ARRAY_SIZE(hd));
>>
>> - pci_cmd646_ide_init(pci_bus, hd, 1);
>> + pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide");
>> + qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1);
>> + qdev_init_nofail(&pci_dev->qdev);
>> + pci_ide_create_devs(pci_dev, hd);
>>
>> isa_create_simple(isa_bus, "i8042");
>>
>> --
>> 1.7.10.4
ATB,
Mark.
© 2016 - 2026 Red Hat, Inc.