diff mbox series

[v2,11/16] ppc/pnv: add pnv-phb-root-port device

Message ID 20220531214917.31668-12-danielhb413@gmail.com (mailing list archive)
State New, archived
Headers show
Series powernv: introduce pnv-phb base/proxy devices | expand

Commit Message

Daniel Henrique Barboza May 31, 2022, 9:49 p.m. UTC
We have two very similar root-port devices, pnv-phb3-root-port and
pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
that, until now, has no additional attributes.

The main difference between the PHB3 and PHB4 root ports is that
pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
other differences can be merged in a single device without too much
trouble.

This patch introduces the unified pnv-phb-root-port that, in time, will
be used as the default root port for the pnv-phb device.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
 hw/pci-host/pnv_phb.h |  17 +++++++
 2 files changed, 116 insertions(+), 8 deletions(-)

Comments

Cédric Le Goater June 1, 2022, 5:56 a.m. UTC | #1
On 5/31/22 23:49, Daniel Henrique Barboza wrote:
> We have two very similar root-port devices, pnv-phb3-root-port and
> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
> that, until now, has no additional attributes.
> 
> The main difference between the PHB3 and PHB4 root ports is that
> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
> other differences can be merged in a single device without too much
> trouble.
> 
> This patch introduces the unified pnv-phb-root-port that, in time, will
> be used as the default root port for the pnv-phb device.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>   hw/pci-host/pnv_phb.h |  17 +++++++
>   2 files changed, 116 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 321c4e768a..5047e90d3a 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>       dc->user_creatable = true;
>   }
>   
> -static void pnv_phb_register_type(void)
> +static void pnv_phb_root_port_reset(DeviceState *dev)
>   {
> -    static const TypeInfo pnv_phb_type_info = {
> -        .name          = TYPE_PNV_PHB,
> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
> -        .instance_size = sizeof(PnvPHB),
> -        .class_init    = pnv_phb_class_init,
> -    };
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
> +    PCIDevice *d = PCI_DEVICE(dev);
> +    uint8_t *conf = d->config;
>   
> +    rpc->parent_reset(dev);
> +
> +    if (rootport->version == 3) {
> +        return;
> +    }
> +
> +    /* PHB4 and later requires these extra reset steps */
> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
> +                               PCI_IO_RANGE_MASK & 0xff);
> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> +                                 PCI_IO_RANGE_MASK & 0xff);
> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
> +    pci_config_set_interrupt_pin(conf, 0);
> +}
> +
> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
> +{
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
> +    PCIDevice *pci = PCI_DEVICE(dev);
> +    PCIBus *bus = pci_get_bus(pci);
> +    PnvPHB *phb = NULL;
> +    Error *local_err = NULL;
> +
> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
> +                                          TYPE_PNV_PHB);
> +
> +    if (!phb) {
> +        error_setg(errp,
> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
> +        return;
> +    }
> +
> +    /* Set unique chassis/slot values for the root port */
> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
> +
> +    rpc->parent_realize(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    pci_config_set_interrupt_pin(pci->config, 0);
> +}
> +
> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
> +
> +    dc->desc     = "IBM PHB PCIE Root Port";
> +
> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
> +                                    &rpc->parent_realize);
> +
> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
> +                                  &rpc->parent_reset);
> +    dc->reset = &pnv_phb_root_port_reset;
> +
> +    dc->user_creatable = true;
> +
> +    k->vendor_id = PCI_VENDOR_ID_IBM;
> +    /* device_id represents the latest PHB root port version supported */
> +    k->device_id = PNV_PHB5_DEVICE_ID;

does that mean powernv8 machines will see phb devices as phb5 devices ?

C.

> +    k->revision  = 0;
> +
> +    rpc->exp_offset = 0x48;
> +    rpc->aer_offset = 0x100;
> +}
> +
> +static const TypeInfo pnv_phb_type_info = {
> +    .name          = TYPE_PNV_PHB,
> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
> +    .instance_size = sizeof(PnvPHB),
> +    .class_init    = pnv_phb_class_init,
> +};
> +
> +static const TypeInfo pnv_phb_root_port_info = {
> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
> +    .parent        = TYPE_PCIE_ROOT_PORT,
> +    .instance_size = sizeof(PnvPHBRootPort),
> +    .class_init    = pnv_phb_root_port_class_init,
> +};
> +
> +static void pnv_phb_register_types(void)
> +{
>       type_register_static(&pnv_phb_type_info);
> +    type_register_static(&pnv_phb_root_port_info);
>   }
> -type_init(pnv_phb_register_type)
> +
> +type_init(pnv_phb_register_types)
> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
> index a7cc8610e2..c8eab4b767 100644
> --- a/hw/pci-host/pnv_phb.h
> +++ b/hw/pci-host/pnv_phb.h
> @@ -36,4 +36,21 @@ struct PnvPHB {
>   #define TYPE_PNV_PHB "pnv-phb"
>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>   
> +/*
> + * PHB PCIe Root port
> + */
> +#define PNV_PHB3_DEVICE_ID         0x03dc
> +#define PNV_PHB4_DEVICE_ID         0x04c1
> +#define PNV_PHB5_DEVICE_ID         0x0652
> +
> +typedef struct PnvPHBRootPort {
> +    PCIESlot parent_obj;
> +
> +    uint32_t version;
> +} PnvPHBRootPort;
> +
> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
> +#define PNV_PHB_ROOT_PORT(obj) \
> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
> +
>   #endif /* PCI_HOST_PNV_PHB_H */
Daniel Henrique Barboza June 1, 2022, 8:04 a.m. UTC | #2
On 6/1/22 02:56, Cédric Le Goater wrote:
> On 5/31/22 23:49, Daniel Henrique Barboza wrote:
>> We have two very similar root-port devices, pnv-phb3-root-port and
>> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
>> that, until now, has no additional attributes.
>>
>> The main difference between the PHB3 and PHB4 root ports is that
>> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
>> other differences can be merged in a single device without too much
>> trouble.
>>
>> This patch introduces the unified pnv-phb-root-port that, in time, will
>> be used as the default root port for the pnv-phb device.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>>   hw/pci-host/pnv_phb.h |  17 +++++++
>>   2 files changed, 116 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>> index 321c4e768a..5047e90d3a 100644
>> --- a/hw/pci-host/pnv_phb.c
>> +++ b/hw/pci-host/pnv_phb.c
>> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>>       dc->user_creatable = true;
>>   }
>> -static void pnv_phb_register_type(void)
>> +static void pnv_phb_root_port_reset(DeviceState *dev)
>>   {
>> -    static const TypeInfo pnv_phb_type_info = {
>> -        .name          = TYPE_PNV_PHB,
>> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
>> -        .instance_size = sizeof(PnvPHB),
>> -        .class_init    = pnv_phb_class_init,
>> -    };
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
>> +    PCIDevice *d = PCI_DEVICE(dev);
>> +    uint8_t *conf = d->config;
>> +    rpc->parent_reset(dev);
>> +
>> +    if (rootport->version == 3) {
>> +        return;
>> +    }
>> +
>> +    /* PHB4 and later requires these extra reset steps */
>> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
>> +                               PCI_IO_RANGE_MASK & 0xff);
>> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
>> +                                 PCI_IO_RANGE_MASK & 0xff);
>> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
>> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
>> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
>> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
>> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
>> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
>> +    pci_config_set_interrupt_pin(conf, 0);
>> +}
>> +
>> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>> +    PCIDevice *pci = PCI_DEVICE(dev);
>> +    PCIBus *bus = pci_get_bus(pci);
>> +    PnvPHB *phb = NULL;
>> +    Error *local_err = NULL;
>> +
>> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>> +                                          TYPE_PNV_PHB);
>> +
>> +    if (!phb) {
>> +        error_setg(errp,
>> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
>> +        return;
>> +    }
>> +
>> +    /* Set unique chassis/slot values for the root port */
>> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
>> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
>> +
>> +    rpc->parent_realize(dev, &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    pci_config_set_interrupt_pin(pci->config, 0);
>> +}
>> +
>> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
>> +
>> +    dc->desc     = "IBM PHB PCIE Root Port";
>> +
>> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
>> +                                    &rpc->parent_realize);
>> +
>> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
>> +                                  &rpc->parent_reset);
>> +    dc->reset = &pnv_phb_root_port_reset;
>> +
>> +    dc->user_creatable = true;
>> +
>> +    k->vendor_id = PCI_VENDOR_ID_IBM;
>> +    /* device_id represents the latest PHB root port version supported */
>> +    k->device_id = PNV_PHB5_DEVICE_ID;
> 
> does that mean powernv8 machines will see phb devices as phb5 devices ?


I had something like this in this patch that would set device_id properly:


diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 5d66264a96..d468e8d44a 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -144,6 +144,22 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
      PCIBus *bus = pci_get_bus(pci);
      PnvPHB *phb = NULL;
      Error *local_err = NULL;
+    PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
+    PCIDeviceClass *k = PCI_DEVICE_GET_CLASS(pci);
+
+    switch (phb_rp->version) {
+    case 3:
+        k->device_id = PNV_PHB3_DEVICE_ID;
+        break;
+    case 4:
+        k->device_id = PNV_PHB4_DEVICE_ID;
+        break;
+    case 5:
+        k->device_id = PNV_PHB5_DEVICE_ID;
+        break;
+    default:
+        g_assert_not_reached();
+    }
  
      phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
                                            TYPE_PNV_PHB);
@@ -166,6 +182,11 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
      pci_config_set_interrupt_pin(pci->config, 0);
  }
  
+static Property pnv_phb_root_port_properties[] = {
+    DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
  static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
  {
      DeviceClass *dc = DEVICE_CLASS(klass);
@@ -181,6 +202,7 @@ static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
                                    &rpc->parent_reset);
      dc->reset = &pnv_phb_root_port_reset;
  
+    device_class_set_props(dc, pnv_phb_root_port_properties);
      dc->user_creatable = true;
  
      k->vendor_id = PCI_VENDOR_ID_IBM;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 4d2ea405db..13c8753eb2 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2148,6 +2148,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
  
      static GlobalProperty phb_compat[] = {
          { TYPE_PNV_PHB, "version", "3" },
+        { TYPE_PNV_PHB_ROOT_PORT, "version", "3" },
      };
  
      mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
@@ -2173,6 +2174,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
  
      static GlobalProperty phb_compat[] = {
          { TYPE_PNV_PHB, "version", "4" },
+        { TYPE_PNV_PHB_ROOT_PORT, "version", "4" },
      };
  
      mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
@@ -2199,6 +2201,7 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
  
      static GlobalProperty phb_compat[] = {
          { TYPE_PNV_PHB, "version", "5" },
+        { TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
      };
  
      mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";


The reason I didn't follow it through is because I wasn't sure if setting k->device_id
during realize() time was acceptable. Everyone else seems to set k->device_id during
class_init() or via an extra attribute 'device_id' that is written directly into
the PCI header.

If this is something that we can do then I'm fine with fixing this up in this patch.


Thanks,


Daniel

> 
> C.
> 
>> +    k->revision  = 0;
>> +
>> +    rpc->exp_offset = 0x48;
>> +    rpc->aer_offset = 0x100;
>> +}
>> +
>> +static const TypeInfo pnv_phb_type_info = {
>> +    .name          = TYPE_PNV_PHB,
>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>> +    .instance_size = sizeof(PnvPHB),
>> +    .class_init    = pnv_phb_class_init,
>> +};
>> +
>> +static const TypeInfo pnv_phb_root_port_info = {
>> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
>> +    .parent        = TYPE_PCIE_ROOT_PORT,
>> +    .instance_size = sizeof(PnvPHBRootPort),
>> +    .class_init    = pnv_phb_root_port_class_init,
>> +};
>> +
>> +static void pnv_phb_register_types(void)
>> +{
>>       type_register_static(&pnv_phb_type_info);
>> +    type_register_static(&pnv_phb_root_port_info);
>>   }
>> -type_init(pnv_phb_register_type)
>> +
>> +type_init(pnv_phb_register_types)
>> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
>> index a7cc8610e2..c8eab4b767 100644
>> --- a/hw/pci-host/pnv_phb.h
>> +++ b/hw/pci-host/pnv_phb.h
>> @@ -36,4 +36,21 @@ struct PnvPHB {
>>   #define TYPE_PNV_PHB "pnv-phb"
>>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>> +/*
>> + * PHB PCIe Root port
>> + */
>> +#define PNV_PHB3_DEVICE_ID         0x03dc
>> +#define PNV_PHB4_DEVICE_ID         0x04c1
>> +#define PNV_PHB5_DEVICE_ID         0x0652
>> +
>> +typedef struct PnvPHBRootPort {
>> +    PCIESlot parent_obj;
>> +
>> +    uint32_t version;
>> +} PnvPHBRootPort;
>> +
>> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
>> +#define PNV_PHB_ROOT_PORT(obj) \
>> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
>> +
>>   #endif /* PCI_HOST_PNV_PHB_H */
>
Mark Cave-Ayland June 2, 2022, 7:06 a.m. UTC | #3
On 01/06/2022 09:04, Daniel Henrique Barboza wrote:

> On 6/1/22 02:56, Cédric Le Goater wrote:
>> On 5/31/22 23:49, Daniel Henrique Barboza wrote:
>>> We have two very similar root-port devices, pnv-phb3-root-port and
>>> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
>>> that, until now, has no additional attributes.
>>>
>>> The main difference between the PHB3 and PHB4 root ports is that
>>> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
>>> other differences can be merged in a single device without too much
>>> trouble.
>>>
>>> This patch introduces the unified pnv-phb-root-port that, in time, will
>>> be used as the default root port for the pnv-phb device.
>>>
>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>> ---
>>>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>>>   hw/pci-host/pnv_phb.h |  17 +++++++
>>>   2 files changed, 116 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>>> index 321c4e768a..5047e90d3a 100644
>>> --- a/hw/pci-host/pnv_phb.c
>>> +++ b/hw/pci-host/pnv_phb.c
>>> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>>>       dc->user_creatable = true;
>>>   }
>>> -static void pnv_phb_register_type(void)
>>> +static void pnv_phb_root_port_reset(DeviceState *dev)
>>>   {
>>> -    static const TypeInfo pnv_phb_type_info = {
>>> -        .name          = TYPE_PNV_PHB,
>>> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
>>> -        .instance_size = sizeof(PnvPHB),
>>> -        .class_init    = pnv_phb_class_init,
>>> -    };
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
>>> +    PCIDevice *d = PCI_DEVICE(dev);
>>> +    uint8_t *conf = d->config;
>>> +    rpc->parent_reset(dev);
>>> +
>>> +    if (rootport->version == 3) {
>>> +        return;
>>> +    }
>>> +
>>> +    /* PHB4 and later requires these extra reset steps */
>>> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
>>> +                               PCI_IO_RANGE_MASK & 0xff);
>>> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
>>> +                                 PCI_IO_RANGE_MASK & 0xff);
>>> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
>>> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
>>> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
>>> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
>>> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
>>> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
>>> +    pci_config_set_interrupt_pin(conf, 0);
>>> +}
>>> +
>>> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>>> +{
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>> +    PCIDevice *pci = PCI_DEVICE(dev);
>>> +    PCIBus *bus = pci_get_bus(pci);
>>> +    PnvPHB *phb = NULL;
>>> +    Error *local_err = NULL;
>>> +
>>> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>>> +                                          TYPE_PNV_PHB);
>>> +
>>> +    if (!phb) {
>>> +        error_setg(errp,
>>> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
>>> +        return;
>>> +    }
>>> +
>>> +    /* Set unique chassis/slot values for the root port */
>>> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
>>> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
>>> +
>>> +    rpc->parent_realize(dev, &local_err);
>>> +    if (local_err) {
>>> +        error_propagate(errp, local_err);
>>> +        return;
>>> +    }
>>> +    pci_config_set_interrupt_pin(pci->config, 0);
>>> +}
>>> +
>>> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
>>> +
>>> +    dc->desc     = "IBM PHB PCIE Root Port";
>>> +
>>> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
>>> +                                    &rpc->parent_realize);
>>> +
>>> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
>>> +                                  &rpc->parent_reset);
>>> +    dc->reset = &pnv_phb_root_port_reset;
>>> +
>>> +    dc->user_creatable = true;
>>> +
>>> +    k->vendor_id = PCI_VENDOR_ID_IBM;
>>> +    /* device_id represents the latest PHB root port version supported */
>>> +    k->device_id = PNV_PHB5_DEVICE_ID;
>>
>> does that mean powernv8 machines will see phb devices as phb5 devices ?
> 
> 
> I had something like this in this patch that would set device_id properly:
> 
> 
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 5d66264a96..d468e8d44a 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -144,6 +144,22 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error 
> **errp)
>       PCIBus *bus = pci_get_bus(pci);
>       PnvPHB *phb = NULL;
>       Error *local_err = NULL;
> +    PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
> +    PCIDeviceClass *k = PCI_DEVICE_GET_CLASS(pci);
> +
> +    switch (phb_rp->version) {
> +    case 3:
> +        k->device_id = PNV_PHB3_DEVICE_ID;
> +        break;
> +    case 4:
> +        k->device_id = PNV_PHB4_DEVICE_ID;
> +        break;
> +    case 5:
> +        k->device_id = PNV_PHB5_DEVICE_ID;
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> 
>       phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>                                             TYPE_PNV_PHB);
> @@ -166,6 +182,11 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error 
> **errp)
>       pci_config_set_interrupt_pin(pci->config, 0);
>   }
> 
> +static Property pnv_phb_root_port_properties[] = {
> +    DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>   static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>   {
>       DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -181,6 +202,7 @@ static void pnv_phb_root_port_class_init(ObjectClass *klass, void 
> *data)
>                                     &rpc->parent_reset);
>       dc->reset = &pnv_phb_root_port_reset;
> 
> +    device_class_set_props(dc, pnv_phb_root_port_properties);
>       dc->user_creatable = true;
> 
>       k->vendor_id = PCI_VENDOR_ID_IBM;
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 4d2ea405db..13c8753eb2 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -2148,6 +2148,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void 
> *data)
> 
>       static GlobalProperty phb_compat[] = {
>           { TYPE_PNV_PHB, "version", "3" },
> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "3" },
>       };
> 
>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
> @@ -2173,6 +2174,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void 
> *data)
> 
>       static GlobalProperty phb_compat[] = {
>           { TYPE_PNV_PHB, "version", "4" },
> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "4" },
>       };
> 
>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
> @@ -2199,6 +2201,7 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, 
> void *data)
> 
>       static GlobalProperty phb_compat[] = {
>           { TYPE_PNV_PHB, "version", "5" },
> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
>       };
> 
>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
> 
> 
> The reason I didn't follow it through is because I wasn't sure if setting k->device_id
> during realize() time was acceptable. Everyone else seems to set k->device_id during
> class_init() or via an extra attribute 'device_id' that is written directly into
> the PCI header.
> 
> If this is something that we can do then I'm fine with fixing this up in this patch.

Yeah I'd be slightly nervous about doing this outside of class_init() too. I think my 
preferred method would be that used by virtio, which is to write the value to config 
space (see virtio_pci_device_plugged()) and then set k->device_id to 0 with an 
appropriate comment as per 
https://gitlab.com/qemu-project/qemu/-/blob/master/hw/virtio/vhost-user-rng-pci.c#L53. That 
makes it quite clear that the 0 value in class_init() is a placeholder for something 
else.

> Thanks,
>  
> Daniel
> 
>>
>> C.
>>
>>> +    k->revision  = 0;
>>> +
>>> +    rpc->exp_offset = 0x48;
>>> +    rpc->aer_offset = 0x100;
>>> +}
>>> +
>>> +static const TypeInfo pnv_phb_type_info = {
>>> +    .name          = TYPE_PNV_PHB,
>>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>>> +    .instance_size = sizeof(PnvPHB),
>>> +    .class_init    = pnv_phb_class_init,
>>> +};
>>> +
>>> +static const TypeInfo pnv_phb_root_port_info = {
>>> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
>>> +    .parent        = TYPE_PCIE_ROOT_PORT,
>>> +    .instance_size = sizeof(PnvPHBRootPort),
>>> +    .class_init    = pnv_phb_root_port_class_init,
>>> +};
>>> +
>>> +static void pnv_phb_register_types(void)
>>> +{
>>>       type_register_static(&pnv_phb_type_info);
>>> +    type_register_static(&pnv_phb_root_port_info);
>>>   }
>>> -type_init(pnv_phb_register_type)
>>> +
>>> +type_init(pnv_phb_register_types)
>>> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
>>> index a7cc8610e2..c8eab4b767 100644
>>> --- a/hw/pci-host/pnv_phb.h
>>> +++ b/hw/pci-host/pnv_phb.h
>>> @@ -36,4 +36,21 @@ struct PnvPHB {
>>>   #define TYPE_PNV_PHB "pnv-phb"
>>>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>>> +/*
>>> + * PHB PCIe Root port
>>> + */
>>> +#define PNV_PHB3_DEVICE_ID         0x03dc
>>> +#define PNV_PHB4_DEVICE_ID         0x04c1
>>> +#define PNV_PHB5_DEVICE_ID         0x0652
>>> +
>>> +typedef struct PnvPHBRootPort {
>>> +    PCIESlot parent_obj;
>>> +
>>> +    uint32_t version;
>>> +} PnvPHBRootPort;
>>> +
>>> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
>>> +#define PNV_PHB_ROOT_PORT(obj) \
>>> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
>>> +
>>>   #endif /* PCI_HOST_PNV_PHB_H */

ATB,

Mark.
Mark Cave-Ayland June 2, 2022, 8:12 a.m. UTC | #4
On 31/05/2022 22:49, Daniel Henrique Barboza wrote:

> We have two very similar root-port devices, pnv-phb3-root-port and
> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
> that, until now, has no additional attributes.
> 
> The main difference between the PHB3 and PHB4 root ports is that
> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
> other differences can be merged in a single device without too much
> trouble.
> 
> This patch introduces the unified pnv-phb-root-port that, in time, will
> be used as the default root port for the pnv-phb device.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>   hw/pci-host/pnv_phb.h |  17 +++++++
>   2 files changed, 116 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 321c4e768a..5047e90d3a 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>       dc->user_creatable = true;
>   }
>   
> -static void pnv_phb_register_type(void)
> +static void pnv_phb_root_port_reset(DeviceState *dev)
>   {
> -    static const TypeInfo pnv_phb_type_info = {
> -        .name          = TYPE_PNV_PHB,
> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
> -        .instance_size = sizeof(PnvPHB),
> -        .class_init    = pnv_phb_class_init,
> -    };
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
> +    PCIDevice *d = PCI_DEVICE(dev);
> +    uint8_t *conf = d->config;
>   
> +    rpc->parent_reset(dev);
> +
> +    if (rootport->version == 3) {
> +        return;
> +    }
> +
> +    /* PHB4 and later requires these extra reset steps */
> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
> +                               PCI_IO_RANGE_MASK & 0xff);
> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> +                                 PCI_IO_RANGE_MASK & 0xff);
> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
> +    pci_config_set_interrupt_pin(conf, 0);
> +}
> +
> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
> +{
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
> +    PCIDevice *pci = PCI_DEVICE(dev);
> +    PCIBus *bus = pci_get_bus(pci);
> +    PnvPHB *phb = NULL;
> +    Error *local_err = NULL;
> +
> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
> +                                          TYPE_PNV_PHB);

Same here too.

> +    if (!phb) {
> +        error_setg(errp,
> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
> +        return;
> +    }
> +
> +    /* Set unique chassis/slot values for the root port */
> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);

Again this is from older code, but we already have dev so these could be:

     qdev_prop_set_uint8(dev, "chassis", phb->chip_id);
     qdev_prop_set_uint16(dev, "slot", phb->phb_id);

> +    rpc->parent_realize(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    pci_config_set_interrupt_pin(pci->config, 0);
> +}
> +
> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
> +
> +    dc->desc     = "IBM PHB PCIE Root Port";
> +
> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
> +                                    &rpc->parent_realize);
> +
> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
> +                                  &rpc->parent_reset);
> +    dc->reset = &pnv_phb_root_port_reset;
> +
> +    dc->user_creatable = true;
> +
> +    k->vendor_id = PCI_VENDOR_ID_IBM;
> +    /* device_id represents the latest PHB root port version supported */
> +    k->device_id = PNV_PHB5_DEVICE_ID;
> +    k->revision  = 0;
> +
> +    rpc->exp_offset = 0x48;
> +    rpc->aer_offset = 0x100;
> +}
> +
> +static const TypeInfo pnv_phb_type_info = {
> +    .name          = TYPE_PNV_PHB,
> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
> +    .instance_size = sizeof(PnvPHB),
> +    .class_init    = pnv_phb_class_init,
> +};
> +
> +static const TypeInfo pnv_phb_root_port_info = {
> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
> +    .parent        = TYPE_PCIE_ROOT_PORT,
> +    .instance_size = sizeof(PnvPHBRootPort),
> +    .class_init    = pnv_phb_root_port_class_init,
> +};
> +
> +static void pnv_phb_register_types(void)
> +{
>       type_register_static(&pnv_phb_type_info);
> +    type_register_static(&pnv_phb_root_port_info);
>   }
> -type_init(pnv_phb_register_type)
> +
> +type_init(pnv_phb_register_types)
> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
> index a7cc8610e2..c8eab4b767 100644
> --- a/hw/pci-host/pnv_phb.h
> +++ b/hw/pci-host/pnv_phb.h
> @@ -36,4 +36,21 @@ struct PnvPHB {
>   #define TYPE_PNV_PHB "pnv-phb"
>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>   
> +/*
> + * PHB PCIe Root port
> + */
> +#define PNV_PHB3_DEVICE_ID         0x03dc
> +#define PNV_PHB4_DEVICE_ID         0x04c1
> +#define PNV_PHB5_DEVICE_ID         0x0652
> +
> +typedef struct PnvPHBRootPort {
> +    PCIESlot parent_obj;
> +
> +    uint32_t version;
> +} PnvPHBRootPort;
> +
> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
> +#define PNV_PHB_ROOT_PORT(obj) \
> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
> +
>   #endif /* PCI_HOST_PNV_PHB_H */


ATB,

Mark.
Daniel Henrique Barboza June 3, 2022, 8:47 p.m. UTC | #5
On 6/2/22 05:12, Mark Cave-Ayland wrote:
> On 31/05/2022 22:49, Daniel Henrique Barboza wrote:
> 
>> We have two very similar root-port devices, pnv-phb3-root-port and
>> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
>> that, until now, has no additional attributes.
>>
>> The main difference between the PHB3 and PHB4 root ports is that
>> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
>> other differences can be merged in a single device without too much
>> trouble.
>>
>> This patch introduces the unified pnv-phb-root-port that, in time, will
>> be used as the default root port for the pnv-phb device.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>>   hw/pci-host/pnv_phb.h |  17 +++++++
>>   2 files changed, 116 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>> index 321c4e768a..5047e90d3a 100644
>> --- a/hw/pci-host/pnv_phb.c
>> +++ b/hw/pci-host/pnv_phb.c
>> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>>       dc->user_creatable = true;
>>   }
>> -static void pnv_phb_register_type(void)
>> +static void pnv_phb_root_port_reset(DeviceState *dev)
>>   {
>> -    static const TypeInfo pnv_phb_type_info = {
>> -        .name          = TYPE_PNV_PHB,
>> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
>> -        .instance_size = sizeof(PnvPHB),
>> -        .class_init    = pnv_phb_class_init,
>> -    };
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
>> +    PCIDevice *d = PCI_DEVICE(dev);
>> +    uint8_t *conf = d->config;
>> +    rpc->parent_reset(dev);
>> +
>> +    if (rootport->version == 3) {
>> +        return;
>> +    }
>> +
>> +    /* PHB4 and later requires these extra reset steps */
>> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
>> +                               PCI_IO_RANGE_MASK & 0xff);
>> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
>> +                                 PCI_IO_RANGE_MASK & 0xff);
>> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
>> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
>> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
>> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
>> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
>> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
>> +    pci_config_set_interrupt_pin(conf, 0);
>> +}
>> +
>> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>> +    PCIDevice *pci = PCI_DEVICE(dev);
>> +    PCIBus *bus = pci_get_bus(pci);
>> +    PnvPHB *phb = NULL;
>> +    Error *local_err = NULL;
>> +
>> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>> +                                          TYPE_PNV_PHB);
> 
> Same here too.


This case is a bit different than the previous because there's no ->phb_base in
this device. Doing

PnvPHB *phb = PNV_PHB(PNV_PHB_ROOT_PORT(dev));

Will somehow retrieve a PnvPHB pointer but with zeroed properties. This makes
the slot/chassis code down below to fail when adding a second port.

I checked how other parts of the code handles that and the closer I found so
far is doing something like this:

     PCIDevice *pci = PCI_DEVICE(dev);
     PnvPHB *phb = PNV_PHB(pci_device_root_bus(pci)->qbus.parent);

This is how pci_bus_bypass_iommu() from hw/pci/pci.c retrieves a PCIHostState
pointer of a given bus.

Another idea is to simply add a pointer to the parent PnvPHB device that the
root port is attached to. This would trivialize this part and I could also
use the already set PnvPHB->version for the root port logic as well since they're
set to be the same.


Thanks,


Daniel



> 
>> +    if (!phb) {
>> +        error_setg(errp,
>> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
>> +        return;
>> +    }
>> +
>> +    /* Set unique chassis/slot values for the root port */
>> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
>> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
> 
> Again this is from older code, but we already have dev so these could be:
> 
>      qdev_prop_set_uint8(dev, "chassis", phb->chip_id);
>      qdev_prop_set_uint16(dev, "slot", phb->phb_id);
> 
>> +    rpc->parent_realize(dev, &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    pci_config_set_interrupt_pin(pci->config, 0);
>> +}
>> +
>> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
>> +
>> +    dc->desc     = "IBM PHB PCIE Root Port";
>> +
>> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
>> +                                    &rpc->parent_realize);
>> +
>> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
>> +                                  &rpc->parent_reset);
>> +    dc->reset = &pnv_phb_root_port_reset;
>> +
>> +    dc->user_creatable = true;
>> +
>> +    k->vendor_id = PCI_VENDOR_ID_IBM;
>> +    /* device_id represents the latest PHB root port version supported */
>> +    k->device_id = PNV_PHB5_DEVICE_ID;
>> +    k->revision  = 0;
>> +
>> +    rpc->exp_offset = 0x48;
>> +    rpc->aer_offset = 0x100;
>> +}
>> +
>> +static const TypeInfo pnv_phb_type_info = {
>> +    .name          = TYPE_PNV_PHB,
>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>> +    .instance_size = sizeof(PnvPHB),
>> +    .class_init    = pnv_phb_class_init,
>> +};
>> +
>> +static const TypeInfo pnv_phb_root_port_info = {
>> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
>> +    .parent        = TYPE_PCIE_ROOT_PORT,
>> +    .instance_size = sizeof(PnvPHBRootPort),
>> +    .class_init    = pnv_phb_root_port_class_init,
>> +};
>> +
>> +static void pnv_phb_register_types(void)
>> +{
>>       type_register_static(&pnv_phb_type_info);
>> +    type_register_static(&pnv_phb_root_port_info);
>>   }
>> -type_init(pnv_phb_register_type)
>> +
>> +type_init(pnv_phb_register_types)
>> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
>> index a7cc8610e2..c8eab4b767 100644
>> --- a/hw/pci-host/pnv_phb.h
>> +++ b/hw/pci-host/pnv_phb.h
>> @@ -36,4 +36,21 @@ struct PnvPHB {
>>   #define TYPE_PNV_PHB "pnv-phb"
>>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>> +/*
>> + * PHB PCIe Root port
>> + */
>> +#define PNV_PHB3_DEVICE_ID         0x03dc
>> +#define PNV_PHB4_DEVICE_ID         0x04c1
>> +#define PNV_PHB5_DEVICE_ID         0x0652
>> +
>> +typedef struct PnvPHBRootPort {
>> +    PCIESlot parent_obj;
>> +
>> +    uint32_t version;
>> +} PnvPHBRootPort;
>> +
>> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
>> +#define PNV_PHB_ROOT_PORT(obj) \
>> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
>> +
>>   #endif /* PCI_HOST_PNV_PHB_H */
> 
> 
> ATB,
> 
> Mark.
Mark Cave-Ayland June 6, 2022, 12:41 p.m. UTC | #6
On 03/06/2022 21:47, Daniel Henrique Barboza wrote:

> On 6/2/22 05:12, Mark Cave-Ayland wrote:
>> On 31/05/2022 22:49, Daniel Henrique Barboza wrote:
>>
>>> We have two very similar root-port devices, pnv-phb3-root-port and
>>> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
>>> that, until now, has no additional attributes.
>>>
>>> The main difference between the PHB3 and PHB4 root ports is that
>>> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
>>> other differences can be merged in a single device without too much
>>> trouble.
>>>
>>> This patch introduces the unified pnv-phb-root-port that, in time, will
>>> be used as the default root port for the pnv-phb device.
>>>
>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>> ---
>>>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>>>   hw/pci-host/pnv_phb.h |  17 +++++++
>>>   2 files changed, 116 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>>> index 321c4e768a..5047e90d3a 100644
>>> --- a/hw/pci-host/pnv_phb.c
>>> +++ b/hw/pci-host/pnv_phb.c
>>> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>>>       dc->user_creatable = true;
>>>   }
>>> -static void pnv_phb_register_type(void)
>>> +static void pnv_phb_root_port_reset(DeviceState *dev)
>>>   {
>>> -    static const TypeInfo pnv_phb_type_info = {
>>> -        .name          = TYPE_PNV_PHB,
>>> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
>>> -        .instance_size = sizeof(PnvPHB),
>>> -        .class_init    = pnv_phb_class_init,
>>> -    };
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
>>> +    PCIDevice *d = PCI_DEVICE(dev);
>>> +    uint8_t *conf = d->config;
>>> +    rpc->parent_reset(dev);
>>> +
>>> +    if (rootport->version == 3) {
>>> +        return;
>>> +    }
>>> +
>>> +    /* PHB4 and later requires these extra reset steps */
>>> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
>>> +                               PCI_IO_RANGE_MASK & 0xff);
>>> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
>>> +                                 PCI_IO_RANGE_MASK & 0xff);
>>> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
>>> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
>>> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
>>> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
>>> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
>>> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
>>> +    pci_config_set_interrupt_pin(conf, 0);
>>> +}
>>> +
>>> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>>> +{
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>> +    PCIDevice *pci = PCI_DEVICE(dev);
>>> +    PCIBus *bus = pci_get_bus(pci);
>>> +    PnvPHB *phb = NULL;
>>> +    Error *local_err = NULL;
>>> +
>>> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>>> +                                          TYPE_PNV_PHB);
>>
>> Same here too.
> 
> 
> This case is a bit different than the previous because there's no ->phb_base in
> this device. Doing
> 
> PnvPHB *phb = PNV_PHB(PNV_PHB_ROOT_PORT(dev));
> 
> Will somehow retrieve a PnvPHB pointer but with zeroed properties. This makes
> the slot/chassis code down below to fail when adding a second port.

Hmmm that's odd.

> I checked how other parts of the code handles that and the closer I found so
> far is doing something like this:
> 
>      PCIDevice *pci = PCI_DEVICE(dev);
>      PnvPHB *phb = PNV_PHB(pci_device_root_bus(pci)->qbus.parent);
> 
> This is how pci_bus_bypass_iommu() from hw/pci/pci.c retrieves a PCIHostState
> pointer of a given bus.
> 
> Another idea is to simply add a pointer to the parent PnvPHB device that the
> root port is attached to. This would trivialize this part and I could also
> use the already set PnvPHB->version for the root port logic as well since they're
> set to be the same.

I think what should happen is that the parent device should instantiate the pnv_phb 
root port via object_initialize_child() so it is embedded within it, at which point 
the pnv_phb root port device can just use container_of() to obtain the reference to 
the parent device state.

But certainly dereferencing the internal qbus object is not the right long-term solution.

>>> +    if (!phb) {
>>> +        error_setg(errp,
>>> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
>>> +        return;
>>> +    }
>>> +
>>> +    /* Set unique chassis/slot values for the root port */
>>> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
>>> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
>>
>> Again this is from older code, but we already have dev so these could be:
>>
>>      qdev_prop_set_uint8(dev, "chassis", phb->chip_id);
>>      qdev_prop_set_uint16(dev, "slot", phb->phb_id);
>>
>>> +    rpc->parent_realize(dev, &local_err);
>>> +    if (local_err) {
>>> +        error_propagate(errp, local_err);
>>> +        return;
>>> +    }
>>> +    pci_config_set_interrupt_pin(pci->config, 0);
>>> +}
>>> +
>>> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
>>> +
>>> +    dc->desc     = "IBM PHB PCIE Root Port";
>>> +
>>> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
>>> +                                    &rpc->parent_realize);
>>> +
>>> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
>>> +                                  &rpc->parent_reset);
>>> +    dc->reset = &pnv_phb_root_port_reset;
>>> +
>>> +    dc->user_creatable = true;
>>> +
>>> +    k->vendor_id = PCI_VENDOR_ID_IBM;
>>> +    /* device_id represents the latest PHB root port version supported */
>>> +    k->device_id = PNV_PHB5_DEVICE_ID;
>>> +    k->revision  = 0;
>>> +
>>> +    rpc->exp_offset = 0x48;
>>> +    rpc->aer_offset = 0x100;
>>> +}
>>> +
>>> +static const TypeInfo pnv_phb_type_info = {
>>> +    .name          = TYPE_PNV_PHB,
>>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>>> +    .instance_size = sizeof(PnvPHB),
>>> +    .class_init    = pnv_phb_class_init,
>>> +};
>>> +
>>> +static const TypeInfo pnv_phb_root_port_info = {
>>> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
>>> +    .parent        = TYPE_PCIE_ROOT_PORT,
>>> +    .instance_size = sizeof(PnvPHBRootPort),
>>> +    .class_init    = pnv_phb_root_port_class_init,
>>> +};
>>> +
>>> +static void pnv_phb_register_types(void)
>>> +{
>>>       type_register_static(&pnv_phb_type_info);
>>> +    type_register_static(&pnv_phb_root_port_info);
>>>   }
>>> -type_init(pnv_phb_register_type)
>>> +
>>> +type_init(pnv_phb_register_types)
>>> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
>>> index a7cc8610e2..c8eab4b767 100644
>>> --- a/hw/pci-host/pnv_phb.h
>>> +++ b/hw/pci-host/pnv_phb.h
>>> @@ -36,4 +36,21 @@ struct PnvPHB {
>>>   #define TYPE_PNV_PHB "pnv-phb"
>>>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>>> +/*
>>> + * PHB PCIe Root port
>>> + */
>>> +#define PNV_PHB3_DEVICE_ID         0x03dc
>>> +#define PNV_PHB4_DEVICE_ID         0x04c1
>>> +#define PNV_PHB5_DEVICE_ID         0x0652
>>> +
>>> +typedef struct PnvPHBRootPort {
>>> +    PCIESlot parent_obj;
>>> +
>>> +    uint32_t version;
>>> +} PnvPHBRootPort;
>>> +
>>> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
>>> +#define PNV_PHB_ROOT_PORT(obj) \
>>> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
>>> +
>>>   #endif /* PCI_HOST_PNV_PHB_H */


ATB,

Mark.
Cédric Le Goater June 7, 2022, 6:37 a.m. UTC | #7
On 6/2/22 09:06, Mark Cave-Ayland wrote:
> On 01/06/2022 09:04, Daniel Henrique Barboza wrote:
> 
>> On 6/1/22 02:56, Cédric Le Goater wrote:
>>> On 5/31/22 23:49, Daniel Henrique Barboza wrote:
>>>> We have two very similar root-port devices, pnv-phb3-root-port and
>>>> pnv-phb4-root-port. Both consist of a wrapper around the PCIESlot device
>>>> that, until now, has no additional attributes.
>>>>
>>>> The main difference between the PHB3 and PHB4 root ports is that
>>>> pnv-phb4-root-port has the pnv_phb4_root_port_reset() callback. All
>>>> other differences can be merged in a single device without too much
>>>> trouble.
>>>>
>>>> This patch introduces the unified pnv-phb-root-port that, in time, will
>>>> be used as the default root port for the pnv-phb device.
>>>>
>>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>>> ---
>>>>   hw/pci-host/pnv_phb.c | 107 ++++++++++++++++++++++++++++++++++++++----
>>>>   hw/pci-host/pnv_phb.h |  17 +++++++
>>>>   2 files changed, 116 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>>>> index 321c4e768a..5047e90d3a 100644
>>>> --- a/hw/pci-host/pnv_phb.c
>>>> +++ b/hw/pci-host/pnv_phb.c
>>>> @@ -114,15 +114,106 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
>>>>       dc->user_creatable = true;
>>>>   }
>>>> -static void pnv_phb_register_type(void)
>>>> +static void pnv_phb_root_port_reset(DeviceState *dev)
>>>>   {
>>>> -    static const TypeInfo pnv_phb_type_info = {
>>>> -        .name          = TYPE_PNV_PHB,
>>>> -        .parent        = TYPE_PCIE_HOST_BRIDGE,
>>>> -        .instance_size = sizeof(PnvPHB),
>>>> -        .class_init    = pnv_phb_class_init,
>>>> -    };
>>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>>> +    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
>>>> +    PCIDevice *d = PCI_DEVICE(dev);
>>>> +    uint8_t *conf = d->config;
>>>> +    rpc->parent_reset(dev);
>>>> +
>>>> +    if (rootport->version == 3) {
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    /* PHB4 and later requires these extra reset steps */
>>>> +    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
>>>> +                               PCI_IO_RANGE_MASK & 0xff);
>>>> +    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
>>>> +                                 PCI_IO_RANGE_MASK & 0xff);
>>>> +    pci_set_word(conf + PCI_MEMORY_BASE, 0);
>>>> +    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
>>>> +    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
>>>> +    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
>>>> +    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
>>>> +    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
>>>> +    pci_config_set_interrupt_pin(conf, 0);
>>>> +}
>>>> +
>>>> +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>>>> +{
>>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
>>>> +    PCIDevice *pci = PCI_DEVICE(dev);
>>>> +    PCIBus *bus = pci_get_bus(pci);
>>>> +    PnvPHB *phb = NULL;
>>>> +    Error *local_err = NULL;
>>>> +
>>>> +    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>>>> +                                          TYPE_PNV_PHB);
>>>> +
>>>> +    if (!phb) {
>>>> +        error_setg(errp,
>>>> +"pnv_phb_root_port devices must be connected to pnv-phb buses");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    /* Set unique chassis/slot values for the root port */
>>>> +    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
>>>> +    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
>>>> +
>>>> +    rpc->parent_realize(dev, &local_err);
>>>> +    if (local_err) {
>>>> +        error_propagate(errp, local_err);
>>>> +        return;
>>>> +    }
>>>> +    pci_config_set_interrupt_pin(pci->config, 0);
>>>> +}
>>>> +
>>>> +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>>>> +    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
>>>> +
>>>> +    dc->desc     = "IBM PHB PCIE Root Port";
>>>> +
>>>> +    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
>>>> +                                    &rpc->parent_realize);
>>>> +
>>>> +    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
>>>> +                                  &rpc->parent_reset);
>>>> +    dc->reset = &pnv_phb_root_port_reset;
>>>> +
>>>> +    dc->user_creatable = true;
>>>> +
>>>> +    k->vendor_id = PCI_VENDOR_ID_IBM;
>>>> +    /* device_id represents the latest PHB root port version supported */
>>>> +    k->device_id = PNV_PHB5_DEVICE_ID;
>>>
>>> does that mean powernv8 machines will see phb devices as phb5 devices ?
>>
>>
>> I had something like this in this patch that would set device_id properly:
>>
>>
>> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
>> index 5d66264a96..d468e8d44a 100644
>> --- a/hw/pci-host/pnv_phb.c
>> +++ b/hw/pci-host/pnv_phb.c
>> @@ -144,6 +144,22 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>>       PCIBus *bus = pci_get_bus(pci);
>>       PnvPHB *phb = NULL;
>>       Error *local_err = NULL;
>> +    PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
>> +    PCIDeviceClass *k = PCI_DEVICE_GET_CLASS(pci);
>> +
>> +    switch (phb_rp->version) {
>> +    case 3:
>> +        k->device_id = PNV_PHB3_DEVICE_ID;
>> +        break;
>> +    case 4:
>> +        k->device_id = PNV_PHB4_DEVICE_ID;
>> +        break;
>> +    case 5:
>> +        k->device_id = PNV_PHB5_DEVICE_ID;
>> +        break;
>> +    default:
>> +        g_assert_not_reached();
>> +    }
>>
>>       phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
>>                                             TYPE_PNV_PHB);
>> @@ -166,6 +182,11 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
>>       pci_config_set_interrupt_pin(pci->config, 0);
>>   }
>>
>> +static Property pnv_phb_root_port_properties[] = {
>> +    DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>>   static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>>   {
>>       DeviceClass *dc = DEVICE_CLASS(klass);
>> @@ -181,6 +202,7 @@ static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
>>                                     &rpc->parent_reset);
>>       dc->reset = &pnv_phb_root_port_reset;
>>
>> +    device_class_set_props(dc, pnv_phb_root_port_properties);
>>       dc->user_creatable = true;
>>
>>       k->vendor_id = PCI_VENDOR_ID_IBM;
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 4d2ea405db..13c8753eb2 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -2148,6 +2148,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
>>
>>       static GlobalProperty phb_compat[] = {
>>           { TYPE_PNV_PHB, "version", "3" },
>> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "3" },
>>       };
>>
>>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
>> @@ -2173,6 +2174,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
>>
>>       static GlobalProperty phb_compat[] = {
>>           { TYPE_PNV_PHB, "version", "4" },
>> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "4" },
>>       };
>>
>>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
>> @@ -2199,6 +2201,7 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
>>
>>       static GlobalProperty phb_compat[] = {
>>           { TYPE_PNV_PHB, "version", "5" },
>> +        { TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
>>       };
>>
>>       mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
>>
>>
>> The reason I didn't follow it through is because I wasn't sure if setting k->device_id
>> during realize() time was acceptable. Everyone else seems to set k->device_id during
>> class_init() or via an extra attribute 'device_id' that is written directly into
>> the PCI header.
>>
>> If this is something that we can do then I'm fine with fixing this up in this patch.
> 
> Yeah I'd be slightly nervous about doing this outside of class_init() too. I think my preferred method would be that used by virtio, which is to write the value to config space (see virtio_pci_device_plugged()) and then set k->device_id to 0 with an appropriate comment as per https://gitlab.com/qemu-project/qemu/-/blob/master/hw/virtio/vhost-user-rng-pci.c#L53. That makes it quite clear that the 0 value in class_init() is a placeholder for something else.


Ah yes. This is a nice trick. It would simplify a lot the models.

Thanks,

C.


> 
>> Thanks,
>>
>> Daniel
>>
>>>
>>> C.
>>>
>>>> +    k->revision  = 0;
>>>> +
>>>> +    rpc->exp_offset = 0x48;
>>>> +    rpc->aer_offset = 0x100;
>>>> +}
>>>> +
>>>> +static const TypeInfo pnv_phb_type_info = {
>>>> +    .name          = TYPE_PNV_PHB,
>>>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>>>> +    .instance_size = sizeof(PnvPHB),
>>>> +    .class_init    = pnv_phb_class_init,
>>>> +};
>>>> +
>>>> +static const TypeInfo pnv_phb_root_port_info = {
>>>> +    .name          = TYPE_PNV_PHB_ROOT_PORT,
>>>> +    .parent        = TYPE_PCIE_ROOT_PORT,
>>>> +    .instance_size = sizeof(PnvPHBRootPort),
>>>> +    .class_init    = pnv_phb_root_port_class_init,
>>>> +};
>>>> +
>>>> +static void pnv_phb_register_types(void)
>>>> +{
>>>>       type_register_static(&pnv_phb_type_info);
>>>> +    type_register_static(&pnv_phb_root_port_info);
>>>>   }
>>>> -type_init(pnv_phb_register_type)
>>>> +
>>>> +type_init(pnv_phb_register_types)
>>>> diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
>>>> index a7cc8610e2..c8eab4b767 100644
>>>> --- a/hw/pci-host/pnv_phb.h
>>>> +++ b/hw/pci-host/pnv_phb.h
>>>> @@ -36,4 +36,21 @@ struct PnvPHB {
>>>>   #define TYPE_PNV_PHB "pnv-phb"
>>>>   OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
>>>> +/*
>>>> + * PHB PCIe Root port
>>>> + */
>>>> +#define PNV_PHB3_DEVICE_ID         0x03dc
>>>> +#define PNV_PHB4_DEVICE_ID         0x04c1
>>>> +#define PNV_PHB5_DEVICE_ID         0x0652
>>>> +
>>>> +typedef struct PnvPHBRootPort {
>>>> +    PCIESlot parent_obj;
>>>> +
>>>> +    uint32_t version;
>>>> +} PnvPHBRootPort;
>>>> +
>>>> +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
>>>> +#define PNV_PHB_ROOT_PORT(obj) \
>>>> +    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
>>>> +
>>>>   #endif /* PCI_HOST_PNV_PHB_H */
> 
> ATB,
> 
> Mark.
diff mbox series

Patch

diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 321c4e768a..5047e90d3a 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -114,15 +114,106 @@  static void pnv_phb_class_init(ObjectClass *klass, void *data)
     dc->user_creatable = true;
 }
 
-static void pnv_phb_register_type(void)
+static void pnv_phb_root_port_reset(DeviceState *dev)
 {
-    static const TypeInfo pnv_phb_type_info = {
-        .name          = TYPE_PNV_PHB,
-        .parent        = TYPE_PCIE_HOST_BRIDGE,
-        .instance_size = sizeof(PnvPHB),
-        .class_init    = pnv_phb_class_init,
-    };
+    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+    PnvPHBRootPort *rootport = PNV_PHB_ROOT_PORT(dev);
+    PCIDevice *d = PCI_DEVICE(dev);
+    uint8_t *conf = d->config;
 
+    rpc->parent_reset(dev);
+
+    if (rootport->version == 3) {
+        return;
+    }
+
+    /* PHB4 and later requires these extra reset steps */
+    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
+                               PCI_IO_RANGE_MASK & 0xff);
+    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_set_word(conf + PCI_MEMORY_BASE, 0);
+    pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
+    pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
+    pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
+    pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
+    pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
+    pci_config_set_interrupt_pin(conf, 0);
+}
+
+static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
+{
+    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+    PCIDevice *pci = PCI_DEVICE(dev);
+    PCIBus *bus = pci_get_bus(pci);
+    PnvPHB *phb = NULL;
+    Error *local_err = NULL;
+
+    phb = (PnvPHB *) object_dynamic_cast(OBJECT(bus->qbus.parent),
+                                          TYPE_PNV_PHB);
+
+    if (!phb) {
+        error_setg(errp,
+"pnv_phb_root_port devices must be connected to pnv-phb buses");
+        return;
+    }
+
+    /* Set unique chassis/slot values for the root port */
+    qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
+    qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
+
+    rpc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    pci_config_set_interrupt_pin(pci->config, 0);
+}
+
+static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
+
+    dc->desc     = "IBM PHB PCIE Root Port";
+
+    device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
+                                    &rpc->parent_realize);
+
+    device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
+                                  &rpc->parent_reset);
+    dc->reset = &pnv_phb_root_port_reset;
+
+    dc->user_creatable = true;
+
+    k->vendor_id = PCI_VENDOR_ID_IBM;
+    /* device_id represents the latest PHB root port version supported */
+    k->device_id = PNV_PHB5_DEVICE_ID;
+    k->revision  = 0;
+
+    rpc->exp_offset = 0x48;
+    rpc->aer_offset = 0x100;
+}
+
+static const TypeInfo pnv_phb_type_info = {
+    .name          = TYPE_PNV_PHB,
+    .parent        = TYPE_PCIE_HOST_BRIDGE,
+    .instance_size = sizeof(PnvPHB),
+    .class_init    = pnv_phb_class_init,
+};
+
+static const TypeInfo pnv_phb_root_port_info = {
+    .name          = TYPE_PNV_PHB_ROOT_PORT,
+    .parent        = TYPE_PCIE_ROOT_PORT,
+    .instance_size = sizeof(PnvPHBRootPort),
+    .class_init    = pnv_phb_root_port_class_init,
+};
+
+static void pnv_phb_register_types(void)
+{
     type_register_static(&pnv_phb_type_info);
+    type_register_static(&pnv_phb_root_port_info);
 }
-type_init(pnv_phb_register_type)
+
+type_init(pnv_phb_register_types)
diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h
index a7cc8610e2..c8eab4b767 100644
--- a/hw/pci-host/pnv_phb.h
+++ b/hw/pci-host/pnv_phb.h
@@ -36,4 +36,21 @@  struct PnvPHB {
 #define TYPE_PNV_PHB "pnv-phb"
 OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
 
+/*
+ * PHB PCIe Root port
+ */
+#define PNV_PHB3_DEVICE_ID         0x03dc
+#define PNV_PHB4_DEVICE_ID         0x04c1
+#define PNV_PHB5_DEVICE_ID         0x0652
+
+typedef struct PnvPHBRootPort {
+    PCIESlot parent_obj;
+
+    uint32_t version;
+} PnvPHBRootPort;
+
+#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
+#define PNV_PHB_ROOT_PORT(obj) \
+    OBJECT_CHECK(PnvPHBRootPort, obj, TYPE_PNV_PHB_ROOT_PORT)
+
 #endif /* PCI_HOST_PNV_PHB_H */