diff mbox series

sun4u: implement power device

Message ID 20180115205848.26027-1-mark.cave-ayland@ilande.co.uk
State New
Headers show
Series sun4u: implement power device | expand

Commit Message

Mark Cave-Ayland Jan. 15, 2018, 8:58 p.m. UTC
This inbuilt device contains a single 4-byte register, of which bit 24 is used
to power down the machine on a real Ultra 5.

The power device exists at offset 0x724000 on a real machine, but due to the
current configuration of the BARs in QEMU it must be located lower in PCI IO
space.

For the moment we place the power device at offset 0x7240 as a reminder of its
original location and raise the base PCI IO address from 0x4000 to 0x8000.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/sparc64/sun4u.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

Comments

Philippe Mathieu-Daudé Jan. 16, 2018, 12:54 a.m. UTC | #1
CC'ing PCI maintainers.

Hi Mark,

On 01/15/2018 05:58 PM, Mark Cave-Ayland wrote:
> This inbuilt device contains a single 4-byte register, of which bit 24 is used
> to power down the machine on a real Ultra 5.
> 
> The power device exists at offset 0x724000 on a real machine, but due to the
> current configuration of the BARs in QEMU it must be located lower in PCI IO
> space.
Is is some issue in pci_bar_address()?

> 
> For the moment we place the power device at offset 0x7240 as a reminder of its
> original location and raise the base PCI IO address from 0x4000 to 0x8000.

If we can't fix it, I rather prefer a #define with a comment in the
code, IMHO this is safer and easier to remember than looking in git history.

> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/sparc64/sun4u.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 63 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
> index ec45ec2801..26ab6e9a9c 100644
> --- a/hw/sparc64/sun4u.c
> +++ b/hw/sparc64/sun4u.c
> @@ -205,6 +205,59 @@ typedef struct ResetData {
>      uint64_t prom_addr;
>  } ResetData;
>  
> +#define TYPE_SUN4U_POWER "power"
> +#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
> +
> +typedef struct PowerDevice {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion power_mmio;
> +} PowerDevice;
> +
> +/* Power */
> +static void power_mem_write(void *opaque, hwaddr addr,
> +                            uint64_t val, unsigned size)
> +{
> +    /* According to a real Ultra 5, bit 24 controls the power */
> +    if (val & 0x1000000) {
> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +    }
> +}
> +
> +static const MemoryRegionOps power_mem_ops = {
> +    .write = power_mem_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void power_realize(DeviceState *dev, Error **errp)
> +{
> +    PowerDevice *d = SUN4U_POWER(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
> +                          "power", sizeof(uint32_t));
> +
> +    sysbus_init_mmio(sbd, &d->power_mmio);
> +}
> +
> +static void power_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = power_realize;
> +}
> +
> +static const TypeInfo power_info = {
> +    .name          = TYPE_SUN4U_POWER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PowerDevice),
> +    .class_init    = power_class_init,
> +};
> +
>  static void ebus_isa_irq_handler(void *opaque, int n, int level)
>  {
>      EbusState *s = EBUS(opaque);
> @@ -221,6 +274,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level)
>  static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>  {
>      EbusState *s = EBUS(pci_dev);
> +    SysBusDevice *sbd;
>      DeviceState *dev;
>      qemu_irq *isa_irq;
>      DriveInfo *fd[MAX_FD];
> @@ -270,6 +324,13 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>      qdev_prop_set_uint32(dev, "dma", -1);
>      qdev_init_nofail(dev);
>  
> +    /* Power */
> +    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
> +    qdev_init_nofail(dev);
> +    sbd = SYS_BUS_DEVICE(dev);
> +    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
> +                                sysbus_mmio_get_region(sbd, 0));
> +
>      /* PCI */
>      pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
>      pci_dev->config[0x05] = 0x00;
> @@ -282,7 +343,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>                               0, 0x1000000);
>      pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
>      memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
> -                             0, 0x4000);
> +                             0, 0x8000);

What about using 2 MR, bar1_lo/bar1_hi, registering bar1_lo at offset @0
and bar1_hi at @0x724000?

>      pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
>  }
>  
> @@ -693,6 +754,7 @@ static const TypeInfo sun4v_type = {
>  
>  static void sun4u_register_types(void)
>  {
> +    type_register_static(&power_info);
>      type_register_static(&ebus_info);
>      type_register_static(&prom_info);
>      type_register_static(&ram_info);
>
Marcel Apfelbaum Jan. 16, 2018, 2:23 p.m. UTC | #2
Hi Philippe,

On 16/01/2018 2:54, Philippe Mathieu-Daudé wrote:
> CC'ing PCI maintainers.
> 
> Hi Mark,
> 
> On 01/15/2018 05:58 PM, Mark Cave-Ayland wrote:
>> This inbuilt device contains a single 4-byte register, of which bit 24 is used
>> to power down the machine on a real Ultra 5.
>>
>> The power device exists at offset 0x724000 on a real machine, but due to the
>> current configuration of the BARs in QEMU it must be located lower in PCI IO
>> space.
> Is is some issue in pci_bar_address()?
> 

The QEMU IO layout:

     /*
      * QEMU I/O address space usage:
      *   0000 - 0fff    legacy isa, pci config, pci root bus, ...
      *   1000 - 9fff    free
      *   a000 - afff    hotplug (cpu, pci via acpi, i440fx/piix only)
      *   b000 - bfff    power management (PORT_ACPI_PM_BASE)
      *                  [ qemu 1.4+ implements pci config registers
      *                    properly so guests can place the registers
      *                    where they want, on older versions its fixed ]
      *   c000 - ffff    free, traditionally used for pci io
      */

As you can see we don't have IO address space over ffff.

Thanks,
Marcel

>>
>> For the moment we place the power device at offset 0x7240 as a reminder of its
>> original location and raise the base PCI IO address from 0x4000 to 0x8000.
> 
> If we can't fix it, I rather prefer a #define with a comment in the
> code, IMHO this is safer and easier to remember than looking in git history.
> 
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/sparc64/sun4u.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 63 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
>> index ec45ec2801..26ab6e9a9c 100644
>> --- a/hw/sparc64/sun4u.c
>> +++ b/hw/sparc64/sun4u.c
>> @@ -205,6 +205,59 @@ typedef struct ResetData {
>>       uint64_t prom_addr;
>>   } ResetData;
>>   
>> +#define TYPE_SUN4U_POWER "power"
>> +#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
>> +
>> +typedef struct PowerDevice {
>> +    SysBusDevice parent_obj;
>> +
>> +    MemoryRegion power_mmio;
>> +} PowerDevice;
>> +
>> +/* Power */
>> +static void power_mem_write(void *opaque, hwaddr addr,
>> +                            uint64_t val, unsigned size)
>> +{
>> +    /* According to a real Ultra 5, bit 24 controls the power */
>> +    if (val & 0x1000000) {
>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps power_mem_ops = {
>> +    .write = power_mem_write,
>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 4,
>> +    },
>> +};
>> +
>> +static void power_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PowerDevice *d = SUN4U_POWER(dev);
>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> +
>> +    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
>> +                          "power", sizeof(uint32_t));
>> +
>> +    sysbus_init_mmio(sbd, &d->power_mmio);
>> +}
>> +
>> +static void power_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = power_realize;
>> +}
>> +
>> +static const TypeInfo power_info = {
>> +    .name          = TYPE_SUN4U_POWER,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(PowerDevice),
>> +    .class_init    = power_class_init,
>> +};
>> +
>>   static void ebus_isa_irq_handler(void *opaque, int n, int level)
>>   {
>>       EbusState *s = EBUS(opaque);
>> @@ -221,6 +274,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level)
>>   static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>   {
>>       EbusState *s = EBUS(pci_dev);
>> +    SysBusDevice *sbd;
>>       DeviceState *dev;
>>       qemu_irq *isa_irq;
>>       DriveInfo *fd[MAX_FD];
>> @@ -270,6 +324,13 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>       qdev_prop_set_uint32(dev, "dma", -1);
>>       qdev_init_nofail(dev);
>>   
>> +    /* Power */
>> +    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
>> +    qdev_init_nofail(dev);
>> +    sbd = SYS_BUS_DEVICE(dev);
>> +    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
>> +                                sysbus_mmio_get_region(sbd, 0));
>> +
>>       /* PCI */
>>       pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
>>       pci_dev->config[0x05] = 0x00;
>> @@ -282,7 +343,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>                                0, 0x1000000);
>>       pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
>>       memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
>> -                             0, 0x4000);
>> +                             0, 0x8000);
> 
> What about using 2 MR, bar1_lo/bar1_hi, registering bar1_lo at offset @0
> and bar1_hi at @0x724000?
> 
>>       pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
>>   }
>>   
>> @@ -693,6 +754,7 @@ static const TypeInfo sun4v_type = {
>>   
>>   static void sun4u_register_types(void)
>>   {
>> +    type_register_static(&power_info);
>>       type_register_static(&ebus_info);
>>       type_register_static(&prom_info);
>>       type_register_static(&ram_info);
>>
>
Mark Cave-Ayland Jan. 16, 2018, 8:03 p.m. UTC | #3
On 16/01/18 00:54, Philippe Mathieu-Daudé wrote:

> CC'ing PCI maintainers.
> 
> Hi Mark,
> 
> On 01/15/2018 05:58 PM, Mark Cave-Ayland wrote:
>> This inbuilt device contains a single 4-byte register, of which bit 24 is used
>> to power down the machine on a real Ultra 5.
>>
>> The power device exists at offset 0x724000 on a real machine, but due to the
>> current configuration of the BARs in QEMU it must be located lower in PCI IO
>> space.
> Is is some issue in pci_bar_address()?

Hi Philippe,

It's not an issue with QEMU at all, more the way in which the on-board 
devices are mapped. From memory there are 3 different issues with the 
current setup:

- OpenBIOS uses PCI IO space accesses for all its drivers

In a real Ultra 5 the on-board devices are behind a memory BAR but 
everything in OpenBIOS is hard-coded to use IO accesses. Changing that 
will be fairly hard.

- Some OSs use the ebus BAR to access the onboard devices, others use 
the direct physical accesses

This means that the ebus BAR has to be located at address zero (even 
though its in slot 1) for both accesses to work. The first part of PCI 
IO space containing the ebus is then aliased back onto its physical 
address to make everything consistent.

- Linux sabre fix-up bug

Potentially this could be fixed by increasing the base physical address 
of the simba IO space, however Linux has a fixup routine for this 
particular PCI host bridge and this has a bug which means that it 
presumes the lower word of the address is 0 (like a real Ultra 5) rather 
than reading it from the DT.

Therefore whilst moving the base of PCI IO space within the physical 
address space should work, due to this bug the PCI addresses are 
converted incorrectly from physical addresses causing a panic.

>> For the moment we place the power device at offset 0x7240 as a reminder of its
>> original location and raise the base PCI IO address from 0x4000 to 0x8000.
> 
> If we can't fix it, I rather prefer a #define with a comment in the
> code, IMHO this is safer and easier to remember than looking in git history.

Well TBH just about all of the current devices for sun4u are either 
incorrect or located at the wrong address, and could possibly change 
later if required for Solaris compatibility. So while things are still 
quite fluid, I'm more inclined to leave them as hard-coded offsets 
(similarly in OpenBIOS) until things become more clear.


ATB,

Mark.
Mark Cave-Ayland Jan. 16, 2018, 8:05 p.m. UTC | #4
On 16/01/18 14:23, Marcel Apfelbaum wrote:

> Hi Philippe,
> 
> On 16/01/2018 2:54, Philippe Mathieu-Daudé wrote:
>> CC'ing PCI maintainers.
>>
>> Hi Mark,
>>
>> On 01/15/2018 05:58 PM, Mark Cave-Ayland wrote:
>>> This inbuilt device contains a single 4-byte register, of which bit 
>>> 24 is used
>>> to power down the machine on a real Ultra 5.
>>>
>>> The power device exists at offset 0x724000 on a real machine, but due 
>>> to the
>>> current configuration of the BARs in QEMU it must be located lower in 
>>> PCI IO
>>> space.
>> Is is some issue in pci_bar_address()?
>>
> 
> The QEMU IO layout:
> 
>      /*
>       * QEMU I/O address space usage:
>       *   0000 - 0fff    legacy isa, pci config, pci root bus, ...
>       *   1000 - 9fff    free
>       *   a000 - afff    hotplug (cpu, pci via acpi, i440fx/piix only)
>       *   b000 - bfff    power management (PORT_ACPI_PM_BASE)
>       *                  [ qemu 1.4+ implements pci config registers
>       *                    properly so guests can place the registers
>       *                    where they want, on older versions its fixed ]
>       *   c000 - ffff    free, traditionally used for pci io
>       */
> 
> As you can see we don't have IO address space over ffff.

Well that's not actually quite true - we use a separate ebus address 
space for the onboard devices (and that does have 32-bit PCI IO accesses 
enabled), but the issue here is one of the sun4u PCI host/onboard device 
configuration rather than anything to do with QEMU.


ATB,

Mark.
Marcel Apfelbaum Jan. 17, 2018, 2:25 p.m. UTC | #5
On 16/01/2018 22:05, Mark Cave-Ayland wrote:
> On 16/01/18 14:23, Marcel Apfelbaum wrote:
> 
>> Hi Philippe,
>>
>> On 16/01/2018 2:54, Philippe Mathieu-Daudé wrote:
>>> CC'ing PCI maintainers.
>>>
>>> Hi Mark,
>>>
>>> On 01/15/2018 05:58 PM, Mark Cave-Ayland wrote:
>>>> This inbuilt device contains a single 4-byte register, of which bit 24 is used
>>>> to power down the machine on a real Ultra 5.
>>>>
>>>> The power device exists at offset 0x724000 on a real machine, but due to the
>>>> current configuration of the BARs in QEMU it must be located lower in PCI IO
>>>> space.
>>> Is is some issue in pci_bar_address()?
>>>
>>
>> The QEMU IO layout:
>>
>>      /*
>>       * QEMU I/O address space usage:
>>       *   0000 - 0fff    legacy isa, pci config, pci root bus, ...
>>       *   1000 - 9fff    free
>>       *   a000 - afff    hotplug (cpu, pci via acpi, i440fx/piix only)
>>       *   b000 - bfff    power management (PORT_ACPI_PM_BASE)
>>       *                  [ qemu 1.4+ implements pci config registers
>>       *                    properly so guests can place the registers
>>       *                    where they want, on older versions its fixed ]
>>       *   c000 - ffff    free, traditionally used for pci io
>>       */
>>
>> As you can see we don't have IO address space over ffff.
> 
> Well that's not actually quite true - we use a separate ebus address space for the onboard devices (and that does have 
> 32-bit PCI IO accesses enabled), but the issue here is one of the sun4u PCI host/onboard device configuration rather 
> than anything to do with QEMU.
> 

Got it, thanks (the above is probably true only for x86 machines)
Marcel

> 
> ATB,
> 
> Mark.
Artyom Tarasenko Jan. 20, 2018, 8:10 p.m. UTC | #6
Hi Mark,


On Mon, Jan 15, 2018 at 9:58 PM, Mark Cave-Ayland
<mark.cave-ayland@ilande.co.uk> wrote:
> This inbuilt device contains a single 4-byte register, of which bit 24 is used
> to power down the machine on a real Ultra 5.
>
> The power device exists at offset 0x724000 on a real machine, but due to the
> current configuration of the BARs in QEMU it must be located lower in PCI IO
> space.
>
> For the moment we place the power device at offset 0x7240 as a reminder of its
> original location and raise the base PCI IO address from 0x4000 to 0x8000.

I think it's ok to have it there for now. The guests should get the
info from the device tree.

> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

Reviewed-by: Artyom Tarasenko <atar4qemu@gmail.com>

> ---
>  hw/sparc64/sun4u.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 63 insertions(+), 1 deletion(-)
>
> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
> index ec45ec2801..26ab6e9a9c 100644
> --- a/hw/sparc64/sun4u.c
> +++ b/hw/sparc64/sun4u.c
> @@ -205,6 +205,59 @@ typedef struct ResetData {
>      uint64_t prom_addr;
>  } ResetData;
>
> +#define TYPE_SUN4U_POWER "power"
> +#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
> +
> +typedef struct PowerDevice {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion power_mmio;
> +} PowerDevice;
> +
> +/* Power */
> +static void power_mem_write(void *opaque, hwaddr addr,
> +                            uint64_t val, unsigned size)
> +{
> +    /* According to a real Ultra 5, bit 24 controls the power */
> +    if (val & 0x1000000) {
> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +    }
> +}
> +
> +static const MemoryRegionOps power_mem_ops = {
> +    .write = power_mem_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void power_realize(DeviceState *dev, Error **errp)
> +{
> +    PowerDevice *d = SUN4U_POWER(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
> +                          "power", sizeof(uint32_t));
> +
> +    sysbus_init_mmio(sbd, &d->power_mmio);
> +}
> +
> +static void power_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = power_realize;
> +}
> +
> +static const TypeInfo power_info = {
> +    .name          = TYPE_SUN4U_POWER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PowerDevice),
> +    .class_init    = power_class_init,
> +};
> +
>  static void ebus_isa_irq_handler(void *opaque, int n, int level)
>  {
>      EbusState *s = EBUS(opaque);
> @@ -221,6 +274,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level)
>  static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>  {
>      EbusState *s = EBUS(pci_dev);
> +    SysBusDevice *sbd;
>      DeviceState *dev;
>      qemu_irq *isa_irq;
>      DriveInfo *fd[MAX_FD];
> @@ -270,6 +324,13 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>      qdev_prop_set_uint32(dev, "dma", -1);
>      qdev_init_nofail(dev);
>
> +    /* Power */
> +    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
> +    qdev_init_nofail(dev);
> +    sbd = SYS_BUS_DEVICE(dev);
> +    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
> +                                sysbus_mmio_get_region(sbd, 0));
> +
>      /* PCI */
>      pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
>      pci_dev->config[0x05] = 0x00;
> @@ -282,7 +343,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>                               0, 0x1000000);
>      pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
>      memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
> -                             0, 0x4000);
> +                             0, 0x8000);
>      pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
>  }
>
> @@ -693,6 +754,7 @@ static const TypeInfo sun4v_type = {
>
>  static void sun4u_register_types(void)
>  {
> +    type_register_static(&power_info);
>      type_register_static(&ebus_info);
>      type_register_static(&prom_info);
>      type_register_static(&ram_info);
> --
> 2.11.0
>
Mark Cave-Ayland Jan. 21, 2018, 9:14 a.m. UTC | #7
On 20/01/18 20:10, Artyom Tarasenko wrote:

> Hi Mark,
> 
> 
> On Mon, Jan 15, 2018 at 9:58 PM, Mark Cave-Ayland
> <mark.cave-ayland@ilande.co.uk> wrote:
>> This inbuilt device contains a single 4-byte register, of which bit 24 is used
>> to power down the machine on a real Ultra 5.
>>
>> The power device exists at offset 0x724000 on a real machine, but due to the
>> current configuration of the BARs in QEMU it must be located lower in PCI IO
>> space.
>>
>> For the moment we place the power device at offset 0x7240 as a reminder of its
>> original location and raise the base PCI IO address from 0x4000 to 0x8000.
> 
> I think it's ok to have it there for now. The guests should get the
> info from the device tree.

Yes indeed. For reference you can see the corresponding OpenBIOS 
patchset at 
https://mail.coreboot.org/pipermail/openbios/2018-January/010160.html.


ATB,

Mark.

>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> 
> Reviewed-by: Artyom Tarasenko <atar4qemu@gmail.com>
> 
>> ---
>>   hw/sparc64/sun4u.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 63 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
>> index ec45ec2801..26ab6e9a9c 100644
>> --- a/hw/sparc64/sun4u.c
>> +++ b/hw/sparc64/sun4u.c
>> @@ -205,6 +205,59 @@ typedef struct ResetData {
>>       uint64_t prom_addr;
>>   } ResetData;
>>
>> +#define TYPE_SUN4U_POWER "power"
>> +#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
>> +
>> +typedef struct PowerDevice {
>> +    SysBusDevice parent_obj;
>> +
>> +    MemoryRegion power_mmio;
>> +} PowerDevice;
>> +
>> +/* Power */
>> +static void power_mem_write(void *opaque, hwaddr addr,
>> +                            uint64_t val, unsigned size)
>> +{
>> +    /* According to a real Ultra 5, bit 24 controls the power */
>> +    if (val & 0x1000000) {
>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps power_mem_ops = {
>> +    .write = power_mem_write,
>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 4,
>> +    },
>> +};
>> +
>> +static void power_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PowerDevice *d = SUN4U_POWER(dev);
>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> +
>> +    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
>> +                          "power", sizeof(uint32_t));
>> +
>> +    sysbus_init_mmio(sbd, &d->power_mmio);
>> +}
>> +
>> +static void power_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = power_realize;
>> +}
>> +
>> +static const TypeInfo power_info = {
>> +    .name          = TYPE_SUN4U_POWER,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(PowerDevice),
>> +    .class_init    = power_class_init,
>> +};
>> +
>>   static void ebus_isa_irq_handler(void *opaque, int n, int level)
>>   {
>>       EbusState *s = EBUS(opaque);
>> @@ -221,6 +274,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level)
>>   static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>   {
>>       EbusState *s = EBUS(pci_dev);
>> +    SysBusDevice *sbd;
>>       DeviceState *dev;
>>       qemu_irq *isa_irq;
>>       DriveInfo *fd[MAX_FD];
>> @@ -270,6 +324,13 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>       qdev_prop_set_uint32(dev, "dma", -1);
>>       qdev_init_nofail(dev);
>>
>> +    /* Power */
>> +    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
>> +    qdev_init_nofail(dev);
>> +    sbd = SYS_BUS_DEVICE(dev);
>> +    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
>> +                                sysbus_mmio_get_region(sbd, 0));
>> +
>>       /* PCI */
>>       pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
>>       pci_dev->config[0x05] = 0x00;
>> @@ -282,7 +343,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
>>                                0, 0x1000000);
>>       pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
>>       memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
>> -                             0, 0x4000);
>> +                             0, 0x8000);
>>       pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
>>   }
>>
>> @@ -693,6 +754,7 @@ static const TypeInfo sun4v_type = {
>>
>>   static void sun4u_register_types(void)
>>   {
>> +    type_register_static(&power_info);
>>       type_register_static(&ebus_info);
>>       type_register_static(&prom_info);
>>       type_register_static(&ram_info);
>> --
>> 2.11.0
>>
> 
> 
>
diff mbox series

Patch

diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index ec45ec2801..26ab6e9a9c 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -205,6 +205,59 @@  typedef struct ResetData {
     uint64_t prom_addr;
 } ResetData;
 
+#define TYPE_SUN4U_POWER "power"
+#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
+
+typedef struct PowerDevice {
+    SysBusDevice parent_obj;
+
+    MemoryRegion power_mmio;
+} PowerDevice;
+
+/* Power */
+static void power_mem_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    /* According to a real Ultra 5, bit 24 controls the power */
+    if (val & 0x1000000) {
+        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+    }
+}
+
+static const MemoryRegionOps power_mem_ops = {
+    .write = power_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void power_realize(DeviceState *dev, Error **errp)
+{
+    PowerDevice *d = SUN4U_POWER(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
+                          "power", sizeof(uint32_t));
+
+    sysbus_init_mmio(sbd, &d->power_mmio);
+}
+
+static void power_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = power_realize;
+}
+
+static const TypeInfo power_info = {
+    .name          = TYPE_SUN4U_POWER,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PowerDevice),
+    .class_init    = power_class_init,
+};
+
 static void ebus_isa_irq_handler(void *opaque, int n, int level)
 {
     EbusState *s = EBUS(opaque);
@@ -221,6 +274,7 @@  static void ebus_isa_irq_handler(void *opaque, int n, int level)
 static void ebus_realize(PCIDevice *pci_dev, Error **errp)
 {
     EbusState *s = EBUS(pci_dev);
+    SysBusDevice *sbd;
     DeviceState *dev;
     qemu_irq *isa_irq;
     DriveInfo *fd[MAX_FD];
@@ -270,6 +324,13 @@  static void ebus_realize(PCIDevice *pci_dev, Error **errp)
     qdev_prop_set_uint32(dev, "dma", -1);
     qdev_init_nofail(dev);
 
+    /* Power */
+    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
+    qdev_init_nofail(dev);
+    sbd = SYS_BUS_DEVICE(dev);
+    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
+                                sysbus_mmio_get_region(sbd, 0));
+
     /* PCI */
     pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
     pci_dev->config[0x05] = 0x00;
@@ -282,7 +343,7 @@  static void ebus_realize(PCIDevice *pci_dev, Error **errp)
                              0, 0x1000000);
     pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
     memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
-                             0, 0x4000);
+                             0, 0x8000);
     pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
 }
 
@@ -693,6 +754,7 @@  static const TypeInfo sun4v_type = {
 
 static void sun4u_register_types(void)
 {
+    type_register_static(&power_info);
     type_register_static(&ebus_info);
     type_register_static(&prom_info);
     type_register_static(&ram_info);